Join us in Outworldz at www.outworldz.com:9000 or follow us:

Search dozens of selected web sites for OpenSim and LSL script

New! Script Meta-Search will search thousands of scripts here and at other sites for LSL or Opensim scripts.
Loading

Want to add a script or a project? Upload it and a half million people will see it and your name here this year.

Home   Show All
Category: Contributor: Creator
Twitter Twiiter_Library  

Twiiter_Library

Using the Twitter OAuth Library

T...

Category: Twitter
By : Babbage Linden
Created: 2011-01-01 Edited: 2011-01-01
Worlds: Second Life

the Zip file

Download all files for Twiiter_Library
Contents are in zip format, with .LSL (text) source code and LSLEdit (text + Solution) formats.
Get file # 1. Twiiter_Library_1.lsl
Get file # 2. Twiiter_Library_2.lsl
1 //////////////////////////////////////////////////////////////////////////////////////
2 //
3 // Twitter OAuth Client 1.0: An example client that uses the LSL OAuth 1.0a
4 // Library for Twitter by Babbage Linden.
5 //
6 // Released under the Creative Commons Creative Commons Attribution-Share Alike 3.0
7 // license http://creativecommons.org/licenses/by-sa/3.0/
8 //
9 //////////////////////////////////////////////////////////////////////////////////////
10
11 // Application constants generated by Twitter.
12 // Set up a new Twitter application here: http://twitter.com/oauth_clients
13 string TWITTER_OAUTH_CONSUMER_KEY = "YOUR CONSUMER KEY HERE";
14 string TWITTER_OAUTH_CONSUMER_SECRET = "YOUR CONSUMER SECRET HERE";
15
16 // Message constants defined by Twitter OAuth library.
17 integer TWITTER_OAUTH_SET_CONSUMER_KEY = 999000;
18 integer TWITTER_OAUTH_SET_CONSUMER_SECRET = 999001;
19 integer TWITTER_OAUTH_SET_MAX_RETRIES = 999002;
20 integer TWITTER_OAUTH_UPDATE_STATUS = 999003;
21
22 TwitterOAuthInit()
23 {
24 // Set up Twitter OAuth library, using application consumer key and secret generated by Twitter.
25 llMessageLinked(LINK_THIS, TWITTER_OAUTH_SET_CONSUMER_KEY, TWITTER_OAUTH_CONSUMER_KEY, NULL_KEY);
26 llMessageLinked(LINK_THIS, TWITTER_OAUTH_SET_CONSUMER_SECRET, TWITTER_OAUTH_CONSUMER_SECRET, NULL_KEY);
27 llMessageLinked(LINK_THIS, TWITTER_OAUTH_SET_MAX_RETRIES, "10", NULL_KEY);
28 }
29
30 string TwitterOAuthGetSLURL()
31 {
32 string globe = "http://maps.secondlife.com/secondlife";
33 string region = llGetRegionName();
34 vector pos = llGetPos();
35 string posx = (string) llRound(pos.x);
36 string posy = (string) llRound(pos.y);
37 string posz = (string) llRound(pos.z);
38 return globe + "/" + llEscapeURL(region) +"/" + posx + "/" + posy + "/" + posz;
39 }
40
41 string TwitterOAuthBuildMessage()
42 {
43 // Example message, change this as appropriate.
44 return "I did something amazing in Second Life here " + TwitterOAuthGetSLURL() + " #inSL";
45 }
46
47 TwitterOAuthUpdateStatus(string message, key avatar)
48 {
49 llMessageLinked(LINK_THIS, TWITTER_OAUTH_UPDATE_STATUS, message, avatar);
50 }
51
52 // STOP COPYING HERE
53
54 default
55 {
57 {
58 TwitterOAuthInit();
59 }
60
61 on_rez(integer param)
62 {
63 TwitterOAuthInit();
64 }
65
66 touch_start(integer total_number)
67 {
68 TwitterOAuthUpdateStatus(TwitterOAuthBuildMessage(), llDetectedKey(0));
69 }
70 }

Twiiter_Library

Twitter OAuth Library

Category: Twitter
By : Babbage Linden
Created: 2011-01-01 Edited: 2011-01-01
Worlds: Second Life

