corrade-lsl-templates – Diff between revs 5 and 29

Subversion Repositories:
Rev:
Only display areas with differencesIgnore whitespace
Rev 5 Rev 29
1 /////////////////////////////////////////////////////////////////////////// 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // 2 // Copyright (C) Wizardry and Steamworks 2014 - License: CC BY 2.0 //
3 /////////////////////////////////////////////////////////////////////////// 3 ///////////////////////////////////////////////////////////////////////////
4 // 4 //
5 // This is relays instant messages chat to an avatar and meant to work with 5 // This is relays instant messages chat to an avatar and meant to work with
6 // Corrade the Second Life / OpenSim bot. You can find more details about 6 // Corrade the Second Life / OpenSim bot. You can find more details about
7 // the bot by following the URL: 7 // the bot by following the URL:
8 // 8 //
9 // http://was.fm/secondlife/scripted_agents/corrade 9 // http://was.fm/secondlife/scripted_agents/corrade
10 // 10 //
11 // The script works in combination with a "configuration" notecard that 11 // The script works in combination with a "configuration" notecard that
12 // must be placed in the same primitive as this script. The purpose of this 12 // must be placed in the same primitive as this script. The purpose of this
13 // script is to demonstrate relaying instant messages to an avatar using 13 // script is to demonstrate relaying instant messages to an avatar using
14 // Corrade and you are free to use, change, and commercialize it under the 14 // Corrade and you are free to use, change, and commercialize it under the
15 // terms of the GNU/GPLv3 license at: http://www.gnu.org/licenses/gpl.html 15 // terms of the CC BY 2.0 license at: https://creativecommons.org/licenses/by/2.0
16 // 16 //
17 /////////////////////////////////////////////////////////////////////////// 17 ///////////////////////////////////////////////////////////////////////////
18   18  
19 /////////////////////////////////////////////////////////////////////////// 19 ///////////////////////////////////////////////////////////////////////////
20 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 20 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
21 /////////////////////////////////////////////////////////////////////////// 21 ///////////////////////////////////////////////////////////////////////////
22 string wasKeyValueGet(string k, string data) { 22 string wasKeyValueGet(string k, string data) {
23 if(llStringLength(data) == 0) return ""; 23 if(llStringLength(data) == 0) return "";
24 if(llStringLength(k) == 0) return ""; 24 if(llStringLength(k) == 0) return "";
25 list a = llParseString2List(data, ["&", "="], []); 25 list a = llParseString2List(data, ["&", "="], []);
26 integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]); 26 integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]);
27 if(i != -1) return llList2String(a, 2*i+1); 27 if(i != -1) return llList2String(a, 2*i+1);
28 return ""; 28 return "";
29 } 29 }
30 30
31 /////////////////////////////////////////////////////////////////////////// 31 ///////////////////////////////////////////////////////////////////////////
32 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 // 32 // Copyright (C) 2013 Wizardry and Steamworks - License: CC BY 2.0 //
33 /////////////////////////////////////////////////////////////////////////// 33 ///////////////////////////////////////////////////////////////////////////
34 string wasKeyValueEncode(list data) { 34 string wasKeyValueEncode(list data) {
35 list k = llList2ListStrided(data, 0, -1, 2); 35 list k = llList2ListStrided(data, 0, -1, 2);
36 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2); 36 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2);
37 data = []; 37 data = [];
38 do { 38 do {
39 data += llList2String(k, 0) + "=" + llList2String(v, 0); 39 data += llList2String(k, 0) + "=" + llList2String(v, 0);
40 k = llDeleteSubList(k, 0, 0); 40 k = llDeleteSubList(k, 0, 0);
41 v = llDeleteSubList(v, 0, 0); 41 v = llDeleteSubList(v, 0, 0);
42 } while(llGetListLength(k) != 0); 42 } while(llGetListLength(k) != 0);
43 return llDumpList2String(data, "&"); 43 return llDumpList2String(data, "&");
44 } 44 }
45   45  
46 /////////////////////////////////////////////////////////////////////////// 46 ///////////////////////////////////////////////////////////////////////////
47 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 47 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
48 /////////////////////////////////////////////////////////////////////////// 48 ///////////////////////////////////////////////////////////////////////////
49 // escapes a string in conformance with RFC1738 49 // escapes a string in conformance with RFC1738
50 string wasURLEscape(string i) { 50 string wasURLEscape(string i) {
51 string o = ""; 51 string o = "";
52 do { 52 do {
53 string c = llGetSubString(i, 0, 0); 53 string c = llGetSubString(i, 0, 0);
54 i = llDeleteSubString(i, 0, 0); 54 i = llDeleteSubString(i, 0, 0);
55 if(c == "") jump continue; 55 if(c == "") jump continue;
56 if(c == " ") { 56 if(c == " ") {
57 o += "+"; 57 o += "+";
58 jump continue; 58 jump continue;
59 } 59 }
60 if(c == "\n") { 60 if(c == "\n") {
61 o += "%0D" + llEscapeURL(c); 61 o += "%0D" + llEscapeURL(c);
62 jump continue; 62 jump continue;
63 } 63 }
64 o += llEscapeURL(c); 64 o += llEscapeURL(c);
65 @continue; 65 @continue;
66 } while(i != ""); 66 } while(i != "");
67 return o; 67 return o;
68 } 68 }
69   69  
70 /////////////////////////////////////////////////////////////////////////// 70 ///////////////////////////////////////////////////////////////////////////
71 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // 71 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
72 /////////////////////////////////////////////////////////////////////////// 72 ///////////////////////////////////////////////////////////////////////////
73 // unescapes a string in conformance with RFC1738 73 // unescapes a string in conformance with RFC1738
74 string wasURLUnescape(string i) { 74 string wasURLUnescape(string i) {
75 return llUnescapeURL( 75 return llUnescapeURL(
76 llDumpList2String( 76 llDumpList2String(
77 llParseString2List( 77 llParseString2List(
78 llDumpList2String( 78 llDumpList2String(
79 llParseString2List( 79 llParseString2List(
80 i, 80 i,
81 ["+"], 81 ["+"],
82 [] 82 []
83 ), 83 ),
84 " " 84 " "
85 ), 85 ),
86 ["%0D%0A"], 86 ["%0D%0A"],
87 [] 87 []
88 ), 88 ),
89 "\n" 89 "\n"
90 ) 90 )
91 ); 91 );
92 } 92 }
93   93  
94 // corrade data 94 // corrade data
95 key CORRADE = NULL_KEY; 95 key CORRADE = NULL_KEY;
96 string GROUP = ""; 96 string GROUP = "";
97 string PASSWORD = ""; 97 string PASSWORD = "";
98   98  
99 // instance variables 99 // instance variables
100 string firstname = ""; 100 string firstname = "";
101 string lastname = ""; 101 string lastname = "";
102 string message = ""; 102 string message = "";
103   103  
104 // for holding the callback URL 104 // for holding the callback URL
105 string callback = ""; 105 string callback = "";
106   106  
107 // for notecard reading 107 // for notecard reading
108 integer line = 0; 108 integer line = 0;
109 109
110 // key-value data will be read into this list 110 // key-value data will be read into this list
111 list tuples = []; 111 list tuples = [];
112   112  
113 default { 113 default {
114 state_entry() { 114 state_entry() {
115 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) { 115 if(llGetInventoryType("configuration") != INVENTORY_NOTECARD) {
116 llOwnerSay("Sorry, could not find a configuration inventory notecard."); 116 llOwnerSay("Sorry, could not find a configuration inventory notecard.");
117 return; 117 return;
118 } 118 }
119 // DEBUG 119 // DEBUG
120 llOwnerSay("Reading configuration file..."); 120 llOwnerSay("Reading configuration file...");
121 llGetNotecardLine("configuration", line); 121 llGetNotecardLine("configuration", line);
122 } 122 }
123 dataserver(key id, string data) { 123 dataserver(key id, string data) {
124 if(data == EOF) { 124 if(data == EOF) {
125 // invariant, length(tuples) % 2 == 0 125 // invariant, length(tuples) % 2 == 0
126 if(llGetListLength(tuples) % 2 != 0) { 126 if(llGetListLength(tuples) % 2 != 0) {
127 llOwnerSay("Error in configuration notecard."); 127 llOwnerSay("Error in configuration notecard.");
128 return; 128 return;
129 } 129 }
130 CORRADE = llList2Key( 130 CORRADE = llList2Key(
131 tuples, 131 tuples,
132 llListFindList( 132 llListFindList(
133 tuples, 133 tuples,
134 [ 134 [
135 "corrade" 135 "corrade"
136 ] 136 ]
137 ) 137 )
138 +1); 138 +1);
139 if(CORRADE == NULL_KEY) { 139 if(CORRADE == NULL_KEY) {
140 llOwnerSay("Error in configuration notecard: corrade"); 140 llOwnerSay("Error in configuration notecard: corrade");
141 return; 141 return;
142 } 142 }
143 GROUP = llList2String( 143 GROUP = llList2String(
144 tuples, 144 tuples,
145 llListFindList( 145 llListFindList(
146 tuples, 146 tuples,
147 [ 147 [
148 "group" 148 "group"
149 ] 149 ]
150 ) 150 )
151 +1); 151 +1);
152 if(GROUP == "") { 152 if(GROUP == "") {
153 llOwnerSay("Error in configuration notecard: group"); 153 llOwnerSay("Error in configuration notecard: group");
154 return; 154 return;
155 } 155 }
156 PASSWORD = llList2String( 156 PASSWORD = llList2String(
157 tuples, 157 tuples,
158 llListFindList( 158 llListFindList(
159 tuples, 159 tuples,
160 [ 160 [
161 "password" 161 "password"
162 ] 162 ]
163 ) 163 )
164 +1); 164 +1);
165 if(PASSWORD == "") { 165 if(PASSWORD == "") {
166 llOwnerSay("Error in configuration notecard: password"); 166 llOwnerSay("Error in configuration notecard: password");
167 return; 167 return;
168 } 168 }
169 // DEBUG 169 // DEBUG
170 llOwnerSay("Read configuration notecard..."); 170 llOwnerSay("Read configuration notecard...");
171 state url; 171 state url;
172 } 172 }
173 if(data == "") jump continue; 173 if(data == "") jump continue;
174 integer i = llSubStringIndex(data, "#"); 174 integer i = llSubStringIndex(data, "#");
175 if(i != -1) data = llDeleteSubString(data, i, -1); 175 if(i != -1) data = llDeleteSubString(data, i, -1);
176 list o = llParseString2List(data, ["="], []); 176 list o = llParseString2List(data, ["="], []);
177 // get rid of starting and ending quotes 177 // get rid of starting and ending quotes
178 string k = llDumpList2String( 178 string k = llDumpList2String(
179 llParseString2List( 179 llParseString2List(
180 llStringTrim( 180 llStringTrim(
181 llList2String( 181 llList2String(
182 o, 182 o,
183 0 183 0
184 ), 184 ),
185 STRING_TRIM), 185 STRING_TRIM),
186 ["\""], [] 186 ["\""], []
187 ), "\""); 187 ), "\"");
188 string v = llDumpList2String( 188 string v = llDumpList2String(
189 llParseString2List( 189 llParseString2List(
190 llStringTrim( 190 llStringTrim(
191 llList2String( 191 llList2String(
192 o, 192 o,
193 1 193 1
194 ), 194 ),
195 STRING_TRIM), 195 STRING_TRIM),
196 ["\""], [] 196 ["\""], []
197 ), "\""); 197 ), "\"");
198 if(k == "" || v == "") jump continue; 198 if(k == "" || v == "") jump continue;
199 tuples += k; 199 tuples += k;
200 tuples += v; 200 tuples += v;
201 @continue; 201 @continue;
202 llGetNotecardLine("configuration", ++line); 202 llGetNotecardLine("configuration", ++line);
203 } 203 }
204 on_rez(integer num) { 204 on_rez(integer num) {
205 llResetScript(); 205 llResetScript();
206 } 206 }
207 changed(integer change) { 207 changed(integer change) {
208 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 208 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
209 llResetScript(); 209 llResetScript();
210 } 210 }
211 } 211 }
212 } 212 }
213   213  
214 state url { 214 state url {
215 state_entry() { 215 state_entry() {
216 // DEBUG 216 // DEBUG
217 llOwnerSay("Requesting URL..."); 217 llOwnerSay("Requesting URL...");
218 llRequestURL(); 218 llRequestURL();
219 } 219 }
220 http_request(key id, string method, string body) { 220 http_request(key id, string method, string body) {
221 if(method != URL_REQUEST_GRANTED) return; 221 if(method != URL_REQUEST_GRANTED) return;
222 callback = body; 222 callback = body;
223 // DEBUG 223 // DEBUG
224 llOwnerSay("Got URL..."); 224 llOwnerSay("Got URL...");
225 state detect; 225 state detect;
226 } 226 }
227 on_rez(integer num) { 227 on_rez(integer num) {
228 llResetScript(); 228 llResetScript();
229 } 229 }
230 changed(integer change) { 230 changed(integer change) {
231 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 231 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
232 llResetScript(); 232 llResetScript();
233 } 233 }
234 } 234 }
235 } 235 }
236 236
237 state detect { 237 state detect {
238 state_entry() { 238 state_entry() {
239 // DEBUG 239 // DEBUG
240 llOwnerSay("Detecting if Corrade is online..."); 240 llOwnerSay("Detecting if Corrade is online...");
241 llSetTimerEvent(5); 241 llSetTimerEvent(5);
242 } 242 }
243 timer() { 243 timer() {
244 llRequestAgentData((key)CORRADE, DATA_ONLINE); 244 llRequestAgentData((key)CORRADE, DATA_ONLINE);
245 } 245 }
246 dataserver(key id, string data) { 246 dataserver(key id, string data) {
247 if(data != "1") { 247 if(data != "1") {
248 // DEBUG 248 // DEBUG
249 llOwnerSay("Corrade is not online, sleeping..."); 249 llOwnerSay("Corrade is not online, sleeping...");
250 llSetTimerEvent(30); 250 llSetTimerEvent(30);
251 return; 251 return;
252 } 252 }
253 state notify; 253 state notify;
254 } 254 }
255 on_rez(integer num) { 255 on_rez(integer num) {
256 llResetScript(); 256 llResetScript();
257 } 257 }
258 changed(integer change) { 258 changed(integer change) {
259 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 259 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
260 llResetScript(); 260 llResetScript();
261 } 261 }
262 } 262 }
263 } 263 }
264 264
265 state notify { 265 state notify {
266 state_entry() { 266 state_entry() {
267 // DEBUG 267 // DEBUG
268 llOwnerSay("Binding to the instant message notification..."); 268 llOwnerSay("Binding to the instant message notification...");
269 llInstantMessage( 269 llInstantMessage(
270 (key)CORRADE, 270 (key)CORRADE,
271 wasKeyValueEncode( 271 wasKeyValueEncode(
272 [ 272 [
273 "command", "notify", 273 "command", "notify",
274 "group", wasURLEscape(GROUP), 274 "group", wasURLEscape(GROUP),
275 "password", wasURLEscape(PASSWORD), 275 "password", wasURLEscape(PASSWORD),
276 "action", "set", 276 "action", "set",
277 "type", "message", 277 "type", "message",
278 "URL", wasURLEscape(callback), 278 "URL", wasURLEscape(callback),
279 "callback", wasURLEscape(callback) 279 "callback", wasURLEscape(callback)
280 ] 280 ]
281 ) 281 )
282 ); 282 );
283 } 283 }
284 http_request(key id, string method, string body) { 284 http_request(key id, string method, string body) {
285 llHTTPResponse(id, 200, "OK"); 285 llHTTPResponse(id, 200, "OK");
286 if(wasKeyValueGet("command", body) != "notify" || 286 if(wasKeyValueGet("command", body) != "notify" ||
287 wasKeyValueGet("success", body) != "True") { 287 wasKeyValueGet("success", body) != "True") {
288 // DEBUG 288 // DEBUG
289 llOwnerSay("Failed to bind to the message notification..."); 289 llOwnerSay("Failed to bind to the message notification...");
290 state detect; 290 state detect;
291 } 291 }
292 // DEBUG 292 // DEBUG
293 llOwnerSay("Local chat notification installed..."); 293 llOwnerSay("Local chat notification installed...");
294 state chat; 294 state chat;
295 } 295 }
296 on_rez(integer num) { 296 on_rez(integer num) {
297 llResetScript(); 297 llResetScript();
298 } 298 }
299 changed(integer change) { 299 changed(integer change) {
300 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 300 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
301 llResetScript(); 301 llResetScript();
302 } 302 }
303 } 303 }
304 } 304 }
305   305  
306 state chat { 306 state chat {
307 state_entry() { 307 state_entry() {
308 // DEBUG 308 // DEBUG
309 llOwnerSay("Waiting for instant messages..."); 309 llOwnerSay("Waiting for instant messages...");
310 llSetTimerEvent(5); 310 llSetTimerEvent(5);
311 } 311 }
312 timer() { 312 timer() {
313 llRequestAgentData((key)CORRADE, DATA_ONLINE); 313 llRequestAgentData((key)CORRADE, DATA_ONLINE);
314 } 314 }
315 dataserver(key id, string data) { 315 dataserver(key id, string data) {
316 if(data == "1") return; 316 if(data == "1") return;
317 // DEBUG 317 // DEBUG
318 llOwnerSay("Corrade is not online, sleeping..."); 318 llOwnerSay("Corrade is not online, sleeping...");
319 // Switch to detect loop and wait there for Corrade to come online. 319 // Switch to detect loop and wait there for Corrade to come online.
320 state detect; 320 state detect;
321 } 321 }
322 http_request(key id, string method, string body) { 322 http_request(key id, string method, string body) {
323 llHTTPResponse(id, 200, "OK"); 323 llHTTPResponse(id, 200, "OK");
324 firstname = wasURLUnescape(wasKeyValueGet("firstname", body)); 324 firstname = wasURLUnescape(wasKeyValueGet("firstname", body));
325 lastname = wasURLUnescape(wasKeyValueGet("lastname", body)); 325 lastname = wasURLUnescape(wasKeyValueGet("lastname", body));
326 // DEBUG 326 // DEBUG
327 llOwnerSay("Got instant message from: " + firstname + " " + lastname); 327 llOwnerSay("Got instant message from: " + firstname + " " + lastname);
328 message = wasKeyValueGet("message", body); 328 message = wasKeyValueGet("message", body);
329 state process; 329 state process;
330 } 330 }
331 on_rez(integer num) { 331 on_rez(integer num) {
332 llResetScript(); 332 llResetScript();
333 } 333 }
334 changed(integer change) { 334 changed(integer change) {
335 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 335 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
336 llResetScript(); 336 llResetScript();
337 } 337 }
338 } 338 }
339 } 339 }
340   340  
341 state process { 341 state process {
342 state_entry() { 342 state_entry() {
343 // DEBUG 343 // DEBUG
344 llOwnerSay("Sending message to Corrade's AI facility..."); 344 llOwnerSay("Sending message to Corrade's AI facility...");
345 llInstantMessage(CORRADE, 345 llInstantMessage(CORRADE,
346 wasKeyValueEncode( 346 wasKeyValueEncode(
347 [ 347 [
348 "command", "ai", 348 "command", "ai",
349 "group", wasURLEscape(GROUP), 349 "group", wasURLEscape(GROUP),
350 "password", wasURLEscape(PASSWORD), 350 "password", wasURLEscape(PASSWORD),
351 "action", "process", 351 "action", "process",
352 "message", wasURLEscape(message), 352 "message", wasURLEscape(message),
353 "callback", wasURLEscape(callback) 353 "callback", wasURLEscape(callback)
354 ] 354 ]
355 ) 355 )
356 ); 356 );
357 llSetTimerEvent(5); 357 llSetTimerEvent(5);
358 } 358 }
359 timer() { 359 timer() {
360 llRequestAgentData((key)CORRADE, DATA_ONLINE); 360 llRequestAgentData((key)CORRADE, DATA_ONLINE);
361 } 361 }
362 dataserver(key id, string data) { 362 dataserver(key id, string data) {
363 if(data == "1") return; 363 if(data == "1") return;
364 // DEBUG 364 // DEBUG
365 llOwnerSay("Corrade is not online, sleeping..."); 365 llOwnerSay("Corrade is not online, sleeping...");
366 // Switch to detect loop and wait there for Corrade to come online. 366 // Switch to detect loop and wait there for Corrade to come online.
367 state detect; 367 state detect;
368 } 368 }
369 http_request(key id, string method, string body) { 369 http_request(key id, string method, string body) {
370 llHTTPResponse(id, 200, "OK"); 370 llHTTPResponse(id, 200, "OK");
371 // DEBUG 371 // DEBUG
372 llOwnerSay("Sending answer to: " + firstname + " " + lastname); 372 llOwnerSay("Sending answer to: " + firstname + " " + lastname);
373 llInstantMessage(CORRADE, 373 llInstantMessage(CORRADE,
374 wasKeyValueEncode( 374 wasKeyValueEncode(
375 [ 375 [
376 "command", "tell", 376 "command", "tell",
377 "group", wasURLEscape(GROUP), 377 "group", wasURLEscape(GROUP),
378 "password", wasURLEscape(PASSWORD), 378 "password", wasURLEscape(PASSWORD),
379 "firstname", firstname, 379 "firstname", firstname,
380 "lastname", lastname, 380 "lastname", lastname,
381 "entity", "avatar", 381 "entity", "avatar",
382 "message", wasKeyValueGet("data", body) 382 "message", wasKeyValueGet("data", body)
383 ] 383 ]
384 ) 384 )
385 ); 385 );
386 state chat; 386 state chat;
387 } 387 }
388 on_rez(integer num) { 388 on_rez(integer num) {
389 llResetScript(); 389 llResetScript();
390 } 390 }
391 changed(integer change) { 391 changed(integer change) {
392 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) { 392 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START)) {
393 llResetScript(); 393 llResetScript();
394 } 394 }
395 } 395 }
396 } 396 }
397   397