Automated merge with ssh://hg@prosody.im/prosody-hg

Mon, 30 Mar 2009 20:04:31 +0100

author
Matthew Wild <mwild1@gmail.com>
date
Mon, 30 Mar 2009 20:04:31 +0100
changeset 941
13ebec89b568
parent 939
b832f786af62 (diff)
parent 940
776cb8c847c5 (current diff)
child 942
dae54304967d

Automated merge with ssh://hg@prosody.im/prosody-hg

prosody file | annotate | diff | comparison | revisions
--- a/core/componentmanager.lua	Mon Mar 30 20:04:11 2009 +0100
+++ b/core/componentmanager.lua	Mon Mar 30 20:04:31 2009 +0100
@@ -20,6 +20,18 @@
 
 local components = {};
 
+local disco_items = require "util.multitable".new();
+local NULL = {};
+require "core.discomanager".addDiscoItemsHandler("*host", function(reply, to, from, node)
+	if #node == 0 and hosts[to] then
+		for jid in pairs(disco_items:get(to) or NULL) do
+			reply:tag("item", {jid = jid}):up();
+		end
+		return true;
+	end
+end);
+
+
 module "componentmanager"
 
 function load_enabled_components(config)
@@ -64,7 +76,10 @@
 	if not hosts[host] or (hosts[host].type == 'component' and not hosts[host].connected) then
 		components[host] = component;
 		hosts[host] = session or create_component(host, component);
-		
+		-- add to disco_items
+		if not(host:find("@", 1, true) or host:find("/", 1, true)) and host:find(".", 1, true) then
+			disco_items:set(host:sub(host:find(".", 1, true)+1), host, true);
+		end
 		-- FIXME only load for a.b.c if b.c has dialback, and/or check in config
 		modulemanager.load(host, "dialback");
 		log("debug", "component added: "..host);
@@ -79,6 +94,10 @@
 		modulemanager.unload(host, "dialback");
 		components[host] = nil;
 		hosts[host] = nil;
+		-- remove from disco_items
+		if not(host:find("@", 1, true) or host:find("/", 1, true)) and host:find(".", 1, true) then
+			disco_items:remove(host:sub(host:find(".", 1, true)+1), host);
+		end
 		log("debug", "component removed: "..host);
 		return true;
 	else
--- a/core/modulemanager.lua	Mon Mar 30 20:04:11 2009 +0100
+++ b/core/modulemanager.lua	Mon Mar 30 20:04:31 2009 +0100
@@ -204,7 +204,7 @@
 	local name, xmlns, origin_type = stanza.name, stanza.attr.xmlns, origin.type;
 	if name == "iq" and xmlns == "jabber:client" then
 		if stanza.attr.type == "get" or stanza.attr.type == "set" then
-			xmlns = stanza.tags[1].attr.xmlns;
+			xmlns = stanza.tags[1].attr.xmlns or "jabber:client";
 			log("debug", "Stanza of type %s from %s has xmlns: %s", name, origin_type, xmlns);
 		else
 			log("debug", "Discarding %s from %s of type: %s", name, origin_type, stanza.attr.type);
--- a/core/rostermanager.lua	Mon Mar 30 20:04:11 2009 +0100
+++ b/core/rostermanager.lua	Mon Mar 30 20:04:31 2009 +0100
@@ -224,6 +224,10 @@
 	if is_contact_pending_in(username, host, jid) then
 		local roster = load_roster(username, host);
 		local item = roster[jid];
+		if not item then -- FIXME should roster item be auto-created?
+			item = {subscription = "none", groups = {}};
+			roster[jid] = item;
+		end
 		if item.subscription == "none" then
 			item.subscription = "from";
 		else -- subscription == to
--- a/core/s2smanager.lua	Mon Mar 30 20:04:11 2009 +0100
+++ b/core/s2smanager.lua	Mon Mar 30 20:04:31 2009 +0100
@@ -24,6 +24,7 @@
 local modulemanager = require "core.modulemanager";
 local st = require "stanza";
 local stanza = st.stanza;
+local nameprep = require "util.encodings".stringprep.nameprep;
 
 local uuid_gen = require "util.uuid".generate;
 
