This is the LSL code for the latest version of the Twitterbox itself.
// Twitterbox v0.5 // Post to Twitter and receive updates from within SL
// Ordinal Malaprop // 2007-02-26 // Last updated 2007-05-12 // Free for distribution and use, but if you use it in something else // I would like at least a mention.
// Full instructions and the latest version are always at: // http://ordinalmalaprop.com/twitter/
//------------------------------------------------------------------ // Modifications from 0.3: // - only works when attached to prevent boxes on the floor spamming you // - keeps list of 10 most recent tweets, menu item added for this // - option to show or hide your own tweets, showing by default // - immediately checks for new tweets on startup // - option to repeat the last tweet you made, useful for failures // - checks for updates (separate script)
// Changes from 0.4: // - option to block posts over 140 characters
//------------------------------------------------------------------ // Edit these to your own specifications // The email address you signed up to Twitter with
string EMAIL ="ordinal.malaprop@fastmail.fm"; // Your Twitter password
string PASS ="h8gtied"; // Your public RSS feeds (leave blank if you don't have any or you don't know what this means) list FEEDS =[ "FLICKR","http://api.flickr.com/services/feeds/photos_public.gne?id=25972087@N00&format=rss_200", "VIMEO","http://www.vimeo.com/user:ordinal/clips/rss", "BLOG","http://feeds.feedburner.com/engine-proceeding" ];
// Seconds between checks, change if desired
float CHECK_INTERVAL =120.0;
// This is the URL of the intermediary script. Don't change it unless // you are using an intermediary of your own.
string TWITTERPING ="http://ordinalmalaprop.com/twitter/control-0.4.php";
key twitter_send(string action, string subject) { if(EMAIL ==""|| PASS ==""){
llOwnerSay("No email/password set - edit script and try again"); return NULL_KEY; } elseif(gBlock140 && llStringLength(subject)>140){
llOwnerSay("Lawks! Your post was over 140 characters and has been blocked - please try again or touch me to turn this option off. Your post was:");
llOwnerSay(subject); return NULL_KEY; } else{
vector pos= llGetPos(); return llHTTPRequest(TWITTERPING, [HTTP_METHOD,"POST"],
EMAIL +"\n"+ PASS +"\n"+ action +"\n"+ subject +"\n"+ llGetRegionName()+"/"+(string)llRound(pos.x)+"/"+(string)llRound(pos.y)+"/"+(string)llRound(pos.z)+"/\n"+ llDumpList2String(FEEDS,",")); } }
menu() { list buttons =["Check Now","Web","List Feeds", "Recent","Repeat","Notify","Help"];
string text ="Current email: "+ EMAIL +"\n"; if(gShowMine){
text +="Showing your own tweets.\n";
buttons =["Hide Mine"]+ buttons; } else{
text +="Hiding your own tweets.\n";
buttons =["Show Mine"]+ buttons; } if(gBlock140){
text +="Blocking posts > 140 chars\n";
buttons =["Allow >140"]+ buttons; } else{
text +="Allowing posts > 140 chars\n";
buttons =["Block >140"]+ buttons; } if(gLastTweet !="") text +="Your last tweet: '"+ gLastTweet +"'\n";
llDialog(llGetOwner(), text +"\nPlease select an option:", buttons,282); }
list_feeds() {
integer feeds = llGetListLength(FEEDS); if(feeds ==0){
llOwnerSay("You have no feed keywords defined at the moment."); }else{
llOwnerSay("Your current feed keywords are...");
integer f =0; do{
llOwnerSay(llList2String(FEEDS, f)+" - "+ llList2String(FEEDS, f +1));
f +=2; }while(f < feeds); }
llOwnerSay("Edit the script to add or remove feed keywords - for more information see http://ordinalmalaprop.com/twitter/"); }
help() { if(EMAIL ==""|| PASS ==""){
llOwnerSay( "BEWARE! You have not configured an `email and password! "+"Open the object, open the TwitterBox script, and fill in "+"the variables at the top."); }
llOwnerSay( "To send a tweet, say '/282 <text>', or touch the TwitterBox "+"HUD for more options."); }
about() {
llOwnerSay("A simple SL client for Twitter - http://twitter.com/ "+"- by Ordinal Malaprop");
llOwnerSay( "TwitterBox will automatically check for new tweets from your "+ "friends every minute, or when you tell it to manually from "+ "the menu, obtainable by touching the HUD.");
llOwnerSay( "To use, you need to have registered with Twitter, and edited "+"the script to include your email address and password.");
llOwnerSay( "For more information or the latest version, visit "+ "http://ordinalmalaprop.com/twitter/"); }
startup() { // Get screen name again whenever it is attached, // as this may change
twitter_send("get id",""); // Check for new updates immediately
twitter_send("check",""); // Also display the help message
help();
list_feeds();
llRequestPermissions(llGetOwner(), PERMISSION_TRIGGER_ANIMATION);
llSetTimerEvent(CHECK_INTERVAL); }
startup_check() { if(llGetAttached()) startup(); else llOwnerSay("I must be attached to operate - please wear me"); }
list push(string tweet,list tweetlist) {
tweetlist = tweetlist +[tweet]; if(llGetListLength(tweetlist)>8){ // remove first element
tweetlist = llDeleteSubList(tweetlist,0,0); } return tweetlist; }
list_recent() {
llOwnerSay("Recent tweets received:"); if(gRecent ==[]){
llOwnerSay("None received yet"); }
integer f =0;
integer n = llGetListLength(gRecent); do{
llOwnerSay(llList2String(gRecent, f)); }while(++f < n); }
default {
state_entry() {
llOwnerSay("Initialising..."); // At the start... // reset the clock to now // gTime = llGetUnixTime(); // and also start listening for commands
llListen(282,"", llGetOwner(),""); // and start everything up if attached
startup_check(); }
on_rez(integer p) { if(llGetAttached()==0){
llOwnerSay("I must be attached to operate - please wear me"); } }
attach(key id) { // Turn off check when not attached if(id == NULL_KEY){
llSetTimerEvent(0.0);
llOwnerSay("Detached - regular check has been cancelled"); }else{
startup(); } }
timer() {
twitter_send("check",""); }
touch_start(integer n) { // On owner touch, launch a control menu if(llDetectedKey(0)!= llGetOwner())return;
menu(); }
listen(integer c, string name,key id, string msg) { if(msg =="Check Now"){
llOwnerSay("Checking latest entries...");
gManual =TRUE;
twitter_send("check","");
llSetTimerEvent(CHECK_INTERVAL); } elseif(msg =="List Feeds"){
list_feeds(); } elseif(msg =="TestTwit"){
llSleep(1.0);
twitterball(); } elseif(msg =="Web"){
llLoadURL(id,"Visit your own Twitter page","http://twitter.com/"+ gScreenName); } elseif(msg =="Show Mine"){
llOwnerSay("Showing your tweets");
gShowMine =TRUE; } elseif(msg =="Hide Mine"){
llOwnerSay("Hiding your tweets");
gShowMine =FALSE; } elseif(msg =="Help"){
about(); } elseif(msg =="Notify"){
llDialog(llGetOwner(),"Please select an option for notifications - currently "+ notify_level(),["Quiet","Private","Public","Cancel"],282); } elseif(msg =="Quiet"){
gNotify =0;
llOwnerSay("No sound or animation notifications"); } elseif(msg =="Private"){
gNotify =1;
llOwnerSay("Private sound only for notifications"); } elseif(msg =="Public"){
gNotify =2;
llOwnerSay("Animations and public sound when twittering, private sound for new tweets"); } elseif(msg =="Recent"){
list_recent(); } elseif(msg =="Repeat"){
llOwnerSay("Repeating your last update...");
twitter_send("update", gLastTweet); } elseif(msg =="Allow >140"){
llOwnerSay("Allowing posts over 140 characters");
gBlock140 =FALSE; } elseif(msg =="Block >140"){
llOwnerSay("Blocking posts over 140 characters");
gBlock140 =TRUE; } elseif(msg !="Cancel"){
llOwnerSay("Twittering...");
gLastTweet = msg;
twitter_send("update", msg); } }
http_response(key id, integer status,list metadata, string body) { if(llGetSubString(body,0,1)=="OK"){ // A success list lines = llParseString2List(body,["\n"],[]);
string firstLine = llList2String(lines,0); if(llGetListLength(lines)==1){ // A successful update, or an ID check list bits = llParseString2List(firstLine,[","],[]);
gCode = llList2Integer(bits,1);
gScreenName = llList2String(bits,2); if(llList2String(bits,3)=="posted"){
llOwnerSay("Successfully Twittered!"); if(gNotify ==1){
llPlaySound("c923f3d9-83a6-99dc-9b7d-bbcdb3c30789",1.0); }elseif(gNotify ==2){
twitterball(); } } } else{
integer f =1;
integer maxTime = gTime;
string tweet =""; do{
string user = llList2String(lines, f);
integer time= llList2Integer(lines, f +2); // llOwnerSay("gTime = " + (string)gTime); // llOwnerSay(user + " @ " + (string)time); if((gShowMine || user != gScreenName)&&time> gTime){ if(maxTime == gTime){ // First new tweet, play sound if(gNotify !=0){
llPlaySound("c923f3d9-83a6-99dc-9b7d-bbcdb3c30789",1.0); } }
tweet = llList2String(lines, f)+": "+ llList2String(lines, f +1);
llOwnerSay(tweet);
gRecent = push(tweet, gRecent);
maxTime =time; }
f +=3; }while(f < llGetListLength(lines)); if(maxTime == gTime){ if(gManual){
llOwnerSay("No new entries");
gManual =FALSE; } }else{
gTime = maxTime; } } }else{ if(body ==""){ // SL sends back a blank entry if it can't get in touch at all
body ="Could not contact intermediary server "+ TWITTERPING; } else{ if(status ==200){ // Intermediary server worked okay
llOwnerSay("I received an error - '"+ body +"'"); }else{ // Something else went wrong, don't bother the user with the exact details // If they are techie enough to know what the details mean, they can edit // this script so that it tells them :)
llOwnerSay("I received an error with code "+(string)status +" - please try again in a bit"); } } } } }