Changeset

2627:ce5b5d7f87c3

Merge with backout
author Matthew Wild <mwild1@gmail.com>
date Sat, 13 Feb 2010 15:34:33 +0000
parents 2625:03287c06d986 (diff) 2626:39a2e8ff0b0f (current diff)
children 2628:04958fb28c44 2630:e8fc67b73820
files
diffstat 19 files changed, 241 insertions(+), 280 deletions(-) [+]
line wrap: on
line diff
--- a/core/hostmanager.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/core/hostmanager.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -32,12 +32,19 @@
 
 local function load_enabled_hosts(config)
 	local defined_hosts = config or configmanager.getconfig();
+	local activated_any_host;
 	
 	for host, host_config in pairs(defined_hosts) do
-		if host ~= "*" and (host_config.core.enabled == nil or host_config.core.enabled) and not host_config.core.component_module then
+		if host ~= "*" and host_config.core.enabled ~= false and not host_config.core.component_module then
+			activated_any_host = true;
 			activate(host, host_config);
 		end
 	end
+	
+	if not activated_any_host then
+		log("error", "No hosts defined in the config file. This may cause unexpected behaviour as no modules will be loaded.");
+	end
+	
 	eventmanager.fire_event("hosts-activated", defined_hosts);
 	hosts_loaded_once = true;
 end
--- a/core/loggingmanager.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/core/loggingmanager.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -94,7 +94,7 @@
 			end
 		end
 	elseif type(logging_config) == "string" and (not logging_config:match("^%*")) and sink_type == "file" then
-		-- User specified simply a filename, and the "file" sink type 
+		-- User specified simply a filename, and the "file" sink type
 		-- was just added
 		for _, sink_config in pairs(default_file_logging) do
 			sink_config.filename = logging_config;
@@ -128,7 +128,7 @@
 				return set;
 			elseif in_range then
 				set[level] = true;
-			end	
+			end
 		end
 	end
 	
@@ -161,12 +161,12 @@
 		if timestamps then
 			io_write(os_date(timestamps), " ");
 		end
-		if ... then 
+		if ... then
 			io_write(name, rep(" ", sourcewidth-namelen), level, "\t", format(message, ...), "\n");
 		else
 			io_write(name, rep(" ", sourcewidth-namelen), level, "\t", message, "\n");
 		end
-	end	
+	end
 end
 
 do
@@ -197,7 +197,7 @@
 			if timestamps then
 				io_write(os_date(timestamps), " ");
 			end
-			if ... then 
+			if ... then
 				io_write(name, rep(" ", sourcewidth-namelen), getstring(logstyles[level], level), "\t", format(message, ...), "\n");
 			else
 				io_write(name, rep(" ", sourcewidth-namelen), getstring(logstyles[level], level), "\t", message, "\n");
@@ -237,7 +237,7 @@
 		if timestamps then
 			write(logfile, os_date(timestamps), " ");
 		end
-		if ... then 
+		if ... then
 			write(logfile, name, "\t", level, "\t", format(message, ...), "\n");
 		else
 			write(logfile, name, "\t" , level, "\t", message, "\n");
--- a/core/modulemanager.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/core/modulemanager.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -127,6 +127,7 @@
 	local api_instance = setmetatable({ name = module_name, host = host, config = config,  _log = _log, log = function (self, ...) return _log(...); end }, { __index = api });
 
 	local pluginenv = setmetatable({ module = api_instance }, { __index = _G });
+	api_instance.environment = pluginenv;
 	
 	setfenv(mod, pluginenv);
 	if not hosts[host] then
@@ -397,7 +398,7 @@
 		f, n = pluginloader.load_code(lib, lib..".lib.lua");
 	end
 	if not f then error("Failed to load plugin library '"..lib.."', error: "..n); end -- FIXME better error message
-	setfenv(f, setmetatable({ module = self }, { __index = _G }));
+	setfenv(f, self.environment);
 	return f();
 end
 
--- a/core/s2smanager.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/core/s2smanager.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -389,7 +389,7 @@
 			local features = st.stanza("stream:features");
 			
 			if session.to_host then
-				hosts[session.to_host].events.fire_event("s2s-stream-features", { session = session, features = features });
+				hosts[session.to_host].events.fire_event("s2s-stream-features", { origin = session, features = features });
 			else
 				(session.log or log)("warn", "No 'to' on stream header from %s means we can't offer any features", session.from_host or "unknown host");
 			end
@@ -508,6 +508,8 @@
 	end
 end
 
+local function null_data_handler(conn, data) log("debug", "Discarding data from destroyed s2s session: %s", data); end
+
 function destroy_session(session, reason)
 	(session.log or log)("info", "Destroying "..tostring(session.direction).." session "..tostring(session.from_host).."->"..tostring(session.to_host));
 	
