corrade-lsl-templates – Blame information for rev 2

Subversion Repositories:
Rev:
Rev Author Line No. Line
2 office 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) Wizardry and Steamworks 2016 - License: GNU GPLv3 //
3 ///////////////////////////////////////////////////////////////////////////
4 //
5 // This script is able to send messages to avatars, groups or talk in local
6 // using Corrade.
7 //
8 // For more information on Corrade, please see:
9 // http://grimore.org/secondlife/scripted_agents/corrade
10 //
11 ///////////////////////////////////////////////////////////////////////////
12  
13 ///////////////////////////////////////////////////////////////////////////
14 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
15 ///////////////////////////////////////////////////////////////////////////
16 string wasKeyValueGet(string k, string data) {
17 if(llStringLength(data) == 0) return "";
18 if(llStringLength(k) == 0) return "";
19 list a = llParseString2List(data, ["&", "="], []);
20 integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]);
21 if(i != -1) return llList2String(a, 2*i+1);
22 return "";
23 }
24  
25 ///////////////////////////////////////////////////////////////////////////
26 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
27 ///////////////////////////////////////////////////////////////////////////
28 string wasKeyValueEncode(list data) {
29 list k = llList2ListStrided(data, 0, -1, 2);
30 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2);
31 data = [];
32 do {
33 data += llList2String(k, 0) + "=" + llList2String(v, 0);
34 k = llDeleteSubList(k, 0, 0);
35 v = llDeleteSubList(v, 0, 0);
36 } while(llGetListLength(k) != 0);
37 return llDumpList2String(data, "&");
38 }
39  
40 ///////////////////////////////////////////////////////////////////////////
41 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
42 ///////////////////////////////////////////////////////////////////////////
43 // escapes a string in conformance with RFC1738
44 string wasURLEscape(string i) {
45 string o = "";
46 do {
47 string c = llGetSubString(i, 0, 0);
48 i = llDeleteSubString(i, 0, 0);
49 if(c == "") jump continue;
50 if(c == " ") {
51 o += "+";
52 jump continue;
53 }
54 if(c == "\n") {
55 o += "%0D" + llEscapeURL(c);
56 jump continue;
57 }
58 o += llEscapeURL(c);
59 @continue;
60 } while(i != "");
61 return o;
62 }
63  
64 ///////////////////////////////////////////////////////////////////////////
65 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
66 ///////////////////////////////////////////////////////////////////////////
67 list wasCSVToList(string csv) {
68 list l = [];
69 list s = [];
70 string m = "";
71 do {
72 string a = llGetSubString(csv, 0, 0);
73 csv = llDeleteSubString(csv, 0, 0);
74 if(a == ",") {
75 if(llList2String(s, -1) != "\"") {
76 l += m;
77 m = "";
78 jump continue;
79 }
80 m += a;
81 jump continue;
82 }
83 if(a == "\"" && llGetSubString(csv, 0, 0) == a) {
84 m += a;
85 csv = llDeleteSubString(csv, 0, 0);
86 jump continue;
87 }
88 if(a == "\"") {
89 if(llList2String(s, -1) != a) {
90 s += a;
91 jump continue;
92 }
93 s = llDeleteSubList(s, -1, -1);
94 jump continue;
95 }
96 m += a;
97 @continue;
98 } while(csv != "");
99 // postcondition: length(s) = 0
100 return l + m;
101 }
102  
103 ///////////////////////////////////////////////////////////////////////////
104 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
105 ///////////////////////////////////////////////////////////////////////////
106 string wasListToCSV(list l) {
107 list v = [];
108 do {
109 string a = llDumpList2String(
110 llParseStringKeepNulls(
111 llList2String(
112 l,
113  
114 ),
115 ["\""],
116 []
117 ),
118 "\"\""
119 );
120 if(llParseStringKeepNulls(
121 a,
122 [" ", ",", "\n", "\""], []
123 ) !=
124 (list) a
125 ) a = "\"" + a + "\"";
126 v += a;
127 l = llDeleteSubList(l, 0, 0);
128 } while(l != []);
129 return llDumpList2String(v, ",");
130 }
131  
132 ///////////////////////////////////////////////////////////////////////////
133 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
134 ///////////////////////////////////////////////////////////////////////////
135 // unescapes a string in conformance with RFC1738
136 string wasURLUnescape(string i) {
137 return llUnescapeURL(
138 llDumpList2String(
139 llParseString2List(
140 llDumpList2String(
141 llParseString2List(
142 i,
143 ["+"],
144 []
145 ),
146 " "
147 ),
148 ["%0D%0A"],
149 []
150 ),
151 "\n"
152 )
153 );
154 }
155  
156  
157 ///////////////////////////////////////////////////////////////////////////
158 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
159 ///////////////////////////////////////////////////////////////////////////
160 integer wasMenuIndex = 0;
161 list wasDialogMenu(list input, list actions, string direction) {
162 integer cut = 11-wasListCountExclude(actions, [""]);
163 if(direction == ">" && (wasMenuIndex+1)*cut+wasMenuIndex+1 < llGetListLength(input)) {
164 ++wasMenuIndex;
165 jump slice;
166 }
167 if(direction == "<" && wasMenuIndex-1 >= 0) {
168 --wasMenuIndex;
169 jump slice;
170 }
171 @slice;
172 integer multiple = wasMenuIndex*cut;
173 input = llList2List(input, multiple+wasMenuIndex, multiple+cut+wasMenuIndex);
174 input = wasListMerge(input, actions, "");
175 return input;
176 }
177  
178 ///////////////////////////////////////////////////////////////////////////
179 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
180 ///////////////////////////////////////////////////////////////////////////
181 integer wasListCountExclude(list input, list exclude) {
182 if(llGetListLength(input) == 0) return 0;
183 if(llListFindList(exclude, (list)llList2String(input, 0)) == -1)
184 return 1 + wasListCountExclude(llDeleteSubList(input, 0, 0), exclude);
185 return wasListCountExclude(llDeleteSubList(input, 0, 0), exclude);
186 }
187  
188 ///////////////////////////////////////////////////////////////////////////
189 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
190 ///////////////////////////////////////////////////////////////////////////
191 list wasListMerge(list l, list m, string merge) {
192 if(llGetListLength(l) == 0 && llGetListLength(m) == 0) return [];
193 string a = llList2String(m, 0);
194 if(a != merge) return [ a ] + wasListMerge(l, llDeleteSubList(m, 0, 0), merge);
195 return [ llList2String(l, 0) ] + wasListMerge(llDeleteSubList(l, 0, 0), llDeleteSubList(m, 0, 0), merge);
196 }
197  
198 // callback URL
199 string callback = "";
200 // configuration data
201 string configuration = "";
202 // listen handle
203 integer listenHandle = 0;
204 string firstname = "";
205 string lastname = "";
206 list names = [];
207 list UUIDs = [];
208 // temporary list for button name normalization
209 list menu = [];
210 integer select = -1;
211 string entity = "";
212  
213 default {
214 state_entry() {
215 llSetTimerEvent(1);
216 }
217 link_message(integer sender, integer num, string message, key id) {
218 if(sender != 1 || id != "configuration") return;
219 configuration = message;
220 state off;
221 }
222 timer() {
223 llMessageLinked(LINK_ROOT, 0, "configuration", NULL_KEY);
224 }
225 attach(key id) {
226 llResetScript();
227 }
228 on_rez(integer num) {
229 llResetScript();
230 }
231 changed(integer change) {
232 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
233 llResetScript();
234 }
235 }
236 state_exit() {
237 llSetTimerEvent(0);
238 }
239 }
240  
241 state off {
242 state_entry() {
243 llReleaseControls();
244 llSetColor(<.5,0,0>, ALL_SIDES);
245 }
246 touch_end(integer num) {
247 state on;
248 }
249 attach(key id) {
250 llResetScript();
251 }
252 on_rez(integer num) {
253 llResetScript();
254 }
255 changed(integer change) {
256 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
257 llResetScript();
258 }
259 }
260 }
261  
262 state on {
263 state_entry() {
264 llSetColor(<0,.5,0>, ALL_SIDES);
265 state url;
266 }
267 attach(key id) {
268 llResetScript();
269 }
270 on_rez(integer num) {
271 llResetScript();
272 }
273 changed(integer change) {
274 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
275 llResetScript();
276 }
277 }
278 }
279  
280 state url {
281 state_entry() {
282 // DEBUG
283 llOwnerSay("Requesting URL...");
284 llRequestURL();
285 }
286 touch_end(integer num) {
287 llSetColor(<.5,0,0>, ALL_SIDES);
288 llResetScript();
289 }
290 http_request(key id, string method, string body) {
291 if(method != URL_REQUEST_GRANTED) return;
292 callback = body;
293 // DEBUG
294 llOwnerSay("Got URL...");
295 state choose;
296 }
297 attach(key id) {
298 llResetScript();
299 }
300 on_rez(integer num) {
301 llResetScript();
302 }
303 changed(integer change) {
304 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
305 llResetScript();
306 }
307 }
308 }
309  
310 state choose {
311 state_entry() {
312 // DEBUG
313 llOwnerSay("Tell...");
314 llSetTimerEvent(1);
315 listenHandle = llListen(-24, "", llGetOwner(), "");
316 llDialog(
317 llGetOwner(),
318 "[CORRADE] Select avatar, local or group:",
319 [
320 "avatar",
321 "local",
322 "group"
323 ],
324 -24
325 );
326 }
327 touch_end(integer num) {
328 llResetScript();
329 }
330 listen(integer channel, string name, key id, string message) {
331 llListenRemove(listenHandle);
332  
333 entity = message;
334  
335 if(message == "local") state tell;
336 if(message == "avatar") state select_avatar;
337 if(message == "group") state get_groups;
338  
339 llResetScript();
340 }
341 attach(key id) {
342 llResetScript();
343 }
344 on_rez(integer num) {
345 llResetScript();
346 }
347 changed(integer change) {
348 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
349 llResetScript();
350 }
351 }
352 state_exit() {
353 llSetTimerEvent(0);
354 }
355 }
356  
357 state get_groups {
358 state_entry() {
359 // DEBUG
360 llOwnerSay("Getting groups...");
361 llSetTimerEvent(1);
362 llInstantMessage(
363 wasKeyValueGet(
364 "corrade",
365 configuration
366 ),
367 wasKeyValueEncode(
368 [
369 "command", "getcurrentgroups",
370 "group", wasURLEscape(
371 wasKeyValueGet(
372 "group",
373 configuration
374 )
375 ),
376 "password", wasURLEscape(
377 wasKeyValueGet(
378 "password",
379 configuration
380 )
381 ),
382 "sift", wasListToCSV(
383 [
384 "take", 16
385 ]
386 ),
387 "callback", wasURLEscape(callback)
388 ]
389 )
390 );
391 }
392 http_request(key id, string method, string body) {
393 llHTTPResponse(id, 200, "OK");
394 if(wasKeyValueGet("command", body) != "getcurrentgroups" ||
395 wasKeyValueGet("success", body) != "True") {
396 // DEBUG
397 llOwnerSay("Too many groups or unable to groups...");
398 llResetScript();
399 }
400 list data = wasCSVToList(
401 wasURLUnescape(
402 wasKeyValueGet(
403 "data",
404 body
405 )
406 )
407 );
408 // Copy the names and UUIDs of the groups for the menu.
409 names = [];
410 UUIDs = [];
411 do {
412 UUIDs += llList2String(data, -1);
413 data = llDeleteSubList(data, -1, -1);
414 names += llList2String(data, -1);
415 data = llDeleteSubList(data, -1, -1);
416 } while(llGetListLength(data));
417 state select_group;
418 }
419 timer() {
420 llRequestAgentData(
421 (key)wasKeyValueGet(
422 "corrade",
423 configuration
424 ), DATA_ONLINE);
425 }
426 dataserver(key id, string data) {
427 if(data != "1") llResetScript();
428 }
429 attach(key id) {
430 llResetScript();
431 }
432 on_rez(integer num) {
433 llResetScript();
434 }
435 changed(integer change) {
436 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
437 llResetScript();
438 }
439 }
440 state_exit() {
441 llSetTimerEvent(0);
442 }
443 }
444  
445 state select_group {
446 state_entry() {
447 // DEBUG
448 llOwnerSay("Sending menu...");
449 menu = [];
450 integer i = 0;
451 do {
452 menu += llGetSubString(llList2String(names, i), 0, 23);
453 } while(++i < llGetListLength(names));
454 llListen(-10, "", llGetOwner(), "");
455 llDialog(llGetOwner(), "\nPlease choose a group for Corrade to talk in from the list below:\n", wasDialogMenu(menu, ["⟵ Back", "", "Next ⟶"], ""), -10);
456 llSetTimerEvent(60);
457 }
458 touch_end(integer num) {
459 llSetColor(<.5,0,0>, ALL_SIDES);
460 llResetScript();
461 }
462 listen(integer channel, string name, key id, string message) {
463 if(message == "⟵ Back") {
464 llDialog(id, "\nPlease choose a group for Corrade to talk in from the list below:\n", wasDialogMenu(menu, ["⟵ Back", "", "Next ⟶"], "<"), -10);
465 return;
466 }
467 if(message == "Next ⟶") {
468 llDialog(id, "\nPlease choose a primitive for Corrade to sit on from the list below:\n", wasDialogMenu(menu, ["⟵ Back", "", "Next ⟶"], ">"), -10);
469 return;
470 }
471 integer i = llGetListLength(menu) - 1;
472 do {
473 string v = llList2String(menu, i);
474 if(llSubStringIndex(v, message) != -1)
475 jump sit;
476 } while(--i > -1);
477 // GC
478 menu = [];
479 // DEBUG
480 llOwnerSay("Invalid menu item selected...");
481 llResetScript();
482 @sit;
483 // GC
484 menu = [];
485 select = i;
486  
487 state tell;
488  
489 }
490 timer() {
491 // DEBUG
492 llOwnerSay("Dialog menu timeout...");
493 llResetScript();
494 }
495 attach(key id) {
496 llResetScript();
497 }
498 on_rez(integer num) {
499 llResetScript();
500 }
501 changed(integer change) {
502 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
503 llResetScript();
504 }
505 }
506 state_exit() {
507 llSetTimerEvent(0);
508 }
509 }
510  
511 state select_avatar {
512 state_entry() {
513 // DEBUG
514 llOwnerSay("Select avatar...");
515 llSetTimerEvent(1);
516 listenHandle = llListen(-24, "", llGetOwner(), "");
517 llTextBox(llGetOwner(), "[CORRADE] Enter the avatar name:", -24);
518 }
519 touch_end(integer num) {
520 llResetScript();
521 }
522 listen(integer channel, string name, key id, string message) {
523 llListenRemove(listenHandle);
524 list name = llParseString2List(message, [" "], [""]);
525 if(llGetListLength(name) != 2) {
526 llOwnerSay("Invalid avatar name...");
527 state tell;
528 }
529 firstname = llList2String(name, 0);
530 lastname = llList2String(name, 1);
531 state tell;
532 }
533 timer() {
534 llRequestAgentData(
535 (key)wasKeyValueGet(
536 "corrade",
537 configuration
538 ), DATA_ONLINE);
539 }
540 dataserver(key id, string data) {
541 if(data != "1") llResetScript();
542 }
543 attach(key id) {
544 llResetScript();
545 }
546 on_rez(integer num) {
547 llResetScript();
548 }
549 changed(integer change) {
550 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
551 llResetScript();
552 }
553 }
554 state_exit() {
555 llSetTimerEvent(0);
556 }
557 }
558  
559 state tell {
560 state_entry() {
561 // DEBUG
562 llOwnerSay("Tell...");
563 llSetTimerEvent(1);
564 listenHandle = llListen(-24, "", llGetOwner(), "");
565 llTextBox(llGetOwner(), "[CORRADE] Enter the message:", -24);
566 }
567 touch_end(integer num) {
568 llResetScript();
569 }
570 timer() {
571 llRequestAgentData(
572 (key)wasKeyValueGet(
573 "corrade",
574 configuration
575 ), DATA_ONLINE);
576 }
577 dataserver(key id, string data) {
578 if(data != "1") llResetScript();
579 }
580 listen(integer channel, string name, key id, string message) {
581 llListenRemove(listenHandle);
582 llInstantMessage(
583 wasKeyValueGet(
584 "corrade",
585 configuration
586 ),
587 wasKeyValueEncode(
588 [
589 "command", "tell",
590 "group", wasURLEscape(
591 wasKeyValueGet(
592 "group",
593 configuration
594 )
595 ),
596 "password", wasURLEscape(
597 wasKeyValueGet(
598 "password",
599 configuration
600 )
601 ),
602 "entity", entity,
603 "type", "normal",
604 "target", wasURLEscape(
605 llList2String(UUIDs, select)
606 ),
607 "firstname", wasURLEscape(firstname),
608 "lastname", wasURLEscape(lastname),
609 "message", wasURLEscape(message),
610 "callback", wasURLEscape(callback)
611 ]
612 )
613 );
614 }
615 http_request(key id, string method, string body) {
616 llHTTPResponse(id, 200, "OK");
617 if(wasKeyValueGet("command", body) != "tell" ||
618 wasKeyValueGet("success", body) != "True") {
619 // DEBUG
620 llOwnerSay("Failed to say message: " + wasKeyValueGet("error", body));
621 }
622 llResetScript();
623 }
624 attach(key id) {
625 llResetScript();
626 }
627 on_rez(integer num) {
628 llResetScript();
629 }
630 changed(integer change) {
631 if((change & CHANGED_INVENTORY) || (change & CHANGED_REGION_START) || (change & CHANGED_OWNER)) {
632 llResetScript();
633 }
634 }
635 state_exit() {
636 llSetTimerEvent(0);
637 }
638 }