@@ -211,8 +212,8 @@
 	
 	if session.direction == "incoming" then
 		-- Send a reply stream header
-		session.to_host = attr.to;
-		session.from_host = attr.from;
+		session.to_host = attr.to and nameprep(attr.to);
+		session.from_host = attr.from and nameprep(attr.from);
 	
 		session.streamid = uuid_gen();
 		(session.log or log)("debug", "incoming s2s received <stream:stream>");
--- a/core/sessionmanager.lua	Mon Mar 30 20:04:11 2009 +0100
+++ b/core/sessionmanager.lua	Mon Mar 30 20:04:31 2009 +0100
@@ -23,6 +23,7 @@
 local uuid_generate = require "util.uuid".generate;
 local rm_load_roster = require "core.rostermanager".load_roster;
 local config_get = require "core.configmanager".get;
+local nameprep = require "util.encodings".stringprep.nameprep;
 
 local fire_event = require "core.eventmanager".fire_event;
 
@@ -156,6 +157,7 @@
 function streamopened(session, attr)
 						local send = session.send;
 						session.host = attr.to or error("Client failed to specify destination hostname");
+						session.host = nameprep(session.host);
 			                        session.version = tonumber(attr.version) or 0;
 			                        session.streamid = m_random(1000000, 99999999);
 			                        (session.log or session)("debug", "Client sent opening <stream:stream> to %s", session.host);
--- a/core/stanza_router.lua	Mon Mar 30 20:04:11 2009 +0100
+++ b/core/stanza_router.lua	Mon Mar 30 20:04:31 2009 +0100
@@ -51,9 +51,11 @@
 
 	if not stanza.attr.xmlns then stanza.attr.xmlns = "jabber:client"; end -- FIXME Hack. This should be removed when we fix namespace handling.
 	-- TODO verify validity of stanza (as well as JID validity)
-	if stanza.name == "iq" and #stanza.tags > 1 then
-		if stanza.attr.type == "set" or stanza.attr.type == "get" then
-			error("Invalid IQ");
+	if stanza.attr.xmlns == "error" and #stanza.tags == 0 then return; end -- TODO invalid stanza, log
+	if stanza.name == "iq" then
+		if (stanza.attr.type == "set" or stanza.attr.type == "get") and #stanza.tags ~= 1 then
+			origin.send(st.error_reply(stanza, "modify", "bad-request"));
+			return;
 		end
 	end
 
--- a/net/http.lua	Mon Mar 30 20:04:11 2009 +0100
+++ b/net/http.lua	Mon Mar 30 20:04:31 2009 +0100
@@ -115,6 +115,7 @@
 	local req = url.parse(u);
 	
 	if not (req and req.host) then
+		callback(nil, 0, req);
 		return nil, "invalid-url";
 	end
 	
--- a/plugins/mod_muc.lua	Mon Mar 30 20:04:11 2009 +0100
+++ b/plugins/mod_muc.lua	Mon Mar 30 20:04:31 2009 +0100
@@ -369,6 +369,16 @@
 		elseif type ~= "error" and type ~= "result" then
 			origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
 		end
+	elseif stanza.name == "message" and not stanza.attr.type and #stanza.tags == 1 and jid_nick:get(stanza.attr.from, stanza.attr.to)
+		and stanza.tags[1].name == "x" and stanza.tags[1].attr.xmlns == "http://jabber.org/protocol/muc#user" and #stanza.tags[1].tags == 1
+		and stanza.tags[1].tags[1].name == "invite" and stanza.tags[1].tags[1].attr.to then
+		local _from, _to = stanza.attr.from, stanza.attr.to;
+		local _invitee = stanza.tags[1].tags[1].attr.to;
+		stanza.attr.from, stanza.attr.to = _to, _invitee;
+		stanza.tags[1].tags[1].attr.from, stanza.tags[1].tags[1].attr.to = _from, nil;
+		core_route_stanza(component, stanza);
+		stanza.tags[1].tags[1].attr.from, stanza.tags[1].tags[1].attr.to = nil, _invitee;
+		stanza.attr.from, stanza.attr.to = _from, _to;
 	else
 		if type == "error" or type == "result" then return; end
 		origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
