Monday, November 08, 2010 at 12:06 AM.
system.verbs.builtins.tcp.im.rpi.server
on server (xmltext, adrhandlerstable=@user.im.rpiHandlers, driverName=nil, screenName=nil) { <<Changes <<9/19/02; 3:32:46 PM by AR <<Accept driverName and screenName as optional parameters, put them into a local table and use that table as context when calling #security scripts and the RPI handler. <<5/24/02; 1:20:02 PM by JB <<Modified to use base64 encoding. <<Some drivers can't guarentee what happens to whitespace. For human-targetted messages, we can tolerate this, but "A File.txt" is not the same as "A File.txt" (two spaces)... for RPI purposes, we must be exact. Solution: base64-encode the payloads. <<This no longer follows the exact XML-RPC encoding spec. The following change to the spec as of May 24, 2002 are hereby made: <<The payload of all <string>'s is modified to be base64 encoded. All other scalars are left as-is. This applies *before* all rules about XML-RPC encoding as specified in the XML-RPC spec and XML spec, which is to say, it renders those rules irrelevent. Thus, when sending a string parameter of "<", what goes out to the driver will be base64.encode("<", infinity), which does not need to be further XML-encoded. This *only* applies to string parameters. <<5/15/02; 9:08:46 PM by JB <<Modified to only invoke the targetted script, and not return any messages to the sender. <<5/8/02; 3:09:56 PM by DW <<Cribbed from betty.rpc.server. <<local (xmlResponse = "", indentlevel = 1) <<on add (s) <<xmlResponse = xmlResponse + (string.filledString ("\t", indentlevel) + s + "\r\n"); << <<on rpcFault (errorstring, errornum) <<add ("<?xml version=\"1.0\"?>") <<add ("<methodResponse>"); indentlevel++ <<add ("<fault>"); indentlevel++ <<add ("<value>"); indentlevel++ <<add ("<struct>"); indentlevel++ << <<add ("<member>"); indentlevel++ <<add ("<name>faultCode</name>") <<add ("<value>"); indentlevel++ <<add ("<int>" + errornum + "</int>") <<add ("</value>"); indentlevel-- <<add ("</member>"); indentlevel-- << <<bundle //AR 6/14/1999: make sure errorstring is encoded <<errorstring = string.replaceAll (errorstring, "&", "&") <<errorstring = string.replaceAll (errorstring, "<", "<") << <<add ("<member>"); indentlevel++ <<add ("<name>faultString</name>") <<add ("<value>"); indentlevel++ <<add ("<string>" + errorstring + "</string>") <<add ("</value>"); indentlevel-- <<add ("</member>"); indentlevel-- << <<add ("</struct>"); indentlevel-- <<add ("</value>"); indentlevel++ <<add ("</fault>"); indentlevel-- <<add ("</methodResponse>"); indentlevel-- local (xtable); bundle { //compile xmltext into xtable try { xml.compile (xmlText, @xtable)} else { <<return (rpcFault (tryError, betty.rpc.errorcodes.xmlFormatError)) return}}; local (procedureName, paramlist); bundle { //set the procedure name and fill the params list by walking the XML structure try { on decodeStruct ( structAdr ) { // takes the address of a struct and recurses on it, base64-decoding all strings for element in structAdr { if typeOf ( element^ ) == tableType { decodeStruct(element)}; if typeOf ( element^ ) == stringType { element^ = base64.decode(element^)}}}; paramlist = {}; local (adrcall = xml.getAddress (@xtable, "methodCall")); procedureName = xml.getValue (adrcall, "methodName"); local (adrparams, flParams = true); try { //if there's no <params> element, getting its address will fail adrparams = xml.getAddress (adrcall, "params")} else { //no params flParams = false}; if flParams { local (adrparamlist = xml.getAddressList (adrparams, "param")); local (param, name, adrvalue, val); for param in adrparamlist { adrvalue = xml.getAddress (param, "value"); if typeof (adrvalue^) == tabletype { xml.coercions.structToFrontierValue (@adrvalue^ [1], @val); decodeStruct(@val)} // JB 5/24/02: Handle base64 decoding of strings else { if typeOf ( adrvalue^ ) == stringType { table.assign (@val, base64.decode(adrvalue^))} // JB 5/24/02 else { table.assign (@val, adrvalue^)}}; <<table.assign (@val, adrvalue^) //AR 6/14/1999 // orignal else clause paramlist = paramlist + {val}}}} else { <<return (rpcFault (tryError, betty.rpc.errorcodes.illegalCallStructureError)) return}}; local (contextTable); bundle { //initialize context table new (tableType, @contextTable); contextTable.driverName = driverName; contextTable.screenName = screenName}; bundle { //call the script local (nomad, adrscript, securitylist = {}); try { //locate the script local (s = procedureName, name); nomad = adrhandlerstable; loop { if typeOf (nomad^) == tabletype { local (adr = @nomad^.["#security"]); if defined (adr^) { securitylist = securitylist + {adr}}}; if sizeof (s) == 0 { break}; name = string.nthField (s, '.', 1); nomad = @nomad^.[name]; if typeof (nomad^) == addresstype { nomad = nomad^}; s = string.delete (s, 1, sizeof (name) + 1)}; adrscript = nomad} else { <<return (rpcFault (tryError, betty.rpc.errorcodes.scriptAddressError)) return}; try { //check in with the #security scripts local (adr); for adr in securitylist { callScript (string (adr), {}, @contextTable)}} else { <<return (rpcFault (tryError, betty.rpc.errorcodes.securityFault)) return}; <<local (scriptResponse) try { //call the script callScript (string (adrscript), paramlist, @contextTable)} <<scriptResponse = callScript (string (adrscript), paramlist) else { <<return (rpcFault (tryError, betty.rpc.errorcodes.scriptError)) return}; }; <<local (encodedString) <<try //encode the response <<encodedString = xml.coercions.frontierValueToTaggedText (@scriptResponse, 1) <<else <<return (rpcFault (tryError, betty.rpc.errorcodes.encodingFailure)) << <<try //add the encoded string to the returned XML text <<add ("<?xml version=\"1.0\"?>") <<add ("<methodResponse>"); indentlevel++ <<add ("<params>"); indentlevel++ <<add ("<param>"); indentlevel++ <<add ("<value>" + encodedString + "</value>") <<add ("</param>"); indentlevel-- <<add ("</params>"); indentlevel-- <<add ("</methodResponse>"); indentlevel-- <<else <<return (rpcFault (tryError, betty.rpc.errorcodes.addReturnedValueError)) <<return (xmlResponse) return}; bundle { //test code server (string (workspace.rpcCall))}
This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.