• GeSHi library error: sites/all/modules/geshifilter/geshi is not a directory.
  • : preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /home/ordinal/ordinalmalaprop.com/engine/includes/unicode.inc on line 345.
  • : preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /home/ordinal/ordinalmalaprop.com/engine/includes/unicode.inc on line 345.
  • : preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead in /home/ordinal/ordinalmalaprop.com/engine/includes/unicode.inc on line 345.
  • 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.
  • strict warning: Non-static method view::load() should not be called statically in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/views.module on line 906.
  • strict warning: Declaration of views_handler_field_comment::init() should be compatible with views_handler_field::init(&$view, $options) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/modules/comment/views_handler_field_comment.inc on line 49.
  • strict warning: Declaration of views_handler_filter::options_validate() should be compatible with views_handler::options_validate($form, &$form_state) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/handlers/views_handler_filter.inc on line 607.
  • strict warning: Declaration of views_handler_filter::options_submit() should be compatible with views_handler::options_submit($form, &$form_state) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/handlers/views_handler_filter.inc on line 607.
  • strict warning: Declaration of views_handler_filter_node_status::operator_form() should be compatible with views_handler_filter::operator_form(&$form, &$form_state) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/modules/node/views_handler_filter_node_status.inc on line 13.
  • strict warning: Declaration of views_plugin_row::options_validate() should be compatible with views_plugin::options_validate(&$form, &$form_state) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/plugins/views_plugin_row.inc on line 134.
  • strict warning: Declaration of views_plugin_row::options_submit() should be compatible with views_plugin::options_submit(&$form, &$form_state) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/plugins/views_plugin_row.inc on line 134.
  • strict warning: Non-static method view::load() should not be called statically in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/views.module on line 906.
  • strict warning: Declaration of views_handler_argument::init() should be compatible with views_handler::init(&$view, $options) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/handlers/views_handler_argument.inc on line 744.
  • strict warning: Declaration of views_handler_filter_boolean_operator::value_validate() should be compatible with views_handler_filter::value_validate($form, &$form_state) in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/handlers/views_handler_filter_boolean_operator.inc on line 159.
  • strict warning: Non-static method view::load() should not be called statically in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/views.module on line 906.
  • strict warning: Non-static method view::load() should not be called statically in /home/ordinal/ordinalmalaprop.com/engine/sites/all/modules/views/views.module on line 906.

Mass distribution script

Code summary: 

Sends inventory contents to each named individual on a list, by trying to get their key from a series of databases. This would be so much easier if there was a name2key function. But there isn't.

To use this script: place it in a prim, along with some other items that you want to send to people, and a notecard called "Names" which has a list of avatar names to send items to, one per line without spaces before or after them. (Blank lines will be ignored; anything else, and the script will try to find the line as if it were a name, and fail, and tell you that it has failed.)

Then, touch to start sending. There will be a display of names left to check and estimated time remaining.

