Merge with waqas for MUC/routing fixes

Wed, 11 Feb 2009 18:30:44 +0000

author
Matthew Wild <mwild1@gmail.com>
date
Wed, 11 Feb 2009 18:30:44 +0000
changeset 785
31d5be1371cf
parent 776
89eb9f59993c (current diff)
parent 784
1de8a32f81e9 (diff)
child 786
f2dc6118b3f4

Merge with waqas for MUC/routing fixes

core/stanza_router.lua file | annotate | diff | comparison | revisions
--- a/core/componentmanager.lua	Wed Feb 11 16:09:48 2009 +0000
+++ b/core/componentmanager.lua	Wed Feb 11 18:30:44 2009 +0000
@@ -27,21 +27,13 @@
 		
 	for host, host_config in pairs(defined_hosts) do
 		if host ~= "*" and ((host_config.core.enabled == nil or host_config.core.enabled) and type(host_config.core.component_module) == "string") then
-			hosts[host] = { type = "component", host = host, connected = true, s2sout = {} };
-			modulemanager.load(host, "dialback");
+			hosts[host] = { type = "component", host = host, connected = false, s2sout = {} };
 			local ok, err = modulemanager.load(host, host_config.core.component_module);
 			if not ok then
 				log("error", "Error loading %s component %s: %s", tostring(host_config.core.component_module), tostring(host), tostring(err));
 			else
 				log("info", "Activated %s component: %s", host_config.core.component_module, host);
 			end
-			
-			local ok, component_handler = modulemanager.call_module_method(modulemanager.get_module(host, host_config.core.component_module), "load_component");
-			if not ok then
-				log("error", "Error loading %s component %s: %s", tostring(host_config.core.component_module), tostring(host), tostring(component_handler));
-			else
-				components[host] = component_handler;
-			end
 		end
 	end
 end
@@ -63,7 +55,7 @@
 end
 
 function register_component(host, component)
-	if not hosts[host] then
+	if not hosts[host] or (hosts[host].type == 'component' and not hosts[host].connected) then
 		-- TODO check for host well-formedness
 		components[host] = component;
 		hosts[host] = { type = "component", host = host, connected = true, s2sout = {} };
--- a/core/modulemanager.lua	Wed Feb 11 16:09:48 2009 +0000
+++ b/core/modulemanager.lua	Wed Feb 11 18:30:44 2009 +0000
@@ -112,6 +112,7 @@
 	local pluginenv = setmetatable({ module = api_instance }, { __index = _G });
 	
 	setfenv(mod, pluginenv);
+	if not hosts[host] then hosts[host] = { type = "component", host = host, connected = false, s2sout = {} }; end
 	
 	local success, ret = pcall(mod);
 	if not success then
--- a/core/presencemanager.lua	Wed Feb 11 16:09:48 2009 +0000
+++ b/core/presencemanager.lua	Wed Feb 11 18:30:44 2009 +0000
@@ -97,7 +97,7 @@
 		if stanza.attr.type == "unavailable" then
 			origin.presence = nil;
 			if origin.directed then
-				for _, jid in ipairs(origin.directed) do
+				for jid in pairs(origin.directed) do
 					stanza.attr.to = jid;
 					core_route_stanza(origin, stanza);
 				end
--- a/core/stanza_router.lua	Wed Feb 11 16:09:48 2009 +0000
+++ b/core/stanza_router.lua	Wed Feb 11 18:30:44 2009 +0000
@@ -34,6 +34,8 @@
 local t_insert = table.insert;
 local tonumber = tonumber;
 local s_find = string.find;
+local pairs = pairs;
+local ipairs = ipairs;
 
 local jid_split = require "util.jid".split;
 local jid_prepped_split = require "util.jid".prepped_split;
@@ -105,6 +107,11 @@
 				return; -- FIXME what should we do here? does this work with subdomains?
 			end
 		end
+		if origin.type == "c2s" and stanza.name == "presence" and to ~= nil and not(origin.roster[to_bare] and (origin.roster[to_bare].subscription == "both" or origin.roster[to_bare].subscription == "from")) then -- directed presence
+			origin.directed = origin.directed or {};
+			origin.directed[to] = true;
+			--t_insert(origin.directed, to); -- FIXME does it make more sense to add to_bare rather than to?
+		end
 		if not to then
 			core_handle_stanza(origin, stanza);
 		elseif hosts[to] and hosts[to].type == "local" then -- directed at a local server
@@ -122,10 +129,6 @@
 		elseif origin.type ~= "c2s" and stanza.name == "iq" and not resource then -- directed at bare JID
 			core_handle_stanza(origin, stanza);
 		else
-			if origin.type == "c2s" and stanza.name == "presence" and to ~= nil and not(origin.roster[to_bare] and (origin.roster[to_bare].subscription == "both" or origin.roster[to_bare].subscription == "from")) then
-				origin.directed = origin.directed or {};
-				t_insert(origin.directed, to); -- FIXME does it make more sense to add to_bare rather than to?
-			end
 			core_route_stanza(origin, stanza);
 		end
 	else
@@ -177,6 +180,14 @@
 	origin = origin or hosts[from_host];
 	if not origin then return false; end
 	