@@ -523,6 +525,7 @@
 			session[k] = nil;
 		end
 	end
+	session.data = null_data_handler;
 end
 
 return _M;
--- a/core/sessionmanager.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/core/sessionmanager.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -66,13 +66,13 @@
 	return session;
 end
 
+local function null_data_handler(conn, data) log("debug", "Discarding data from destroyed c2s session: %s", data); end
+
 function destroy_session(session, err)
 	(session.log or log)("info", "Destroying session for %s (%s@%s)", session.full_jid or "(unknown)", session.username or "(unknown)", session.host or "(unknown)");
 	
 	-- Remove session/resource from user's session list
 	if session.full_jid then
-		hosts[session.host].events.fire_event("resource-unbind", {session=session, error=err});
-
 		hosts[session.host].sessions[session.username].sessions[session.resource] = nil;
 		full_sessions[session.full_jid] = nil;
 		
@@ -81,6 +81,8 @@
 			hosts[session.host].sessions[session.username] = nil;
 			bare_sessions[session.username..'@'..session.host] = nil;
 		end
+
+		hosts[session.host].events.fire_event("resource-unbind", {session=session, error=err});
 	end
 	
 	for k in pairs(session) do
@@ -88,6 +90,7 @@
 			session[k] = nil;
 		end
 	end
+	session.data = null_data_handler;
 end
 
 function make_authenticated(session, username)
@@ -190,6 +193,7 @@
 	end
 
 	local features = st.stanza("stream:features");
+	hosts[session.host].events.fire_event("stream-features", { origin = session, features = features });
 	fire_event("stream-features", session, features);
 
 	send(features);
--- a/core/stanza_router.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/core/stanza_router.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -124,7 +124,7 @@
 	local node, host, resource = jid_split(to);
 	local to_bare = node and (node.."@"..host) or host; -- bare JID
 
-	local to_type;
+	local to_type, to_self;
 	if node then
 		if resource then
 			to_type = '/full';
@@ -132,6 +132,7 @@
 			to_type = '/bare';
 			if node == origin.username and host == origin.host then
 				stanza.attr.to = nil;
+				to_self = true;
 			end
 		end
 	else
@@ -149,6 +150,7 @@
 	local h = hosts[to_bare] or hosts[host or origin.host];
 	if h then
 		if h.events.fire_event(stanza.name..to_type, event_data) then return; end -- do processing
+		if to_self and h.events.fire_event(stanza.name..'/self', event_data) then return; end -- do processing
 
 		if h.type == "component" then
 			component_handle_stanza(origin, stanza);
--- a/net/dns.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/net/dns.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -594,17 +594,18 @@
 
 function resolver:remember(rr, type)    -- - - - - - - - - - - - - -  remember
 	--print ('remember', type, rr.class, rr.type, rr.name)
+	local qname, qtype, qclass = standardize(rr.name, rr.type, rr.class);
 
 	if type ~= '*' then
-		type = rr.type;
-		local all = get(self.cache, rr.class, '*', rr.name);
+		type = qtype;
+		local all = get(self.cache, qclass, '*', qname);
 		--print('remember all', all);
 		if all then append(all, rr); end
 	end
 
 	self.cache = self.cache or setmetatable({}, cache_metatable);
-	local rrs = get(self.cache, rr.class, type, rr.name) or
-		set(self.cache, rr.class, type, rr.name, setmetatable({}, rrs_metatable));
+	local rrs = get(self.cache, qclass, type, qname) or
+		set(self.cache, qclass, type, qname, setmetatable({}, rrs_metatable));
 	append(rrs, rr);
 
 	if type == 'MX' then self.unsorted[rrs] = true; end
@@ -723,7 +724,7 @@
 	for i,sock in pairs(rset) do
 
 		if self.socketset[sock] then
-			local packet = sock.receive();
+			local packet = sock:receive();
 			if packet then
 				response = self:decode(packet);
 				if response and self.active[response.header.id]
--- a/net/server_event.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/net/server_event.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -43,7 +43,7 @@
 local coroutine = use "coroutine"
 local setmetatable = use "setmetatable"
 
-local ssl = use "ssl" or require "ssl"
+local ssl = use "ssl"
 local socket = use "socket" or require "socket"
 
 local log = require ("util.logger").init("socket")
@@ -142,7 +142,7 @@
 					self:_close()
 					debug( "new connection failed. id:", self.id, "error:", self.fatalerror )
 				else
-					if plainssl then  -- start ssl session
+					if plainssl and ssl then  -- start ssl session
 						self:starttls()
 					else  -- normal connection
 						self:_start_session( self.listener.onconnect )
@@ -489,6 +489,7 @@
 			_sslctx = sslctx; -- parameters
 			_usingssl = false;  -- client is using ssl;
 		}
