aboutsummaryrefslogtreecommitdiffstats
path: root/core/stanza_router.lua
diff options
context:
space:
mode:
authorMatthew Wild <mwild1@gmail.com>2008-10-26 13:19:09 +0000
committerMatthew Wild <mwild1@gmail.com>2008-10-26 13:19:09 +0000
commit4d5a2486b5e283a4d464fd19b74c2500903a009c (patch)
tree6a4bedaa461bcac7f7c4921d752fd49fb2efa1b8 /core/stanza_router.lua
parent08940b23081e7328f25099816f54e8bcd9d280ae (diff)
parent1746f7eea0135b89a4f871d11c71cded04c4c0c3 (diff)
downloadprosody-4d5a2486b5e283a4d464fd19b74c2500903a009c.tar.gz
prosody-4d5a2486b5e283a4d464fd19b74c2500903a009c.zip
Merge presence/subscription support from waqas
Diffstat (limited to 'core/stanza_router.lua')
-rw-r--r--core/stanza_router.lua182
1 files changed, 143 insertions, 39 deletions
diff --git a/core/stanza_router.lua b/core/stanza_router.lua
index 44c2a82b..dfb91ee3 100644
--- a/core/stanza_router.lua
+++ b/core/stanza_router.lua
@@ -8,10 +8,25 @@ require "core.servermanager"
local log = require "util.logger".init("stanzarouter")
local st = require "util.stanza";
-local send = require "core.sessionmanager".send_to_session;
+local _send = require "core.sessionmanager".send_to_session;
local send_s2s = require "core.s2smanager".send_to_host;
+function send(session, stanza)
+ if session.type == "c2s" then
+ _send(session, stanza);
+ else
+ local xmlns = stanza.attr.xmlns;
+ --stanza.attr.xmlns = "jabber:server";
+ stanza.attr.xmlns = nil;
+ log("debug", "sending s2s stanza: %s", tostring(stanza));
+ send_s2s(session.host, host, stanza); -- TODO handle remote routing errors
+ stanza.attr.xmlns = xmlns; -- reset
+ end
+end
local user_exists = require "core.usermanager".user_exists;
+local rostermanager = require "core.rostermanager";
+local sessionmanager = require "core.sessionmanager";
+
local s2s_verify_dialback = require "core.s2smanager".verify_dialback;
local s2s_make_authenticated = require "core.s2smanager".make_authenticated;
local format = string.format;
@@ -44,7 +59,13 @@ function core_process_stanza(origin, stanza)
end
if not to then
- core_handle_stanza(origin, stanza);
+ core_handle_stanza(origin, stanza);
+ elseif origin.type == "c2s" and stanza.name == "presence" and stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" then
+ local node, host = jid_split(stanza.attr.to);
+ local to_bare = node and (node.."@"..host) or host; -- bare JID
+ local from_node, from_host = jid_split(stanza.attr.from);
+ local from_bare = from_node and (from_node.."@"..from_host) or from_host; -- bare JID
+ handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare);
elseif hosts[to] and hosts[to].type == "local" then
core_handle_stanza(origin, stanza);
elseif stanza.name == "iq" and not select(3, jid_split(to)) then
@@ -77,7 +98,7 @@ function core_handle_stanza(origin, stanza)
core_route_stanza(origin, stanza);
end
end
- if not origin.presence then -- presence probes on initial presence
+ if not origin.presence then -- presence probes on initial presence -- FIXME does unavailable qualify as initial presence?
local probe = st.presence({from = origin.full_jid, type = "probe"});
for jid in pairs(origin.roster) do -- probe all contacts we are subscribed to
local subscription = origin.roster[jid].subscription;
@@ -162,10 +183,110 @@ function core_handle_stanza(origin, stanza)
end
end
-function is_authorized_to_see_presence(origin, username, host)
- local roster = datamanager.load(username, host, "roster") or {};
- local item = roster[origin.username.."@"..origin.host];
- return item and (item.subscription == "both" or item.subscription == "from");
+function send_presence_of_available_resources(user, host, jid, recipient_session)
+ local h = hosts[host];
+ local count = 0;
+ if h and h.type == "local" then
+ local u = h.sessions[user];
+ if u then
+ for k, session in pairs(u.sessions) do
+ local pres = session.presence;
+ if pres then
+ pres.attr.to = jid;
+ pres.attr.from = session.full_jid;
+ send(recipient_session, pres);
+ pres.attr.to = nil;
+ pres.attr.from = nil;
+ count = count + 1;
+ end
+ end
+ end
+ end
+ return count;
+end
+
+function handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare)
+ local node, host = jid_split(from_bare);
+ local st_from, st_to = stanza.attr.from, stanza.attr.to;
+ stanza.attr.from, stanza.attr.to = from_bare, to_bare;
+ if stanza.attr.type == "subscribe" then
+ log("debug", "outbound subscribe from "..from_bare.." for "..to_bare);
+ -- 1. route stanza
+ -- 2. roster push (subscription = none, ask = subscribe)
+ if rostermanager.set_contact_pending_out(node, host, to_bare) then
+ rostermanager.roster_push(node, host, to_bare);
+ end -- else file error
+ core_route_stanza(origin, stanza);
+ elseif stanza.attr.type == "unsubscribe" then
+ log("debug", "outbound unsubscribe from "..from_bare.." for "..to_bare);
+ -- 1. route stanza
+ -- 2. roster push (subscription = none or from)
+ if rostermanager.unsubscribe(node, host, to_bare) then
+ rostermanager.roster_push(node, host, to_bare); -- FIXME do roster push when roster has in fact not changed?
+ end -- else file error
+ core_route_stanza(origin, stanza);
+ elseif stanza.attr.type == "subscribed" then
+ log("debug", "outbound subscribed from "..from_bare.." for "..to_bare);
+ -- 1. route stanza
+ -- 2. roster_push ()
+ -- 3. send_presence_of_available_resources
+ if rostermanager.subscribed(node, host, to_bare) then
+ rostermanager.roster_push(node, host, to_bare);
+ core_route_stanza(origin, stanza);
+ send_presence_of_available_resources(node, host, to_bare, origin);
+ end
+ elseif stanza.attr.type == "unsubscribed" then
+ log("debug", "outbound unsubscribed from "..from_bare.." for "..to_bare);
+ -- 1. route stanza
+ -- 2. roster push (subscription = none or to)
+ if rostermanager.unsubscribed(node, host, to_bare) then
+ rostermanager.roster_push(node, host, to_bare);
+ core_route_stanza(origin, stanza);
+ end
+ end
+ stanza.attr.from, stanza.attr.to = st_from, st_to;
+end
+
+function handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare)
+ local node, host = jid_split(to_bare);
+ local st_from, st_to = stanza.attr.from, stanza.attr.to;
+ stanza.attr.from, stanza.attr.to = from_bare, to_bare;
+ if stanza.attr.type == "probe" then
+ if rostermanager.is_contact_subscribed(node, host, from_bare) then
+ if 0 == send_presence_of_available_resources(node, host, from_bare, origin) then
+ -- TODO send last recieved unavailable presence (or we MAY do nothing, which is fine too)
+ end
+ else
+ core_route_stanza(origin, st.presence({from=to_bare, to=from_bare, type="unsubscribed"}));
+ end
+ elseif stanza.attr.type == "subscribe" then
+ log("debug", "inbound subscribe from "..from_bare.." for "..to_bare);
+ if rostermanager.is_contact_subscribed(node, host, from_bare) then
+ core_route_stanza(origin, st.presence({from=to_bare, to=from_bare, type="subscribed"})); -- already subscribed
+ else
+ if not rostermanager.is_contact_pending_in(node, host, from_bare) then
+ if rostermanager.set_contact_pending_in(node, host, from_bare) then
+ sessionmanager.send_to_available_resources(node, host, stanza);
+ end -- TODO else return error, unable to save
+ end
+ end
+ elseif stanza.attr.type == "unsubscribe" then
+ log("debug", "inbound unsubscribe from "..from_bare.." for "..to_bare);
+ if rostermanager.process_inbound_unsubscribe(node, host, from_bare) then
+ rostermanager.roster_push(node, host, from_bare);
+ end
+ elseif stanza.attr.type == "subscribed" then
+ log("debug", "inbound subscribed from "..from_bare.." for "..to_bare);
+ if rostermanager.process_inbound_subscription_approval(node, host, from_bare) then
+ rostermanager.roster_push(node, host, from_bare);
+ end
+ elseif stanza.attr.type == "unsubscribed" then
+ log("debug", "inbound unsubscribed from "..from_bare.." for "..to_bare);
+ if rostermanager.process_inbound_subscription_approval(node, host, from_bare) then
+ rostermanager.roster_push(node, host, from_bare);
+ end
+ end -- discard any other type
+ stanza.attr.from, stanza.attr.to = st_from, st_to;
end
function core_route_stanza(origin, stanza)
@@ -175,6 +296,10 @@ function core_route_stanza(origin, stanza)
-- Deliver
local to = stanza.attr.to;
local node, host, resource = jid_split(to);
+ local to_bare = node and (node.."@"..host) or host; -- bare JID
+ local from = stanza.attr.from;
+ local from_node, from_host, from_resource = jid_split(from);
+ local from_bare = from_node and (from_node.."@"..from_host) or from_host; -- bare JID
if stanza.name == "presence" and (stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable") then resource = nil; end
@@ -188,34 +313,11 @@ function core_route_stanza(origin, stanza)
-- if we get here, resource was not specified or was unavailable
if stanza.name == "presence" then
if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" then
- if stanza.attr.type == "probe" then
- if is_authorized_to_see_presence(origin, node, host) then
- for k in pairs(user.sessions) do -- return presence for all resources
- if user.sessions[k].presence then
- local pres = user.sessions[k].presence;
- pres.attr.to = origin.full_jid;
- pres.attr.from = user.sessions[k].full_jid;
- send(origin, pres);
- pres.attr.to = nil;
- pres.attr.from = nil;
- end
- end
- else
- send(origin, st.presence({from=user.."@"..host, to=origin.username.."@"..origin.host, type="unsubscribed"}));
- end
- elseif stanza.attr.type == "subscribe" then
- -- TODO
- elseif stanza.attr.type == "unsubscribe" then
- -- TODO
- elseif stanza.attr.type == "subscribed" then
- -- TODO
- elseif stanza.attr.type == "unsubscribed" then
- -- TODO
- end -- discard any other type
+ handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare);
else -- sender is available or unavailable
- for k in pairs(user.sessions) do -- presence broadcast to all user resources
+ 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?
if user.sessions[k].full_jid then
- stanza.attr.to = user.sessions[k].full_jid;
+ stanza.attr.to = user.sessions[k].full_jid; -- reset at the end of function
send(user.sessions[k], stanza);
end
end
@@ -234,17 +336,17 @@ function core_route_stanza(origin, stanza)
end
else
-- User + resource is online...
- stanza.attr.to = res.full_jid;
+ stanza.attr.to = res.full_jid; -- reset at the end of function
send(res, stanza); -- Yay \o/
end
else
-- user not online
if user_exists(node, host) then
if stanza.name == "presence" then
- if stanza.attr.type == "probe" and is_authorized_to_see_presence(origin, node, host) then -- FIXME what to do for not c2s?
- -- TODO send last recieved unavailable presence
+ if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" then
+ handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare);
else
- -- TODO send unavailable presence
+ -- TODO send unavailable presence or unsubscribed
end
elseif stanza.name == "message" then
-- TODO send message error, or store offline messages
@@ -255,7 +357,7 @@ function core_route_stanza(origin, stanza)
-- TODO we would get here for nodeless JIDs too. Do something fun maybe? Echo service? Let plugins use xmpp:server/resource addresses?
if stanza.name == "presence" then
if stanza.attr.type == "probe" then
- send(origin, st.presence({from = stanza.attr.to, to = stanza.attr.from, type = "unsubscribed"}));
+ send(origin, st.presence({from = to_bare, to = from_bare, type = "unsubscribed"}));
end
-- else ignore
else
@@ -265,10 +367,12 @@ function core_route_stanza(origin, stanza)
end
elseif origin.type == "c2s" then
-- Remote host
+ local xmlns = stanza.attr.xmlns;
--stanza.attr.xmlns = "jabber:server";
stanza.attr.xmlns = nil;
log("debug", "sending s2s stanza: %s", tostring(stanza));
- send_s2s(origin.host, host, stanza);
+ send_s2s(origin.host, host, stanza); -- TODO handle remote routing errors
+ stanza.attr.xmlns = xmlns; -- reset
else
log("warn", "received stanza from unhandled connection type: %s", origin.type);
end