util/xmlrpc.lua

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

mercurial