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.