--- a/plugins/mod_register.lua	Mon Mar 30 20:04:11 2009 +0100
+++ b/plugins/mod_register.lua	Mon Mar 30 20:04:31 2009 +0100
@@ -13,6 +13,7 @@
 local usermanager_create_user = require "core.usermanager".create_user;
 local datamanager_store = require "util.datamanager".store;
 local os_time = os.time;
+local nodeprep = require "util.encodings".stringprep.nodeprep;
 
 module:add_feature("jabber:iq:register");
 
@@ -29,22 +30,23 @@
 		elseif stanza.attr.type == "set" then
 			if query.tags[1] and query.tags[1].name == "remove" then
 				-- TODO delete user auth data, send iq response, kick all user resources with a <not-authorized/>, delete all user data
+				local username, host = session.username, session.host;
 				--session.send(st.error_reply(stanza, "cancel", "not-allowed"));
 				--return;
-				usermanager_create_user(session.username, nil, session.host); -- Disable account
+				usermanager_create_user(username, nil, host); -- Disable account
 				-- FIXME the disabling currently allows a different user to recreate the account
 				-- we should add an in-memory account block mode when we have threading
 				session.send(st.reply(stanza));
 				local roster = session.roster;
-				for _, session in pairs(hosts[session.host].sessions[session.username].sessions) do -- disconnect all resources
+				for _, session in pairs(hosts[host].sessions[username].sessions) do -- disconnect all resources
 					session:close({condition = "not-authorized", text = "Account deleted"});
 				end
 				-- TODO datamanager should be able to delete all user data itself
-				datamanager.store(session.username, session.host, "roster", nil);
-				datamanager.store(session.username, session.host, "vcard", nil);
-				datamanager.store(session.username, session.host, "private", nil);
-				datamanager.store(session.username, session.host, "offline", nil);
-				--local bare = session.username.."@"..session.host;
+				datamanager.store(username, host, "roster", nil);
+				datamanager.store(username, host, "vcard", nil);
+				datamanager.store(username, host, "private", nil);
+				datamanager.store(username, host, "offline", nil);
+				--local bare = username.."@"..host;
 				for jid, item in pairs(roster) do
 					if jid ~= "pending" then
 						if item.subscription == "both" or item.subscription == "to" then
@@ -55,13 +57,13 @@
 						end
 					end
 				end
-				datamanager.store(session.username, session.host, "accounts", nil); -- delete accounts datastore at the end
+				datamanager.store(username, host, "accounts", nil); -- delete accounts datastore at the end
 			else
 				local username = query:child_with_name("username");
 				local password = query:child_with_name("password");
 				if username and password then
 					-- FIXME shouldn't use table.concat
-					username = table.concat(username);
+					username = nodeprep(table.concat(username));
 					password = table.concat(password);
 					if username == session.username then
 						if usermanager_create_user(username, password, session.host) then -- password change -- TODO is this the right way?
@@ -132,7 +134,7 @@
 						end
 					end
 					-- FIXME shouldn't use table.concat
-					username = table.concat(username);
+					username = nodeprep(table.concat(username));
 					password = table.concat(password);
 					if usermanager_user_exists(username, session.host) then
 						session.send(st.error_reply(stanza, "cancel", "conflict"));
--- a/plugins/mod_roster.lua	Mon Mar 30 20:04:11 2009 +0100
+++ b/plugins/mod_roster.lua	Mon Mar 30 20:04:31 2009 +0100
@@ -11,6 +11,7 @@
 local st = require "util.stanza"
 
 local jid_split = require "util.jid".split;
+local jid_prep = require "util.jid".prep;
 local t_concat = table.concat;
 local tostring = tostring;
 
@@ -61,17 +62,18 @@
 						local item = query.tags[1];
 						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
-						local node, host, resource = jid_split(item.attr.jid);
-						local to_bare = node and (node.."@"..host) or host; -- bare JID
+						local jid = jid_prep(item.attr.jid);
+						local node, host, resource = jid_split(jid);
 						if not resource and host then
-							if item.attr.jid ~= from_node.."@"..from_host then
+							if jid ~= from_node.."@"..from_host then
 								if item.attr.subscription == "remove" then
-									local r_item = session.roster[item.attr.jid];
+									local r_item = session.roster[jid];
 									if r_item then
