corrade-lsl-templates – Blame information for rev 18

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, " ");
481 jump_state = "get";
482 state url;
483 }
484 on_rez(integer num) {
485 llResetScript();
486 }
487 changed(integer change) {
488 if((change & CHANGED_INVENTORY) ||
489 (change & CHANGED_REGION_START) ||
490 (change & CHANGED_OWNER)) {
491 llResetScript();
492 }
493 }
494 }
495  
496 state get {
497 state_entry() {
498 // DEBUG
499 llOwnerSay("[Joke] Retrieving from database.");
500 llInstantMessage(
501 wasKeyValueGet(
502 "corrade",
503 configuration
504 ),
505 wasKeyValueEncode(
506 [
507 "command", "database",
508 "group", wasURLEscape(
509 wasKeyValueGet(
510 "group",
511 configuration
512 )
513 ),
514 "password", wasURLEscape(
515 wasKeyValueGet(
516 "password",
517 configuration
518 )
519 ),
520 "SQL", wasURLEscape("SELECT * FROM \"" +
521 wasKeyValueGet("joke table", configuration) +
522 "\" WHERE name=:group AND id=:id"),
523 "data", wasURLEscape(
524 wasListToCSV(
525 [
526 "group",
527 wasURLEscape(
528 wasKeyValueGet(
529 "group",
530 configuration
531 )
532 ),
533 "id",
534 (string)(
535 (integer)llFrand(
536 joke_counter
537 ) + 1
538 )
539 ]
540 )
541 ),
542 "callback", wasURLEscape(URL)
543 ]
544 )
545 );
546 llSetTimerEvent(60);
547 }
548 http_request(key id, string method, string body) {
549 llHTTPResponse(id, 200, "OK");
550 llReleaseURL(URL);
551 if(wasKeyValueGet("command", body) != "database" ||
552 wasKeyValueGet("success", body) != "True") {
553 // DEBUG
554 llOwnerSay("[Joke] Unable retrieve from database: " +
555 wasURLUnescape(
556 wasKeyValueGet("error", body)
557 )
558 );
559 state listen_group;
560 }
561  
562 list result = wasCSVToList(
563 wasURLUnescape(
564 wasKeyValueGet("data", body)
565 )
566 );
567  
568 if(result == []) {
569 data = "Could not select a joke. . .";
570 state tell;
571 }
572  
573 data = llList2String(
574 result,
575 llListFindList(result, ["data"]) + 1
576 );
577  
578 string firstname = llList2String(
579 result,
580 llListFindList(result, ["firstname"]) + 1
581 );
582  
583 string lastname = llList2String(
584 result,
585 llListFindList(result, ["lastname"]) + 1
586 );
587  
588 string id = llList2String(
589 result,
590 llListFindList(result, ["id"]) + 1
591 );
592  
593 // Build data to be sent.
594 data += " " + "[" + firstname + " " + lastname + "/" + id + "]";
595  
596 state tell;
597 }
598 timer() {
599 llReleaseURL(URL);
600 state listen_group;
601 }
602 on_rez(integer num) {
603 llResetScript();
604 }
605 changed(integer change) {
606 if((change & CHANGED_INVENTORY) ||
607 (change & CHANGED_REGION_START) ||
608 (change & CHANGED_OWNER)) {
609 llResetScript();
610 }
611 }
612 state_exit() {
613 llSetTimerEvent(0);
614 }
615 }
616  
617 state add {
618 state_entry() {
619 // DEBUG
620 llOwnerSay("[Joke] Adding to database.");
621 llInstantMessage(
622 wasKeyValueGet(
623 "corrade",
624 configuration
625 ),
626 wasKeyValueEncode(
627 [
628 "command", "database",
629 "group", wasURLEscape(
630 wasKeyValueGet(
631 "group",
632 configuration
633 )
634 ),
635 "password", wasURLEscape(
636 wasKeyValueGet(
637 "password",
638 configuration
639 )
640 ),
641 "SQL", wasURLEscape("INSERT INTO \"" +
642 wasKeyValueGet("joke table", configuration) +
643 "\" (name, data, firstname, lastname) VALUES (:name, :data, :firstname, :lastname)"),
644 "data", wasURLEscape(
645 wasListToCSV(
646 [
647 "name",
648 wasURLEscape(
649 wasKeyValueGet(
650 "group",
651 configuration
652 )
653 ),
654 "data",
655 wasURLEscape(data),
656 "firstname",
657 wasURLEscape(firstname),
658 "lastname",
659 wasURLEscape(lastname)
660 ]
661 )
662 ),
663 "callback", wasURLEscape(URL)
664 ]
665 )
666 );
667 llSetTimerEvent(60);
668 }
669 http_request(key id, string method, string body) {
670 llHTTPResponse(id, 200, "OK");
671 llReleaseURL(URL);
672 if(wasKeyValueGet("command", body) != "database" ||
673 wasKeyValueGet("success", body) != "True") {
674 // DEBUG
675 llOwnerSay("[Joke] Unable modify database: " +
676 wasURLUnescape(
677 wasKeyValueGet("error", body)
678 )
679 );
680 state listen_group;
681 }
682 ++joke_counter;
683 data = "Joke has been stored.";
684 state tell;
685 }
686 timer() {
687 llReleaseURL(URL);
688 state listen_group;
689 }
690 on_rez(integer num) {
691 llResetScript();
692 }
693 changed(integer change) {
694 if((change & CHANGED_INVENTORY) ||
695 (change & CHANGED_REGION_START) ||
696 (change & CHANGED_OWNER)) {
697 llResetScript();
698 }
699 }
700 state_exit() {
701 llSetTimerEvent(0);
702 }
703 }
704  
705 state remove {
706 state_entry() {
707 // DEBUG
708 llOwnerSay("[Joke] Removing from database.");
709 llInstantMessage(
710 wasKeyValueGet(
711 "corrade",
712 configuration
713 ),
714 wasKeyValueEncode(
715 [
716 "command", "database",
717 "group", wasURLEscape(
718 wasKeyValueGet(
719 "group",
720 configuration
721 )
722 ),
723 "password", wasURLEscape(
724 wasKeyValueGet(
725 "password",
726 configuration
727 )
728 ),
729 "SQL", wasURLEscape("DELETE FROM \"" +
730 wasKeyValueGet("joke table", configuration) +
731 "\" WHERE name=:name AND id=:id"),
732 "data", wasURLEscape(
733 wasListToCSV(
734 [
735 "name",
736 wasURLEscape(
737 wasKeyValueGet(
738 "group",
739 configuration
740 )
741 ),
742 "id",
743 wasURLEscape(data)
744 ]
745 )
746 ),
747 "callback", wasURLEscape(URL)
748 ]
749 )
750 );
751 llSetTimerEvent(60);
752 }
753 http_request(key id, string method, string body) {
754 llHTTPResponse(id, 200, "OK");
755 llReleaseURL(URL);
756 if(wasKeyValueGet("command", body) != "database" ||
757 wasKeyValueGet("success", body) != "True") {
758 // DEBUG
759 llOwnerSay("[Joke] Unable modify database: " +
760 wasURLUnescape(
761 wasKeyValueGet("error", body)
762 )
763 );
764 state listen_group;
765 }
766 --joke_counter;
767 data = "Joke " + data + " has been removed.";
768 state tell;
769 }
770 timer() {
771 llReleaseURL(URL);
772 state listen_group;
773 }
774 on_rez(integer num) {
775 llResetScript();
776 }
777 changed(integer change) {
778 if((change & CHANGED_INVENTORY) ||
779 (change & CHANGED_REGION_START) ||
780 (change & CHANGED_OWNER)) {
781 llResetScript();
782 }
783 }
784 state_exit() {
785 llSetTimerEvent(0);
786 }
787 }
788  
789 state tell {
790 state_entry() {
791 // DEBUG
792 llOwnerSay("[Joke] Sending to group.");
793 llInstantMessage(
794 wasKeyValueGet(
795 "corrade",
796 configuration
797 ),
798 wasKeyValueEncode(
799 [
800 "command", "tell",
801 "group", wasURLEscape(
802 wasKeyValueGet(
803 "group",
804 configuration
805 )
806 ),
807 "password", wasURLEscape(
808 wasKeyValueGet(
809 "password",
810 configuration
811 )
812 ),
813 "entity", "group",
814 "message", wasURLEscape(data)
815 ]
816 )
817 );
818 state listen_group;
819 }
820 }