// // Copyright (C) 2000, 2001, 2002 Virtual Cowboys info@virtualcowboys.nl // // Author: Ruben Daniels // Version: 0.91 // Date: 29-08-2001 // Site: www.vcdn.org/Public/XMLRPC/ // // 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Object.prototype.toXMLRPC = function(){ var wo = this.valueOf(); if(wo.toXMLRPC == this.toXMLRPC){ retstr = ""; for(prop in this){ if(typeof wo[prop] != "function"){ retstr += "" + prop + "" + XMLRPC.getXML(wo[prop]) + ""; } } retstr += ""; return retstr; } else{ return wo.toXMLRPC(); } } String.prototype.toXMLRPC = function(){ // return "";//.replace(/" + this + ""; } else if(this == parseFloat(this)){ return "" + this + ""; } else{ return false.toXMLRPC(); } } Boolean.prototype.toXMLRPC = function(){ if(this) return "1"; else return "0"; } Date.prototype.toXMLRPC = function(){ //Could build in possibilities to express dates //in weeks or other iso8601 possibillities //hmmmm ???? //19980717T14:08:55 return "" + doYear(this.getUTCYear()) + doZero(this.getMonth()) + doZero(this.getUTCDate()) + "T" + doZero(this.getHours()) + ":" + doZero(this.getMinutes()) + ":" + doZero(this.getSeconds()) + ""; function doZero(nr) { nr = String("0" + nr); return nr.substr(nr.length-2, 2); } function doYear(year) { if(year > 9999 || year < 0) XMLRPC.handleError(new Error("Unsupported year: " + year)); year = String("0000" + year) return year.substr(year.length-4, 4); } } Array.prototype.toXMLRPC = function(){ var retstr = ""; for(var i=0;i"; } return retstr + ""; } function VirtualService(servername, oRPC){ this.version = '0.91'; this.URL = servername; this.multicall = false; this.autoroute = true; this.onerror = null; this.rpc = oRPC; this.receive = {}; this.purge = function(receive){ return this.rpc.purge(this, receive); } this.revert = function(){ this.rpc.revert(this); } this.add = function(name, alias, receive){ this.rpc.validateMethodName();if(this.rpc.stop){this.rpc.stop = false;return false} if(receive) this.receive[name] = receive; this[(alias || name)] = new Function('var args = new Array(), i;for(i=0;i mask/s * -------------------- * undefined -> 0/1 [default] * number -> 2 * boolean -> 4 * string -> 8 * function -> 16 * object -> 32 * -------------------- * Examples: * Want [String] only: (eqv. (typeof(vDunno) == 'string') ) * Soya.Common.typematch(unknown, 8) * Anything else than 'undefined' acceptable: * Soya.Common.typematch(unknown) * Want [Number], [Boolean] or [Function]: * Soya.Common.typematch(unknown, 2 + 4 + 16) * Want [Number] only: * Soya.Common.typematch(unknown, 2) **/ typematch : function (vDunno, nCase){ var nMask; switch(typeof(vDunno)){ case 'number' : nMask = 2; break; case 'boolean' : nMask = 4; break; case 'string' : nMask = 8; break; case 'function': nMask = 16; break; case 'object' : nMask = 32; break; default : nMask = 1; break; } return Boolean(nMask & (nCase || 62)); }, getNode : function(data, tree){ var nc = 0;//nodeCount //node = 1 if(data != null){ for(i=0;i 1){ tree.shift(); data = this.getNode(data, tree); } return data; } nc++ } } } return false; }, toObject : function(data){ var ret, i; switch(data.tagName){ case "string": var s="" //Mozilla has many textnodes with a size of 4096 chars each instead of one large one. //They all need to be concatenated. for(var j=0;j 0) return sEncoded; /* Use NN's built-in base64 decoder if available. This procedure is horribly slow running under NN4, so the NN built-in equivalent comes in very handy. :) */ else if(typeof(atob) != 'undefined') return atob(sEncoded); var nBits, i, sDecoded = ''; var base64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; sEncoded = sEncoded.replace(/\W|=/g, ''); for(i=0; i < sEncoded.length; i += 4){ nBits = (base64.indexOf(sEncoded.charAt(i)) & 0xff) << 18 | (base64.indexOf(sEncoded.charAt(i+1)) & 0xff) << 12 | (base64.indexOf(sEncoded.charAt(i+2)) & 0xff) << 6 | base64.indexOf(sEncoded.charAt(i+3)) & 0xff; sDecoded += String.fromCharCode( (nBits & 0xff0000) >> 16, (nBits & 0xff00) >> 8, nBits & 0xff); } // not sure if the following statement behaves as supposed under // all circumstances, but tests up til now says it does. return sDecoded.substring(0, sDecoded.length - ((sEncoded.charCodeAt(i - 2) == 61) ? 2 : (sEncoded.charCodeAt(i - 1) == 61 ? 1 : 0))); }, getObject : function(type, message){ if(type == "HTTP"){ if(isIE) obj = new ActiveXObject("microsoft.XMLHTTP"); else if(isNS) obj = new XMLHttpRequest(); } else if(type == "XMLDOM"){ if(isIE){ obj = new ActiveXObject("microsoft.XMLDOM"); obj.loadXML(message) }else if(isNS){ obj = new DOMParser(); obj = obj.parseFromString(message, "text/xml"); } } else{ this.handleError(new Error("Unknown Object")); } return obj; }, validateMethodName : function(name){ /*do Checking: The string may only contain identifier characters, upper and lower-case A-Z, the numeric characters, 0-9, underscore, dot, colon and slash. */ if(/^[A-Za-z0-9\._\/:]+$/.test(name)) return true else this.handleError(new Error("Incorrect method name")); }, getXML : function(obj){ if(typeof obj == "function"){ this.handleError(new Error("Cannot Parse functions")); }else if(obj == null || obj == undefined || (typeof obj == "number" && !isFinite(obj))) return false.toXMLRPC(); else return obj.toXMLRPC(); }, handleError : function(e){ if(!this.onerror || !this.onerror(e)){ //alert("An error has occured: " + e.message); throw e; } this.stop = true; this.lastError = e; }, cancel : function(id){ //You can only cancel a request when it was executed async (I think) if(!this.queue[id]) return false; this.queue[id][0].abort(); return true; }, send : function(serverAddress, functionName, args, receive, multicall, autoroute){ var id, http; //default is sync this.validateMethodName(); if(this.stop){this.stop = false; return false;} //setting up multicall multicall = (multicall != null) ? multicall : this.multicall; if(multicall){ if(!this.stack[serverAddress]) this.stack[serverAddress] = new Array(); this.stack[serverAddress].push({methodName : functionName, params : args}); return true; } //creating http object var http = this.getObject("HTTP"); //setting some things for async/sync transfers if(!receive || isNS){; async = false; } else{ async = true; /* The timer functionality is implemented instead of the onreadystatechange event because somehow the calling of this event crashed IE5.x */ id = this.queue.push([http, receive, null, new Date()])-1; this.queue[id][2] = new Function("var id='" + id + "';var dt = new Date(new Date().getTime() - XMLRPC.queue[id][3].getTime());diff = parseInt(dt.getSeconds()*1000 + dt.getMilliseconds());if(diff > XMLRPC.timeout){if(XMLRPC.ontimeout) XMLRPC.ontimeout(); clearInterval(XMLRPC.timers[id]);XMLRPC.cancel(id);return};if(XMLRPC.queue[id][0].readyState == 4){XMLRPC.queue[id][0].onreadystatechange = function(){};XMLRPC.receive(id);clearInterval(XMLRPC.timers[id])}"); this.timers[id] = setInterval("XMLRPC.queue[" + id + "][2]()", 20); } //setting up the routing autoroute = (autoroute || this.autoroute); //'active' is only set when direct sending the message has failed var srv = (autoroute == "active") ? this.routeServer : serverAddress; try{ http.open('POST', srv, async); http.setRequestHeader("User-Agent", "vcXMLRPC v0.91 (" + navigator.userAgent + ")"); http.setRequestHeader("Host", srv.replace(/^https?:\/{2}([:\[\]\-\w\.]+)\/?.*/, '$1')); http.setRequestHeader("Content-type", "text/xml"); if(autoroute == "active"){ http.setRequestHeader("X-Proxy-Request", serverAddress); http.setRequestHeader("X-Compress-Response", "gzip"); } } catch(e){ if(autoroute == true){ //Access has been denied, Routing call. autoroute = "active"; if(id){ delete this.queue[id]; clearInterval(this.timers[id]); } return this.send(serverAddress, functionName, args, receive, multicall, autoroute); } //Routing didn't work either..Throwing error this.handleError(new Error("Could not sent XMLRPC Message (Reason: Access Denied on client)")); if(this.stop){this.stop = false;return false} } //Construct the message var message = '' + functionName + ''; for(i=0;i'; } message += ''; var xmldom = this.getObject('XMLDOM', message); if(self.DEBUG) alert(message); try{ //send message http.send(xmldom); } catch(e){ //Most likely the message timed out(what happend to your internet connection?) this.handleError(new Error("XMLRPC Message not Sent(Reason: " + e.message + ")")); if(this.stop){this.stop = false;return false} } if(!async && receive) return [autoroute, receive(this.processResult(http))]; else if(receive) return [autoroute, id]; else return [autoroute, this.processResult(http)]; }, receive : function(id){ //Function for handling async transfers.. if(this.queue[id]){ var data = this.processResult(this.queue[id][0]); this.queue[id][1](data); delete this.queue[id]; } else{ this.handleError(new Error("Error while processing queue")); } }, processResult : function(http){ if(self.DEBUG) alert(http.responseText); if(http.status == 200){ //getIncoming message dom = http.responseXML; if(dom){ var rpcErr, main; //Check for XMLRPC Errors rpcErr = dom.getElementsByTagName("fault"); if(rpcErr.length > 0){ rpcErr = this.toObject(rpcErr[0].firstChild); this.handleError(new Error(rpcErr.faultCode, rpcErr.faultString)); return false } //handle method result main = dom.getElementsByTagName("param"); if(main.length == 0) this.handleError(new Error("Malformed XMLRPC Message")); data = this.toObject(this.getNode(main[0], [0])); //handle receiving if(this.onreceive) this.onreceive(data); return data; } else{ this.handleError(new Error("Malformed XMLRPC Message")); } } else{ this.handleError(new Error("HTTP Exception: (" + http.status + ") " + http.statusText + "\n\n" + http.responseText)); } } } //Smell something ver = navigator.appVersion; app = navigator.appName; isNS = Boolean(navigator.productSub) //moz_can_do_http = (parseInt(navigator.productSub) >= 20010308) isIE = (ver.indexOf("MSIE 5") != -1 || ver.indexOf("MSIE 6") != -1) ? 1 : 0; isIE55 = (ver.indexOf("MSIE 5.5") != -1) ? 1 : 0; isOTHER = (!isNS && !isIE) ? 1 : 0;