corrade-lsl-templates – Blame information for rev 42

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