aboutsummaryrefslogtreecommitdiffstats
path: root/util/stanza.lua
diff options
context:
space:
mode:
Diffstat (limited to 'util/stanza.lua')
-rw-r--r--util/stanza.lua96
1 files changed, 60 insertions, 36 deletions
diff --git a/util/stanza.lua b/util/stanza.lua
index 86b88169..0f8827d5 100644
--- a/util/stanza.lua
+++ b/util/stanza.lua
@@ -21,12 +21,15 @@ local type = type;
local s_gsub = string.gsub;
local s_sub = string.sub;
local s_find = string.find;
+local t_move = table.move or require "util.table".move;
+local t_create = require"util.table".create;
local valid_utf8 = require "util.encodings".utf8.valid;
local do_pretty_printing, termcolours = pcall(require, "util.termcolours");
local xmlns_stanzas = "urn:ietf:params:xml:ns:xmpp-stanzas";
+local xmpp_stanzas_attr = { xmlns = xmlns_stanzas };
local _ENV = nil;
-- luacheck: std none
@@ -179,6 +182,14 @@ function stanza_mt:get_child_text(name, xmlns)
return nil;
end
+function stanza_mt:get_child_attr(name, xmlns, attr)
+ local tag = self:get_child(name, xmlns);
+ if tag then
+ return tag.attr[attr];
+ end
+ return nil;
+end
+
function stanza_mt:child_with_name(name)
for _, child in ipairs(self.tags) do
if child.name == name then return child; end
@@ -283,25 +294,33 @@ function stanza_mt:find(path)
end
local function _clone(stanza, only_top)
- local attr, tags = {}, {};
+ local attr = {};
for k,v in pairs(stanza.attr) do attr[k] = v; end
local old_namespaces, namespaces = stanza.namespaces;
if old_namespaces then
namespaces = {};
for k,v in pairs(old_namespaces) do namespaces[k] = v; end
end
- local new = { name = stanza.name, attr = attr, namespaces = namespaces, tags = tags };
+ local tags, new;
+ if only_top then
+ tags = {};
+ new = { name = stanza.name, attr = attr, namespaces = namespaces, tags = tags };
+ else
+ tags = t_create(#stanza.tags, 0);
+ new = t_create(#stanza, 4);
+ new.name = stanza.name;
+ new.attr = attr;
+ new.namespaces = namespaces;
+ new.tags = tags;
+ end
+
+ setmetatable(new, stanza_mt);
if not only_top then
- for i=1,#stanza do
- local child = stanza[i];
- if child.name then
- child = _clone(child);
- t_insert(tags, child);
- end
- t_insert(new, child);
- end
+ t_move(stanza, 1, #stanza, 1, new);
+ t_move(stanza.tags, 1, #stanza.tags, 1, tags);
+ new:maptags(_clone);
end
- return setmetatable(new, stanza_mt);
+ return new;
end
local function clone(stanza, only_top)
@@ -387,6 +406,33 @@ function stanza_mt.get_error(stanza)
return error_type, condition or "undefined-condition", text, extra_tag;
end
+function stanza_mt.add_error(stanza, error_type, condition, error_message, error_by)
+ local extra;
+ if type(error_type) == "table" then -- an util.error or similar object
+ if type(error_type.extra) == "table" then
+ extra = error_type.extra;
+ end
+ if type(error_type.context) == "table" and type(error_type.context.by) == "string" then error_by = error_type.context.by; end
+ error_type, condition, error_message = error_type.type, error_type.condition, error_type.text;
+ end
+ if stanza.attr.from == error_by then
+ error_by = nil;
+ end
+ stanza:tag("error", {type = error_type, by = error_by}) --COMPAT: Some day xmlns:stanzas goes here
+ :tag(condition, xmpp_stanzas_attr);
+ if extra and condition == "gone" and type(extra.uri) == "string" then
+ stanza:text(extra.uri);
+ end
+ stanza:up();
+ if error_message then stanza:text_tag("text", error_message, xmpp_stanzas_attr); end
+ if extra and is_stanza(extra.tag) then
+ stanza:add_child(extra.tag);
+ elseif extra and extra.namespace and extra.condition then
+ stanza:tag(extra.condition, { xmlns = extra.namespace }):up();
+ end
+ return stanza:up();
+end
+
local function preserialize(stanza)
local s = { name = stanza.name, attr = stanza.attr };
for _, child in ipairs(stanza) do
@@ -461,7 +507,6 @@ local function reply(orig)
});
end
-local xmpp_stanzas_attr = { xmlns = xmlns_stanzas };
local function error_reply(orig, error_type, condition, error_message, error_by)
if not is_stanza(orig) then
error("bad argument to error_reply: expected stanza, got "..type(orig));
@@ -470,30 +515,9 @@ local function error_reply(orig, error_type, condition, error_message, error_by)
end
local t = reply(orig);
t.attr.type = "error";
- local extra;
- if type(error_type) == "table" then -- an util.error or similar object
- if type(error_type.extra) == "table" then
- extra = error_type.extra;
- end
- if type(error_type.context) == "table" and type(error_type.context.by) == "string" then error_by = error_type.context.by; end
- error_type, condition, error_message = error_type.type, error_type.condition, error_type.text;
- end
- if t.attr.from == error_by then
- error_by = nil;
- end
- t:tag("error", {type = error_type, by = error_by}) --COMPAT: Some day xmlns:stanzas goes here
- :tag(condition, xmpp_stanzas_attr);
- if extra and condition == "gone" and type(extra.uri) == "string" then
- t:text(extra.uri);
- end
- t:up();
- if error_message then t:text_tag("text", error_message, xmpp_stanzas_attr); end
- if extra and is_stanza(extra.tag) then
- t:add_child(extra.tag);
- elseif extra and extra.namespace and extra.condition then
- t:tag(extra.condition, { xmlns = extra.namespace }):up();
- end
- return t; -- stanza ready for adding app-specific errors
+ t:add_error(error_type, condition, error_message, error_by);
+ t.last_add = { t[1] }; -- ready to add application-specific errors
+ return t;
end
local function presence(attr)