Difference between revisions of "User:Kireji Haiku/SIMchat headset"

From Second Life Wiki
Jump to navigation Jump to search
m (color - yay!)
m (<lsl> tag to <source>)
 
(28 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{Help |Wiki=*}}
{{LSL Header}}
{{LSL Header}}
<span id="top"></span>
<div style="float:right;">__TOC__</div>
<div style="float:right;">__TOC__</div>
=SIMchat headset=
<div id="box">
<div id="box">
==SCRIPT:==
<div style="padding: 0.5em;">
<div style="padding: 0.5em;">


= SIMchat headset by [[User:Kireji Haiku|Kireji]] =


This script is being provided "as is". It's been thoroughly tested in May 2010.
== General information: ==


If you want to use it, you should drop it into a <font color="red">childprim</font> of a linkset.
This setup will give you the possibilty to forward your chat on a certain channel <font color="red">within</font> the whole region your are in and <font color="red">encrypt</font> it.
Just make sure anybody you want to talk to has the same variables as you do.


</div></div>
[[File:SIMchat_Headset.jpg|thumb|700px|center|This is what it could look like. There's no particle system in the script, I just added it for demonstration purposes.]]
[http://wiki.secondlife.com/wiki/User:Kireji_Haiku/SIMchat_headset Go to top!]
<lsl>
string  ProtocolSignature;
float  ProtocolVersion; // can range from 0.0 to 255.255
string  Password;
integer communicationsChannel;
string  Header;
string  strHex;
integer Debug;
integer listener;
integer gListenID = -1;
integer X;
integer Y;
integer Z;
key    user;
list    mainmenu = ["RegionCount","SLURL","SIMchatOFF","Chat info","Chat howto"];
integer ConfigRequired = TRUE; string ConfigNotecardSuffix = ".cfg"; float ConfigTimeout = 60.0; integer ConfigLineIndex; key ConfigRequestID; list ConfigCards; string ConfigCardName; integer ConfigCardIndex;
string  Name;
string  SLURL;
string  menu_info_1 = "


    This popup shows up because you touched your SIMchat headset.
[[File:SIMchat_Headset_grey.jpg|thumb|700px|center|Yellow marker shows the root prim (parent), red marker shows the invisible linked prim (child) containing the script.]]


        ";
[[#top|Back to top!]]
string  menu_info_2 = "Choose one of the following.";
integer mChannel = 8989;
string  prim_name;
string  prim_desc;
vector  Where;
string  CONTROLLER_ID = "A";
integer AUTO_START = TRUE;
list    particle_parameters=[];
list    target_parameters=[];


config_init()
== Script: ==
{
 
    strHex = "0123456789ABCDEF";
<source lang="lsl2">
    Password = "P@ssw0rd";
//  This script includes the XTEA-LSL-Implementation by:
    ProtocolVersion = 0.3;
//  - Morse Dillon
    ProtocolSignature = "ENC";
//  - Strife Onizuka
    mChannel = 8989;
//  - Dedric Mauriac
    communicationsChannel = 9;
//  - JB Kraft
}
//  http://wiki.secondlife.com/wiki/XTEA_Strong_Encryption_Implementation


config_dump()
//  Setup:
{
//  1. Make sure the object in which you want to use this script has more than one prim.
     say("You are using channel " + (string)communicationsChannel + " for chatting.");
//  2. Make sure the object is modifiable by you.
     say("Your password is: " + Password);
//  3. This script must go into a childprim of your object, it doesn't matter into which one.
    say("Your protocol version is " + (string)ProtocolVersion + ", your protocol signature " + ProtocolSignature + " and your stringHex is " + strHex);
//  4. After you have copied the script into your object, make sure everyone you want to talk to has the same
    say("The menu for the dialog-channel is: " + (string)mChannel);
//     settings for KEY1, KEY2, KEY3, KEY4 and COMM_CHANNEL. You can use any valid, positive (!) integer number
}
//     for COMM_CHANNEL excluding PUBLIC_CHANNEL (which is 0) and DEBUG_CHANNEL (which is 2147483647). Do not use
//    a negative channel!
//  5. When chatting, please type in local chat and add your channel. Example: If your COMM_CHANNEL was 9 then you'd type: '/9 hello'
//  6. The code is written for an avatar attachment (usually a headset / HUD) and will run in no-script areas.


config_parse(string str, string cardName, integer lineNum)
integer COMM_CHANNEL = 9;
integer KEY1        = 11111111;
integer KEY2        = 22222222;
integer KEY3        = 33333333;
integer KEY4        = 44444444;
//  If you're not sure what you're doing,
//  do NOT change anything below!
key    ownerKey;
string ownerName;
integer CYCLES    = 6;
list    cypherkey;
integer delta    = 0x9E3779B9;
integer ord(string chr)
{
{
    str = llStringTrim(str, STRING_TRIM_HEAD);
     if (llStringLength(chr) != 1)
     if (llGetSubString(str,0,0) == "/") {
        return;
    }
    list ldata  = llParseStringKeepNulls(str, ["="], [""]);
    string cmd  = llToUpper(llStringTrim(llList2String(ldata,0),STRING_TRIM));
    string arg1 = llStringTrim(llList2String(ldata,1),STRING_TRIM);
    if (cmd == "STRHEX")
     {
     {
         strHex = arg1;
         return ERR_GENERIC;
     }
     }
     else if (cmd == "CHANNEL")
     if (chr == " ")
     {
     {
         communicationsChannel = (integer)arg1;
         return 32;
     }
     }
     else if (cmd == "PASSWORD")
     string ASCII = "            \n                    !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
    return llSubStringIndex(ASCII, chr);
}
string chr(integer i)
{
    i %= 127;
 
    string ASCII = "            \n                    !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
    return llGetSubString(ASCII, i, i);
}
string DWord2Hex(integer m)
{
    string  result;
    integer index;
    string  characters = "0123456789ABCDEF"
    integer i;
    for (; i < 8; i++)
     {
     {
         Password = arg1;
         index  = (m >> (i * 4)) & 0xF;
        result = llInsertString(result, 0, llGetSubString(characters, index, index));
     }
     }
     else if (cmd == "VERSION")
     return result;
}
integer Hex2DWord(string m)
{
    integer result;
    string digit;
    integer value;
    integer index;
    string characters = "0123456789ABCDEF";
    integer i;
    for (; i < 8; i++)
     {
     {
         ProtocolVersion = (float)arg1;
         index = 8 - (i + 1);
        digit = llGetSubString(m,index,index);
        value = llSubStringIndex(characters, digit);
        result = result | value << (i * 4);
     }
     }
     else if (cmd == "SIGNATURE")
     return result;
}
string Encrypt(string cleartext)
{
    integer cyphertext_numeric;
    integer dword1;
    integer dword2;
    list    cypherblock;
    string  cyphertext;
 
    while(llStringLength(cleartext) & 0x7)
     {
     {
         ProtocolSignature = arg1;
         cleartext += " ";
     }
     }
     else if (cmd == "DIALOG")
 
     {
     integer character;
        mChannel = (integer)arg1;
     integer stringlength = llStringLength(cleartext);  
     }
 
     else if (cmd == "debug")
     integer i;
     while (i < stringlength)
     {
     {
         Debug = (integer) arg1;
         dword1 = ord(llGetSubString(cleartext,i,i));
    }
        i++;
}
        dword1 =  dword1 | (ord(llGetSubString(cleartext,i,i)) << 8);
        i++;
        dword1 =  dword1 | (ord(llGetSubString(cleartext,i,i)) << 16);
        i++;
        dword1 =  dword1 | (ord(llGetSubString(cleartext,i,i)) << 24);
        i++;


config_done() { if (Debug) { config_dump(); } say("Config done"); }
        dword2 =  ord(llGetSubString(cleartext,i,i));
        i++;
        dword2 =  dword2 | ord(llGetSubString(cleartext,i,i)) << 8;
        i++;
        dword2 =  dword2 | ord(llGetSubString(cleartext,i,i)) << 16;
        i++;
        dword2 =  dword2 | ord(llGetSubString(cleartext,i,i)) << 24;
        i++;


say(string str) { llSay(0, str); }
        cypherblock = TEAEncrypt(dword1,dword2,cypherkey);


debug(string str) { if (Debug) { say(llGetScriptName() + ": " + str); } }
        cyphertext = cyphertext + DWord2Hex(llList2Integer(cypherblock,0)) + DWord2Hex(llList2Integer(cypherblock,1));


integer next_card()
         dword1      = 0;
{
         dword2      = 0;
    if (ConfigCardIndex >= llGetListLength(ConfigCards)) {
        cypherblock = [];
         ConfigCards = [];
    }
         return (FALSE);
    }
    ConfigLineIndex = 0;
    ConfigCardName = llList2String(ConfigCards, ConfigCardIndex);
    ConfigCardIndex++;
    ConfigRequestID = llGetNotecardLine(ConfigCardName, ConfigLineIndex);
    say("Reading " + ConfigCardName);
    return (TRUE);
}


string error(string message)
    return cyphertext;
string Decrypt(string cyphertext)
{
{
     if(Debug) llSay(DEBUG_CHANNEL, message);
     integer dword1;
     return "";
     integer dword2;
}
    list    clearblock;
    string  cleartext;
    string  hexvalue1;
    string  hexvalue2;


string  decrypt(string password, string message)
     integer i;
{
     while (i < llStringLength(cyphertext))
     integer signatureLength = llStringLength(ProtocolSignature);
     {
     integer headerLength = signatureLength + 12;
         hexvalue1 += llGetSubString(cyphertext,i,i + 7);
    if(llStringLength(message) < signatureLength + 44)
         i = i + 8;
        return error("Too small for secret message.");
     if(llSubStringIndex(message, ProtocolSignature) != 0)
         return error("Unknown protocol.");
    integer index = signatureLength;
    string major = "0x" + llGetSubString(message, index, ++index);
    string minor = "0x" + llGetSubString(message, ++index, ++index);
    float version = (float)((string)((integer)major) + "." + (string)((integer)minor));
    if(version != ProtocolVersion)
         return error("Unknown version.");
    integer nonce = (integer)("0x" + llGetSubString(message, ++index, index + 7));
    message = llGetSubString(message, headerLength, -1);
    string oneTimePad = llMD5String(password, nonce);
    while(llStringLength(oneTimePad) < (llStringLength(message) / 2 * 3))
    oneTimePad += llMD5String(oneTimePad, nonce);
    oneTimePad = llStringToBase64(oneTimePad);
    message = llXorBase64StringsCorrect(message, oneTimePad);
    message = llBase64ToString(message);
    string digest = llGetSubString(message, 0, 31);
    message = llGetSubString(message, 32, -1);
    if(llMD5String(message, nonce) != digest)
        return error("Message digest was not valid.");
    return message;
}


string  hex(integer value)
         hexvalue2 += llGetSubString(cyphertext,i,i + 7);
{
         i = i + 8;
    integer digit = value & 0xF;
    string text = llGetSubString(strHex, digit, digit);
    value = (value >> 4) & 0xfffFFFF;
    integer odd = TRUE;
    while(value)
    {
         digit = value & 0xF;
        text = llGetSubString(strHex, digit, digit) + text;
        odd = !odd;
        value = value >> 4;
    }
    if(odd)
         text = "0" + text;
    return text;
}


string  encrypt(string password, string message)
        dword1 = Hex2DWord(hexvalue1);
{
         dword2 = Hex2DWord(hexvalue2);  
    integer nonce = (integer)llFrand(0x7FFFFFFF);
    message = llMD5String(message, nonce) + message;
    string oneTimePad = llMD5String(password, nonce);
    integer count = (llStringLength(message) - 1) / 32;
    if(count)
         do
            oneTimePad += llMD5String(oneTimePad, nonce);
    while(--count);
    return Header + llGetSubString("00000000" + hex(nonce), -8, -1) + llXorBase64StringsCorrect(llStringToBase64(message), llStringToBase64(oneTimePad));
}


init1()
        clearblock = TEADecrypt(dword1, dword2, cypherkey);
{
    list versions = llParseString2List((string)ProtocolVersion, ["."], []);
    string minor = llList2String(versions, 1);
    integer p = 0;
    while(llGetSubString(minor, --p, p) == "0");
    Header = ProtocolSignature + hex(llList2Integer(versions, 0)) + hex((integer)llGetSubString(minor, 0xFF000000, p));
}


init2()
        cleartext += chr( llList2Integer(clearblock, 0) & 0x000000FF);
{
         cleartext += chr( (llList2Integer(clearblock, 0) & 0x0000FF00)  >> 8);
    if(listener != 0)
         cleartext += chr( (llList2Integer(clearblock, 0) & 0x00FF0000)  >> 16);
    {
        cleartext += chr( (llList2Integer(clearblock, 0) & 0xFF000000)  >> 24);
         llListenRemove(listener);
         listener = 0;
    }
    listener = llListen(communicationsChannel, "", NULL_KEY, "");
}


default
        cleartext += chr( llList2Integer(clearblock, 1) & 0x000000FF);
{
         cleartext += chr( (llList2Integer(clearblock, 1) & 0x0000FF00)  >> 8);
    state_entry() {
        cleartext += chr( (llList2Integer(clearblock, 1) & 0x00FF0000)  >> 16);
         llSetText("", <1.0,1.0,1.0>, 1.0);
         cleartext += chr( (llList2Integer(clearblock, 1) & 0xFF000000)  >> 24);
         state s_config;
    }
}


state s_reconfig { state_entry() { state s_config; } }
        hexvalue1  = "";
        hexvalue2  = "";
        dword1    = 0;
        dword2    = 0;
        clearblock = [];
    }


state s_config
     return cleartext;
{
     state_entry() {
        config_init();
        string item;
        ConfigCards = [];
        integer n = llGetInventoryNumber(INVENTORY_NOTECARD);
        while (n-- > 0) { item = llGetInventoryName(INVENTORY_NOTECARD, n); if (llSubStringIndex(item, ConfigNotecardSuffix) != -1) { ConfigCards += [item]; }
        }
        ConfigCardIndex = 0;
        if (next_card()) { llSetTimerEvent(ConfigTimeout); }
        else if (ConfigRequired) { say("Configuration notecard missing."); state s_configRetry; }
        else { state s_active; }
    }
    dataserver(key query_id, string data) {
        if (query_id == ConfigRequestID) {
            if (data == EOF) { if (! next_card()) { config_done(); state s_active; } }
            else { config_parse(data, ConfigCardName, ConfigLineIndex); ConfigRequestID = llGetNotecardLine(ConfigCardName, ++ConfigLineIndex); llSetTimerEvent(ConfigTimeout); }
        }
    }
    timer() { say("Dataserver time out: touch to retry"); state s_configRetry; }
    on_rez(integer num) { state s_reconfig; }
    changed(integer change) {
        if (change & CHANGED_OWNER) { llResetScript(); }
        if (change & CHANGED_INVENTORY) { state s_reconfig; }
    }
    state_exit() { llSetTimerEvent(0); }
}
}
   
   
state s_configRetry
list TEAEncrypt(integer dword1, integer dword2,list cypherkey)
{
{
     touch_start(integer tot) { if (llDetectedKey(0) == llGetOwner()) { state s_config; } }
     integer sum;
    list    cryptlist;
     changed(integer change) {
 
         if (change & CHANGED_OWNER) { llResetScript(); }
    integer n = CYCLES;
         if (change & CHANGED_INVENTORY) { state s_config; }
     while (n-- > 0)
    {
         dword1 = dword1 + ( ( dword2 << 4 ^ ((dword2 >> 5) & 0x07FFFFFF) ) + dword2 ^ sum + llList2Integer(cypherkey, (sum & 3) ) );
         sum += delta;
        dword2 = dword2 + ( ( dword1 << 4 ^ ((dword1 >> 5) & 0x07FFFFFF) ) + dword1 ^ sum + llList2Integer(cypherkey, ((sum >> 11) & 3) ) );
     }
     }
    cryptlist = [dword1,dword2];
    return cryptlist;
}
}
 
state s_unconfigured
list TEADecrypt(integer dword1, integer dword2,list cypherkey)
{
{
     state_entry() { llSetText("Configuration missing", <1.0,1.0,1.0>, 1.0); }
     integer sum = delta * CYCLES;
     list    cryptlist;
    changed(integer change) {
        if (change & CHANGED_OWNER) { llResetScript(); }
        if (change & CHANGED_INVENTORY) { state s_reconfig; }
     }
    state_exit() { llSetText("", <1.0,1.0,1.0>, 1.0); }
}


state s_active
    integer n = CYCLES;
{
     while (n-- > 0)
     state_entry()
     {
     {
         llListenRemove(gListenID);
         dword2 = dword2 - ( ( dword1 << 4 ^ ((dword1 >> 5) & 0x07FFFFFF) ) + dword1 ^ sum + llList2Integer(cypherkey, ((sum >> 11) & 3) ) );
        gListenID = llListen(communicationsChannel, "", "", "");
         sum -= delta;
        init1();
         dword1 = dword1 - ( ( dword2 << 4 ^ ((dword2 >> 5) & 0x07FFFFFF) ) + dword2 ^ sum + llList2Integer(cypherkey, (sum & 3) ) );      
        init2();
        llOwnerSay("
            Initialisation complete!
            SIMchat online!
            Type /" + (string)communicationsChannel + " and then your message to talk to people that have their channel set the same.
            Touch headset for options.");
        prim_name = "SIMchat(" + llKey2Name(llGetOwner()) + ")";
         prim_desc = "Last reset was: " + llGetTimestamp();
         llSetObjectName(prim_name);
        llSetObjectDesc(prim_desc);
        particle_parameters = [
            PSYS_PART_START_SCALE,<0.02,0.02,FALSE>,PSYS_PART_END_SCALE,<0.5,0.5, FALSE>,
            PSYS_PART_START_COLOR,<0.94118,0.00000,0.23529>,PSYS_PART_END_COLOR,<1,0,0>,
            PSYS_PART_START_ALPHA,(float)0.5,PSYS_PART_END_ALPHA,(float)0.0,
            PSYS_SRC_BURST_PART_COUNT,(integer)4,
            PSYS_SRC_BURST_RATE,(float)7.5,
            PSYS_PART_MAX_AGE,(float)0.5,
            PSYS_SRC_PATTERN,(integer)1,
            PSYS_PART_FLAGS,(integer)(0 |PSYS_PART_INTERP_COLOR_MASK
                                        |PSYS_PART_INTERP_SCALE_MASK
                                        |PSYS_PART_EMISSIVE_MASK
                                        |PSYS_PART_FOLLOW_SRC_MASK
                                        |PSYS_PART_TARGET_POS_MASK)];
        if ( AUTO_START ) llParticleSystem( particle_parameters );
     }
     }


    cryptlist = [dword1,dword2];
    return cryptlist;
}
default
{
     on_rez(integer start_param)
     on_rez(integer start_param)
     {
     {
         init1();
         if (llGetOwner() != ownerKey)
        init2();
        llResetScript();
    }
 
    attach(key id)
    {
        if (id)
         {
         {
             llOwnerSay("Headset has been reset.");
             llReleaseControls();
             llResetScript();
             llResetScript();
         }
         }
     }
     }
 
     touch_start(integer total_number)
     changed(integer change)
     {
     {
         if (llDetectedKey(0) == llGetOwner())
         if (change & CHANGED_OWNER)
         {
         {
             user = llGetOwner();
             llReleaseControls();
             llDialog(user, menu_info_1 + menu_info_2,mainmenu,mChannel);
             llResetScript();
            llListen(mChannel,llKey2Name(user),user,"");
         }
         }
     }
     }
    state_entry()
    {
        ownerKey  = llGetOwner();
        ownerName = llKey2Name(ownerKey);
        cypherkey = [KEY1, KEY2, KEY3, KEY4];
        string timeStamp = llGetTimestamp();
        llSetLinkPrimitiveParamsFast(LINK_THIS, [
            PRIM_NAME, ownerName,
            PRIM_DESC, timeStamp]);
        llRequestPermissions(ownerKey, PERMISSION_TAKE_CONTROLS);


        llListen(COMM_CHANNEL, "", NULL_KEY, "");
    }
     listen(integer channel, string name, key id, string message)
     listen(integer channel, string name, key id, string message)
     {
     {
         if(id==user)
        if (channel != COMM_CHANNEL)
        {
            return;
        }
         if (id == ownerKey)
         {
         {
             if(message=="SLURL")
             llRegionSay(COMM_CHANNEL, Encrypt(message));
            {
             llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_NAME, ""]);
                Name = llGetRegionName();
             llOwnerSay("/me [" + ownerName + "]: '" + message + "'");
                Where = llGetPos();
             llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_NAME, ownerName]);
                X = (integer)Where.x;
                Y = (integer)Where.y;
                Z = (integer)Where.z;
                SLURL = "SLURL for this location is:\n\n" + "http://slurl.com/secondlife/" + Name + "/" + (string)X + "/" + (string)Y + "/" + (string)Z + "/";
                llSay(0, SLURL);
                return;
            }
            if(message=="SIMchatOFF")
            {
                state sleeping;
                return;
             }
            if(message=="Chat info")
            {
                llOwnerSay("Type /" + (string)communicationsChannel + " and then your message to talk to people that have their channel set the same.");
                return;
             }
            if(message=="Chat howto")
            {
                llOwnerSay("Type in local chat: /" + (string)communicationsChannel + " ... \nFor example: /" + (string)communicationsChannel + " hello, my name is Nick. \nEverybody in the same SIM using this SIMchat function on channel " + (string)communicationsChannel + " will be able to read what you write.\nRemember to use channel" + (string)communicationsChannel + "for anything you want to write with this SIMchat-tool. Local chat is limited to 20m radius and will not be encrypted.");
                return;
            }
             if(message=="RegionCount")
            {
                llOwnerSay("  Region count is now:" + (string)llGetRegionAgentCount());
                return;
            }
            else
            {
                //do nothing
            }
         }
         }
         if (channel == communicationsChannel)
         else if (llGetAgentSize(id) == ZERO_VECTOR)
         {
         {
             if (id == llGetOwner())
             message = Decrypt(message);
             {
             llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_NAME, ""]);
                llRegionSay(communicationsChannel, encrypt(Password, message));
            llOwnerSay("/me [" + name + "]: '" + message + "'");
                llOwnerSay("You said: " + message);
             llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_NAME, ownerName]);
            }
            if (llGetAgentSize(id) == ZERO_VECTOR)
            {
                string message = decrypt(Password, message);
                llOwnerSay((string)name + " said: " + (string)message);
             }
         }
         }
     }
     }
}
 
     run_time_permissions(integer perm)
