-- Prosody IM
-- 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.
--
local t_insert = table.insert;
-local t_concat = table.concat;
local t_remove = table.remove;
local t_concat = table.concat;
local s_format = string.format;
local s_match = string.match;
local tostring = tostring;
local setmetatable = setmetatable;
-local getmetatable = getmetatable;
local pairs = pairs;
local ipairs = ipairs;
local type = type;
-local next = next;
-local print = print;
-local unpack = unpack;
local s_gsub = string.gsub;
-local s_char = string.char;
+local s_sub = string.sub;
local s_find = string.find;
local os = os;
if (not name or child.name == name)
and ((not xmlns and self.attr.xmlns == child.attr.xmlns)
or child.attr.xmlns == xmlns) then
-
+
return child;
end
end
end
function stanza_mt:childtags(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
local v = tags[i];
if (not name or v.name == name)
- and (not xmlns or xmlns == v.attr.xmlns) then
+ and ((not xmlns and self.attr.xmlns == v.attr.xmlns)
+ or v.attr.xmlns == xmlns) then
start_i = i+1;
return v;
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
+ while curr_tag <= n_tags and n_tags > 0 do
if self[i] == tags[curr_tag] then
local ret = callback(self[i]);
if ret == nil then
t_remove(tags, curr_tag);
n_children = n_children - 1;
n_tags = n_tags - 1;
+ i = i - 1;
+ curr_tag = curr_tag - 1;
else
self[i] = ret;
- tags[i] = ret;
+ tags[curr_tag] = ret;
end
- i = i + 1;
curr_tag = curr_tag + 1;
end
+ i = i + 1;
end
return self;
end
+function stanza_mt:find(path)
+ local pos = 1;
+ local len = #path + 1;
+
+ repeat
+ local xmlns, name, text;
+ local char = s_sub(path, pos, pos);
+ if char == "@" then
+ return self.attr[s_sub(path, pos + 1)];
+ elseif char == "{" then
+ xmlns, pos = s_match(path, "^([^}]+)}()", pos + 1);
+ end
+ name, text, pos = s_match(path, "^([^@/#]*)([/#]?)()", pos);
+ name = name ~= "" and name or nil;
+ if pos == len then
+ if text == "#" then
+ return self:get_child_text(name, xmlns);
+ end
+ return self:get_child(name, xmlns);
+ end
+ self = self:get_child(name, xmlns);
+ until not self
+end
+
+
local xml_escape
do
- local escape_table = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" };
- function xml_escape(str) return (s_gsub(str, "['&<>\"]", escape_table)); end
+ local escape_table = {
+ ["'"] = "'";
+ ['"'] = """;
+ ["<"] = "<";
+ [">"] = ">";
+ ["&"] = "&";
+ -- escape this whitespace because [\r\n\t] change into spaces in attributes
+ -- and \r\n changes into \n in text, and we want to preserve original bytes
+ ["\t"] = "	";
+ ["\n"] = "
";
+ ["\r"] = "
";
+ };
+ function xml_escape(str) return (s_gsub(str, "['&<>\"\t\n\r]", escape_table)); end
_M.xml_escape = xml_escape;
end
function stanza_mt.get_error(stanza)
local type, condition, text;
-
+
local error_tag = stanza:get_child("error");
if not error_tag then
return nil, nil, nil;
end
type = error_tag.attr.type;
-
- for child in error_tag:childtags() do
+
+ for _, child in ipairs(error_tag.tags) do
if child.attr.xmlns == xmlns_stanzas then
if not text and child.name == "text" then
text = child:get_text();
return type, condition or "undefined-condition", text;
end
-function stanza_mt.__add(s1, s2)
- return s1:add_direct_child(s2);
-end
-
-
do
local id = 0;
function new_id()
stanza.tags = tags;
end
end
-
+
return stanza;
end
-function clone(stanza)
- local lookup_table = {};
- local function _copy(object)
- if type(object) ~= "table" then
- return object;
- elseif lookup_table[object] then
- return lookup_table[object];
- end
- local new_table = {};
- lookup_table[object] = new_table;
- for index, value in pairs(object) do
- new_table[_copy(index)] = _copy(value);
+local function _clone(stanza)
+ local attr, tags = {}, {};
+ for k,v in pairs(stanza.attr) do attr[k] = v; end
+ local new = { name = stanza.name, attr = attr, tags = tags };
+ for i=1,#stanza do
+ local child = stanza[i];
+ if child.name then
+ child = _clone(child);
+ t_insert(tags, child);
end
- return setmetatable(new_table, getmetatable(object));
+ t_insert(new, child);
end
-
- return _copy(stanza)
+ return setmetatable(new, stanza_mt);
end
+clone = _clone;
function message(attr, body)
if not body then
local style_attrv = getstyle("red");
local style_tagname = getstyle("red");
local style_punc = getstyle("magenta");
-
+
local attr_format = " "..getstring(style_attrk, "%s")..getstring(style_punc, "=")..getstring(style_attrv, "'%s'");
local top_tag_format = getstring(style_punc, "<")..getstring(style_tagname, "%s").."%s"..getstring(style_punc, ">");
--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, ">");
end
return s_format(tag_format, t.name, attr_string, children_text, t.name);
end
-
+
function stanza_mt.pretty_top_tag(t)
local attr_string = "";
if t.attr then