certmanager: Don't disable LuaSec and future cert loading on failure, and add error...
[prosody.git] / core / xmlhandlers.lua
1 -- Prosody IM
2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
4 -- 
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
7 --
8
9
10
11 require "util.stanza"
12
13 local st = stanza;
14 local tostring = tostring;
15 local t_insert = table.insert;
16 local t_concat = table.concat;
17
18 local default_log = require "util.logger".init("xmlhandlers");
19
20 local error = error;
21
22 module "xmlhandlers"
23
24 local ns_prefixes = {
25         ["http://www.w3.org/XML/1998/namespace"] = "xml";
26 };
27
28 local xmlns_streams = "http://etherx.jabber.org/streams";
29
30 local ns_separator = "\1";
31 local ns_pattern = "^([^"..ns_separator.."]*)"..ns_separator.."?(.*)$";
32
33 function init_xmlhandlers(session, stream_callbacks)
34         local chardata = {};
35         local xml_handlers = {};
36         local log = session.log or default_log;
37         
38         local cb_streamopened = stream_callbacks.streamopened;
39         local cb_streamclosed = stream_callbacks.streamclosed;
40         local cb_error = stream_callbacks.error or function(session, e) error("XML stream error: "..tostring(e)); end;
41         local cb_handlestanza = stream_callbacks.handlestanza;
42         
43         local stream_ns = stream_callbacks.stream_ns or xmlns_streams;
44         local stream_tag = stream_ns..ns_separator..(stream_callbacks.stream_tag or "stream");
45         local stream_error_tag = stream_ns..ns_separator..(stream_callbacks.error_tag or "error");
46         
47         local stream_default_ns = stream_callbacks.default_ns;
48         
49         local stanza;
50         function xml_handlers:StartElement(tagname, attr)
51                 if stanza and #chardata > 0 then
52                         -- We have some character data in the buffer
53                         stanza:text(t_concat(chardata));
54                         chardata = {};
55                 end
56                 local curr_ns,name = tagname:match(ns_pattern);
57                 if name == "" then
58                         curr_ns, name = "", curr_ns;
59                 end
60
61                 if curr_ns ~= stream_default_ns then
62                         attr.xmlns = curr_ns;
63                 end
64                 
65                 -- FIXME !!!!!
66                 for i=1,#attr do
67                         local k = attr[i];
68                         attr[i] = nil;
69                         local ns, nm = k:match(ns_pattern);
70                         if nm ~= "" then
71                                 ns = ns_prefixes[ns]; 
72                                 if ns then 
73                                         attr[ns..":"..nm] = attr[k];
74                                         attr[k] = nil;
75                                 end
76                         end
77                 end
78                 
79                 if not stanza then --if we are not currently inside a stanza
80                         if session.notopen then
81                                 if tagname == stream_tag then
82                                         if cb_streamopened then
83                                                 cb_streamopened(session, attr);
84                                         end
85                                 else
86                                         -- Garbage before stream?
87                                         cb_error(session, "no-stream");
88                                 end
89                                 return;
90                         end
91                         if curr_ns == "jabber:client" and name ~= "iq" and name ~= "presence" and name ~= "message" then
92                                 cb_error(session, "invalid-top-level-element");
93                         end
94                         
95                         stanza = st.stanza(name, attr);
96                 else -- we are inside a stanza, so add a tag
97                         attr.xmlns = nil;
98                         if curr_ns ~= stream_default_ns then
99                                 attr.xmlns = curr_ns;
100                         end
101                         stanza:tag(name, attr);
102                 end
103         end
104         function xml_handlers:CharacterData(data)
105                 if stanza then
106                         t_insert(chardata, data);
107                 end
108         end
109         function xml_handlers:EndElement(tagname)
110                 if stanza then
111                         if #chardata > 0 then
112                                 -- We have some character data in the buffer
113                                 stanza:text(t_concat(chardata));
114                                 chardata = {};
115                         end
116                         -- Complete stanza
117                         if #stanza.last_add == 0 then
118                                 if tagname ~= stream_error_tag then
119                                         cb_handlestanza(session, stanza);
120                                 else
121                                         cb_error(session, "stream-error", stanza);
122                                 end
123                                 stanza = nil;
124                         else
125                                 stanza:up();
126                         end
127                 else
128                         if tagname == stream_tag then
129                                 if cb_streamclosed then
130                                         cb_streamclosed(session);
131                                 end
132                         else
133                                 local curr_ns,name = tagname:match(ns_pattern);
134                                 if name == "" then
135                                         curr_ns, name = "", curr_ns;
136                                 end
137                                 cb_error(session, "parse-error", "unexpected-element-close", name);
138                         end
139                         stanza, chardata = nil, {};
140                 end
141         end
142         return xml_handlers;
143 end
144
145 return init_xmlhandlers;