-										local success, err_type, err_cond, err_msg = rm_remove_from_roster(session, item.attr.jid);
+										local success, err_type, err_cond, err_msg = rm_remove_from_roster(session, jid);
 										if success then
 											session.send(st.reply(stanza));
-											rm_roster_push(from_node, from_host, item.attr.jid);
+											rm_roster_push(from_node, from_host, jid);
+											local to_bare = node and (node.."@"..host) or host; -- bare JID
 											if r_item.subscription == "both" or r_item.subscription == "from" then
 												handle_presence(session, st.presence({type="unsubscribed"}), from_bare, to_bare,
 													core_route_stanza, false);
@@ -88,9 +90,9 @@
 								else
 									local r_item = {name = item.attr.name, groups = {}};
 									if r_item.name == "" then r_item.name = nil; end
-									if session.roster[item.attr.jid] then
-										r_item.subscription = session.roster[item.attr.jid].subscription;
-										r_item.ask = session.roster[item.attr.jid].ask;
+									if session.roster[jid] then
+										r_item.subscription = session.roster[jid].subscription;
+										r_item.ask = session.roster[jid].ask;
 									else
 										r_item.subscription = "none";
 									end
@@ -102,10 +104,10 @@
 											end
 										end
 									end
-									local success, err_type, err_cond, err_msg = rm_add_to_roster(session, item.attr.jid, r_item);
+									local success, err_type, err_cond, err_msg = rm_add_to_roster(session, jid, r_item);
 									if success then
 										session.send(st.reply(stanza));
-										rm_roster_push(from_node, from_host, item.attr.jid);
+										rm_roster_push(from_node, from_host, jid);
 									else
 										session.send(st.error_reply(stanza, err_type, err_cond, err_msg));
 									end
--- a/plugins/mod_saslauth.lua	Mon Mar 30 20:04:11 2009 +0100
+++ b/plugins/mod_saslauth.lua	Mon Mar 30 20:04:31 2009 +0100
@@ -72,7 +72,15 @@
 local function sasl_handler(session, stanza)
 	if stanza.name == "auth" then
 		-- FIXME ignoring duplicates because ejabberd does
+		if config.get(session.host or "*", "core", "anonymous_login") and stanza.attr.mechanism ~= "ANONYMOUS" then
+			return session.send(build_reply("failure", "invalid-mechanism"));
+		elseif stanza.attr.mechanism == "ANONYMOUS" then
+			return session.send(build_reply("failure", "mechanism-too-weak"));
+		end
 		session.sasl_handler = new_sasl(stanza.attr.mechanism, session.host, password_callback);
+		if not session.sasl_handler then
+			return session.send(build_reply("failure", "invalid-mechanism"));
+		end
 	elseif not session.sasl_handler then
 		return; -- FIXME ignoring out of order stanzas because ejabberd does
 	end
@@ -105,10 +113,11 @@
 			if not session.username then
 				features:tag("mechanisms", mechanisms_attr);
 				-- TODO: Provide PLAIN only if TLS is active, this is a SHOULD from the introduction of RFC 4616. This behavior could be overridden via configuration but will issuing a warning or so.
-					features:tag("mechanism"):text("PLAIN"):up();
-					features:tag("mechanism"):text("DIGEST-MD5"):up();
-					if config.get(session.host or "*", "core", "sasl_anonymous") then
+					if config.get(session.host or "*", "core", "anonymous_login") then
 						features:tag("mechanism"):text("ANONYMOUS"):up();
+					else
+						features:tag("mechanism"):text("DIGEST-MD5"):up();
+						features:tag("mechanism"):text("PLAIN"):up();
 					end
 				features:up();
 			else
--- a/prosody	Mon Mar 30 20:04:11 2009 +0100
+++ b/prosody	Mon Mar 30 20:04:31 2009 +0100
@@ -104,6 +104,9 @@
 
 local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data";
 require "util.datamanager".set_data_path(data_path);
+require "util.datamanager".set_callback(function(username, host, datastore)
+	return config.get(host, "core", "anonymous_login");
+end);
 
 ----------- End of out-of-place code --------------
 
