LSL Protocol/Restrained Living Relay/Other Implementations/Dominatech RLV Relay

From Second Life Wiki
< LSL Protocol‎ | Restrained Living Relay/Other Implementations
Revision as of 01:11, 14 February 2009 by Julia Banshee (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

<lsl> // 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 General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // See http://www.gnu.org/licenses/gpl.html for terms of this license.

integer relayChannel = -1812221819; string version = "1030"; string implversion = "Dominatech Relay 2.0";

integer backChannel; // for @getsitid key sitting;

list objects; list restrictions;

list pingObjects; list pingRestrictions; key pingSitting; integer pingSitRetry;

integer lit;

integer askMode; list allowedObjects; list rejectedObjects; list pendingObjects; list pendingCommands;

integer permChannel; integer permListener; integer permClose;

updateStatus(integer r) {

   if ( r )
   {
       if ( ! lit )
       {
           llMessageLinked(LINK_SET, TRUE, "relay-lock", NULL_KEY);
           llSetColor(<1.0, 0.0, 0.0>, ALL_SIDES);
           lit = TRUE;
       }
   }
   else
   {
       if ( lit )
       {
           llMessageLinked(LINK_SET, FALSE, "relay-lock", NULL_KEY);
           llSetColor(<0.0, 1.0, 0.0>, ALL_SIDES);
           lit = FALSE;
       }
   }

}

clear(key obj) {

   integer o = llListFindList(objects, [obj]);
   if ( o >= 0 )
   {
       integer i;
       while ( (i = llListFindList(restrictions, [o])) >= 0 )
       {
           string restr = llList2String(restrictions, i + 1);
           restrictions = llDeleteSubList(restrictions, i, i + 1);
           if ( llListFindList(restrictions, [restr]) < 0 )
               llOwnerSay("@" + restr + "=y");
       }
   }
   if ( llGetListLength(restrictions) == 0 )
   {
       objects = [];
       updateStatus(FALSE);
   }

}

clearSome(key obj, string param) {

   integer o = llListFindList(objects, [obj]);
   if ( o >= 0 )
   {
       integer len = llGetListLength(restrictions);
       integer i;
       for ( i = 0 ; i < len ; i += 2 )
       {
           if ( llList2Integer(restrictions, i) == o )
           {
               string restr = llList2String(restrictions, i + 1);
               if ( llSubStringIndex(restr, param) >= 0 )
               {
                   restrictions = llDeleteSubList(restrictions, i, i + 1);
                   if ( llListFindList(restrictions, [restr]) < 0 )
                       llOwnerSay("@" + restr + "=y");
                   i -= 2;
                   len -= 2;
               }
           }
       }
   }
   if ( llGetListLength(restrictions) == 0 )
   {
       objects = [];
       updateStatus(FALSE);
   }

}

rlvCommand(key id, string cmd) {

   integer e = llSubStringIndex(cmd, "=");
   if ( e >= 0 )
   {
       string restr = llGetSubString(cmd, 1, e - 1);
       string param = llGetSubString(cmd, e + 1, -1);
       if ( param == "n" || param == "add" )
       {
           llOwnerSay(cmd);
           integer i;
           integer o = llListFindList(objects, [id]);
           if ( o < 0 )
           {
               o = llGetListLength(objects);
               objects += id;
               i = -1;
           }
           else i = llListFindList(restrictions, [o, restr]);
           if ( i < 0 )
           {
               restrictions += [o, restr];
               updateStatus(TRUE);
           }
           if ( restr == "unsit" )
               llOwnerSay("@getsitid=" + (string)backChannel);
       }
       else if ( param == "y" || param == "rem" )
       {
           integer o = llListFindList(objects, [id]);
           if ( o >= 0 )
           {
               integer i = llListFindList(restrictions, [o, restr]);
               if ( i >= 0 )
               {
                   restrictions = llDeleteSubList(restrictions, i, i + 1);
                   if ( llGetListLength(restrictions) == 0 )
                   {
                       objects = [];
                       updateStatus(FALSE);
                   }
               }
           }
           if ( llListFindList(restrictions, [restr]) < 0 )
               llOwnerSay(cmd);
       }
       else
       {
           if ( restr == "clear" )
               clearSome(id, param);
           else
               llOwnerSay(cmd);
       }
   }
   else
   {
       if ( cmd == "@clear" )
           clear(id);
       else
           llOwnerSay(cmd);
   }

}

string getStatus(integer o) // it's okay if o is not an existing object, or -1, we just result an empty string {

   string result = "";
   integer len = llGetListLength(restrictions);
   integer i;
   for ( i = 0 ; i < len ; i += 2 )
       if ( llList2Integer(restrictions, i) == o )
           result += "/" + llList2String(restrictions, i + 1);
   return result;

}