+		if not ssl then interface.starttls = false; end
 		interface.id = tostring(interface):match("%x+$");
 		interface.writecallback = function( event )  -- called on write events
 			--vdebug( "new client write event, id/ip/port:", interface, ip, port )
@@ -670,7 +671,7 @@
 				interface._connections = interface._connections + 1  -- increase connection count
 				local clientinterface = handleclient( client, ip, port, interface, pattern, listener, nil, sslctx )
 				--vdebug( "client id:", clientinterface, "startssl:", startssl )
-				if sslctx then
+				if ssl and sslctx then
 					clientinterface:starttls(sslctx)
 				else
 					clientinterface:_start_session( clientinterface.onconnect )
--- a/net/server_select.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/net/server_select.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -55,8 +55,8 @@
 
 --// extern libs //--
 
-local luasec = select( 2, pcall( require, "ssl" ) )
-local luasocket = require "socket"
+local luasec = use "ssl"
+local luasocket = use "socket" or require "socket"
 
 --// extern lib methods //--
 
@@ -472,7 +472,7 @@
 			_sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) -- delete socket from writelist
 			_ = needtls and handler:starttls(nil, true)
 			_writetimes[ handler ] = nil
-		_ = toclose and handler.close( )
+			_ = toclose and handler.close( )
 			return true
 		elseif byte and ( err == "timeout" or err == "wantwrite" ) then -- want write
 			buffer = string_sub( buffer, byte + 1, bufferlen ) -- new buffer
@@ -601,8 +601,10 @@
 			handler.readbuffer = _readbuffer
 			handler.sendbuffer = _sendbuffer
 		end
+	else
+		handler.readbuffer = _readbuffer
+		handler.sendbuffer = _sendbuffer
 	end
-
 	send = socket.send
 	receive = socket.receive
 	shutdown = ( ssl and id ) or socket.shutdown
--- a/plugins/mod_bosh.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/plugins/mod_bosh.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -206,6 +206,7 @@
 		-- Send creation response
 		
 		local features = st.stanza("stream:features");
