User:Kireji Haiku/SIMchat headset
Help Portal: |
Avatar | Bug Fixes | Communication | Community | Glossary | Land & Sim | Multimedia | Navigation | Object | Video Tutorials | Viewer | Wiki | Misc |
LSL Portal | Functions | Events | Types | Operators | Constants | Flow Control | Script Library | Categorized Library | Tutorials |
SIMchat headset
SCRIPT:
This script is being provided "as is". It's been thoroughly tested in May 2010.
If you want to use it, you should drop it into a childprim of a linkset together with the notecard. 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 in the setup-notecard as you do.
You can turn off the SIMchat function (if you are being spammed on that channel...you could of course change the channel, too), get a SLURL to your current location, get the current count of avatars within the region or get a quick reminder of the currently-used-channel and a howto by touching the childprim containing this script and the attached setup notecard.
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.
";
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() {
strHex = "0123456789ABCDEF"; Password = "P@ssw0rd"; ProtocolVersion = 0.3; ProtocolSignature = "ENC"; mChannel = 8989; communicationsChannel = 9;
}
config_dump() {
say("You are using channel " + (string)communicationsChannel + " for chatting."); say("Your password is: " + Password); say("Your protocol version is " + (string)ProtocolVersion + ", your protocol signature " + ProtocolSignature + " and your stringHex is " + strHex); say("The menu for the dialog-channel is: " + (string)mChannel);
}
config_parse(string str, string cardName, integer lineNum) {
str = llStringTrim(str, STRING_TRIM_HEAD); 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; } else if (cmd == "CHANNEL") { communicationsChannel = (integer)arg1; } else if (cmd == "PASSWORD") { Password = arg1; } else if (cmd == "VERSION") { ProtocolVersion = (float)arg1; } else if (cmd == "SIGNATURE") { ProtocolSignature = arg1; } else if (cmd == "DIALOG") { mChannel = (integer)arg1; } else if (cmd == "debug") { Debug = (integer) arg1; }
}
config_done() { if (Debug) { config_dump(); } say("Config done"); }
say(string str) { llOwnerSay(str); }
debug(string str) { if (Debug) { say(llGetScriptName() + ": " + str); } }
integer next_card() {
if (ConfigCardIndex >= llGetListLength(ConfigCards)) { ConfigCards = []; return (FALSE); } ConfigLineIndex = 0; ConfigCardName = llList2String(ConfigCards, ConfigCardIndex); ConfigCardIndex++; ConfigRequestID = llGetNotecardLine(ConfigCardName, ConfigLineIndex); say("Reading " + ConfigCardName); return (TRUE);
}
string error(string message) {
if(Debug) llSay(DEBUG_CHANNEL, message); return "";
}
string decrypt(string password, string message) {
integer signatureLength = llStringLength(ProtocolSignature); integer headerLength = signatureLength + 12; if(llStringLength(message) < signatureLength + 44) 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) {
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) {
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() {
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() {
if(listener != 0) { llListenRemove(listener); listener = 0; } listener = llListen(communicationsChannel, "", NULL_KEY, "");
}
default {
state_entry() { llSetText("", <1.0,1.0,1.0>, 1.0); state s_config; }
}
state s_reconfig { state_entry() { state s_config; } }
state s_config {
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 {
touch_start(integer tot) { if (llDetectedKey(0) == llGetOwner()) { state s_config; } } changed(integer change) { if (change & CHANGED_OWNER) { llResetScript(); } if (change & CHANGED_INVENTORY) { state s_config; } }
}
state s_unconfigured {
state_entry() { llSetText("Configuration missing", <1.0,1.0,1.0>, 1.0); } 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 {
state_entry() { llListenRemove(gListenID); gListenID = llListen(communicationsChannel, "", "", ""); init1(); 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 ); }
on_rez(integer start_param) { init1(); init2(); llResetScript(); }
attach(key id) { if (id) { llOwnerSay("Headset has been reset."); llResetScript(); }
}
touch_start(integer total_number) { if (llDetectedKey(0) == llGetOwner()) { user = llGetOwner(); llDialog(user, menu_info_1 + menu_info_2,mainmenu,mChannel); llListen(mChannel,llKey2Name(user),user,""); } }
listen(integer channel, string name, key id, string message) { if(id==user) { if(message=="SLURL") { Name = llGetRegionName(); Where = llGetPos(); 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) { if (id == llGetOwner()) { llRegionSay(communicationsChannel, encrypt(Password, message)); llOwnerSay("You said: " + message); } if (llGetAgentSize(id) == ZERO_VECTOR) { string message = decrypt(Password, message); llOwnerSay((string)name + " said: " + (string)message); } } }
}
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()) { llOwnerSay("SIMchat back online! Touch headset for further informations."); state s_active; } }
on_rez(integer start_param) { llResetScript(); }
} </lsl>
NOTECARD:
- Name this notecard with an ending ".cfg", 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.
- The value for "version" can range from 0.0 to 255.255
- Comments are by leading "//"
Go to top! <lsl> //version from 0.0 to 255.255 //comments by leading "//" // strhex = 123456789ABCDEF channel = 9 password = P@ssw0rd version = 0.3 signature = ENC dialog = 8989 debug = 1 </lsl>