Comparison

core/stanza_router.lua @ 175:5f71d290bb44

Routing code reorganization
author Waqas Hussain <waqas20@gmail.com>
date Sat, 25 Oct 2008 06:49:48 +0500
parent 174:f9aff1fc7e99
child 176:e5cd2a03891d
comparison
equal deleted inserted replaced
174:f9aff1fc7e99 175:5f71d290bb44
6 require "core.servermanager" 6 require "core.servermanager"
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 send_s2s = require "core.s2smanager".send_to_host;
13 function send(session, stanza)
14 if session.type == "c2s" then
15 _send(session, stanza);
16 else
17 local xmlns = stanza.attr.xmlns;
18 --stanza.attr.xmlns = "jabber:server";
19 stanza.attr.xmlns = nil;
20 log("debug", "sending s2s stanza: %s", tostring(stanza));
21 send_s2s(session.host, host, stanza); -- TODO handle remote routing errors
22 stanza.attr.xmlns = xmlns; -- reset
23 end
24 end
13 local user_exists = require "core.usermanager".user_exists; 25 local user_exists = require "core.usermanager".user_exists;
14 26
15 local rostermanager = require "core.rostermanager"; 27 local rostermanager = require "core.rostermanager";
28 local sessionmanager = require "core.sessionmanager";
16 29
17 local s2s_verify_dialback = require "core.s2smanager".verify_dialback; 30 local s2s_verify_dialback = require "core.s2smanager".verify_dialback;
18 local s2s_make_authenticated = require "core.s2smanager".make_authenticated; 31 local s2s_make_authenticated = require "core.s2smanager".make_authenticated;
19 local format = string.format; 32 local format = string.format;
20 local tostring = tostring; 33 local tostring = tostring;
77 if res ~= origin and res.full_jid then -- to resource. FIXME is res.full_jid the correct check? Maybe it should be res.presence 90 if res ~= origin and res.full_jid then -- to resource. FIXME is res.full_jid the correct check? Maybe it should be res.presence
78 stanza.attr.to = res.full_jid; 91 stanza.attr.to = res.full_jid;
79 core_route_stanza(origin, stanza); 92 core_route_stanza(origin, stanza);
80 end 93 end
81 end 94 end
82 if not origin.presence then -- presence probes on initial presence 95 if not origin.presence then -- presence probes on initial presence -- FIXME does unavailable qualify as initial presence?
83 local probe = st.presence({from = origin.full_jid, type = "probe"}); 96 local probe = st.presence({from = origin.full_jid, type = "probe"});
84 for jid in pairs(origin.roster) do -- probe all contacts we are subscribed to 97 for jid in pairs(origin.roster) do -- probe all contacts we are subscribed to
85 local subscription = origin.roster[jid].subscription; 98 local subscription = origin.roster[jid].subscription;
86 if subscription == "both" or subscription == "to" then 99 if subscription == "both" or subscription == "to" then
87 probe.attr.to = jid; 100 probe.attr.to = jid;
159 else 172 else
160 log("warn", "Unhandled origin: %s", origin.type); 173 log("warn", "Unhandled origin: %s", origin.type);
161 end 174 end
162 end 175 end
163 176
164 function is_authorized_to_see_presence(origin, username, host) 177 function send_presence_of_available_resources(user, host, jid, recipient_session)
165 local roster = datamanager.load(username, host, "roster") or {}; 178 local h = hosts[host];
166 local item = roster[origin.username.."@"..origin.host]; 179 local count = 0;
167 return item and (item.subscription == "both" or item.subscription == "from"); 180 if h and h.type == "local" then
181 local u = h.sessions[user];
182 if u then
183 for k, session in pairs(u.sessions) do
184 local pres = session.presence;
185 if pres then
186 pres.attr.to = jid;
187 pres.attr.from = session.full_jid;
188 send(recipient_session, pres);
189 pres.attr.to = nil;
190 pres.attr.from = nil;
191 count = count + 1;
192 end
193 end
194 end
195 end
196 return count;
197 end
198
199 function handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare)
200 local node, host = jid_split(to_bare);
201 if stanza.attr.type == "probe" then
202 if rostermanager.is_contact_subscribed(node, host, from_bare) then
203 if 0 == send_presence_of_available_resources(node, host, from_bare, origin) then
204 -- TODO send last recieved unavailable presence (or we MAY do nothing, which is fine too)
205 end
206 else
207 send(origin, st.presence({from=to_bare, to=from_bare, type="unsubscribed"}));
208 end
209 elseif stanza.attr.type == "subscribe" then
210 if rostermanager.is_contact_subscribed(node, host, from_bare) then
211 send(origin, st.presence({from=to_bare, to=from_bare, type="subscribed"})); -- already subscribed
212 else
213 sessionmanager.send_to_available_resources(node, host, st.presence({from=from_bare, type="subscribe"}));
214 -- TODO store when no resources online
215 end
216 elseif stanza.attr.type == "unsubscribe" then
217 if rostermanager.process_inbound_unsubscribe(node, host, from_bare) then
218 rostermanager.roster_push(node, host, from_bare);
219 end
220 elseif stanza.attr.type == "subscribed" then
221 if rostermanager.process_inbound_subscription_approval(node, host, from_bare) then
222 rostermanager.roster_push(node, host, from_bare);
223 send_presence_of_available_resources(node, host, from_bare, origin);
224 end
225 elseif stanza.attr.type == "unsubscribed" then
226 if rostermanager.process_inbound_subscription_approval(node, host, from_bare) then
227 rostermanager.roster_push(node, host, from_bare);
228 end
229 end -- discard any other type
168 end 230 end
169 231
170 function core_route_stanza(origin, stanza) 232 function core_route_stanza(origin, stanza)
171 -- Hooks 233 -- Hooks
172 --- ...later 234 --- ...later
189 local res = user.sessions[resource]; 251 local res = user.sessions[resource];
190 if not res then 252 if not res then
191 -- if we get here, resource was not specified or was unavailable 253 -- if we get here, resource was not specified or was unavailable
192 if stanza.name == "presence" then 254 if stanza.name == "presence" then
193 if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" then 255 if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" then
194 if stanza.attr.type == "probe" then 256 handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare);
195 if is_authorized_to_see_presence(origin, node, host) then
196 for k in pairs(user.sessions) do -- return presence for all resources
197 local pres = user.sessions[k].presence;
198 if pres then
199 pres.attr.to = from; -- FIXME use from_bare or from?
200 pres.attr.from = user.sessions[k].full_jid;
201 send(origin, pres);
202 end
203 end
204 pres.attr.to = nil;
205 pres.attr.from = nil;
206 else
207 send(origin, st.presence({from=to_bare, to=from_bare, type="unsubscribed"}));
208 end
209 elseif stanza.attr.type == "subscribe" then
210 if rostermanager.is_contact_subscribed(node, host, from_bare) then
211 send(origin, st.presence(from=to_bare, to=from_bare, type="subscribed")); -- already subscribed
212 else
213 local pres = st.presence({from=from_bare}, type="subscribe");
214 for k in pairs(user.sessions) do -- return presence for all resources
215 if user.sessions[k].presence then
216 send(user.sessions[k], pres);
217 end
218 end
219 end
220 elseif stanza.attr.type == "unsubscribe" then
221 if rostermanager.process_inbound_unsubscribe(node, host, from_bare) then
222 rostermanager.roster_push(node, host, from_bare);
223 end
224 elseif stanza.attr.type == "subscribed" then
225 if rostermanager.process_inbound_subscription_approval(node, host, from_bare) then
226 rostermanager.roster_push(node, host, from_bare);
227 for k in pairs(user.sessions) do -- return presence for all resources
228 local pres = user.sessions[k].presence;
229 if pres then
230 pres.attr.to = from; -- FIXME use from_bare or from?
231 pres.attr.from = user.sessions[k].full_jid;
232 send(origin, pres);
233 end
234 end
235 pres.attr.to = nil;
236 pres.attr.from = nil;
237 end
238 elseif stanza.attr.type == "unsubscribed" then
239 if rostermanager.process_inbound_subscription_approval(node, host, from_bare) then
240 rostermanager.roster_push(node, host, from_bare);
241 end
242 end -- discard any other type
243 else -- sender is available or unavailable 257 else -- sender is available or unavailable
244 for k in pairs(user.sessions) do -- presence broadcast to all user resources 258 for k in pairs(user.sessions) do -- presence broadcast to all user resources. FIXME should this be just for available resources? Do we need to check subscription?
245 if user.sessions[k].full_jid then 259 if user.sessions[k].full_jid then
246 stanza.attr.to = user.sessions[k].full_jid; -- reset at the end of function 260 stanza.attr.to = user.sessions[k].full_jid; -- reset at the end of function
247 send(user.sessions[k], stanza); 261 send(user.sessions[k], stanza);
248 end 262 end
249 end 263 end
267 end 281 end
268 else 282 else
269 -- user not online 283 -- user not online
270 if user_exists(node, host) then 284 if user_exists(node, host) then
271 if stanza.name == "presence" then 285 if stanza.name == "presence" then
272 if stanza.attr.type == "probe" and is_authorized_to_see_presence(origin, node, host) then -- FIXME what to do for not c2s? 286 if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" then
273 -- TODO send last recieved unavailable presence (or we MAY do nothing, which is fine too) 287 handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare);
274 else 288 else
275 -- TODO send unavailable presence 289 -- TODO send unavailable presence or unsubscribed
276 end 290 end
277 elseif stanza.name == "message" then 291 elseif stanza.name == "message" then
278 -- TODO send message error, or store offline messages 292 -- TODO send message error, or store offline messages
279 elseif stanza.name == "iq" then 293 elseif stanza.name == "iq" then
280 -- TODO send IQ error 294 -- TODO send IQ error