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
|
-- Prosody IM v0.4
-- Copyright (C) 2008-2009 Matthew Wild
-- Copyright (C) 2008-2009 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 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, object)
local stanza = st.stanza("methodCall")
:tag("methodName"):text(method_name):up()
:tag("params"):tag("param"):tag("value");
_lua_to_xmlrpc(stanza, object);
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;
|