state sleeping
{
    state_entry()
    {
        llOwnerSay("SIMchat offline! Touch headset to go back online.");
        particle_parameters = [];
        if ( AUTO_START ) llParticleSystem( particle_parameters );
    }
 
     touch_start(integer n)
     {
     {
         if (llDetectedKey(0) == llGetOwner())
         if (perm & PERMISSION_TAKE_CONTROLS)
         {
         {
             llOwnerSay("SIMchat back online! Touch headset for further informations.");
             llTakeControls(CONTROL_DOWN, TRUE, TRUE);
            state s_active;
         }
         }
     }
     }
 
     on_rez(integer start_param)
//  needs a control event for no-script-area hack
     control(key id, integer level, integer edge)
     {
     {
         llResetScript();
         ;
     }
     }
}
}
</lsl>
</source>
 
<div id="box">
==NOTECARD:==
<div style="padding: 0.5em;">
 
 
Name this notecard with an <font color="red">ending ".cfg"</font>, for example "SIMchat headset.cfg" or "config.cfg".
Commands (like "strhex", "channel", "password", ...) are NOT case sensitive, the values for the commands however ARE case sensitive.
It doesn't matter if you write "=" or " = ", both will be fine.
 
 
</div></div>


[http://wiki.secondlife.com/wiki/User:Kireji_Haiku/SIMchat_headset Go to top!]
[[#top|Back to top!]]
<lsl>
</div>
strhex = 123456789ABCDEF
</div>
channel = 9
password = P@ssw0rd
version = 0.3
signature = ENC
dialog = 8989
debug = 1
</lsl>

Latest revision as of 19:11, 24 January 2015

SIMchat headset by Kireji

General information:

If you want to use it, you should drop it into a childprim of a linkset. This setup will give you the possibilty to forward your chat on a certain channel within the whole region your are in and encrypt it. Just make sure anybody you want to talk to has the same variables as you do.

This is what it could look like. There's no particle system in the script, I just added it for demonstration purposes.
Yellow marker shows the root prim (parent), red marker shows the invisible linked prim (child) containing the script.

Back to top!

Script:

//  This script includes the XTEA-LSL-Implementation by:
//  - Morse Dillon
//  - Strife Onizuka
//  - Dedric Mauriac
//  - JB Kraft
//  http://wiki.secondlife.com/wiki/XTEA_Strong_Encryption_Implementation

//  Setup:
//  1. Make sure the object in which you want to use this script has more than one prim.
//  2. Make sure the object is modifiable by you.
//  3. This script must go into a childprim of your object, it doesn't matter into which one.
//  4. After you have copied the script into your object, make sure everyone you want to talk to has the same
//     settings for KEY1, KEY2, KEY3, KEY4 and COMM_CHANNEL. You can use any valid, positive (!) integer number
//     for COMM_CHANNEL excluding PUBLIC_CHANNEL (which is 0) and DEBUG_CHANNEL (which is 2147483647). Do not use
//     a negative channel!
//  5. When chatting, please type in local chat and add your channel. Example: If your COMM_CHANNEL was 9 then you'd type: '/9 hello'
//  6. The code is written for an avatar attachment (usually a headset / HUD) and will run in no-script areas.

 
integer COMM_CHANNEL = 9;
integer KEY1         = 11111111;
integer KEY2         = 22222222;
integer KEY3         = 33333333;
integer KEY4         = 44444444;
 
//  If you're not sure what you're doing,
//  do NOT change anything below!
 
key     ownerKey;
string  ownerName;
 
integer CYCLES    = 6;
 
list    cypherkey;
integer delta     = 0x9E3779B9;
 
integer ord(string chr)
{
    if (llStringLength(chr) != 1)
    {
        return ERR_GENERIC;
    }
    if (chr == " ")
    {
        return 32;
    }
 
    string ASCII = "             \n                    !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
    return llSubStringIndex(ASCII, chr);
}
 
string chr(integer i)
{
    i %= 127;

    string ASCII = "             \n                    !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
     return llGetSubString(ASCII, i, i);
}
 
string DWord2Hex(integer m)
{
    string  result;
    integer index;
    string  characters = "0123456789ABCDEF";   
 
    integer i;
    for (; i < 8; i++)
    {
        index  = (m >> (i * 4)) & 0xF;
        result = llInsertString(result, 0, llGetSubString(characters, index, index));
    }
 
    return result;
}
 
integer Hex2DWord(string m)
{
    integer result;
    string digit;
    integer value;
    integer index;
 
    string characters = "0123456789ABCDEF";
 
    integer i;
    for (; i < 8; i++)
    {
        index = 8 - (i + 1);
        digit = llGetSubString(m,index,index);
 
        value = llSubStringIndex(characters, digit);
 
        result = result | value << (i * 4);
    }
 
    return result;
}
 
string Encrypt(string cleartext)
{
    integer cyphertext_numeric;
    integer dword1;
    integer dword2;
    list    cypherblock;
    string  cyphertext;

    while(llStringLength(cleartext) & 0x7)
    {
        cleartext += " ";
    }

    integer character;
    integer stringlength = llStringLength(cleartext); 

    integer i;
    while (i < stringlength)
    {
        dword1 =  ord(llGetSubString(cleartext,i,i));
        i++;
        dword1 =  dword1 | (ord(llGetSubString(cleartext,i,i)) << 8);
        i++;
        dword1 =  dword1 | (ord(llGetSubString(cleartext,i,i)) << 16);
        i++;
        dword1 =  dword1 | (ord(llGetSubString(cleartext,i,i)) << 24);
        i++;

        dword2 =  ord(llGetSubString(cleartext,i,i));
        i++;
        dword2 =  dword2 | ord(llGetSubString(cleartext,i,i)) << 8;
        i++;
        dword2 =  dword2 | ord(llGetSubString(cleartext,i,i)) << 16;
        i++;
        dword2 =  dword2 | ord(llGetSubString(cleartext,i,i)) << 24;
        i++;

        cypherblock = TEAEncrypt(dword1,dword2,cypherkey);

        cyphertext = cyphertext + DWord2Hex(llList2Integer(cypherblock,0)) + DWord2Hex(llList2Integer(cypherblock,1));

        dword1      = 0;
        dword2      = 0;
        cypherblock = [];
     }

    return cyphertext;
}  
 
string Decrypt(string cyphertext)
{
    integer dword1;
    integer dword2;
    list    clearblock;
    string  cleartext;
    string  hexvalue1;
    string  hexvalue2;

    integer i;
    while (i < llStringLength(cyphertext))
    {
        hexvalue1 += llGetSubString(cyphertext,i,i + 7);
        i = i + 8;

        hexvalue2 += llGetSubString(cyphertext,i,i + 7);
        i = i + 8;

        dword1 = Hex2DWord(hexvalue1);
        dword2 = Hex2DWord(hexvalue2); 

        clearblock = TEADecrypt(dword1, dword2, cypherkey);

        cleartext += chr( llList2Integer(clearblock, 0) & 0x000000FF);
        cleartext += chr( (llList2Integer(clearblock, 0) & 0x0000FF00)  >> 8);
        cleartext += chr( (llList2Integer(clearblock, 0) & 0x00FF0000)  >> 16);
        cleartext += chr( (llList2Integer(clearblock, 0) & 0xFF000000)  >> 24);

        cleartext += chr( llList2Integer(clearblock, 1) & 0x000000FF);
        cleartext += chr( (llList2Integer(clearblock, 1) & 0x0000FF00)  >> 8);
        cleartext += chr( (llList2Integer(clearblock, 1) & 0x00FF0000)  >> 16);
        cleartext += chr( (llList2Integer(clearblock, 1) & 0xFF000000)  >> 24);

        hexvalue1  = "";
        hexvalue2  = "";
        dword1     = 0;
        dword2     = 0;
        clearblock = [];
     }

    return cleartext;
}
 
list TEAEncrypt(integer dword1, integer dword2,list cypherkey)
{
    integer sum;
    list    cryptlist;

    integer n = CYCLES;
    while (n-- > 0)
    {
        dword1 = dword1 + ( ( dword2 << 4 ^ ((dword2 >> 5) & 0x07FFFFFF) ) + dword2 ^ sum + llList2Integer(cypherkey, (sum & 3) ) );
        sum += delta;
        dword2 = dword2 + ( ( dword1 << 4 ^ ((dword1 >> 5) & 0x07FFFFFF) ) + dword1 ^ sum + llList2Integer(cypherkey, ((sum >> 11) & 3) ) );
    }

    cryptlist = [dword1,dword2];

    return cryptlist;
}
 
list TEADecrypt(integer dword1, integer dword2,list cypherkey)
{
    integer sum = delta * CYCLES;
    list    cryptlist;

    integer n = CYCLES;
    while (n-- > 0)
    {
        dword2 = dword2 - ( ( dword1 << 4 ^ ((dword1 >> 5) & 0x07FFFFFF) ) + dword1 ^ sum + llList2Integer(cypherkey, ((sum >> 11) & 3) ) );
        sum -= delta;
        dword1 = dword1 - ( ( dword2 << 4 ^ ((dword2 >> 5) & 0x07FFFFFF) ) + dword2 ^ sum + llList2Integer(cypherkey, (sum & 3) ) );        
    }

    cryptlist = [dword1,dword2];
    return cryptlist;
}
 
default
{
    on_rez(integer start_param)
    {
        if (llGetOwner() != ownerKey)
        {
            llReleaseControls();
            llResetScript();
        }
    }
 
    changed(integer change)
    {
        if (change & CHANGED_OWNER)
        {
            llReleaseControls();
            llResetScript();
        }
    }
 
    state_entry()
    {
        ownerKey  = llGetOwner();
        ownerName = llKey2Name(ownerKey);
        cypherkey = [KEY1, KEY2, KEY3, KEY4];

        string timeStamp = llGetTimestamp();
 
        llSetLinkPrimitiveParamsFast(LINK_THIS, [
            PRIM_NAME, ownerName,
            PRIM_DESC, timeStamp]);
 
        llRequestPermissions(ownerKey, PERMISSION_TAKE_CONTROLS);

        llListen(COMM_CHANNEL, "", NULL_KEY, "");
    }
 
    listen(integer channel, string name, key id, string message)
    {
        if (channel != COMM_CHANNEL)
        {
            return;
        }
 
        if (id == ownerKey)
        {
            llRegionSay(COMM_CHANNEL, Encrypt(message));
            llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_NAME, ""]);
            llOwnerSay("/me [" + ownerName + "]: '" + message + "'");
            llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_NAME, ownerName]);
        }
        else if (llGetAgentSize(id) == ZERO_VECTOR)
        {
            message = Decrypt(message);
            llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_NAME, ""]);
            llOwnerSay("/me [" + name + "]: '" + message + "'");
            llSetLinkPrimitiveParamsFast(LINK_THIS, [PRIM_NAME, ownerName]);
        }
    }
 
    run_time_permissions(integer perm)
    {
        if (perm & PERMISSION_TAKE_CONTROLS)
        {
            llTakeControls(CONTROL_DOWN, TRUE, TRUE);
        }
    }
 
//  needs a control event for no-script-area hack
    control(key id, integer level, integer edge)
    {
        ;
    }
}

Back to top!