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.