<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.secondlife.com/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Julia+Banshee</id>
	<title>Second Life Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.secondlife.com/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Julia+Banshee"/>
	<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/wiki/Special:Contributions/Julia_Banshee"/>
	<updated>2026-05-30T01:47:59Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.42.1</generator>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Open_Relay_Group/vision&amp;diff=636212</id>
		<title>LSL Protocol/Restrained Love Open Relay Group/vision</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Open_Relay_Group/vision&amp;diff=636212"/>
		<updated>2009-10-29T09:23:31Z</updated>

		<summary type="html">&lt;p&gt;Julia Banshee: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ ORG Restrained Life Relay Specs TOC }}&lt;br /&gt;
&lt;br /&gt;
== !x-vision ==  &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Implemented in THINK KINK&#039;s tkPBA v30k and above, and in Dominatech Relay 2.1&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
; Description : meta command to control what the victim can see while under restraint. This will allow a full range of vision control of the victim. Full blindness, partial, color, textures, etc..&lt;br /&gt;
; Implementation : using a small microprim that hides on the back of our RelayHUD, we can expand and texture this to control the sight of the victim. Put them in a dark cell, they go blind. Or in a forcefield change the color, make it partially transparant, put up a texture, etc. We are/will also be using this as a &amp;quot;MouseLook&amp;quot; enforcer to punish a victim when they won&#039;t stay in mouselook (get out of mouselook, go totally blind). Currently being implemented in devices from THINK KINK.&lt;br /&gt;
; Syntax : &#039;&#039;&#039;!x-vision/(color)/(alpha)/(texture)/(repeats)/(offsets)/(rotation)&#039;&#039;&#039;&lt;br /&gt;
: &#039;&#039;&#039;!x-vision/clear&#039;&#039;&#039;&lt;br /&gt;
::(color) = color for the HUD covering prim in RGB format &amp;lt;r&#039;g&#039;b&amp;gt; 0-255 (NOTE: the &#039; is the seperator instead of , to avoid parsing issues with the rest of the RLV command string)&lt;br /&gt;
::(alpha) = % transparent to make the HUD prim cover (in alpha format 0.0-1.0)&lt;br /&gt;
::(texture) = UUID for a texture to apply to the prim&lt;br /&gt;
::(repeats) = x/y repeats for the texture, same format as the texture tab on an prim 1.0&#039;1.0&lt;br /&gt;
::(offsets) = x/y offsets for the texture, same format as the texture tab on an prim 0.0&#039;0.0&lt;br /&gt;
::(rotation) = rotation of the texture&lt;br /&gt;
&lt;br /&gt;
:: SPECIAL ENTRY, any of the parameters can be replaced with &amp;quot;*&amp;quot; for &#039;do not change existing value&#039;&lt;br /&gt;
&lt;br /&gt;
:: NOTE: the &#039;default&#039; value of the HUD prim is 100% transparent, white, TEXTURE_BLANK. ie. !vision/0.0/&amp;lt;255&#039;255&#039;255&amp;gt;/TEXTURE_BLANK/1.0&#039;1.0/0.0&#039;0.0&lt;br /&gt;
:: if all you want to do is &#039;blind&#039; someone, then !vision/&amp;lt;0&#039;0&#039;0&amp;gt;/1.0/*/*/*/*&lt;br /&gt;
&lt;br /&gt;
:: The second form clears the vision restriction set.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
; Examples&lt;br /&gt;
: Total blackout &amp;quot;!x-vision/&amp;lt;0&#039;0&#039;0&amp;gt;/1.0/TEXTURE_BLANK/1.0&#039;1.0/0.0&#039;0.0/0.0&lt;br /&gt;
: Light fog &amp;quot;!x-vision/&amp;lt;128&#039;128&#039;128&amp;gt;/0.5/TEXTURE_BLANK/1.0&#039;1.0/0.0&#039;0.0/0.0&amp;quot;&lt;br /&gt;
: In a plywood box no matter where they look &amp;quot;!x-vision/&amp;lt;255&#039;255&#039;255&amp;gt;/1.0/TEXTURE_PLYWOOD/1.0&#039;1.0/0.0&#039;0.0&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; Discussion&lt;br /&gt;
Although this feature has been extensively discussed elsewhere, that discussion was unnecessarily contentious and is not repeated here.&lt;/div&gt;</summary>
		<author><name>Julia Banshee</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Living_Relay/Other_Implementations/Dominatech_RLV_Relay&amp;diff=237942</id>
		<title>LSL Protocol/Restrained Living Relay/Other Implementations/Dominatech RLV Relay</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Living_Relay/Other_Implementations/Dominatech_RLV_Relay&amp;diff=237942"/>
		<updated>2009-02-14T08:39:37Z</updated>

		<summary type="html">&lt;p&gt;Julia Banshee: /* Dominatech RLV Relay */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Restrained Life Relay Specs TOC}}&lt;br /&gt;
