core/stanza_router.lua

changeset 121
74e5919e4737
parent 119
b48a573608e8
child 122
21f8d2175393
child 128
77a1778b16e8
equal deleted inserted replaced
120:ef964468f174 121:74e5919e4737
7 7
8 local log = require "util.logger".init("stanzarouter") 8 local log = require "util.logger".init("stanzarouter")
9 9
10 local st = require "util.stanza"; 10 local st = require "util.stanza";
11 local send = require "core.sessionmanager".send_to_session; 11 local send = require "core.sessionmanager".send_to_session;
12 local send_s2s = require "core.s2smanager".send_to_host;
12 local user_exists = require "core.usermanager".user_exists; 13 local user_exists = require "core.usermanager".user_exists;
13 14
14 local jid_split = require "util.jid".split; 15 local jid_split = require "util.jid".split;
15 local print = print; 16 local print = print;
16 17
45 elseif origin.type == "c2s" then 46 elseif origin.type == "c2s" then
46 core_route_stanza(origin, stanza); 47 core_route_stanza(origin, stanza);
47 end 48 end
48 end 49 end
49 50
51 -- This function handles stanzas which are not routed any further,
52 -- that is, they are handled by this server
50 function core_handle_stanza(origin, stanza) 53 function core_handle_stanza(origin, stanza)
51 -- Handlers 54 -- Handlers
52 if origin.type == "c2s" or origin.type == "c2s_unauthed" then 55 if origin.type == "c2s" or origin.type == "c2s_unauthed" then
53 local session = origin; 56 local session = origin;
54 57
149 send(res, stanza); 152 send(res, stanza);
150 else 153 else
151 -- TODO send IQ error 154 -- TODO send IQ error
152 end 155 end
153 else 156 else
157 -- User + resource is online...
154 stanza.attr.to = res.full_jid; 158 stanza.attr.to = res.full_jid;
155 send(res, stanza); -- Yay \o/ 159 send(res, stanza); -- Yay \o/
156 end 160 end
157 else 161 else
158 -- user not online 162 -- user not online
189 end 193 end
190 end 194 end
191 stanza.attr.to = to; -- reset 195 stanza.attr.to = to; -- reset
192 end 196 end
193 197
194 function handle_stanza_nodest(stanza)
195 if stanza.name == "iq" then
196 handle_stanza_iq_no_to(session, stanza);
197 elseif stanza.name == "presence" then
198 -- Broadcast to this user's contacts
199 handle_stanza_presence_broadcast(session, stanza);
200 -- also, if it is initial presence, send out presence probes
201 if not session.last_presence then
202 handle_stanza_presence_probe_broadcast(session, stanza);
203 end
204 session.last_presence = stanza;
205 elseif stanza.name == "message" then
206 -- Treat as if message was sent to bare JID of the sender
207 handle_stanza_to_local_user(stanza);
208 end
209 end
210
211 function handle_stanza_tolocal(stanza)
212 local node, host, resource = jid.split(stanza.attr.to);
213 if host and hosts[host] and hosts[host].type == "local" then
214 -- Is a local host, handle internally
215 if node then
216 -- Is a local user, send to their session
217 log("debug", "Routing stanza to %s@%s", node, host);
218 if not session.username then return; end --FIXME: Correct response when trying to use unauthed stream is what?
219 handle_stanza_to_local_user(stanza);
220 else
221 -- Is sent to this server, let's handle it...
222 log("debug", "Routing stanza to %s", host);
223 handle_stanza_to_server(stanza, session);
224 end
225 end
226 end
227
228 function handle_stanza_toremote(stanza) 198 function handle_stanza_toremote(stanza)
229 log("error", "Stanza bound for remote host, but s2s is not implemented"); 199 log("error", "Stanza bound for remote host, but s2s is not implemented");
230 end 200 end
231
232
233 --[[
234 local function route_c2s_stanza(session, stanza)
235 stanza.attr.from = session.full_jid;
236 if not stanza.attr.to and session.username then
237 -- Has no 'to' attribute, handle internally
238 if stanza.name == "iq" then
239 handle_stanza_iq_no_to(session, stanza);
240 elseif stanza.name == "presence" then
241 -- Broadcast to this user's contacts
242 handle_stanza_presence_broadcast(session, stanza);
243 -- also, if it is initial presence, send out presence probes
244 if not session.last_presence then
245 handle_stanza_presence_probe_broadcast(session, stanza);
246 end
247 session.last_presence = stanza;
248 elseif stanza.name == "message" then
249 -- Treat as if message was sent to bare JID of the sender
250 handle_stanza_to_local_user(stanza);
251 end
252 end
253 local node, host, resource = jid.split(stanza.attr.to);
254 if host and hosts[host] and hosts[host].type == "local" then
255 -- Is a local host, handle internally
256 if node then
257 -- Is a local user, send to their session
258 if not session.username then return; end --FIXME: Correct response when trying to use unauthed stream is what?
259 handle_stanza_to_local_user(stanza);
260 else
261 -- Is sent to this server, let's handle it...
262 handle_stanza_to_server(stanza, session);
263 end
264 else
265 -- Is not for us or a local user, route accordingly
266 route_s2s_stanza(stanza);
267 end
268 end
269
270 function handle_stanza_no_to(session, stanza)
271 if not stanza.attr.id then log("warn", "<iq> without id attribute is invalid"); end
272 local xmlns = (stanza.tags[1].attr and stanza.tags[1].attr.xmlns);
273 if stanza.attr.type == "get" or stanza.attr.type == "set" then
274 if iq_handlers[xmlns] then
275 if iq_handlers[xmlns](stanza) then return; end; -- If handler returns true, it handled it
276 end
277 -- Oh, handler didn't handle it. Need to send service-unavailable now.
278 log("warn", "Unhandled namespace: "..xmlns);
279 session:send(format("<iq type='error' id='%s'><error type='cancel'><service-unavailable/></error></iq>", stanza.attr.id));
280 return; -- All done!
281 end
282 end
283
284 function handle_stanza_to_local_user(stanza)
285 if stanza.name == "message" then
286 handle_stanza_message_to_local_user(stanza);
287 elseif stanza.name == "presence" then
288 handle_stanza_presence_to_local_user(stanza);
289 elseif stanza.name == "iq" then
290 handle_stanza_iq_to_local_user(stanza);
291 end
292 end
293
294 function handle_stanza_message_to_local_user(stanza)
295 local node, host, resource = stanza.to.node, stanza.to.host, stanza.to.resource;
296 local destuser = hosts[host].sessions[node];
297 if destuser then
298 if resource and destuser[resource] then
299 destuser[resource]:send(stanza);
300 else
301 -- Bare JID, or resource offline
302 local best_session;
303 for resource, session in pairs(destuser.sessions) do
304 if not best_session then best_session = session;
305 elseif session.priority >= best_session.priority and session.priority >= 0 then
306 best_session = session;
307 end
308 end
309 if not best_session then
310 offlinemessage.new(node, host, stanza);
311 else
312 print("resource '"..resource.."' was not online, have chosen to send to '"..best_session.username.."@"..best_session.host.."/"..best_session.resource.."'");
313 destuser[best_session]:send(stanza);
314 end
315 end
316 else
317 -- User is offline
318 offlinemessage.new(node, host, stanza);
319 end
320 end
321
322 function handle_stanza_presence_to_local_user(stanza)
323 local node, host, resource = stanza.to.node, stanza.to.host, stanza.to.resource;
324 local destuser = hosts[host].sessions[node];
325 if destuser then
326 if resource then
327 if destuser[resource] then
328 destuser[resource]:send(stanza);
329 else
330 return;
331 end
332 else
333 -- Broadcast to all user's resources
334 for resource, session in pairs(destuser.sessions) do
335 session:send(stanza);
336 end
337 end
338 end
339 end
340
341 function handle_stanza_iq_to_local_user(stanza)
342
343 end
344
345 function foo()
346 local node, host, resource = stanza.to.node, stanza.to.host, stanza.to.resource;
347 local destuser = hosts[host].sessions[node];
348 if destuser and destuser.sessions then
349 -- User online
350 if resource and destuser.sessions[resource] then
351 stanza.to:send(stanza);
352 else
353 --User is online, but specified resource isn't (or no resource specified)
354 local best_session;
355 for resource, session in pairs(destuser.sessions) do
356 if not best_session then best_session = session;
357 elseif session.priority >= best_session.priority and session.priority >= 0 then
358 best_session = session;
359 end
360 end
361 if not best_session then
362 offlinemessage.new(node, host, stanza);
363 else
364 print("resource '"..resource.."' was not online, have chosen to send to '"..best_session.username.."@"..best_session.host.."/"..best_session.resource.."'");
365 resource = best_session.resource;
366 end
367 end
368 if destuser.sessions[resource] == session then
369 log("warn", "core", "Attempt to send stanza to self, dropping...");
370 else
371 print("...sending...", tostring(stanza));
372 --destuser.sessions[resource].conn.write(tostring(data));
373 print(" to conn ", destuser.sessions[resource].conn);
374 destuser.sessions[resource].conn.write(tostring(stanza));
375 print("...sent")
376 end
377 elseif stanza.name == "message" then
378 print(" ...will be stored offline");
379 offlinemessage.new(node, host, stanza);
380 elseif stanza.name == "iq" then
381 print(" ...is an iq");
382 stanza.from:send(st.reply(stanza)
383 :tag("error", { type = "cancel" })
384 :tag("service-unavailable", { xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas" }));
385 end
386 end
387
388 -- Broadcast a presence stanza to all of a user's contacts
389 function handle_stanza_presence_broadcast(session, stanza)
390 if session.roster then
391 local initial_presence = not session.last_presence;
392 session.last_presence = stanza;
393
394 -- Broadcast presence and probes
395 local broadcast = st.presence({ from = session.full_jid, type = stanza.attr.type });
396
397 for child in stanza:childtags() do
398 broadcast:add_child(child);
399 end
400 for contact_jid in pairs(session.roster) do
401 broadcast.attr.to = contact_jid;
402 send_to(contact_jid, broadcast);
403 if initial_presence then
404 local node, host = jid.split(contact_jid);
405 if hosts[host] and hosts[host].type == "local" then
406 local contact = hosts[host].sessions[node]
407 if contact then
408 local pres = st.presence { to = session.full_jid };
409 for resource, contact_session in pairs(contact.sessions) do
410 if contact_session.last_presence then
411 pres.tags = contact_session.last_presence.tags;
412 pres.attr.from = contact_session.full_jid;
413 send(pres);
414 end
415 end
416 end
417 --FIXME: Do we send unavailable if they are offline?
418 else
419 probe.attr.to = contact;
420 send_to(contact, probe);
421 end
422 end
423 end
424
425 -- Probe for our contacts' presence
426 end
427 end
428
429 -- Broadcast presence probes to all of a user's contacts
430 function handle_stanza_presence_probe_broadcast(session, stanza)
431 end
432
433 --
434 function handle_stanza_to_server(stanza)
435 end
436
437 function handle_stanza_iq_no_to(session, stanza)
438 end
439 ]]

mercurial