1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
-- Prosody IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--
local pairs = pairs;
local type = type;
local error = error;
local t_concat = table.concat;
local t_insert = table.insert;
local tostring = tostring;
local tonumber = tonumber;
local select = select;
local st = require "util.stanza";
module "xmlrpc"
local _lua_to_xmlrpc;
local map = {
table=function(stanza, object)
stanza:tag("struct");
for name, value in pairs(object) do
stanza:tag("member");
stanza:tag("name"):text(tostring(name)):up();
stanza:tag("value");
_lua_to_xmlrpc(stanza, value);
stanza:up();
stanza:up();
end
stanza:up();
end;
boolean=function(stanza, object)
stanza:tag("boolean"):text(object and "1" or "0"):up();
end;
string=function(stanza, object)
stanza:tag("string"):text(object):up();
end;
number=function(stanza, object)
stanza:tag("int"):text(tostring(object)):up();
end;
["nil"]=function(stanza, object) -- nil extension
stanza:tag("nil"):up();
end;
};
_lua_to_xmlrpc = function(stanza, object)
local h = map[type(object)];
if h then
h(stanza, object);
else
error("Type not supported by XML-RPC: " .. type(object));
end
end
function create_response(object)
local stanza = st.stanza("methodResponse"):tag("params"):tag("param"):tag("value");
_lua_to_xmlrpc(stanza, object);
stanza:up():up():up();
return stanza;
end
function create_error_response(faultCode, faultString)
local stanza = st.stanza("methodResponse"):tag("fault"):tag("value");
_lua_to_xmlrpc(stanza, {faultCode=faultCode, faultString=faultString});
stanza:up():up();
return stanza;
end
function create_request(method_name, ...)
local stanza = st.stanza("methodCall")
:tag("methodName"):text(method_name):up()
:tag("params");
for i=1,select('#', ...) do
stanza:tag("param"):tag("value");
_lua_to_xmlrpc(stanza, select(i, ...));
stanza:up():up();
end
stanza:up():up():up();
return stanza;
end
local _xmlrpc_to_lua;
local int_parse = function(stanza)
if #stanza.tags ~= 0 or #stanza == 0 then error("<"..stanza.name.."> must have a single text child"); end
local n = tonumber(t_concat(stanza));
if n then return n; end
error("Failed to parse content of <"..stanza.name..">");
end
local rmap = {
methodCall=function(stanza)
if #stanza.tags ~= 2 then error("<methodCall> must have exactly two subtags"); end -- FIXME <params> is optional
if stanza.tags[1].name ~= "methodName" then error("First <methodCall> child tag must be <methodName>") end
if stanza.tags[2].name ~= "params" then error("Second <methodCall> child tag must be <params>") end
return _xmlrpc_to_lua(stanza.tags[1]), _xmlrpc_to_lua(stanza.tags[2]);
end;
methodName=function(stanza)
if #stanza.tags ~= 0 then error("<methodName> must not have any subtags"); end
if #stanza == 0 then error("<methodName> must have text content"); end
return t_concat(stanza);
end;
params=function(stanza)
local t = {};
for _, child in pairs(stanza.tags) do
if child.name ~= "param" then error("<params> can only have <param> children"); end;
t_insert(t, _xmlrpc_to_lua(child));
end
return t;
end;
param=function(stanza)
if not(#stanza.tags == 1 and stanza.tags[1].name == "value") then error("<param> must have exactly one <value> child"); end
return _xmlrpc_to_lua(stanza.tags[1]);
end;
value=function(stanza)
if #stanza.tags == 0 then return t_concat(stanza); end
if #stanza.tags ~= 1 then error("<value> must have a single child"); end
return _xmlrpc_to_lua(stanza.tags[1]);
end;
int=int_parse;
i4=int_parse;
double=int_parse;
boolean=function(stanza)
if #stanza.tags ~= 0 or #stanza == 0 then error("<boolean> must have a single text child"); end
local b = t_concat(stanza);
if b ~= "1" and b ~= "0" then error("Failed to parse content of <boolean>"); end
return b == "1" and true or false;
end;
string=function(stanza)
if #stanza.tags ~= 0 then error("<string> must have a single text child"); end
return t_concat(stanza);
end;
array=function(stanza)
if #stanza.tags ~= 1 then error("<array> must have a single <data> child"); end
return _xmlrpc_to_lua(stanza.tags[1]);
end;
data=function(stanza)
local t = {};
for _,child in pairs(stanza.tags) do
if child.name ~= "value" then error("<data> can only have <value> children"); end
t_insert(t, _xmlrpc_to_lua(child));
end
return t;
end;
struct=function(stanza)
local t = {};
for _,child in pairs(stanza.tags) do
if child.name ~= "member" then error("<struct> can only have <member> children"); end
local name, value = _xmlrpc_to_lua(child);
t[name] = value;
end
return t;
end;
member=function(stanza)
if #stanza.tags ~= 2 then error("<member> must have exactly two subtags"); end -- FIXME <params> is optional
if stanza.tags[1].name ~= "name" then error("First <member> child tag must be <name>") end
if stanza.tags[2].name ~= "value" then error("Second <member> child tag must be <value>") end
return _xmlrpc_to_lua(stanza.tags[1]), _xmlrpc_to_lua(stanza.tags[2]);
end;
name=function(stanza)
if #stanza.tags ~= 0 then error("<name> must have a single text child"); end
local n = t_concat(stanza)
if tostring(tonumber(n)) == n then n = tonumber(n); end
return n;
end;
["nil"]=function(stanza) -- nil extension
return nil;
end;
}
_xmlrpc_to_lua = function(stanza)
local h = rmap[stanza.name];
if h then
return h(stanza);
else
error("Unknown element: "..stanza.name);
end
end
function translate_request(stanza)
if stanza.name ~= "methodCall" then error("XML-RPC requests must have <methodCall> as root element"); end
return _xmlrpc_to_lua(stanza);
end
return _M;
|