1 //////////////////////////////////////////////////////////////////////////////////////
2 //
3 // Twitter OAuth Lib 1.0: An LSL OAuth 1.0a Library for Twitter by Babbage Linden.
4 // Built with Cale Flanagan's LSL HMAC-SHA1 implementation and Strife Onizuka's
5 // LGPL Combined Library and with help from Latif Khalifa.
6 //
7 // This library is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU Lesser General Public License
9 // as published by the Free Software Foundation;
10 // version 3 of the License.
11 //
12 // This library is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Lesser General Public License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public License
18 // along with this library. If not, see <http://www.gnu.org/licenses/>
19 // or write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 // Boston, MA 02111-1307 USA
21 //
22 //////////////////////////////////////////////////////////////////////////////////////
23
24 // Library protocol constants.
25 integer TWITTER_OAUTH_SET_CONSUMER_KEY = 999000;
26 integer TWITTER_OAUTH_SET_CONSUMER_SECRET = 999001;
27 integer TWITTER_OAUTH_SET_MAX_RETRIES = 999002;
28 integer TWITTER_OAUTH_UPDATE_STATUS = 999003;
29
30 // Library state.
31 string gConsumerKey = "";
32 string gConsumerSecret = "";
33 integer gMaxRetries = 10;
34
35 // Request state.
36 key gAvatarKey;
37 string gMessage;
38 key gRequestTokenKey;
39 string gRequestToken;
40 string gRequestTokenSecret;
41 key gAccessTokenKey;
42 string gVerifier;
43 string gAuthorizeUrl = "oob";
44 integer gRetries;
45
46 string TrimRight(string src, string chrs)//LSLEditor Unsafe, LSL Safe
47 {
48 integer i = llStringLength(src);
49 do ; while(~llSubStringIndex(chrs, llGetSubString(src, i = ~-i, i)) && i);
50 return llDeleteSubString(src, -~(i), 0x7FFFFFF0);
51 }
52
53 string WriteBase64Integer(string data, integer index, integer value)
54 {
55
56 integer S = 12 - ((index % 3) << 1);
57 return llDeleteSubString(
59 data,
60 index = ((index << 4) / 3),
63 (llBase64ToInteger(llGetSubString((data = llGetSubString(data, index, index+7)) + "AAAAAA", 0, 5)) & (0xFFF00000 << S)) |
64 ((value >> (12 - S)) & ~(0xFFF00000 << S))
65 ), 2,
67 (llBase64ToInteger(llGetSubString((llDeleteSubString(data, 0, 1)) + "AAAAAA", 0, 5)) & ~(0xFFFFFFFF << S)) |
68 (value << S)
69 ) ) ), index+7, index + 22);//insert it then remove the old and the extra.
70 }
71
72 string DwordListToBase64(list a)
73 {
74 integer len = (a != []);
75 integer i = -1;
76 string out;
77 while((i = -~i) < len)
78 out = WriteBase64Integer(out, i, llList2Integer(a, i));
79 return TrimRight(out,"A");
80 }
81
82 // Takes a dwordblock, adds a string and puts it padded for blocksize into a dwordlist
83 // returns sha1blocks
84 list PrepareShortkey(string s)
85 {
86 integer v = 0;
87 integer cnt = llStringLength(s);
88 integer n = cnt;
89 list dw_skey;
90
91 for (n = 0; n < cnt; n++)
92 {
93 v = v | 0xFF & llBase64ToInteger("AAAA" + llStringToBase64(llGetSubString(s, n, n)));
94 if(n % 4 == 3)
95 {
96 dw_skey += [v];
97 v = 0;
98 }
99 else
100 {
101 v = v << 8;
102 }
103 }
104
105 //pad 0s (could be done dword-wise, after filling up to boundary, later, maybe...)
106 for ( ; n < 64; n++)
107 {
108 if(n % 4 == 3)
109 {
110 dw_skey += [v];
111 v = 0;
112 }
113 else
114 {
115 v = v << 8;
116 }
117 }
118 dw_skey += [v];
119
120 return dw_skey;
121 }
122
123 // Takes a dwordblock, adds a string and puts it padded for blocksize into a dwordlist
124 // returns sha1blocks
125 list PrepareSha1Blocks(list dwords, string s)
126 {
127 integer v = 0;
128 integer cnt = llStringLength(s);
129 integer n = cnt;
130 integer mcnt = cnt;
131 list shablocks = dwords;
132
133 mcnt = cnt + (dwords != []) * 4; // add up the dword-data (total message length)
134
135 for (n = 0; n < cnt; n++)
136 {
137 v = v | 0xFF & llBase64ToInteger("AAAA" + llStringToBase64(llGetSubString(s, n, n)));
138 if(n % 4 == 3)
139 {
140 shablocks += [v];
141 v = 0;
142 }
143 else
144 {
145 v = v << 8;
146 }
147 }
148
149 // pad a 1 and seven 0's
150 v = v | 0x80;
151 if(n % 4 == 3)
152 {
153 shablocks += [v];
154 v = 0;
155 }
156 else
157 {
158 v = v << 8;
159 }
160 n++;
161
162 //we ignored the dwords silently, but now we have to take them into account
163
164 //how many bytes do we need to fill blocks and have 8 bytes left...
165 cnt = ((mcnt + 8) / 64 + 1) * 64 - 9;
166
167 //pad 0s (could be done dword-wise, after filling up to boundary, later, maybe...)
168 for (n += (dwords != []) * 4 ; n < cnt; n++)
169 {
170 if(n % 4 == 3)
171 {
172 shablocks += [v];
173 v = 0;
174 }
175 else
176 {
177 v = v << 8;
178 }
179 }
180 shablocks += [v];
181
182 // pad message length
183 shablocks += [0]; // we assume not to have more as 16M messagesize (roughly)
184 shablocks += [8 * mcnt];
185
186 return shablocks;
187 }
188
189 // Inner core of sha1 calculation, based on FIPS 180-1
190 // http://www.itl.nist.gov/fipspubs/fip180-1.htm
191 // and some help from http://www.herongyang.com/crypto/message_digest_sha1.html
192 // and a bit from lkalif specialized on dwordlists
193 //
194 // Takes a dwordlist as input and returns hash as dwordlist
195 list ProcessSha1(list dwblocks)
196 {
197 integer block;
198 integer blocks = (dwblocks != []) / 16;
199 integer H0 = 0x67452301;
200 integer H1 = 0xEFCDAB89;
201 integer H2 = 0x98BADCFE;
202 integer H3 = 0x10325476;
203 integer H4 = 0xC3D2E1F0;
204
205 for (block = 0; block < blocks; block++)
206 {
207 list W;
208 integer t;
209 integer A = H0;
210 integer B = H1;
211 integer C = H2;
212 integer D = H3;
213 integer E = H4;
214
215 for (t = 0; t < 16; t++)
216 {
217 W += [llList2Integer(dwblocks, t + block * 16)];
218 }
219 for ( ; t < 80; t++)
220 {
221 integer x = llList2Integer(W, t - 3) ^ llList2Integer(W, t - 8) ^ llList2Integer(W, t - 14) ^ llList2Integer(W, t - 16);
222 W += [(x << 1) |!!(x & 0x80000000)]; // borrowed from lkalif
223 }
224
225 for (t = 0; t < 20; t++)
226 {
227 integer TEMP = ((A << 5) | ((A >> 27) & 0x1F)) + ((B & C) | ((~B) & D)) + E + llList2Integer(W, t) + 0x5A827999;
228 E = D; D = C; C = ((B << 30) | ((B >> 2) & 0x3FFFFFFF)); B = A; A = TEMP;
229 }
230 for (; t < 40; t++)
231 {
232 integer TEMP = ((A << 5) | ((A >> 27) & 0x1F)) + (B ^ C ^ D) + E + llList2Integer(W, t) + 0x6ED9EBA1;
233 E = D; D = C; C = ((B << 30) | ((B >> 2) & 0x3FFFFFFF)); B = A; A = TEMP;
234 }
235 for (; t < 60; t++)
236 {
237 integer TEMP = ((A << 5) | ((A >> 27) & 0x1F)) + ((B & C) | (B & D) | (C & D)) + E + llList2Integer(W, t) + 0x8F1BBCDC;
238 E = D; D = C; C = ((B << 30) | ((B >> 2) & 0x3FFFFFFF)); B = A; A = TEMP;
239 }
240 for (; t < 80; t++)
241 {
242 integer TEMP = ((A << 5) | ((A >> 27) & 0x1F)) + (B ^ C ^ D) + E + llList2Integer(W, t) + 0xCA62C1D6;
243 E = D; D = C; C = ((B << 30) | ((B >> 2) & 0x3FFFFFFF)); B = A; A = TEMP;
244 }
245
246 H0 += A;
247 H1 += B;
248 H2 += C;
249 H3 += D;
250 H4 += E;
251 }
252
253 return [H0, H1, H2, H3, H4];
254 }
255
256 //Caveats: Handling of unicode undefined and no message longer 16M allowed
257 list Sha1DWord(list dw, string message)
258 {
259 list sha1blocks = PrepareSha1Blocks(dw, message);
260 list digest = ProcessSha1(sha1blocks);
261 return digest;
262 }
263
264 list dw_key;
265 list dw_ipad;
266 list dw_opad;
267
268 // xor the 64bytes (16 dwords) with value
269 list PreparePad(integer val)
270 {
271 list r;
272 integer i;
273
274 for (i = 0; i < 16; )
275 {
276 r += [llList2Integer(dw_key, i++) ^ val];
277 }
278
279 return r;
280 }
281
282 // 2 step design, for simple re-use of key-data
283 HmacInit(string secretkey)
284 {
285 if(llStringLength(secretkey) > 64) // sha1 only if blocksize exceeded
286 dw_key = Sha1DWord([], secretkey) + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
287 else
288 dw_key = PrepareShortkey(secretkey);
289
290 dw_ipad = PreparePad(0x36363636);
291 dw_opad = PreparePad(0x5c5c5c5c);
292 }
293
294 list HmacUpdate(string message)
295 {
296 list dw_ihash = Sha1DWord(dw_ipad, message);
297 list dw_opad2 = dw_opad + dw_ihash;
298
299 return Sha1DWord(dw_opad2, "");
300 }
301
302 integer cacheSize = 25;
303 list tokenCache = [];
304
305 string GetAccessToken(key avatarId)
306 {
307 string result = "";
308 integer index = llListFindList(tokenCache, [avatarId]);
309 if(index != -1)
310 {
311 result = llList2String(tokenCache, index + 1);
312 }
313 return result;
314 }
315
316 string GetAccessTokenSecret(key avatarId)
317 {
318 string result = "";
319 integer index = llListFindList(tokenCache, [avatarId]);
320 if(index != -1)
321 {
322 result = llList2String(tokenCache, index + 2);
323 }
324 return result;
325 }
326
327 SetAccessToken(key avatarId, string accessToken, string accessTokenSecret)
328 {
329 integer stride = 3;
330 integer maxLength = (cacheSize * stride) - stride;
331 if(llGetListLength(tokenCache) > maxLength)
332 {
333 tokenCache = llDeleteSubList(tokenCache, maxLength, -1);
334 }
335 tokenCache = [avatarId, accessToken, accessTokenSecret] + tokenCache;
336 }
337
338 string OAuthUrlEncodeString(string s)
339 {
340 string result = "";
341 integer count = llStringLength(s);
342 integer i;
343 for (i = 0; i < count; ++i)
344 {
345 string c = llGetSubString(s, i, i);
346 if(c != "-" && c != "_" && c != "." && c != "," && c != "~")
347 {
348 c = llEscapeURL(c);
349 }
350 result += c;
351 }
352 return result;
353 }
354
355 list OAuthUrlEncodeList(list l)
356 {
357 list result = [];
359 integer i;
360 for(i = 0; i < c; ++i)
361 {
362 result += OAuthUrlEncodeString(llList2String(l, i));
363 }
364 return result;
365 }
366
367 string OAuthConcatenate(list l)
368 {
369 string result = "";
370 integer count = llGetListLength(l);
371 integer i = 0;
372 while(i < count)
373 {
374 result += llList2String(l, i) + "=" + llList2String(l, i + 1);
375 i += 2;
376 if(i < count)
377 {
378 result += "&";
379 }
380 }
381 return result;
382 }
383
384 string Sign(string method, string url, string consumerSecret, string tokenSecret, list parameters)
385 {
386 string signatureBase = OAuthUrlEncodeString(method) + "&" + OAuthUrlEncodeString(url) + "&" +
387 OAuthUrlEncodeString(OAuthConcatenate(parameters));
388 //llOwnerSay(signatureBase);
389
390 list keyList = [];
391 keyList += consumerSecret;
392 keyList += tokenSecret;
393 string keyString = consumerSecret + "&" + tokenSecret;
394 //llOwnerSay(keyString);
395
396 HmacInit(keyString);
397 list dwSig = HmacUpdate(signatureBase);
398
399 return DwordListToBase64(dwSig) + "=";
400 }
401
402 string OAuthUrl(string method, string url, string consumerKey, string consumerSecret, string token,
403 string tokenSecret, list additionalParams)
404 {
405 integer nonce = (integer)llFrand(1000000);
406 list parameters = ["oauth_version","1.0a",
407 "oauth_nonce", (string)nonce,
408 "oauth_consumer_key", consumerKey,
409 "oauth_signature_method", "HMAC-SHA1",
410 "oauth_timestamp", (string)llGetUnixTime()];
411
412 if(token != "")
413 {
414 parameters += "oauth_token";
415 parameters += token;
416 }
417
418 parameters += additionalParams;
419
420 parameters = OAuthUrlEncodeList(parameters);
421 parameters = llListSort(parameters, 2, 1);
422
423 string sig = Sign(method, url, consumerSecret, tokenSecret, parameters);
424 parameters += "oauth_signature";
425 parameters += sig;
426
427 url = url + "?" + OAuthConcatenate(parameters);
428 //llOwnerSay(url);
429 return url;
430 }
431
432 string FindOAuthResponseValue(string name, list tokens)
433 {
434 //llOwnerSay("Looking for " + name + " in:" + llList2CSV(tokens));
435 integer index = llListFindList(tokens, [name]);
436 if(index != -1)
437 {
438 return llList2String(tokens, index + 1);
439 }
440 return "";
441 }
442
443 list TokenizeOAuthResponse(string response)
444 {
445 return llParseString2List(response, ["=", "&"], []);
446 }
447
448 ResetTimeout()
449 {
450 // Time out HTTP requests and input requests after a minute of inactivity.
452 }
453
454 Reset()
455 {
456 gAvatarKey = NULL_KEY;
457 gMessage = "";
458 gRequestTokenKey = NULL_KEY;
459 gRequestToken = "";
460 gRequestTokenSecret = "";
461 gAccessTokenKey = NULL_KEY;
462 gVerifier = "";
463 gRetries = 0;
465 }
466
467 RequestAccessToken()
468 {
469 list parameters = ["oauth_verifier", gVerifier];
470 string url = OAuthUrl("POST", "http://twitter.com/oauth/access_token",
471 gConsumerKey, gConsumerSecret, gRequestToken, gRequestTokenSecret, parameters);
472 ResetTimeout();
473 gAccessTokenKey = llHTTPRequest(url, [HTTP_METHOD, "POST"], "");
474 }
475
476 RequestRequestToken()
477 {
478 string url = OAuthUrl("GET", "http://twitter.com/oauth/request_token", gConsumerKey, gConsumerSecret, "", "",
479 ["oauth_callback", gAuthorizeUrl]);
480 ResetTimeout();
481 gRequestTokenKey = llHTTPRequest(url, [], "");
482 }
483
484 RequestTokens(key avatar, string message)
485 {
486 string accessToken = GetAccessToken(avatar);
487 string accessTokenSecret = GetAccessTokenSecret(avatar);
488
489 if(accessToken != "" && accessTokenSecret != "")
490 {
491 // Have access token, update immediately.
492 UpdateStatus(accessToken, accessTokenSecret, message);
493 }
494 else
495 {
496 if(gRequestTokenKey != NULL_KEY ||
497 gAccessTokenKey != NULL_KEY)
498 {
499 // Currently requesting access token, drop this request on the floor.
500 // TODO: babbage: queue request for later, handle paralell requests, or signal failure to caller...
501 llOwnerSay("OAuth request in progress, please wait.");
502 return;
503 }
504
505 // Access token unknown and no request in progress, request access token.
506 Reset();
507 gAvatarKey = avatar;
508 gMessage = message;
509 RequestRequestToken();
510 }
511 }
512
513 UpdateStatus(string accessToken, string accessTokenSecret, string message)
514 {
515 list parameters = ["status", message];
516 string url = OAuthUrl("POST", "http://twitter.com/statuses/update.xml",
517 gConsumerKey, gConsumerSecret, accessToken, accessTokenSecret, parameters);
518 llHTTPRequest(url, [HTTP_METHOD, "POST"], "");
519 }
520
521 default
522 {
524 {
526 Reset();
527 }
528
529 on_rez(integer param)
530 {
532 Reset();
533 }
534
535 changed(integer changes)
536 {
537 if((changes & CHANGED_REGION_START) != 0)
538 {
540 }
541 }
542
543 link_message(integer sender_num, integer num, string message, key avatar)
544 {
545 if(num == TWITTER_OAUTH_SET_CONSUMER_KEY)
546 {
547 gConsumerKey = message;
548 }
549 else if(num == TWITTER_OAUTH_SET_CONSUMER_SECRET)
550 {
551 gConsumerSecret = message;
552 }
553 else if(num == TWITTER_OAUTH_SET_MAX_RETRIES)
554 {
555 gMaxRetries = (integer) message;
556 }
557 else if(num == TWITTER_OAUTH_UPDATE_STATUS)
558 {
559 if(gConsumerKey == "")
560 {
561 llOwnerSay("Consumer key must be set before status update.");
562 return;
563 }
564 if(gConsumerSecret == "")
565 {
566 llOwnerSay("Consumer secret must be set before status update.");
567 return;
568 }
569 RequestTokens(avatar, message);
570 }
571 }
572
573 http_response(key id, integer status, list meta, string body)
574 {
575 //llOwnerSay("status:" + (string)status);
576 //llOwnerSay("body:" + body);
577
578 if(id == gRequestTokenKey)
579 {
580 if(status != 200)
581 {
582 if(gRetries++ < gMaxRetries)
583 {
584 llOwnerSay("Failed to obtain oauth request token, retrying...");
585 RequestRequestToken();
586 }
587 else
588 {
589 llOwnerSay("Failed to obtain oauth request token");
590 llOwnerSay("Status:" + (string)status);
591 llOwnerSay("Body:" + body);
592 Reset();
593 }
594 return;
595 }
596
597 gRetries = 0;
598 list responseTokens = TokenizeOAuthResponse(body);
599 gRequestToken = FindOAuthResponseValue("oauth_token", responseTokens);
600 gRequestTokenSecret = FindOAuthResponseValue("oauth_token_secret", responseTokens);
601
602 string url = "http://twitter.com/oauth/authorize?" +
603 OAuthConcatenate(["oauth_token", gRequestToken]);
604 ResetTimeout();
605 llLoadURL(gAvatarKey, "Please authorise Twitter access", url);
606
607 if(gAuthorizeUrl == "oob")
608 {
609 llListen(3, "", NULL_KEY, "");
610 llOwnerSay("Please chat PIN on channel 3 (eg \"/3 12345678\")");
611 }
612 }
613 else if(id == gAccessTokenKey)
614 {
615 if(status != 200)
616 {
617 if(gRetries++ < gMaxRetries)
618 {
619 llOwnerSay("Failed to obtain oauth access token, retrying...");
620 RequestAccessToken();
621 }
622 else
623 {
624 llOwnerSay("Failed to obtain oauth access token");
625 llOwnerSay("Status:" + (string)status);
626 llOwnerSay("Body:" + body);
627 Reset();
628 }
629 return;
630 }
631
632 gRetries = 0;
633 list responseTokens = TokenizeOAuthResponse(body);
634 string accessToken = FindOAuthResponseValue("oauth_token", responseTokens);
635 string accessTokenSecret = FindOAuthResponseValue("oauth_token_secret", responseTokens);
636 string screenName = FindOAuthResponseValue("screen_name", responseTokens);
637 SetAccessToken(gAvatarKey, accessToken, accessTokenSecret);
638 UpdateStatus(accessToken, accessTokenSecret, gMessage);
639 llLoadURL(gAvatarKey, "Show status update?", "http://twitter.com/" + screenName);
640 Reset();
641 }
642 else
643 {
644 // NOTE: babbage: status update always fail as http out cannot accept XML or JSON
645 // TODO: babbage: allow http out to accept XML or JSON, so we can actually check for errors here...
646 return;
647 }
648 }
649
650 listen(integer channel, string name, key id, string message)
651 {
652 if(id == gAvatarKey && channel == 3)
653 {
654 // PIN based authorization flow.
655 gVerifier = message;
656 RequestAccessToken();
657 }
658 }
659
660 http_request(key id, string method, string body)
661 {
662 if(method == "URL_REQUEST_GRANTED")
663 {
664 // NOTE: babbage: need trailing / path...
665 gAuthorizeUrl = body + "/";
666 }
667 else if(method == "URL_REQUEST_DENIED")
668 {
669 llOwnerSay("No URLs available, using PIN based flow.");
670 gAuthorizeUrl = "oob";
671 }
672 else if(method == "GET")
673 {
674 list responseTokens = TokenizeOAuthResponse(llGetHTTPHeader(id, "x-query-string"));
675 gVerifier = FindOAuthResponseValue("oauth_verifier", responseTokens);
676
677 RequestAccessToken();
678
679 // TODO: babbage: allow HTML response body, so we can show something more useful than a blank web page here...
680 llHTTPResponse(id, 200, "");
681 }
682 }
683
684 timer()
685 {
686 llOwnerSay("Request timeout, resetting...");
687 Reset();
688 }
689 }

Back to the Best Free Tools in Second Life and OpenSim.