&lt;br /&gt;
== Dominatech RLV Relay ==&lt;br /&gt;
&amp;amp;copy; 2009 Julia Banshee&lt;br /&gt;
&lt;br /&gt;
This is an open source RLV relay script that supports relaying from multiple devices.&lt;br /&gt;
&lt;br /&gt;
It it fully compatible with version 1.030 of the RLV Relay Specification, but has one non-standard extention, a &amp;quot;!getstatus&amp;quot; command that returns the restrictions held only by the one device requesting the status.  This (or similar functionality) has been proposed for inclusion in a future version of the official specification.&lt;br /&gt;
&lt;br /&gt;
See the [[Talk:LSL_Protocol/Restrained_Life_Relay/Other_Implementations/Dominatech_RLV_Relay|discussion page]] for some issues with multi-device relays.&lt;br /&gt;
&lt;br /&gt;
So without further ado...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// Dominatech RLV Relay Script 2.0&lt;br /&gt;
// Copyright (C) 2009 Julia Banshee&lt;br /&gt;
//&lt;br /&gt;
// This program is free software: you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// See http://www.gnu.org/licenses/gpl.html for terms of this license.&lt;br /&gt;
&lt;br /&gt;
integer relayChannel = -1812221819;&lt;br /&gt;
string version = &amp;quot;1030&amp;quot;;&lt;br /&gt;
string implversion = &amp;quot;Dominatech Relay 2.0&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
integer backChannel; // for @getsitid&lt;br /&gt;
key sitting;&lt;br /&gt;
&lt;br /&gt;
list objects;&lt;br /&gt;
list restrictions;&lt;br /&gt;
&lt;br /&gt;
list pingObjects;&lt;br /&gt;
list pingRestrictions;&lt;br /&gt;
key pingSitting;&lt;br /&gt;
integer pingSitRetry;&lt;br /&gt;
&lt;br /&gt;
integer lit;&lt;br /&gt;
&lt;br /&gt;
integer askMode;&lt;br /&gt;
list allowedObjects;&lt;br /&gt;
list rejectedObjects;&lt;br /&gt;
list pendingObjects;&lt;br /&gt;
list pendingCommands;&lt;br /&gt;
&lt;br /&gt;
integer permChannel;&lt;br /&gt;
integer permListener;&lt;br /&gt;
integer permClose;&lt;br /&gt;
&lt;br /&gt;
updateStatus(integer r)&lt;br /&gt;
{&lt;br /&gt;
    if ( r )&lt;br /&gt;
    {&lt;br /&gt;
        if ( ! lit )&lt;br /&gt;
        {&lt;br /&gt;
            llMessageLinked(LINK_SET, TRUE, &amp;quot;relay-lock&amp;quot;, NULL_KEY);&lt;br /&gt;
            llSetColor(&amp;lt;1.0, 0.0, 0.0&amp;gt;, ALL_SIDES);&lt;br /&gt;
            lit = TRUE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if ( lit )&lt;br /&gt;
        {&lt;br /&gt;
            llMessageLinked(LINK_SET, FALSE, &amp;quot;relay-lock&amp;quot;, NULL_KEY);&lt;br /&gt;
            llSetColor(&amp;lt;0.0, 1.0, 0.0&amp;gt;, ALL_SIDES);&lt;br /&gt;
            lit = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
clear(key obj)&lt;br /&gt;
{&lt;br /&gt;
    integer o = llListFindList(objects, [obj]);&lt;br /&gt;
    if ( o &amp;gt;= 0 )&lt;br /&gt;
    {&lt;br /&gt;
        integer i;&lt;br /&gt;
        while ( (i = llListFindList(restrictions, [o])) &amp;gt;= 0 )&lt;br /&gt;
        {&lt;br /&gt;
            string restr = llList2String(restrictions, i + 1);&lt;br /&gt;
            restrictions = llDeleteSubList(restrictions, i, i + 1);&lt;br /&gt;
            if ( llListFindList(restrictions, [restr]) &amp;lt; 0 )&lt;br /&gt;
                llOwnerSay(&amp;quot;@&amp;quot; + restr + &amp;quot;=y&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    if ( llGetListLength(restrictions) == 0 )&lt;br /&gt;
    {&lt;br /&gt;
        objects = [];&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
clearSome(key obj, string param)&lt;br /&gt;
{&lt;br /&gt;
    integer o = llListFindList(objects, [obj]);&lt;br /&gt;
    if ( o &amp;gt;= 0 )&lt;br /&gt;
    {&lt;br /&gt;
        integer len = llGetListLength(restrictions);&lt;br /&gt;
        integer i;&lt;br /&gt;
        for ( i = 0 ; i &amp;lt; len ; i += 2 )&lt;br /&gt;
        {&lt;br /&gt;
            if ( llList2Integer(restrictions, i) == o )&lt;br /&gt;
            {&lt;br /&gt;
                string restr = llList2String(restrictions, i + 1);&lt;br /&gt;
                if ( llSubStringIndex(restr, param) &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    restrictions = llDeleteSubList(restrictions, i, i + 1);&lt;br /&gt;
                    if ( llListFindList(restrictions, [restr]) &amp;lt; 0 )&lt;br /&gt;
                        llOwnerSay(&amp;quot;@&amp;quot; + restr + &amp;quot;=y&amp;quot;);&lt;br /&gt;
                    i -= 2;&lt;br /&gt;
                    len -= 2;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    if ( llGetListLength(restrictions) == 0 )&lt;br /&gt;
    {&lt;br /&gt;
        objects = [];&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
rlvCommand(key id, string cmd)&lt;br /&gt;
{&lt;br /&gt;
    integer e = llSubStringIndex(cmd, &amp;quot;=&amp;quot;);&lt;br /&gt;
    if ( e &amp;gt;= 0 )&lt;br /&gt;
    {&lt;br /&gt;
        string restr = llGetSubString(cmd, 1, e - 1);&lt;br /&gt;
        string param = llGetSubString(cmd, e + 1, -1);&lt;br /&gt;
        if ( param == &amp;quot;n&amp;quot; || param == &amp;quot;add&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            llOwnerSay(cmd);&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer o = llListFindList(objects, [id]);&lt;br /&gt;
            if ( o &amp;lt; 0 )&lt;br /&gt;
            {&lt;br /&gt;
                o = llGetListLength(objects);&lt;br /&gt;
                objects += id;&lt;br /&gt;
                i = -1;&lt;br /&gt;
            }&lt;br /&gt;
            else i = llListFindList(restrictions, [o, restr]);&lt;br /&gt;
            if ( i &amp;lt; 0 )&lt;br /&gt;
            {&lt;br /&gt;
                restrictions += [o, restr];&lt;br /&gt;
                updateStatus(TRUE);&lt;br /&gt;
            }&lt;br /&gt;
            if ( restr == &amp;quot;unsit&amp;quot; )&lt;br /&gt;
                llOwnerSay(&amp;quot;@getsitid=&amp;quot; + (string)backChannel);&lt;br /&gt;
        }&lt;br /&gt;
        else if ( param == &amp;quot;y&amp;quot; || param == &amp;quot;rem&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            integer o = llListFindList(objects, [id]);&lt;br /&gt;
            if ( o &amp;gt;= 0 )&lt;br /&gt;
            {&lt;br /&gt;
                integer i = llListFindList(restrictions, [o, restr]);&lt;br /&gt;
                if ( i &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    restrictions = llDeleteSubList(restrictions, i, i + 1);&lt;br /&gt;
                    if ( llGetListLength(restrictions) == 0 )&lt;br /&gt;
                    {&lt;br /&gt;
                        objects = [];&lt;br /&gt;
                        updateStatus(FALSE);&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            if ( llListFindList(restrictions, [restr]) &amp;lt; 0 )&lt;br /&gt;
                llOwnerSay(cmd);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            if ( restr == &amp;quot;clear&amp;quot; )&lt;br /&gt;
                clearSome(id, param);&lt;br /&gt;
            else&lt;br /&gt;
                llOwnerSay(cmd);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if ( cmd == &amp;quot;@clear&amp;quot; )&lt;br /&gt;
            clear(id);&lt;br /&gt;
        else&lt;br /&gt;
            llOwnerSay(cmd);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string getStatus(integer o) // it&#039;s okay if o is not an existing object, or -1, we just result an empty string&lt;br /&gt;
{&lt;br /&gt;
    string result = &amp;quot;&amp;quot;;&lt;br /&gt;
    integer len = llGetListLength(restrictions);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for ( i = 0 ; i &amp;lt; len ; i += 2 )&lt;br /&gt;
        if ( llList2Integer(restrictions, i) == o )&lt;br /&gt;
            result += &amp;quot;/&amp;quot; + llList2String(restrictions, i + 1);&lt;br /&gt;
    return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer allowCommand(key id, string cmd)&lt;br /&gt;
{&lt;br /&gt;
    if ( ! askMode ) return TRUE;                                 // not in ask mode, automatically allow&lt;br /&gt;
    if ( llListFindList(allowedObjects, [id]) &amp;gt;= 0 ) return TRUE; // this object has permission&lt;br /&gt;
    if ( llGetOwnerKey(id) == llGetOwner() ) return TRUE;         // owner&#039;s own objects always have permission&lt;br /&gt;
    if ( llGetSubString(cmd, -2, -1) == &amp;quot;=n&amp;quot; ) return FALSE;      // adding restrictions not allowed without permission&lt;br /&gt;
    if ( llGetSubString(cmd, -4, -1) == &amp;quot;=add&amp;quot; ) return FALSE;    // adding restrictions not allowed without permission&lt;br /&gt;
    if ( llGetSubString(cmd, -6, -1) == &amp;quot;=force&amp;quot; ) return FALSE;  // forcing actions not allowed without permission&lt;br /&gt;
    return TRUE;                                                  // anything else is okay (e.g. @version)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSetObjectName(implversion);&lt;br /&gt;
        &lt;br /&gt;
        lit = TRUE;&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
        &lt;br /&gt;
        llListen(relayChannel, &amp;quot;&amp;quot;, NULL_KEY, &amp;quot;&amp;quot;);&lt;br /&gt;
        llListen(backChannel = 16777216 + (integer)llFrand(16777216.0), &amp;quot;&amp;quot;, llGetOwner(), &amp;quot;&amp;quot;);&lt;br /&gt;
        llSetTimerEvent(5.0);&lt;br /&gt;
        &lt;br /&gt;
        llMessageLinked(LINK_SET, -123, llGetScriptName() + &amp;quot; free: &amp;quot; + (string)llGetFreeMemory(), NULL_KEY);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    listen(integer ch, string name, key id, string msg)&lt;br /&gt;
    {&lt;br /&gt;
        if ( ch == relayChannel )&lt;br /&gt;
        {&lt;br /&gt;
            list pack = llCSV2List(msg);&lt;br /&gt;
            key target = llList2String(pack, 1);&lt;br /&gt;
            if ( target == llGetOwner() )&lt;br /&gt;
            {&lt;br /&gt;
                string cmdid = llList2String(pack, 0);&lt;br /&gt;
                list cmds = llParseString2List(llList2String(pack, 2), [&amp;quot;|&amp;quot;], []);&lt;br /&gt;
                integer len = llGetListLength(cmds);&lt;br /&gt;
                integer i;&lt;br /&gt;
                for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                {&lt;br /&gt;
                    string cmd = llList2String(cmds, i);&lt;br /&gt;
                    if ( llGetSubString(cmd, 0, 0) == &amp;quot;@&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        if ( allowCommand(id, cmd) )&lt;br /&gt;
                        {&lt;br /&gt;
                            rlvCommand(id, cmd);&lt;br /&gt;
                            llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ok&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
                        else if ( llListFindList(rejectedObjects, [id]) &amp;gt;= 0 )&lt;br /&gt;
                        {&lt;br /&gt;
                            llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ko&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
                        else&lt;br /&gt;
                        {&lt;br /&gt;
                            integer p = llListFindList(pendingObjects, [id]);&lt;br /&gt;
                            if ( p &amp;lt; 0 )&lt;br /&gt;
                            {&lt;br /&gt;
                                p = llGetListLength(pendingObjects);&lt;br /&gt;
                                pendingObjects += id;&lt;br /&gt;
                                &lt;br /&gt;
                                list buttons;&lt;br /&gt;
                                if ( p )&lt;br /&gt;
                                    buttons = [&amp;quot;Yes &amp;quot; + (string)p, &amp;quot;No &amp;quot; + (string)p];&lt;br /&gt;
                                else&lt;br /&gt;
                                    buttons = [&amp;quot;Yes&amp;quot;, &amp;quot;No&amp;quot;];&lt;br /&gt;
                                string object = llKey2Name(id);&lt;br /&gt;
                                string ownedby = llKey2Name(llGetOwnerKey(id));&lt;br /&gt;
                                if ( ownedby ) object += &amp;quot; (owned by &amp;quot; + ownedby + &amp;quot;)&amp;quot;;&lt;br /&gt;
                                if ( ! permListener )&lt;br /&gt;
                                    permListener = llListen(permChannel = -16777216 - (integer)llFrand(16777216.0), &amp;quot;&amp;quot;, llGetOwner(), &amp;quot;&amp;quot;);&lt;br /&gt;
                                llDialog(llGetOwner(), &amp;quot;The object &amp;quot; + object&lt;br /&gt;
                                    + &amp;quot; is attempting to use your Restrained Life Viewer relay.  Do you wish to allow it?&amp;quot;, buttons, permChannel);&lt;br /&gt;
                                permClose = llGetUnixTime() + 120;&lt;br /&gt;
                            }&lt;br /&gt;
                            if ( llListFindList(pendingCommands, [p, cmdid, cmd]) &amp;lt; 0 ) // some devices spam the same command over and over, don&#039;t keep growing list&lt;br /&gt;
                                pendingCommands += [p, cmdid, cmd];&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!release&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        clear(id);&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ok&amp;quot;);&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!getstatus&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        integer o = llListFindList(objects, [id]);&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,&amp;quot; + getStatus(o));&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!version&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,&amp;quot; + version);&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!implversion&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,&amp;quot; + implversion);&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!pong&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        integer p = llListFindList(pingObjects, [id]);&lt;br /&gt;
                        if ( p &amp;gt;= 0 )&lt;br /&gt;
                        {&lt;br /&gt;
                            llOwnerSay(&amp;quot;Got pong, you&#039;re out of luck.  Reapplying restrictions from &amp;quot; + name + &amp;quot;...&amp;quot;);&lt;br /&gt;
                            integer o = llListFindList(objects, [id]);&lt;br /&gt;
                            if ( o &amp;lt; 0 )&lt;br /&gt;
                            {&lt;br /&gt;
                                o = llGetListLength(objects);&lt;br /&gt;
                                objects += id;&lt;br /&gt;
                            }&lt;br /&gt;
                            string cmd = &amp;quot;&amp;quot;;&lt;br /&gt;
                            string pre = &amp;quot;@&amp;quot;;&lt;br /&gt;
                            integer i;&lt;br /&gt;
                            while ( (i = llListFindList(pingRestrictions, [p])) &amp;gt;= 0 )&lt;br /&gt;
                            {&lt;br /&gt;
                                string restr = llList2String(pingRestrictions, i + 1);&lt;br /&gt;
                                if ( restr == &amp;quot;unsit&amp;quot; )&lt;br /&gt;
                                {&lt;br /&gt;
                                    if ( pingSitting )&lt;br /&gt;
                                    {&lt;br /&gt;
                                        llOwnerSay(&amp;quot;@sit:&amp;quot; + (string)pingSitting + &amp;quot;=force&amp;quot;);&lt;br /&gt;
                                        pingSitRetry = 12; // keep trying for a minute -- it can take that long for things to rez&lt;br /&gt;
                                    }&lt;br /&gt;
                                }&lt;br /&gt;
                                cmd += pre + restr + &amp;quot;=n&amp;quot;;&lt;br /&gt;
                                pre = &amp;quot;,&amp;quot;;&lt;br /&gt;
                                restrictions += [o, restr];&lt;br /&gt;
                                pingRestrictions = llDeleteSubList(pingRestrictions, i, i + 1);&lt;br /&gt;
                            }&lt;br /&gt;
                            if ( cmd )&lt;br /&gt;
                                llOwnerSay(cmd);&lt;br /&gt;
                            updateStatus(TRUE);&lt;br /&gt;
                            if ( llGetListLength(pingRestrictions) == 0 )&lt;br /&gt;
                                pingObjects = [];&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            else if ( target == llGetKey() )&lt;br /&gt;
            {&lt;br /&gt;
                string cmdid = llList2String(pack, 0);&lt;br /&gt;
                if ( cmdid == &amp;quot;uniquecheck&amp;quot; )&lt;br /&gt;
                    llOwnerSay(&amp;quot;You are wearing another RLV relay (&amp;quot; + name + &amp;quot;).  Remove it.  You should never wear more than one RLV relay at a time.&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( ch == permChannel )&lt;br /&gt;
        {&lt;br /&gt;
            integer o = (integer) llGetSubString(msg, -2, -1);&lt;br /&gt;
            key obj = llList2Key(pendingObjects, o);&lt;br /&gt;
            if ( llGetSubString(msg, 0, 2) == &amp;quot;Yes&amp;quot; )&lt;br /&gt;
            {&lt;br /&gt;
                allowedObjects = obj + llList2List(allowedObjects, 0, 8);&lt;br /&gt;
                integer i;&lt;br /&gt;
                while ( (i = llListFindList(pendingCommands, [o])) &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    string cmd = llList2String(pendingCommands, i + 2);&lt;br /&gt;
                    rlvCommand(obj, cmd);&lt;br /&gt;
                    llShout(relayChannel, llList2String(pendingCommands, i + 1) + &amp;quot;,&amp;quot; + (string)obj + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ok&amp;quot;);&lt;br /&gt;
                    pendingCommands = llDeleteSubList(pendingCommands, i, i + 2);&lt;br /&gt;
                }&lt;br /&gt;
                if ( llGetListLength(pendingCommands) == 0 )&lt;br /&gt;
                    pendingObjects = [];&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                rejectedObjects = obj + llList2List(rejectedObjects, 0, 8);&lt;br /&gt;
                integer i;&lt;br /&gt;
                while ( (i = llListFindList(pendingCommands, [o])) &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    string cmd = llList2String(pendingCommands, i + 2);&lt;br /&gt;
                    llShout(relayChannel, llList2String(pendingCommands, i + 1) + &amp;quot;,&amp;quot; + (string)obj + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ko&amp;quot;);&lt;br /&gt;
                    pendingCommands = llDeleteSubList(pendingCommands, i, i + 2);&lt;br /&gt;
                }&lt;br /&gt;
                if ( llGetListLength(pendingCommands) == 0 )&lt;br /&gt;
                    pendingObjects = [];&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( ch == backChannel )&lt;br /&gt;
        {&lt;br /&gt;
            sitting = msg;&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    on_rez(integer param)&lt;br /&gt;
    {&lt;br /&gt;
        if ( objects )&lt;br /&gt;
        {&lt;br /&gt;
            integer len = llGetListLength(objects);&lt;br /&gt;
            integer i;&lt;br /&gt;
            for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                if ( llListFindList(restrictions, [i]) &amp;gt;= 0 )&lt;br /&gt;
                    llShout(relayChannel, &amp;quot;ping,&amp;quot; + (string)llList2Key(objects, i) + &amp;quot;,ping,ping&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        pingObjects = objects;&lt;br /&gt;
        pingRestrictions = restrictions;&lt;br /&gt;
        pingSitting = sitting;&lt;br /&gt;
        pingSitRetry = 0;&lt;br /&gt;
        &lt;br /&gt;
        objects = [];&lt;br /&gt;
        restrictions = [];&lt;br /&gt;
        sitting = NULL_KEY;&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
        &lt;br /&gt;
        allowedObjects = [];&lt;br /&gt;
        rejectedObjects = [];&lt;br /&gt;
        pendingObjects = [];&lt;br /&gt;
        pendingCommands = [];&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    timer()&lt;br /&gt;
    {&lt;br /&gt;
        if ( llGetAgentInfo(llGetOwner()) &amp;amp; AGENT_ON_OBJECT )&lt;br /&gt;
        {&lt;br /&gt;
            llOwnerSay(&amp;quot;@getsitid=&amp;quot; + (string)backChannel);&lt;br /&gt;
            pingSitRetry = 0;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            sitting = NULL_KEY;&lt;br /&gt;
            if ( pingSitRetry )&lt;br /&gt;
            {&lt;br /&gt;
                llOwnerSay(&amp;quot;@sit:&amp;quot; + (string)pingSitting + &amp;quot;=force&amp;quot;);&lt;br /&gt;
                --pingSitRetry;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( permListener )&lt;br /&gt;
        {&lt;br /&gt;
            if ( llGetUnixTime() &amp;gt;= permClose )&lt;br /&gt;
            {&lt;br /&gt;
                pendingObjects = [];&lt;br /&gt;
                pendingCommands = [];&lt;br /&gt;
                llListenRemove(permListener);&lt;br /&gt;
                permListener = 0;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    link_message(integer src, integer num, string msg, key id)&lt;br /&gt;
    {&lt;br /&gt;
        if ( msg == &amp;quot;relay-ask&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            askMode = num;&lt;br /&gt;
            if ( askMode )&lt;br /&gt;
            {&lt;br /&gt;
                allowedObjects = objects;&lt;br /&gt;
                rejectedObjects = [];&lt;br /&gt;
                pendingObjects = [];&lt;br /&gt;
                pendingCommands = [];&lt;br /&gt;
            }&lt;br /&gt;
            else if ( permListener )&lt;br /&gt;
            {&lt;br /&gt;
                allowedObjects = [];&lt;br /&gt;
                rejectedObjects = [];&lt;br /&gt;
                pendingObjects = [];&lt;br /&gt;
                pendingCommands = [];&lt;br /&gt;
                llListenRemove(permListener);&lt;br /&gt;
                permListener = 0;&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( msg == &amp;quot;relay-status&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            integer len = llGetListLength(objects);&lt;br /&gt;
            if ( len )&lt;br /&gt;
            {&lt;br /&gt;
                integer i;&lt;br /&gt;
                for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                    llMessageLinked(LINK_SET, num, getStatus(i), llList2Key(objects, i));&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
                llMessageLinked(LINK_SET, num, &amp;quot;&amp;quot;, NULL_KEY);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( msg == &amp;quot;relay-reset&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            integer len = llGetListLength(objects);&lt;br /&gt;
            integer i;&lt;br /&gt;
            for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                llShout(relayChannel, &amp;quot;safeword,&amp;quot; + (string)llList2Key(objects, i) + &amp;quot;,!release,ok&amp;quot;);&lt;br /&gt;
            llResetScript();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    attach(key id)&lt;br /&gt;
    {&lt;br /&gt;
        if ( id )&lt;br /&gt;
            llWhisper(relayChannel, &amp;quot;uniquecheck,&amp;quot; + (string)id + &amp;quot;,!version&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if ( change &amp;amp; CHANGED_OWNER )&lt;br /&gt;
            llResetScript();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;/div&gt;</summary>
		<author><name>Julia Banshee</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=Talk:LSL_Protocol/Restrained_Living_Relay/Other_Implementations/Dominatech_RLV_Relay&amp;diff=237932</id>
		<title>Talk:LSL Protocol/Restrained Living Relay/Other Implementations/Dominatech RLV Relay</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=Talk:LSL_Protocol/Restrained_Living_Relay/Other_Implementations/Dominatech_RLV_Relay&amp;diff=237932"/>
		<updated>2009-02-14T08:37:04Z</updated>

		<summary type="html">&lt;p&gt;Julia Banshee: New page: == Issues with multi-device relays ==  There&amp;#039;s a couple of issues that people need to consider now that multi-device relays are becoming available.  First, it used to be you could assume t...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Issues with multi-device relays ==&lt;br /&gt;
&lt;br /&gt;
There&#039;s a couple of issues that people need to consider now that multi-device relays are becoming available.&lt;br /&gt;
&lt;br /&gt;
First, it used to be you could assume that if someone&#039;s relay would talk to you and take commands, they were not otherwise restricted.  This is obviously no longer the case.  Don&#039;t assume someone has no restrictions just because their relay responds to you.&lt;br /&gt;
&lt;br /&gt;
Second, any relay that supports an arbitrary number of devices using a finite number of prims ought to have some way to report the status back to a device of only the restrictions coming from that device.  The usual @getstatus is insufficient for this task, since that will tell you every restriction from the relay, not from the device, since the reply will come from the client rather than the relay.  And a relay can&#039;t simply intercept and reply to @getstatus itself since will be listening for the response to come from the avatar.  Hence, my proposed !getstatus command.  Using multiple prims on the relay works only to a point.  No matter what N you choose, sooner or later someone&#039;s going to want N+1, and having all those scripts running at once to handle a task that could just as well be handled by one doesn&#039;t strike me as Grid-friendly.&lt;br /&gt;
&lt;br /&gt;
Thoughts?&lt;br /&gt;
&lt;br /&gt;
--[[User:Julia Banshee|Julia Banshee]] 08:37, 14 February 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>Julia Banshee</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Living_Relay/Other_Implementations/Dominatech_RLV_Relay&amp;diff=237922</id>
		<title>LSL Protocol/Restrained Living Relay/Other Implementations/Dominatech RLV Relay</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Living_Relay/Other_Implementations/Dominatech_RLV_Relay&amp;diff=237922"/>
		<updated>2009-02-14T08:21:00Z</updated>

		<summary type="html">&lt;p&gt;Julia Banshee: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Restrained Life Relay Specs TOC}}&lt;br /&gt;
&lt;br /&gt;
== Dominatech RLV Relay ==&lt;br /&gt;
&amp;amp;copy; 2009 Julia Banshee&lt;br /&gt;
&lt;br /&gt;
This is an open source RLV relay script that supports relaying from multiple devices.&lt;br /&gt;
&lt;br /&gt;
It it fully compatible with version 1.030 of the RLV Relay Specification, but has one non-standard extention, a &amp;quot;!getstatus&amp;quot; command that returns the restrictions held only by the one device requesting the status.  This (or similar functionality) has been proposed for inclusion in a future version of the official specification.&lt;br /&gt;
&lt;br /&gt;
So without further ado...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// Dominatech RLV Relay Script 2.0&lt;br /&gt;
// Copyright (C) 2009 Julia Banshee&lt;br /&gt;
//&lt;br /&gt;
// This program is free software: you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// See http://www.gnu.org/licenses/gpl.html for terms of this license.&lt;br /&gt;
&lt;br /&gt;
integer relayChannel = -1812221819;&lt;br /&gt;
string version = &amp;quot;1030&amp;quot;;&lt;br /&gt;
string implversion = &amp;quot;Dominatech Relay 2.0&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
integer backChannel; // for @getsitid&lt;br /&gt;
key sitting;&lt;br /&gt;
&lt;br /&gt;
list objects;&lt;br /&gt;
list restrictions;&lt;br /&gt;
&lt;br /&gt;
list pingObjects;&lt;br /&gt;
list pingRestrictions;&lt;br /&gt;
key pingSitting;&lt;br /&gt;
integer pingSitRetry;&lt;br /&gt;
&lt;br /&gt;
integer lit;&lt;br /&gt;
&lt;br /&gt;
integer askMode;&lt;br /&gt;
list allowedObjects;&lt;br /&gt;
list rejectedObjects;&lt;br /&gt;
list pendingObjects;&lt;br /&gt;
list pendingCommands;&lt;br /&gt;
&lt;br /&gt;
integer permChannel;&lt;br /&gt;
integer permListener;&lt;br /&gt;
integer permClose;&lt;br /&gt;
&lt;br /&gt;
updateStatus(integer r)&lt;br /&gt;
{&lt;br /&gt;
    if ( r )&lt;br /&gt;
    {&lt;br /&gt;
        if ( ! lit )&lt;br /&gt;
        {&lt;br /&gt;
            llMessageLinked(LINK_SET, TRUE, &amp;quot;relay-lock&amp;quot;, NULL_KEY);&lt;br /&gt;
            llSetColor(&amp;lt;1.0, 0.0, 0.0&amp;gt;, ALL_SIDES);&lt;br /&gt;
            lit = TRUE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if ( lit )&lt;br /&gt;
        {&lt;br /&gt;
            llMessageLinked(LINK_SET, FALSE, &amp;quot;relay-lock&amp;quot;, NULL_KEY);&lt;br /&gt;
            llSetColor(&amp;lt;0.0, 1.0, 0.0&amp;gt;, ALL_SIDES);&lt;br /&gt;
            lit = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
clear(key obj)&lt;br /&gt;
{&lt;br /&gt;
    integer o = llListFindList(objects, [obj]);&lt;br /&gt;
    if ( o &amp;gt;= 0 )&lt;br /&gt;
    {&lt;br /&gt;
        integer i;&lt;br /&gt;
        while ( (i = llListFindList(restrictions, [o])) &amp;gt;= 0 )&lt;br /&gt;
        {&lt;br /&gt;
            string restr = llList2String(restrictions, i + 1);&lt;br /&gt;
            restrictions = llDeleteSubList(restrictions, i, i + 1);&lt;br /&gt;
            if ( llListFindList(restrictions, [restr]) &amp;lt; 0 )&lt;br /&gt;
                llOwnerSay(&amp;quot;@&amp;quot; + restr + &amp;quot;=y&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    if ( llGetListLength(restrictions) == 0 )&lt;br /&gt;
    {&lt;br /&gt;
        objects = [];&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
clearSome(key obj, string param)&lt;br /&gt;
{&lt;br /&gt;
    integer o = llListFindList(objects, [obj]);&lt;br /&gt;
    if ( o &amp;gt;= 0 )&lt;br /&gt;
    {&lt;br /&gt;
        integer len = llGetListLength(restrictions);&lt;br /&gt;
        integer i;&lt;br /&gt;
        for ( i = 0 ; i &amp;lt; len ; i += 2 )&lt;br /&gt;
        {&lt;br /&gt;
            if ( llList2Integer(restrictions, i) == o )&lt;br /&gt;
            {&lt;br /&gt;
                string restr = llList2String(restrictions, i + 1);&lt;br /&gt;
                if ( llSubStringIndex(restr, param) &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    restrictions = llDeleteSubList(restrictions, i, i + 1);&lt;br /&gt;
                    if ( llListFindList(restrictions, [restr]) &amp;lt; 0 )&lt;br /&gt;
                        llOwnerSay(&amp;quot;@&amp;quot; + restr + &amp;quot;=y&amp;quot;);&lt;br /&gt;
                    i -= 2;&lt;br /&gt;
                    len -= 2;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    if ( llGetListLength(restrictions) == 0 )&lt;br /&gt;
    {&lt;br /&gt;
        objects = [];&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
rlvCommand(key id, string cmd)&lt;br /&gt;
{&lt;br /&gt;
    integer e = llSubStringIndex(cmd, &amp;quot;=&amp;quot;);&lt;br /&gt;
    if ( e &amp;gt;= 0 )&lt;br /&gt;
    {&lt;br /&gt;
        string restr = llGetSubString(cmd, 1, e - 1);&lt;br /&gt;
        string param = llGetSubString(cmd, e + 1, -1);&lt;br /&gt;
        if ( param == &amp;quot;n&amp;quot; || param == &amp;quot;add&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            llOwnerSay(cmd);&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer o = llListFindList(objects, [id]);&lt;br /&gt;
            if ( o &amp;lt; 0 )&lt;br /&gt;
            {&lt;br /&gt;
                o = llGetListLength(objects);&lt;br /&gt;
                objects += id;&lt;br /&gt;
                i = -1;&lt;br /&gt;
            }&lt;br /&gt;
            else i = llListFindList(restrictions, [o, restr]);&lt;br /&gt;
            if ( i &amp;lt; 0 )&lt;br /&gt;
            {&lt;br /&gt;
                restrictions += [o, restr];&lt;br /&gt;
                updateStatus(TRUE);&lt;br /&gt;
            }&lt;br /&gt;
            if ( restr == &amp;quot;unsit&amp;quot; )&lt;br /&gt;
                llOwnerSay(&amp;quot;@getsitid=&amp;quot; + (string)backChannel);&lt;br /&gt;
        }&lt;br /&gt;
        else if ( param == &amp;quot;y&amp;quot; || param == &amp;quot;rem&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            integer o = llListFindList(objects, [id]);&lt;br /&gt;
            if ( o &amp;gt;= 0 )&lt;br /&gt;
            {&lt;br /&gt;
                integer i = llListFindList(restrictions, [o, restr]);&lt;br /&gt;
                if ( i &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    restrictions = llDeleteSubList(restrictions, i, i + 1);&lt;br /&gt;
                    if ( llGetListLength(restrictions) == 0 )&lt;br /&gt;
                    {&lt;br /&gt;
                        objects = [];&lt;br /&gt;
                        updateStatus(FALSE);&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            if ( llListFindList(restrictions, [restr]) &amp;lt; 0 )&lt;br /&gt;
                llOwnerSay(cmd);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            if ( restr == &amp;quot;clear&amp;quot; )&lt;br /&gt;
                clearSome(id, param);&lt;br /&gt;
            else&lt;br /&gt;
                llOwnerSay(cmd);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if ( cmd == &amp;quot;@clear&amp;quot; )&lt;br /&gt;
            clear(id);&lt;br /&gt;
        else&lt;br /&gt;
            llOwnerSay(cmd);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string getStatus(integer o) // it&#039;s okay if o is not an existing object, or -1, we just result an empty string&lt;br /&gt;
{&lt;br /&gt;
    string result = &amp;quot;&amp;quot;;&lt;br /&gt;
    integer len = llGetListLength(restrictions);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for ( i = 0 ; i &amp;lt; len ; i += 2 )&lt;br /&gt;
        if ( llList2Integer(restrictions, i) == o )&lt;br /&gt;
            result += &amp;quot;/&amp;quot; + llList2String(restrictions, i + 1);&lt;br /&gt;
    return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer allowCommand(key id, string cmd)&lt;br /&gt;
{&lt;br /&gt;
    if ( ! askMode ) return TRUE;                                 // not in ask mode, automatically allow&lt;br /&gt;
    if ( llListFindList(allowedObjects, [id]) &amp;gt;= 0 ) return TRUE; // this object has permission&lt;br /&gt;
    if ( llGetOwnerKey(id) == llGetOwner() ) return TRUE;         // owner&#039;s own objects always have permission&lt;br /&gt;
    if ( llGetSubString(cmd, -2, -1) == &amp;quot;=n&amp;quot; ) return FALSE;      // adding restrictions not allowed without permission&lt;br /&gt;
    if ( llGetSubString(cmd, -4, -1) == &amp;quot;=add&amp;quot; ) return FALSE;    // adding restrictions not allowed without permission&lt;br /&gt;
    if ( llGetSubString(cmd, -6, -1) == &amp;quot;=force&amp;quot; ) return FALSE;  // forcing actions not allowed without permission&lt;br /&gt;
    return TRUE;                                                  // anything else is okay (e.g. @version)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSetObjectName(implversion);&lt;br /&gt;
        &lt;br /&gt;
        lit = TRUE;&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
        &lt;br /&gt;
        llListen(relayChannel, &amp;quot;&amp;quot;, NULL_KEY, &amp;quot;&amp;quot;);&lt;br /&gt;
        llListen(backChannel = 16777216 + (integer)llFrand(16777216.0), &amp;quot;&amp;quot;, llGetOwner(), &amp;quot;&amp;quot;);&lt;br /&gt;
        llSetTimerEvent(5.0);&lt;br /&gt;
        &lt;br /&gt;
        llMessageLinked(LINK_SET, -123, llGetScriptName() + &amp;quot; free: &amp;quot; + (string)llGetFreeMemory(), NULL_KEY);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    listen(integer ch, string name, key id, string msg)&lt;br /&gt;
    {&lt;br /&gt;
        if ( ch == relayChannel )&lt;br /&gt;
        {&lt;br /&gt;
            list pack = llCSV2List(msg);&lt;br /&gt;
            key target = llList2String(pack, 1);&lt;br /&gt;
            if ( target == llGetOwner() )&lt;br /&gt;
            {&lt;br /&gt;
                string cmdid = llList2String(pack, 0);&lt;br /&gt;
                list cmds = llParseString2List(llList2String(pack, 2), [&amp;quot;|&amp;quot;], []);&lt;br /&gt;
                integer len = llGetListLength(cmds);&lt;br /&gt;
                integer i;&lt;br /&gt;
                for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                {&lt;br /&gt;
                    string cmd = llList2String(cmds, i);&lt;br /&gt;
                    if ( llGetSubString(cmd, 0, 0) == &amp;quot;@&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        if ( allowCommand(id, cmd) )&lt;br /&gt;
                        {&lt;br /&gt;
                            rlvCommand(id, cmd);&lt;br /&gt;
                            llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ok&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
                        else if ( llListFindList(rejectedObjects, [id]) &amp;gt;= 0 )&lt;br /&gt;
                        {&lt;br /&gt;
                            llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ko&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
                        else&lt;br /&gt;
                        {&lt;br /&gt;
                            integer p = llListFindList(pendingObjects, [id]);&lt;br /&gt;
                            if ( p &amp;lt; 0 )&lt;br /&gt;
                            {&lt;br /&gt;
                                p = llGetListLength(pendingObjects);&lt;br /&gt;
                                pendingObjects += id;&lt;br /&gt;
                                &lt;br /&gt;
                                list buttons;&lt;br /&gt;
                                if ( p )&lt;br /&gt;
                                    buttons = [&amp;quot;Yes &amp;quot; + (string)p, &amp;quot;No &amp;quot; + (string)p];&lt;br /&gt;
                                else&lt;br /&gt;
                                    buttons = [&amp;quot;Yes&amp;quot;, &amp;quot;No&amp;quot;];&lt;br /&gt;
                                string object = llKey2Name(id);&lt;br /&gt;
                                string ownedby = llKey2Name(llGetOwnerKey(id));&lt;br /&gt;
                                if ( ownedby ) object += &amp;quot; (owned by &amp;quot; + ownedby + &amp;quot;)&amp;quot;;&lt;br /&gt;
                                if ( ! permListener )&lt;br /&gt;
                                    permListener = llListen(permChannel = -16777216 - (integer)llFrand(16777216.0), &amp;quot;&amp;quot;, llGetOwner(), &amp;quot;&amp;quot;);&lt;br /&gt;
                                llDialog(llGetOwner(), &amp;quot;The object &amp;quot; + object&lt;br /&gt;
                                    + &amp;quot; is attempting to use your Restrained Life Viewer relay.  Do you wish to allow it?&amp;quot;, buttons, permChannel);&lt;br /&gt;
                                permClose = llGetUnixTime() + 120;&lt;br /&gt;
                            }&lt;br /&gt;
                            if ( llListFindList(pendingCommands, [p, cmdid, cmd]) &amp;lt; 0 ) // some devices spam the same command over and over, don&#039;t keep growing list&lt;br /&gt;
                                pendingCommands += [p, cmdid, cmd];&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!release&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        clear(id);&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ok&amp;quot;);&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!getstatus&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        integer o = llListFindList(objects, [id]);&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,&amp;quot; + getStatus(o));&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!version&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,&amp;quot; + version);&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!implversion&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,&amp;quot; + implversion);&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!pong&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        integer p = llListFindList(pingObjects, [id]);&lt;br /&gt;
                        if ( p &amp;gt;= 0 )&lt;br /&gt;
                        {&lt;br /&gt;
                            llOwnerSay(&amp;quot;Got pong, you&#039;re out of luck.  Reapplying restrictions from &amp;quot; + name + &amp;quot;...&amp;quot;);&lt;br /&gt;
                            integer o = llListFindList(objects, [id]);&lt;br /&gt;
                            if ( o &amp;lt; 0 )&lt;br /&gt;
                            {&lt;br /&gt;
                                o = llGetListLength(objects);&lt;br /&gt;
                                objects += id;&lt;br /&gt;
                            }&lt;br /&gt;
                            string cmd = &amp;quot;&amp;quot;;&lt;br /&gt;
                            string pre = &amp;quot;@&amp;quot;;&lt;br /&gt;
                            integer i;&lt;br /&gt;
                            while ( (i = llListFindList(pingRestrictions, [p])) &amp;gt;= 0 )&lt;br /&gt;
                            {&lt;br /&gt;
                                string restr = llList2String(pingRestrictions, i + 1);&lt;br /&gt;
                                if ( restr == &amp;quot;unsit&amp;quot; )&lt;br /&gt;
                                {&lt;br /&gt;
                                    if ( pingSitting )&lt;br /&gt;
                                    {&lt;br /&gt;
                                        llOwnerSay(&amp;quot;@sit:&amp;quot; + (string)pingSitting + &amp;quot;=force&amp;quot;);&lt;br /&gt;
                                        pingSitRetry = 12; // keep trying for a minute -- it can take that long for things to rez&lt;br /&gt;
                                    }&lt;br /&gt;
                                }&lt;br /&gt;
                                cmd += pre + restr + &amp;quot;=n&amp;quot;;&lt;br /&gt;
                                pre = &amp;quot;,&amp;quot;;&lt;br /&gt;
                                restrictions += [o, restr];&lt;br /&gt;
                                pingRestrictions = llDeleteSubList(pingRestrictions, i, i + 1);&lt;br /&gt;
                            }&lt;br /&gt;
                            if ( cmd )&lt;br /&gt;
                                llOwnerSay(cmd);&lt;br /&gt;
                            updateStatus(TRUE);&lt;br /&gt;
                            if ( llGetListLength(pingRestrictions) == 0 )&lt;br /&gt;
                                pingObjects = [];&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            else if ( target == llGetKey() )&lt;br /&gt;
            {&lt;br /&gt;
                string cmdid = llList2String(pack, 0);&lt;br /&gt;
                if ( cmdid == &amp;quot;uniquecheck&amp;quot; )&lt;br /&gt;
                    llOwnerSay(&amp;quot;You are wearing another RLV relay (&amp;quot; + name + &amp;quot;).  Remove it.  You should never wear more than one RLV relay at a time.&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( ch == permChannel )&lt;br /&gt;
        {&lt;br /&gt;
            integer o = (integer) llGetSubString(msg, -2, -1);&lt;br /&gt;
            key obj = llList2Key(pendingObjects, o);&lt;br /&gt;
            if ( llGetSubString(msg, 0, 2) == &amp;quot;Yes&amp;quot; )&lt;br /&gt;
            {&lt;br /&gt;
                allowedObjects = obj + llList2List(allowedObjects, 0, 8);&lt;br /&gt;
                integer i;&lt;br /&gt;
                while ( (i = llListFindList(pendingCommands, [o])) &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    string cmd = llList2String(pendingCommands, i + 2);&lt;br /&gt;
                    rlvCommand(obj, cmd);&lt;br /&gt;
                    llShout(relayChannel, llList2String(pendingCommands, i + 1) + &amp;quot;,&amp;quot; + (string)obj + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ok&amp;quot;);&lt;br /&gt;
                    pendingCommands = llDeleteSubList(pendingCommands, i, i + 2);&lt;br /&gt;
                }&lt;br /&gt;
                if ( llGetListLength(pendingCommands) == 0 )&lt;br /&gt;
                    pendingObjects = [];&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                rejectedObjects = obj + llList2List(rejectedObjects, 0, 8);&lt;br /&gt;
                integer i;&lt;br /&gt;
                while ( (i = llListFindList(pendingCommands, [o])) &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    string cmd = llList2String(pendingCommands, i + 2);&lt;br /&gt;
                    llShout(relayChannel, llList2String(pendingCommands, i + 1) + &amp;quot;,&amp;quot; + (string)obj + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ko&amp;quot;);&lt;br /&gt;
                    pendingCommands = llDeleteSubList(pendingCommands, i, i + 2);&lt;br /&gt;
                }&lt;br /&gt;
                if ( llGetListLength(pendingCommands) == 0 )&lt;br /&gt;
                    pendingObjects = [];&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( ch == backChannel )&lt;br /&gt;
        {&lt;br /&gt;
            sitting = msg;&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    on_rez(integer param)&lt;br /&gt;
    {&lt;br /&gt;
        if ( objects )&lt;br /&gt;
        {&lt;br /&gt;
            integer len = llGetListLength(objects);&lt;br /&gt;
            integer i;&lt;br /&gt;
            for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                if ( llListFindList(restrictions, [i]) &amp;gt;= 0 )&lt;br /&gt;
                    llShout(relayChannel, &amp;quot;ping,&amp;quot; + (string)llList2Key(objects, i) + &amp;quot;,ping,ping&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        pingObjects = objects;&lt;br /&gt;
        pingRestrictions = restrictions;&lt;br /&gt;
        pingSitting = sitting;&lt;br /&gt;
        pingSitRetry = 0;&lt;br /&gt;
        &lt;br /&gt;
        objects = [];&lt;br /&gt;
        restrictions = [];&lt;br /&gt;
        sitting = NULL_KEY;&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
        &lt;br /&gt;
        allowedObjects = [];&lt;br /&gt;
        rejectedObjects = [];&lt;br /&gt;
        pendingObjects = [];&lt;br /&gt;
        pendingCommands = [];&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    timer()&lt;br /&gt;
    {&lt;br /&gt;
        if ( llGetAgentInfo(llGetOwner()) &amp;amp; AGENT_ON_OBJECT )&lt;br /&gt;
        {&lt;br /&gt;
            llOwnerSay(&amp;quot;@getsitid=&amp;quot; + (string)backChannel);&lt;br /&gt;
            pingSitRetry = 0;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            sitting = NULL_KEY;&lt;br /&gt;
            if ( pingSitRetry )&lt;br /&gt;
            {&lt;br /&gt;
                llOwnerSay(&amp;quot;@sit:&amp;quot; + (string)pingSitting + &amp;quot;=force&amp;quot;);&lt;br /&gt;
                --pingSitRetry;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( permListener )&lt;br /&gt;
        {&lt;br /&gt;
            if ( llGetUnixTime() &amp;gt;= permClose )&lt;br /&gt;
            {&lt;br /&gt;
                pendingObjects = [];&lt;br /&gt;
                pendingCommands = [];&lt;br /&gt;
                llListenRemove(permListener);&lt;br /&gt;
                permListener = 0;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    link_message(integer src, integer num, string msg, key id)&lt;br /&gt;
    {&lt;br /&gt;
        if ( msg == &amp;quot;relay-ask&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            askMode = num;&lt;br /&gt;
            if ( askMode )&lt;br /&gt;
            {&lt;br /&gt;
                allowedObjects = objects;&lt;br /&gt;
                rejectedObjects = [];&lt;br /&gt;
                pendingObjects = [];&lt;br /&gt;
                pendingCommands = [];&lt;br /&gt;
            }&lt;br /&gt;
            else if ( permListener )&lt;br /&gt;
            {&lt;br /&gt;
                allowedObjects = [];&lt;br /&gt;
                rejectedObjects = [];&lt;br /&gt;
                pendingObjects = [];&lt;br /&gt;
                pendingCommands = [];&lt;br /&gt;
                llListenRemove(permListener);&lt;br /&gt;
                permListener = 0;&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( msg == &amp;quot;relay-status&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            integer len = llGetListLength(objects);&lt;br /&gt;
            if ( len )&lt;br /&gt;
            {&lt;br /&gt;
                integer i;&lt;br /&gt;
                for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                    llMessageLinked(LINK_SET, num, getStatus(i), llList2Key(objects, i));&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
                llMessageLinked(LINK_SET, num, &amp;quot;&amp;quot;, NULL_KEY);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( msg == &amp;quot;relay-reset&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            integer len = llGetListLength(objects);&lt;br /&gt;
            integer i;&lt;br /&gt;
            for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                llShout(relayChannel, &amp;quot;safeword,&amp;quot; + (string)llList2Key(objects, i) + &amp;quot;,!release,ok&amp;quot;);&lt;br /&gt;
            llResetScript();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    attach(key id)&lt;br /&gt;
    {&lt;br /&gt;
        if ( id )&lt;br /&gt;
            llWhisper(relayChannel, &amp;quot;uniquecheck,&amp;quot; + (string)id + &amp;quot;,!version&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if ( change &amp;amp; CHANGED_OWNER )&lt;br /&gt;
            llResetScript();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;/div&gt;</summary>
		<author><name>Julia Banshee</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Living_Relay/Other_Implementations/Dominatech_RLV_Relay&amp;diff=237912</id>
		<title>LSL Protocol/Restrained Living Relay/Other Implementations/Dominatech RLV Relay</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Living_Relay/Other_Implementations/Dominatech_RLV_Relay&amp;diff=237912"/>
		<updated>2009-02-14T08:13:03Z</updated>

		<summary type="html">&lt;p&gt;Julia Banshee: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Restrained Life Relay Specs TOC}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
// Dominatech RLV Relay Script 2.0&lt;br /&gt;
// Copyright (C) 2009 Julia Banshee&lt;br /&gt;
//&lt;br /&gt;
// This program is free software: you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// See http://www.gnu.org/licenses/gpl.html for terms of this license.&lt;br /&gt;
&lt;br /&gt;
integer relayChannel = -1812221819;&lt;br /&gt;
string version = &amp;quot;1030&amp;quot;;&lt;br /&gt;
string implversion = &amp;quot;Dominatech Relay 2.0&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
integer backChannel; // for @getsitid&lt;br /&gt;
key sitting;&lt;br /&gt;
&lt;br /&gt;
list objects;&lt;br /&gt;
list restrictions;&lt;br /&gt;
&lt;br /&gt;
list pingObjects;&lt;br /&gt;
list pingRestrictions;&lt;br /&gt;
key pingSitting;&lt;br /&gt;
integer pingSitRetry;&lt;br /&gt;
&lt;br /&gt;
integer lit;&lt;br /&gt;
&lt;br /&gt;
integer askMode;&lt;br /&gt;
list allowedObjects;&lt;br /&gt;
list rejectedObjects;&lt;br /&gt;
list pendingObjects;&lt;br /&gt;
list pendingCommands;&lt;br /&gt;
&lt;br /&gt;
integer permChannel;&lt;br /&gt;
integer permListener;&lt;br /&gt;
integer permClose;&lt;br /&gt;
&lt;br /&gt;
updateStatus(integer r)&lt;br /&gt;
{&lt;br /&gt;
    if ( r )&lt;br /&gt;
    {&lt;br /&gt;
        if ( ! lit )&lt;br /&gt;
        {&lt;br /&gt;
            llMessageLinked(LINK_SET, TRUE, &amp;quot;relay-lock&amp;quot;, NULL_KEY);&lt;br /&gt;
            llSetColor(&amp;lt;1.0, 0.0, 0.0&amp;gt;, ALL_SIDES);&lt;br /&gt;
            lit = TRUE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if ( lit )&lt;br /&gt;
        {&lt;br /&gt;
            llMessageLinked(LINK_SET, FALSE, &amp;quot;relay-lock&amp;quot;, NULL_KEY);&lt;br /&gt;
            llSetColor(&amp;lt;0.0, 1.0, 0.0&amp;gt;, ALL_SIDES);&lt;br /&gt;
            lit = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
clear(key obj)&lt;br /&gt;
{&lt;br /&gt;
    integer o = llListFindList(objects, [obj]);&lt;br /&gt;
    if ( o &amp;gt;= 0 )&lt;br /&gt;
    {&lt;br /&gt;
        integer i;&lt;br /&gt;
        while ( (i = llListFindList(restrictions, [o])) &amp;gt;= 0 )&lt;br /&gt;
        {&lt;br /&gt;
            string restr = llList2String(restrictions, i + 1);&lt;br /&gt;
            restrictions = llDeleteSubList(restrictions, i, i + 1);&lt;br /&gt;
            if ( llListFindList(restrictions, [restr]) &amp;lt; 0 )&lt;br /&gt;
                llOwnerSay(&amp;quot;@&amp;quot; + restr + &amp;quot;=y&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    if ( llGetListLength(restrictions) == 0 )&lt;br /&gt;
    {&lt;br /&gt;
        objects = [];&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
clearSome(key obj, string param)&lt;br /&gt;
{&lt;br /&gt;
    integer o = llListFindList(objects, [obj]);&lt;br /&gt;
    if ( o &amp;gt;= 0 )&lt;br /&gt;
    {&lt;br /&gt;
        integer len = llGetListLength(restrictions);&lt;br /&gt;
        integer i;&lt;br /&gt;
        for ( i = 0 ; i &amp;lt; len ; i += 2 )&lt;br /&gt;
        {&lt;br /&gt;
            if ( llList2Integer(restrictions, i) == o )&lt;br /&gt;
            {&lt;br /&gt;
                string restr = llList2String(restrictions, i + 1);&lt;br /&gt;
                if ( llSubStringIndex(restr, param) &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    restrictions = llDeleteSubList(restrictions, i, i + 1);&lt;br /&gt;
                    if ( llListFindList(restrictions, [restr]) &amp;lt; 0 )&lt;br /&gt;
                        llOwnerSay(&amp;quot;@&amp;quot; + restr + &amp;quot;=y&amp;quot;);&lt;br /&gt;
                    i -= 2;&lt;br /&gt;
                    len -= 2;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    if ( llGetListLength(restrictions) == 0 )&lt;br /&gt;
    {&lt;br /&gt;
        objects = [];&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
rlvCommand(key id, string cmd)&lt;br /&gt;
{&lt;br /&gt;
    integer e = llSubStringIndex(cmd, &amp;quot;=&amp;quot;);&lt;br /&gt;
    if ( e &amp;gt;= 0 )&lt;br /&gt;
    {&lt;br /&gt;
        string restr = llGetSubString(cmd, 1, e - 1);&lt;br /&gt;
        string param = llGetSubString(cmd, e + 1, -1);&lt;br /&gt;
        if ( param == &amp;quot;n&amp;quot; || param == &amp;quot;add&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            llOwnerSay(cmd);&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer o = llListFindList(objects, [id]);&lt;br /&gt;
            if ( o &amp;lt; 0 )&lt;br /&gt;
            {&lt;br /&gt;
                o = llGetListLength(objects);&lt;br /&gt;
                objects += id;&lt;br /&gt;
                i = -1;&lt;br /&gt;
            }&lt;br /&gt;
            else i = llListFindList(restrictions, [o, restr]);&lt;br /&gt;
            if ( i &amp;lt; 0 )&lt;br /&gt;
            {&lt;br /&gt;
                restrictions += [o, restr];&lt;br /&gt;
                updateStatus(TRUE);&lt;br /&gt;
            }&lt;br /&gt;
            if ( restr == &amp;quot;unsit&amp;quot; )&lt;br /&gt;
                llOwnerSay(&amp;quot;@getsitid=&amp;quot; + (string)backChannel);&lt;br /&gt;
        }&lt;br /&gt;
        else if ( param == &amp;quot;y&amp;quot; || param == &amp;quot;rem&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            integer o = llListFindList(objects, [id]);&lt;br /&gt;
            if ( o &amp;gt;= 0 )&lt;br /&gt;
            {&lt;br /&gt;
                integer i = llListFindList(restrictions, [o, restr]);&lt;br /&gt;
                if ( i &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    restrictions = llDeleteSubList(restrictions, i, i + 1);&lt;br /&gt;
                    if ( llGetListLength(restrictions) == 0 )&lt;br /&gt;
                    {&lt;br /&gt;
                        objects = [];&lt;br /&gt;
                        updateStatus(FALSE);&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            if ( llListFindList(restrictions, [restr]) &amp;lt; 0 )&lt;br /&gt;
                llOwnerSay(cmd);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            if ( restr == &amp;quot;clear&amp;quot; )&lt;br /&gt;
                clearSome(id, param);&lt;br /&gt;
            else&lt;br /&gt;
                llOwnerSay(cmd);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if ( cmd == &amp;quot;@clear&amp;quot; )&lt;br /&gt;
            clear(id);&lt;br /&gt;
        else&lt;br /&gt;
            llOwnerSay(cmd);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string getStatus(integer o) // it&#039;s okay if o is not an existing object, or -1, we just result an empty string&lt;br /&gt;
{&lt;br /&gt;
    string result = &amp;quot;&amp;quot;;&lt;br /&gt;
    integer len = llGetListLength(restrictions);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for ( i = 0 ; i &amp;lt; len ; i += 2 )&lt;br /&gt;
        if ( llList2Integer(restrictions, i) == o )&lt;br /&gt;
            result += &amp;quot;/&amp;quot; + llList2String(restrictions, i + 1);&lt;br /&gt;
    return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer allowCommand(key id, string cmd)&lt;br /&gt;
{&lt;br /&gt;
    if ( ! askMode ) return TRUE;                                 // not in ask mode, automatically allow&lt;br /&gt;
    if ( llListFindList(allowedObjects, [id]) &amp;gt;= 0 ) return TRUE; // this object has permission&lt;br /&gt;
    if ( llGetOwnerKey(id) == llGetOwner() ) return TRUE;         // owner&#039;s own objects always have permission&lt;br /&gt;
    if ( llGetSubString(cmd, -2, -1) == &amp;quot;=n&amp;quot; ) return FALSE;      // adding restrictions not allowed without permission&lt;br /&gt;
    if ( llGetSubString(cmd, -4, -1) == &amp;quot;=add&amp;quot; ) return FALSE;    // adding restrictions not allowed without permission&lt;br /&gt;
    if ( llGetSubString(cmd, -6, -1) == &amp;quot;=force&amp;quot; ) return FALSE;  // forcing actions not allowed without permission&lt;br /&gt;
    return TRUE;                                                  // anything else is okay (e.g. @version)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSetObjectName(implversion);&lt;br /&gt;
        &lt;br /&gt;
        lit = TRUE;&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
        &lt;br /&gt;
        llListen(relayChannel, &amp;quot;&amp;quot;, NULL_KEY, &amp;quot;&amp;quot;);&lt;br /&gt;
        llListen(backChannel = 16777216 + (integer)llFrand(16777216.0), &amp;quot;&amp;quot;, llGetOwner(), &amp;quot;&amp;quot;);&lt;br /&gt;
        llSetTimerEvent(5.0);&lt;br /&gt;
        &lt;br /&gt;
        llMessageLinked(LINK_SET, -123, llGetScriptName() + &amp;quot; free: &amp;quot; + (string)llGetFreeMemory(), NULL_KEY);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    listen(integer ch, string name, key id, string msg)&lt;br /&gt;
    {&lt;br /&gt;
        if ( ch == relayChannel )&lt;br /&gt;
        {&lt;br /&gt;
            list pack = llCSV2List(msg);&lt;br /&gt;
            key target = llList2String(pack, 1);&lt;br /&gt;
            if ( target == llGetOwner() )&lt;br /&gt;
            {&lt;br /&gt;
                string cmdid = llList2String(pack, 0);&lt;br /&gt;
                list cmds = llParseString2List(llList2String(pack, 2), [&amp;quot;|&amp;quot;], []);&lt;br /&gt;
                integer len = llGetListLength(cmds);&lt;br /&gt;
                integer i;&lt;br /&gt;
                for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                {&lt;br /&gt;
                    string cmd = llList2String(cmds, i);&lt;br /&gt;
                    if ( llGetSubString(cmd, 0, 0) == &amp;quot;@&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        if ( allowCommand(id, cmd) )&lt;br /&gt;
                        {&lt;br /&gt;
                            rlvCommand(id, cmd);&lt;br /&gt;
                            llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ok&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
                        else if ( llListFindList(rejectedObjects, [id]) &amp;gt;= 0 )&lt;br /&gt;
                        {&lt;br /&gt;
                            llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ko&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
                        else&lt;br /&gt;
                        {&lt;br /&gt;
                            integer p = llListFindList(pendingObjects, [id]);&lt;br /&gt;
                            if ( p &amp;lt; 0 )&lt;br /&gt;
                            {&lt;br /&gt;
                                p = llGetListLength(pendingObjects);&lt;br /&gt;
                                pendingObjects += id;&lt;br /&gt;
                                &lt;br /&gt;
                                list buttons;&lt;br /&gt;
                                if ( p )&lt;br /&gt;
                                    buttons = [&amp;quot;Yes &amp;quot; + (string)p, &amp;quot;No &amp;quot; + (string)p];&lt;br /&gt;
                                else&lt;br /&gt;
                                    buttons = [&amp;quot;Yes&amp;quot;, &amp;quot;No&amp;quot;];&lt;br /&gt;
                                string object = llKey2Name(id);&lt;br /&gt;
                                string ownedby = llKey2Name(llGetOwnerKey(id));&lt;br /&gt;
                                if ( ownedby ) object += &amp;quot; (owned by &amp;quot; + ownedby + &amp;quot;)&amp;quot;;&lt;br /&gt;
                                if ( ! permListener )&lt;br /&gt;
                                    permListener = llListen(permChannel = -16777216 - (integer)llFrand(16777216.0), &amp;quot;&amp;quot;, llGetOwner(), &amp;quot;&amp;quot;);&lt;br /&gt;
                                llDialog(llGetOwner(), &amp;quot;The object &amp;quot; + object&lt;br /&gt;
                                    + &amp;quot; is attempting to use your Restrained Life Viewer relay.  Do you wish to allow it?&amp;quot;, buttons, permChannel);&lt;br /&gt;
                                permClose = llGetUnixTime() + 120;&lt;br /&gt;
                            }&lt;br /&gt;
                            if ( llListFindList(pendingCommands, [p, cmdid, cmd]) &amp;lt; 0 ) // some devices spam the same command over and over, don&#039;t keep growing list&lt;br /&gt;
                                pendingCommands += [p, cmdid, cmd];&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!release&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        clear(id);&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ok&amp;quot;);&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!getstatus&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        integer o = llListFindList(objects, [id]);&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,&amp;quot; + getStatus(o));&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!version&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,&amp;quot; + version);&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!implversion&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,&amp;quot; + implversion);&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!pong&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        integer p = llListFindList(pingObjects, [id]);&lt;br /&gt;
                        if ( p &amp;gt;= 0 )&lt;br /&gt;
                        {&lt;br /&gt;
                            llOwnerSay(&amp;quot;Got pong, you&#039;re out of luck.  Reapplying restrictions from &amp;quot; + name + &amp;quot;...&amp;quot;);&lt;br /&gt;
                            integer o = llListFindList(objects, [id]);&lt;br /&gt;
                            if ( o &amp;lt; 0 )&lt;br /&gt;
                            {&lt;br /&gt;
                                o = llGetListLength(objects);&lt;br /&gt;
                                objects += id;&lt;br /&gt;
                            }&lt;br /&gt;
                            string cmd = &amp;quot;&amp;quot;;&lt;br /&gt;
                            string pre = &amp;quot;@&amp;quot;;&lt;br /&gt;
                            integer i;&lt;br /&gt;
                            while ( (i = llListFindList(pingRestrictions, [p])) &amp;gt;= 0 )&lt;br /&gt;
                            {&lt;br /&gt;
                                string restr = llList2String(pingRestrictions, i + 1);&lt;br /&gt;
                                if ( restr == &amp;quot;unsit&amp;quot; )&lt;br /&gt;
                                {&lt;br /&gt;
                                    if ( pingSitting )&lt;br /&gt;
                                    {&lt;br /&gt;
                                        llOwnerSay(&amp;quot;@sit:&amp;quot; + (string)pingSitting + &amp;quot;=force&amp;quot;);&lt;br /&gt;
                                        pingSitRetry = 12; // keep trying for a minute -- it can take that long for things to rez&lt;br /&gt;
                                    }&lt;br /&gt;
                                }&lt;br /&gt;
                                cmd += pre + restr + &amp;quot;=n&amp;quot;;&lt;br /&gt;
                                pre = &amp;quot;,&amp;quot;;&lt;br /&gt;
                                restrictions += [o, restr];&lt;br /&gt;
                                pingRestrictions = llDeleteSubList(pingRestrictions, i, i + 1);&lt;br /&gt;
                            }&lt;br /&gt;
                            if ( cmd )&lt;br /&gt;
                                llOwnerSay(cmd);&lt;br /&gt;
                            updateStatus(TRUE);&lt;br /&gt;
                            if ( llGetListLength(pingRestrictions) == 0 )&lt;br /&gt;
                                pingObjects = [];&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            else if ( target == llGetKey() )&lt;br /&gt;
            {&lt;br /&gt;
                string cmdid = llList2String(pack, 0);&lt;br /&gt;
                if ( cmdid == &amp;quot;uniquecheck&amp;quot; )&lt;br /&gt;
                    llOwnerSay(&amp;quot;You are wearing another RLV relay (&amp;quot; + name + &amp;quot;).  Remove it.  You should never wear more than one RLV relay at a time.&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( ch == permChannel )&lt;br /&gt;
        {&lt;br /&gt;
            integer o = (integer) llGetSubString(msg, -2, -1);&lt;br /&gt;
            key obj = llList2Key(pendingObjects, o);&lt;br /&gt;
            if ( llGetSubString(msg, 0, 2) == &amp;quot;Yes&amp;quot; )&lt;br /&gt;
            {&lt;br /&gt;
                allowedObjects = obj + llList2List(allowedObjects, 0, 8);&lt;br /&gt;
                integer i;&lt;br /&gt;
                while ( (i = llListFindList(pendingCommands, [o])) &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    string cmd = llList2String(pendingCommands, i + 2);&lt;br /&gt;
                    rlvCommand(obj, cmd);&lt;br /&gt;
                    llShout(relayChannel, llList2String(pendingCommands, i + 1) + &amp;quot;,&amp;quot; + (string)obj + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ok&amp;quot;);&lt;br /&gt;
                    pendingCommands = llDeleteSubList(pendingCommands, i, i + 2);&lt;br /&gt;
                }&lt;br /&gt;
                if ( llGetListLength(pendingCommands) == 0 )&lt;br /&gt;
                    pendingObjects = [];&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                rejectedObjects = obj + llList2List(rejectedObjects, 0, 8);&lt;br /&gt;
                integer i;&lt;br /&gt;
                while ( (i = llListFindList(pendingCommands, [o])) &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    string cmd = llList2String(pendingCommands, i + 2);&lt;br /&gt;
                    llShout(relayChannel, llList2String(pendingCommands, i + 1) + &amp;quot;,&amp;quot; + (string)obj + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ko&amp;quot;);&lt;br /&gt;
                    pendingCommands = llDeleteSubList(pendingCommands, i, i + 2);&lt;br /&gt;
                }&lt;br /&gt;
                if ( llGetListLength(pendingCommands) == 0 )&lt;br /&gt;
                    pendingObjects = [];&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( ch == backChannel )&lt;br /&gt;
        {&lt;br /&gt;
            sitting = msg;&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    on_rez(integer param)&lt;br /&gt;
    {&lt;br /&gt;
        if ( objects )&lt;br /&gt;
        {&lt;br /&gt;
            integer len = llGetListLength(objects);&lt;br /&gt;
            integer i;&lt;br /&gt;
            for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                if ( llListFindList(restrictions, [i]) &amp;gt;= 0 )&lt;br /&gt;
                    llShout(relayChannel, &amp;quot;ping,&amp;quot; + (string)llList2Key(objects, i) + &amp;quot;,ping,ping&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        pingObjects = objects;&lt;br /&gt;
        pingRestrictions = restrictions;&lt;br /&gt;
        pingSitting = sitting;&lt;br /&gt;
        pingSitRetry = 0;&lt;br /&gt;
        &lt;br /&gt;
        objects = [];&lt;br /&gt;
        restrictions = [];&lt;br /&gt;
        sitting = NULL_KEY;&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
        &lt;br /&gt;
        allowedObjects = [];&lt;br /&gt;
        rejectedObjects = [];&lt;br /&gt;
        pendingObjects = [];&lt;br /&gt;
        pendingCommands = [];&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    timer()&lt;br /&gt;
    {&lt;br /&gt;
        if ( llGetAgentInfo(llGetOwner()) &amp;amp; AGENT_ON_OBJECT )&lt;br /&gt;
        {&lt;br /&gt;
            llOwnerSay(&amp;quot;@getsitid=&amp;quot; + (string)backChannel);&lt;br /&gt;
            pingSitRetry = 0;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            sitting = NULL_KEY;&lt;br /&gt;
            if ( pingSitRetry )&lt;br /&gt;
            {&lt;br /&gt;
                llOwnerSay(&amp;quot;@sit:&amp;quot; + (string)pingSitting + &amp;quot;=force&amp;quot;);&lt;br /&gt;
                --pingSitRetry;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( permListener )&lt;br /&gt;
        {&lt;br /&gt;
            if ( llGetUnixTime() &amp;gt;= permClose )&lt;br /&gt;
            {&lt;br /&gt;
                pendingObjects = [];&lt;br /&gt;
                pendingCommands = [];&lt;br /&gt;
                llListenRemove(permListener);&lt;br /&gt;
                permListener = 0;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    link_message(integer src, integer num, string msg, key id)&lt;br /&gt;
    {&lt;br /&gt;
        if ( msg == &amp;quot;relay-ask&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            askMode = num;&lt;br /&gt;
            if ( askMode )&lt;br /&gt;
            {&lt;br /&gt;
                allowedObjects = objects;&lt;br /&gt;
                rejectedObjects = [];&lt;br /&gt;
                pendingObjects = [];&lt;br /&gt;
                pendingCommands = [];&lt;br /&gt;
            }&lt;br /&gt;
            else if ( permListener )&lt;br /&gt;
            {&lt;br /&gt;
                allowedObjects = [];&lt;br /&gt;
                rejectedObjects = [];&lt;br /&gt;
                pendingObjects = [];&lt;br /&gt;
                pendingCommands = [];&lt;br /&gt;
                llListenRemove(permListener);&lt;br /&gt;
                permListener = 0;&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( msg == &amp;quot;relay-status&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            integer len = llGetListLength(objects);&lt;br /&gt;
            if ( len )&lt;br /&gt;
            {&lt;br /&gt;
                integer i;&lt;br /&gt;
                for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                    llMessageLinked(LINK_SET, num, getStatus(i), llList2Key(objects, i));&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
                llMessageLinked(LINK_SET, num, &amp;quot;&amp;quot;, NULL_KEY);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( msg == &amp;quot;relay-reset&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            integer len = llGetListLength(objects);&lt;br /&gt;
            integer i;&lt;br /&gt;
            for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                llShout(relayChannel, &amp;quot;safeword,&amp;quot; + (string)llList2Key(objects, i) + &amp;quot;,!release,ok&amp;quot;);&lt;br /&gt;
            llResetScript();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    attach(key id)&lt;br /&gt;
    {&lt;br /&gt;
        if ( id )&lt;br /&gt;
            llWhisper(relayChannel, &amp;quot;uniquecheck,&amp;quot; + (string)id + &amp;quot;,!version&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if ( change &amp;amp; CHANGED_OWNER )&lt;br /&gt;
            llResetScript();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;/div&gt;</summary>
		<author><name>Julia Banshee</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Living_Relay/Other_Implementations/Dominatech_RLV_Relay&amp;diff=237902</id>
		<title>LSL Protocol/Restrained Living Relay/Other Implementations/Dominatech RLV Relay</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Living_Relay/Other_Implementations/Dominatech_RLV_Relay&amp;diff=237902"/>
		<updated>2009-02-14T08:11:10Z</updated>

		<summary type="html">&lt;p&gt;Julia Banshee: New page: &amp;lt;lsl&amp;gt; // Dominatech RLV Relay Script 2.0 // Copyright (C) 2009 Julia Banshee // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Gen...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;lsl&amp;gt;&lt;br /&gt;
// Dominatech RLV Relay Script 2.0&lt;br /&gt;
// Copyright (C) 2009 Julia Banshee&lt;br /&gt;
//&lt;br /&gt;
// This program is free software: you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// This program is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// See http://www.gnu.org/licenses/gpl.html for terms of this license.&lt;br /&gt;
&lt;br /&gt;
integer relayChannel = -1812221819;&lt;br /&gt;
string version = &amp;quot;1030&amp;quot;;&lt;br /&gt;
string implversion = &amp;quot;Dominatech Relay 2.0&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
integer backChannel; // for @getsitid&lt;br /&gt;
key sitting;&lt;br /&gt;
&lt;br /&gt;
list objects;&lt;br /&gt;
list restrictions;&lt;br /&gt;
&lt;br /&gt;
list pingObjects;&lt;br /&gt;
list pingRestrictions;&lt;br /&gt;
key pingSitting;&lt;br /&gt;
integer pingSitRetry;&lt;br /&gt;
&lt;br /&gt;
integer lit;&lt;br /&gt;
&lt;br /&gt;
integer askMode;&lt;br /&gt;
list allowedObjects;&lt;br /&gt;
list rejectedObjects;&lt;br /&gt;
list pendingObjects;&lt;br /&gt;
list pendingCommands;&lt;br /&gt;
&lt;br /&gt;
integer permChannel;&lt;br /&gt;
integer permListener;&lt;br /&gt;
integer permClose;&lt;br /&gt;
&lt;br /&gt;
updateStatus(integer r)&lt;br /&gt;
{&lt;br /&gt;
    if ( r )&lt;br /&gt;
    {&lt;br /&gt;
        if ( ! lit )&lt;br /&gt;
        {&lt;br /&gt;
            llMessageLinked(LINK_SET, TRUE, &amp;quot;relay-lock&amp;quot;, NULL_KEY);&lt;br /&gt;
            llSetColor(&amp;lt;1.0, 0.0, 0.0&amp;gt;, ALL_SIDES);&lt;br /&gt;
            lit = TRUE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if ( lit )&lt;br /&gt;
        {&lt;br /&gt;
            llMessageLinked(LINK_SET, FALSE, &amp;quot;relay-lock&amp;quot;, NULL_KEY);&lt;br /&gt;
            llSetColor(&amp;lt;0.0, 1.0, 0.0&amp;gt;, ALL_SIDES);&lt;br /&gt;
            lit = FALSE;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
clear(key obj)&lt;br /&gt;
{&lt;br /&gt;
    integer o = llListFindList(objects, [obj]);&lt;br /&gt;
    if ( o &amp;gt;= 0 )&lt;br /&gt;
    {&lt;br /&gt;
        integer i;&lt;br /&gt;
        while ( (i = llListFindList(restrictions, [o])) &amp;gt;= 0 )&lt;br /&gt;
        {&lt;br /&gt;
            string restr = llList2String(restrictions, i + 1);&lt;br /&gt;
            restrictions = llDeleteSubList(restrictions, i, i + 1);&lt;br /&gt;
            if ( llListFindList(restrictions, [restr]) &amp;lt; 0 )&lt;br /&gt;
                llOwnerSay(&amp;quot;@&amp;quot; + restr + &amp;quot;=y&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    if ( llGetListLength(restrictions) == 0 )&lt;br /&gt;
    {&lt;br /&gt;
        objects = [];&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
clearSome(key obj, string param)&lt;br /&gt;
{&lt;br /&gt;
    integer o = llListFindList(objects, [obj]);&lt;br /&gt;
    if ( o &amp;gt;= 0 )&lt;br /&gt;
    {&lt;br /&gt;
        integer len = llGetListLength(restrictions);&lt;br /&gt;
        integer i;&lt;br /&gt;
        for ( i = 0 ; i &amp;lt; len ; i += 2 )&lt;br /&gt;
        {&lt;br /&gt;
            if ( llList2Integer(restrictions, i) == o )&lt;br /&gt;
            {&lt;br /&gt;
                string restr = llList2String(restrictions, i + 1);&lt;br /&gt;
                if ( llSubStringIndex(restr, param) &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    restrictions = llDeleteSubList(restrictions, i, i + 1);&lt;br /&gt;
                    if ( llListFindList(restrictions, [restr]) &amp;lt; 0 )&lt;br /&gt;
                        llOwnerSay(&amp;quot;@&amp;quot; + restr + &amp;quot;=y&amp;quot;);&lt;br /&gt;
                    i -= 2;&lt;br /&gt;
                    len -= 2;&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    if ( llGetListLength(restrictions) == 0 )&lt;br /&gt;
    {&lt;br /&gt;
        objects = [];&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
rlvCommand(key id, string cmd)&lt;br /&gt;
{&lt;br /&gt;
    integer e = llSubStringIndex(cmd, &amp;quot;=&amp;quot;);&lt;br /&gt;
    if ( e &amp;gt;= 0 )&lt;br /&gt;
    {&lt;br /&gt;
        string restr = llGetSubString(cmd, 1, e - 1);&lt;br /&gt;
        string param = llGetSubString(cmd, e + 1, -1);&lt;br /&gt;
        if ( param == &amp;quot;n&amp;quot; || param == &amp;quot;add&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            llOwnerSay(cmd);&lt;br /&gt;
            integer i;&lt;br /&gt;
            integer o = llListFindList(objects, [id]);&lt;br /&gt;
            if ( o &amp;lt; 0 )&lt;br /&gt;
            {&lt;br /&gt;
                o = llGetListLength(objects);&lt;br /&gt;
                objects += id;&lt;br /&gt;
                i = -1;&lt;br /&gt;
            }&lt;br /&gt;
            else i = llListFindList(restrictions, [o, restr]);&lt;br /&gt;
            if ( i &amp;lt; 0 )&lt;br /&gt;
            {&lt;br /&gt;
                restrictions += [o, restr];&lt;br /&gt;
                updateStatus(TRUE);&lt;br /&gt;
            }&lt;br /&gt;
            if ( restr == &amp;quot;unsit&amp;quot; )&lt;br /&gt;
                llOwnerSay(&amp;quot;@getsitid=&amp;quot; + (string)backChannel);&lt;br /&gt;
        }&lt;br /&gt;
        else if ( param == &amp;quot;y&amp;quot; || param == &amp;quot;rem&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            integer o = llListFindList(objects, [id]);&lt;br /&gt;
            if ( o &amp;gt;= 0 )&lt;br /&gt;
            {&lt;br /&gt;
                integer i = llListFindList(restrictions, [o, restr]);&lt;br /&gt;
                if ( i &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    restrictions = llDeleteSubList(restrictions, i, i + 1);&lt;br /&gt;
                    if ( llGetListLength(restrictions) == 0 )&lt;br /&gt;
                    {&lt;br /&gt;
                        objects = [];&lt;br /&gt;
                        updateStatus(FALSE);&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            if ( llListFindList(restrictions, [restr]) &amp;lt; 0 )&lt;br /&gt;
                llOwnerSay(cmd);&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            if ( restr == &amp;quot;clear&amp;quot; )&lt;br /&gt;
                clearSome(id, param);&lt;br /&gt;
            else&lt;br /&gt;
                llOwnerSay(cmd);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
        if ( cmd == &amp;quot;@clear&amp;quot; )&lt;br /&gt;
            clear(id);&lt;br /&gt;
        else&lt;br /&gt;
            llOwnerSay(cmd);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
string getStatus(integer o) // it&#039;s okay if o is not an existing object, or -1, we just result an empty string&lt;br /&gt;
{&lt;br /&gt;
    string result = &amp;quot;&amp;quot;;&lt;br /&gt;
    integer len = llGetListLength(restrictions);&lt;br /&gt;
    integer i;&lt;br /&gt;
    for ( i = 0 ; i &amp;lt; len ; i += 2 )&lt;br /&gt;
        if ( llList2Integer(restrictions, i) == o )&lt;br /&gt;
            result += &amp;quot;/&amp;quot; + llList2String(restrictions, i + 1);&lt;br /&gt;
    return result;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
integer allowCommand(key id, string cmd)&lt;br /&gt;
{&lt;br /&gt;
    if ( ! askMode ) return TRUE;                                 // not in ask mode, automatically allow&lt;br /&gt;
    if ( llListFindList(allowedObjects, [id]) &amp;gt;= 0 ) return TRUE; // this object has permission&lt;br /&gt;
    if ( llGetOwnerKey(id) == llGetOwner() ) return TRUE;         // owner&#039;s own objects always have permission&lt;br /&gt;
    if ( llGetSubString(cmd, -2, -1) == &amp;quot;=n&amp;quot; ) return FALSE;      // adding restrictions not allowed without permission&lt;br /&gt;
    if ( llGetSubString(cmd, -4, -1) == &amp;quot;=add&amp;quot; ) return FALSE;    // adding restrictions not allowed without permission&lt;br /&gt;
    if ( llGetSubString(cmd, -6, -1) == &amp;quot;=force&amp;quot; ) return FALSE;  // forcing actions not allowed without permission&lt;br /&gt;
    return TRUE;                                                  // anything else is okay (e.g. @version)&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
default&lt;br /&gt;
{&lt;br /&gt;
    state_entry()&lt;br /&gt;
    {&lt;br /&gt;
        llSetObjectName(implversion);&lt;br /&gt;
        &lt;br /&gt;
        lit = TRUE;&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
        &lt;br /&gt;
        llListen(relayChannel, &amp;quot;&amp;quot;, NULL_KEY, &amp;quot;&amp;quot;);&lt;br /&gt;
        llListen(backChannel = 16777216 + (integer)llFrand(16777216.0), &amp;quot;&amp;quot;, llGetOwner(), &amp;quot;&amp;quot;);&lt;br /&gt;
        llSetTimerEvent(5.0);&lt;br /&gt;
        &lt;br /&gt;
        llMessageLinked(LINK_SET, -123, llGetScriptName() + &amp;quot; free: &amp;quot; + (string)llGetFreeMemory(), NULL_KEY);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    listen(integer ch, string name, key id, string msg)&lt;br /&gt;
    {&lt;br /&gt;
        if ( ch == relayChannel )&lt;br /&gt;
        {&lt;br /&gt;
            list pack = llCSV2List(msg);&lt;br /&gt;
            key target = llList2String(pack, 1);&lt;br /&gt;
            if ( target == llGetOwner() )&lt;br /&gt;
            {&lt;br /&gt;
                string cmdid = llList2String(pack, 0);&lt;br /&gt;
                list cmds = llParseString2List(llList2String(pack, 2), [&amp;quot;|&amp;quot;], []);&lt;br /&gt;
                integer len = llGetListLength(cmds);&lt;br /&gt;
                integer i;&lt;br /&gt;
                for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                {&lt;br /&gt;
                    string cmd = llList2String(cmds, i);&lt;br /&gt;
                    if ( llGetSubString(cmd, 0, 0) == &amp;quot;@&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        if ( allowCommand(id, cmd) )&lt;br /&gt;
                        {&lt;br /&gt;
                            rlvCommand(id, cmd);&lt;br /&gt;
                            llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ok&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
                        else if ( llListFindList(rejectedObjects, [id]) &amp;gt;= 0 )&lt;br /&gt;
                        {&lt;br /&gt;
                            llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ko&amp;quot;);&lt;br /&gt;
                        }&lt;br /&gt;
                        else&lt;br /&gt;
                        {&lt;br /&gt;
                            integer p = llListFindList(pendingObjects, [id]);&lt;br /&gt;
                            if ( p &amp;lt; 0 )&lt;br /&gt;
                            {&lt;br /&gt;
                                p = llGetListLength(pendingObjects);&lt;br /&gt;
                                pendingObjects += id;&lt;br /&gt;
                                &lt;br /&gt;
                                list buttons;&lt;br /&gt;
                                if ( p )&lt;br /&gt;
                                    buttons = [&amp;quot;Yes &amp;quot; + (string)p, &amp;quot;No &amp;quot; + (string)p];&lt;br /&gt;
                                else&lt;br /&gt;
                                    buttons = [&amp;quot;Yes&amp;quot;, &amp;quot;No&amp;quot;];&lt;br /&gt;
                                string object = llKey2Name(id);&lt;br /&gt;
                                string ownedby = llKey2Name(llGetOwnerKey(id));&lt;br /&gt;
                                if ( ownedby ) object += &amp;quot; (owned by &amp;quot; + ownedby + &amp;quot;)&amp;quot;;&lt;br /&gt;
                                if ( ! permListener )&lt;br /&gt;
                                    permListener = llListen(permChannel = -16777216 - (integer)llFrand(16777216.0), &amp;quot;&amp;quot;, llGetOwner(), &amp;quot;&amp;quot;);&lt;br /&gt;
                                llDialog(llGetOwner(), &amp;quot;The object &amp;quot; + object&lt;br /&gt;
                                    + &amp;quot; is attempting to use your Restrained Life Viewer relay.  Do you wish to allow it?&amp;quot;, buttons, permChannel);&lt;br /&gt;
                                permClose = llGetUnixTime() + 120;&lt;br /&gt;
                            }&lt;br /&gt;
                            if ( llListFindList(pendingCommands, [p, cmdid, cmd]) &amp;lt; 0 ) // some devices spam the same command over and over, don&#039;t keep growing list&lt;br /&gt;
                                pendingCommands += [p, cmdid, cmd];&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!release&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        clear(id);&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ok&amp;quot;);&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!getstatus&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        integer o = llListFindList(objects, [id]);&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,&amp;quot; + getStatus(o));&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!version&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,&amp;quot; + version);&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!implversion&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        llShout(relayChannel, cmdid + &amp;quot;,&amp;quot; + (string)id + &amp;quot;,&amp;quot; + cmd + &amp;quot;,&amp;quot; + implversion);&lt;br /&gt;
                    }&lt;br /&gt;
                    else if ( cmd == &amp;quot;!pong&amp;quot; )&lt;br /&gt;
                    {&lt;br /&gt;
                        integer p = llListFindList(pingObjects, [id]);&lt;br /&gt;
                        if ( p &amp;gt;= 0 )&lt;br /&gt;
                        {&lt;br /&gt;
                            llOwnerSay(&amp;quot;Got pong, you&#039;re out of luck.  Reapplying restrictions from &amp;quot; + name + &amp;quot;...&amp;quot;);&lt;br /&gt;
                            integer o = llListFindList(objects, [id]);&lt;br /&gt;
                            if ( o &amp;lt; 0 )&lt;br /&gt;
                            {&lt;br /&gt;
                                o = llGetListLength(objects);&lt;br /&gt;
                                objects += id;&lt;br /&gt;
                            }&lt;br /&gt;
                            string cmd = &amp;quot;&amp;quot;;&lt;br /&gt;
                            string pre = &amp;quot;@&amp;quot;;&lt;br /&gt;
                            integer i;&lt;br /&gt;
                            while ( (i = llListFindList(pingRestrictions, [p])) &amp;gt;= 0 )&lt;br /&gt;
                            {&lt;br /&gt;
                                string restr = llList2String(pingRestrictions, i + 1);&lt;br /&gt;
                                if ( restr == &amp;quot;unsit&amp;quot; )&lt;br /&gt;
                                {&lt;br /&gt;
                                    if ( pingSitting )&lt;br /&gt;
                                    {&lt;br /&gt;
                                        llOwnerSay(&amp;quot;@sit:&amp;quot; + (string)pingSitting + &amp;quot;=force&amp;quot;);&lt;br /&gt;
                                        pingSitRetry = 12; // keep trying for a minute -- it can take that long for things to rez&lt;br /&gt;
                                    }&lt;br /&gt;
                                }&lt;br /&gt;
                                cmd += pre + restr + &amp;quot;=n&amp;quot;;&lt;br /&gt;
                                pre = &amp;quot;,&amp;quot;;&lt;br /&gt;
                                restrictions += [o, restr];&lt;br /&gt;
                                pingRestrictions = llDeleteSubList(pingRestrictions, i, i + 1);&lt;br /&gt;
                            }&lt;br /&gt;
                            if ( cmd )&lt;br /&gt;
                                llOwnerSay(cmd);&lt;br /&gt;
                            updateStatus(TRUE);&lt;br /&gt;
                            if ( llGetListLength(pingRestrictions) == 0 )&lt;br /&gt;
                                pingObjects = [];&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
            else if ( target == llGetKey() )&lt;br /&gt;
            {&lt;br /&gt;
                string cmdid = llList2String(pack, 0);&lt;br /&gt;
                if ( cmdid == &amp;quot;uniquecheck&amp;quot; )&lt;br /&gt;
                    llOwnerSay(&amp;quot;You are wearing another RLV relay (&amp;quot; + name + &amp;quot;).  Remove it.  You should never wear more than one RLV relay at a time.&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( ch == permChannel )&lt;br /&gt;
        {&lt;br /&gt;
            integer o = (integer) llGetSubString(msg, -2, -1);&lt;br /&gt;
            key obj = llList2Key(pendingObjects, o);&lt;br /&gt;
            if ( llGetSubString(msg, 0, 2) == &amp;quot;Yes&amp;quot; )&lt;br /&gt;
            {&lt;br /&gt;
                allowedObjects = obj + llList2List(allowedObjects, 0, 8);&lt;br /&gt;
                integer i;&lt;br /&gt;
                while ( (i = llListFindList(pendingCommands, [o])) &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    string cmd = llList2String(pendingCommands, i + 2);&lt;br /&gt;
                    rlvCommand(obj, cmd);&lt;br /&gt;
                    llShout(relayChannel, llList2String(pendingCommands, i + 1) + &amp;quot;,&amp;quot; + (string)obj + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ok&amp;quot;);&lt;br /&gt;
                    pendingCommands = llDeleteSubList(pendingCommands, i, i + 2);&lt;br /&gt;
                }&lt;br /&gt;
                if ( llGetListLength(pendingCommands) == 0 )&lt;br /&gt;
                    pendingObjects = [];&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                rejectedObjects = obj + llList2List(rejectedObjects, 0, 8);&lt;br /&gt;
                integer i;&lt;br /&gt;
                while ( (i = llListFindList(pendingCommands, [o])) &amp;gt;= 0 )&lt;br /&gt;
                {&lt;br /&gt;
                    string cmd = llList2String(pendingCommands, i + 2);&lt;br /&gt;
                    llShout(relayChannel, llList2String(pendingCommands, i + 1) + &amp;quot;,&amp;quot; + (string)obj + &amp;quot;,&amp;quot; + cmd + &amp;quot;,ko&amp;quot;);&lt;br /&gt;
                    pendingCommands = llDeleteSubList(pendingCommands, i, i + 2);&lt;br /&gt;
                }&lt;br /&gt;
                if ( llGetListLength(pendingCommands) == 0 )&lt;br /&gt;
                    pendingObjects = [];&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( ch == backChannel )&lt;br /&gt;
        {&lt;br /&gt;
            sitting = msg;&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    on_rez(integer param)&lt;br /&gt;
    {&lt;br /&gt;
        if ( objects )&lt;br /&gt;
        {&lt;br /&gt;
            integer len = llGetListLength(objects);&lt;br /&gt;
            integer i;&lt;br /&gt;
            for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                if ( llListFindList(restrictions, [i]) &amp;gt;= 0 )&lt;br /&gt;
                    llShout(relayChannel, &amp;quot;ping,&amp;quot; + (string)llList2Key(objects, i) + &amp;quot;,ping,ping&amp;quot;);&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        pingObjects = objects;&lt;br /&gt;
        pingRestrictions = restrictions;&lt;br /&gt;
        pingSitting = sitting;&lt;br /&gt;
        pingSitRetry = 0;&lt;br /&gt;
        &lt;br /&gt;
        objects = [];&lt;br /&gt;
        restrictions = [];&lt;br /&gt;
        sitting = NULL_KEY;&lt;br /&gt;
        updateStatus(FALSE);&lt;br /&gt;
        &lt;br /&gt;
        allowedObjects = [];&lt;br /&gt;
        rejectedObjects = [];&lt;br /&gt;
        pendingObjects = [];&lt;br /&gt;
        pendingCommands = [];&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    timer()&lt;br /&gt;
    {&lt;br /&gt;
        if ( llGetAgentInfo(llGetOwner()) &amp;amp; AGENT_ON_OBJECT )&lt;br /&gt;
        {&lt;br /&gt;
            llOwnerSay(&amp;quot;@getsitid=&amp;quot; + (string)backChannel);&lt;br /&gt;
            pingSitRetry = 0;&lt;br /&gt;
        }&lt;br /&gt;
        else&lt;br /&gt;
        {&lt;br /&gt;
            sitting = NULL_KEY;&lt;br /&gt;
            if ( pingSitRetry )&lt;br /&gt;
            {&lt;br /&gt;
                llOwnerSay(&amp;quot;@sit:&amp;quot; + (string)pingSitting + &amp;quot;=force&amp;quot;);&lt;br /&gt;
                --pingSitRetry;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( permListener )&lt;br /&gt;
        {&lt;br /&gt;
            if ( llGetUnixTime() &amp;gt;= permClose )&lt;br /&gt;
            {&lt;br /&gt;
                pendingObjects = [];&lt;br /&gt;
                pendingCommands = [];&lt;br /&gt;
                llListenRemove(permListener);&lt;br /&gt;
                permListener = 0;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    link_message(integer src, integer num, string msg, key id)&lt;br /&gt;
    {&lt;br /&gt;
        if ( msg == &amp;quot;relay-ask&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            askMode = num;&lt;br /&gt;
            if ( askMode )&lt;br /&gt;
            {&lt;br /&gt;
                allowedObjects = objects;&lt;br /&gt;
                rejectedObjects = [];&lt;br /&gt;
                pendingObjects = [];&lt;br /&gt;
                pendingCommands = [];&lt;br /&gt;
            }&lt;br /&gt;
            else if ( permListener )&lt;br /&gt;
            {&lt;br /&gt;
                allowedObjects = [];&lt;br /&gt;
                rejectedObjects = [];&lt;br /&gt;
                pendingObjects = [];&lt;br /&gt;
                pendingCommands = [];&lt;br /&gt;
                llListenRemove(permListener);&lt;br /&gt;
                permListener = 0;&lt;br /&gt;
            }&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( msg == &amp;quot;relay-status&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            integer len = llGetListLength(objects);&lt;br /&gt;
            if ( len )&lt;br /&gt;
            {&lt;br /&gt;
                integer i;&lt;br /&gt;
                for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                    llMessageLinked(LINK_SET, num, getStatus(i), llList2Key(objects, i));&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
                llMessageLinked(LINK_SET, num, &amp;quot;&amp;quot;, NULL_KEY);&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
        &lt;br /&gt;
        if ( msg == &amp;quot;relay-reset&amp;quot; )&lt;br /&gt;
        {&lt;br /&gt;
            integer len = llGetListLength(objects);&lt;br /&gt;
            integer i;&lt;br /&gt;
            for ( i = 0 ; i &amp;lt; len ; ++i )&lt;br /&gt;
                llShout(relayChannel, &amp;quot;safeword,&amp;quot; + (string)llList2Key(objects, i) + &amp;quot;,!release,ok&amp;quot;);&lt;br /&gt;
            llResetScript();&lt;br /&gt;
            return;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    attach(key id)&lt;br /&gt;
    {&lt;br /&gt;
        if ( id )&lt;br /&gt;
            llWhisper(relayChannel, &amp;quot;uniquecheck,&amp;quot; + (string)id + &amp;quot;,!version&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    changed(integer change)&lt;br /&gt;
    {&lt;br /&gt;
        if ( change &amp;amp; CHANGED_OWNER )&lt;br /&gt;
            llResetScript();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;/div&gt;</summary>
		<author><name>Julia Banshee</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Other_Implementations&amp;diff=237892</id>
		<title>LSL Protocol/Restrained Love Relay/Other Implementations</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Other_Implementations&amp;diff=237892"/>
		<updated>2009-02-14T08:09:58Z</updated>

		<summary type="html">&lt;p&gt;Julia Banshee: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Restrained Life Relay Specs TOC}}&lt;br /&gt;
&lt;br /&gt;
Want to share your own relay script?&lt;br /&gt;
&lt;br /&gt;
Please create a new page and add a link here.&lt;br /&gt;
&lt;br /&gt;
== Amethyst Plugin version by Felis Darwin ==&lt;br /&gt;
An edited version of the Reference Implementation meant to be used as a plugin for Amethyst collars.  &#039;&#039;&#039;WARNING: This is currently a work in progress, and can cause conflicts (&#039;&#039;specifically, nullifying restrictions on release&#039;&#039;) with the standard Amethyst Restrained Life Plugin.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Adds an actual timeout for the ask dialog, periodic pinging, and locking support.&lt;br /&gt;
&lt;br /&gt;
[[LSL Protocol/Restrained Life Relay/Other Implementations/Felis Darwin&#039;s Amethyst Plugin|This version&#039;s subpage]]&lt;br /&gt;
&lt;br /&gt;
== Maike Short&#039;s Version ==&lt;br /&gt;
&lt;br /&gt;
[[LSL Protocol/Restrained Life Relay/Other Implementations/Maike Short&#039;s Relay|Maike Short&#039;s Relay]]&lt;br /&gt;
&lt;br /&gt;
== Dominatech RLV Relay ==&lt;br /&gt;
&lt;br /&gt;
[[LSL Protocol/Restrained Life Relay/Other Implementations/Dominatech RLV Relay|Julia Banshee&#039;s relay]], with multiple device support.&lt;/div&gt;</summary>
		<author><name>Julia Banshee</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Bugs_and_Pending_Features&amp;diff=91745</id>
		<title>LSL Protocol/Restrained Love Relay/Bugs and Pending Features</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Bugs_and_Pending_Features&amp;diff=91745"/>
		<updated>2008-09-18T08:05:09Z</updated>

		<summary type="html">&lt;p&gt;Julia Banshee: /* Foreign Channel Chat */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Restrained Life Relay Specs TOC}}&lt;br /&gt;
&lt;br /&gt;
== 1.02 ==&lt;br /&gt;
&lt;br /&gt;
Version 1.02 reintroduces all the problems listed in 1.014.&lt;br /&gt;
&lt;br /&gt;
=== Foreign Channel Chat ===&lt;br /&gt;
&lt;br /&gt;
; Description : An object can force the agent to say any lower case text on any channel using @getstatus&lt;br /&gt;
; Note :  Relays which do not add any restriction on their own (like @detach=n) may be abused using @gestatus to trigger dialog responses, gag talk or other scripts like &amp;quot;to buy as gift, say the name of the receiver on channel /&#039;&#039;x&#039;&#039;&amp;quot;. Any version of the reference implementation smaller than (not including) 1.015 (but including 1.020 which is based on 1.014) are affected by this.&lt;br /&gt;
; Workaround : none&lt;br /&gt;
; Fixed : in [[LSL Protocol/Restrained Life Relay/Other Implementations/Maike Short&#039;s Relay|Maike Short&#039;s Relay]]&lt;br /&gt;
; Proposed fixed : Add &amp;quot;this-is-a-script-generated-message-beyond-the-control-of-the-agent/&amp;quot; at the beginning of @getstatus-replies on all channel by issuing this as the very first restriction. This still allows to trigger gags but it will include a human readable warning (if you speak Gagish well enough). The usual &amp;quot;to buy as gift, say the name of the receiver on channel /&#039;&#039;x&#039;&#039;&amp;quot; scripts will try to resolve this text as part of the name and will fail because such long avatar names are not allowed. Other scripts waiting for commands are very likely not to accept this text either. A more secure solution would be to define one single channel which must be used for such queries but that would break a lot of content.&lt;br /&gt;
&lt;br /&gt;
It would probably be sufficient to &amp;quot;ko&amp;quot; @getstatus=x requests where x &amp;lt; 1000.  Most gags or other scripts that expect human-typed channel numbers stick to &amp;lt; 1000, whereas most furniture looking for status use much larger channel numbers (mine use random channels, but with a minimum of 1000000, for example).&lt;br /&gt;
&lt;br /&gt;
=== Foreign Public Chat ===&lt;br /&gt;
&lt;br /&gt;
; Description : An object can force the agent to say any text in public chat using @getstatus=0 and use similar functions (like @version) to spam other text there.&lt;br /&gt;
; Note : This allows the same abuse mentioned in the above entry, too. But being public chat makes even non abusable cases very annoying.&lt;br /&gt;
; Workaround : none&lt;br /&gt;
; Fixed : in [[LSL Protocol/Restrained Life Relay/Other Implementations/Maike Short&#039;s Relay|Maike Short&#039;s Relay]]&lt;br /&gt;
; Proposed fixed : The relay should filter all queries directed to answer on channel 0. Add this at the end of the huge if / else if / else if block in executeRLVCommand&lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
    else if ((integer) param == 0) {&lt;br /&gt;
        // this is either an unknown param (not &amp;quot;n&amp;quot;, &amp;quot;add&amp;quot;, &amp;quot;y&amp;quot;, &amp;quot;rem&amp;quot;, &amp;quot;force&amp;quot;)&lt;br /&gt;
        // or a query which should be answered on the public chat channel 0.&lt;br /&gt;
        ack(cmd_id, id, command, &amp;quot;ko&amp;quot;);&lt;br /&gt;
        return;&lt;br /&gt;
    }    &lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Relay Crash in Ask mode ===&lt;br /&gt;
&lt;br /&gt;
; Description : A malicious objects scans for all avatars within the sensor range. For each avatar a new object is rezes out of the content. This objects sends 10 messages to the relay each of about 1000 characters causing sPendingMessage to overflow. After the 10 messages are send these objects die making tracking very difficult.&lt;br /&gt;
; Note : Some relays accept commands from objects more than &amp;lt;del&amp;gt;20&amp;lt;/del&amp;gt;100 meters away so the attacking objects can be hidden far away.&lt;br /&gt;
; Workaround : None&lt;br /&gt;
; Open : although fixed in version 1.15 it was reintroduced by the revert in version 1.02&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1.015 ==&lt;br /&gt;
&lt;br /&gt;
The below problems are fixed [[LSL_Protocol/Restrained_Life_Relay/Other_Implementations/Maike_Short&#039;s_Relay|here]], except for the forced sit issue below.&lt;br /&gt;
&lt;br /&gt;
== 1.014 ==&lt;br /&gt;
&lt;br /&gt;
The following problems occured in version 1.014 and have been fixed:&lt;br /&gt;
&lt;br /&gt;
=== Stuck: Accepting Permission Dialog after !release ===&lt;br /&gt;
; Discovered by : Maike Short&lt;br /&gt;
; Workaround : Don&#039;t accept requests after you have been freed. In case it happend, reenter the cage / sit down again; relog.&lt;br /&gt;
; Fixed : in 1.015&lt;br /&gt;
&lt;br /&gt;
=== Force Sit during Login on the control object instead of the forced-sit one ===&lt;br /&gt;
&lt;br /&gt;
; Discovered by : Azoth Amat&lt;br /&gt;
; Workaround : Always send a &amp;quot;@sit:&amp;lt;id&amp;gt;=force&amp;quot; command if you want a forced sit on relog, even if the victim is already sitting.&lt;br /&gt;
; Fix : change in &amp;lt;code&amp;gt;timer()&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)lastForceSitDestination+&amp;quot;=force&amp;quot;);&amp;lt;/code&amp;gt;&lt;br /&gt;
; Note : This prevents @unsit to work in case the person set down without being forced if the furniture in question hasn&#039;t sent a @sit:&amp;lt;id&amp;gt;=force command.  (This should probably be considered a bug in the furniture, not the relay.)&lt;br /&gt;
; Fixed : in 1.015 (but that fix breaks other things, forcing sits when not appropriate), and 1.02 (that fix always works, assuming the furniture is properly setting the @sit destination)&lt;br /&gt;
&lt;br /&gt;
:: Sending a bogus force sit on sit as you suggested may not work if force-sits are filtered. As far as I know there is no way for an attachment to detect the object the avatar is sitting on. So the relay will not be able to tell real force-sits (which should be subjected to the filter) and bogus force-sits for this problem apart. &lt;br /&gt;
:: It could accept a force-sit on the control-object but this would allow to kidnap an agent sitting on an other object. Well, the same can happen with my approach of using the sending object as fall back. Could you give an example for a forced sit when not appropriate with my approach? This may reveal other aspects of the problem.&lt;br /&gt;
:: The specification says &amp;quot;Force sit if unsit is prevented when relogging&amp;quot; in &amp;quot;Relay requirements&amp;quot; so I think objects that just send @unsit=n without force-sit should not be called buggy. If it turns out the current approach does cause more problems than it fixes it may be worth to adjust the spec. But this will cause existing world object to break so should not be taken lightly. --[[User:Maike Short|Maike Short]] 12:55, 17 September 2008 (PDT)&lt;br /&gt;
&lt;br /&gt;
=== Stuck on crash/relog with objects asking for relay upon being sat on ===&lt;br /&gt;
&lt;br /&gt;
; Discovered by : Gregor Mougin&lt;br /&gt;
; Problem : Many objects check for presence of a relay and the RR viewer by asking for the !version when sat on. If the user crashes, and the object was used by someone else in the meantime (or, for testing, reset), the relay enforces all previous restrictions whereas the object doesn&#039;t know of them.&lt;br /&gt;
; Workaround : none&lt;br /&gt;
; Suggested fix : &lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
--- RLV_v1.014a 2008-07-06 23:17:14.000000000 +0200&lt;br /&gt;
+++ RLV_v1.014a-xxx     2008-07-06 23:18:32.000000000 +0200&lt;br /&gt;
@@ -545,10 +545,16 @@&lt;br /&gt;
                 loginPendingForceSit = FALSE;&lt;br /&gt;
                 releaseRestrictions();&lt;br /&gt;
             }&lt;br /&gt;
-            else&lt;br /&gt;
-            {&lt;br /&gt;
-                 sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
-            }&lt;br /&gt;
+            // XXX&lt;br /&gt;
+            // DON&#039;T do it here&lt;br /&gt;
+            // Some (many?) objects ask the relay for the !version upon&lt;br /&gt;
+            // sitting on it. Since the !version is interpreted the same&lt;br /&gt;
+            // as !pong, the relay would think the object is still available&lt;br /&gt;
+            // and put all restrictions on the wearer unconditionally.&lt;br /&gt;
+            //else&lt;br /&gt;
+            //{&lt;br /&gt;
+            //    sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
+            //}&lt;br /&gt;
         }&lt;br /&gt;
  &lt;br /&gt;
         if (!loginPendingForceSit &amp;amp;&amp;amp; !loginWaitingForPong)&lt;br /&gt;
@@ -583,6 +589,18 @@&lt;br /&gt;
  &lt;br /&gt;
             loginWaitingForPong = FALSE; // whatever the message, it is for me =&amp;gt; it satisfies the ping request&lt;br /&gt;
  &lt;br /&gt;
+            // XXX&lt;br /&gt;
+            // force sit here instead of unconditionally in the timer event&lt;br /&gt;
+            if (loginPendingForceSit)&lt;br /&gt;
+            {&lt;br /&gt;
+                integer agentInfo = llGetAgentInfo(llGetOwner());&lt;br /&gt;
+                &lt;br /&gt;
+                loginPendingForceSit = FALSE;&lt;br /&gt;
+                if (!(agentInfo &amp;amp; AGENT_SITTING))&lt;br /&gt;
+                    sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
+            }&lt;br /&gt;
+            // end XXX&lt;br /&gt;
+            &lt;br /&gt;
             if (!isObjectKnow(id))&lt;br /&gt;
             {&lt;br /&gt;
                 debug(&amp;quot;asking for permission because kSource is NULL_KEY&amp;quot;);&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
; Fixed : in 1.015 by specially looking for the !pong reply so that the fix works for cages  as well (no &amp;quot;force sit&amp;quot; in this situation but a collision detection which is triggered on login, too).&lt;/div&gt;</summary>
		<author><name>Julia Banshee</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Bugs_and_Pending_Features&amp;diff=91559</id>
		<title>LSL Protocol/Restrained Love Relay/Bugs and Pending Features</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Bugs_and_Pending_Features&amp;diff=91559"/>
		<updated>2008-09-16T18:51:01Z</updated>

		<summary type="html">&lt;p&gt;Julia Banshee: /* 1.015 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Restrained Life Relay Specs TOC}}&lt;br /&gt;
&lt;br /&gt;
== 1.02 ==&lt;br /&gt;
&lt;br /&gt;
Version 1.02 reintroduces all the problems listed in 1.014.&lt;br /&gt;
&lt;br /&gt;
=== Relay Crash in Ask mode ===&lt;br /&gt;
&lt;br /&gt;
; Description : A malicious objects scans for all avatars within the sensor range. For each avatar a new object is rezes out of the content. This objects sends 10 messages to the relay each of about 1000 characters causing sPendingMessage to overflow. After the 10 messages are send these objects die making tracking very difficult.&lt;br /&gt;
; Note : Some relays accept commands from objects more than &amp;lt;del&amp;gt;20&amp;lt;/del&amp;gt;100 meters away so the attacking objects can be hidden far away.&lt;br /&gt;
; Workaround : None&lt;br /&gt;
; Open : although fixed in version 1.15 it was reintroduced by the revert in version 1.02&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1.015 ==&lt;br /&gt;
&lt;br /&gt;
The below problems are fixed [[LSL_Protocol/Restrained_Life_Relay/Other_Implementations/Maike_Short&#039;s_Relay|here]], except for the forced sit issue below.&lt;br /&gt;
&lt;br /&gt;
== 1.014 ==&lt;br /&gt;
&lt;br /&gt;
The following problems occured in version 1.014 and have been fixed:&lt;br /&gt;
&lt;br /&gt;
=== Stuck: Accepting Permission Dialog after !release ===&lt;br /&gt;
; Discovered by : Maike Short&lt;br /&gt;
; Workaround : Don&#039;t accept requests after you have been freed. In case it happend, reenter the cage / sit down again; relog.&lt;br /&gt;
; Fixed : in 1.015&lt;br /&gt;
&lt;br /&gt;
=== Force Sit during Login on the control object instead of the forced-sit one ===&lt;br /&gt;
&lt;br /&gt;
; Discovered by : Azoth Amat&lt;br /&gt;
; Workaround : Always send a &amp;quot;@sit:&amp;lt;id&amp;gt;=force&amp;quot; command if you want a forced sit on relog, even if the victim is already sitting.&lt;br /&gt;
; Fix : change in &amp;lt;code&amp;gt;timer()&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)lastForceSitDestination+&amp;quot;=force&amp;quot;);&amp;lt;/code&amp;gt;&lt;br /&gt;
; Note : This prevents @unsit to work in case the person set down without being forced if the furniture in question hasn&#039;t sent a @sit:&amp;lt;id&amp;gt;=force command.  (This should probably be considered a bug in the furniture, not the relay.)&lt;br /&gt;
; Fixed : in 1.015 (but that fix breaks other things, forcing sits when not appropriate), and 1.02 (that fix always works, assuming the furniture is properly setting the @sit destination)&lt;br /&gt;
&lt;br /&gt;
=== Stuck on crash/relog with objects asking for relay upon being sat on ===&lt;br /&gt;
&lt;br /&gt;
; Discovered by : Gregor Mougin&lt;br /&gt;
; Problem : Many objects check for presence of a relay and the RR viewer by asking for the !version when sat on. If the user crashes, and the object was used by someone else in the meantime (or, for testing, reset), the relay enforces all previous restrictions whereas the object doesn&#039;t know of them.&lt;br /&gt;
; Workaround : none&lt;br /&gt;
; Suggested fix : &lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
--- RLV_v1.014a 2008-07-06 23:17:14.000000000 +0200&lt;br /&gt;
+++ RLV_v1.014a-xxx     2008-07-06 23:18:32.000000000 +0200&lt;br /&gt;
@@ -545,10 +545,16 @@&lt;br /&gt;
                 loginPendingForceSit = FALSE;&lt;br /&gt;
                 releaseRestrictions();&lt;br /&gt;
             }&lt;br /&gt;
-            else&lt;br /&gt;
-            {&lt;br /&gt;
-                 sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
-            }&lt;br /&gt;
+            // XXX&lt;br /&gt;
+            // DON&#039;T do it here&lt;br /&gt;
+            // Some (many?) objects ask the relay for the !version upon&lt;br /&gt;
+            // sitting on it. Since the !version is interpreted the same&lt;br /&gt;
+            // as !pong, the relay would think the object is still available&lt;br /&gt;
+            // and put all restrictions on the wearer unconditionally.&lt;br /&gt;
+            //else&lt;br /&gt;
+            //{&lt;br /&gt;
+            //    sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
+            //}&lt;br /&gt;
         }&lt;br /&gt;
  &lt;br /&gt;
         if (!loginPendingForceSit &amp;amp;&amp;amp; !loginWaitingForPong)&lt;br /&gt;
@@ -583,6 +589,18 @@&lt;br /&gt;
  &lt;br /&gt;
             loginWaitingForPong = FALSE; // whatever the message, it is for me =&amp;gt; it satisfies the ping request&lt;br /&gt;
  &lt;br /&gt;
+            // XXX&lt;br /&gt;
+            // force sit here instead of unconditionally in the timer event&lt;br /&gt;
+            if (loginPendingForceSit)&lt;br /&gt;
+            {&lt;br /&gt;
+                integer agentInfo = llGetAgentInfo(llGetOwner());&lt;br /&gt;
+                &lt;br /&gt;
+                loginPendingForceSit = FALSE;&lt;br /&gt;
+                if (!(agentInfo &amp;amp; AGENT_SITTING))&lt;br /&gt;
+                    sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
+            }&lt;br /&gt;
+            // end XXX&lt;br /&gt;
+            &lt;br /&gt;
             if (!isObjectKnow(id))&lt;br /&gt;
             {&lt;br /&gt;
                 debug(&amp;quot;asking for permission because kSource is NULL_KEY&amp;quot;);&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
; Fixed : in 1.015 by specially looking for the !pong reply so that the fix works for cages  as well (no &amp;quot;force sit&amp;quot; in this situation but a collision detection which is triggered on login, too).&lt;/div&gt;</summary>
		<author><name>Julia Banshee</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Bugs_and_Pending_Features&amp;diff=91558</id>
		<title>LSL Protocol/Restrained Love Relay/Bugs and Pending Features</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Bugs_and_Pending_Features&amp;diff=91558"/>
		<updated>2008-09-16T18:45:46Z</updated>

		<summary type="html">&lt;p&gt;Julia Banshee: /* Force Sit during Login on the control object instead of the forced-sit one */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Restrained Life Relay Specs TOC}}&lt;br /&gt;
&lt;br /&gt;
== 1.02 ==&lt;br /&gt;
&lt;br /&gt;
Version 1.02 reintroduces all the problems listed in 1.014.&lt;br /&gt;
&lt;br /&gt;
=== Relay Crash in Ask mode ===&lt;br /&gt;
&lt;br /&gt;
; Description : A malicious objects scans for all avatars within the sensor range. For each avatar a new object is rezes out of the content. This objects sends 10 messages to the relay each of about 1000 characters causing sPendingMessage to overflow. After the 10 messages are send these objects die making tracking very difficult.&lt;br /&gt;
; Note : Some relays accept commands from objects more than &amp;lt;del&amp;gt;20&amp;lt;/del&amp;gt;100 meters away so the attacking objects can be hidden far away.&lt;br /&gt;
; Workaround : None&lt;br /&gt;
; Open : although fixed in version 1.15 it was reintroduced by the revert in version 1.02&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1.015 ==&lt;br /&gt;
&lt;br /&gt;
The below problems are fixed [[LSL_Protocol/Restrained_Life_Relay/Other_Implementations/Maike_Short&#039;s_Relay|here]]&lt;br /&gt;
&lt;br /&gt;
== 1.014 ==&lt;br /&gt;
&lt;br /&gt;
The following problems occured in version 1.014 and have been fixed:&lt;br /&gt;
&lt;br /&gt;
=== Stuck: Accepting Permission Dialog after !release ===&lt;br /&gt;
; Discovered by : Maike Short&lt;br /&gt;
; Workaround : Don&#039;t accept requests after you have been freed. In case it happend, reenter the cage / sit down again; relog.&lt;br /&gt;
; Fixed : in 1.015&lt;br /&gt;
&lt;br /&gt;
=== Force Sit during Login on the control object instead of the forced-sit one ===&lt;br /&gt;
&lt;br /&gt;
; Discovered by : Azoth Amat&lt;br /&gt;
; Workaround : Always send a &amp;quot;@sit:&amp;lt;id&amp;gt;=force&amp;quot; command if you want a forced sit on relog, even if the victim is already sitting.&lt;br /&gt;
; Fix : change in &amp;lt;code&amp;gt;timer()&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)lastForceSitDestination+&amp;quot;=force&amp;quot;);&amp;lt;/code&amp;gt;&lt;br /&gt;
; Note : This prevents @unsit to work in case the person set down without being forced if the furniture in question hasn&#039;t sent a @sit:&amp;lt;id&amp;gt;=force command.  (This should probably be considered a bug in the furniture, not the relay.)&lt;br /&gt;
; Fixed : in 1.015 (but that fix breaks other things, forcing sits when not appropriate), and 1.02 (that fix always works, assuming the furniture is properly setting the @sit destination)&lt;br /&gt;
&lt;br /&gt;
=== Stuck on crash/relog with objects asking for relay upon being sat on ===&lt;br /&gt;
&lt;br /&gt;
; Discovered by : Gregor Mougin&lt;br /&gt;
; Problem : Many objects check for presence of a relay and the RR viewer by asking for the !version when sat on. If the user crashes, and the object was used by someone else in the meantime (or, for testing, reset), the relay enforces all previous restrictions whereas the object doesn&#039;t know of them.&lt;br /&gt;
; Workaround : none&lt;br /&gt;
; Suggested fix : &lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
--- RLV_v1.014a 2008-07-06 23:17:14.000000000 +0200&lt;br /&gt;
+++ RLV_v1.014a-xxx     2008-07-06 23:18:32.000000000 +0200&lt;br /&gt;
@@ -545,10 +545,16 @@&lt;br /&gt;
                 loginPendingForceSit = FALSE;&lt;br /&gt;
                 releaseRestrictions();&lt;br /&gt;
             }&lt;br /&gt;
-            else&lt;br /&gt;
-            {&lt;br /&gt;
-                 sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
-            }&lt;br /&gt;
+            // XXX&lt;br /&gt;
+            // DON&#039;T do it here&lt;br /&gt;
+            // Some (many?) objects ask the relay for the !version upon&lt;br /&gt;
+            // sitting on it. Since the !version is interpreted the same&lt;br /&gt;
+            // as !pong, the relay would think the object is still available&lt;br /&gt;
+            // and put all restrictions on the wearer unconditionally.&lt;br /&gt;
+            //else&lt;br /&gt;
+            //{&lt;br /&gt;
+            //    sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
+            //}&lt;br /&gt;
         }&lt;br /&gt;
  &lt;br /&gt;
         if (!loginPendingForceSit &amp;amp;&amp;amp; !loginWaitingForPong)&lt;br /&gt;
@@ -583,6 +589,18 @@&lt;br /&gt;
  &lt;br /&gt;
             loginWaitingForPong = FALSE; // whatever the message, it is for me =&amp;gt; it satisfies the ping request&lt;br /&gt;
  &lt;br /&gt;
+            // XXX&lt;br /&gt;
+            // force sit here instead of unconditionally in the timer event&lt;br /&gt;
+            if (loginPendingForceSit)&lt;br /&gt;
+            {&lt;br /&gt;
+                integer agentInfo = llGetAgentInfo(llGetOwner());&lt;br /&gt;
+                &lt;br /&gt;
+                loginPendingForceSit = FALSE;&lt;br /&gt;
+                if (!(agentInfo &amp;amp; AGENT_SITTING))&lt;br /&gt;
+                    sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
+            }&lt;br /&gt;
+            // end XXX&lt;br /&gt;
+            &lt;br /&gt;
             if (!isObjectKnow(id))&lt;br /&gt;
             {&lt;br /&gt;
                 debug(&amp;quot;asking for permission because kSource is NULL_KEY&amp;quot;);&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
; Fixed : in 1.015 by specially looking for the !pong reply so that the fix works for cages  as well (no &amp;quot;force sit&amp;quot; in this situation but a collision detection which is triggered on login, too).&lt;/div&gt;</summary>
		<author><name>Julia Banshee</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Bugs_and_Pending_Features&amp;diff=91556</id>
		<title>LSL Protocol/Restrained Love Relay/Bugs and Pending Features</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Bugs_and_Pending_Features&amp;diff=91556"/>
		<updated>2008-09-16T18:43:42Z</updated>

		<summary type="html">&lt;p&gt;Julia Banshee: /* Force Sit during Login on the control object instead of the forced-sit one */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Restrained Life Relay Specs TOC}}&lt;br /&gt;
&lt;br /&gt;
== 1.02 ==&lt;br /&gt;
&lt;br /&gt;
Version 1.02 reintroduces all the problems listed in 1.014.&lt;br /&gt;
&lt;br /&gt;
=== Relay Crash in Ask mode ===&lt;br /&gt;
&lt;br /&gt;
; Description : A malicious objects scans for all avatars within the sensor range. For each avatar a new object is rezes out of the content. This objects sends 10 messages to the relay each of about 1000 characters causing sPendingMessage to overflow. After the 10 messages are send these objects die making tracking very difficult.&lt;br /&gt;
; Note : Some relays accept commands from objects more than &amp;lt;del&amp;gt;20&amp;lt;/del&amp;gt;100 meters away so the attacking objects can be hidden far away.&lt;br /&gt;
; Workaround : None&lt;br /&gt;
; Open : although fixed in version 1.15 it was reintroduced by the revert in version 1.02&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1.015 ==&lt;br /&gt;
&lt;br /&gt;
The below problems are fixed [[LSL_Protocol/Restrained_Life_Relay/Other_Implementations/Maike_Short&#039;s_Relay|here]]&lt;br /&gt;
&lt;br /&gt;
== 1.014 ==&lt;br /&gt;
&lt;br /&gt;
The following problems occured in version 1.014 and have been fixed:&lt;br /&gt;
&lt;br /&gt;
=== Stuck: Accepting Permission Dialog after !release ===&lt;br /&gt;
; Discovered by : Maike Short&lt;br /&gt;
; Workaround : Don&#039;t accept requests after you have been freed. In case it happend, reenter the cage / sit down again; relog.&lt;br /&gt;
; Fixed : in 1.015&lt;br /&gt;
&lt;br /&gt;
=== Force Sit during Login on the control object instead of the forced-sit one ===&lt;br /&gt;
&lt;br /&gt;
; Discovered by : Azoth Amat&lt;br /&gt;
; Workaround : Always send a &amp;quot;@sit:&amp;lt;id&amp;gt;=force&amp;quot; command if you want a forced sit on relog, even if the victim is already sitting.&lt;br /&gt;
; Fix : change in &amp;lt;code&amp;gt;timer()&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)lastForceSitDestination+&amp;quot;=force&amp;quot;);&amp;lt;/code&amp;gt;&lt;br /&gt;
; Note : This prevents @unsit to work in case the person set down without being forced if the furniture in question hasn&#039;t sent a @sit:&amp;lt;id&amp;gt;=force command.  (This should probably be considered a bug in the furniture, not the relay.)&lt;br /&gt;
; Fixed : in 1.015 (but that fix breaks other things, forcing sits when not appropriate), and 1.02 if the workaround above is used&lt;br /&gt;
&lt;br /&gt;
=== Stuck on crash/relog with objects asking for relay upon being sat on ===&lt;br /&gt;
&lt;br /&gt;
; Discovered by : Gregor Mougin&lt;br /&gt;
; Problem : Many objects check for presence of a relay and the RR viewer by asking for the !version when sat on. If the user crashes, and the object was used by someone else in the meantime (or, for testing, reset), the relay enforces all previous restrictions whereas the object doesn&#039;t know of them.&lt;br /&gt;
; Workaround : none&lt;br /&gt;
; Suggested fix : &lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
--- RLV_v1.014a 2008-07-06 23:17:14.000000000 +0200&lt;br /&gt;
+++ RLV_v1.014a-xxx     2008-07-06 23:18:32.000000000 +0200&lt;br /&gt;
@@ -545,10 +545,16 @@&lt;br /&gt;
                 loginPendingForceSit = FALSE;&lt;br /&gt;
                 releaseRestrictions();&lt;br /&gt;
             }&lt;br /&gt;
-            else&lt;br /&gt;
-            {&lt;br /&gt;
-                 sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
-            }&lt;br /&gt;
+            // XXX&lt;br /&gt;
+            // DON&#039;T do it here&lt;br /&gt;
+            // Some (many?) objects ask the relay for the !version upon&lt;br /&gt;
+            // sitting on it. Since the !version is interpreted the same&lt;br /&gt;
+            // as !pong, the relay would think the object is still available&lt;br /&gt;
+            // and put all restrictions on the wearer unconditionally.&lt;br /&gt;
+            //else&lt;br /&gt;
+            //{&lt;br /&gt;
+            //    sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
+            //}&lt;br /&gt;
         }&lt;br /&gt;
  &lt;br /&gt;
         if (!loginPendingForceSit &amp;amp;&amp;amp; !loginWaitingForPong)&lt;br /&gt;
@@ -583,6 +589,18 @@&lt;br /&gt;
  &lt;br /&gt;
             loginWaitingForPong = FALSE; // whatever the message, it is for me =&amp;gt; it satisfies the ping request&lt;br /&gt;
  &lt;br /&gt;
+            // XXX&lt;br /&gt;
+            // force sit here instead of unconditionally in the timer event&lt;br /&gt;
+            if (loginPendingForceSit)&lt;br /&gt;
+            {&lt;br /&gt;
+                integer agentInfo = llGetAgentInfo(llGetOwner());&lt;br /&gt;
+                &lt;br /&gt;
+                loginPendingForceSit = FALSE;&lt;br /&gt;
+                if (!(agentInfo &amp;amp; AGENT_SITTING))&lt;br /&gt;
+                    sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
+            }&lt;br /&gt;
+            // end XXX&lt;br /&gt;
+            &lt;br /&gt;
             if (!isObjectKnow(id))&lt;br /&gt;
             {&lt;br /&gt;
                 debug(&amp;quot;asking for permission because kSource is NULL_KEY&amp;quot;);&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
; Fixed : in 1.015 by specially looking for the !pong reply so that the fix works for cages  as well (no &amp;quot;force sit&amp;quot; in this situation but a collision detection which is triggered on login, too).&lt;/div&gt;</summary>
		<author><name>Julia Banshee</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Bugs_and_Pending_Features&amp;diff=91555</id>
		<title>LSL Protocol/Restrained Love Relay/Bugs and Pending Features</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Bugs_and_Pending_Features&amp;diff=91555"/>
		<updated>2008-09-16T18:42:29Z</updated>

		<summary type="html">&lt;p&gt;Julia Banshee: /* Force Sit during Login on the control object instead of the forced-sit one */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Restrained Life Relay Specs TOC}}&lt;br /&gt;
&lt;br /&gt;
== 1.02 ==&lt;br /&gt;
&lt;br /&gt;
Version 1.02 reintroduces all the problems listed in 1.014.&lt;br /&gt;
&lt;br /&gt;
=== Relay Crash in Ask mode ===&lt;br /&gt;
&lt;br /&gt;
; Description : A malicious objects scans for all avatars within the sensor range. For each avatar a new object is rezes out of the content. This objects sends 10 messages to the relay each of about 1000 characters causing sPendingMessage to overflow. After the 10 messages are send these objects die making tracking very difficult.&lt;br /&gt;
; Note : Some relays accept commands from objects more than &amp;lt;del&amp;gt;20&amp;lt;/del&amp;gt;100 meters away so the attacking objects can be hidden far away.&lt;br /&gt;
; Workaround : None&lt;br /&gt;
; Open : although fixed in version 1.15 it was reintroduced by the revert in version 1.02&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1.015 ==&lt;br /&gt;
&lt;br /&gt;
The below problems are fixed [[LSL_Protocol/Restrained_Life_Relay/Other_Implementations/Maike_Short&#039;s_Relay|here]]&lt;br /&gt;
&lt;br /&gt;
== 1.014 ==&lt;br /&gt;
&lt;br /&gt;
The following problems occured in version 1.014 and have been fixed:&lt;br /&gt;
&lt;br /&gt;
=== Stuck: Accepting Permission Dialog after !release ===&lt;br /&gt;
; Discovered by : Maike Short&lt;br /&gt;
; Workaround : Don&#039;t accept requests after you have been freed. In case it happend, reenter the cage / sit down again; relog.&lt;br /&gt;
; Fixed : in 1.015&lt;br /&gt;
&lt;br /&gt;
=== Force Sit during Login on the control object instead of the forced-sit one ===&lt;br /&gt;
&lt;br /&gt;
; Discovered by : Azoth Amat&lt;br /&gt;
; Workaround : Always send a &amp;quot;@sit:&amp;lt;id&amp;gt;=force&amp;quot; command if you want a forced sit on relog, even if the victim is already sitting.&lt;br /&gt;
; Fix : change in &amp;lt;code&amp;gt;timer()&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)lastForceSitDestination+&amp;quot;=force&amp;quot;);&amp;lt;/code&amp;gt;&lt;br /&gt;
; Note : This prevents @unsit to work in case the person set down without being forced if the furniture in question hasn&#039;t sent a @sit:&amp;lt;id&amp;gt;=force command.  (This should probably be considered a bug in the furniture, not the relay.)&lt;br /&gt;
; Fixed : in 1.015, and 1.02 if the workaround above is used&lt;br /&gt;
&lt;br /&gt;
=== Stuck on crash/relog with objects asking for relay upon being sat on ===&lt;br /&gt;
&lt;br /&gt;
; Discovered by : Gregor Mougin&lt;br /&gt;
; Problem : Many objects check for presence of a relay and the RR viewer by asking for the !version when sat on. If the user crashes, and the object was used by someone else in the meantime (or, for testing, reset), the relay enforces all previous restrictions whereas the object doesn&#039;t know of them.&lt;br /&gt;
; Workaround : none&lt;br /&gt;
; Suggested fix : &lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
--- RLV_v1.014a 2008-07-06 23:17:14.000000000 +0200&lt;br /&gt;
+++ RLV_v1.014a-xxx     2008-07-06 23:18:32.000000000 +0200&lt;br /&gt;
@@ -545,10 +545,16 @@&lt;br /&gt;
                 loginPendingForceSit = FALSE;&lt;br /&gt;
                 releaseRestrictions();&lt;br /&gt;
             }&lt;br /&gt;
-            else&lt;br /&gt;
-            {&lt;br /&gt;
-                 sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
-            }&lt;br /&gt;
+            // XXX&lt;br /&gt;
+            // DON&#039;T do it here&lt;br /&gt;
+            // Some (many?) objects ask the relay for the !version upon&lt;br /&gt;
+            // sitting on it. Since the !version is interpreted the same&lt;br /&gt;
+            // as !pong, the relay would think the object is still available&lt;br /&gt;
+            // and put all restrictions on the wearer unconditionally.&lt;br /&gt;
+            //else&lt;br /&gt;
+            //{&lt;br /&gt;
+            //    sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
+            //}&lt;br /&gt;
         }&lt;br /&gt;
  &lt;br /&gt;
         if (!loginPendingForceSit &amp;amp;&amp;amp; !loginWaitingForPong)&lt;br /&gt;
@@ -583,6 +589,18 @@&lt;br /&gt;
  &lt;br /&gt;
             loginWaitingForPong = FALSE; // whatever the message, it is for me =&amp;gt; it satisfies the ping request&lt;br /&gt;
  &lt;br /&gt;
+            // XXX&lt;br /&gt;
+            // force sit here instead of unconditionally in the timer event&lt;br /&gt;
+            if (loginPendingForceSit)&lt;br /&gt;
+            {&lt;br /&gt;
+                integer agentInfo = llGetAgentInfo(llGetOwner());&lt;br /&gt;
+                &lt;br /&gt;
+                loginPendingForceSit = FALSE;&lt;br /&gt;
+                if (!(agentInfo &amp;amp; AGENT_SITTING))&lt;br /&gt;
+                    sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
+            }&lt;br /&gt;
+            // end XXX&lt;br /&gt;
+            &lt;br /&gt;
             if (!isObjectKnow(id))&lt;br /&gt;
             {&lt;br /&gt;
                 debug(&amp;quot;asking for permission because kSource is NULL_KEY&amp;quot;);&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
; Fixed : in 1.015 by specially looking for the !pong reply so that the fix works for cages  as well (no &amp;quot;force sit&amp;quot; in this situation but a collision detection which is triggered on login, too).&lt;/div&gt;</summary>
		<author><name>Julia Banshee</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Bugs_and_Pending_Features&amp;diff=91554</id>
		<title>LSL Protocol/Restrained Love Relay/Bugs and Pending Features</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Bugs_and_Pending_Features&amp;diff=91554"/>
		<updated>2008-09-16T18:41:35Z</updated>

		<summary type="html">&lt;p&gt;Julia Banshee: /* Force Sit during Login on the control object instead of the forced-sit one */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Restrained Life Relay Specs TOC}}&lt;br /&gt;
&lt;br /&gt;
== 1.02 ==&lt;br /&gt;
&lt;br /&gt;
Version 1.02 reintroduces all the problems listed in 1.014.&lt;br /&gt;
&lt;br /&gt;
=== Relay Crash in Ask mode ===&lt;br /&gt;
&lt;br /&gt;
; Description : A malicious objects scans for all avatars within the sensor range. For each avatar a new object is rezes out of the content. This objects sends 10 messages to the relay each of about 1000 characters causing sPendingMessage to overflow. After the 10 messages are send these objects die making tracking very difficult.&lt;br /&gt;
; Note : Some relays accept commands from objects more than &amp;lt;del&amp;gt;20&amp;lt;/del&amp;gt;100 meters away so the attacking objects can be hidden far away.&lt;br /&gt;
; Workaround : None&lt;br /&gt;
; Open : although fixed in version 1.15 it was reintroduced by the revert in version 1.02&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1.015 ==&lt;br /&gt;
&lt;br /&gt;
The below problems are fixed [[LSL_Protocol/Restrained_Life_Relay/Other_Implementations/Maike_Short&#039;s_Relay|here]]&lt;br /&gt;
&lt;br /&gt;
== 1.014 ==&lt;br /&gt;
&lt;br /&gt;
The following problems occured in version 1.014 and have been fixed:&lt;br /&gt;
&lt;br /&gt;
=== Stuck: Accepting Permission Dialog after !release ===&lt;br /&gt;
; Discovered by : Maike Short&lt;br /&gt;
; Workaround : Don&#039;t accept requests after you have been freed. In case it happend, reenter the cage / sit down again; relog.&lt;br /&gt;
; Fixed : in 1.015&lt;br /&gt;
&lt;br /&gt;
=== Force Sit during Login on the control object instead of the forced-sit one ===&lt;br /&gt;
&lt;br /&gt;
; Discovered by : Azoth Amat&lt;br /&gt;
; Workaround : Always send a &amp;quot;@sit:&amp;lt;id&amp;gt;=force&amp;quot; command if you want a forced sit on relog, even if the victim is already sitting.&lt;br /&gt;
; Broken fix attempt : change in &amp;lt;code&amp;gt;timer()&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)lastForceSitDestination+&amp;quot;=force&amp;quot;);&amp;lt;/code&amp;gt;&lt;br /&gt;
; Note : This prevents @unsit to work in case the person set down without being forced if the furniture in question hasn&#039;t sent a @sit:&amp;lt;id&amp;gt;=force command.  (This should probably be considered a bug in the furniture, not the relay.)&lt;br /&gt;
; Fixed : in 1.015, and 1.02 if the workaround above is used&lt;br /&gt;
&lt;br /&gt;
=== Stuck on crash/relog with objects asking for relay upon being sat on ===&lt;br /&gt;
&lt;br /&gt;
; Discovered by : Gregor Mougin&lt;br /&gt;
; Problem : Many objects check for presence of a relay and the RR viewer by asking for the !version when sat on. If the user crashes, and the object was used by someone else in the meantime (or, for testing, reset), the relay enforces all previous restrictions whereas the object doesn&#039;t know of them.&lt;br /&gt;
; Workaround : none&lt;br /&gt;
; Suggested fix : &lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
--- RLV_v1.014a 2008-07-06 23:17:14.000000000 +0200&lt;br /&gt;
+++ RLV_v1.014a-xxx     2008-07-06 23:18:32.000000000 +0200&lt;br /&gt;
@@ -545,10 +545,16 @@&lt;br /&gt;
                 loginPendingForceSit = FALSE;&lt;br /&gt;
                 releaseRestrictions();&lt;br /&gt;
             }&lt;br /&gt;
-            else&lt;br /&gt;
-            {&lt;br /&gt;
-                 sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
-            }&lt;br /&gt;
+            // XXX&lt;br /&gt;
+            // DON&#039;T do it here&lt;br /&gt;
+            // Some (many?) objects ask the relay for the !version upon&lt;br /&gt;
+            // sitting on it. Since the !version is interpreted the same&lt;br /&gt;
+            // as !pong, the relay would think the object is still available&lt;br /&gt;
+            // and put all restrictions on the wearer unconditionally.&lt;br /&gt;
+            //else&lt;br /&gt;
+            //{&lt;br /&gt;
+            //    sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
+            //}&lt;br /&gt;
         }&lt;br /&gt;
  &lt;br /&gt;
         if (!loginPendingForceSit &amp;amp;&amp;amp; !loginWaitingForPong)&lt;br /&gt;
@@ -583,6 +589,18 @@&lt;br /&gt;
  &lt;br /&gt;
             loginWaitingForPong = FALSE; // whatever the message, it is for me =&amp;gt; it satisfies the ping request&lt;br /&gt;
  &lt;br /&gt;
+            // XXX&lt;br /&gt;
+            // force sit here instead of unconditionally in the timer event&lt;br /&gt;
+            if (loginPendingForceSit)&lt;br /&gt;
+            {&lt;br /&gt;
+                integer agentInfo = llGetAgentInfo(llGetOwner());&lt;br /&gt;
+                &lt;br /&gt;
+                loginPendingForceSit = FALSE;&lt;br /&gt;
+                if (!(agentInfo &amp;amp; AGENT_SITTING))&lt;br /&gt;
+                    sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
+            }&lt;br /&gt;
+            // end XXX&lt;br /&gt;
+            &lt;br /&gt;
             if (!isObjectKnow(id))&lt;br /&gt;
             {&lt;br /&gt;
                 debug(&amp;quot;asking for permission because kSource is NULL_KEY&amp;quot;);&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
; Fixed : in 1.015 by specially looking for the !pong reply so that the fix works for cages  as well (no &amp;quot;force sit&amp;quot; in this situation but a collision detection which is triggered on login, too).&lt;/div&gt;</summary>
		<author><name>Julia Banshee</name></author>
	</entry>
	<entry>
		<id>https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Bugs_and_Pending_Features&amp;diff=91553</id>
		<title>LSL Protocol/Restrained Love Relay/Bugs and Pending Features</title>
		<link rel="alternate" type="text/html" href="https://wiki.secondlife.com/w/index.php?title=LSL_Protocol/Restrained_Love_Relay/Bugs_and_Pending_Features&amp;diff=91553"/>
		<updated>2008-09-16T18:40:34Z</updated>

		<summary type="html">&lt;p&gt;Julia Banshee: /* Force Sit during Login on the control object instead of the forced-sit one */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Restrained Life Relay Specs TOC}}&lt;br /&gt;
&lt;br /&gt;
== 1.02 ==&lt;br /&gt;
&lt;br /&gt;
Version 1.02 reintroduces all the problems listed in 1.014.&lt;br /&gt;
&lt;br /&gt;
=== Relay Crash in Ask mode ===&lt;br /&gt;
&lt;br /&gt;
; Description : A malicious objects scans for all avatars within the sensor range. For each avatar a new object is rezes out of the content. This objects sends 10 messages to the relay each of about 1000 characters causing sPendingMessage to overflow. After the 10 messages are send these objects die making tracking very difficult.&lt;br /&gt;
; Note : Some relays accept commands from objects more than &amp;lt;del&amp;gt;20&amp;lt;/del&amp;gt;100 meters away so the attacking objects can be hidden far away.&lt;br /&gt;
; Workaround : None&lt;br /&gt;
; Open : although fixed in version 1.15 it was reintroduced by the revert in version 1.02&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 1.015 ==&lt;br /&gt;
&lt;br /&gt;
The below problems are fixed [[LSL_Protocol/Restrained_Life_Relay/Other_Implementations/Maike_Short&#039;s_Relay|here]]&lt;br /&gt;
&lt;br /&gt;
== 1.014 ==&lt;br /&gt;
&lt;br /&gt;
The following problems occured in version 1.014 and have been fixed:&lt;br /&gt;
&lt;br /&gt;
=== Stuck: Accepting Permission Dialog after !release ===&lt;br /&gt;
; Discovered by : Maike Short&lt;br /&gt;
; Workaround : Don&#039;t accept requests after you have been freed. In case it happend, reenter the cage / sit down again; relog.&lt;br /&gt;
; Fixed : in 1.015&lt;br /&gt;
&lt;br /&gt;
=== Force Sit during Login on the control object instead of the forced-sit one ===&lt;br /&gt;
&lt;br /&gt;
; Discovered by : Azoth Amat&lt;br /&gt;
; Workaround : Always send a &amp;quot;@sit:&amp;lt;id&amp;gt;=force&amp;quot; command if you want a forced sit on relog, even if the victim is already sitting.&lt;br /&gt;
; Broken fix attempt : change in &amp;lt;code&amp;gt;timer()&amp;lt;/code&amp;gt;: &amp;lt;code&amp;gt;sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)lastForceSitDestination+&amp;quot;=force&amp;quot;);&amp;lt;/code&amp;gt;&lt;br /&gt;
; Note : This prevents @unsit to work in case the person set down without being forced if the furniture in question hasn&#039;t sent a @sit:&amp;lt;id&amp;gt;=force command.  (This should probably be considered a bug in the furniture, not the relay.)&lt;br /&gt;
; Fixed : in 1.015&lt;br /&gt;
&lt;br /&gt;
=== Stuck on crash/relog with objects asking for relay upon being sat on ===&lt;br /&gt;
&lt;br /&gt;
; Discovered by : Gregor Mougin&lt;br /&gt;
; Problem : Many objects check for presence of a relay and the RR viewer by asking for the !version when sat on. If the user crashes, and the object was used by someone else in the meantime (or, for testing, reset), the relay enforces all previous restrictions whereas the object doesn&#039;t know of them.&lt;br /&gt;
; Workaround : none&lt;br /&gt;
; Suggested fix : &lt;br /&gt;
&amp;lt;lsl&amp;gt;&lt;br /&gt;
--- RLV_v1.014a 2008-07-06 23:17:14.000000000 +0200&lt;br /&gt;
+++ RLV_v1.014a-xxx     2008-07-06 23:18:32.000000000 +0200&lt;br /&gt;
@@ -545,10 +545,16 @@&lt;br /&gt;
                 loginPendingForceSit = FALSE;&lt;br /&gt;
                 releaseRestrictions();&lt;br /&gt;
             }&lt;br /&gt;
-            else&lt;br /&gt;
-            {&lt;br /&gt;
-                 sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
-            }&lt;br /&gt;
+            // XXX&lt;br /&gt;
+            // DON&#039;T do it here&lt;br /&gt;
+            // Some (many?) objects ask the relay for the !version upon&lt;br /&gt;
+            // sitting on it. Since the !version is interpreted the same&lt;br /&gt;
+            // as !pong, the relay would think the object is still available&lt;br /&gt;
+            // and put all restrictions on the wearer unconditionally.&lt;br /&gt;
+            //else&lt;br /&gt;
+            //{&lt;br /&gt;
+            //    sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
+            //}&lt;br /&gt;
         }&lt;br /&gt;
  &lt;br /&gt;
         if (!loginPendingForceSit &amp;amp;&amp;amp; !loginWaitingForPong)&lt;br /&gt;
@@ -583,6 +589,18 @@&lt;br /&gt;
  &lt;br /&gt;
             loginWaitingForPong = FALSE; // whatever the message, it is for me =&amp;gt; it satisfies the ping request&lt;br /&gt;
  &lt;br /&gt;
+            // XXX&lt;br /&gt;
+            // force sit here instead of unconditionally in the timer event&lt;br /&gt;
+            if (loginPendingForceSit)&lt;br /&gt;
+            {&lt;br /&gt;
+                integer agentInfo = llGetAgentInfo(llGetOwner());&lt;br /&gt;
+                &lt;br /&gt;
+                loginPendingForceSit = FALSE;&lt;br /&gt;
+                if (!(agentInfo &amp;amp; AGENT_SITTING))&lt;br /&gt;
+                    sendRLCmd (&amp;quot;@sit:&amp;quot;+(string)kSource+&amp;quot;=force&amp;quot;);&lt;br /&gt;
+            }&lt;br /&gt;
+            // end XXX&lt;br /&gt;
+            &lt;br /&gt;
             if (!isObjectKnow(id))&lt;br /&gt;
             {&lt;br /&gt;
                 debug(&amp;quot;asking for permission because kSource is NULL_KEY&amp;quot;);&lt;br /&gt;
&amp;lt;/lsl&amp;gt;&lt;br /&gt;
; Fixed : in 1.015 by specially looking for the !pong reply so that the fix works for cages  as well (no &amp;quot;force sit&amp;quot; in this situation but a collision detection which is triggered on login, too).&lt;/div&gt;</summary>
		<author><name>Julia Banshee</name></author>
	</entry>
</feed>