From 091e961c40b6d89f548efecea07e641e3f9c4210 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Sat, 25 Oct 2008 21:16:08 +0500 Subject: Outbound presence subscription --- core/rostermanager.lua | 136 +++++++++++++++++++++++++++++++++++++++++++++--- core/sessionmanager.lua | 3 ++ core/stanza_router.lua | 42 ++++++++++++++- 3 files changed, 171 insertions(+), 10 deletions(-) (limited to 'core') diff --git a/core/rostermanager.lua b/core/rostermanager.lua index 7d7fd061..ffc4f481 100644 --- a/core/rostermanager.lua +++ b/core/rostermanager.lua @@ -96,10 +96,10 @@ end function process_inbound_subscription_approval(username, host, jid) local roster = load_roster(username, host); local item = roster[jid]; - if item and item.ask and (item.subscription == "none" or item.subscription == "from") then + if item and item.ask then if item.subscription == "none" then item.subscription = "to"; - else + else -- subscription == from item.subscription = "both"; end item.ask = nil; @@ -110,13 +110,21 @@ end function process_inbound_subscription_cancellation(username, host, jid) local roster = load_roster(username, host); local item = roster[jid]; - if item and (item.subscription == "to" or item.subscription == "both") then + local changed = nil; + if is_contact_pending_out(username, host, jid) then + item.ask = nil; + changed = true; + end + if item then if item.subscription == "to" then item.subscription = "none"; - else + changed = true; + elseif item.subscription == "both" then item.subscription = "from"; + changed = true; end - -- FIXME do we need to item.ask = nil;? + end + if changed then return datamanager.store(username, host, "roster", roster); end end @@ -124,13 +132,21 @@ end function process_inbound_unsubscribe(username, host, jid) local roster = load_roster(username, host); local item = roster[jid]; - if item and (item.subscription == "from" or item.subscription == "both") then + local changed = nil; + if is_contact_pending_in(username, host, jid) then + roster.pending[jid] = nil; -- TODO maybe delete roster.pending if empty? + changed = true; + end + if item then if item.subscription == "from" then item.subscription = "none"; - else + changed = true; + elseif item.subscription == "both" then item.subscription = "to"; + changed = true; end - item.ask = nil; + end + if changed then return datamanager.store(username, host, "roster", roster); end end @@ -141,4 +157,108 @@ function is_contact_subscribed(username, host, jid) return item and (item.subscription == "from" or item.subscription == "both"); end +function is_contact_pending_in(username, host, jid) + local roster = load_roster(username, host); + return roster.pending or roster.pending[jid]; +end +function set_contact_pending_in(username, host, jid, pending) + local roster = load_roster(username, host); + local item = roster[jid]; + if item and (item.subscription == "from" or item.subscription == "both") then + return; -- false + end + if not roster.pending then roster.pending = {}; end + roster.pending[jid] = true; + return datamanager.store(username, host, "roster", roster); +end +function is_contact_pending_out(username, host, jid) + local roster = load_roster(username, host); + local item = roster[jid]; + return item and item.ask; +end +function set_contact_pending_out(username, host, jid) -- subscribe + local roster = load_roster(username, host); + local item = roster[jid]; + if item and (item.ask or item.subscription == "to" or item.subscription == "both") then + return true; + end + if not item then + item = {subscription = "none"}; + roster[jid] = item; + end + item.ask = "subscribe"; + return datamanager.store(username, host, "roster", roster); +end +function unsubscribe(username, host, jid) + local roster = load_roster(username, host); + local item = roster[jid]; + if not item then return false; end + if (item.subscription == "from" or item.subscription == "none") and not item.ask then + return true; + end + item.ask = nil; + if item.subscription == "both" then + item.subscription = "from"; + elseif item.subscription == "to" then + item.subscription = "none"; + end + return datamanager.store(username, host, "roster", roster); +end +function subscribed(username, host, jid) + if is_contact_pending_in(username, host, jid) then + local roster = load_roster(username, host); + local item = roster[jid]; + if item.subscription == "none" then + item.subscription = "from"; + else -- subscription == to + item.subsctiption = "both"; + end + roster.pending[jid] = nil; + -- TODO maybe remove roster.pending if empty + return datamanager.store(username, host, "roster", roster); + end -- TODO else implement optional feature pre-approval (ask = subscribed) +end +function unsubscribed(username, host, jid) + local roster = load_roster(username, host); + local item = roster[jid]; + local pending = is_contact_pending_in(username, host, jid); + local changed = nil; + if is_contact_pending_in(username, host, jid) then + roster.pending[jid] = nil; -- TODO maybe delete roster.pending if empty? + changed = true; + end + if item then + if item.subscription == "from" then + item.subscription = "none"; + changed = true; + elseif item.subscription == both then + item.subscription = "to"; + changed = true; + end + end + if changed then + return datamanager.store(username, host, "roster", roster); + end +end + +function process_outbound_subscription_request(username, host, jid) + local roster = load_roster(username, host); + local item = roster[jid]; + if item and (item.subscription == "none" or item.subscription == "from") then + item.ask = "subscribe"; + return datamanager.store(username, host, "roster", roster); + end +end + +--[[function process_outbound_subscription_approval(username, host, jid) + local roster = load_roster(username, host); + local item = roster[jid]; + if item and (item.subscription == "none" or item.subscription == "from" then + item.ask = "subscribe"; + return datamanager.store(username, host, "roster", roster); + end +end]] + + + return _M; \ No newline at end of file diff --git a/core/sessionmanager.lua b/core/sessionmanager.lua index db898693..82a001c1 100644 --- a/core/sessionmanager.lua +++ b/core/sessionmanager.lua @@ -116,6 +116,7 @@ function streamopened(session, attr) end function send_to_available_resources(user, host, stanza) + local count = 0; local to = stanza.attr.to; stanza.attr.to = nil; local h = hosts[host]; @@ -125,11 +126,13 @@ function send_to_available_resources(user, host, stanza) for k, session in pairs(u.sessions) do if session.presence then session.send(stanza); + count = count + 1; end end end end stanza.attr.to = to; + return count; end return _M; \ No newline at end of file diff --git a/core/stanza_router.lua b/core/stanza_router.lua index a5dfa6ce..8293747a 100644 --- a/core/stanza_router.lua +++ b/core/stanza_router.lua @@ -196,6 +196,41 @@ function send_presence_of_available_resources(user, host, jid, recipient_session return count; end +function handle_outbound_presence_subscriptions(origin, stanza, from_bare, to_bare) + local node, host = jid_split(to_bare); + if stanza.attr.type == "subscribe" then + -- 1. route stanza + -- 2. roster push (subscription = none, ask = subscribe) + if rostermanager.set_contact_pending_out(node, host, from_bare) then + rostermanager.roster_push(node, host, from_bare); + end -- else file error + core_route_stanza(origin, st.presence({from=from_bare, to=to_bare, type="subscribe"})); + elseif stanza.attr.type == "unsubscribe" then + -- 1. route stanza + -- 2. roster push (subscription = none or from) + if rostermanager.unsubscribe(node, host, from_bare) then + rostermanager.roster_push(node, host, from_bare); -- FIXME do roster push when roster has in fact not changed? + end -- else file error + core_route_stanza(origin, st.presence({from=from_bare, to=to_bare, type="unsubscribe"})); + elseif stanza.attr.type == "subscribed" then + -- 1. route stanza + -- 2. roster_push () + -- 3. send_presence_of_available_resources + if rostermanager.subscribed(node, host, from_bare) then + rostermanager.roster_push(node, host, from_bare); + core_route_stanza(origin, st.presence({from=from_bare, to=to_bare, type="subscribed"})); + send_presence_of_available_resources(user, host, from_bare, origin); + end + elseif stanza.attr.type == "unsubscribed" then + -- 1. route stanza + -- 2. roster push (subscription = none or to) + if rostermanager.unsubscribed(node, host, from_bare) then + rostermanager.roster_push(node, host, from_bare); + core_route_stanza(origin, st.presence({from=from_bare, to=to_bare, type="unsubscribed"})); + end + end +end + function handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare) local node, host = jid_split(to_bare); if stanza.attr.type == "probe" then @@ -210,8 +245,11 @@ function handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_b if rostermanager.is_contact_subscribed(node, host, from_bare) then send(origin, st.presence({from=to_bare, to=from_bare, type="subscribed"})); -- already subscribed else - sessionmanager.send_to_available_resources(node, host, st.presence({from=from_bare, type="subscribe"})); - -- TODO store when no resources online + if not rostermanager.is_contact_pending(node, host, from_bare) then + if rostermanager.set_contact_pending(node, host, from_bare) then + sessionmanager.send_to_available_resources(node, host, st.presence({from=from_bare, type="subscribe"})); + end -- TODO else return error, unable to save + end end elseif stanza.attr.type == "unsubscribe" then if rostermanager.process_inbound_unsubscribe(node, host, from_bare) then -- cgit v1.2.3