20 |
20 |
21 local stream_callbacks = { |
21 local stream_callbacks = { |
22 stream_ns = xmlns_stream, |
22 stream_ns = xmlns_stream, |
23 stream_tag = "stream", |
23 stream_tag = "stream", |
24 default_ns = "jabber:client" }; |
24 default_ns = "jabber:client" }; |
25 |
25 |
26 function stream_callbacks.streamopened(stream, attr) |
26 function stream_callbacks.streamopened(stream, attr) |
27 stream.stream_id = attr.id; |
27 stream.stream_id = attr.id; |
28 if not stream:event("opened", attr) then |
28 if not stream:event("opened", attr) then |
29 stream.notopen = nil; |
29 stream.notopen = nil; |
30 end |
30 end |
74 end |
74 end |
75 |
75 |
76 function stream:connect_client(jid, pass) |
76 function stream:connect_client(jid, pass) |
77 self.jid, self.password = jid, pass; |
77 self.jid, self.password = jid, pass; |
78 self.username, self.host, self.resource = jid_split(jid); |
78 self.username, self.host, self.resource = jid_split(jid); |
79 |
79 |
80 -- Required XMPP features |
80 -- Required XMPP features |
81 self:add_plugin("tls"); |
81 self:add_plugin("tls"); |
82 self:add_plugin("sasl"); |
82 self:add_plugin("sasl"); |
83 self:add_plugin("bind"); |
83 self:add_plugin("bind"); |
84 self:add_plugin("session"); |
84 self:add_plugin("session"); |
85 |
85 |
86 function self.data(conn, data) |
86 function self.data(conn, data) |
87 local ok, err = self.stream:feed(data); |
87 local ok, err = self.stream:feed(data); |
88 if ok then return; end |
88 if ok then return; end |
89 self:debug("Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " ")); |
89 self:debug("Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " ")); |
90 self:close("xml-not-well-formed"); |
90 self:close("xml-not-well-formed"); |
91 end |
91 end |
92 |
92 |
93 self:hook("connected", function () self:reopen(); end); |
93 self:hook("connected", function () self:reopen(); end); |
94 self:hook("incoming-raw", function (data) return self.data(self.conn, data); end); |
94 self:hook("incoming-raw", function (data) return self.data(self.conn, data); end); |
95 |
95 |
96 self.curr_id = 0; |
96 self.curr_id = 0; |
97 |
97 |
98 self.tracked_iqs = {}; |
98 self.tracked_iqs = {}; |
99 self:hook("stanza", function (stanza) |
99 self:hook("stanza", function (stanza) |
100 local id, type = stanza.attr.id, stanza.attr.type; |
100 local id, type = stanza.attr.id, stanza.attr.type; |
101 if id and stanza.name == "iq" and (type == "result" or type == "error") and self.tracked_iqs[id] then |
101 if id and stanza.name == "iq" and (type == "result" or type == "error") and self.tracked_iqs[id] then |
102 self.tracked_iqs[id](stanza); |
102 self.tracked_iqs[id](stanza); |
103 self.tracked_iqs[id] = nil; |
103 self.tracked_iqs[id] = nil; |
104 return true; |
104 return true; |
105 end |
105 end |
106 end); |
106 end); |
107 |
107 |
108 self:hook("stanza", function (stanza) |
108 self:hook("stanza", function (stanza) |
109 local ret; |
109 local ret; |
110 if stanza.attr.xmlns == nil or stanza.attr.xmlns == "jabber:client" then |
110 if stanza.attr.xmlns == nil or stanza.attr.xmlns == "jabber:client" then |
111 if stanza.name == "iq" and (stanza.attr.type == "get" or stanza.attr.type == "set") then |
111 if stanza.name == "iq" and (stanza.attr.type == "get" or stanza.attr.type == "set") then |
112 local xmlns = stanza.tags[1] and stanza.tags[1].attr.xmlns; |
112 local xmlns = stanza.tags[1] and stanza.tags[1].attr.xmlns; |
130 self:hook("outgoing", function (data) |
130 self:hook("outgoing", function (data) |
131 if data.name then |
131 if data.name then |
132 self:event("stanza-out", data); |
132 self:event("stanza-out", data); |
133 end |
133 end |
134 end); |
134 end); |
135 |
135 |
136 self:hook("stanza-out", function (stanza) |
136 self:hook("stanza-out", function (stanza) |
137 if not stanza.attr.xmlns then |
137 if not stanza.attr.xmlns then |
138 self:event(stanza.name.."-out", stanza); |
138 self:event(stanza.name.."-out", stanza); |
139 end |
139 end |
140 end); |
140 end); |
141 |
141 |
142 local function stream_ready() |
142 local function stream_ready() |
143 self:event("ready"); |
143 self:event("ready"); |
144 end |
144 end |
145 self:hook("session-success", stream_ready, -1) |
145 self:hook("session-success", stream_ready, -1) |
146 self:hook("bind-success", stream_ready, -1); |
146 self:hook("bind-success", stream_ready, -1); |
153 self.closed = true; |
153 self.closed = true; |
154 else |
154 else |
155 return self:close(reason); |
155 return self:close(reason); |
156 end |
156 end |
157 end |
157 end |
158 |
158 |
159 local function start_connect() |
159 local function start_connect() |
160 -- Initialise connection |
160 -- Initialise connection |
161 self:connect(self.connect_host or self.host, self.connect_port or 5222); |
161 self:connect(self.connect_host or self.host, self.connect_port or 5222); |
162 end |
162 end |
163 |
163 |
164 if not (self.connect_host or self.connect_port) then |
164 if not (self.connect_host or self.connect_port) then |
165 -- Look up SRV records |
165 -- Look up SRV records |
166 adns.lookup(function (answer) |
166 adns.lookup(function (answer) |
167 if answer then |
167 if answer then |
168 local srv_hosts = {}; |
168 local srv_hosts = {}; |
169 self.srv_hosts = srv_hosts; |
169 self.srv_hosts = srv_hosts; |
170 for _, record in ipairs(answer) do |
170 for _, record in ipairs(answer) do |
171 table.insert(srv_hosts, record.srv); |
171 table.insert(srv_hosts, record.srv); |
172 end |
172 end |
173 table.sort(srv_hosts, compare_srv_priorities); |
173 table.sort(srv_hosts, compare_srv_priorities); |
174 |
174 |
175 local srv_choice = srv_hosts[1]; |
175 local srv_choice = srv_hosts[1]; |
176 self.srv_choice = 1; |
176 self.srv_choice = 1; |
177 if srv_choice then |
177 if srv_choice then |
178 self.connect_host, self.connect_port = srv_choice.target, srv_choice.port; |
178 self.connect_host, self.connect_port = srv_choice.target, srv_choice.port; |
179 self:debug("Best record found, will connect to %s:%d", self.connect_host or self.host, self.connect_port or 5222); |
179 self:debug("Best record found, will connect to %s:%d", self.connect_host or self.host, self.connect_port or 5222); |
180 end |
180 end |
181 |
181 |
182 self:hook("disconnected", function () |
182 self:hook("disconnected", function () |
183 if self.srv_hosts and self.srv_choice < #self.srv_hosts then |
183 if self.srv_hosts and self.srv_choice < #self.srv_hosts then |
184 self.srv_choice = self.srv_choice + 1; |
184 self.srv_choice = self.srv_choice + 1; |
185 local srv_choice = srv_hosts[self.srv_choice]; |
185 local srv_choice = srv_hosts[self.srv_choice]; |
186 self.connect_host, self.connect_port = srv_choice.target, srv_choice.port; |
186 self.connect_host, self.connect_port = srv_choice.target, srv_choice.port; |
187 start_connect(); |
187 start_connect(); |
188 return true; |
188 return true; |
189 end |
189 end |
190 end, 1000); |
190 end, 1000); |
191 |
191 |
192 self:hook("connected", function () |
192 self:hook("connected", function () |
193 self.srv_hosts = nil; |
193 self.srv_hosts = nil; |
194 end, 1000); |
194 end, 1000); |
195 end |
195 end |
196 start_connect(); |
196 start_connect(); |