+	if hosts[to] and hosts[to].type == "component" then -- hack to allow components to handle node@server/resource and server/resource
+		return component_handle_stanza(origin, stanza);
+	elseif hosts[to_bare] and hosts[to_bare].type == "component" then -- hack to allow components to handle node@server
+		return component_handle_stanza(origin, stanza);
+	elseif hosts[host] and hosts[host].type == "component" then -- directed at a component
+		return component_handle_stanza(origin, stanza);
+	end
+
 	if stanza.name == "presence" and (stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable") then resource = nil; end
 
 	local host_session = hosts[host]
@@ -199,25 +210,36 @@
 						end
 					end
 				elseif stanza.name == "message" then -- select a resource to recieve message
-					local priority = 0;
-					local recipients = {};
-					for _, session in pairs(user.sessions) do -- find resource with greatest priority
-						local p = session.priority or -1;
-						if p > priority then
-							priority = p;
-							recipients = {session};
-						elseif p == priority then
-							t_insert(recipients, session);
+					stanza.attr.to = to_bare;
+					if stanza.attr.type == 'headline' then
+						for _, session in pairs(user.sessions) do -- find resource with greatest priority
+							if session.presence and session.priority >= 0 then
+								session.send(stanza);
+							end
 						end
-					end
-					local count = 0;
-					for _, session in pairs(recipients) do
-						session.send(stanza);
-						count = count + 1;
-					end
-					if count == 0 then
-						offlinemanager.store(node, host, stanza);
-						-- TODO deal with storage errors
+					else
+						local priority = 0;
+						local recipients = {};
+						for _, session in pairs(user.sessions) do -- find resource with greatest priority
+							if session.presence then
+								local p = session.priority;
+								if p > priority then
+									priority = p;
+									recipients = {session};
+								elseif p == priority then
+									t_insert(recipients, session);
+								end
+							end
+						end
+						local count = 0;
+						for _, session in ipairs(recipients) do
+							session.send(stanza);
+							count = count + 1;
+						end
+						if count == 0 and (stanza.attr.type == "chat" or stanza.attr.type == "normal" or not stanza.attr.type) then
+							offlinemanager.store(node, host, stanza);
+							-- TODO deal with storage errors
+						end
 					end
 				else
 					-- TODO send IQ error
@@ -237,6 +259,7 @@
 						-- TODO send unavailable presence or unsubscribed
 					end
 				elseif stanza.name == "message" then -- FIXME if full jid, then send out to resources with highest priority
+					stanza.attr.to = to_bare; -- TODO not in RFC, but seems obvious. Should discuss on the mailing list.
 					if stanza.attr.type == "chat" or stanza.attr.type == "normal" or not stanza.attr.type then
 						offlinemanager.store(node, host, stanza);
 						-- FIXME don't store messages with only chat state notifications
--- a/plugins/mod_muc.lua	Wed Feb 11 16:09:48 2009 +0000
+++ b/plugins/mod_muc.lua	Wed Feb 11 18:30:44 2009 +0000
@@ -7,14 +7,15 @@
 local st = require "util.stanza";
 local log = require "util.logger".init("mod_muc");
 local multitable_new = require "util.multitable".new;
+local t_insert, t_remove = table.insert, table.remove;
 
 if module:get_host_type() ~= "component" then
 	error("MUC should be loaded as a component, please see http://prosody.im/doc/components", 0);
 end
 
 local muc_domain = module:get_host();
-
 local muc_name = "MUCMUCMUC!!!";
+local history_length = 20;
 
 -- room_name -> room
 	-- occupant_room_nick -> data
@@ -30,6 +31,7 @@
 	-- subject - the room's subject
 	-- non-anonymous = true|nil
 	-- persistent = true|nil
+	-- history = {preserialized stanzas}
 local rooms_info = multitable_new();
 
 local persist_list = datamanager.load(nil, muc_domain, 'room_list') or {};
@@ -131,6 +133,15 @@
 			stanza.attr.to = o_data.jid;
 			core_route_stanza(component, stanza);
 		end
+		if not subject and body then -- add to history
+			local history = rooms_info:get(room, 'history');
+			if not history then history = {}; rooms_info:set(room, 'history', history); end
+			-- stanza = st.deserialize(st.preserialize(stanza));
+			stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = muc_domain, stamp = datetime.datetime()}):up(); -- XEP-0203
+			stanza:tag("x", {xmlns = "jabber:x:delay", from = muc_domain, stamp = datetime.legacy()}):up(); -- XEP-0091 (deprecated)
+			t_insert(history, st.preserialize(stanza));
+			while #history > history_length do t_remove(history, 1) end
+		end
 	end
 end
 
@@ -200,7 +211,14 @@
 						end
 					end
 					broadcast_presence(nil, to, room);
-					-- TODO send discussion history
+					local history = rooms_info:get(room, 'history'); -- send discussion history
+					if history then
+						for _, msg in ipairs(history) do
+							msg = st.deserialize(msg);
+							msg.attr.to=from;
+							core_route_stanza(component, msg);
+						end
+					end
 					if rooms_info:get(room, 'subject') then
 						core_route_stanza(component, st.message({type='groupchat', from=room, to=from}):tag("subject"):text(rooms_info:get(room, 'subject')));
 					end
@@ -266,7 +284,7 @@
 	end
 end
 
-function handle_stanza(origin, stanza)
+register_component(muc_domain, function(origin, stanza)
 	local to_node, to_host, to_resource = jid_split(stanza.attr.to);
 	if stanza.name == "presence" and stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" then
 		if type == "error" or type == "result" then return; end
@@ -282,11 +300,7 @@
 		if type == "error" or type == "result" then return; end
 		handle_to_domain(origin, stanza);
 	end
-end
-
-module.load_component = function()
-	return handle_stanza; -- Return the function that we want to handle incoming stanzas
-end
+end);
 
 module.unload = function()
 	deregister_component(muc_domain);

mercurial