corrade-lsl-templates – Blame information for rev 21

Subversion Repositories:
Rev:
Rev Author Line No. Line
18 office 1 ///////////////////////////////////////////////////////////////////////////
2 // Copyright (C) Wizardry and Steamworks 2018 - License: GNU GPLv3 //
3 ///////////////////////////////////////////////////////////////////////////
4 //
5 // A database-based joke module for Corrade Eggdrop.
6 //
7 ///////////////////////////////////////////////////////////////////////////
8  
9 ///////////////////////////////////////////////////////////////////////////
10 // Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 //
11 ///////////////////////////////////////////////////////////////////////////
12 string wasKeyValueGet(string k, string data) {
13 if(llStringLength(data) == 0) return "";
14 if(llStringLength(k) == 0) return "";
15 list a = llParseString2List(data, ["&", "="], []);
16 integer i = llListFindList(a, [ k ]);
17 if(i != -1) return llList2String(a, i+1);
18 return "";
19 }
20  
21 ///////////////////////////////////////////////////////////////////////////
22 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
23 ///////////////////////////////////////////////////////////////////////////
24 string wasKeyValueEncode(list data) {
25 list k = llList2ListStrided(data, 0, -1, 2);
26 list v = llList2ListStrided(llDeleteSubList(data, 0, 0), 0, -1, 2);
27 data = [];
28 do {
29 data += llList2String(k, 0) + "=" + llList2String(v, 0);
30 k = llDeleteSubList(k, 0, 0);
31 v = llDeleteSubList(v, 0, 0);
32 } while(llGetListLength(k) != 0);
33 return llDumpList2String(data, "&");
34 }
35  
36 ///////////////////////////////////////////////////////////////////////////
37 // Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3 //
38 ///////////////////////////////////////////////////////////////////////////
39 // http://was.fm/secondlife/wanderer
40 vector wasCirclePoint(float radius) {
41 float x = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
42 float y = llPow(-1, 1 + (integer) llFrand(2)) * llFrand(radius*2);
43 if(llPow(x,2) + llPow(y,2) <= llPow(radius,2))
44 return <x, y, 0>;
45 return wasCirclePoint(radius);
46 }
47  
48 ///////////////////////////////////////////////////////////////////////////
49 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
50 ///////////////////////////////////////////////////////////////////////////
51 // escapes a string in conformance with RFC1738
52 string wasURLEscape(string i) {
53 string o = "";
54 do {
55 string c = llGetSubString(i, 0, 0);
56 i = llDeleteSubString(i, 0, 0);
57 if(c == "") jump continue;
58 if(c == " ") {
59 o += "+";
60 jump continue;
61 }
62 if(c == "\n") {
63 o += "%0D" + llEscapeURL(c);
64 jump continue;
65 }
66 o += llEscapeURL(c);
67 @continue;
68 } while(i != "");
69 return o;
70 }
71  
72 ///////////////////////////////////////////////////////////////////////////
73 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
74 ///////////////////////////////////////////////////////////////////////////
75 list wasCSVToList(string csv) {
76 list l = [];
77 list s = [];
78 string m = "";
79 do {
80 string a = llGetSubString(csv, 0, 0);
81 csv = llDeleteSubString(csv, 0, 0);
82 if(a == ",") {
83 if(llList2String(s, -1) != "\"") {
84 l += m;
85 m = "";
86 jump continue;
87 }
88 m += a;
89 jump continue;
90 }
91 if(a == "\"" && llGetSubString(csv, 0, 0) == a) {
92 m += a;
93 csv = llDeleteSubString(csv, 0, 0);
94 jump continue;
95 }
96 if(a == "\"") {
97 if(llList2String(s, -1) != a) {
98 s += a;
99 jump continue;
100 }
101 s = llDeleteSubList(s, -1, -1);
102 jump continue;
103 }
104 m += a;
105 @continue;
106 } while(csv != "");
107 // postcondition: length(s) = 0
108 return l + m;
109 }
110  
111 ///////////////////////////////////////////////////////////////////////////
112 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
113 ///////////////////////////////////////////////////////////////////////////
114 string wasListToCSV(list l) {
115 list v = [];
116 do {
117 string a = llDumpList2String(
118 llParseStringKeepNulls(
119 llList2String(
120 l,
121  
122 ),
123 ["\""],
124 []
125 ),
126 "\"\""
127 );
128 if(llParseStringKeepNulls(
129 a,
130 [" ", ",", "\n", "\""], []
131 ) !=
132 (list) a
133 ) a = "\"" + a + "\"";
134 v += a;
135 l = llDeleteSubList(l, 0, 0);
136 } while(l != []);
137 return llDumpList2String(v, ",");
138 }
139  
140 ///////////////////////////////////////////////////////////////////////////
141 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
142 ///////////////////////////////////////////////////////////////////////////
143 // unescapes a string in conformance with RFC1738
144 string wasURLUnescape(string i) {
145 return llUnescapeURL(
146 llDumpList2String(
147 llParseString2List(
148 llDumpList2String(
149 llParseString2List(
150 i,
151 ["+"],
152 []
153 ),
154 " "
155 ),
156 ["%0D%0A"],
157 []
158 ),
159 "\n"
160 )
161 );
162 }
163  
164 // configuration data
165 string configuration = "";
166 // callback URL
167 string URL = "";
168 // store message over state.
169 string firstname = "";
170 string lastname = "";
171 string group = "";
172 string data = "";
173 string jump_state = "";
174 integer joke_counter = 0;
175  
176 default {
177 state_entry() {
178 llOwnerSay("[Joke] Starting module...");
179 llSetTimerEvent(10);
180 }
181 link_message(integer sender, integer num, string message, key id) {
182 if(id != "configuration") return;
183 llOwnerSay("[Joke] Got configuration...");
184 configuration = message;
185 jump_state = "create_database";
186 state url;
187 }
188 timer() {
189 llOwnerSay("[Joke] Requesting configuration...");
190 llMessageLinked(LINK_THIS, 0, "configuration", NULL_KEY);
191 }
192 on_rez(integer num) {
193 llResetScript();
194 }
195 changed(integer change) {
196 if((change & CHANGED_INVENTORY) ||
197 (change & CHANGED_REGION_START) ||
198 (change & CHANGED_OWNER)) {
199 llResetScript();
200 }
201 }
202 state_exit() {
203 llSetTimerEvent(0);
204 }
205 }
206  
207 state url {
208 state_entry() {
209 // DEBUG
210 llOwnerSay("[Joke] Requesting URL...");
211 llRequestURL();
212 }
213 http_request(key id, string method, string body) {
214 if(method != URL_REQUEST_GRANTED) return;
215 URL = body;
216 // DEBUG
217 llOwnerSay("[Joke] Got URL...");
218 if(jump_state == "create_database")
219 state create_database;
220 if(jump_state == "get")
221 state get;
222 if(jump_state == "add")
223 state add;
224 if(jump_state == "remove")
225 state remove;
226 if(jump_state == "count_jokes")
227 state count_jokes;
228 if(jump_state == "listen_group")
229 state listen_group;
230  
231 // DEBUG
232 llOwnerSay("[Joke] Jump table corrupted, please contact creator...");
233 llResetScript();
234 }
235 on_rez(integer num) {
236 llResetScript();
237 }
238 changed(integer change) {
239 if((change & CHANGED_INVENTORY) ||
240 (change & CHANGED_REGION_START) ||
241 (change & CHANGED_OWNER)) {
242 llResetScript();
243 }
244 }
245 }
246  
247 state create_database {
248 state_entry() {
249 // DEBUG
250 llOwnerSay("[Joke] Creating database: " + wasKeyValueGet("joke table", configuration));
251 llInstantMessage(
252 wasKeyValueGet(
253 "corrade",
254 configuration
255 ),
256 wasKeyValueEncode(
257 [
258 "command", "database",
259 "group", wasURLEscape(
260 wasKeyValueGet(
261 "group",
262 configuration
263 )
264 ),
265 "password", wasURLEscape(
266 wasKeyValueGet(
267 "password",
268 configuration
269 )
270 ),
271 "SQL", wasURLEscape("CREATE TABLE IF NOT EXISTS \"" +
272 wasKeyValueGet("joke table", configuration) +
273 "\" (data text(1023), name text(35), firstname text(31), lastname text(31), id integer NOT NULL PRIMARY KEY)"),
274 "callback", wasURLEscape(URL)
275 ]
276 )
277 );
278 llSetTimerEvent(60);
279 }
280 http_request(key id, string method, string body) {
281 llHTTPResponse(id, 200, "OK");
282 llReleaseURL(URL);
283 if(wasKeyValueGet("command", body) != "database" ||
284 wasKeyValueGet("success", body) != "True") {
285 // DEBUG
286 llOwnerSay("[Joke] Unable modify database: " +
287 wasURLUnescape(
288 wasKeyValueGet("error", body)
289 ) +
290 " " +
291 wasURLUnescape(
292 wasKeyValueGet("data", body)
293 )
294  
295 );
296 llResetScript();
297 }
298 llOwnerSay("[Joke] Database created!");
299 jump_state = "count_jokes";
300 state url;
301 }
302 timer() {
303 llResetScript();
304 }
305 on_rez(integer num) {
306 llResetScript();
307 }
308 changed(integer change) {
309 if((change & CHANGED_INVENTORY) ||
310 (change & CHANGED_REGION_START) ||
311 (change & CHANGED_OWNER)) {
312 llResetScript();
313 }
314 }
315 state_exit() {
316 llSetTimerEvent(0);
317 }
318 }
319  
320 state count_jokes {
321 state_entry() {
322 // DEBUG
323 llOwnerSay("[Joke] Counting jokes in database: " + wasKeyValueGet("joke table", configuration));
324 llInstantMessage(
325 wasKeyValueGet(
326 "corrade",
327 configuration
328 ),
329 wasKeyValueEncode(
330 [
331 "command", "database",
332 "group", wasURLEscape(
333 wasKeyValueGet(
334 "group",
335 configuration
336 )
337 ),
338 "password", wasURLEscape(
339 wasKeyValueGet(
340 "password",
341 configuration
342 )
343 ),
344 "SQL", wasURLEscape("SELECT COUNT(*) AS count FROM \"" +
345 wasKeyValueGet("joke table", configuration) + "\""),
346 "callback", wasURLEscape(URL)
347 ]
348 )
349 );
350 llSetTimerEvent(60);
351 }
352 http_request(key id, string method, string body) {
353 llHTTPResponse(id, 200, "OK");
354 llReleaseURL(URL);
355 if(wasKeyValueGet("command", body) != "database" ||
356 wasKeyValueGet("success", body) != "True") {
357 // DEBUG
358 llOwnerSay("[Joke] Unable modify database: " +
359 wasURLUnescape(
360 wasKeyValueGet("error", body)
361 ) +
362 " " +
363 wasURLUnescape(
364 wasKeyValueGet("data", body)
365 )
366  
367 );
368 llResetScript();
369 }
370  
371 list result = wasCSVToList(
372 wasURLUnescape(
373 wasKeyValueGet("data", body)
374 )
375 );
376  
377 joke_counter = llList2Integer(
378 result,
379 llListFindList(result, ["count"]) + 1
380 );
381  
382 llOwnerSay("[Joke] There are " + (string)joke_counter + " jokes in the database.");
383 state listen_group;
384 }
385 timer() {
386 llResetScript();
387 }
388 on_rez(integer num) {
389 llResetScript();
390 }
391 changed(integer change) {
392 if((change & CHANGED_INVENTORY) ||
393 (change & CHANGED_REGION_START) ||
394 (change & CHANGED_OWNER)) {
395 llResetScript();
396 }
397 }
398 state_exit() {
399 llSetTimerEvent(0);
400 }
401 }
402  
403 state listen_group {
404 state_entry() {
405 // DEBUG
406 llOwnerSay("[Joke] Waiting for group messages.");
407 }
408 link_message(integer sender, integer num, string message, key id) {
409 // We only care about notifications now.
410 if(id != "notification")
411 return;
412  
413 // This script only processes group notifications.
414 if(wasKeyValueGet("type", message) != "group")
415 return;
416  
417 // Get the message sender.
418 firstname = wasURLUnescape(
419 wasKeyValueGet(
420 "firstname",
421 message
422 )
423 );
424  
425 lastname = wasURLUnescape(
426 wasKeyValueGet(
427 "lastname",
428 message
429 )
430 );
431  
432 // Get the sent message.
433 data = wasURLUnescape(
434 wasKeyValueGet(
435 "message",
436 message
437 )
438 );
439  
440 // Check if this is an eggdrop command.
441 if(llGetSubString(data, 0, 0) !=
442 wasKeyValueGet("command", configuration))
443 return;
444  
445 // Check if the command matches the current module.
446 list command = llParseString2List(data, [" "], []);
447 if(llList2String(command, 0) !=
448 wasKeyValueGet("command", configuration) + "joke")
449 return;
450  
451 // Remove command.
452 command = llDeleteSubList(command, 0, 0);
453  
454 // Remove action.
455 string action = llList2String(command, 0);
456 // Jump to the "add" state for adding
457 if(action == "add") {
458 command = llDeleteSubList(command, 0, 0);
459 data = llDumpList2String(command, " ");
460 if(data == "") {
461 data = "The joke's too short to be funny.";
462 state tell;
463 }
464 jump_state = "add";
465 state url;
466 }
467  
468 // Jump to the "remove" state for removing
469 if(action == "remove") {
470 command = llDeleteSubList(command, 0, 0);
471 data = llDumpList2String(command, " ");
472 if((integer)data == 0) {
473 data = "Which one though? Please provide a joke id.";
474 state tell;
475 }
476 jump_state = "remove";
477 state url;
478 }
479  
480 data = llDumpList2String(command, " ");
20 office 481 if((integer)data == 0)
482 data = "";
18 office 483 jump_state = "get";
484 state url;
485 }
486 on_rez(integer num) {
487 llResetScript();
488 }
489 changed(integer change) {
490 if((change & CHANGED_INVENTORY) ||
491 (change & CHANGED_REGION_START) ||
492 (change & CHANGED_OWNER)) {
493 llResetScript();
494 }
495 }
496 }
497  
498 state get {
499 state_entry() {
500 // DEBUG
501 llOwnerSay("[Joke] Retrieving from database.");
20 office 502 if(data == "") {
503 llInstantMessage(
504 wasKeyValueGet(
505 "corrade",
506 configuration
507 ),
508 wasKeyValueEncode(
509 [
510 "command", "database",
511 "group", wasURLEscape(
512 wasKeyValueGet(
513 "group",
514 configuration
515 )
516 ),
517 "password", wasURLEscape(
518 wasKeyValueGet(
519 "password",
520 configuration
521 )
522 ),
523 "SQL", wasURLEscape("SELECT * FROM \"" +
524 wasKeyValueGet("joke table", configuration) +
525 "\" WHERE name=:group LIMIT 1 OFFSET :id"),
526 "data", wasURLEscape(
527 wasListToCSV(
528 [
529 "group",
530 wasURLEscape(
531 wasKeyValueGet(
532 "group",
533 configuration
534 )
535 ),
536 "id",
537 (string)(
538 (integer)llFrand(
539 joke_counter
540 ) + 1
541 )
542 ]
543 )
544 ),
545 "callback", wasURLEscape(URL)
546 ]
547 )
548 );
549 llSetTimerEvent(60);
550 return;
551 }
18 office 552 llInstantMessage(
553 wasKeyValueGet(
554 "corrade",
555 configuration
556 ),
557 wasKeyValueEncode(
558 [
559 "command", "database",
560 "group", wasURLEscape(
561 wasKeyValueGet(
562 "group",
563 configuration
564 )
565 ),
566 "password", wasURLEscape(
567 wasKeyValueGet(
568 "password",
569 configuration
570 )
571 ),
572 "SQL", wasURLEscape("SELECT * FROM \"" +
573 wasKeyValueGet("joke table", configuration) +
20 office 574 "\" WHERE name=:group AND id=:id"),
18 office 575 "data", wasURLEscape(
576 wasListToCSV(
577 [
578 "group",
579 wasURLEscape(
580 wasKeyValueGet(
581 "group",
582 configuration
583 )
584 ),
585 "id",
20 office 586 data
18 office 587 ]
588 )
589 ),
590 "callback", wasURLEscape(URL)
591 ]
592 )
593 );
594 llSetTimerEvent(60);
595 }
596 http_request(key id, string method, string body) {
597 llHTTPResponse(id, 200, "OK");
598 llReleaseURL(URL);
599 if(wasKeyValueGet("command", body) != "database" ||
600 wasKeyValueGet("success", body) != "True") {
601 // DEBUG
602 llOwnerSay("[Joke] Unable retrieve from database: " +
603 wasURLUnescape(
604 wasKeyValueGet("error", body)
605 )
606 );
607 state listen_group;
608 }
609  
610 list result = wasCSVToList(
611 wasURLUnescape(
612 wasKeyValueGet("data", body)
613 )
614 );
615  
21 office 616 if(llGetListLength(result) != 10) {
617 data = "No joke found. . .";
18 office 618 state tell;
619 }
620  
621 data = llList2String(
622 result,
623 llListFindList(result, ["data"]) + 1
624 );
625  
626 string firstname = llList2String(
627 result,
628 llListFindList(result, ["firstname"]) + 1
629 );
630  
631 string lastname = llList2String(
632 result,
633 llListFindList(result, ["lastname"]) + 1
634 );
635  
636 string id = llList2String(
637 result,
638 llListFindList(result, ["id"]) + 1
639 );
640  
641 // Build data to be sent.
642 data += " " + "[" + firstname + " " + lastname + "/" + id + "]";
643  
644 state tell;
645 }
646 timer() {
647 llReleaseURL(URL);
648 state listen_group;
649 }
650 on_rez(integer num) {
651 llResetScript();
652 }
653 changed(integer change) {
654 if((change & CHANGED_INVENTORY) ||
655 (change & CHANGED_REGION_START) ||
656 (change & CHANGED_OWNER)) {
657 llResetScript();
658 }
659 }
660 state_exit() {
661 llSetTimerEvent(0);
662 }
663 }
664  
665 state add {
666 state_entry() {
667 // DEBUG
668 llOwnerSay("[Joke] Adding to database.");
669 llInstantMessage(
670 wasKeyValueGet(
671 "corrade",
672 configuration
673 ),
674 wasKeyValueEncode(
675 [
676 "command", "database",
677 "group", wasURLEscape(
678 wasKeyValueGet(
679 "group",
680 configuration
681 )
682 ),
683 "password", wasURLEscape(
684 wasKeyValueGet(
685 "password",
686 configuration
687 )
688 ),
689 "SQL", wasURLEscape("INSERT INTO \"" +
690 wasKeyValueGet("joke table", configuration) +
20 office 691 "\" (name, data, firstname, lastname, id) VALUES (:name, :data, :firstname, :lastname, :id)"),
18 office 692 "data", wasURLEscape(
693 wasListToCSV(
694 [
695 "name",
696 wasURLEscape(
697 wasKeyValueGet(
698 "group",
699 configuration
700 )
701 ),
702 "data",
703 wasURLEscape(data),
704 "firstname",
705 wasURLEscape(firstname),
706 "lastname",
20 office 707 wasURLEscape(lastname),
708 "id",
709 (string)(joke_counter + 1)
18 office 710 ]
711 )
712 ),
713 "callback", wasURLEscape(URL)
714 ]
715 )
716 );
717 llSetTimerEvent(60);
718 }
719 http_request(key id, string method, string body) {
720 llHTTPResponse(id, 200, "OK");
721 llReleaseURL(URL);
722 if(wasKeyValueGet("command", body) != "database" ||
723 wasKeyValueGet("success", body) != "True") {
724 // DEBUG
725 llOwnerSay("[Joke] Unable modify database: " +
726 wasURLUnescape(
727 wasKeyValueGet("error", body)
728 )
729 );
730 state listen_group;
731 }
732 ++joke_counter;
20 office 733 data = "Joke " + (string)joke_counter + " has been stored.";
18 office 734 state tell;
735 }
736 timer() {
737 llReleaseURL(URL);
738 state listen_group;
739 }
740 on_rez(integer num) {
741 llResetScript();
742 }
743 changed(integer change) {
744 if((change & CHANGED_INVENTORY) ||
745 (change & CHANGED_REGION_START) ||
746 (change & CHANGED_OWNER)) {
747 llResetScript();
748 }
749 }
750 state_exit() {
751 llSetTimerEvent(0);
752 }
753 }
754  
755 state remove {
756 state_entry() {
757 // DEBUG
758 llOwnerSay("[Joke] Removing from database.");
759 llInstantMessage(
760 wasKeyValueGet(
761 "corrade",
762 configuration
763 ),
764 wasKeyValueEncode(
765 [
766 "command", "database",
767 "group", wasURLEscape(
768 wasKeyValueGet(
769 "group",
770 configuration
771 )
772 ),
773 "password", wasURLEscape(
774 wasKeyValueGet(
775 "password",
776 configuration
777 )
778 ),
779 "SQL", wasURLEscape("DELETE FROM \"" +
780 wasKeyValueGet("joke table", configuration) +
781 "\" WHERE name=:name AND id=:id"),
782 "data", wasURLEscape(
783 wasListToCSV(
784 [
785 "name",
786 wasURLEscape(
787 wasKeyValueGet(
788 "group",
789 configuration
790 )
791 ),
792 "id",
20 office 793 data
18 office 794 ]
795 )
796 ),
797 "callback", wasURLEscape(URL)
798 ]
799 )
800 );
801 llSetTimerEvent(60);
802 }
803 http_request(key id, string method, string body) {
804 llHTTPResponse(id, 200, "OK");
805 llReleaseURL(URL);
806 if(wasKeyValueGet("command", body) != "database" ||
807 wasKeyValueGet("success", body) != "True") {
808 // DEBUG
809 llOwnerSay("[Joke] Unable modify database: " +
810 wasURLUnescape(
811 wasKeyValueGet("error", body)
812 )
813 );
814 state listen_group;
815 }
816 --joke_counter;
817 data = "Joke " + data + " has been removed.";
818 state tell;
819 }
820 timer() {
821 llReleaseURL(URL);
822 state listen_group;
823 }
824 on_rez(integer num) {
825 llResetScript();
826 }
827 changed(integer change) {
828 if((change & CHANGED_INVENTORY) ||
829 (change & CHANGED_REGION_START) ||
830 (change & CHANGED_OWNER)) {
831 llResetScript();
832 }
833 }
834 state_exit() {
835 llSetTimerEvent(0);
836 }
837 }
838  
839 state tell {
840 state_entry() {
841 // DEBUG
842 llOwnerSay("[Joke] Sending to group.");
843 llInstantMessage(
844 wasKeyValueGet(
845 "corrade",
846 configuration
847 ),
848 wasKeyValueEncode(
849 [
850 "command", "tell",
851 "group", wasURLEscape(
852 wasKeyValueGet(
853 "group",
854 configuration
855 )
856 ),
857 "password", wasURLEscape(
858 wasKeyValueGet(
859 "password",
860 configuration
861 )
862 ),
863 "entity", "group",
864 "message", wasURLEscape(data)
865 ]
866 )
867 );
868 state listen_group;
869 }
870 }