+		hosts[session.host].events.fire_event("stream-features", { origin = session, features = features });
 		fire_event("stream-features", session, features);
 		--xmpp:version='1.0' xmlns:xmpp='urn:xmpp:xbosh'
 		local response = st.stanza("body", { xmlns = xmlns_bosh,
@@ -257,6 +258,7 @@
 	
 	if session.notopen then
 		local features = st.stanza("stream:features");
+		hosts[session.host].events.fire_event("stream-features", { origin = session, features = features });
 		fire_event("stream-features", session, features);
 		session.send(features);
 		session.notopen = nil;
--- a/plugins/mod_compression.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/plugins/mod_compression.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -25,24 +25,21 @@
 	return;
 end
 
-module:add_event_hook("stream-features",
-		function (session, features)
-			if not session.compressed then
-				-- FIXME only advertise compression support when TLS layer has no compression enabled
-				features:add_child(compression_stream_feature);
-			end
-		end
-);
+module:hook("stream-features", function(event)
+	local origin, features = event.origin, event.features;
+	if not origin.compressed then
+		-- FIXME only advertise compression support when TLS layer has no compression enabled
+		features:add_child(compression_stream_feature);
+	end
+end);
 
-module:hook("s2s-stream-features",
-		function (data)
-			local session, features = data.session, data.features;
-			-- FIXME only advertise compression support when TLS layer has no compression enabled
-			if not session.compressed then 
-				features:add_child(compression_stream_feature);
-			end
-		end
-);
+module:hook("s2s-stream-features", function(event)
+	local origin, features = event.origin, event.features;
+	-- FIXME only advertise compression support when TLS layer has no compression enabled
+	if not origin.compressed then 
+		features:add_child(compression_stream_feature);
+	end
+end);
 
 -- Hook to activate compression if remote server supports it.
 module:hook_stanza(xmlns_stream, "features",
--- a/plugins/mod_legacyauth.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/plugins/mod_legacyauth.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -19,11 +19,12 @@
 local resourceprep = require "util.encodings".stringprep.resourceprep;
 
 module:add_feature("jabber:iq:auth");
-module:add_event_hook("stream-features", function (session, features)
-	if secure_auth_only and not session.secure then
+module:hook("stream-features", function(event)
+	local origin, features = event.origin, event.features;
+	if secure_auth_only and not origin.secure then
 		-- Sorry, not offering to insecure streams!
 		return;
-	elseif not session.username then
+	elseif not origin.username then
 		features:tag("auth", {xmlns='http://jabber.org/features/iq-auth'}):up();
 	end
 end);
--- a/plugins/mod_presence.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/plugins/mod_presence.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -18,6 +18,7 @@
 local jid_split = require "util.jid".split;
 local jid_bare = require "util.jid".bare;
 local hosts = hosts;
+local NULL = {};
 
 local rostermanager = require "core.rostermanager";
 local sessionmanager = require "core.sessionmanager";
@@ -54,16 +55,18 @@
 	end
 	return recipients;
 end
-local function recalc_resource_map(origin)
-	local user = hosts[origin.host].sessions[origin.username];
-	user.top_resources = select_top_resources(user);
-	if #user.top_resources == 0 then user.top_resources = nil; end
+local function recalc_resource_map(user)
+	if user then
+		user.top_resources = select_top_resources(user);
+		if #user.top_resources == 0 then user.top_resources = nil; end
+	end
 end
 
 function handle_normal_presence(origin, stanza, core_route_stanza)
 	local roster = origin.roster;
 	local node, host = origin.username, origin.host;
-	for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast to all resources
+	local user = bare_sessions[node.."@"..host];
+	for _, res in pairs(user and user.sessions or NULL) do -- broadcast to all resources
 		if res ~= origin and res.presence then -- to resource
 			stanza.attr.to = res.full_jid;
 			core_route_stanza(origin, stanza);
@@ -84,7 +87,7 @@
 				core_route_stanza(origin, probe);
 			end
 		end
-		for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast from all available resources
+		for _, res in pairs(user and user.sessions or NULL) do -- broadcast from all available resources
 			if res ~= origin and res.presence then
 				res.presence.attr.to = origin.full_jid;
 				core_route_stanza(res, res.presence);
@@ -115,7 +118,7 @@
 		origin.presence = nil;
 		if origin.priority then
 			origin.priority = nil;
-			recalc_resource_map(origin);
+			recalc_resource_map(user);
 		end
 		if origin.directed then
 			for jid in pairs(origin.directed) do
@@ -137,7 +140,7 @@
 		else priority = 0; end
 		if origin.priority ~= priority then
 			origin.priority = priority;
-			recalc_resource_map(origin);
+			recalc_resource_map(user);
 		end
 	end
 	stanza.attr.to = nil; -- reset it
--- a/plugins/mod_privacy.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/plugins/mod_privacy.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -17,16 +17,6 @@
 local load_roster = require "core.rostermanager".load_roster;
 local to_number = tonumber;
 
-function findNamedList(privacy_lists, name)
-	if privacy_lists.lists then
-		for i=1,#privacy_lists.lists do
-			if privacy_lists.lists[i].name == name then
-				return i;
-			end
-		end
-	end
-end
-
 function isListUsed(origin, name, privacy_lists)
 	local user = bare_sessions[origin.username.."@"..origin.host];
 	if user then
@@ -75,40 +65,6 @@
 	end
 end
 
-function sendNeededUnavailablePersences(origin, listnameOrItem) -- TODO implement it correctly!
-	if type(listnameOrItem) == "string" then
-		local listname = listnameOrItem;
-		for _,list in ipairs(privacy_lists.lists) do
-			if list.name == listname then
-				for _,item in ipairs(list.items) do
-					sendNeededUnavailablePersences(origin, item);
-				end
-			end
-		end
-	elseif type(listnameOrItem) == "table" then
-		module:log("debug", "got an item, check whether to send unavailable presence stanza or not");
-		local item = listnameOrItem;
-
-		if item["presence-out"] == true then
-			if item.type == "jid" then
-				sendUnavailable(origin, item.value, origin.full_jid);
-			elseif item.type == "group" then
-			elseif item.type == "subscription" then
-			elseif item.type == nil then
-			end
-		elseif item["presence-in"] == true then
-			if item.type == "jid" then
-				sendUnavailable(origin, origin.full_jid, item.value);
-			elseif item.type == "group" then
-			elseif item.type == "subscription" then
-			elseif item.type == nil then
-			end
-		end
-	else
-		module:log("debug", "got unknown type: %s", type(listnameOrItem));
-	end
-end
-
 function declineList(privacy_lists, origin, stanza, which)
 	if which == "default" then
 		if isAnotherSessionUsingDefaultList(origin) then
@@ -126,30 +82,17 @@
 end
 
 function activateList(privacy_lists, origin, stanza, which, name)
-	local idx = findNamedList(privacy_lists, name);
+	local list = privacy_lists.lists[name];
 
-	if privacy_lists.default == nil then
-		privacy_lists.default = "";
-	end
-	if origin.activePrivacyList == nil then
-		origin.activePrivacyList = "";
-	end
-	
-	if which == "default" and idx ~= nil then
+	if which == "default" and list then
 		if isAnotherSessionUsingDefaultList(origin) then
 			return {"cancel", "conflict", "Another session is online and using the default list."};
 		end
 		privacy_lists.default = name;
 		origin.send(st.reply(stanza));
---[[
-		if origin.activePrivacyList == nil then
-			sendNeededUnavailablePersences(origin, name);
-		end
-]]--
-	elseif which == "active" and idx ~= nil then
+	elseif which == "active" and list then
 		origin.activePrivacyList = name;
 		origin.send(st.reply(stanza));
-		-- sendNeededUnavailablePersences(origin, name);
 	else
 		return {"modify", "bad-request", "Either not active or default given or unknown list name specified."};
 	end
@@ -157,19 +100,19 @@
 end
 
 function deleteList(privacy_lists, origin, stanza, name)
-	local idx = findNamedList(privacy_lists, name);
+	local list = privacy_lists.lists[name];
 
-	if idx ~= nil then
+	if list then
 		if isListUsed(origin, name, privacy_lists) then
 			return {"cancel", "conflict", "Another session is online and using the list which should be deleted."};
 		end
 		if privacy_lists.default == name then
-			privacy_lists.default = "";
+			privacy_lists.default = nil;
 		end
 		if origin.activePrivacyList == name then
-			origin.activePrivacyList = "";
+			origin.activePrivacyList = nil;
 		end
-		table.remove(privacy_lists.lists, idx);
+		privacy_lists.lists[name] = nil;
 		origin.send(st.reply(stanza));
 		return true;
 	end
@@ -177,19 +120,16 @@
 end
 
 function createOrReplaceList (privacy_lists, origin, stanza, name, entries, roster)
-	local idx = findNamedList(privacy_lists, name);
 	local bare_jid = origin.username.."@"..origin.host;
 	
 	if privacy_lists.lists == nil then
 		privacy_lists.lists = {};
 	end
 
-	if idx == nil then
-		idx = #privacy_lists.lists + 1;
-	end
+	local list = {};
+	privacy_lists.lists[name] = list;
 
 	local orderCheck = {};
-	local list = {};
 	list.name = name;
 	list.items = {};
 
@@ -251,20 +191,11 @@
 		if tmp.action ~= "deny" and tmp.action ~= "allow" then
 			return {"cancel", "bad-request", "Action must be either deny or allow."};
 		end
-		
---[[
-		if (privacy_lists.default == name and origin.activePrivacyList == nil) or origin.activePrivacyList == name then
-			module:log("debug", "calling sendNeededUnavailablePresences!");
-			-- item is valid and list is active, so send needed unavailable stanzas
-			sendNeededUnavailablePersences(origin, tmp);
-		end
-]]--
 		list.items[#list.items + 1] = tmp;
 	end
 	
 	table.sort(list, function(a, b) return a.order < b.order; end);
 
-	privacy_lists.lists[idx] = list;
 	origin.send(st.reply(stanza));
 	if bare_sessions[bare_jid] ~= nil then
 		local iq = st.iq ( { type = "set", id="push1" } );
@@ -286,17 +217,20 @@
 	reply:tag("query", {xmlns="jabber:iq:privacy"});
 
 	if name == nil then
-		reply:tag("active", {name=origin.activePrivacyList or ""}):up();
-		reply:tag("default", {name=privacy_lists.default or ""}):up();
 		if privacy_lists.lists then
-			for _,list in ipairs(privacy_lists.lists) do
-				reply:tag("list", {name=list.name}):up();
+			if origin.ActivePrivacyList then
+				reply:tag("active", {name=origin.activePrivacyList}):up();
+			end
+			if privacy_lists.default then
+				reply:tag("default", {name=privacy_lists.default}):up();
+			end
+			for name,list in pairs(privacy_lists.lists) do
+				reply:tag("list", {name=name}):up();
 			end
 		end
 	else
-		local idx = findNamedList(privacy_lists, name);
-		if idx ~= nil then
-			local list = privacy_lists.lists[idx];
+		local list = privacy_lists.lists[name];
+		if list then
 			reply = reply:tag("list", {name=list.name});
 			for _,item in ipairs(list.items) do
 				reply:tag("item", {type=item.type, value=item.value, action=item.action, order=item.order});
@@ -321,7 +255,16 @@
 	if stanza.attr.to == nil then -- only service requests to own bare JID
 		local query = stanza.tags[1]; -- the query element
 		local valid = false;
-		local privacy_lists = datamanager.load(origin.username, origin.host, "privacy") or {};
+		local privacy_lists = datamanager.load(origin.username, origin.host, "privacy") or { lists = {} };
+
+		if privacy_lists.lists[1] then -- Code to migrate from old privacy lists format, remove in 0.8
+			module:log("info", "Upgrading format of stored privacy lists for %s@%s", origin.username, origin.host);
+			local lists = privacy_lists.lists;
+			for idx, list in ipairs(lists) do
+				lists[list.name] = list;
+				lists[idx] = nil;
+			end
+		end
 
 		if stanza.attr.type == "set" then
 			if #query.tags == 1 then --  the <query/> element MUST NOT include more than one child element
@@ -358,13 +301,14 @@
 		end
 
 		if valid ~= true then
-			if valid[0] == nil then
-				valid[0] = "cancel";
-			end
+			valid = valid or { "cancel", "bad-request", "Couldn't understand request" };
 			if valid[1] == nil then
-				valid[1] = "bad-request";
+				valid[1] = "cancel";
 			end
-			origin.send(st.error_reply(stanza, valid[0], valid[1], valid[2]));
+			if valid[2] == nil then
+				valid[2] = "bad-request";
+			end
+			origin.send(st.error_reply(stanza, valid[1], valid[2], valid[3]));
 		else
 			datamanager.store(origin.username, origin.host, "privacy", privacy_lists);
 		end
@@ -385,8 +329,7 @@
 	module:log("debug", "stanza: %s, to: %s, from: %s", tostring(stanza.name), tostring(to), tostring(from));
 	
 	if privacy_lists.lists == nil or
-		(session.activePrivacyList == nil or session.activePrivacyList == "") and
-		(privacy_lists.default == nil     or privacy_lists.default == "")
+		not (session.activePrivacyList or privacy_lists.default)
 	then
 		return; -- Nothing to block, default is Allow all
 	end
@@ -395,21 +338,14 @@
 		return; -- from one of a user's resource to another => HANDS OFF!
 	end
 	
-	local idx;
-	local list;
 	local item;
 	local listname = session.activePrivacyList;
-	if listname == nil or listname == "" then
+	if listname == nil then
 		listname = privacy_lists.default; -- no active list selected, use default list
 	end
-	idx = findNamedList(privacy_lists, listname);
-	if idx == nil then
-		module:log("debug", "given privacy listname not found. name: %s", listname);
-		return;
-	end
-	list = privacy_lists.lists[idx];
-	if list == nil then
-		module:log("debug", "privacy list index wrong. index: %d", idx);
+	local list = privacy_lists.lists[listname];
+	if not list then
+		module:log("debug", "given privacy list not found. name: %s", listname);
 		return;
 	end
 	for _,item in ipairs(list.items) do
--- a/plugins/mod_roster.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/plugins/mod_roster.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -23,12 +23,12 @@
 module:add_feature("jabber:iq:roster");
 
 local rosterver_stream_feature = st.stanza("ver", {xmlns="urn:xmpp:features:rosterver"}):tag("optional"):up();
-module:add_event_hook("stream-features", 
-		function (session, features)
-			if session.username then
-				features:add_child(rosterver_stream_feature);
-			end
-		end);
+module:hook("stream-features", function(event)
+	local origin, features = event.origin, event.features;
+	if origin.username then
+		features:add_child(rosterver_stream_feature);
+	end
+end);
 
 module:add_iq_handler("c2s", "jabber:iq:roster", 
 		function (session, stanza)
--- a/plugins/mod_saslauth.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/plugins/mod_saslauth.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -144,21 +144,22 @@
 local mechanisms_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-sasl' };
 local bind_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-bind' };
 local xmpp_session_attr = { xmlns='urn:ietf:params:xml:ns:xmpp-session' };
-module:add_event_hook("stream-features", function(session, features)
-	if not session.username then
-		if secure_auth_only and not session.secure then
+module:hook("stream-features", function(event)
+	local origin, features = event.origin, event.features;
+	if not origin.username then
+		if secure_auth_only and not origin.secure then
 			return;
 		end
 		if module:get_option("anonymous_login") then
-			session.sasl_handler = new_sasl(session.host, anonymous_authentication_profile);
+			origin.sasl_handler = new_sasl(origin.host, anonymous_authentication_profile);
 		else
-			session.sasl_handler = new_sasl(session.host, default_authentication_profile);
-			if not (module:get_option("allow_unencrypted_plain_auth")) and not session.secure then
-				session.sasl_handler:forbidden({"PLAIN"});
+			origin.sasl_handler = new_sasl(origin.host, default_authentication_profile);
+			if not (module:get_option("allow_unencrypted_plain_auth")) and not origin.secure then
+				origin.sasl_handler:forbidden({"PLAIN"});
 			end
 		end
 		features:tag("mechanisms", mechanisms_attr);
-		for k, v in pairs(session.sasl_handler:mechanisms()) do
+		for k, v in pairs(origin.sasl_handler:mechanisms()) do
 			features:tag("mechanism"):text(v):up();
 		end
 		features:up();
--- a/plugins/mod_tls.lua	Sat Feb 13 15:34:22 2010 +0000
+++ b/plugins/mod_tls.lua	Sat Feb 13 15:34:33 2010 +0000
@@ -8,88 +8,79 @@
 
 local st = require "util.stanza";
 
-local xmlns_stream = 'http://etherx.jabber.org/streams';
-local xmlns_starttls = 'urn:ietf:params:xml:ns:xmpp-tls';
-
 local secure_auth_only = module:get_option("c2s_require_encryption") or module:get_option("require_encryption");
 local secure_s2s_only = module:get_option("s2s_require_encryption");
 
+local xmlns_starttls = 'urn:ietf:params:xml:ns:xmpp-tls';
+local starttls_attr = { xmlns = xmlns_starttls };
+local starttls_proceed = st.stanza("proceed", starttls_attr);
+local starttls_failure = st.stanza("failure", starttls_attr);
+local c2s_feature = st.stanza("starttls", starttls_attr);
+local s2s_feature = st.stanza("starttls", starttls_attr);
+if secure_auth_only then c2s_feature:tag("required"):up(); end
+if secure_s2s_only then s2s_feature:tag("required"):up(); end
+
 local global_ssl_ctx = prosody.global_ssl_ctx;
 
-module:add_handler("c2s_unauthed", "starttls", xmlns_starttls,
-		function (session, stanza)
-			if session.conn.starttls then
-				session.send(st.stanza("proceed", { xmlns = xmlns_starttls }));
-				session:reset_stream();
-				local ssl_ctx = session.host and hosts[session.host].ssl_ctx_in or global_ssl_ctx;
-				session.conn:starttls(ssl_ctx);
-				session.log("info", "TLS negotiation started...");
-				session.secure = false;
-			else
-				-- FIXME: What reply?
-				session.log("warn", "Attempt to start TLS, but TLS is not available on this connection");
-			end
-		end);
-		
-module:add_handler("s2sin_unauthed", "starttls", xmlns_starttls,
-		function (session, stanza)
-			if session.conn.starttls then
-				session.sends2s(st.stanza("proceed", { xmlns = xmlns_starttls }));
-				session:reset_stream();
-				local ssl_ctx = session.to_host and hosts[session.to_host].ssl_ctx_in or global_ssl_ctx;
-				session.conn:starttls(ssl_ctx);
-				session.log("info", "TLS negotiation started for incoming s2s...");
-				session.secure = false;
-			else
-				-- FIXME: What reply?
-				session.log("warn", "Attempt to start TLS, but TLS is not available on this s2s connection");
-			end
-		end);
+local host = hosts[module.host];
+
+local function can_do_tls(session)
+	if session.type == "c2s_unauthed" then
+		return session.username and session.conn.starttls and host.ssl_ctx_in;
+	elseif session.type == "s2sin_unauthed" then
+		return origin.to_host and origin.conn.starttls and host.ssl_ctx_in;
+	end
+	return false;
+end
 
+-- Hook <starttls/>
+module:hook("stanza/urn:ietf:params:xml:ns:xmpp-tls:starttls", function(event)
+	local origin = event.origin;
+	if can_do_tls(origin) then
+		(origin.sends2s or origin.send)(starttls_proceed);
+		origin:reset_stream();
+		local host = origin.to_host or origin.host;
+		local ssl_ctx = host and hosts[host].ssl_ctx_in or global_ssl_ctx;
+		origin.conn:starttls(ssl_ctx);
+		origin.log("info", "TLS negotiation started for %s...", origin.type);
+		origin.secure = false;
+	else
+		origin.log("warn", "Attempt to start TLS, but TLS is not available on this %s connection", origin.type);
+		(origin.sends2s or origin.send)(starttls_failure);
+		origin:close();
+	end
+	return true;
+end);
 
-local starttls_attr = { xmlns = xmlns_starttls };
-module:add_event_hook("stream-features", 
-		function (session, features)
-			if not session.username and session.conn.starttls then
-				features:tag("starttls", starttls_attr);
-				if secure_auth_only then
-					features:tag("required"):up():up();
-				else
-					features:up();
-				end
-			end
-		end);
-
-module:hook("s2s-stream-features", 
-		function (data)
-			local session, features = data.session, data.features;
-			if session.to_host and session.type ~= "s2sin" and session.conn.starttls then
-				features:tag("starttls", starttls_attr):up();
-				if secure_s2s_only then
-					features:tag("required"):up():up();
-				else
-					features:up();
-				end
-			end
-		end);
+-- Advertize stream feature
+module:hook("stream-features", function(event)
+	local origin, features = event.origin, event.features;
+	if can_do_tls(origin) then
+		features:add_child(c2s_feature);
+	end
+end);
+module:hook("s2s-stream-features", function(event)
+	local origin, features = event.origin, event.features;
+	if can_do_tls(origin) then
+		features:add_child(s2s_feature);
+	end
+end);
 
 -- For s2sout connections, start TLS if we can
-module:hook_stanza(xmlns_stream, "features",
-		function (session, stanza)
-			module:log("debug", "Received features element");
-			if session.conn.starttls and stanza:child_with_ns(xmlns_starttls) then
-				module:log("%s is offering TLS, taking up the offer...", session.to_host);
-				session.sends2s("<starttls xmlns='"..xmlns_starttls.."'/>");
-				return true;
-			end
-		end, 500);
+module:hook_stanza("http://etherx.jabber.org/streams", "features", function (session, stanza)
+	module:log("debug", "Received features element");
+	if session.conn.starttls and stanza:child_with_ns(xmlns_starttls) then
+		module:log("%s is offering TLS, taking up the offer...", session.to_host);
+		session.sends2s("<starttls xmlns='"..xmlns_starttls.."'/>");
+		return true;
+	end
+end, 500);
 
-module:hook_stanza(xmlns_starttls, "proceed",
-		function (session, stanza)
-			module:log("debug", "Proceeding with TLS on s2sout...");
-			session:reset_stream();
-			local ssl_ctx = session.from_host and hosts[session.from_host].ssl_ctx or global_ssl_ctx;
-			session.conn:starttls(ssl_ctx, true);
-			session.secure = false;
-			return true;
-		end);
+module:hook_stanza(xmlns_starttls, "proceed", function (session, stanza)
+	module:log("debug", "Proceeding with TLS on s2sout...");
+	session:reset_stream();
+	local ssl_ctx = session.from_host and hosts[session.from_host].ssl_ctx or global_ssl_ctx;
+	session.conn:starttls(ssl_ctx, true);
+	session.secure = false;
+	return true;
+end);
--- a/prosody	Sat Feb 13 15:34:22 2010 +0000
+++ b/prosody	Sat Feb 13 15:34:33 2010 +0000
@@ -32,34 +32,6 @@
 	end
 end
 
--- Initialize logging
-require "core.loggingmanager"
-
--- Check runtime dependencies
-if not require "util.dependencies".check_dependencies() then
-	os.exit(1);
-end
-
--- Replace require() with one that doesn't pollute _G, required
--- for neat sandboxing of modules
-do
-	local _realG = _G;
-	local _real_require = require;
-	function require(...)
-		local curr_env = getfenv(2);
-		local curr_env_mt = getmetatable(getfenv(2));
-		local _realG_mt = getmetatable(_realG);
-		if curr_env_mt and curr_env_mt.__index and not curr_env_mt.__newindex and _realG_mt then
-			local old_newindex
-			old_newindex, _realG_mt.__newindex = _realG_mt.__newindex, curr_env;
-			local ret = _real_require(...);
-			_realG_mt.__newindex = old_newindex;
-			return ret;
-		end
-		return _real_require(...);
-	end
-end
-
 -- Load the config-parsing module
 config = require "core.configmanager"
 
@@ -119,6 +91,38 @@
 	server = require "net.server"
 end	
 
+function init_logging()
+	-- Initialize logging
+	require "core.loggingmanager"
+end
+
+function check_dependencies()
+	-- Check runtime dependencies
+	if not require "util.dependencies".check_dependencies() then
+		os.exit(1);
+	end
+end
+
+function sandbox_require()
+	-- Replace require() with one that doesn't pollute _G, required
+	-- for neat sandboxing of modules
+	local _realG = _G;
+	local _real_require = require;
+	function require(...)
+		local curr_env = getfenv(2);
+		local curr_env_mt = getmetatable(getfenv(2));
+		local _realG_mt = getmetatable(_realG);
+		if curr_env_mt and curr_env_mt.__index and not curr_env_mt.__newindex and _realG_mt then
+			local old_newindex
+			old_newindex, _realG_mt.__newindex = _realG_mt.__newindex, curr_env;
+			local ret = _real_require(...);
+			_realG_mt.__newindex = old_newindex;
+			return ret;
+		end
+		return _real_require(...);
+	end
+end
+
 function init_global_state()
 	bare_sessions = {};
 	full_sessions = {};
@@ -407,7 +411,12 @@
 end
 
 -- Are you ready? :)
+-- These actions are in a strict order, as many depend on
+-- previous steps to have already been performed
 read_config();
+init_logging();
+check_dependencies();
+sandbox_require();
 load_libraries();
 init_global_state();
 read_version();
--- a/prosodyctl	Sat Feb 13 15:34:22 2010 +0000
+++ b/prosodyctl	Sat Feb 13 15:34:33 2010 +0000
@@ -29,12 +29,6 @@
 	end
 end
 
-require "core.loggingmanager"
-
-if not require "util.dependencies".check_dependencies() then
-	os.exit(1);
-end
-
 config = require "core.configmanager"
 
 do
@@ -63,6 +57,12 @@
 	end
 end
 
+require "core.loggingmanager"
+
+if not require "util.dependencies".check_dependencies() then
+	os.exit(1);
+end
+
 prosody = { hosts = {}, events = events, platform = "posix" };
 
 local data_path = config.get("*", "core", "data_path") or CFG_DATADIR or "data";