The synchronization script used by Project Alexandria will periodically poll (set to 1s) a user-defined directory on the OpenSim server (in this case /home/opensim/books/
) for files. When a new file is found, it uses the OSSL function osMakeNotecard
to create a notecard from that file.
The path can be changed by modifying the line:
string DOCUMENT_PATH = "/home/opensim/books/";
and setting an absolute path to a top-level directory. The script appends the object description to that path (path-traversal unaware) and scans the resulting folder for files.
Following the video on the main Project Alexandria page, the bookcase is given the description My Documents
. The script below thus scans the path:
"/home/opensim/books/" + llGetObjectDesc();
which, since the description of the object is My Documents
, turns out to be:
/home/opensim/books/My Documents
Thus, the script will pick-up any file placed under /home/opensim/books/My Documents
and create a notecard with the contents of the file.
//c# /////////////////////////////////////////////////////////////////////////// // Copyright (C) Wizardry and Steamworks 2011 - License: GNU GPLv3 // // Please see: http://www.gnu.org/licenses/gpl.html for legal details, // // rights of fair usage, the disclaimer and warranty conditions. // /////////////////////////////////////////////////////////////////////////// string DOCUMENT_PATH = @"/home/opensim/books/"; string filesHash = ""; public void default_event_state_entry() { DOCUMENT_PATH += llGetObjectDesc(); llSetTimerEvent(5.0); } public void default_event_timer() { System.Collections.Generic.List<string> path = new System.Collections.Generic.List<string>(System.IO.Directory.GetFiles(DOCUMENT_PATH)); // If no documents are available, skip. if(path.Count == 0) return; string hash = CalculateMD5Hash(string.Join("", path.ToArray())); // If the last known MD5 hash is different from the newly computed hash, skip. if(hash == filesHash) return; // Save the hash since the file listing has changed. filesHash = hash; // Remove all notecards in inventory or skip if none available. LSL_Types.LSLInteger cards = llGetInventoryNumber(INVENTORY_NOTECARD)-1; if(cards == -1) goto Import; do { llRemoveInventory(llGetInventoryName(INVENTORY_NOTECARD, cards)); } while(--cards>-1); Import: foreach(string file in path) { string notecardName = System.IO.Path.GetFileName(file); // If notecard exists, skip. if(llGetInventoryType(notecardName) == INVENTORY_NOTECARD) continue; // Skip UNIX dot-files. if(llGetSubString(notecardName, 0, 0) == ".") continue; // Attempt to read file, skip if not possible. string data = ""; try { data = System.IO.File.ReadAllText(file); } catch(System.Exception) { // If file could not be read, for any reason, skip. continue; } // Create the notecard. osMakeNotecard(notecardName, (LSL_Types.LSLString) data); } } //http://blogs.msdn.com/b/csharpfaq/archive/2006/10/09/how-do-i-calculate-a-md5-hash-from-a-string_3f00_.aspx private string CalculateMD5Hash(string input) { System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input); byte[] hash = md5.ComputeHash(inputBytes); System.Text.StringBuilder sb = new System.Text.StringBuilder(); for (int i = 0; i < hash.Length; i++) { sb.Append(hash[i].ToString("X2")); } return sb.ToString(); }