b1af299fef6e9ea01f64c792050c7be4382ccbdc
[prosody.git] / core / xmlhandlers.lua
1
2 require "util.stanza"
3
4 local st = stanza;
5 local tostring = tostring;
6 local format = string.format;
7 local m_random = math.random;
8 local t_insert = table.insert;
9 local t_remove = table.remove;
10 local t_concat = table.concat;
11 local t_concatall = function (t, sep) local tt = {}; for _, s in ipairs(t) do t_insert(tt, tostring(s)); end return t_concat(tt, sep); end
12 local sm_destroy_session = import("core.sessionmanager", "destroy_session");
13
14 local error = error;
15
16 module "xmlhandlers"
17
18 function init_xmlhandlers(session, streamopened)
19                 local ns_stack = { "" };
20                 local curr_ns = "";
21                 local curr_tag;
22                 local chardata = {};
23                 local xml_handlers = {};
24                 local log = session.log;
25                 local print = function (...) log("info", "xmlhandlers", t_concatall({...}, "\t")); end
26                 
27                 local send = session.send;
28                 
29                 local stanza
30                 function xml_handlers:StartElement(name, attr)
31                         if stanza and #chardata > 0 then
32                                 -- We have some character data in the buffer
33                                 stanza:text(t_concat(chardata));
34                                 chardata = {};
35                         end
36                         curr_ns,name = name:match("^(.+):(%w+)$");
37                         if not stanza then
38                                 if session.notopen then
39                                         if name == "stream" then
40                                                 streamopened(session, attr);
41                                                 return;
42                                         end
43                                         error("Client failed to open stream successfully");
44                                 end
45                                 if curr_ns == "jabber:client" and name ~= "iq" and name ~= "presence" and name ~= "message" then
46                                         error("Client sent invalid top-level stanza");
47                                 end
48                                 attr.xmlns = curr_ns;
49                                 stanza = st.stanza(name, attr); --{ to = attr.to, type = attr.type, id = attr.id, xmlns = curr_ns });
50                                 curr_tag = stanza;
51                         else
52                                 attr.xmlns = curr_ns;
53                                 stanza:tag(name, attr);
54                         end
55                 end
56                 function xml_handlers:CharacterData(data)
57                         if stanza then
58                                 t_insert(chardata, data);
59                         end
60                 end
61                 function xml_handlers:EndElement(name)
62                         curr_ns,name = name:match("^(.+):(%w+)$");
63                         if (not stanza) or #stanza.last_add < 0 or (#stanza.last_add > 0 and name ~= stanza.last_add[#stanza.last_add].name) then 
64                                 if name == "stream" then
65                                         log("debug", "Stream closed");
66                                         sm_destroy_session(session);
67                                         return;
68                                 else
69                                         error("XML parse error in client stream");
70                                 end
71                         end
72                         if stanza and #chardata > 0 then
73                                 -- We have some character data in the buffer
74                                 stanza:text(t_concat(chardata));
75                                 chardata = {};
76                         end
77                         -- Complete stanza
78                         if #stanza.last_add == 0 then
79                                 session.stanza_dispatch(stanza);
80                                 stanza = nil;
81                         else
82                                 stanza:up();
83                         end
84                 end
85         return xml_handlers;
86 end
87
88 return init_xmlhandlers;