-- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- 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.
stanza_mt.__index = stanza_mt;
function stanza(name, attr)
- local stanza = { name = name, attr = attr or {}, tags = {}, last_add = {}};
+ local stanza = { name = name, attr = attr or {}, tags = {} };
return setmetatable(stanza, stanza_mt);
end
function stanza_mt:tag(name, attrs)
local s = stanza(name, attrs);
- (self.last_add[#self.last_add] or self):add_direct_child(s);
- t_insert(self.last_add, s);
+ local last_add = self.last_add;
+ if not last_add then last_add = {}; self.last_add = last_add; end
+ (last_add[#last_add] or self):add_direct_child(s);
+ t_insert(last_add, s);
return self;
end
function stanza_mt:text(text)
- (self.last_add[#self.last_add] or self):add_direct_child(text);
+ local last_add = self.last_add;
+ (last_add and last_add[#last_add] or self):add_direct_child(text);
return self;
end
function stanza_mt:up()
- t_remove(self.last_add);
+ local last_add = self.last_add;
+ if last_add then t_remove(last_add); end
return self;
end
function stanza_mt:reset()
- local last_add = self.last_add;
- for i = 1,#last_add do
- last_add[i] = nil;
- end
+ self.last_add = nil;
return self;
end
end
function stanza_mt:add_child(child)
- (self.last_add[#self.last_add] or self):add_direct_child(child);
+ local last_add = self.last_add;
+ (last_add and last_add[#last_add] or self):add_direct_child(child);
return self;
end
local i = 0;
return function (a)
i = i + 1
- local v = a[i]
- if v then return v; end
+ return a[i];
end, self, i;
end
+
+function stanza_mt:matching_tags(name, xmlns)
+ xmlns = xmlns or self.attr.xmlns;
+ local tags = self.tags;
+ local start_i, max_i = 1, #tags;
+ return function ()
+ for i=start_i,max_i do
+ v = tags[i];
+ if (not name or v.name == name)
+ and (not xmlns or xmlns == v.attr.xmlns) then
+ start_i = i+1;
+ return v;
+ end
+ end
+ end, tags, i;
+end
+
function stanza_mt:childtags()
local i = 0;
return function (a)
end, self.tags[1], i;
end
+function stanza_mt:maptags(callback)
+ local tags, curr_tag = self.tags, 1;
+ local n_children, n_tags = #self, #tags;
+
+ local i = 1;
+ while curr_tag <= n_tags do
+ if self[i] == tags[curr_tag] then
+ local ret = callback(self[i]);
+ if ret == nil then
+ t_remove(self, i);
+ t_remove(tags, curr_tag);
+ n_children = n_children - 1;
+ n_tags = n_tags - 1;
+ else
+ self[i] = ret;
+ tags[i] = ret;
+ end
+ i = i + 1;
+ curr_tag = curr_tag + 1;
+ end
+ end
+ return self;
+end
+
local xml_escape
do
local escape_table = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" };
end
type = error_tag.attr.type;
- for child in error_tag:children() do
+ for child in error_tag:childtags() do
if child.attr.xmlns == xmlns_stanzas then
if not text and child.name == "text" then
text = child:get_text();
end
end
end
- return type, condition or "undefined-condition", text or "";
+ return type, condition or "undefined-condition", text;
end
function stanza_mt.__add(s1, s2)
for i=1,#attr do attr[i] = nil; end
local attrx = {};
for att in pairs(attr) do
- if s_find(att, "|", 1, true) and not s_find(k, "\1", 1, true) then
- local ns,na = s_match(k, "^([^|]+)|(.+)$");
+ if s_find(att, "|", 1, true) and not s_find(att, "\1", 1, true) then
+ local ns,na = s_match(att, "^([^|]+)|(.+)$");
attrx[ns.."\1"..na] = attr[att];
attr[att] = nil;
end
end
for a,v in pairs(attrx) do
- attr[x] = v;
+ attr[a] = v;
end
setmetatable(stanza, stanza_mt);
for _, child in ipairs(stanza) do
end
end
stanza.tags = tags;
- if not stanza.last_add then
- stanza.last_add = {};
- end
end
end
if not body then
return stanza("message", attr);
else
- return stanza("message", attr):tag("body"):text(body);
+ return stanza("message", attr):tag("body"):text(body):up();
end
end
function iq(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 orig.attr.type) });
end
-function error_reply(orig, type, condition, message)
- local t = reply(orig);
- t.attr.type = "error";
- 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
+do
+ local xmpp_stanzas_attr = { xmlns = xmlns_stanzas };
+ function error_reply(orig, type, condition, message)
+ local t = reply(orig);
+ t.attr.type = "error";
+ t:tag("error", {type = type}) --COMPAT: Some day xmlns:stanzas goes here
+ :tag(condition, xmpp_stanzas_attr):up();
+ if (message) then t:tag("text", xmpp_stanzas_attr):text(message):up(); end
+ return t; -- stanza ready for adding app-specific errors
+ end
end
function presence(attr)