There is no way of determining whether an object has been successfully sent by script, or whether somebody was in busy mode (this is the usual culprit when people complain of not receiving an item - either that, or they did receive it but can't find it) or declined the item. My apologies.

// Mass distribution script // Ordinal Malaprop 2010-01-15 11:29 //..................................................................... // Sends inventory contents to each named individual on a list, by trying to get their key from a series of databases. This would be so much easier if there was a name2key function. But there isn't. // To use this script: place it in a prim, along with some other items that you want to send to people, and a notecard called "Names" which has a list of avatar names to send items to, one per line without spaces before or after them. (Blank lines will be ignored; anything else, and the script will try to find the line as if it were a name, and fail, and tell you that it has failed.) // Then, touch to start sending. There will be a display of names left to check and estimated time remaining. // There is no way of determining whether an object has been successfully sent by script, or whether somebody was in busy mode (this is the usual culprit when people complain of not receiving an item - either that, or they did receive it but can't find it) or declined the item. My apologies. // The original script can be found at http://ordinalmalaprop.com/engine/code/mass-distribution-script //--------------------------------------------------------------------- // LICENCE - Creative Commons "Attribution" 3.0 // http://creativecommons.org/licenses/by/3.0/ // Basically use it how you like, but if you do, please include a mention somewhere of me, and if possible a link to the original script. //--------------------------------------------------------------------- // Globals and constants // Configurable string NAME_NOTECARD = "Names"; // Change this if you want to call the notecard with your list of names on it something else. float TIMEOUT = 10.0; // There is no particular reason you would change this but you might wish to perhaps. integer TEST = FALSE; // change to TRUE to just run through the names in your notecard without sending anything // Not configurable - leave these alone key gQuery = NULL_KEY; string gAvName = ""; integer gLine = 0; integer gNumberOfLines = 0; list gItems = []; list gNotFound = []; integer gQuerySource = -1; //--------------------------------------------------------------------- // Functions // Looks for the next name on the list get_next_name() { llSetTimerEvent(TIMEOUT); if (gNumberOfLines == 0) { llSetText("Checking list size", <1.0, 1.0, 0.0>, 1.0); gQuery = llGetNumberOfNotecardLines(NAME_NOTECARD); } else { gQuery = llGetNotecardLine(NAME_NOTECARD, gLine++); update(); } } // Updates the prim display update() { integer line = gLine - 1; integer done = llRound(100 * line / gNumberOfLines); float x = (float)done / 100.0; llSetColor(, ALL_SIDES); llSetText((string)done + "% done (" + (string)line + "/" + (string)gNumberOfLines + ")\nRemaining time: " + time_left(line), <1.0, 1.0, 0.0>, 1.0); } string time_left(integer line) { if (gNumberOfLines == 0) return "unknown"; if (line == 0) { llResetTime(); return "unknown"; } float timePerLine = llGetTime() / line; return minutes_seconds(llRound(timePerLine * (float)(gNumberOfLines - line))); } string minutes_seconds(integer seconds) { if (seconds < 60) return (string)seconds + "s"; integer minutes = seconds / 60; seconds -= minutes * 60; string msg = (string)minutes + "m"; if (seconds > 0) msg += (string)seconds + "s"; return msg; } // This function sends queries to web databases to get keys from names. It moves through a series of different ones based on the current value of gQuerySource - if a query fails, it moves to the next one. I think that three different databases should eventually provide a reasonable result. Note that you can move the databases around according to your preference by cutting and pasting within the "if ... else" blocks. make_key_request(string name) { gAvName = name; llSetTimerEvent(TIMEOUT); gQuerySource++; string source = ""; if (gQuerySource == 0) { // modularsystems.sl name2key service source = "lawlinter.net"; gQuery = llHTTPRequest("http://lawlinter.net/secondlifeutility/name2key.php5?name=" + llEscapeURL(name), [HTTP_METHOD, "GET"], ""); } else if (gQuerySource == 1) { // visiontech - slow, but claims to be complete source = "VisionTech"; name = llDumpList2String(llParseString2List(name, [" "], []), "_"); gQuery = llHTTPRequest("http://vision-tech.org/name2key/search.php?name=" + name, [HTTP_METHOD, "GET"], ""); } else if (gQuerySource == 2) { // w-hat source = "w-hat"; gQuery = llHTTPRequest("http://w-hat.com/name2key?terse=1&name=" + llEscapeURL(name), [HTTP_METHOD, "GET"], ""); } if (source == "") { // failed, try a new one llOwnerSay("All sources failed to find a key for '" + gAvName + "', moving on."); gQuerySource = -1; gNotFound = (gNotFound = []) + gNotFound + [gAvName]; get_next_name(); } else if (gQuerySource > 0) { llOwnerSay("Trying " + source + " database..."); } } // Gets all of the items to be sent, and sets text based on what they are list get_item_list() { integer f = llGetInventoryNumber(INVENTORY_ALL) - 1; list items = []; string thisScript = llGetScriptName(); while (f >= 0) { string name = llGetInventoryName(INVENTORY_ALL, f); if (name != "" && name != thisScript && name != NAME_NOTECARD) { items = (items = []) + items + [name]; } f--; } if (llGetListLength(items) > 0) { string msg = "Sending:\n" + llDumpList2String(items, "\n"); if (TEST) msg = "[TEST] Not " + (msg = "") + msg; llSetText(msg, <0.0, 1.0, 0.0>, 1.0); } else { llSetText("No items found to send", <1.0, 0.0, 0.0>, 1.0); } return items; } // Sends the actual items to a particular avatar send_items(key id) { integer f = llGetListLength(gItems) - 1; llOwnerSay("Giving items..."); while (f >= 0) { string name = llList2String(gItems, f); if (TEST) llSleep(2.0); else llGiveInventory(id, name); f--; } llOwnerSay("Done."); } //--------------------------------------------------------------------- // Main // The default state is "not sending anything right at this moment". default { state_entry() { llSetText("", <0.0, 0.0, 0.0>, 1.0); llSetColor(<1.0, 1.0, 1.0>, ALL_SIDES); gItems = get_item_list(); llOwnerSay(llGetScriptName() + " ready, touch to start sending inventory."); } on_rez(integer p) { llResetScript(); } touch_start(integer n) { if (llGetListLength(gItems) == 0) { llOwnerSay("Nothing suitable in this item's inventory to give!"); } else if (llGetInventoryType(NAME_NOTECARD) == INVENTORY_NONE) { llOwnerSay("You need a notecard called '" + NAME_NOTECARD + "' in this item for it to send its contents to people."); } else { state sending; } } changed(integer change) { if (change & CHANGED_INVENTORY) llResetScript(); } } // In "sending" state, we are actually reading names, finding keys and sending things out. state sending { state_entry() { gNumberOfLines = 0; gLine = 0; gNotFound = []; gQuerySource = -1; llOwnerSay("Beginning send - take into inventory to stop this."); get_next_name(); } on_rez(integer p) { llResetScript(); } dataserver(key query, string data) { if (query != gQuery) return; if (data == EOF) { llOwnerSay("All notecard lines scanned."); state default; } else if (gNumberOfLines == 0) { gNumberOfLines = (integer)data; get_next_name(); } else if (data != "") { make_key_request(data); } else get_next_name(); } http_response(key query, integer status, list metadata, string data) { if (query != gQuery) return; llSetTimerEvent(0.0); key avKey = (key)data; if (llStringLength(data) == 36 && avKey != NULL_KEY) { llOwnerSay("Found key for '" + gAvName + "' : " + (string)avKey); gQuerySource = -1; send_items(avKey); } else { llOwnerSay("ERROR: Could not find avatar name '" + gAvName + "' in database."); make_key_request(gAvName); } get_next_name(); } timer() { llOwnerSay("ERROR: timed out looking for avatar name '" + gAvName + "'."); make_key_request(gAvName); } state_exit() { llOwnerSay("Names not found: " + llList2CSV(gNotFound)); float time = llGetTime(); llOwnerSay("Total time: " + minutes_seconds((integer)time) + " seconds (" + (string)(time / gNumberOfLines) + " seconds per line)."); } }
Ann Otoole's picture
23 Jan201022:06
Ann Otoole (not verified)

Why not set up a web service to scrape the UUID off secondlife.com? It is a simple query for Ordinal Malprop to obtain this in the resulting string: http://world.secondlife.com/resident/ad87bbec-81d2-4806-afe4-bedea19ee4fc

Ordinal Malaprop's picture
23 Jan201022:12
Ordinal Malaprop

I believe that that is what at least one of the web services I used does. It is true, though, that it would instructional to create such a system and then publish the necessary code, to illustrate how such things are written.

Tali's picture
26 Jan201004:50
Tali (not verified)

I have a script doing much the same, but as a last step, it does a reverse lookup in the dataserver, checking that the found key indeed matches the expected name in the Linden system. It is bordering on paranoid, but it ensures that there is no corruption or tampering with the 3rd party bases.