--- a/util/datamanager.lua	Mon Mar 30 20:04:11 2009 +0100
+++ b/util/datamanager.lua	Mon Mar 30 20:04:31 2009 +0100
@@ -50,6 +50,7 @@
 end
 
 local data_path = "data";
+local callback;
 
 ------- API -------------
 
@@ -57,6 +58,9 @@
 	log("info", "Setting data path to: %s", path);
 	data_path = path;
 end
+function set_callback(func)
+	callback = func;
+end
 
 function getpath(username, host, datastore, ext, create)
 	ext = ext or "dat";
@@ -93,6 +97,7 @@
 	if not data then
 		data = {};
 	end
+	if callback and callback(username, host, datastore) then return true; end
 	-- save the datastore
 	local f, msg = io_open(getpath(username, host, datastore, nil, true), "w+");
 	if not f then
@@ -113,6 +118,7 @@
 
 function list_append(username, host, datastore, data)
 	if not data then return; end
+	if callback and callback(username, host, datastore) then return true; end
 	-- save the datastore
 	local f, msg = io_open(getpath(username, host, datastore, "list", true), "a+");
 	if not f then
@@ -130,6 +136,7 @@
 	if not data then
 		data = {};
 	end
+	if callback and callback(username, host, datastore) then return true; end
 	-- save the datastore
 	local f, msg = io_open(getpath(username, host, datastore, "list", true), "w+");
 	if not f then
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util/events.lua	Mon Mar 30 20:04:31 2009 +0100
@@ -0,0 +1,96 @@
+
+local ipairs = ipairs;
+local pairs = pairs;
+local t_insert = table.insert;
+local select = select;
+
+module "events"
+
+function new()
+	local dispatchers = {};
+	local handlers = {};
+	local event_map = {};
+	local function _rebuild_index() -- TODO optimize index rebuilding
+		for event, _handlers in pairs(event_map) do
+			local index = handlers[event];
+			if index then
+				for i=#index,1,-1 do index[i] = nil; end
+			else index = {}; handlers[event] = index; end
+			for handler in pairs(_handlers) do
+				t_insert(index, handler);
+			end
+		end
+	end;
+	local function add_handler(event, handler)
+		local map = event_map[event];
+		if map then
+			map[handler] = true;
+		else
+			map = {[handler] = true};
+			event_map[event] = map;
+		end
+		_rebuild_index();
+	end;
+	local function remove_handler(event, handler)
+		local map = event_map[event];
+		if map then
+			map[handler] = nil;
+			_rebuild_index();
+		end
+	end;
+	local function add_plugin(plugin)
+		for event, handler in pairs(plugin) do
+			add_handler(event, handler);
+		end
+	end;
+	local function remove_plugin(plugin)
+		for event, handler in pairs(plugin) do
+			remove_handler(event, handler);
+		end
+	end;
+	local function _create_dispatcher(event) -- FIXME duplicate code in fire_event
+		local h = handlers[event];
+		if not h then h = {}; handlers[event] = h; end
+		local dispatcher = function(data)
+			for _, handler in ipairs(h) do
+				handler(data);
+			end
+		end;
+		dispatchers[event] = dispatcher;
+		return dispatcher;
+	end;
+	local function get_dispatcher(event)
+		return dispatchers[event] or _create_dispatcher(event);
+	end;
+	local function fire_event(event, data) -- FIXME duplicates dispatcher code
+		local h = handlers[event];
+		if h then
+			for _, handler in ipairs(h) do
+				handler(data);
+			end
+		end
+	end;
+	local function get_named_arg_dispatcher(event, ...)
+		local dispatcher = get_dispatcher(event);
+		local keys = {...};
+		local data = {};
+		return function(...)
+			for i, key in ipairs(keys) do data[key] = select(i, ...); end
+			dispatcher(data);
+		end;
+	end;
+	return {
+		add_handler = add_handler;
+		remove_handler = remove_handler;
+		add_plugin = add_plugin;
+		remove_plugin = remove_plugin;
+		get_dispatcher = get_dispatcher;
+		fire_event = fire_event;
+		get_named_arg_dispatcher = get_named_arg_dispatcher;
+		_dispatchers = dispatchers;
+		_handlers = handlers;
+		_event_map = event_map;
+	};
+end
+
+return _M;

mercurial