integer allowCommand(key id, string cmd) {

   if ( ! askMode ) return TRUE;                                 // not in ask mode, automatically allow
   if ( llListFindList(allowedObjects, [id]) >= 0 ) return TRUE; // this object has permission
   if ( llGetOwnerKey(id) == llGetOwner() ) return TRUE;         // owner's own objects always have permission
   if ( llGetSubString(cmd, -2, -1) == "=n" ) return FALSE;      // adding restrictions not allowed without permission
   if ( llGetSubString(cmd, -4, -1) == "=add" ) return FALSE;    // adding restrictions not allowed without permission
   if ( llGetSubString(cmd, -6, -1) == "=force" ) return FALSE;  // forcing actions not allowed without permission
   return TRUE;                                                  // anything else is okay (e.g. @version)

}

default {

   state_entry()
   {
       llSetObjectName(implversion);
       
       lit = TRUE;
       updateStatus(FALSE);
       
       llListen(relayChannel, "", NULL_KEY, "");
       llListen(backChannel = 16777216 + (integer)llFrand(16777216.0), "", llGetOwner(), "");
       llSetTimerEvent(5.0);
       
       llMessageLinked(LINK_SET, -123, llGetScriptName() + " free: " + (string)llGetFreeMemory(), NULL_KEY);
   }
   
   listen(integer ch, string name, key id, string msg)
   {
       if ( ch == relayChannel )
       {
           list pack = llCSV2List(msg);
           key target = llList2String(pack, 1);
           if ( target == llGetOwner() )
           {
               string cmdid = llList2String(pack, 0);
               list cmds = llParseString2List(llList2String(pack, 2), ["|"], []);
               integer len = llGetListLength(cmds);
               integer i;
               for ( i = 0 ; i < len ; ++i )
               {
                   string cmd = llList2String(cmds, i);
                   if ( llGetSubString(cmd, 0, 0) == "@" )
                   {
                       if ( allowCommand(id, cmd) )
                       {
                           rlvCommand(id, cmd);
                           llShout(relayChannel, cmdid + "," + (string)id + "," + cmd + ",ok");
                       }
                       else if ( llListFindList(rejectedObjects, [id]) >= 0 )
                       {
                           llShout(relayChannel, cmdid + "," + (string)id + "," + cmd + ",ko");
                       }
                       else
                       {
                           integer p = llListFindList(pendingObjects, [id]);
                           if ( p < 0 )
                           {
                               p = llGetListLength(pendingObjects);
                               pendingObjects += id;
                               
                               list buttons;
                               if ( p )
                                   buttons = ["Yes " + (string)p, "No " + (string)p];
                               else
                                   buttons = ["Yes", "No"];
                               string object = llKey2Name(id);
                               string ownedby = llKey2Name(llGetOwnerKey(id));
                               if ( ownedby ) object += " (owned by " + ownedby + ")";
                               if ( ! permListener )
                                   permListener = llListen(permChannel = -16777216 - (integer)llFrand(16777216.0), "", llGetOwner(), "");
                               llDialog(llGetOwner(), "The object " + object
                                   + " is attempting to use your Restrained Life Viewer relay.  Do you wish to allow it?", buttons, permChannel);
                               permClose = llGetUnixTime() + 120;
                           }
                           if ( llListFindList(pendingCommands, [p, cmdid, cmd]) < 0 ) // some devices spam the same command over and over, don't keep growing list
                               pendingCommands += [p, cmdid, cmd];
                       }
                   }
                   else if ( cmd == "!release" )
                   {
                       clear(id);
                       llShout(relayChannel, cmdid + "," + (string)id + "," + cmd + ",ok");
                   }
                   else if ( cmd == "!getstatus" )
                   {
                       integer o = llListFindList(objects, [id]);
                       llShout(relayChannel, cmdid + "," + (string)id + "," + cmd + "," + getStatus(o));
                   }
                   else if ( cmd == "!version" )
                   {
                       llShout(relayChannel, cmdid + "," + (string)id + "," + cmd + "," + version);
                   }
                   else if ( cmd == "!implversion" )
                   {
                       llShout(relayChannel, cmdid + "," + (string)id + "," + cmd + "," + implversion);
                   }
                   else if ( cmd == "!pong" )
                   {
                       integer p = llListFindList(pingObjects, [id]);
                       if ( p >= 0 )
                       {
                           llOwnerSay("Got pong, you're out of luck.  Reapplying restrictions from " + name + "...");
                           integer o = llListFindList(objects, [id]);
                           if ( o < 0 )
                           {
                               o = llGetListLength(objects);
                               objects += id;
                           }
                           string cmd = "";
                           string pre = "@";
                           integer i;
                           while ( (i = llListFindList(pingRestrictions, [p])) >= 0 )
                           {
                               string restr = llList2String(pingRestrictions, i + 1);
                               if ( restr == "unsit" )
                               {
                                   if ( pingSitting )
                                   {
                                       llOwnerSay("@sit:" + (string)pingSitting + "=force");
                                       pingSitRetry = 12; // keep trying for a minute -- it can take that long for things to rez
                                   }
                               }
                               cmd += pre + restr + "=n";
                               pre = ",";
                               restrictions += [o, restr];
                               pingRestrictions = llDeleteSubList(pingRestrictions, i, i + 1);
                           }
                           if ( cmd )
                               llOwnerSay(cmd);
                           updateStatus(TRUE);
                           if ( llGetListLength(pingRestrictions) == 0 )
                               pingObjects = [];
                       }
                   }
               }
           }
           else if ( target == llGetKey() )
           {
               string cmdid = llList2String(pack, 0);
               if ( cmdid == "uniquecheck" )
                   llOwnerSay("You are wearing another RLV relay (" + name + ").  Remove it.  You should never wear more than one RLV relay at a time.");
           }
           return;
       }
       
       if ( ch == permChannel )
       {
           integer o = (integer) llGetSubString(msg, -2, -1);
           key obj = llList2Key(pendingObjects, o);
           if ( llGetSubString(msg, 0, 2) == "Yes" )
           {
               allowedObjects = obj + llList2List(allowedObjects, 0, 8);
               integer i;
               while ( (i = llListFindList(pendingCommands, [o])) >= 0 )
               {
                   string cmd = llList2String(pendingCommands, i + 2);
                   rlvCommand(obj, cmd);
                   llShout(relayChannel, llList2String(pendingCommands, i + 1) + "," + (string)obj + "," + cmd + ",ok");
                   pendingCommands = llDeleteSubList(pendingCommands, i, i + 2);
               }
               if ( llGetListLength(pendingCommands) == 0 )
                   pendingObjects = [];
           }
           else
           {
               rejectedObjects = obj + llList2List(rejectedObjects, 0, 8);
               integer i;
               while ( (i = llListFindList(pendingCommands, [o])) >= 0 )
               {
                   string cmd = llList2String(pendingCommands, i + 2);
                   llShout(relayChannel, llList2String(pendingCommands, i + 1) + "," + (string)obj + "," + cmd + ",ko");
                   pendingCommands = llDeleteSubList(pendingCommands, i, i + 2);
               }
               if ( llGetListLength(pendingCommands) == 0 )
                   pendingObjects = [];
           }
           return;
       }
       
       if ( ch == backChannel )
       {
           sitting = msg;
           return;
       }
   }
   
   on_rez(integer param)
   {
       if ( objects )
       {
           integer len = llGetListLength(objects);
           integer i;
           for ( i = 0 ; i < len ; ++i )
               if ( llListFindList(restrictions, [i]) >= 0 )
                   llShout(relayChannel, "ping," + (string)llList2Key(objects, i) + ",ping,ping");
       }
       
       pingObjects = objects;
       pingRestrictions = restrictions;
       pingSitting = sitting;
       pingSitRetry = 0;
       
       objects = [];
       restrictions = [];
       sitting = NULL_KEY;
       updateStatus(FALSE);
       
       allowedObjects = [];
       rejectedObjects = [];
       pendingObjects = [];
       pendingCommands = [];
   }
   
   timer()
   {
       if ( llGetAgentInfo(llGetOwner()) & AGENT_ON_OBJECT )
       {
           llOwnerSay("@getsitid=" + (string)backChannel);
           pingSitRetry = 0;
       }
       else
       {
           sitting = NULL_KEY;
           if ( pingSitRetry )
           {
               llOwnerSay("@sit:" + (string)pingSitting + "=force");
               --pingSitRetry;
           }
       }
       
       if ( permListener )
       {
           if ( llGetUnixTime() >= permClose )
           {
               pendingObjects = [];
               pendingCommands = [];
               llListenRemove(permListener);
               permListener = 0;
           }
       }
   }
   
   link_message(integer src, integer num, string msg, key id)
   {
       if ( msg == "relay-ask" )
       {
           askMode = num;
           if ( askMode )
           {
               allowedObjects = objects;
               rejectedObjects = [];
               pendingObjects = [];
               pendingCommands = [];
           }
           else if ( permListener )
           {
               allowedObjects = [];
               rejectedObjects = [];
               pendingObjects = [];
               pendingCommands = [];
               llListenRemove(permListener);
               permListener = 0;
           }
           return;
       }
       
       if ( msg == "relay-status" )
       {
           integer len = llGetListLength(objects);
           if ( len )
           {
               integer i;
               for ( i = 0 ; i < len ; ++i )
                   llMessageLinked(LINK_SET, num, getStatus(i), llList2Key(objects, i));
           }
           else
               llMessageLinked(LINK_SET, num, "", NULL_KEY);
           return;
       }
       
       if ( msg == "relay-reset" )
       {
           integer len = llGetListLength(objects);
           integer i;
           for ( i = 0 ; i < len ; ++i )
               llShout(relayChannel, "safeword," + (string)llList2Key(objects, i) + ",!release,ok");
           llResetScript();
           return;
       }
   }
   
   attach(key id)
   {
       if ( id )
           llWhisper(relayChannel, "uniquecheck," + (string)id + ",!version");
   }
   
   changed(integer change)
   {
       if ( change & CHANGED_OWNER )
           llResetScript();
   }

} </lsl>