corrade-lsl-templates – Blame information for rev 30

Subversion Repositories:
Rev:
Rev Author Line No. Line
18 office 1 ///////////////////////////////////////////////////////////////////////////
30 office 2 // Copyright (C) Wizardry and Steamworks 2018 - License: GNU GPLv3 //
18 office 3 ///////////////////////////////////////////////////////////////////////////
4 //
5 // A database-based joke module for Corrade Eggdrop.
6 //
7 ///////////////////////////////////////////////////////////////////////////
8  
9 ///////////////////////////////////////////////////////////////////////////
30 office 10 // Copyright (C) 2015 Wizardry and Steamworks - License: CC BY 2.0 //
18 office 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, ["&", "="], []);
30 office 16 integer i = llListFindList(llList2ListStrided(a, 0, -1, 2), [ k ]);
17 if(i != -1) return llList2String(a, 2*i+1);
18 office 18 return "";
19 }
20  
21 ///////////////////////////////////////////////////////////////////////////
30 office 22 // Copyright (C) 2013 Wizardry and Steamworks - License: GNU GPLv3 //
18 office 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 ///////////////////////////////////////////////////////////////////////////
30 office 37 // Copyright (C) 2011 Wizardry and Steamworks - License: GNU GPLv3 //
18 office 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 ///////////////////////////////////////////////////////////////////////////
30 office 49 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
18 office 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 ///////////////////////////////////////////////////////////////////////////
30 office 73 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
18 office 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 ///////////////////////////////////////////////////////////////////////////
30 office 112 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
18 office 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 ///////////////////////////////////////////////////////////////////////////
30 office 141 // Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 //
18 office 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
30 office 380 ) + 1;
18 office 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.
30 office 414 if(wasKeyValueGet("type", message) != "group" ||
415 (wasKeyValueGet("type", message) == "group" &&
416 wasURLUnescape(wasKeyValueGet("group", message)) !=
417 wasKeyValueGet("group", configuration)))
18 office 418 return;
419  
420 // Get the message sender.
421 firstname = wasURLUnescape(
422 wasKeyValueGet(
423 "firstname",
424 message
425 )
426 );
427  
428 lastname = wasURLUnescape(
429 wasKeyValueGet(
430 "lastname",
431 message
432 )
433 );
434  
435 // Get the sent message.
436 data = wasURLUnescape(
437 wasKeyValueGet(
438 "message",
439 message
440 )
441 );
442  
443 // Check if this is an eggdrop command.
444 if(llGetSubString(data, 0, 0) !=
445 wasKeyValueGet("command", configuration))
446 return;
447  
448 // Check if the command matches the current module.
449 list command = llParseString2List(data, [" "], []);
450 if(llList2String(command, 0) !=
451 wasKeyValueGet("command", configuration) + "joke")
452 return;
453  
454 // Remove command.
455 command = llDeleteSubList(command, 0, 0);
456  
457 // Remove action.
458 string action = llList2String(command, 0);
459 // Jump to the "add" state for adding
460 if(action == "add") {
461 command = llDeleteSubList(command, 0, 0);
462 data = llDumpList2String(command, " ");
463 if(data == "") {
464 data = "The joke's too short to be funny.";
465 state tell;
466 }
467 jump_state = "add";
468 state url;
469 }
470  
471 // Jump to the "remove" state for removing
472 if(action == "remove") {
473 command = llDeleteSubList(command, 0, 0);
474 data = llDumpList2String(command, " ");
475 if((integer)data == 0) {
476 data = "Which one though? Please provide a joke id.";
477 state tell;
478 }
479 jump_state = "remove";
480 state url;
481 }
482  
483 data = llDumpList2String(command, " ");
30 office 484 if((integer)data <= 0)
20 office 485 data = "";
18 office 486 jump_state = "get";
487 state url;
488 }
489 on_rez(integer num) {
490 llResetScript();
491 }
492 changed(integer change) {
493 if((change & CHANGED_INVENTORY) ||
494 (change & CHANGED_REGION_START) ||
495 (change & CHANGED_OWNER)) {
496 llResetScript();
497 }
498 }
499 }
500  
501 state get {
502 state_entry() {
503 // DEBUG
504 llOwnerSay("[Joke] Retrieving from database.");
20 office 505 if(data == "") {
506 llInstantMessage(
507 wasKeyValueGet(
508 "corrade",
509 configuration
510 ),
511 wasKeyValueEncode(
512 [
513 "command", "database",
514 "group", wasURLEscape(
515 wasKeyValueGet(
516 "group",
517 configuration
518 )
519 ),
520 "password", wasURLEscape(
521 wasKeyValueGet(
522 "password",
523 configuration
524 )
525 ),
526 "SQL", wasURLEscape("SELECT * FROM \"" +
527 wasKeyValueGet("joke table", configuration) +
528 "\" WHERE name=:group LIMIT 1 OFFSET :id"),
529 "data", wasURLEscape(
530 wasListToCSV(
531 [
532 "group",
533 wasURLEscape(
534 wasKeyValueGet(
535 "group",
536 configuration
537 )
538 ),
539 "id",
540 (string)(
541 (integer)llFrand(
542 joke_counter
543 ) + 1
544 )
545 ]
546 )
547 ),
548 "callback", wasURLEscape(URL)
549 ]
550 )
551 );
552 llSetTimerEvent(60);
553 return;
554 }
18 office 555 llInstantMessage(
556 wasKeyValueGet(
557 "corrade",
558 configuration
559 ),
560 wasKeyValueEncode(
561 [
562 "command", "database",
563 "group", wasURLEscape(
564 wasKeyValueGet(
565 "group",
566 configuration
567 )
568 ),
569 "password", wasURLEscape(
570 wasKeyValueGet(
571 "password",
572 configuration
573 )
574 ),
575 "SQL", wasURLEscape("SELECT * FROM \"" +
576 wasKeyValueGet("joke table", configuration) +
20 office 577 "\" WHERE name=:group AND id=:id"),
18 office 578 "data", wasURLEscape(
579 wasListToCSV(
580 [
581 "group",
582 wasURLEscape(
583 wasKeyValueGet(
584 "group",
585 configuration
586 )
587 ),
588 "id",
20 office 589 data
18 office 590 ]
591 )
592 ),
593 "callback", wasURLEscape(URL)
594 ]
595 )
596 );
597 llSetTimerEvent(60);
598 }
599 http_request(key id, string method, string body) {
600 llHTTPResponse(id, 200, "OK");
601 llReleaseURL(URL);
602 if(wasKeyValueGet("command", body) != "database" ||
603 wasKeyValueGet("success", body) != "True") {
604 // DEBUG
605 llOwnerSay("[Joke] Unable retrieve from database: " +
606 wasURLUnescape(
607 wasKeyValueGet("error", body)
608 )
609 );
610 state listen_group;
611 }
612  
613 list result = wasCSVToList(
614 wasURLUnescape(
615 wasKeyValueGet("data", body)
616 )
617 );
618  
21 office 619 if(llGetListLength(result) != 10) {
620 data = "No joke found. . .";
18 office 621 state tell;
622 }
623  
624 data = llList2String(
625 result,
626 llListFindList(result, ["data"]) + 1
627 );
628  
629 string firstname = llList2String(
630 result,
631 llListFindList(result, ["firstname"]) + 1
632 );
633  
634 string lastname = llList2String(
635 result,
636 llListFindList(result, ["lastname"]) + 1
637 );
638  
639 string id = llList2String(
640 result,
641 llListFindList(result, ["id"]) + 1
642 );
643  
644 // Build data to be sent.
645 data += " " + "[" + firstname + " " + lastname + "/" + id + "]";
646  
647 state tell;
648 }
649 timer() {
650 llReleaseURL(URL);
651 state listen_group;
652 }
653 on_rez(integer num) {
654 llResetScript();
655 }
656 changed(integer change) {
657 if((change & CHANGED_INVENTORY) ||
658 (change & CHANGED_REGION_START) ||
659 (change & CHANGED_OWNER)) {
660 llResetScript();
661 }
662 }
663 state_exit() {
664 llSetTimerEvent(0);
665 }
666 }
667  
668 state add {
669 state_entry() {
670 // DEBUG
30 office 671 llOwnerSay("[Joke] Adding to database: " + (string)(joke_counter + 1));
18 office 672 llInstantMessage(
673 wasKeyValueGet(
674 "corrade",
675 configuration
676 ),
677 wasKeyValueEncode(
678 [
679 "command", "database",
680 "group", wasURLEscape(
681 wasKeyValueGet(
682 "group",
683 configuration
684 )
685 ),
686 "password", wasURLEscape(
687 wasKeyValueGet(
688 "password",
689 configuration
690 )
691 ),
692 "SQL", wasURLEscape("INSERT INTO \"" +
693 wasKeyValueGet("joke table", configuration) +
20 office 694 "\" (name, data, firstname, lastname, id) VALUES (:name, :data, :firstname, :lastname, :id)"),
18 office 695 "data", wasURLEscape(
696 wasListToCSV(
697 [
698 "name",
699 wasURLEscape(
700 wasKeyValueGet(
701 "group",
702 configuration
703 )
704 ),
705 "data",
706 wasURLEscape(data),
707 "firstname",
708 wasURLEscape(firstname),
709 "lastname",
20 office 710 wasURLEscape(lastname),
711 "id",
712 (string)(joke_counter + 1)
18 office 713 ]
714 )
715 ),
716 "callback", wasURLEscape(URL)
717 ]
718 )
719 );
720 llSetTimerEvent(60);
721 }
722 http_request(key id, string method, string body) {
723 llHTTPResponse(id, 200, "OK");
724 llReleaseURL(URL);
725 if(wasKeyValueGet("command", body) != "database" ||
726 wasKeyValueGet("success", body) != "True") {
727 // DEBUG
728 llOwnerSay("[Joke] Unable modify database: " +
729 wasURLUnescape(
30 office 730 wasKeyValueGet("data", body)
18 office 731 )
732 );
733 state listen_group;
734 }
735 ++joke_counter;
20 office 736 data = "Joke " + (string)joke_counter + " has been stored.";
18 office 737 state tell;
738 }
739 timer() {
740 llReleaseURL(URL);
741 state listen_group;
742 }
743 on_rez(integer num) {
744 llResetScript();
745 }
746 changed(integer change) {
747 if((change & CHANGED_INVENTORY) ||
748 (change & CHANGED_REGION_START) ||
749 (change & CHANGED_OWNER)) {
750 llResetScript();
751 }
752 }
753 state_exit() {
754 llSetTimerEvent(0);
755 }
756 }
757  
758 state remove {
759 state_entry() {
760 // DEBUG
761 llOwnerSay("[Joke] Removing from database.");
762 llInstantMessage(
763 wasKeyValueGet(
764 "corrade",
765 configuration
766 ),
767 wasKeyValueEncode(
768 [
769 "command", "database",
770 "group", wasURLEscape(
771 wasKeyValueGet(
772 "group",
773 configuration
774 )
775 ),
776 "password", wasURLEscape(
777 wasKeyValueGet(
778 "password",
779 configuration
780 )
781 ),
782 "SQL", wasURLEscape("DELETE FROM \"" +
783 wasKeyValueGet("joke table", configuration) +
784 "\" WHERE name=:name AND id=:id"),
785 "data", wasURLEscape(
786 wasListToCSV(
787 [
788 "name",
789 wasURLEscape(
790 wasKeyValueGet(
791 "group",
792 configuration
793 )
794 ),
795 "id",
20 office 796 data
18 office 797 ]
798 )
799 ),
800 "callback", wasURLEscape(URL)
801 ]
802 )
803 );
804 llSetTimerEvent(60);
805 }
806 http_request(key id, string method, string body) {
807 llHTTPResponse(id, 200, "OK");
808 llReleaseURL(URL);
809 if(wasKeyValueGet("command", body) != "database" ||
810 wasKeyValueGet("success", body) != "True") {
811 // DEBUG
812 llOwnerSay("[Joke] Unable modify database: " +
813 wasURLUnescape(
814 wasKeyValueGet("error", body)
815 )
816 );
817 state listen_group;
818 }
819 --joke_counter;
820 data = "Joke " + data + " has been removed.";
821 state tell;
822 }
823 timer() {
824 llReleaseURL(URL);
825 state listen_group;
826 }
827 on_rez(integer num) {
828 llResetScript();
829 }
830 changed(integer change) {
831 if((change & CHANGED_INVENTORY) ||
832 (change & CHANGED_REGION_START) ||
833 (change & CHANGED_OWNER)) {
834 llResetScript();
835 }
836 }
837 state_exit() {
838 llSetTimerEvent(0);
839 }
840 }
841  
842 state tell {
843 state_entry() {
844 // DEBUG
845 llOwnerSay("[Joke] Sending to group.");
846 llInstantMessage(
847 wasKeyValueGet(
848 "corrade",
849 configuration
850 ),
851 wasKeyValueEncode(
852 [
853 "command", "tell",
854 "group", wasURLEscape(
855 wasKeyValueGet(
856 "group",
857 configuration
858 )
859 ),
860 "password", wasURLEscape(
861 wasKeyValueGet(
862 "password",
863 configuration
864 )
865 ),
866 "entity", "group",
867 "message", wasURLEscape(data)
868 ]
869 )
870 );
871 state listen_group;
872 }
873 }