88d0609f9d26839f88f6a3faf3e39502d38ce17e
[prosody.git] / util / stanza.lua
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
9 module "stanza"
10
11 stanza_mt = {};
12 stanza_mt.__index = stanza_mt;
13
14 function stanza(name, attr)
15         local stanza = { name = name, attr = attr or {}, last_add = {}};
16         return setmetatable(stanza, stanza_mt);
17 end
18
19 function stanza_mt:iq(attrs)
20         return self + stanza("iq", attrs)
21 end
22 function stanza_mt:message(attrs)
23         return self + stanza("message", attrs)
24 end
25 function stanza_mt:presence(attrs)
26         return self + stanza("presence", attrs)
27 end
28 function stanza_mt:query(xmlns)
29         return self:tag("query", { xmlns = xmlns });
30 end
31 function stanza_mt:tag(name, attrs)
32         local s = stanza(name, attrs);
33         (self.last_add[#self.last_add] or self):add_child(s);
34         t_insert(self.last_add, s);
35         return self;
36 end
37
38 function stanza_mt:text(text)
39         (self.last_add[#self.last_add] or self):add_child(text);
40         return self; 
41 end
42
43 function stanza_mt:up()
44         t_remove(self.last_add);
45         return self;
46 end
47
48 function stanza_mt:add_child(child)
49         t_insert(self, child);
50 end
51
52 function stanza_mt:child_with_name(name)
53         for _, child in ipairs(self) do 
54                 if child.name == name then return child; end
55         end
56 end
57
58 function stanza_mt.__tostring(t)
59         local children_text = "";
60         for n, child in ipairs(t) do
61                 children_text = children_text .. tostring(child);
62         end
63
64         local attr_string = "";
65         if t.attr then
66                 for k, v in pairs(t.attr) do attr_string = attr_string .. format(" %s='%s'", k, tostring(v)); end
67         end
68
69         return format("<%s%s>%s</%s>", t.name, attr_string, children_text, t.name);
70 end
71
72 function stanza_mt.__add(s1, s2)
73         return s:add_child(s2);
74 end
75
76
77 do
78         local id = 0;
79         function new_id()
80                 id = id + 1;
81                 return "lx"..id;
82         end
83 end
84
85 function message(attr, body)
86         if not body then
87                 return stanza("message", attr);
88         else
89                 return stanza("message", attr):tag("body"):text(body);
90         end
91 end
92 function iq(attr)
93         if attr and not attr.id then attr.id = new_id(); end
94         return stanza("iq", attr or { id = new_id() });
95 end
96
97 function reply(orig)
98         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) });
99 end
100
101 function presence(attr)
102         return stanza("presence", attr);
103 end
104