• GeSHi library error: sites/all/modules/geshifilter/geshi is not a directory.
  • GeSHi library error: sites/all/modules/geshifilter/geshi is not a directory.
  • GeSHi library error: sites/all/modules/geshifilter/geshi is not a directory.
  • GeSHi library error: sites/all/modules/geshifilter/geshi is not a directory.

Communication and messaging

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

Twitterbox control.php

Code summary: 

This is the latest version of the server PHP script for use with the Twitterbox, which does all of the hard work in contacting Twitter.

"Twitterbox", "X-Twitter-Client-URL" => "http://ordinalmalaprop.com/twitter/", "X-Twitter-Client-Version" => VERSION ); curl_setopt($c, CURLOPT_HTTPHEADER, $headers); // Now send the response off $response = @curl_exec($c); if (chop($response)) { // We got a non-blank response, so try to parse it as JSON $json = json_decode($response, TRUE); curl_close($c); // print_r($json); // Return the parsed data return $json; } else die("No response from Twitter!"); } // Fucntion to get the TinyURL of the first entry in an RSS feed function feedlink_get($url) { $c = curl_init(); curl_setopt($c, CURLOPT_URL, $url); curl_setopt($c, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($c, CURLOPT_HEADER, FALSE); curl_setopt($c, CURLOPT_TIMEOUT, 15); $feed_data = curl_exec($c); curl_close($c); if (!$feed_data) die("Failed to get stream at $url"); else { // Try RSS parsing if (strpos($feed_data, 'rss') !== FALSE && preg_match('/.+?\s*?(\S.+?\S)\s*?<\/link>/is', $feed_data, $matches)) { $feed_data = get_tinyurl($matches[1]); return $feed_data; } // Try Atom parsing else if (strpos($feed_data, '.+?/is', $feed_data, $matches)) { $feed_data = get_tinyurl($matches[1]); return $feed_data; } // Give up else { die("Failed to find new feed link at $url"); } } } // Function to get a tinyurl for something // We probably don't need to use curl here, but, you know, why not? function get_tinyurl($bigurl) { $c = curl_init(); curl_setopt($c, CURLOPT_URL, "http://tinyurl.com/api-create.php?url=$bigurl"); curl_setopt($c, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($c, CURLOPT_HEADER, FALSE); // Don't wait more than 10 seconds for a TinyURL curl_setopt($c, CURLOPT_CONNECTTIMEOUT, 10); $tinyurl = curl_exec($c); curl_close($c); // If we got a tinyurl, return it if ($tinyurl) return $tinyurl; // otherwise just return the original one - Twitter will probably be able to tinyurl it else return $bigurl; } //----------------------------------------------------------------------------- // Main code // Set timezone to be closest to SL time (no San_Francisco timezone code in PHP?) date_default_timezone_set("America/Los_Angeles"); header("Content-type: text/plain"); // Read POST input $post = file('php://input'); // If there isn't anything in the POST, don't do anything if (!$post) { die("go away"); } // Read in the information that was sent $user = urldecode(chop($post[0])); $pass = urldecode(chop($post[1])); $action = urldecode(chop($post[2])); $status = urldecode(chop($post[3])); // location to add slurl for, in the form simname/x/y/z/ $location = urldecode(chop($post[4])); // Text representation of location $loc_array = explode("/", $location); $loc_text = $loc_array[0]. " ". $loc_array[1]. ",". $loc_array[2]. ",". $loc_array[3]; // Keywords and RSS feeds to check and replace $feeds_raw = explode(",", urldecode(chop($post[5]))); $feeds = array(); $f = 0; do { $feeds[$feeds_raw[$f]] = $feeds_raw[$f+1]; $f += 2; } while ($f < sizeof($feeds_raw)); // Unix time of last check - don't return anything before this $since = urldecode(chop($post[6])); ob_flush(); flush(); // Allow for slight clock irregularities $now = time() - 5; // Now process the action requested // All of these request feedback from Twitter in JSON format, which is parsed by the above function. if ($action == "update") { if (strlen($status) > 0) { // "Insert current position" keyword $status = str_replace("SLPOS", $loc_text, $status); // Go through each feed keyword checking to see if it occurs foreach ($feeds as $feed_name => $feed_url) { // Do we have any keywords for that feed here? if (@strpos($status, $feed_name) !== FALSE) { // If so, get the tinyurl for the first element there $tinyurl = feedlink_get($feed_url); // and replace instances of that keyword with it $status = str_replace($feed_name, $tinyurl. " ", $status); ob_flush(); flush(); } } if (strpos($status, "SLURL") !== FALSE && $location) { $loc_array = explode("/", $location); $loc_text = $loc_array[0]. " ". $loc_array[1]. ",". $loc_array[2]. ",". $loc_array[3]; // SLurl page strips out all HTML in the msg - didn't know that... $slurl = "http://slurl.com/secondlife/". str_replace(" ", "%20", $location). "?x=200&y=260&title=". urlencode(gmdate("j M y @ H:i", time() - 28800). " SLT"). "&msg=". rawurlencode(htmlentities(str_replace("SLURL", $loc_text, $status))). "&img=http%3A//ordinalmalaprop.com/twitter/twitterbox-credit.jpg"; $tiny_slurl = get_tinyurl($slurl); $status = str_replace("SLURL", $tiny_slurl, $status); } ob_flush(); flush(); } $json = twitter_send('update', $user, $pass, "status=". rawurlencode($status)); // The update procedure // Check the time that the last update was posted at $created = strtotime($json["created_at"]); // If the time is before now, that means it's failed! // 2007-07-01 - this doesn't seem to work any more, assume it has succeeded // if ($created < $now) { // die("Date was w"); // } // Otherwise say "ok" and coincidentally update the screen name and ID if (sizeof($json, COUNT_RECURSIVE) <= 1) die("Twitter gave me bad output - " + print_r($json, TRUE)); else { echo "OK,". $json["user"]["id"]. ",". $json["user"]["screen_name"]. ",posted"; } } else if ($action == "get id" && ($json = twitter_send('update', $user, $pass, ""))) { // To just update the screen name and ID, send a blank update which will not be displayed // and read in the information. if (sizeof($json, COUNT_RECURSIVE) <= 1) die("Twitter gave me bad output - " + print_r($json, TRUE)); else echo "OK,". $json["user"]["id"]. ",". $json["user"]["screen_name"]; } else if ($action == "check" && ($json = twitter_send('friends_timeline', $user, $pass, ""))) { // Check recent tweets // Go through them and compile a list of the last few, up to an appropriate size limit to send back to LSL // 1500 bytes should work - longer than that and the header gets in the way // LSL doesn't like receiving any real quantity of data $length = 0; $entry = ""; $f = 0; // Sometimes, Twitter doesn't seem to produce proper output, even if it gets through if (sizeof($json, COUNT_RECURSIVE) <= 1) die("Twitter gave me bad output"); $max = sizeof($json); $tweets = array(); do { $length += strlen($entry); if ($entry != "") $tweets[] = $entry; // Format for each tweet: // // () // $unixtime = strtotime($json[$f]["created_at"]); $entry = $json[$f]["user"]["screen_name"]. "\n". $json[$f]["text"]. " (". date("j M H:i", $unixtime). " SLT)\n$unixtime"; ob_flush(); flush(); } while (++$f < $max && $length + strlen($entry) < 1500); // Put them in chronological order $tweets = array_reverse($tweets); // and output echo "OK\n". implode("\n", $tweets); } else echo "pardon?"; ?>

Semaphore - main script

Code summary: 

This is the main script to put in an attachment somewhere.

// Semaphore Animation Script // Ordinal Malaprop // 2007-09-15 // LICENCE // This script is licenced under a Creative Commons // Attribution-Noncommercial-Share Alike licence - see // http://creativecommons.org/licenses/by-nc-sa/3.0/ // for exact details.
Syndicate content