5
|
1 local t_insert = table.insert;
|
|
2 local t_remove = table.remove;
|
|
3 local format = string.format;
|
|
4 local tostring = tostring;
|
|
5 local setmetatable = setmetatable;
|
|
6 local pairs = pairs;
|
|
7 local ipairs = ipairs;
|
|
8 local type = type;
|
|
9 local s_gsub = string.gsub;
|
|
10 module "stanza"
|
|
11
|
|
12 stanza_mt = {};
|
|
13 stanza_mt.__index = stanza_mt;
|
|
14
|
|
15 function stanza(name, attr)
|
|
16 local stanza = { name = name, attr = attr or {}, tags = {}, last_add = {}};
|
|
17 return setmetatable(stanza, stanza_mt);
|
|
18 end
|
|
19
|
|
20 function stanza_mt:iq(attrs)
|
|
21 return self + stanza("iq", attrs)
|
|
22 end
|
|
23 function stanza_mt:message(attrs)
|
|
24 return self + stanza("message", attrs)
|
|
25 end
|
|
26 function stanza_mt:presence(attrs)
|
|
27 return self + stanza("presence", attrs)
|
|
28 end
|
|
29 function stanza_mt:query(xmlns)
|
|
30 return self:tag("query", { xmlns = xmlns });
|
|
31 end
|
|
32 function stanza_mt:tag(name, attrs)
|
|
33 local s = stanza(name, attrs);
|
|
34 (self.last_add[#self.last_add] or self):add_child(s);
|
|
35 t_insert(self.last_add, s);
|
|
36 return self;
|
|
37 end
|
|
38
|
|
39 function stanza_mt:text(text)
|
|
40 (self.last_add[#self.last_add] or self):add_child(text);
|
|
41 return self;
|
|
42 end
|
|
43
|
|
44 function stanza_mt:up()
|
|
45 t_remove(self.last_add);
|
|
46 return self;
|
|
47 end
|
|
48
|
|
49 function stanza_mt:add_child(child)
|
|
50 if type(child) == "table" then
|
|
51 t_insert(self.tags, child);
|
|
52 end
|
|
53 t_insert(self, child);
|
|
54 end
|
|
55
|
|
56 function stanza_mt:child_with_name(name)
|
|
57 for _, child in ipairs(self) do
|
|
58 if child.name == name then return child; end
|
|
59 end
|
|
60 end
|
|
61
|
|
62 function stanza_mt:children()
|
|
63 local i = 0;
|
|
64 return function (a)
|
|
65 i = i + 1
|
|
66 local v = a[i]
|
|
67 if v then return v; end
|
|
68 end, self, i;
|
|
69
|
|
70 end
|
|
71 function stanza_mt:childtags()
|
|
72 local i = 0;
|
|
73 return function (a)
|
|
74 i = i + 1
|
|
75 local v = self.tags[i]
|
|
76 if v then return v; end
|
|
77 end, self.tags[1], i;
|
|
78
|
|
79 end
|
|
80
|
|
81 do
|
|
82 local xml_entities = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" };
|
|
83 function xml_escape(s) return s_gsub(s, "['&<>\"]", xml_entities); end
|
|
84 end
|
|
85
|
|
86 local xml_escape = xml_escape;
|
|
87
|
|
88 function stanza_mt.__tostring(t)
|
|
89 local children_text = "";
|
|
90 for n, child in ipairs(t) do
|
|
91 if type(child) == "string" then
|
|
92 children_text = children_text .. xml_escape(child);
|
|
93 else
|
|
94 children_text = children_text .. tostring(child);
|
|
95 end
|
|
96 end
|
|
97
|
|
98 local attr_string = "";
|
|
99 if t.attr then
|
|
100 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
|
|
101 end
|
|
102
|
|
103 return format("<%s%s>%s</%s>", t.name, attr_string, children_text, t.name);
|
|
104 end
|
|
105
|
|
106 function stanza_mt.__add(s1, s2)
|
|
107 return s1:add_child(s2);
|
|
108 end
|
|
109
|
|
110
|
|
111 do
|
|
112 local id = 0;
|
|
113 function new_id()
|
|
114 id = id + 1;
|
|
115 return "lx"..id;
|
|
116 end
|
|
117 end
|
|
118
|
|
119 function message(attr, body)
|
|
120 if not body then
|
|
121 return stanza("message", attr);
|
|
122 else
|
|
123 return stanza("message", attr):tag("body"):text(body);
|
|
124 end
|
|
125 end
|
|
126 function iq(attr)
|
|
127 if attr and not attr.id then attr.id = new_id(); end
|
|
128 return stanza("iq", attr or { id = new_id() });
|
|
129 end
|
|
130
|
|
131 function reply(orig)
|
|
132 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) });
|
|
133 end
|
|
134
|
|
135 function presence(attr)
|
|
136 return stanza("presence", attr);
|
|
137 end
|
|
138
|