// StatusMonitor // Monitors system status via intercepting link message method calls, // and displays the proper status messages. // Copyright (C) 2005-2006 Francisco V. Saldana // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // Francisco V. Saldana can be contacted using his email account // username: dressedinblue, at domain: gmail.com // and in Second Life by IMming Christopher Omega // ====================== XMLRPC request constants: ====================== \\ // Sent by the client to the server when the server polls // and the client has no data to send. integer NO_REQUESTS = 5000; // Sent by the server to the client when a poll occurs. integer SERVER_POLL = 6000; // Sent by client to server requesting that the server stop polling. integer STOP_POLLING = 6001; // Sent by server to client that tells client that the RPC string contains multiple command seperated // by COMMAND_SEPERATOR. integer MULTI_COMMAND = 6002; // Sent by server to client requesting that the client restart. integer TERMINAL_RESET = 6003; // Sent by the client to the server (or external entity) requesting a // piece of content: integer GET_CATEGORY = 7001; // String value: catagory requested integer GET_NOTECARD = 7002; // String value: Notecard name requested. integer GET_PREV = 7003; // String value: "" integer GET_NEXT = 7004; // String value: "" integer GET_KEYWORD_SEARCH = 7005; // String value: Keyword requested. // Sent by the server to the client, between MENU_BEGIN and MENU_END // requesting that it display text. integer SET_CATEGORY = 8001; // String value: Catagory name to display. integer SET_NOTECARD = 8002; // String value: Notecard name to display. integer SET_PREV = 8003; // String value ignored integer SET_NEXT = 8004; // String value ignored. integer SET_KEYWORD_SEARCH = 8005; // String value ignored. integer SET_TEXT = 8006; // String value: any text. // Sent by the server to the client specifying the start // and end of a menu. integer MENU_BEGIN = 9001; // String value: Menu title integer MENU_END = 9002; // ====================== /XMLRPC request constants ====================== \\ // For use with the MULTI_COMMAND RPC integer. string COMMAND_SEPERATOR = "]^["; // ========== For method invocation ========== string randomStr(string chars, integer len) { integer numChars = llStringLength(chars); string ret; integer i; for (i = 0; i < len; i++) { integer randIndex = llFloor(llFrand(numChars)); ret += llGetSubString(chars, randIndex, randIndex); } return ret; } string SEPERATOR_CHARS = "`~!@#$%^&*()-_+[]{}\|'\";/?.>,<"; integer SEPERATOR_LEN = 3; string dumpList2String(list src) { // Generate a seperator not present in any of the // elements in the list. string chars = (string) src; // Squashes all elements together. string seperator; do { seperator = randomStr(SEPERATOR_CHARS, SEPERATOR_LEN); } while (llSubStringIndex(chars, seperator) != -1); return seperator + llDumpList2String(src, seperator); } list parseStringKeepNulls(string src) { // The seperator should be the first SEPERATOR_LEN // characters in the string. return llParseStringKeepNulls(llDeleteSubString(src, 0, SEPERATOR_LEN - 1), [llGetSubString(src, 0, SEPERATOR_LEN - 1)], []); } callMethod(integer callId, string methodName, list parameters) { llMessageLinked(LINK_THIS, callId, dumpList2String(parameters), methodName); } returnValue(string methodName, integer methodIdentifyer, list value) { llMessageLinked(LINK_THIS, methodIdentifyer, dumpList2String(value), methodName + "_ret"); } // ============================================= string lastMessage = ""; trigger_displayStatusMessage(string msg) { if (msg != lastMessage) { callMethod(0, "displayStatusMessage", [msg]); lastMessage = msg; } } trigger_pong(string moduleName) { callMethod(0, "pong", [moduleName]); } string idleString = ""; string this; default { state_entry() { this = llGetScriptName(); } link_message(integer sender, integer num, string parameters, key methodName) { if (methodName == "sendRpcData") { trigger_displayStatusMessage("Sent data to server, waiting for reply..."); } else if (methodName == "receivedRpcData") { list paramList = parseStringKeepNulls(parameters); // Method signature: // receivedRpcData(integer iData, string sData) integer iData = (integer) llList2String(paramList, 0); string sData = llList2String(paramList, 1); if (iData == MENU_END) { trigger_displayStatusMessage("Data received, displaying..."); idleString = "Display complete."; state waitingForIdle; } else if (iData == MULTI_COMMAND) { list parsedCommands = llParseString2List(sData, [COMMAND_SEPERATOR], []); if (llListFindList(parsedCommands, [(string) MENU_END]) != -1) { trigger_displayStatusMessage("Data received, displaying..."); idleString = "Display complete."; state waitingForIdle; } } else { trigger_displayStatusMessage("Recieving data..."); } } else if (methodName == "menuScrollUp" || methodName == "menuScrollDown") { trigger_displayStatusMessage("Scrolling..."); idleString = "Scroll complete."; state waitingForIdle; } else if (methodName == "ping") { list paramList = parseStringKeepNulls(parameters); // Method signature: // ping(string moduleName) string moduleName = llList2String(paramList, 0); if (moduleName == this) trigger_pong(this); } } } state waitingForIdle { state_entry() { llSetTimerEvent(2); } link_message(integer sender, integer num, string parameters, key methodName) { llSetTimerEvent(2); } timer() { if (idleString != "") trigger_displayStatusMessage(idleString); llSetTimerEvent(0); state default; } }