local t_insert = table.insert;
local t_remove = table.remove;
-local format = string.format;
+local s_format = string.format;
local tostring = tostring;
local setmetatable = setmetatable;
local pairs = pairs;
local ipairs = ipairs;
local type = type;
+local next = next;
+local print = print;
+local unpack = unpack;
local s_gsub = string.gsub;
+
+local debug = debug;
+local log = require "util.logger".init("stanza");
+
module "stanza"
stanza_mt = {};
return setmetatable(stanza, stanza_mt);
end
-function stanza_mt:iq(attrs)
- return self + stanza("iq", attrs)
-end
-function stanza_mt:message(attrs)
- return self + stanza("message", attrs)
-end
-function stanza_mt:presence(attrs)
- return self + stanza("presence", attrs)
-end
function stanza_mt:query(xmlns)
return self:tag("query", { xmlns = xmlns });
end
function stanza_mt:tag(name, attrs)
local s = stanza(name, attrs);
- (self.last_add[#self.last_add] or self):add_child(s);
+ (self.last_add[#self.last_add] or self):add_direct_child(s);
t_insert(self.last_add, s);
return self;
end
function stanza_mt:text(text)
- (self.last_add[#self.last_add] or self):add_child(text);
+ (self.last_add[#self.last_add] or self):add_direct_child(text);
return self;
end
return self;
end
-function stanza_mt:add_child(child)
+function stanza_mt:add_direct_child(child)
if type(child) == "table" then
t_insert(self.tags, child);
end
t_insert(self, child);
end
+function stanza_mt:add_child(child)
+ (self.last_add[#self.last_add] or self):add_direct_child(child);
+ return self;
+end
+
function stanza_mt:child_with_name(name)
for _, child in ipairs(self) do
if child.name == name then return child; end
local attr_string = "";
if t.attr then
- for k, v in pairs(t.attr) do if type(k) == "string" then attr_string = attr_string .. format(" %s='%s'", k, tostring(v)); end end
+ for k, v in pairs(t.attr) do if type(k) == "string" then attr_string = attr_string .. s_format(" %s='%s'", k, tostring(v)); end end
end
-
- return format("<%s%s>%s</%s>", t.name, attr_string, children_text, t.name);
+ return s_format("<%s%s>%s</%s>", t.name, attr_string, children_text, t.name);
end
function stanza_mt.__add(s1, s2)
- return s1:add_child(s2);
+ return s1:add_direct_child(s2);
end
end
end
+function preserialize(stanza)
+ local s = { name = stanza.name, attr = stanza.attr };
+ for _, child in ipairs(stanza) do
+ if type(child) == "table" then
+ t_insert(s, preserialize(child));
+ else
+ t_insert(s, child);
+ end
+ end
+ return s;
+end
+
+function deserialize(stanza)
+ -- Set metatable
+ if stanza then
+ setmetatable(stanza, stanza_mt);
+ for _, child in ipairs(stanza) do
+ if type(child) == "table" then
+ deserialize(child);
+ end
+ end
+ if not stanza.tags then
+ -- Rebuild tags
+ local tags = {};
+ for _, child in ipairs(stanza) do
+ if type(child) == "table" then
+ t_insert(tags, child);
+ end
+ end
+ stanza.tags = tags;
+ end
+ end
+
+ return stanza;
+end
+
function message(attr, body)
if not body then
return stanza("message", attr);
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 nil) });
end
+function error_reply(orig, type, condition, message, clone)
+ local t = reply(orig);
+ t.attr.type = "error";
+ -- TODO use clone
+ t:tag("error", {type = type})
+ :tag(condition, {xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas"}):up();
+ if (message) then t:tag("text"):text(message):up(); end
+ return t; -- stanza ready for adding app-specific errors
+end
+
function presence(attr)
return stanza("presence", attr);
end
+return _M;