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