38 local _ENV = nil; |
38 local _ENV = nil; |
39 |
39 |
40 local stanza_mt = { __type = "stanza" }; |
40 local stanza_mt = { __type = "stanza" }; |
41 stanza_mt.__index = stanza_mt; |
41 stanza_mt.__index = stanza_mt; |
42 |
42 |
43 local function stanza(name, attr, namespaces) |
43 local function new_stanza(name, attr, namespaces) |
44 local stanza = { name = name, attr = attr or {}, namespaces = namespaces, tags = {} }; |
44 local stanza = { name = name, attr = attr or {}, namespaces = namespaces, tags = {} }; |
45 return setmetatable(stanza, stanza_mt); |
45 return setmetatable(stanza, stanza_mt); |
46 end |
46 end |
47 local stanza = stanza; |
|
48 |
47 |
49 function stanza_mt:query(xmlns) |
48 function stanza_mt:query(xmlns) |
50 return self:tag("query", { xmlns = xmlns }); |
49 return self:tag("query", { xmlns = xmlns }); |
51 end |
50 end |
52 |
51 |
53 function stanza_mt:body(text, attr) |
52 function stanza_mt:body(text, attr) |
54 return self:tag("body", attr):text(text); |
53 return self:tag("body", attr):text(text); |
55 end |
54 end |
56 |
55 |
57 function stanza_mt:tag(name, attr, namespaces) |
56 function stanza_mt:tag(name, attr, namespaces) |
58 local s = stanza(name, attr, namespaces); |
57 local s = new_stanza(name, attr, namespaces); |
59 local last_add = self.last_add; |
58 local last_add = self.last_add; |
60 if not last_add then last_add = {}; self.last_add = last_add; end |
59 if not last_add then last_add = {}; self.last_add = last_add; end |
61 (last_add[#last_add] or self):add_direct_child(s); |
60 (last_add[#last_add] or self):add_direct_child(s); |
62 t_insert(last_add, s); |
61 t_insert(last_add, s); |
63 return self; |
62 return self; |
200 |
199 |
201 |
200 |
202 local escape_table = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" }; |
201 local escape_table = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" }; |
203 local function xml_escape(str) return (s_gsub(str, "['&<>\"]", escape_table)); end |
202 local function xml_escape(str) return (s_gsub(str, "['&<>\"]", escape_table)); end |
204 |
203 |
205 local function _dostring(t, buf, self, xml_escape, parentns) |
204 local function _dostring(t, buf, self, _xml_escape, parentns) |
206 local nsid = 0; |
205 local nsid = 0; |
207 local name = t.name |
206 local name = t.name |
208 t_insert(buf, "<"..name); |
207 t_insert(buf, "<"..name); |
209 for k, v in pairs(t.attr) do |
208 for k, v in pairs(t.attr) do |
210 if s_find(k, "\1", 1, true) then |
209 if s_find(k, "\1", 1, true) then |
211 local ns, attrk = s_match(k, "^([^\1]*)\1?(.*)$"); |
210 local ns, attrk = s_match(k, "^([^\1]*)\1?(.*)$"); |
212 nsid = nsid + 1; |
211 nsid = nsid + 1; |
213 t_insert(buf, " xmlns:ns"..nsid.."='"..xml_escape(ns).."' ".."ns"..nsid..":"..attrk.."='"..xml_escape(v).."'"); |
212 t_insert(buf, " xmlns:ns"..nsid.."='".._xml_escape(ns).."' ".."ns"..nsid..":"..attrk.."='".._xml_escape(v).."'"); |
214 elseif not(k == "xmlns" and v == parentns) then |
213 elseif not(k == "xmlns" and v == parentns) then |
215 t_insert(buf, " "..k.."='"..xml_escape(v).."'"); |
214 t_insert(buf, " "..k.."='".._xml_escape(v).."'"); |
216 end |
215 end |
217 end |
216 end |
218 local len = #t; |
217 local len = #t; |
219 if len == 0 then |
218 if len == 0 then |
220 t_insert(buf, "/>"); |
219 t_insert(buf, "/>"); |
221 else |
220 else |
222 t_insert(buf, ">"); |
221 t_insert(buf, ">"); |
223 for n=1,len do |
222 for n=1,len do |
224 local child = t[n]; |
223 local child = t[n]; |
225 if child.name then |
224 if child.name then |
226 self(child, buf, self, xml_escape, t.attr.xmlns); |
225 self(child, buf, self, _xml_escape, t.attr.xmlns); |
227 else |
226 else |
228 t_insert(buf, xml_escape(child)); |
227 t_insert(buf, _xml_escape(child)); |
229 end |
228 end |
230 end |
229 end |
231 t_insert(buf, "</"..name..">"); |
230 t_insert(buf, "</"..name..">"); |
232 end |
231 end |
233 end |
232 end |
250 return t_concat(t); |
249 return t_concat(t); |
251 end |
250 end |
252 end |
251 end |
253 |
252 |
254 function stanza_mt.get_error(stanza) |
253 function stanza_mt.get_error(stanza) |
255 local type, condition, text; |
254 local error_type, condition, text; |
256 |
255 |
257 local error_tag = stanza:get_child("error"); |
256 local error_tag = stanza:get_child("error"); |
258 if not error_tag then |
257 if not error_tag then |
259 return nil, nil, nil; |
258 return nil, nil, nil; |
260 end |
259 end |
261 type = error_tag.attr.type; |
260 error_type = error_tag.attr.type; |
262 |
261 |
263 for _, child in ipairs(error_tag.tags) do |
262 for _, child in ipairs(error_tag.tags) do |
264 if child.attr.xmlns == xmlns_stanzas then |
263 if child.attr.xmlns == xmlns_stanzas then |
265 if not text and child.name == "text" then |
264 if not text and child.name == "text" then |
266 text = child:get_text(); |
265 text = child:get_text(); |
350 return setmetatable(new, stanza_mt); |
349 return setmetatable(new, stanza_mt); |
351 end |
350 end |
352 |
351 |
353 local function message(attr, body) |
352 local function message(attr, body) |
354 if not body then |
353 if not body then |
355 return stanza("message", attr); |
354 return new_stanza("message", attr); |
356 else |
355 else |
357 return stanza("message", attr):tag("body"):text(body):up(); |
356 return new_stanza("message", attr):tag("body"):text(body):up(); |
358 end |
357 end |
359 end |
358 end |
360 local function iq(attr) |
359 local function iq(attr) |
361 if attr and not attr.id then attr.id = new_id(); end |
360 if attr and not attr.id then attr.id = new_id(); end |
362 return stanza("iq", attr or { id = new_id() }); |
361 return new_stanza("iq", attr or { id = new_id() }); |
363 end |
362 end |
364 |
363 |
365 local function reply(orig) |
364 local function reply(orig) |
366 return stanza(orig.name, orig.attr and { to = orig.attr.from, from = orig.attr.to, id = orig.attr.id, type = ((orig.name == "iq" and "result") or orig.attr.type) }); |
365 return new_stanza(orig.name, orig.attr and { to = orig.attr.from, from = orig.attr.to, id = orig.attr.id, type = ((orig.name == "iq" and "result") or orig.attr.type) }); |
367 end |
366 end |
368 |
367 |
369 local xmpp_stanzas_attr = { xmlns = xmlns_stanzas }; |
368 local xmpp_stanzas_attr = { xmlns = xmlns_stanzas }; |
370 local function error_reply(orig, type, condition, message) |
369 local function error_reply(orig, error_type, condition, error_message) |
371 local t = reply(orig); |
370 local t = reply(orig); |
372 t.attr.type = "error"; |
371 t.attr.type = "error"; |
373 t:tag("error", {type = type}) --COMPAT: Some day xmlns:stanzas goes here |
372 t:tag("error", {type = error_type}) --COMPAT: Some day xmlns:stanzas goes here |
374 :tag(condition, xmpp_stanzas_attr):up(); |
373 :tag(condition, xmpp_stanzas_attr):up(); |
375 if (message) then t:tag("text", xmpp_stanzas_attr):text(message):up(); end |
374 if error_message then t:tag("text", xmpp_stanzas_attr):text(error_message):up(); end |
376 return t; -- stanza ready for adding app-specific errors |
375 return t; -- stanza ready for adding app-specific errors |
377 end |
376 end |
378 |
377 |
379 local function presence(attr) |
378 local function presence(attr) |
380 return stanza("presence", attr); |
379 return new_stanza("presence", attr); |
381 end |
380 end |
382 |
381 |
383 if do_pretty_printing then |
382 if do_pretty_printing then |
384 local style_attrk = getstyle("yellow"); |
383 local style_attrk = getstyle("yellow"); |
385 local style_attrv = getstyle("red"); |
384 local style_attrv = getstyle("red"); |
390 local top_tag_format = getstring(style_punc, "<")..getstring(style_tagname, "%s").."%s"..getstring(style_punc, ">"); |
389 local top_tag_format = getstring(style_punc, "<")..getstring(style_tagname, "%s").."%s"..getstring(style_punc, ">"); |
391 --local tag_format = getstring(style_punc, "<")..getstring(style_tagname, "%s").."%s"..getstring(style_punc, ">").."%s"..getstring(style_punc, "</")..getstring(style_tagname, "%s")..getstring(style_punc, ">"); |
390 --local tag_format = getstring(style_punc, "<")..getstring(style_tagname, "%s").."%s"..getstring(style_punc, ">").."%s"..getstring(style_punc, "</")..getstring(style_tagname, "%s")..getstring(style_punc, ">"); |
392 local tag_format = top_tag_format.."%s"..getstring(style_punc, "</")..getstring(style_tagname, "%s")..getstring(style_punc, ">"); |
391 local tag_format = top_tag_format.."%s"..getstring(style_punc, "</")..getstring(style_tagname, "%s")..getstring(style_punc, ">"); |
393 function stanza_mt.pretty_print(t) |
392 function stanza_mt.pretty_print(t) |
394 local children_text = ""; |
393 local children_text = ""; |
395 for n, child in ipairs(t) do |
394 for _, child in ipairs(t) do |
396 if type(child) == "string" then |
395 if type(child) == "string" then |
397 children_text = children_text .. xml_escape(child); |
396 children_text = children_text .. xml_escape(child); |
398 else |
397 else |
399 children_text = children_text .. child:pretty_print(); |
398 children_text = children_text .. child:pretty_print(); |
400 end |
399 end |