Outbound presence subscription

Sat, 25 Oct 2008 21:16:08 +0500

author
Waqas Hussain <waqas20@gmail.com>
date
Sat, 25 Oct 2008 21:16:08 +0500
changeset 176
e5cd2a03891d
parent 175
5f71d290bb44
child 177
606c433955e7

Outbound presence subscription

core/rostermanager.lua file | annotate | diff | comparison | revisions
core/sessionmanager.lua file | annotate | diff | comparison | revisions
core/stanza_router.lua file | annotate | diff | comparison | revisions
--- a/core/rostermanager.lua	Sat Oct 25 06:49:48 2008 +0500
+++ b/core/rostermanager.lua	Sat Oct 25 21:16:08 2008 +0500
@@ -96,10 +96,10 @@
 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 @@
 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 @@
 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 @@
 	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
--- a/core/sessionmanager.lua	Sat Oct 25 06:49:48 2008 +0500
+++ b/core/sessionmanager.lua	Sat Oct 25 21:16:08 2008 +0500
@@ -116,6 +116,7 @@
 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 @@
 			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
--- a/core/stanza_router.lua	Sat Oct 25 06:49:48 2008 +0500
+++ b/core/stanza_router.lua	Sat Oct 25 21:16:08 2008 +0500
@@ -196,6 +196,41 @@
 	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 @@
 		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

mercurial