An Engine Fit For My Proceeding

Twitterbox LSL

Code summary: 

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";

// Leave these alone.
integer gTime = 0;
integer gCode = 0;
string gScreenName = "";
integer gManual = FALSE;
list gRecent = [];
integer gShowMine = TRUE;
string gLastTweet = "";

// gNotify defines the type of notification
// 0 = none
// 1 = private sound
// 2 = full animation and public sound
integer gNotify = 2;

integer gBlock140 = TRUE;

//------------------------------------------------------------------

key twitter_send(string action, string subject)
{
   if (EMAIL == "" || PASS == "") {
      llOwnerSay("No email/password set - edit script and try again");
      return NULL_KEY;
   }
   else if (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/");
}


string notify_level()
{
    if (gNotify == 0) return "Quiet";
    else if (gNotify == 1) return "Private";
    else if (gNotify == 2) return "Public";
    return "** something illegal **";
}

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/");
}

twitterball()
{
    llStartAnimation("Twitter");
    llSleep(1.0);
    llRezObject("Twitterball", llGetPos() + <0.0, 0.0, 1.5>, ZERO_VECTOR, ZERO_ROTATION, 1);
}

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");
        }
    }

   changed(integer change)
   {
      if (change & CHANGED_OWNER) {
         llResetScript();
      }
   }

    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);
      }
      else if (msg == "List Feeds") {
          list_feeds();
      }
      else if (msg == "TestTwit") {
          llSleep(1.0);
          twitterball();
          }
      else if (msg == "Web") {
         llLoadURL(id, "Visit your own Twitter page", "http://twitter.com/" + gScreenName);
      }
      else if (msg == "Show Mine") {
          llOwnerSay("Showing your tweets");
          gShowMine = TRUE;
        }
        else if (msg == "Hide Mine") {
            llOwnerSay("Hiding your tweets");
            gShowMine = FALSE;
        }
      else if (msg == "Help") {
         about();
      }
      else if (msg == "Notify") {
          llDialog(llGetOwner(), "Please select an option for notifications - currently " + notify_level(), ["Quiet", "Private", "Public", "Cancel"], 282);
        }
        else if (msg == "Quiet") {
            gNotify = 0;
            llOwnerSay("No sound or animation notifications");
        }
        else if (msg == "Private") {
            gNotify = 1;
            llOwnerSay("Private sound only for notifications");
        }
        else if (msg == "Public") {
            gNotify = 2;
            llOwnerSay("Animations and public sound when twittering, private sound for new tweets");
        }
        else if (msg == "Recent") {
            list_recent();
        }
        else if (msg == "Repeat") {
             llOwnerSay("Repeating your last update...");
             twitter_send("update", gLastTweet);
        }
        else if (msg == "Allow >140") {
            llOwnerSay("Allowing posts over 140 characters");
            gBlock140 = FALSE;
        }
        else if (msg == "Block >140") {
            llOwnerSay("Blocking posts over 140 characters");
            gBlock140 = TRUE;
        }
      else if (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);
                } else if (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");
                }
            }
      }
   }
}

Mobify empowers marketers and developers to create amazing mobile web experiences. Tap to learn more

Mobify