Merge with backout

Fri, 21 May 2010 19:45:33 +0100

author
Matthew Wild <mwild1@gmail.com>
date
Fri, 21 May 2010 19:45:33 +0100
changeset 3083
cb15fa9242f9
parent 3071
39a870ae75d9 (diff)
parent 3082
920cd9667c7b (current diff)
child 3084
9b17449fb5f4

Merge with backout

plugins/mod_presence.lua file | annotate | diff | comparison | revisions
--- a/.hgignore	Fri May 21 19:44:31 2010 +0100
+++ b/.hgignore	Fri May 21 19:45:33 2010 +0100
@@ -6,6 +6,7 @@
 html/*
 prosody.lua
 prosody.cfg.lua
+prosody.version
 config.unix
 *.patch
 *.orig
--- a/.hgtags	Fri May 21 19:44:31 2010 +0100
+++ b/.hgtags	Fri May 21 19:45:33 2010 +0100
@@ -36,3 +36,4 @@
 5ae3209fefa2c8dc1c53d08c2c1caa340b8ec542 0.5.2
 1a99a3bf3ce6dbdfb362b7fd101d761fb3cc10af 0.6.0
 81b4e738e4d321b78274132f63a9aec7007e64eb 0.6.1
+0395f2f34bd55a01ec7276884fb9a4e0051b0e7a 0.6.2
--- a/HACKERS	Fri May 21 19:44:31 2010 +0100
+++ b/HACKERS	Fri May 21 19:45:33 2010 +0100
@@ -5,6 +5,8 @@
 information on these at http://prosody.im/discuss
 
 Patches are welcome, though before sending we would appreciate if you read 
-docs/coding_style.txt for guidelines on how to format your code, and are 
-comfortable with copyright of contributions being assigned to the core 
-developers.
+docs/coding_style.txt for guidelines on how to format your code, and other tips.
+
+Documentation for developers can be found at http://prosody.im/doc/developers
+
+Have fun :)
--- a/Makefile	Fri May 21 19:44:31 2010 +0100
+++ b/Makefile	Fri May 21 19:45:33 2010 +0100
@@ -21,7 +21,7 @@
 	install -m750 -d $(DATA)
 	install -d $(MAN)/man1
 	install -d $(CONFIG)/certs
-	install -d $(SOURCE)/core $(SOURCE)/net $(SOURCE)/util $(SOURCE)/fallbacks
+	install -d $(SOURCE)/core $(SOURCE)/net $(SOURCE)/util
 	install -m755 ./prosody.install $(BIN)/prosody
 	install -m755 ./prosodyctl.install $(BIN)/prosodyctl
 	install -m644 core/* $(SOURCE)/core
@@ -30,7 +30,6 @@
 	install -m644 util/*.so $(SOURCE)/util
 	install -d $(SOURCE)/util/sasl
 	install -m644 util/sasl/* $(SOURCE)/util/sasl
-	install -m644 fallbacks/* $(SOURCE)/fallbacks
 	install -m644 plugins/*.lua $(MODULES)
 	install -d $(MODULES)/muc
 	install -m644 plugins/muc/* $(MODULES)/muc
--- a/README	Fri May 21 19:44:31 2010 +0100
+++ b/README	Fri May 21 19:45:33 2010 +0100
@@ -32,6 +32,6 @@
 ## Installation
 
 See the accompanying INSTALL file for help on building Prosody from source. Alternatively 
-see our guide at http://prosody.im/install
+see our guide at http://prosody.im/doc/install
 
 
--- a/TODO	Fri May 21 19:44:31 2010 +0100
+++ b/TODO	Fri May 21 19:45:33 2010 +0100
@@ -1,5 +1,16 @@
-- Ad-hoc commands
-- Clustering
+== 0.8 ==
+- Ad-hoc commands:
+	http://code.google.com/p/prosody-modules/wiki/mod_adhoc
+	http://code.google.com/p/prosody-modules/wiki/mod_adhoc_cmd_admin
+	http://code.google.com/p/prosody-modules/wiki/mod_adhoc_cmd_ping
+	http://code.google.com/p/prosody-modules/wiki/mod_adhoc_cmd_uptime
+	
 - Pubsub
+- Data storage backend abstraction
 
+== 0.9 ==
+- Clustering
 
+== 1.0 ==
+- Web interface?
+- World domination
--- a/configure	Fri May 21 19:44:31 2010 +0100
+++ b/configure	Fri May 21 19:45:33 2010 +0100
@@ -61,7 +61,7 @@
 
 while [ "$1" ]
 do
-   value="`echo $1 | sed 's/.*=\(.*\)/\1/'`"
+   value="`echo $1 | sed 's/[^=]*=\(.*\)/\1/'`"
    if echo "$value" | grep -q "~"
    then
       echo
--- a/core/certmanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/core/certmanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -3,7 +3,7 @@
 local ssl = ssl;
 local ssl_newcontext = ssl and ssl.newcontext;
 
-local setmetatable = setmetatable;
+local setmetatable, tostring = setmetatable, tostring;
 
 local prosody = prosody;
 
@@ -39,8 +39,10 @@
 					reason = "Check that the path is correct, and the file exists.";
 				elseif reason == "system lib" then
 					reason = "Previous error (see logs), or other system error.";
+				elseif reason == "(null)" or not reason then
+					reason = "Check that the file exists and the permissions are correct";
 				else
-					reason = "Reason: "..tostring(reason or "unknown"):lower();
+					reason = "Reason: "..tostring(reason):lower();
 				end
 				log("error", "SSL/TLS: Failed to load %s: %s", file, reason);
 			else
@@ -54,7 +56,7 @@
 end
 
 function reload_ssl_config()
-	default_ssl_config = config.get("*", "core", "ssl");
+	default_ssl_config = configmanager.get("*", "core", "ssl");
 end
 
 prosody.events.add_handler("config-reloaded", reload_ssl_config);
--- a/core/componentmanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/core/componentmanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/core/configmanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/core/configmanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -112,7 +112,7 @@
 	function parsers.lua.load(data, filename)
 		local env;
 		-- The ' = true' are needed so as not to set off __newindex when we assign the functions below
-		env = setmetatable({ Host = true; host = true; Component = true, component = true,
+		env = setmetatable({ Host = true, host = true, VirtualHost = true, Component = true, component = true,
 							Include = true, include = true, RunScript = dofile }, { __index = function (t, k)
 												return rawget(_G, k) or
 														function (settings_table)
@@ -124,7 +124,7 @@
 										end});
 		
 		rawset(env, "__currenthost", "*") -- Default is global
-		function env.Host(name)
+		function env.VirtualHost(name)
 			if rawget(config, name) and rawget(config[name].core, "component_module") then
 				error(format("Host %q clashes with previously defined %s Component %q, for services use a sub-domain like conference.%s",
 					name, config[name].core.component_module:gsub("^%a+$", { component = "external", muc = "MUC"}), name, name), 0);
@@ -133,7 +133,7 @@
 			-- Needs at least one setting to logically exist :)
 			set(name or "*", "core", "defined", true);
 		end
-		env.host = env.Host;
+		env.Host, env.host = env.VirtualHost, env.VirtualHost;
 		
 		function env.Component(name)
 			if rawget(config, name) and rawget(config[name].core, "defined") and not rawget(config[name].core, "component_module") then
--- a/core/eventmanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/core/eventmanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/core/hostmanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/core/hostmanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -42,7 +42,7 @@
 	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.");
+		log("error", "No active VirtualHost entries in the config file. This may cause unexpected behaviour as no modules will be loaded.");
 	end
 	
 	eventmanager.fire_event("hosts-activated", defined_hosts);
@@ -60,8 +60,8 @@
 			dialback_secret = configmanager.get(host, "core", "dialback_secret") or uuid_gen();
 	              };
 	for option_name in pairs(host_config.core) do
-		if option_name:match("_ports$") then
-			log("warn", "%s: Option '%s' has no effect for virtual hosts - put it in global Host \"*\" instead", host, option_name);
+		if option_name:match("_ports$") or option_name:match("_interface$") then
+			log("warn", "%s: Option '%s' has no effect for virtual hosts - put it in the server-wide section instead", host, option_name);
 		end
 	end
 	
--- a/core/loggingmanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/core/loggingmanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -33,9 +33,9 @@
 module "loggingmanager"
 
 -- The log config used if none specified in the config file
-local default_logging = { { to = "console" } };
+local default_logging = { { to = "console" , levels = { min = (debug_mode and "debug") or "info" } } };
 local default_file_logging = { { to = "file", levels = { min = (debug_mode and "debug") or "info" }, timestamps = true } };
-local default_timestamp = "%b %d %T";
+local default_timestamp = "%b %d %H:%M:%S";
 -- The actual config loggingmanager is using
 local logging_config = config.get("*", "core", "log") or default_logging;
 
--- a/core/modulemanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/core/modulemanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -19,7 +19,7 @@
 local hosts = hosts;
 local prosody = prosody;
 
-local loadfile, pcall = loadfile, pcall;
+local loadfile, pcall, xpcall = loadfile, pcall, xpcall;
 local setmetatable, setfenv, getfenv = setmetatable, setfenv, getfenv;
 local pairs, ipairs = pairs, ipairs;
 local t_insert, t_concat = table.insert, table.concat;
@@ -29,6 +29,14 @@
 local error = error;
 local tostring, tonumber = tostring, tonumber;
 
+local debug_traceback = debug.traceback;
+local unpack, select = unpack, select;
+pcall = function(f, ...)
+	local n = select("#", ...);
+	local params = {...};
+	return xpcall(function() f(unpack(params, 1, n)) end, function(e) return tostring(e).."\n"..debug_traceback(); end);
+end
+
 local array, set = require "util.array", require "util.set";
 
 local autoload_modules = {"presence", "message", "iq"};
@@ -158,7 +166,7 @@
 		log("error", "Error initializing module '%s' on '%s': %s", module_name, host, err or "nil");
 	end
 	if success then
-		hosts[host].events.fire_event("module-loaded", { module = module_name, host = host });
+		(hosts[api_instance.host] or prosody).events.fire_event("module-loaded", { module = module_name, host = host });
 		return true;
 	else -- load failed, unloading
 		unload(api_instance.host, module_name);
@@ -210,7 +218,7 @@
 		end
 	end
 	modulemap[host][name] = nil;
-	hosts[host].events.fire_event("module-unloaded", { module = name, host = host });
+	(hosts[host] or prosody).events.fire_event("module-unloaded", { module = name, host = host });
 	return true;
 end
 
@@ -274,7 +282,7 @@
 		(handlers[1])(origin, stanza);
 		return true;
 	else
-		if stanza.attr.xmlns == "jabber:client" then
+		if stanza.attr.xmlns == nil then
 			log("debug", "Unhandled %s stanza: %s; xmlns=%s", origin.type, stanza.name, xmlns); -- we didn't handle it
 			if stanza.attr.type ~= "error" and stanza.attr.type ~= "result" then
 				origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
--- a/core/offlinemanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/core/offlinemanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/core/rostermanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/core/rostermanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -114,8 +114,14 @@
 		--end
 	end
 	if roster then
-		if not roster[false] then roster[false] = {}; end
-		roster[false].version = (roster[false].version or 0) + 1;
+		local metadata = roster[false];
+		if not metadata then
+			metadata = {};
+			roster[false] = metadata;
+		end
+		if metadata.version ~= true then
+			metadata.version = (metadata.version or 0) + 1;
+		end
 		return datamanager.store(username, host, "roster", roster);
 	end
 	log("warn", "save_roster: user had no roster to save");
--- a/core/s2smanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/core/s2smanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -16,8 +16,10 @@
 local format = string.format;
 local t_insert, t_sort = table.insert, table.sort;
 local get_traceback = debug.traceback;
-local tostring, pairs, ipairs, getmetatable, newproxy, error, tonumber
-    = tostring, pairs, ipairs, getmetatable, newproxy, error, tonumber;
+local tostring, pairs, ipairs, getmetatable, newproxy, error, tonumber,
+      setmetatable
+    = tostring, pairs, ipairs, getmetatable, newproxy, error, tonumber,
+      setmetatable;
 
 local idna_to_ascii = require "util.encodings".idna.to_ascii;
 local connlisteners_get = require "net.connlisteners".get;
@@ -48,7 +50,9 @@
 
 module "s2smanager"
 
-local function compare_srv_priorities(a,b) return a.priority < b.priority or a.weight < b.weight; end
+function compare_srv_priorities(a,b)
+	return a.priority < b.priority or (a.priority == b.priority and a.weight > b.weight);
+end
 
 local function bounce_sendq(session, reason)
 	local sendq = session.sendq;
@@ -64,7 +68,7 @@
 		for i, data in ipairs(sendq) do
 			local reply = data[2];
 			local xmlns = reply.attr.xmlns;
-			if not xmlns or xmlns == "jabber:client" or xmlns == "jabber:server" then
+			if not xmlns then
 				reply.attr.type = "error";
 				reply:tag("error", {type = "cancel"})
 					:tag("remote-server-not-found", {xmlns = "urn:ietf:params:xml:ns:xmpp-stanzas"}):up();
@@ -87,7 +91,7 @@
 	local host = hosts[from_host].s2sout[to_host];
 	if host then
 		-- We have a connection to this host already
-		if host.type == "s2sout_unauthed" and (data.name ~= "db:verify" or not host.dialback_key) and ((not data.xmlns) or data.xmlns == "jabber:client" or data.xmlns == "jabber:server") then
+		if host.type == "s2sout_unauthed" and (data.name ~= "db:verify" or not host.dialback_key) then
 			(host.log or log)("debug", "trying to send over unauthed s2sout to "..to_host);
 			
 			-- Queue stanza until we are able to send it
@@ -301,7 +305,7 @@
 end
 
 function make_connect(host_session, connect_host, connect_port)
-	host_session.log("info", "Beginning new connection attempt to %s (%s:%d)", host_session.to_host, connect_host, connect_port);
+	(host_session.log or log)("info", "Beginning new connection attempt to %s (%s:%d)", host_session.to_host, connect_host, connect_port);
 	-- Ok, we're going to try to connect
 	
 	local from_host, to_host = host_session.from_host, host_session.to_host;
@@ -365,11 +369,6 @@
 		session.secure = true;
 	end
 	
-	if session.version >= 1.0 and not (attr.to and attr.from) then
-		(session.log or log)("warn", "Remote of stream "..(session.from_host or "(unknown)").."->"..(session.to_host or "(unknown)")
-			.." failed to specify to (%s) and/or from (%s) hostname as per RFC", tostring(attr.to), tostring(attr.from));
-	end
-	
 	if session.direction == "incoming" then
 		-- Send a reply stream header
 		session.to_host = attr.to and nameprep(attr.to);
@@ -430,11 +429,8 @@
 end
 
 function streamclosed(session)
-	(session.log or log)("debug", "</stream:stream>");
-	if session.sends2s then
-		session.sends2s("</stream:stream>");
-	end
-	session.notopen = true;
+	(session.log or log)("debug", "Received </stream:stream>");
+	session:close();
 end
 
 function initiate_dialback(session)
@@ -508,9 +504,32 @@
 	end
 end
 
-local function null_data_handler(conn, data) log("debug", "Discarding data from destroyed s2s session: %s", data); end
+local resting_session = { -- Resting, not dead
+		destroyed = true;
+		type = "s2s_destroyed";
+		open_stream = function (session)
+			session.log("debug", "Attempt to open stream on resting session");
+		end;
+		close = function (session)
+			session.log("debug", "Attempt to close already-closed session");
+		end;
+	}; resting_session.__index = resting_session;
+
+function retire_session(session)
+	local log = session.log or log;
+	for k in pairs(session) do
+		if k ~= "trace" and k ~= "log" and k ~= "id" then
+			session[k] = nil;
+		end
+	end
+
+	function session.send(data) log("debug", "Discarding data sent to resting session: %s", tostring(data)); end
+	function session.data(data) log("debug", "Discarding data received from resting session: %s", tostring(data)); end
+	return setmetatable(session, resting_session);
+end
 
 function destroy_session(session, reason)
+	if session.destroyed then return; end
 	(session.log or log)("info", "Destroying "..tostring(session.direction).." session "..tostring(session.from_host).."->"..tostring(session.to_host));
 	
 	if session.direction == "outgoing" then
@@ -520,12 +539,7 @@
 		incoming_s2s[session] = nil;
 	end
 	
-	for k in pairs(session) do
-		if k ~= "trace" then
-			session[k] = nil;
-		end
-	end
-	session.data = null_data_handler;
+	retire_session(session); -- Clean session until it is GC'd
 end
 
 return _M;
--- a/core/sessionmanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/core/sessionmanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -8,7 +8,7 @@
 
 
 
-local tonumber, tostring = tonumber, tostring;
+local tonumber, tostring, setmetatable = tonumber, tostring, setmetatable;
 local ipairs, pairs, print, next= ipairs, pairs, print, next;
 local format = import("string", "format");
 
@@ -66,10 +66,30 @@
 	return session;
 end
 
-local function null_data_handler(conn, data) log("debug", "Discarding data from destroyed c2s session: %s", data); end
+local resting_session = { -- Resting, not dead
+		destroyed = true;
+		type = "c2s_destroyed";
+		close = function (session)
+			session.log("debug", "Attempt to close already-closed session");
+		end;
+	}; resting_session.__index = resting_session;
+
+function retire_session(session)
+	local log = session.log or log;
+	for k in pairs(session) do
+		if k ~= "trace" and k ~= "log" and k ~= "id" then
+			session[k] = nil;
+		end
+	end
+
+	function session.send(data) log("debug", "Discarding data sent to resting session: %s", tostring(data)); end
+	function session.data(data) log("debug", "Discarding data received from resting session: %s", tostring(data)); end
+	return setmetatable(session, resting_session);
+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)");
+	if session.destroyed then return; end
 	
 	-- Remove session/resource from user's session list
 	if session.full_jid then
@@ -85,12 +105,7 @@
 		hosts[session.host].events.fire_event("resource-unbind", {session=session, error=err});
 	end
 	
-	for k in pairs(session) do
-		if k ~= "trace" then
-			session[k] = nil;
-		end
-	end
-	session.data = null_data_handler;
+	retire_session(session);
 end
 
 function make_authenticated(session, username)
@@ -168,7 +183,12 @@
 
 function streamopened(session, attr)
 	local send = session.send;
-	session.host = attr.to or error("Client failed to specify destination hostname");
+	session.host = attr.to;
+	if not session.host then
+		session:close{ condition = "improper-addressing",
+			text = "A 'to' attribute is required on stream headers" };
+		return;
+	end
 	session.host = nameprep(session.host);
 	session.version = tonumber(attr.version) or 0;
 	session.streamid = uuid_generate();
@@ -201,8 +221,8 @@
 end
 
 function streamclosed(session)
-	session.send("</stream:stream>");
-	session.notopen = true;
+	session.log("debug", "Received </stream:stream>");
+	session:close();
 end
 
 function send_to_available_resources(user, host, stanza)
--- a/core/stanza_router.lua	Fri May 21 19:44:31 2010 +0100
+++ b/core/stanza_router.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -23,9 +23,6 @@
 function core_process_stanza(origin, stanza)
 	(origin.log or log)("debug", "Received[%s]: %s", origin.type, stanza:top_tag())
 
-	-- Currently we guarantee every stanza to have an xmlns, should we keep this rule?
-	if not stanza.attr.xmlns then stanza.attr.xmlns = "jabber:client"; end
-	
 	-- TODO verify validity of stanza (as well as JID validity)
 	if stanza.attr.type == "error" and #stanza.tags == 0 then return; end -- TODO invalid stanza, log
 	if stanza.name == "iq" then
@@ -36,12 +33,14 @@
 		end
 	end
 
-	if origin.type == "c2s" then
+	if origin.type == "c2s" and not stanza.attr.xmlns then
 		if not origin.full_jid
 			and not(stanza.name == "iq" and stanza.attr.type == "set" and stanza.tags[1] and stanza.tags[1].name == "bind"
 					and stanza.tags[1].attr.xmlns == "urn:ietf:params:xml:ns:xmpp-bind") then
 			-- authenticated client isn't bound and current stanza is not a bind request
-			origin.send(st.error_reply(stanza, "auth", "not-authorized")); -- FIXME maybe allow stanzas to account or server
+			if stanza.attr.type ~= "result" and stanza.attr.type ~= "error" then
+				origin.send(st.error_reply(stanza, "auth", "not-authorized")); -- FIXME maybe allow stanzas to account or server
+			end
 			return;
 		end
 
@@ -90,7 +89,7 @@
 		return; -- FIXME what should we do here?
 	end]] -- FIXME
 
-	if (origin.type == "s2sin" or origin.type == "c2s" or origin.type == "component") and xmlns == "jabber:client" then
+	if (origin.type == "s2sin" or origin.type == "c2s" or origin.type == "component") and xmlns == nil then
 		if origin.type == "s2sin" and not origin.dummy then
 			local host_status = origin.hosts[from_host];
 			if not host_status or not host_status.authed then -- remote server trying to impersonate some other server?
@@ -103,14 +102,14 @@
 		local h = hosts[stanza.attr.to or origin.host or origin.to_host];
 		if h then
 			local event;
-			if stanza.attr.xmlns == "jabber:client" then
+			if xmlns == nil then
 				if stanza.name == "iq" and (stanza.attr.type == "set" or stanza.attr.type == "get") then
 					event = "stanza/iq/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name;
 				else
 					event = "stanza/"..stanza.name;
 				end
 			else
-				event = "stanza/"..stanza.attr.xmlns..":"..stanza.name;
+				event = "stanza/"..xmlns..":"..stanza.name;
 			end
 			if h.events.fire_event(event, {origin = origin, stanza = stanza}) then return; end
 		end
@@ -140,6 +139,7 @@
 			to_type = '/host';
 		else
 			to_type = '/bare';
+			to_self = true;
 		end
 	end
 
--- a/core/usermanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/core/usermanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 --
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -14,11 +14,17 @@
 local hashes = require "util.hashes";
 local jid_bare = require "util.jid".bare;
 local config = require "core.configmanager";
+local hosts = hosts;
+
+local require_provisioning = config.get("*", "core", "cyrus_require_provisioning") or false;
 
 module "usermanager"
 
+local function is_cyrus(host) return config.get(host, "core", "sasl_backend") == "cyrus"; end
+
 function validate_credentials(host, username, password, method)
 	log("debug", "User '%s' is being validated", username);
+	if is_cyrus(host) then return nil, "Legacy auth not supported with Cyrus SASL."; end
 	local credentials = datamanager.load(username, host, "accounts") or {};
 
 	if method == nil then method = "PLAIN"; end
@@ -48,14 +54,26 @@
 end
 
 function get_password(username, host)
-  return (datamanager.load(username, host, "accounts") or {}).password
+	if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
+	return (datamanager.load(username, host, "accounts") or {}).password
+end
+function set_password(username, host, password)
+	if is_cyrus(host) then return nil, "Passwords unavailable for Cyrus SASL."; end
+	local account = datamanager.load(username, host, "accounts");
+	if account then
+		account.password = password;
+		return datamanager.store(username, host, "accounts", account);
+	end
+	return nil, "Account not available.";
 end
 
 function user_exists(username, host)
+	if not(require_provisioning) and is_cyrus(host) then return true; end
 	return datamanager.load(username, host, "accounts") ~= nil; -- FIXME also check for empty credentials
 end
 
 function create_user(username, password, host)
+	if not(require_provisioning) and is_cyrus(host) then return nil, "Account creation/modification not available with Cyrus SASL."; end
 	return datamanager.store(username, host, "accounts", {password = password});
 end
 
--- a/core/xmlhandlers.lua	Fri May 21 19:44:31 2010 +0100
+++ b/core/xmlhandlers.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/fallbacks/bit.lua	Fri May 21 19:44:31 2010 +0100
+++ b/fallbacks/bit.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/man/prosodyctl.man	Fri May 21 19:44:31 2010 +0100
+++ b/man/prosodyctl.man	Fri May 21 19:45:33 2010 +0100
@@ -49,6 +49,10 @@
 Stops the \fBprosody\fP server daemon. This operation will block for up to five
 seconds to wait for the server to stop executing.
 
+.IP \fBrestart\fP
+Restarts the \fBprosody\fP server daemon. Equivalent to running \fBprosodyctl
+stop\fP followed by \fBprosodyctl start\fP.
+
 .IP \fBstatus\fP
 Prints the current execution status of the \fBprosody\fP server daemon.
 
@@ -76,4 +80,4 @@
 More information may be found online at: \fIhttp://prosody.im/\fP
 
 .SH AUTHORS
-Dwayne Bent <dbb.0@liqd.org>
+Dwayne Bent <dbb.1@liqd.org>
--- a/net/adns.lua	Fri May 21 19:44:31 2010 +0100
+++ b/net/adns.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -49,16 +49,20 @@
 	local listener = {};
 	local handler = {};
 	function listener.onincoming(conn, data)
-		dns.feed(handler, data);
+		if data then
+			dns.feed(handler, data);
+		end
 	end
 	function listener.ondisconnect(conn, err)
-		log("warn", "DNS socket for %s disconnected: %s", peername, err);
-		local servers = resolver.server;
-		if resolver.socketset[conn] == resolver.best_server and resolver.best_server == #servers then
-			log("error", "Exhausted all %d configured DNS servers, next lookup will try %s again", #servers, servers[1]);
+		if err then
+			log("warn", "DNS socket for %s disconnected: %s", peername, err);
+			local servers = resolver.server;
+			if resolver.socketset[conn] == resolver.best_server and resolver.best_server == #servers then
+				log("error", "Exhausted all %d configured DNS servers, next lookup will try %s again", #servers, servers[1]);
+			end
+		
+			resolver:servfail(conn); -- Let the magic commence
 		end
-		
-		resolver:servfail(conn); -- Let the magic commence
 	end
 	handler = server.wrapclient(sock, "dns", 53, listener);
 	if not handler then
--- a/net/connlisteners.lua	Fri May 21 19:44:31 2010 +0100
+++ b/net/connlisteners.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/net/dns.lua	Fri May 21 19:44:31 2010 +0100
+++ b/net/dns.lua	Fri May 21 19:45:33 2010 +0100
@@ -532,14 +532,19 @@
 		if not self.server or #self.server == 0 then
 			-- TODO log warning about no nameservers, adding opendns servers as fallback
 			self:addnameserver("208.67.222.222");
-			self:addnameserver("208.67.220.220") ; 	
+			self:addnameserver("208.67.220.220");
 		end
 	else -- posix
 		local resolv_conf = io.open("/etc/resolv.conf");
 		if resolv_conf then
 			for line in resolv_conf:lines() do
-				local address = line:gsub("#.*$", ""):match('^%s*nameserver%s+(%d+%.%d+%.%d+%.%d+)%s*$');
-				if address then self:addnameserver(address) end
+				line = line:gsub("#.*$", "")
+					:match('^%s*nameserver%s+(.*)%s*$');
+				if line then
+					line:gsub("%f[%d.](%d+%.%d+%.%d+%.%d+)%f[^%d.]", function (address)
+						self:addnameserver(address)
+					end);
+				end
 			end
 		end
 		if not self.server or #self.server == 0 then
@@ -796,7 +801,7 @@
 				set(self.wanted, q.class, q.type, q.name, nil);
 			end
 		end
-	end 
+	end
 
 	return response;
 end
@@ -846,7 +851,13 @@
 
 function resolver:lookup(qname, qtype, qclass)    -- - - - - - - - - -  lookup
 	self:query (qname, qtype, qclass)
-	while self:pulse() do socket.select(self.socket, nil, 4); end
+	while self:pulse() do
+           local recvt = {}
+           for i, s in ipairs(self.socket) do
+              recvt[i] = s
+           end
+           socket.select(recvt, nil, 4)
+        end
 	--print(self.cache);
 	return self:peek(qname, qtype, qclass);
 end
--- a/net/http.lua	Fri May 21 19:44:31 2010 +0100
+++ b/net/http.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -17,11 +17,10 @@
 local listener = connlisteners_get("httpclient") or error("No httpclient listener!");
 
 local t_insert, t_concat = table.insert, table.concat;
-local tonumber, tostring, pairs, xpcall, select, debug_traceback, char, format = 
+local tonumber, tostring, pairs, xpcall, select, debug_traceback, char, format =
         tonumber, tostring, pairs, xpcall, select, debug.traceback, string.char, string.format;
 
 local log = require "util.logger".init("http");
-local print = function () end
 
 module "http"
 
@@ -43,6 +42,7 @@
 		elseif request.state ~= "completed" then
 			-- Error.. connection was closed prematurely
 			request.callback("connection-closed", 0, request);
+			return;
 		end
 		destroy_request(request);
 		request.body = nil;
@@ -50,7 +50,7 @@
 		return;
 	end
 	if request.state == "body" and request.state ~= "completed" then
-		print("Reading body...")
+		log("debug", "Reading body...")
 		if not request.body then request.body = {}; request.havebodylength, request.bodylength = 0, tonumber(request.responseheaders["content-length"]); end
 		if startpos then
 			data = data:sub(startpos, -1)
@@ -67,42 +67,54 @@
 				request.body = nil;
 				request.state = "completed";
 			else
-				print("", "Have "..request.havebodylength.." bytes out of "..request.bodylength);
+				log("debug", "Have "..request.havebodylength.." bytes out of "..request.bodylength);
 			end
 		end
 	elseif request.state == "headers" then
-		print("Reading headers...")
+		log("debug", "Reading headers...")
 		local pos = startpos;
-		local headers = request.responseheaders or {};
+		local headers, headers_complete = request.responseheaders;
+		if not headers then
+			headers = {};
+			request.responseheaders = headers;
+		end
 		for line in data:sub(startpos, -1):gmatch("(.-)\r\n") do
 			startpos = startpos + #line + 2;
 			local k, v = line:match("(%S+): (.+)");
 			if k and v then
 				headers[k:lower()] = v;
-				print("Header: "..k:lower().." = "..v);
+				--log("debug", "Header: "..k:lower().." = "..v);
 			elseif #line == 0 then
-				request.responseheaders = headers;
+				headers_complete = true;
 				break;
 			else
-				print("Unhandled header line: "..line);
+				log("warn", "Unhandled header line: "..line);
 			end
 		end
+		if not headers_complete then return; end
 		-- Reached the end of the headers
-		request.state = "body";
+		if not expectbody(request, request.code) then
+			request.callback(nil, request.code, request);
+			return;
+		end
+			request.state = "body";
 		if #data > startpos then
 			return request_reader(request, data, startpos);
 		end
 	elseif request.state == "status" then
-		print("Reading status...")
+		log("debug", "Reading status...")
 		local http, code, text, linelen = data:match("^HTTP/(%S+) (%d+) (.-)\r\n()", startpos);
 		code = tonumber(code);
 		if not code then
-			return request.callback("invalid-status-line", 0, request);
+			log("warn", "Invalid HTTP status line, telling callback then closing");
+			local ret = request.callback("invalid-status-line", 0, request);
+			destroy_request(request);
+			return ret;
 		end
 		
 		request.code, request.responseversion = code, http;
 		
-		if request.onlystatus or not expectbody(request, code) then
+		if request.onlystatus then
 			if request.callback then
 				request.callback(nil, code, request);
 			end
@@ -199,8 +211,9 @@
 
 function destroy_request(request)
 	if request.conn then
-		request.handler.close()
-		listener.ondisconnect(request.conn, "closed");
+		request.conn = nil;
+		request.handler:close()
+		listener.ondisconnect(request.handler, "closed");
 	end
 end
 
--- a/net/httpclient_listener.lua	Fri May 21 19:44:31 2010 +0100
+++ b/net/httpclient_listener.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -30,7 +30,7 @@
 
 function httpclient.ondisconnect(conn, err)
 	local request = requests[conn];
-	if request then
+	if request and err ~= "closed" then
 		request:reader(nil);
 	end
 	requests[conn] = nil;
--- a/net/httpserver.lua	Fri May 21 19:44:31 2010 +0100
+++ b/net/httpserver.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/net/httpserver_listener.lua	Fri May 21 19:44:31 2010 +0100
+++ b/net/httpserver_listener.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -29,7 +29,7 @@
 		end
 	end
 
-	if data then
+	if data and data ~= "" then
 		request_reader(request, data);
 	end
 end
--- a/net/server.lua	Fri May 21 19:44:31 2010 +0100
+++ b/net/server.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,3 +1,10 @@
+-- Prosody IM
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
+-- 
+-- This project is MIT/X11 licensed. Please see the
+-- COPYING file in the source package for more information.
+--
 
 local use_luaevent = require "core.configmanager".get("*", "core", "use_libevent");
 
@@ -36,7 +43,6 @@
 			if type(signal_id) ~= "number" then
 				return false, "invalid-signal";
 			end
-			--_signal_signal(signal_id, handler);
 			return server.hook_signal(signal_id, handler);
 		end
 	end
@@ -47,4 +53,4 @@
 
 -- require "net.server" shall now forever return this,
 -- ie. server_select or server_event as chosen above.
-return server; 
+return server;
--- a/net/server_event.lua	Fri May 21 19:44:31 2010 +0100
+++ b/net/server_event.lua	Fri May 21 19:45:33 2010 +0100
@@ -20,14 +20,14 @@
 
 local cfg = {
 	MAX_CONNECTIONS       = 100000,  -- max per server connections (use "ulimit -n" on *nix)
-	MAX_HANDSHAKE_ATTEMPS = 10,  -- attemps to finish ssl handshake
-	HANDSHAKE_TIMEOUT     = 1,  -- timout in seconds per handshake attemp
+	MAX_HANDSHAKE_ATTEMPS = 1000,  -- attempts to finish ssl handshake
+	HANDSHAKE_TIMEOUT     = 60,  -- timout in seconds per handshake attempt
 	MAX_READ_LENGTH       = 1024 * 1024 * 1024 * 1024,  -- max bytes allowed to read from sockets
 	MAX_SEND_LENGTH       = 1024 * 1024 * 1024 * 1024,  -- max bytes size of write buffer (for writing on sockets)
-	ACCEPT_DELAY          = 10,  -- seconds to wait until the next attemp of a full server to accept
-	READ_TIMEOUT          = 60 * 30,  -- timeout in seconds for read data from socket
-	WRITE_TIMEOUT         = 30,  -- timeout in seconds for write data on socket
-	CONNECT_TIMEOUT       = 10,  -- timeout in seconds for connection attemps
+	ACCEPT_DELAY          = 10,  -- seconds to wait until the next attempt of a full server to accept
+	READ_TIMEOUT          = 60 * 60 * 6,  -- timeout in seconds for read data from socket
+	WRITE_TIMEOUT         = 180,  -- timeout in seconds for write data on socket
+	CONNECT_TIMEOUT       = 20,  -- timeout in seconds for connection attempts
 	CLEAR_DELAY           = 5,  -- seconds to wait for clearing interface list (and calling ondisconnect listeners)
 	DEBUG                 = true,  -- show debug messages
 }
@@ -160,8 +160,8 @@
 			local callback = function( )
 				self:_lock( false,  false, false )
 				--vdebug( "start listening on client socket with id:", self.id )
-				self.eventread = addevent( base, self.conn, EV_READ, self.readcallback, cfg.READ_TIMEOUT )  -- register callback
-				self:onincoming()
+				self.eventread = addevent( base, self.conn, EV_READ, self.readcallback, cfg.READ_TIMEOUT );  -- register callback
+				self:onconnect()
 				self.eventsession = nil
 				return -1
 			end
@@ -197,7 +197,7 @@
 					local _, err
 					local attempt = 0
 					local maxattempt = cfg.MAX_HANDSHAKE_ATTEMPS
-					while attempt < 1000 do  -- no endless loop
+					while attempt < maxattempt do  -- no endless loop
 						attempt = attempt + 1
 						debug( "ssl handshake of client with id:"..tostring(self).."attemp:"..attempt )
 						if attempt > maxattempt then
@@ -262,7 +262,7 @@
 				_ = self.eventsession and self.eventsession:close( )
 				_ = self.eventwritetimeout and self.eventwritetimeout:close( )
 				_ = self.eventreadtimeout and self.eventreadtimeout:close( )
-				_ = self.ondisconnect and self:ondisconnect( self.fatalerror )  -- call ondisconnect listener (wont be the case if handshake failed on connect)
+				_ = self.ondisconnect and self:ondisconnect( self.fatalerror ~= "client to close" and self.fatalerror)  -- call ondisconnect listener (wont be the case if handshake failed on connect)
 				_ = self.conn and self.conn:close( ) -- close connection, must also be called outside of any socket registered events!
 				_ = self._server and self._server:counter(-1);
 				self.eventread, self.eventwrite = nil, nil
@@ -281,6 +281,23 @@
 			self.nointerface, self.noreading, self.nowriting = nointerface, noreading, nowriting
 			return nointerface, noreading, nowriting
 	end
+	
+	--TODO: Deprecate
+	function interface_mt:lock_read(switch)
+		if switch then
+			return self:pause();
+		else
+			return self:resume();
+		end
+	end
+
+	function interface_mt:pause()
+		return self:_lock(self.nointerface, true, self.nowriting);
+	end
+
+	function interface_mt:resume()
+		return self:_lock(self.nointerface, false, self.nowriting);
+	end
 
 	function interface_mt:counter(c)
 		if c then
@@ -385,6 +402,13 @@
 			self.starttls = false; -- prevent starttls()
 		end
 	end
+
+	function interface_mt:set_mode(pattern)
+		if pattern then
+			self._pattern = pattern;
+		end
+		return self._pattern;
+	end
 	
 	function interface_mt:set_send(new_send)
 		-- No-op, we always use the underlying connection's send
@@ -433,6 +457,7 @@
 	
 	-- Stub handlers
 	function interface_mt:onconnect()
+		return self:onincoming(nil);
 	end
 	function interface_mt:onincoming()
 	end
@@ -440,6 +465,8 @@
 	end
 	function interface_mt:ontimeout()
 	end
+	function interface_mt:ondrain()
+	end
 	function interface_mt:onstatus()
 		debug("server.lua: Dummy onstatus()")
 	end
@@ -520,6 +547,7 @@
 				if succ then  -- writing succesful
 					interface.writebuffer = ""
 					interface.writebufferlen = 0
+					interface:ondrain();
 					if interface.fatalerror then
 						debug "closing client after writing"
 						interface:_close()  -- close interface if needed
@@ -531,7 +559,7 @@
 					end
 					interface.eventwrite = nil
 					return -1
-				elseif byte then  -- want write again
+				elseif byte and (err == "timeout" or err == "wantwrite") then  -- want write again
 					--vdebug( "writebuffer is not empty:", err )
 					interface.writebuffer = string_sub( interface.writebuffer, byte + 1, interface.writebufferlen )  -- new buffer
 					interface.writebufferlen = interface.writebufferlen - byte
@@ -539,7 +567,7 @@
 						local callback = function( )
 							interface:_close()
 							interface.eventwritetimeout = nil
-							return evreturn, evtimeout
+							return -1;
 						end
 						interface.eventwritetimeout = addevent( base, nil, EV_TIMEOUT, callback, cfg.WRITE_TIMEOUT )  -- reg a new timeout event
 						debug( "wantread during write attemp, reg it in readcallback but dont know what really happens next..." )
@@ -581,7 +609,7 @@
 						interface.eventreadtimeout = nil
 					end
 				end
-				local buffer, err, part = interface.conn:receive( pattern )  -- receive buffer with "pattern"
+				local buffer, err, part = interface.conn:receive( interface._pattern )  -- receive buffer with "pattern"
 				--vdebug( "read data:", tostring(buffer), "error:", tostring(err), "part:", tostring(part) )
 				buffer = buffer or part or ""
 				local len = string_len( buffer )
@@ -667,16 +695,16 @@
 					debug( "maximal connections reached, refuse client connection; accept delay:", delay )
 					return EV_TIMEOUT, delay  -- delay for next accept attemp
 				end
-				local ip, port = client:getpeername( )
+				local client_ip, client_port = client:getpeername( )
 				interface._connections = interface._connections + 1  -- increase connection count
-				local clientinterface = handleclient( client, ip, port, interface, pattern, listener, nil, sslctx )
+				local clientinterface = handleclient( client, client_ip, client_port, interface, pattern, listener, nil, sslctx )
 				--vdebug( "client id:", clientinterface, "startssl:", startssl )
 				if ssl and sslctx then
 					clientinterface:starttls(sslctx)
 				else
 					clientinterface:_start_session( clientinterface.onconnect )
 				end
-				debug( "accepted incoming client connection from:", ip, port )
+				debug( "accepted incoming client connection from:", client_ip or "<unknown IP>", client_port or "<unknown port>", "to", port or "<unknown port>");
 				
 				client, err = server:accept()    -- try to accept again
 			end
@@ -758,7 +786,7 @@
 			local server = function( )
 				return nil, "this is a dummy server interface"
 			end
-			local interface = wrapclient( client, ip, serverport, listeners, pattern, sslctx, startssl )
+			local interface = wrapclient( client, ip, serverport, listener, pattern, sslctx, startssl )
 			interface:_start_connection( startssl )
 			debug( "new connection id:", interface.id )
 			return interface, err
@@ -817,11 +845,32 @@
 	return signal_events[signal_num];
 end
 
+local function link(sender, receiver, buffersize)
+	sender:set_mode(buffersize);
+	local sender_locked;
+	
+	function receiver:ondrain()
+		if sender_locked then
+			sender:resume();
+			sender_locked = nil;
+		end
+	end
+	
+	function sender:onincoming(data)
+		receiver:write(data);
+		if receiver.writebufferlen >= buffersize then
+			sender_locked = true;
+			sender:pause();
+		end
+	end
+end
+
 return {
 
 	cfg = cfg,
 	base = base,
 	loop = loop,
+	link = link,
 	event = event,
 	event_base = base,
 	addevent = newevent,
--- a/net/server_select.lua	Fri May 21 19:44:31 2010 +0100
+++ b/net/server_select.lua	Fri May 21 19:45:33 2010 +0100
@@ -2,7 +2,7 @@
 -- server.lua by blastbeat of the luadch project
 -- Re-used here under the MIT/X Consortium License
 -- 
--- Modifications (C) 2008-2009 Matthew Wild, Waqas Hussain
+-- Modifications (C) 2008-2010 Matthew Wild, Waqas Hussain
 --
 
 -- // wrapping luadch stuff // --
@@ -252,6 +252,7 @@
 	local dispatch = listeners.onincoming
 	local status = listeners.onstatus
 	local disconnect = listeners.ondisconnect
+	local drain = listeners.ondrain
 
 	local bufferqueue = { } -- buffer array
 	local bufferqueuelen = 0	-- end of buffer array
@@ -284,6 +285,7 @@
 		dispatch = listeners.onincoming
 		disconnect = listeners.ondisconnect
 		status = listeners.onstatus
+		drain = listeners.ondrain
 	end
 	handler.getstats = function( )
 		return readtraffic, sendtraffic
@@ -379,7 +381,7 @@
 	handler.socket = function( self )
 		return socket
 	end
-	handler.pattern = function( self, new )
+	handler.set_mode = function( self, new )
 		pattern = new or pattern
 		return pattern
 	end
@@ -392,6 +394,7 @@
 		maxreadlen = readlen or maxreadlen
 		return bufferlen, maxreadlen, maxsendlen
 	end
+	--TODO: Deprecate
 	handler.lock_read = function (self, switch)
 		if switch == true then
 			local tmp = _readlistlen
@@ -409,6 +412,12 @@
 		end
 		return noread
 	end
+	handler.pause = function (self)
+		return self:lock_read(true);
+	end
+	handler.resume = function (self)
+		return self:lock_read(false);
+	end
 	handler.lock = function( self, switch )
 		handler.lock_read (switch)
 		if switch == true then
@@ -430,12 +439,12 @@
 	end
 	local _readbuffer = function( ) -- this function reads data
 		local buffer, err, part = receive( socket, pattern )	-- receive buffer with "pattern"
-		if not err or (err == "wantread" or err == "timeout") or string_len(part) > 0 then -- received something
+		if not err or (err == "wantread" or err == "timeout") then -- received something
 			local buffer = buffer or part or ""
 			local len = string_len( buffer )
 			if len > maxreadlen then
 				disconnect( handler, "receive buffer exceeded" )
-				handler.close( true )
+				handler:close( true )
 				return false
 			end
 			local count = len * STAT_UNIT
@@ -448,7 +457,7 @@
 			out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " read error: ", tostring(err) )
 			fatalerror = true
 			disconnect( handler, err )
-		_ = handler and handler.close( )
+		_ = handler and handler:close( )
 			return false
 		end
 	end
@@ -472,7 +481,10 @@
 			_sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) -- delete socket from writelist
 			_ = needtls and handler:starttls(nil, true)
 			_writetimes[ handler ] = nil
-			_ = toclose and handler.close( )
+			if drain then
+				drain(handler)
+			end
+			_ = 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
@@ -485,7 +497,7 @@
 			out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " write error: ", tostring(err) )
 			fatalerror = true
 			disconnect( handler, err )
-			_ = handler and handler.close( )
+			_ = handler and handler:close( )
 			return false
 		end
 	end
@@ -611,7 +623,16 @@
 
 	_socketlist[ socket ] = handler
 	_readlistlen = addsocket(_readlist, socket, _readlistlen)
-
+	if listeners.onconnect then
+		_sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
+		handler.sendbuffer = function ()
+			listeners.onconnect(handler);
+			handler.sendbuffer = _sendbuffer;
+			if bufferqueuelen > 0 then
+				return _sendbuffer();
+			end
+		end
+	end
 	return handler, socket
 end
 
@@ -654,6 +675,28 @@
 	--mem_free( )
 end
 
+local function link(sender, receiver, buffersize)
+	sender:set_mode(buffersize);
+	local sender_locked;
+	local _sendbuffer = receiver.sendbuffer;
+	function receiver.sendbuffer()
+		_sendbuffer();
+		if sender_locked and receiver.bufferlen() < buffersize then
+			sender:lock_read(false); -- Unlock now
+			sender_locked = nil;
+		end
+	end
+	
+	local _readbuffer = sender.readbuffer;
+	function sender.readbuffer()
+		_readbuffer();
+		if not sender_locked and receiver.bufferlen() >= buffersize then
+			sender_locked = true;
+			sender:lock_read(true);
+		end
+	end
+end
+
 ----------------------------------// PUBLIC //--
 
 addserver = function( addr, port, listeners, pattern, sslctx ) -- this function provides a way for other scripts to reg a server
@@ -661,7 +704,7 @@
 	if type( listeners ) ~= "table" then
 		err = "invalid listener table"
 	end
-	if not type( port ) == "number" or not ( port >= 0 and port <= 65535 ) then
+	if type( port ) ~= "number" or not ( port >= 0 and port <= 65535 ) then
 		err = "invalid port"
 	elseif _server[ port ] then
 		err = "listeners on port '" .. port .. "' already exist"
@@ -877,6 +920,7 @@
 	wrapclient = wrapclient,
 	
 	loop = loop,
+	link = link,
 	stats = stats,
 	closeall = closeall,
 	addtimer = addtimer,
--- a/net/xmppclient_listener.lua	Fri May 21 19:44:31 2010 +0100
+++ b/net/xmppclient_listener.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -33,13 +33,32 @@
 local stream_callbacks = { default_ns = "jabber:client",
 		streamopened = sm_streamopened, streamclosed = sm_streamclosed, handlestanza = core_process_stanza };
 
+local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams";
+
 function stream_callbacks.error(session, error, data)
 	if error == "no-stream" then
 		session.log("debug", "Invalid opening stream header");
 		session:close("invalid-namespace");
-	elseif session.close then
-		(session.log or log)("debug", "Client XML parse error: %s", tostring(error));
+	elseif error == "parse-error" then
+		(session.log or log)("debug", "Client XML parse error: %s", tostring(data));
 		session:close("xml-not-well-formed");
+	elseif error == "stream-error" then
+		local condition, text = "undefined-condition";
+		for child in data:children() do
+			if child.attr.xmlns == xmlns_xmpp_streams then
+				if child.name ~= "text" then
+					condition = child.name;
+				else
+					text = child:get_text();
+				end
+				if condition ~= "undefined-condition" and text then
+					break;
+				end
+			end
+		end
+		text = condition .. (text and (" ("..text..")") or "");
+		session.log("info", "Session closed by remote with error: %s", text);
+		session:close(nil, text);
 	end
 end
 
--- a/net/xmppcomponent_listener.lua	Fri May 21 19:44:31 2010 +0100
+++ b/net/xmppcomponent_listener.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -34,16 +34,33 @@
 
 local stream_callbacks = { default_ns = xmlns_component };
 
+local xmlns_xmpp_streams = "urn:ietf:params:xml:ns:xmpp-streams";
+
 function stream_callbacks.error(session, error, data, data2)
+	if session.destroyed then return; end
 	log("warn", "Error processing component stream: "..tostring(error));
 	if error == "no-stream" then
 		session:close("invalid-namespace");
-	elseif error == "xml-parse-error" and data == "unexpected-element-close" then
-		session.log("warn", "Unexpected close of '%s' tag", data2);
+	elseif error == "parse-error" then
+		session.log("warn", "External component %s XML parse error: %s", tostring(session.host), tostring(data));
 		session:close("xml-not-well-formed");
-	else
-		session.log("warn", "External component %s XML parse error: %s", tostring(session.host), tostring(error));
-		session:close("xml-not-well-formed");
+	elseif error == "stream-error" then
+		local condition, text = "undefined-condition";
+		for child in data:children() do
+			if child.attr.xmlns == xmlns_xmpp_streams then
+				if child.name ~= "text" then
+					condition = child.name;
+				else
+					text = child:get_text();
+				end
+				if condition ~= "undefined-condition" and text then
+					break;
+				end
+			end
+		end
+		text = condition .. (text and (" ("..text..")") or "");
+		session.log("info", "Session closed by remote with error: %s", text);
+		session:close(nil, text);
 	end
 end
 
@@ -71,8 +88,8 @@
 end
 
 function stream_callbacks.streamclosed(session)
-	session.send("</stream:stream>");
-	session.notopen = true;
+	session.log("Received </stream:stream>");
+	session:close();
 end
 
 local core_process_stanza = core_process_stanza;
@@ -89,6 +106,7 @@
 local stream_xmlns_attr = {xmlns='urn:ietf:params:xml:ns:xmpp-streams'};
 local default_stream_attr = { ["xmlns:stream"] = "http://etherx.jabber.org/streams", xmlns = stream_callbacks.default_ns, version = "1.0", id = "" };
 local function session_close(session, reason)
+	if session.destroyed then return; end
 	local log = session.log or log;
 	if session.conn then
 		if session.notopen then
@@ -146,6 +164,7 @@
 		function session.data(conn, data)
 			local ok, err = parser:parse(data);
 			if ok then return; end
+			log("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "):gsub("[%z\1-\31]", "_"));
 			session:close("xml-not-well-formed");
 		end
 		
@@ -167,7 +186,12 @@
 			hosts[session.host].connected = nil;
 		end
 		sessions[conn]  = nil;
-		for k in pairs(session) do session[k] = nil; end
+		for k in pairs(session) do
+			if k ~= "log" and k ~= "close" then
+				session[k] = nil;
+			end
+		end
+		session.destroyed = true;
 		session = nil;
 	end
 end
--- a/net/xmppserver_listener.lua	Fri May 21 19:44:31 2010 +0100
+++ b/net/xmppserver_listener.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -50,6 +50,9 @@
 
 local function handleerr(err) log("error", "Traceback[s2s]: %s: %s", tostring(err), debug.traceback()); end
 function stream_callbacks.handlestanza(a, b)
+	if b.attr.xmlns == "jabber:client" then --COMPAT: Prosody pre-0.6.2 may send jabber:client
+		b.attr.xmlns = nil;
+	end
 	xpcall(function () core_process_stanza(a, b) end, handleerr);
 end
 
@@ -176,7 +179,7 @@
 				return; -- Session lives for now
 			end
 		end
-		(session.log or log)("info", "s2s disconnected: %s->%s (%s)", tostring(session.from_host), tostring(session.to_host), tostring(err));
+		(session.log or log)("info", "s2s disconnected: %s->%s (%s)", tostring(session.from_host), tostring(session.to_host), tostring(err or "closed"));
 		s2s_destroy_session(session, err);
 		sessions[conn]  = nil;
 		session = nil;
--- a/plugins/mod_announce.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_announce.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_bosh.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_bosh.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -23,7 +23,7 @@
 local log = logger.init("mod_bosh");
 
 local xmlns_bosh = "http://jabber.org/protocol/httpbind"; -- (hard-coded into a literal in session.send)
-local stream_callbacks = { stream_ns = "http://jabber.org/protocol/httpbind", stream_tag = "body", default_ns = xmlns_bosh };
+local stream_callbacks = { stream_ns = "http://jabber.org/protocol/httpbind", stream_tag = "body", default_ns = "jabber:client" };
 
 local BOSH_DEFAULT_HOLD = tonumber(module:get_option("bosh_default_hold")) or 1;
 local BOSH_DEFAULT_INACTIVITY = tonumber(module:get_option("bosh_max_inactivity")) or 60;
@@ -31,6 +31,8 @@
 local BOSH_DEFAULT_REQUESTS = tonumber(module:get_option("bosh_max_requests")) or 2;
 local BOSH_DEFAULT_MAXPAUSE = tonumber(module:get_option("bosh_max_pause")) or 300;
 
+local consider_bosh_secure = module:get_option_boolean("consider_bosh_secure");
+
 local default_headers = { ["Content-Type"] = "text/xml; charset=utf-8" };
 local session_close_reply = { headers = default_headers, body = st.stanza("body", { xmlns = xmlns_bosh, type = "terminate" }), attr = {} };
 
@@ -63,8 +65,11 @@
 	local session = sessions[request.sid];
 	if session then
 		local requests = session.requests;
-		for i,r in pairs(requests) do
-			if r == request then requests[i] = nil; break; end
+		for i,r in ipairs(requests) do
+			if r == request then
+				t_remove(requests, i);
+				break;
+			end
 		end
 		
 		-- If this session now has no requests open, mark it as inactive
@@ -90,6 +95,8 @@
 	--log("debug", "Handling new request %s: %s\n----------", request.id, tostring(body));
 	request.notopen = true;
 	request.log = log;
+	request.on_destroy = on_destroy_request;
+	
 	local parser = lxp.new(init_xmlhandlers(request, stream_callbacks), "\1");
 	
 	parser:parse(body);
@@ -118,14 +125,21 @@
 			session.send(resp);
 		end
 		
-		if not request.destroyed and session.bosh_wait then
-			request.reply_before = os_time() + session.bosh_wait;
-			request.on_destroy = on_destroy_request;
-			waiting_requests[request] = true;
+		if not request.destroyed then
+			-- We're keeping this request open, to respond later
+			log("debug", "Have nothing to say, so leaving request unanswered for now");
+			if session.bosh_wait then
+				request.reply_before = os_time() + session.bosh_wait;
+				waiting_requests[request] = true;
+			end
+			if inactive_sessions[session] then
+				-- Session was marked as inactive, since we have
+				-- a request open now, unmark it
+				inactive_sessions[session] = nil;
+			end
 		end
 		
-		log("debug", "Have nothing to say, so leaving request unanswered for now");
-		return true;
+		return true; -- Inform httpserver we shall reply later
 	end
 end
 
@@ -162,10 +176,14 @@
 		
 		-- New session
 		sid = new_uuid();
-		local session = { type = "c2s_unauthed", conn = {}, sid = sid, rid = tonumber(attr.rid), host = attr.to, bosh_version = attr.ver, bosh_wait = attr.wait, streamid = sid, 
-						bosh_hold = BOSH_DEFAULT_HOLD, bosh_max_inactive = BOSH_DEFAULT_INACTIVITY,
-						requests = { }, send_buffer = {}, reset_stream = bosh_reset_stream, close = bosh_close_stream, 
-						dispatch_stanza = core_process_stanza, log = logger.init("bosh"..sid), secure = request.secure };
+		local session = {
+			type = "c2s_unauthed", conn = {}, sid = sid, rid = tonumber(attr.rid)-1, host = attr.to,
+			bosh_version = attr.ver, bosh_wait = attr.wait, streamid = sid,
+			bosh_hold = BOSH_DEFAULT_HOLD, bosh_max_inactive = BOSH_DEFAULT_INACTIVITY,
+			requests = { }, send_buffer = {}, reset_stream = bosh_reset_stream,
+			close = bosh_close_stream, dispatch_stanza = core_process_stanza,
+			log = logger.init("bosh"..sid),	secure = consider_bosh_secure or request.secure
+		};
 		sessions[sid] = session;
 		
 		log("info", "New BOSH session, assigned it sid '%s'", sid);
@@ -174,11 +192,6 @@
 		function session.send(s)
 			--log("debug", "Sending BOSH data: %s", tostring(s));
 			local oldest_request = r[1];
-			while oldest_request and oldest_request.destroyed do
-				t_remove(r, 1);
-				waiting_requests[oldest_request] = nil;
-				oldest_request = r[1];
-			end
 			if oldest_request then
 				log("debug", "We have an open request, so sending on that");
 				response.body = t_concat{"<body xmlns='http://jabber.org/protocol/httpbind' sid='", sid, "' xmlns:stream = 'http://etherx.jabber.org/streams'>", tostring(s), "</body>" };
@@ -193,7 +206,6 @@
 				else
 					log("debug", "Destroying the request now...");
 					oldest_request:destroy();
-					t_remove(r, 1);
 				end
 			elseif s ~= "" then
 				log("debug", "Saved to send buffer because there are %d open requests", #r);
@@ -235,8 +247,9 @@
 			session.log("warn", "rid too large (means a request was lost). Last rid: %d New rid: %s", session.rid, attr.rid);
 		elseif diff <= 0 then
 			-- Repeated, ignore
-			session.log("debug", "rid repeated (on request %s), ignoring: %d", request.id, session.rid);
+			session.log("debug", "rid repeated (on request %s), ignoring: %s (diff %d)", request.id, session.rid, diff);
 			request.notopen = nil;
+			request.sid = sid;
 			t_insert(session.requests, request);
 			return;
 		end
@@ -250,12 +263,6 @@
 		return;
 	end
 	
-	-- If session was inactive, make sure it is now marked as not
-	if #session.requests == 0 then
-		(session.log or log)("debug", "BOSH client now active again at %d", os_time());
-		inactive_sessions[session] = nil;
-	end
-	
 	if session.notopen then
 		local features = st.stanza("stream:features");
 		hosts[session.host].events.fire_event("stream-features", { origin = session, features = features });
@@ -274,7 +281,7 @@
 	local session = sessions[request.sid];
 	if session then
 		if stanza.attr.xmlns == xmlns_bosh then
-			stanza.attr.xmlns = "jabber:client";
+			stanza.attr.xmlns = nil;
 		end
 		session.ip = request.handler:ip();
 		core_process_stanza(session, stanza);
--- a/plugins/mod_component.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_component.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_compression.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_compression.lua	Fri May 21 19:45:33 2010 +0100
@@ -8,6 +8,8 @@
 local st = require "util.stanza";
 local zlib = require "zlib";
 local pcall = pcall;
+local tostring = tostring;
+
 local xmlns_compression_feature = "http://jabber.org/features/compress"
 local xmlns_compression_protocol = "http://jabber.org/protocol/compress"
 local xmlns_stream = "http://etherx.jabber.org/streams";
@@ -71,7 +73,7 @@
 		local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("setup-failed");
 		(session.sends2s or session.send)(error_st);
 		session.log("error", "Failed to create zlib.deflate filter.");
-		module:log("error", deflate_stream);
+		module:log("error", "%s", tostring(deflate_stream));
 		return
 	end
 	return deflate_stream
@@ -83,8 +85,8 @@
 	if status == false then
 		local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("setup-failed");
 		(session.sends2s or session.send)(error_st);
-		session.log("error", "Failed to create zlib.deflate filter.");
-		module:log("error", inflate_stream);
+		session.log("error", "Failed to create zlib.inflate filter.");
+		module:log("error", "%s", tostring(inflate_stream));
 		return
 	end
 	return inflate_stream
@@ -104,7 +106,7 @@
 					text = compressed;
 					extra = st.stanza("failure", {xmlns="http://jabber.org/protocol/compress"}):tag("processing-failed");
 				});
-				module:log("warn", compressed);
+				module:log("warn", "%s", tostring(compressed));
 				return;
 			end
 			session.conn:write(compressed);
@@ -125,7 +127,7 @@
 					text = decompressed;
 					extra = st.stanza("failure", {xmlns="http://jabber.org/protocol/compress"}):tag("processing-failed");
 				});
-				module:log("warn", decompressed);
+				module:log("warn", "%s", tostring(decompressed));
 				return;
 			end
 			old_data(conn, decompressed);
@@ -166,15 +168,17 @@
 		function(session, stanza)
 			-- fail if we are already compressed
 			if session.compressed then
-				local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("unsupported-method");
+				local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("setup-failed");
 				(session.sends2s or session.send)(error_st);
-				session.log("warn", "Tried to establish another compression layer.");
+				session.log("debug", "Client tried to establish another compression layer.");
+				return;
 			end
 			
 			-- checking if the compression method is supported
-			local method = stanza:child_with_name("method")[1];
+			local method = stanza:child_with_name("method");
+			method = method and (method[1] or "");
 			if method == "zlib" then
-				session.log("debug", method.." compression selected.");
+				session.log("debug", "zlib compression enabled.");
 				
 				-- create deflate and inflate streams
 				local deflate_stream = get_deflate_stream(session);
@@ -199,10 +203,12 @@
 						return true;
 					end;
 				session.compressed = true;
-			else
-				session.log("warn", method.." compression selected. But we don't support it.");
+			elseif method then
+				session.log("debug", "%s compression selected, but we don't support it.", tostring(method));
 				local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("unsupported-method");
 				(session.sends2s or session.send)(error_st);
+			else
+				(session.sends2s or session.send)(st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("setup-failed"));
 			end
 		end
 );
--- a/plugins/mod_console.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_console.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -53,76 +53,78 @@
 
 local sessions = {};
 
+function console_listener.onconnect(conn)
+	-- Handle new connection
+	local session = console:new_session(conn);
+	sessions[conn] = session;
+	printbanner(session);
+	session.send(string.char(0));
+end
+
 function console_listener.onincoming(conn, data)
 	local session = sessions[conn];
-	
-	if not session then
-		-- Handle new connection
-		session = console:new_session(conn);
-		sessions[conn] = session;
-		printbanner(session);
-	end
-	if data then
-		-- Handle data
-		(function(session, data)
-			local useglobalenv;
-			
-			if data:match("^>") then
-				data = data:gsub("^>", "");
-				useglobalenv = true;
-			elseif data == "\004" then
-				commands["bye"](session, data);
-				return;
-			else
-				local command = data:lower();
-				command = data:match("^%w+") or data:match("%p");
-				if commands[command] then
-					commands[command](session, data);
-					return;
-				end
-			end
 
-			session.env._ = data;
-			
-			local chunk, err = loadstring("return "..data);
-			if not chunk then
-				chunk, err = loadstring(data);
-				if not chunk then
-					err = err:gsub("^%[string .-%]:%d+: ", "");
-					err = err:gsub("^:%d+: ", "");
-					err = err:gsub("'<eof>'", "the end of the line");
-					session.print("Sorry, I couldn't understand that... "..err);
-					return;
-				end
-			end
-			
-			setfenv(chunk, (useglobalenv and redirect_output(_G, session)) or session.env or nil);
-			
-			local ranok, taskok, message = pcall(chunk);
-			
-			if not (ranok or message or useglobalenv) and commands[data:lower()] then
-				commands[data:lower()](session, data);
+	-- Handle data
+	(function(session, data)
+		local useglobalenv;
+		
+		if data:match("^>") then
+			data = data:gsub("^>", "");
+			useglobalenv = true;
+		elseif data == "\004" then
+			commands["bye"](session, data);
+			return;
+		else
+			local command = data:lower();
+			command = data:match("^%w+") or data:match("%p");
+			if commands[command] then
+				commands[command](session, data);
 				return;
 			end
-			
-			if not ranok then
-				session.print("Fatal error while running command, it did not complete");
-				session.print("Error: "..taskok);
+		end
+
+		session.env._ = data;
+		
+		local chunkname = "=console";
+		local chunk, err = loadstring("return "..data, chunkname);
+		if not chunk then
+			chunk, err = loadstring(data, chunkname);
+			if not chunk then
+				err = err:gsub("^%[string .-%]:%d+: ", "");
+				err = err:gsub("^:%d+: ", "");
+				err = err:gsub("'<eof>'", "the end of the line");
+				session.print("Sorry, I couldn't understand that... "..err);
 				return;
 			end
-			
-			if not message then
-				session.print("Result: "..tostring(taskok));
-				return;
-			elseif (not taskok) and message then
-				session.print("Command completed with a problem");
-				session.print("Message: "..tostring(message));
-				return;
-			end
-			
-			session.print("OK: "..tostring(message));
-		end)(session, data);
-	end
+		end
+		
+		setfenv(chunk, (useglobalenv and redirect_output(_G, session)) or session.env or nil);
+		
+		local ranok, taskok, message = pcall(chunk);
+		
+		if not (ranok or message or useglobalenv) and commands[data:lower()] then
+			commands[data:lower()](session, data);
+			return;
+		end
+		
+		if not ranok then
+			session.print("Fatal error while running command, it did not complete");
+			session.print("Error: "..taskok);
+			return;
+		end
+		
+		if not message then
+			session.print("Result: "..tostring(taskok));
+			return;
+		elseif (not taskok) and message then
+			session.print("Command completed with a problem");
+			session.print("Message: "..tostring(message));
+			return;
+		end
+		
+		session.print("OK: "..tostring(message));
+	end)(session, data);
+	
 	session.send(string.char(0));
 end
 
@@ -192,7 +194,7 @@
 	elseif section == "server" then
 		print [[server:version() - Show the server's version number]]
 		print [[server:uptime() - Show how long the server has been running]]
-		--print [[server:shutdown(reason) - Shut down the server, with an optional reason to be broadcast to all connections]]
+		print [[server:shutdown(reason) - Shut down the server, with an optional reason to be broadcast to all connections]]
 	elseif section == "config" then
 		print [[config:reload() - Reload the server configuration. Modules may need to be reloaded for changes to take effect.]]
 	elseif section == "console" then
--- a/plugins/mod_debug.lua	Fri May 21 19:44:31 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +0,0 @@
--- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
--- 
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-module.host = "*";
-
-local connlisteners_register = require "net.connlisteners".register;
-
-local console_listener = { default_port = 5583; default_mode = "*l"; default_interface = "127.0.0.1" };
-
-local sha256, missingglobal = require "util.hashes".sha256;
-
-local commands = {};
-local debug_env = {};
-local debug_env_mt = { __index = function (t, k) return rawget(_G, k) or missingglobal(k); end, __newindex = function (t, k, v) rawset(_G, k, v); end };
-
-local t_insert, t_concat = table.insert, table.concat;
-local t_concatall = function (t, sep) local tt = {}; for k, s in pairs(t) do tt[k] = tostring(s); end return t_concat(tt, sep); end
-
-
-setmetatable(debug_env, debug_env_mt);
-
-console = {};
-
-function console:new_session(conn)
-	local w = function(s) conn.write(s:gsub("\n", "\r\n")); end;
-	local session = { conn = conn;
-			send = function (t) w(tostring(t)); end;
-			print = function (t) w("| "..tostring(t).."\n"); end;
-			disconnect = function () conn.close(); end;
-			};
-	
-	return session;
-end
-
-local sessions = {};
-
-function console_listener.listener(conn, data)
-	local session = sessions[conn];
-	
-	if not session then
-		-- Handle new connection
-		session = console:new_session(conn);
-		sessions[conn] = session;
-		printbanner(session);
-	end
-	if data then
-		-- Handle data
-		(function(session, data)
-			if data:match("[!.]$") then
-				local command = data:lower();
-				command = data:match("^%w+") or data:match("%p");
-				if commands[command] then
-					commands[command](session, data);
-					return;
-				end
-			end
-			
-			local chunk, err = loadstring("return "..data);
-			if not chunk then
-				chunk, err = loadstring(data);
-				if not chunk then
-					err = err:gsub("^%[string .-%]:%d+: ", "");
-					err = err:gsub("^:%d+: ", "");
-					err = err:gsub("'<eof>'", "the end of the line");
-					session.print("Sorry, I couldn't understand that... "..err);
-					return;
-				end
-			end
-			
-			debug_env.print = session.print;
-			
-			setfenv(chunk, debug_env);
-			
-			local ret = { pcall(chunk) };
-			
-			if not ret[1] then
-				session.print("Fatal error while running command, it did not complete");
-				session.print("Error: "..ret[2]);
-				return;
-			end
-			
-			table.remove(ret, 1);
-			
-			local retstr = t_concatall(ret, ", ");
-			if retstr ~= "" then
-				session.print("Result: "..retstr);
-			else
-				session.print("No result, or nil");
-				return;
-			end
-		end)(session, data);
-	end
-	session.send(string.char(0));
-end
-
-function console_listener.disconnect(conn, err)
-	
-end
-
-connlisteners_register('debug', console_listener);
-require "net.connlisteners".start("debug");
-
--- Console commands --
--- These are simple commands, not valid standalone in Lua
-
-function commands.bye(session)
-	session.print("See you! :)");
-	session.disconnect();
-end
-
-commands["!"] = function (session, data)
-	if data:match("^!!") then
-		session.print("!> "..session.env._);
-		return console_listener.listener(session.conn, session.env._);
-	end
-	local old, new = data:match("^!(.-[^\\])!(.-)!$");
-	if old and new then
-		local ok, res = pcall(string.gsub, session.env._, old, new);
-		if not ok then
-			session.print(res)
-			return;
-		end
-		session.print("!> "..res);
-		return console_listener.listener(session.conn, res);
-	end
-	session.print("Sorry, not sure what you want");
-end
-
-function printbanner(session)
-session.print [[
-                   ____                \   /     _       
-                    |  _ \ _ __ ___  ___  _-_   __| |_   _ 
-                    | |_) | '__/ _ \/ __|/ _ \ / _` | | | |
-                    |  __/| | | (_) \__ \ |_| | (_| | |_| |
-                    |_|   |_|  \___/|___/\___/ \__,_|\__, |
-                    A study in simplicity            |___/ 
-
-]]
-session.print("Welcome to the Prosody debug console. For a list of commands, type: help");
-session.print("You may find more help on using this console in our online documentation at ");
-session.print("http://prosody.im/doc/debugconsole\n");
-end
-
-local byte, char = string.byte, string.char;
-local gmatch, gsub = string.gmatch, string.gsub;
-
-local function vdecode(text, key)
-	local keyarr = {};
-	for l in gmatch(key, ".") do t_insert(keyarr, byte(l) - 32) end
-	local pos, keylen = 0, #keyarr;
-	return (gsub(text, ".",	function (letter)
-							if byte(letter) < 32 then return ""; end
-							pos = (pos%keylen)+1;
-							return char(((byte(letter) - 32 - keyarr[pos]) % 94) + 32);
-						end));
-end
-
-local subst = {
-	["f880c08056ba7dbecb1ccfe5d7728bd6dcd654e94f7a9b21788c43397bae0bc5"] =
-		[=[nRYeKR$l'5Ix%u*1Mc-K}*bwv*\ $1KLMBd$KH R38`$[6}VQ@,6Qn]=];
-	["92f718858322157202ec740698c1390e47bc819e52b6a099c54c378a9f7529d6"] =
-		[=[V\Z5`WZ5,T$<)7LM'w3Z}M(7V'{pa) &'>0+{v)O(0M*V5K$$LL$|2wT}6
-		 1as*")e!>]=];
-	["467b65edcc7c7cd70abf2136cc56abd037216a6cd9e17291a2219645be2e2216"] =
-		[=[i#'Z,E1-"YaHW(j/0xs]I4x&%(Jx1h&18'(exNWT D3b+K{*8}w(%D {]=];
-	["f73729d7f2fbe686243a25ac088c7e6aead3d535e081329f2817438a5c78bee5"] =
-		[=[,3+(Q{3+W\ftQ%wvv/C0z-l%f>ABc(vkp<bb8]=];
-	["6afa189489b096742890d0c5bd17d5bb8af8ac460c7026984b64e8f14a40404e"] =
-		[=[9N{)5j34gd*}&]H&dy"I&7(",a F1v6jY+IY7&S+86)1z(Vo]=];
-	["cc5e5293ef8a1acbd9dd2bcda092c5c77ef46d3ec5aea65024fca7ed4b3c94a9"] = 
-		[=[_]Rc}IF'Kfa&))Ry+6|x!K2|T*Vze)%4Hwz'L3uI|OwIa)|q#uq2+Qu u7
-		[V3(z(*TYY|T\1_W'2] Dwr{-{@df#W.H5^x(ydtr{c){UuV@]=];
-	["b3df231fd7ddf73f72f39cb2510b1fe39318f4724728ed58948a180663184d3e"] =
-		[=[iH!"9NLS'%geYw3^R*fvWM1)MwxLS!d[zP(p0sQ|8tX{dWO{9w!+W)b"MU
-		W)V8&(2Wx"'dTL9*PP%1"JV(I|Jr1^f'-Hc3U\2H3Z='K#,)dPm]=];
-	}
-
-function missingglobal(name)
-	if sha256 then
-		local hash = sha256(name.."|"..name:reverse(), true);
-		
-		if subst[hash] then
-			return vdecode(subst[hash], sha256(name:reverse(), true));
-		end
-	end
-end
--- a/plugins/mod_dialback.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_dialback.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_disco.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_disco.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_groups.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_groups.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,14 +1,14 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
 --
 
 
-local groups = { default = {} };
-local members = { [false] = {} };
+local groups;
+local members;
 
 local groups_file;
 
@@ -18,9 +18,9 @@
 local module_host = module:get_host();
 
 function inject_roster_contacts(username, host, roster)
-	module:log("warn", "Injecting group members to roster");
+	--module:log("debug", "Injecting group members to roster");
 	local bare_jid = username.."@"..host;
-	if not members[bare_jid] then return; end -- Not a member of any groups
+	if not members[bare_jid] and not members[false] then return; end -- Not a member of any groups
 	
 	local function import_jids_to_roster(group_name)
 		for jid in pairs(groups[group_name]) do
@@ -39,13 +39,23 @@
 	end
 
 	-- Find groups this JID is a member of
-	for _, group_name in ipairs(members[bare_jid]) do
-		import_jids_to_roster(group_name);
+	if members[bare_jid] then
+		for _, group_name in ipairs(members[bare_jid]) do
+			--module:log("debug", "Importing group %s", group_name);
+			import_jids_to_roster(group_name);
+		end
 	end
 	
 	-- Import public groups
-	for _, group_name in ipairs(members[false]) do
-		import_jids_to_roster(group_name);
+	if members[false] then
+		for _, group_name in ipairs(members[false]) do
+			--module:log("debug", "Importing group %s", group_name);
+			import_jids_to_roster(group_name);
+		end
+	end
+	
+	if roster[false] then
+		roster[false].version = true;
 	end
 end
 
@@ -57,6 +67,7 @@
 				new_roster[jid] = contact;
 			end
 		end
+		new_roster[false].version = nil; -- Version is void
 		return username, host, datastore, new_roster;
 	end
 
@@ -71,20 +82,23 @@
 	datamanager.add_callback(remove_virtual_contacts);
 	
 	groups = { default = {} };
-	members = { [false] = {} };
+	members = { };
 	local curr_group = "default";
 	for line in io.lines(groups_file) do
 		if line:match("^%s*%[.-%]%s*$") then
 			curr_group = line:match("^%s*%[(.-)%]%s*$");
 			if curr_group:match("^%+") then
 				curr_group = curr_group:gsub("^%+", "");
+				if not members[false] then
+					members[false] = {};
+				end
 				members[false][#members[false]+1] = curr_group; -- Is a public group
 			end
 			module:log("debug", "New group: %s", tostring(curr_group));
 			groups[curr_group] = groups[curr_group] or {};
 		else
 			-- Add JID
-			local jid = jid_prep(line);
+			local jid = jid_prep(line:match("%S+"));
 			if jid then
 				module:log("debug", "New member of %s: %s", tostring(curr_group), tostring(jid));
 				groups[curr_group][jid] = true;
--- a/plugins/mod_httpserver.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_httpserver.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_iq.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_iq.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -53,6 +53,18 @@
 	end
 end);
 
+module:hook("iq/self", function(data)
+	-- IQ to bare JID recieved
+	local origin, stanza = data.origin, data.stanza;
+
+	if stanza.attr.type == "get" or stanza.attr.type == "set" then
+		return module:fire_event("iq/self/"..stanza.tags[1].attr.xmlns..":"..stanza.tags[1].name, data);
+	else
+		module:fire_event("iq/self/"..stanza.attr.id, data);
+		return true;
+	end
+end);
+
 module:hook("iq/host", function(data)
 	-- IQ to a local host recieved
 	local origin, stanza = data.origin, data.stanza;
--- a/plugins/mod_lastactivity.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_lastactivity.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_legacyauth.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_legacyauth.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_message.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_message.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_offline.lua	Fri May 21 19:44:31 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
--- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
--- 
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-
-local datamanager = require "util.datamanager";
-local st = require "util.stanza";
-local datetime = require "util.datetime";
-local ipairs = ipairs;
-local jid_split = require "util.jid".split;
-
-module:add_feature("msgoffline");
-
-module:hook("message/offline/store", function(event)
-	local origin, stanza = event.origin, event.stanza;
-	local to = stanza.attr.to;
-	local node, host;
-	if to then
-		node, host = jid_split(to)
-	else
-		node, host = origin.username, origin.host;
-	end
-	
-	stanza.attr.stamp, stanza.attr.stamp_legacy = datetime.datetime(), datetime.legacy();
-	local result = datamanager.list_append(node, host, "offline", st.preserialize(stanza));
-	stanza.attr.stamp, stanza.attr.stamp_legacy = nil, nil;
-	
-	return true;
-end);
-
-module:hook("message/offline/broadcast", function(event)
-	local origin = event.origin;
-	local node, host = origin.username, origin.host;
-	
-	local data = datamanager.list_load(node, host, "offline");
-	if not data then return true; end
-	for _, stanza in ipairs(data) do
-		stanza = st.deserialize(stanza);
-		stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = host, stamp = stanza.attr.stamp}):up(); -- XEP-0203
-		stanza:tag("x", {xmlns = "jabber:x:delay", from = host, stamp = stanza.attr.stamp_legacy}):up(); -- XEP-0091 (deprecated)
-		stanza.attr.stamp, stanza.attr.stamp_legacy = nil, nil;
-		origin.send(stanza);
-	end
-	return true;
-end);
-
-module:hook("message/offline/delete", function(event)
-	local origin = event.origin;
-	local node, host = origin.username, origin.host;
-
-	return datamanager.list_store(node, host, "offline", nil);
-end);
--- a/plugins/mod_pep.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_pep.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_ping.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_ping.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_posix.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_posix.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -82,6 +82,7 @@
 	end
 	pidfile = module:get_option("pidfile");
 	if pidfile then
+		local err;
 		local mode = stat(pidfile) and "r+" or "w+";
 		pidfile_handle, err = io.open(pidfile, mode);
 		if not pidfile_handle then
--- a/plugins/mod_presence.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_presence.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_privacy.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_privacy.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2009-2010 Matthew Wild
+-- Copyright (C) 2009-2010 Waqas Hussain
 -- Copyright (C) 2009 Thilo Cestonaro
 -- 
 -- This project is MIT/X11 licensed. Please see the
@@ -13,7 +13,7 @@
 local bare_sessions, full_sessions = bare_sessions, full_sessions;
 local util_Jid = require "util.jid";
 local jid_bare = util_Jid.bare;
-local jid_split = util_Jid.split;
+local jid_split, jid_join = util_Jid.split, util_Jid.join;
 local load_roster = require "core.rostermanager".load_roster;
 local to_number = tonumber;
 
@@ -160,26 +160,7 @@
 			end
 		end
 		
-		if tmp.type == "group" then
-			local found = false;
-			local roster = load_roster(origin.username, origin.host);
-			for jid,item in pairs(roster) do
-				if item.groups ~= nil then
-					for group in pairs(item.groups) do
-						if group == tmp.value then
-							found = true;
-							break;
-						end
-					end
-					if found == true then
-						break;
-					end
-				end
-			end
-			if found == false then
-				return {"cancel", "item-not-found", "Specifed roster group not existing."};
-			end
-		elseif tmp.type == "subscription" then
+		if tmp.type == "subscription" then
 			if	tmp.value ~= "both" and
 				tmp.value ~= "to" and
 				tmp.value ~= "from" and
@@ -379,17 +360,22 @@
 				block = (item.action == "deny");
 			elseif item.type == "group" then
 				local roster = load_roster(session.username, session.host);
-				local groups = roster[evilJid.node .. "@" .. evilJid.host].groups;
-				for group in pairs(groups) do
-					if group == item.value then
-						apply = true;
-						block = (item.action == "deny");
-						break;
+				local roster_entry = roster[jid_join(evilJid.node, evilJid.host)];
+				if roster_entry then
+					local groups = roster_entry.groups;
+					for group in pairs(groups) do
+						if group == item.value then
+							apply = true;
+							block = (item.action == "deny");
+							break;
+						end
 					end
 				end
-			elseif item.type == "subscription" and evilJid.node ~= nil and evilJid.host ~= nil then -- we need a valid bare evil jid
+			elseif item.type == "subscription" then -- we need a valid bare evil jid
 				local roster = load_roster(session.username, session.host);
-				if roster[evilJid.node .. "@" .. evilJid.host].subscription == item.value then
+				local roster_entry = roster[jid_join(evilJid.node, evilJid.host)];
+				if (not(roster_entry) and item.value == "none")
+				   or (roster_entry and roster_entry.subscription == item.value) then
 					apply = true;
 					block = (item.action == "deny");
 				end
--- a/plugins/mod_private.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_private.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_proxy65.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_proxy65.lua	Fri May 21 19:45:33 2010 +0100
@@ -20,6 +20,7 @@
 local config_get = require "core.configmanager".get;
 local connlisteners = require "net.connlisteners";
 local sha1 = require "util.hashes".sha1;
+local server = require "net.server";
 
 local host, name = module:get_host(), "SOCKS5 Bytestreams Service";
 local sessions, transfers, component, replies_cache = {}, {}, nil, {};
@@ -28,6 +29,7 @@
 local proxy_interface = config_get(host, "core", "proxy65_interface") or "*";
 local proxy_address = config_get(host, "core", "proxy65_address") or (proxy_interface ~= "*" and proxy_interface) or host;
 local proxy_acl = config_get(host, "core", "proxy65_acl");
+local max_buffer_size = 4096;
 
 local connlistener = { default_port = proxy_port, default_interface = proxy_interface, default_mode = "*a" };
 
@@ -84,19 +86,19 @@
 				transfers[sha].initiator = conn;
 				session.sha = sha;
 				module:log("debug", "initiator connected ... ");
-				throttle_sending(conn, transfers[sha].target);
-				throttle_sending(transfers[sha].target, conn);
+				server.link(conn, transfers[sha].target, max_buffer_size);
+				server.link(transfers[sha].target, conn, max_buffer_size);
 			end
 			conn:write(string.char(5, 0, 0, 3, sha:len()) .. sha .. string.char(0, 0)); -- VER, REP, RSV, ATYP, BND.ADDR (sha), BND.PORT (2 Byte)
 			conn:lock_read(true)
 		else
 			module:log("warn", "Neither data transfer nor initial connect of a participator of a transfer.")
-			conn.close();
+			conn:close();
 		end
 	else
 		if data ~= nil then
 			module:log("warn", "unknown connection with no authentication data -> closing it");
-			conn.close();
+			conn:close();
 		end
 	end
 end
@@ -107,9 +109,9 @@
 		if session.sha and transfers[session.sha] then
 			local initiator, target = transfers[session.sha].initiator, transfers[session.sha].target;
 			if initiator == conn and target ~= nil then
-				target.close();
+				target:close();
 			elseif target == conn and initiator ~= nil then
-			 	initiator.close();
+			 	initiator:close();
 			end
 			transfers[session.sha] = nil;
 		end
@@ -234,8 +236,12 @@
 			elseif xmlns == "http://jabber.org/protocol/bytestreams" then
 				origin.send(get_stream_host(origin, stanza));
 				return true;
+			else
+				origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
+				return true;
 			end
 		elseif stanza.name == "iq" and type == "set" then
+			module:log("debug", "Received activation request from %s", stanza.attr.from);
 			local reply, from, to, sid = set_activation(stanza);
 			if reply ~= nil and from ~= nil and to ~= nil and sid ~= nil then
 				local sha = sha1(sid .. from .. to, true);
@@ -246,6 +252,15 @@
 					transfers[sha].activated = true;
 					transfers[sha].target:lock_read(false);
 					transfers[sha].initiator:lock_read(false);
+				else
+					module:log("debug", "Both parties were not yet connected");
+					local message = "Neither party is connected to the proxy";
+					if transfers[sha].initiator then
+						message = "The recipient is not connected to the proxy";
+					elseif transfers[sha].target then
+						message = "The sender (you) is not connected to the proxy";
+					end
+					origin.send(st.error_reply(stanza, "cancel", "not-allowed", message));
 				end
 			else
 				module:log("error", "activation failed: sid: %s, initiator: %s, target: %s", tostring(sid), tostring(from), tostring(to));
@@ -262,25 +277,3 @@
 
 connlisteners.start(module.host .. ':proxy65');
 component = componentmanager.register_component(host, handle_to_domain);
-local sender_lock_threshold = 4096;
-function throttle_sending(sender, receiver)
-	sender:pattern(sender_lock_threshold);
-	local sender_locked;
-	local _sendbuffer = receiver.sendbuffer;
-	function receiver.sendbuffer()
-		_sendbuffer();
-		if sender_locked and receiver.bufferlen() < sender_lock_threshold then
-			sender:lock_read(false); -- Unlock now
-			sender_locked = nil;
-		end
-	end
-	
-	local _readbuffer = sender.readbuffer;
-	function sender.readbuffer()
-		_readbuffer();
-		if not sender_locked and receiver.bufferlen() >= sender_lock_threshold then
-			sender_locked = true;
-			sender:lock_read(true);
-		end
-	end
-end
--- a/plugins/mod_register.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_register.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -12,6 +12,7 @@
 local datamanager = require "util.datamanager";
 local usermanager_user_exists = require "core.usermanager".user_exists;
 local usermanager_create_user = require "core.usermanager".create_user;
+local usermanager_set_password = require "core.usermanager".set_password;
 local datamanager_store = require "util.datamanager".store;
 local os_time = os.time;
 local nodeprep = require "util.encodings".stringprep.nodeprep;
@@ -34,7 +35,7 @@
 				local username, host = session.username, session.host;
 				--session.send(st.error_reply(stanza, "cancel", "not-allowed"));
 				--return;
-				usermanager_create_user(username, nil, host); -- Disable account
+				usermanager_set_password(username, host, nil); -- 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));
@@ -69,7 +70,7 @@
 					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?
+						if usermanager_set_password(username, session.host, password) then
 							session.send(st.reply(stanza));
 						else
 							-- TODO unable to write file, file may be locked, etc, what's the correct error?
--- a/plugins/mod_roster.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_roster.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -36,9 +36,10 @@
 				if stanza.attr.type == "get" then
 					local roster = st.reply(stanza);
 					
-					local ver = stanza.tags[1].attr.ver
+					local client_ver = tonumber(stanza.tags[1].attr.ver);
+					local server_ver = tonumber(session.roster[false].version or 1);
 					
-					if (not ver) or tonumber(ver) ~= (session.roster[false].version or 1) then
+					if not (client_ver and server_ver) or client_ver ~= server_ver then
 						roster:query("jabber:iq:roster");
 						-- Client does not support versioning, or has stale roster
 						for jid in pairs(session.roster) do
@@ -55,7 +56,7 @@
 								roster:up(); -- move out from item
 							end
 						end
-						roster.tags[1].attr.ver = tostring(session.roster[false].version or "1");
+						roster.tags[1].attr.ver = server_ver;
 					end
 					session.send(roster);
 					session.interested = true; -- resource is interested in roster updates
--- a/plugins/mod_saslauth.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_saslauth.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,7 +1,7 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
---
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
+-- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
 --
@@ -28,6 +28,12 @@
 local secure_auth_only = module:get_option("c2s_require_encryption") or module:get_option("require_encryption");
 local sasl_backend = module:get_option("sasl_backend") or "builtin";
 
+-- Cyrus config options
+local require_provisioning = module:get_option("cyrus_require_provisioning") or false;
+local cyrus_service_realm = module:get_option("cyrus_service_realm");
+local cyrus_service_name = module:get_option("cyrus_service_name");
+local cyrus_application_name = module:get_option("cyrus_application_name");
+
 local log = module._log;
 
 local xmlns_sasl ='urn:ietf:params:xml:ns:xmpp-sasl';
@@ -35,21 +41,29 @@
 local xmlns_stanzas ='urn:ietf:params:xml:ns:xmpp-stanzas';
 
 local new_sasl;
-if sasl_backend == "cyrus" then
-	local cyrus, err = pcall(require, "util.sasl_cyrus");
-	if cyrus then
+if sasl_backend == "builtin" then
+	new_sasl = require "util.sasl".new;
+elseif sasl_backend == "cyrus" then
+	prosody.unlock_globals(); --FIXME: Figure out why this is needed and
+	                          -- why cyrussasl isn't caught by the sandbox
+	local ok, cyrus = pcall(require, "util.sasl_cyrus");
+	prosody.lock_globals();
+	if ok then
 		local cyrus_new = cyrus.new;
 		new_sasl = function(realm)
-			return cyrus_new(realm, module:get_option("cyrus_service_name") or "xmpp");
+			return cyrus_new(
+				cyrus_service_realm or realm,
+				cyrus_service_name or "xmpp",
+				cyrus_application_name or "prosody"
+			);
 		end
 	else
-		sasl_backend = "builtin";
-		module:log("warn", "Failed to load Cyrus SASL, falling back to builtin auth mechanisms");
+		module:log("error", "Failed to load Cyrus SASL because: %s", cyrus);
+		error("Failed to load Cyrus SASL");
 	end
-end
-if not new_sasl then
-	if sasl_backend ~= "builtin" then module:log("warn", "Unknown SASL backend %s", sasl_backend); end;
-	new_sasl = require "util.sasl".new;
+else
+	module:log("error", "Unknown SASL backend: %s", sasl_backend);
+	error("Unknown SASL backend");
 end
 
 local default_authentication_profile = {
@@ -90,7 +104,7 @@
 	return reply;
 end
 
-local function handle_status(session, status)
+local function handle_status(session, status, ret, err_msg)
 	if status == "failure" then
 		session.sasl_handler = session.sasl_handler:clean_clone();
 	elseif status == "success" then
@@ -99,12 +113,20 @@
 			module:log("warn", "SASL succeeded but we didn't get a username!");
 			session.sasl_handler = nil;
 			session:reset_stream();
-			return;
+			return status, ret, err_msg;
 		end
-		sm_make_authenticated(session, session.sasl_handler.username);
-		session.sasl_handler = nil;
-		session:reset_stream();
+
+		if not(require_provisioning) or usermanager_user_exists(username, session.host) then
+			sm_make_authenticated(session, session.sasl_handler.username);
+			session.sasl_handler = nil;
+			session:reset_stream();
+		else
+			module:log("warn", "SASL succeeded but we don't have an account provisioned for %s", username);
+			session.sasl_handler = session.sasl_handler:clean_clone();
+			return "failure", "not-authorized", "User authenticated successfully, but not provisioned for XMPP";
+		end
 	end
+	return status, ret, err_msg;
 end
 
 local function sasl_handler(session, stanza)
@@ -138,7 +160,7 @@
 		end
 	end
 	local status, ret, err_msg = session.sasl_handler:process(text);
-	handle_status(session, status);
+	status, ret, err_msg = handle_status(session, status, ret, err_msg);
 	local s = build_reply(status, ret, err_msg);
 	log("debug", "sasl reply: %s", tostring(s));
 	session.send(s);
@@ -157,10 +179,11 @@
 		if secure_auth_only and not origin.secure then
 			return;
 		end
+		local realm = module:get_option("sasl_realm") or origin.host;
 		if module:get_option("anonymous_login") then
-			origin.sasl_handler = new_sasl(origin.host, anonymous_authentication_profile);
+			origin.sasl_handler = new_sasl(realm, anonymous_authentication_profile);
 		else
-			origin.sasl_handler = new_sasl(origin.host, default_authentication_profile);
+			origin.sasl_handler = new_sasl(realm, default_authentication_profile);
 			if not (module:get_option("allow_unencrypted_plain_auth")) and not origin.secure then
 				origin.sasl_handler:forbidden({"PLAIN"});
 			end
--- a/plugins/mod_selftests.lua	Fri May 21 19:44:31 2010 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,61 +0,0 @@
--- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
--- 
--- This project is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-module.host = "*" -- Global module
-
-local st = require "util.stanza";
-local register_component = require "core.componentmanager".register_component;
-local core_route_stanza = core_route_stanza;
-local socket = require "socket";
-local ping_hosts = module:get_option("ping_hosts") or { "coversant.interop.xmpp.org", "djabberd.interop.xmpp.org", "djabberd-trunk.interop.xmpp.org", "ejabberd.interop.xmpp.org", "openfire.interop.xmpp.org" };
-
-local open_pings = {};
-
-local t_insert = table.insert;
-
-local log = require "util.logger".init("mod_selftests");
-
-local tests_jid = "self_tests@getjabber.ath.cx";
-local host = "getjabber.ath.cx";
-
-if not (tests_jid and host) then
-	for currhost in pairs(host) do
-		if currhost ~= "localhost" then
-			tests_jid, host = "self_tests@"..currhost, currhost;
-		end
-	end
-end
-
-if tests_jid and host then
-	local bot = register_component(tests_jid, 	function(origin, stanza, ourhost)
-										local time = open_pings[stanza.attr.id];
-										
-										if time then
-											log("info", "Ping reply from %s in %fs", tostring(stanza.attr.from), socket.gettime() - time);
-										else
-											log("info", "Unexpected reply: %s", stanza:pretty_print());
-										end
-									end);
-
-
-	local our_origin = hosts[host];
-	module:add_event_hook("server-started", 
-					function ()
-						local id = st.new_id();
-						local ping_attr = { xmlns = 'urn:xmpp:ping' };
-						local function send_ping(to)
-							log("info", "Sending ping to %s", to);
-							core_route_stanza(our_origin, st.iq{ to = to, from = tests_jid, id = id, type = "get" }:tag("ping", ping_attr));
-							open_pings[id] = socket.gettime();
-						end
-						
-						for _, host in ipairs(ping_hosts) do
-							send_ping(host);
-						end
-					end);
-end
--- a/plugins/mod_time.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_time.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_tls.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_tls.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -10,6 +10,7 @@
 
 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 allow_s2s_tls = module:get_option("s2s_allow_encryption") ~= false;
 
 local xmlns_starttls = 'urn:ietf:params:xml:ns:xmpp-tls';
 local starttls_attr = { xmlns = xmlns_starttls };
@@ -27,8 +28,10 @@
 local function can_do_tls(session)
 	if session.type == "c2s_unauthed" then
 		return session.conn.starttls and host.ssl_ctx_in;
-	elseif session.type == "s2sin_unauthed" then
+	elseif session.type == "s2sin_unauthed" and allow_s2s_tls then
 		return session.conn.starttls and host.ssl_ctx_in;
+	elseif session.direction == "outgoing" and allow_s2s_tls then
+		return session.conn.starttls and host.ssl_ctx;
 	end
 	return false;
 end
@@ -69,7 +72,7 @@
 -- For s2sout connections, start TLS if we can
 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
+	if can_do_tls(session) 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;
--- a/plugins/mod_uptime.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_uptime.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_vcard.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_vcard.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_version.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_version.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_watchregistrations.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_watchregistrations.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/mod_welcome.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/mod_welcome.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/muc/mod_muc.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/muc/mod_muc.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/plugins/muc/muc.lib.lua	Fri May 21 19:44:31 2010 +0100
+++ b/plugins/muc/muc.lib.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -319,6 +319,11 @@
 								:tag("item", {affiliation=affiliation or "none", role=role or "none"}):up()
 								:tag("status", {code='110'}));
 						end
+						if self._data.whois == 'anyone' then -- non-anonymous?
+							self:_route_stanza(st.stanza("message", {from=to, to=from, type='groupchat'})
+								:tag("x", {xmlns='http://jabber.org/protocol/muc#user'})
+								:tag("status", {code='100'}));
+						end
 						self:send_history(from);
 					else -- banned
 						local reply = st.error_reply(stanza, "auth", "forbidden"):up();
@@ -514,6 +519,9 @@
 					if not item.attr.jid and item.attr.nick then -- COMPAT Workaround for Miranda sending 'nick' instead of 'jid' when changing affiliation
 						local occupant = self._occupants[self.jid.."/"..item.attr.nick];
 						if occupant then item.attr.jid = occupant.jid; end
+					elseif not item.attr.nick and item.attr.jid then
+						local nick = self._jid_nick[item.attr.jid];
+						if nick then item.attr.nick = select(3, jid_split(nick)); end
 					end
 					local reason = item.tags[1] and item.tags[1].name == "reason" and #item.tags[1] == 1 and item.tags[1][1];
 					if item.attr.affiliation and item.attr.jid and not item.attr.role then
@@ -743,7 +751,7 @@
 function room_mt:set_role(actor, occupant_jid, role, callback, reason)
 	if role == "none" then role = nil; end
 	if role and role ~= "moderator" and role ~= "participant" and role ~= "visitor" then return nil, "modify", "not-acceptable"; end
-	if self:get_affiliation(actor) ~= "owner" then return nil, "cancel", "not-allowed"; end
+	if self:get_role(self._jid_nick[actor]) ~= "moderator" then return nil, "cancel", "not-allowed"; end
 	local occupant = self._occupants[occupant_jid];
 	if not occupant then return nil, "modify", "not-acceptable"; end
 	if occupant.affiliation == "owner" or occupant.affiliation == "admin" then return nil, "cancel", "not-allowed"; end
@@ -796,9 +804,6 @@
 				end
 			end
 		end
-		if self._data.whois == 'anyone' then
-		    muc_child:tag('status', { code = '100' });
-		end
 	end
 	self:route_stanza(stanza);
 	if muc_child then
--- a/prosody	Fri May 21 19:44:31 2010 +0100
+++ b/prosody	Fri May 21 19:45:33 2010 +0100
@@ -1,7 +1,7 @@
 #!/usr/bin/env lua
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -123,6 +123,33 @@
 	end
 end
 
+function set_function_metatable()
+	local mt = {};
+	function mt.__index(f, upvalue)
+		local i, name, value = 0;
+		repeat
+			i = i + 1;
+			name, value = debug.getupvalue(f, i);
+		until name == upvalue or name == nil;
+		return value;
+	end
+	function mt.__newindex(f, upvalue, value)
+		local i, name = 0;
+		repeat
+			i = i + 1;
+			name = debug.getupvalue(f, i);
+		until name == upvalue or name == nil;
+		if name then
+			debug.setupvalue(f, i, value);
+		end
+	end
+	function mt.__tostring(f)
+		local info = debug.getinfo(f);
+		return ("function(%s:%d)"):format(info.short_src:match("[^\\/]*$"), info.linedefined);
+	end
+	debug.setmetatable(function() end, mt);
+end
+
 function init_global_state()
 	bare_sessions = {};
 	full_sessions = {};
@@ -418,6 +445,7 @@
 init_logging();
 check_dependencies();
 sandbox_require();
+set_function_metatable();
 load_libraries();
 init_global_state();
 read_version();
--- a/prosody.cfg.lua.dist	Fri May 21 19:44:31 2010 +0100
+++ b/prosody.cfg.lua.dist	Fri May 21 19:45:33 2010 +0100
@@ -1,110 +1,127 @@
 -- Prosody Example Configuration File
 -- 
--- If it wasn't already obvious, -- starts a comment, and all
--- text after it on a line is ignored by Prosody.
---
--- The config is split into sections, a global section, and one
--- for each defined host that we serve. You can add as many host
--- sections as you like.
---
--- Lists are written { "like", "this", "one" }
--- Lists can also be of { 1, 2, 3 } numbers, and other things.
--- Either commas, or semi-colons; may be used
--- as seperators.
---
--- A table is a list of values, except each value has a name. An
--- example table would be:
---
--- ssl = { key = "keyfile.key", certificate = "certificate.cert" }
---
--- Whitespace (that is tabs, spaces, line breaks) is mostly insignificant, so
--- can
--- be placed anywhere that 	you deem fitting.
---
--- Tip: You can check that the syntax of this file is correct when you have finished
--- by running: luac -p prosody.cfg.lua
--- If there are any errors, it will let you know what and where they are, otherwise it
--- will keep quiet.
+-- Information on configuring Prosody can be found on our
+-- website at http://prosody.im/doc/configure
+-- 
+-- Tip: You can check that the syntax of this file is correct
+-- when you have finished by running: luac -p prosody.cfg.lua
+-- If there are any errors, it will let you know what and where
+-- they are, otherwise it will keep quiet.
 --
 -- The only thing left to do is rename this file to remove the .dist ending, and fill in the
 -- blanks. Good luck, and happy Jabbering!
 
--- Server-wide settings go in this section
-Host "*"
-	
-	-- This is a (by default, empty) list of accounts that are admins
-	-- for the server. Note that you must create the accounts separately
-	-- (see http://prosody.im/doc/creating_accounts for info)
-	-- Example: admins = { "user1@example.com", "user2@example.net" }
-	admins = { }
-	
-	-- This is the list of modules Prosody will load on startup.
-	-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too.
-	modules_enabled = {
-			-- Generally required
-				"roster"; -- Allow users to have a roster. Recommended ;)
-				"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
-				"tls"; -- Add support for secure TLS on c2s/s2s connections
-				"dialback"; -- s2s dialback support
-			  	"disco"; -- Service discovery
-			
-			-- Not essential, but recommended
-				"private"; -- Private XML storage (for room bookmarks, etc.)
-				"vcard"; -- Allow users to set vCards
-			
-			-- Nice to have
-				"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
-				"version"; -- Replies to server version requests
-			  	"uptime"; -- Report how long server has been running
-			  	"time"; -- Let others know the time here on this server
-			  	"ping"; -- Replies to XMPP pings with pongs
-			  	"pep"; -- Enables users to publish their mood, activity, playing music and more
-				"register"; -- Allow users to register on this server using a client and change passwords
+
+---------- Server-wide settings ----------
+-- Settings in this section apply to the whole server and are the default settings
+-- for any virtual hosts
+
+-- This is a (by default, empty) list of accounts that are admins
+-- for the server. Note that you must create the accounts separately
+-- (see http://prosody.im/doc/creating_accounts for info)
+-- Example: admins = { "user1@example.com", "user2@example.net" }
+admins = { }
+
+-- Enable use of libevent for better performance under high load
+-- For more information see: http://prosody.im/doc/libevent
+--use_libevent = true;
+
+-- This is the list of modules Prosody will load on startup.
+-- It looks for mod_modulename.lua in the plugins folder, so make sure that exists too.
+-- Documentation on modules can be found at: http://prosody.im/doc/modules
+modules_enabled = {
+
+	-- Generally required
+		"roster"; -- Allow users to have a roster. Recommended ;)
+		"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
+		"tls"; -- Add support for secure TLS on c2s/s2s connections
+		"dialback"; -- s2s dialback support
+		"disco"; -- Service discovery
+
+	-- Not essential, but recommended
+		"private"; -- Private XML storage (for room bookmarks, etc.)
+		"vcard"; -- Allow users to set vCards
+		--"privacy"; -- Support privacy lists
+		--"compression"; -- Stream compression
+
+	-- Nice to have
+		"legacyauth"; -- Legacy authentication. Only used by some old clients and bots.
+		"version"; -- Replies to server version requests
+		"uptime"; -- Report how long server has been running
+		"time"; -- Let others know the time here on this server
+		"ping"; -- Replies to XMPP pings with pongs
+		"pep"; -- Enables users to publish their mood, activity, playing music and more
+		"register"; -- Allow users to register on this server using a client and change passwords
 
-			-- Other specific functionality
-				--"posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
-			  	--"console"; -- Opens admin telnet interface on localhost port 5582
-				--"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
-				--"httpserver"; -- Serve static files from a directory over HTTP
-			  };
-	
-	-- These modules are auto-loaded, should you
-	-- for (for some mad reason) want to disable
-	-- them then uncomment them below
-	modules_disabled = {
-			-- "presence";
-			-- "message";
-			-- "iq";
-	};
+	-- Other specific functionality
+		--"posix"; -- POSIX functionality, sends server to background, enables syslog, etc.
+		--"console"; -- Opens admin telnet interface on localhost port 5582
+		--"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
+		--"httpserver"; -- Serve static files from a directory over HTTP
+		--"groups"; -- Shared roster support
+		--"announce"; -- Send announcement to all online users
+		--"welcome"; -- Welcome users who register accounts
+		--"watchregistrations"; -- Alert admins of registrations
+};
+
+-- These modules are auto-loaded, should you
+-- for (for some mad reason) want to disable
+-- them then uncomment them below
+modules_disabled = {
+	-- "presence";
+	-- "message";
+	-- "iq";
+};
 
-	-- Disable account creation by default, for security
-	-- For more information see http://prosody.im/doc/creating_accounts
-	allow_registration = false;
+-- Disable account creation by default, for security
+-- For more information see http://prosody.im/doc/creating_accounts
+allow_registration = false;
 	
-	-- These are the SSL/TLS-related settings. If you don't want
-	-- to use SSL/TLS, you may comment or remove this
-	ssl = {
-		key = "certs/localhost.key";
-		certificate = "certs/localhost.cert";
-		}
+-- These are the SSL/TLS-related settings. If you don't want
+-- to use SSL/TLS, you may comment or remove this
+ssl = {
+	key = "certs/localhost.key";
+	certificate = "certs/localhost.cert";
+}
+
+-- Require encryption on client/server connections?
+--c2s_require_encryption = false
+--s2s_require_encryption = false
 
--- This allows clients to connect to localhost. No harm in it.
-Host "localhost"
+-- Logging configuration
+-- For advanced logging see http://prosody.im/doc/logging
+log = "prosody.log";
+debug = false; -- Log debug messages?
 
--- Section for example.com
--- (replace example.com with your domain name)
-Host "example.com"
+----------- Virtual hosts -----------
+-- You need to add a VirtualHost entry for each domain you wish Prosody to serve.
+-- Settings under each VirtualHost entry apply *only* to that host.
 
-	enabled = false -- This will disable the host, preserving the config, but denying connections
+VirtualHost "localhost"
+
+VirtualHost "example.com"
+	enabled = false -- Remove this line to enable this host
 
 	-- Assign this host a certificate for TLS, otherwise it would use the one
 	-- set in the global section (if any).
 	-- Note that old-style SSL on port 5223 only supports one certificate, and will always
 	-- use the global one.
-	ssl = {
+	ssl = { 
 		key = "certs/example.com.key";
 		certificate = "certs/example.com.crt";
-		}
+	}
+
+------ Components ------
+-- You can specify components to add hosts that provide special services,
+-- like multi-user conferences, and transports.
+-- For more information on components, see http://prosody.im/doc/components
 
--- Set up a MUC (multi-user chat) room server on conference.example.com:
-Component "conference.example.com" "muc"
+---Set up a MUC (multi-user chat) room server on conference.example.com:
+--Component "conference.example.com" "muc"
+
+-- Set up a SOCKS5 bytestream proxy for server-proxied file transfers:
+--Component "proxy.example.com" "proxy65"
+
+---Set up an external component (default component port is 5347)
+--Component "gateway.example.com"
+--	component_secret = "password"
--- a/prosodyctl	Fri May 21 19:44:31 2010 +0100
+++ b/prosodyctl	Fri May 21 19:45:33 2010 +0100
@@ -433,6 +433,19 @@
 	return 1;
 end
 
+function commands.restart(arg)
+	if arg[1] == "--help" then
+		show_usage([[restart]], [[Restart a running Prosody server]]);
+		return 1;
+	end
+	
+	local ret = commands.stop(arg);
+	if ret == 0 then
+		ret = commands.start(arg);
+	end
+	return ret;
+end
+
 -- ejabberdctl compatibility
 
 function commands.register(arg)
@@ -491,6 +504,10 @@
 	};
 
 function commands.addplugin(arg)
+	if not arg[1] or arg[1] == "--help" then
+		show_usage("addplugin URL", "Download and install a plugin from a URL");
+		return 1;
+	end
 	local url = arg[1];
 	if url:match("^http://") then
 		local http = require "socket.http";
@@ -562,8 +579,8 @@
 	print("");
 	print("Where COMMAND may be one of:\n");
 
-	local hidden_commands = require "util.set".new{ "register", "unregister" };
-	local commands_order = { "adduser", "passwd", "deluser" };
+	local hidden_commands = require "util.set".new{ "register", "unregister", "addplugin" };
+	local commands_order = { "adduser", "passwd", "deluser", "start", "stop", "restart" };
 
 	local done = {};
 
--- a/tests/test.lua	Fri May 21 19:44:31 2010 +0100
+++ b/tests/test.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/tests/test_core_configmanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/tests/test_core_configmanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/tests/test_core_modulemanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/tests/test_core_modulemanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/tests/test_core_s2smanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/tests/test_core_s2smanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -30,18 +30,18 @@
 	assert_equal(csp(r3, r2), false);
 	assert_equal(csp(r3, r3), false);
 	assert_equal(csp(r3, r4), false);
-	assert_equal(csp(r3, r5), true);
+	assert_equal(csp(r3, r5), false);
 
 	assert_equal(csp(r4, r1), false);
 	assert_equal(csp(r4, r2), false);
 	assert_equal(csp(r4, r3), false);
 	assert_equal(csp(r4, r4), false);
-	assert_equal(csp(r4, r5), true);
+	assert_equal(csp(r4, r5), false);
 
 	assert_equal(csp(r5, r1), false);
 	assert_equal(csp(r5, r2), false);
-	assert_equal(csp(r5, r3), false);
-	assert_equal(csp(r5, r4), false);
+	assert_equal(csp(r5, r3), true);
+	assert_equal(csp(r5, r4), true);
 	assert_equal(csp(r5, r5), false);
 
 end
--- a/tests/test_core_stanza_router.lua	Fri May 21 19:44:31 2010 +0100
+++ b/tests/test_core_stanza_router.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/tests/test_sasl.lua	Fri May 21 19:44:31 2010 +0100
+++ b/tests/test_sasl.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/tests/test_util_jid.lua	Fri May 21 19:44:31 2010 +0100
+++ b/tests/test_util_jid.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/tests/test_util_multitable.lua	Fri May 21 19:44:31 2010 +0100
+++ b/tests/test_util_multitable.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/tests/test_util_stanza.lua	Fri May 21 19:44:31 2010 +0100
+++ b/tests/test_util_stanza.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/tests/util/logger.lua	Fri May 21 19:44:31 2010 +0100
+++ b/tests/util/logger.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/tools/ejabberd2prosody.lua	Fri May 21 19:44:31 2010 +0100
+++ b/tools/ejabberd2prosody.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,7 +1,7 @@
 #!/usr/bin/env lua
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -17,6 +17,8 @@
 
 require "erlparse";
 
+prosody = {};
+
 local serialize = require "util.serialization".serialize;
 local st = require "util.stanza";
 package.loaded["util.logger"] = {init = function() return function() end; end}
@@ -49,7 +51,7 @@
 end
 function password(node, host, password)
 	local ret, err = dm.store(node, host, "accounts", {password = password});
-	print("["..(err or "success").."] accounts: "..node.."@"..host.." = "..password);
+	print("["..(err or "success").."] accounts: "..node.."@"..host);
 end
 function roster(node, host, jid, item)
 	local roster = dm.load(node, host, "roster") or {};
--- a/tools/ejabberdsql2prosody.lua	Fri May 21 19:44:31 2010 +0100
+++ b/tools/ejabberdsql2prosody.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,7 +1,7 @@
 #!/usr/bin/env lua
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -254,7 +254,7 @@
 for i, row in ipairs(t["users"] or NULL) do
 	local node, password = row.username, row.password;
 	local ret, err = dm.store(node, host, "accounts", {password = password});
-	print("["..(err or "success").."] accounts: "..node.."@"..host.." = "..password);
+	print("["..(err or "success").."] accounts: "..node.."@"..host);
 end
 
 function roster(node, host, jid, item)
--- a/tools/erlparse.lua	Fri May 21 19:44:31 2010 +0100
+++ b/tools/erlparse.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,21 +1,27 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
 --
 
-
+local string_byte, string_char = string.byte, string.char;
+local t_concat, t_insert = table.concat, table.insert;
+local type, tonumber, tostring = type, tonumber, tostring;
 
 local file = nil;
 local last = nil;
+local line = 1;
 local function read(expected)
 	local ch;
 	if last then
 		ch = last; last = nil;
-	else ch = file:read(1); end
-	if expected and ch ~= expected then error("expected: "..expected.."; got: "..(ch or "nil")); end
+	else
+		ch = file:read(1);
+		if ch == "\n" then line = line + 1; end
+	end
+	if expected and ch ~= expected then error("expected: "..expected.."; got: "..(ch or "nil").." on line "..line); end
 	return ch;
 end
 local function pushback(ch)
@@ -27,21 +33,21 @@
 	return last;
 end
 
-local _A, _a, _Z, _z, _0, _9, __, _at, _space = string.byte("AaZz09@_ ", 1, 9);
+local _A, _a, _Z, _z, _0, _9, __, _at, _space, _minus = string_byte("AaZz09@_ -", 1, 10);
 local function isLowerAlpha(ch)
-	ch = string.byte(ch) or 0;
+	ch = string_byte(ch) or 0;
 	return (ch >= _a and ch <= _z);
 end
 local function isNumeric(ch)
-	ch = string.byte(ch) or 0;
-	return (ch >= _0 and ch <= _9);
+	ch = string_byte(ch) or 0;
+	return (ch >= _0 and ch <= _9) or ch == _minus;
 end
 local function isAtom(ch)
-	ch = string.byte(ch) or 0;
+	ch = string_byte(ch) or 0;
 	return (ch >= _A and ch <= _Z) or (ch >= _a and ch <= _z) or (ch >= _0 and ch <= _9) or ch == __ or ch == _at;
 end
 local function isSpace(ch)
-	ch = string.byte(ch) or "x";
+	ch = string_byte(ch) or "x";
 	return ch <= _space;
 end
 
@@ -49,79 +55,85 @@
 local function readString()
 	read("\""); -- skip quote
 	local slash = nil;
-	local str = "";
+	local str = {};
 	while true do
 		local ch = read();
 		if slash then
 			slash = slash..ch;
 			if not escapes[slash] then error("Unknown escape sequence: "..slash); end
-			str = str..escapes[slash];
+			str[#str+1] = escapes[slash];
 			slash = nil;
 		elseif ch == "\"" then
 			break;
 		elseif ch == "\\" then
 			slash = ch;
 		else
-			str = str..ch;
+			str[#str+1] = ch;
 		end
 	end
-	return str;
+	return t_concat(str);
 end
 local function readAtom1()
-	local var = read();
+	local var = { read() };
 	while isAtom(peek()) do
-		var = var..read();
+		var[#var+1] = read();
 	end
-	return var;
+	return t_concat(var);
 end
 local function readAtom2()
-	local str = read("'");
+	local str = { read("'") };
 	local slash = nil;
 	while true do
 		local ch = read();
-		str = str..ch;
+		str[#str+1] = ch;
 		if ch == "'" and not slash then break; end
 	end
-	return str;
+	return t_concat(str);
 end
 local function readNumber()
-	local num = read();
+	local num = { read() };
 	while isNumeric(peek()) do
-		num = num..read();
+		num[#num+1] = read();
 	end
-	return tonumber(num);
+	return tonumber(t_concat(num));
 end
 local readItem = nil;
 local function readTuple()
 	local t = {};
-	local s = ""; -- string representation
+	local s = {}; -- string representation
 	read(); -- read {, or [, or <
 	while true do
 		local item = readItem();
 		if not item then break; end
-		if type(item) ~= type(0) or item > 255 then
+		if type(item) ~= "number" or item > 255 then
 			s = nil;
 		elseif s then
-			s = s..string.char(item);
+			s[#s+1] = string_char(item);
 		end
-		table.insert(t, item);
+		t_insert(t, item);
 	end
 	read(); -- read }, or ], or >
-	if s and s ~= "" then
-		return s
+	if s and #s > 0  then
+		return t_concat(s)
 	else
 		return t
 	end;
 end
 local function readBinary()
 	read("<"); -- read <
+	-- Discard PIDs
+	if isNumeric(peek()) then
+		while peek() ~= ">" do read(); end
+		read(">");
+		return {};
+	end
 	local t = readTuple();
 	read(">") -- read >
 	local ch = peek();
-	if type(t) == type("") then
+	if type(t) == "string" then
 		-- binary is a list of integers
 		return t;
-	elseif type(t) == type({}) then
+	elseif type(t) == "table" then
 		if t[1] then
 			-- binary contains string
 			return t[1];
--- a/util-src/encodings.c	Fri May 21 19:44:31 2010 +0100
+++ b/util-src/encodings.c	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
-/* Prosody IM v0.4
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+/* Prosody IM
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util-src/hashes.c	Fri May 21 19:44:31 2010 +0100
+++ b/util-src/hashes.c	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
-/* Prosody IM v0.4
--- Copyright (C) 2008 Matthew Wild
--- Copyright (C) 2008 Waqas Hussain
+/* Prosody IM
+-- Copyright (C) 2009-2010 Matthew Wild
+-- Copyright (C) 2009-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util-src/pposix.c	Fri May 21 19:44:31 2010 +0100
+++ b/util-src/pposix.c	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
-/* Prosody IM v0.4
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+/* Prosody IM
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- Copyright (C) 2009 Tobias Markmann
 --
 -- This project is MIT/X11 licensed. Please see the
--- a/util-src/windows.c	Fri May 21 19:44:31 2010 +0100
+++ b/util-src/windows.c	Fri May 21 19:45:33 2010 +0100
@@ -1,45 +1,58 @@
-
-#include <stdio.h>
-#include <windows.h>
-#include <windns.h>
-
-#include "lua.h"
-#include "lauxlib.h"
-
-static int Lget_nameservers(lua_State *L) {
-	char stack_buffer[1024]; // stack allocated buffer
-	IP4_ARRAY* ips = (IP4_ARRAY*) stack_buffer;
-	DWORD len = sizeof(stack_buffer);
-	DNS_STATUS status;
-
-	status = DnsQueryConfig(DnsConfigDnsServerList, FALSE, NULL, NULL, ips, &len);
-	if (status == 0) {
-		DWORD i;
-		lua_createtable(L, ips->AddrCount, 0);
-		for (i = 0; i < ips->AddrCount; i++) {
-			DWORD ip = ips->AddrArray[i];
-			char ip_str[16] = "";
-			sprintf_s(ip_str, sizeof(ip_str), "%d.%d.%d.%d", (ip >> 0) & 255, (ip >> 8) & 255, (ip >> 16) & 255, (ip >> 24) & 255);
-			lua_pushstring(L, ip_str);
-			lua_rawseti(L, -2, i+1);
-		}
-		return 1;
-	} else {
-		luaL_error(L, "DnsQueryConfig returned %d", status);
-		return 0; // unreachable, but prevents a compiler warning
-	}
-}
-
-static const luaL_Reg Reg[] =
-{
-	{ "get_nameservers",	Lget_nameservers	},
-	{ NULL,		NULL	}
-};
-
-LUALIB_API int luaopen_util_windows(lua_State *L) {
-	luaL_register(L, "windows", Reg);
-	lua_pushliteral(L, "version");			/** version */
-	lua_pushliteral(L, "-3.14");
-	lua_settable(L,-3);
-	return 1;
-}
+/* Prosody IM
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
+-- 
+-- This project is MIT/X11 licensed. Please see the
+-- COPYING file in the source package for more information.
+--
+*/
+
+/*
+* windows.c
+* Windows support functions for Lua
+*/
+
+#include <stdio.h>
+#include <windows.h>
+#include <windns.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+
+static int Lget_nameservers(lua_State *L) {
+	char stack_buffer[1024]; // stack allocated buffer
+	IP4_ARRAY* ips = (IP4_ARRAY*) stack_buffer;
+	DWORD len = sizeof(stack_buffer);
+	DNS_STATUS status;
+
+	status = DnsQueryConfig(DnsConfigDnsServerList, FALSE, NULL, NULL, ips, &len);
+	if (status == 0) {
+		DWORD i;
+		lua_createtable(L, ips->AddrCount, 0);
+		for (i = 0; i < ips->AddrCount; i++) {
+			DWORD ip = ips->AddrArray[i];
+			char ip_str[16] = "";
+			sprintf_s(ip_str, sizeof(ip_str), "%d.%d.%d.%d", (ip >> 0) & 255, (ip >> 8) & 255, (ip >> 16) & 255, (ip >> 24) & 255);
+			lua_pushstring(L, ip_str);
+			lua_rawseti(L, -2, i+1);
+		}
+		return 1;
+	} else {
+		luaL_error(L, "DnsQueryConfig returned %d", status);
+		return 0; // unreachable, but prevents a compiler warning
+	}
+}
+
+static const luaL_Reg Reg[] =
+{
+	{ "get_nameservers",	Lget_nameservers	},
+	{ NULL,		NULL	}
+};
+
+LUALIB_API int luaopen_util_windows(lua_State *L) {
+	luaL_register(L, "windows", Reg);
+	lua_pushliteral(L, "version");			/** version */
+	lua_pushliteral(L, "-3.14");
+	lua_settable(L,-3);
+	return 1;
+}
--- a/util/array.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/array.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/broadcast.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/broadcast.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/dataforms.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/dataforms.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/datamanager.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/datamanager.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/datetime.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/datetime.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/dependencies.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/dependencies.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/events.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/events.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/helpers.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/helpers.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/hmac.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/hmac.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/import.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/import.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/iterators.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/iterators.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/jid.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/jid.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/logger.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/logger.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/multitable.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/multitable.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/pluginloader.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/pluginloader.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/prosodyctl.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/prosodyctl.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/sasl.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/sasl.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,5 +1,5 @@
 -- sasl.lua v0.4
--- Copyright (C) 2008-2009 Tobias Markmann
+-- Copyright (C) 2008-2010 Tobias Markmann
 --
 --    All rights reserved.
 --
@@ -143,7 +143,7 @@
 end
 
 -- load the mechanisms
-load_mechs = {"plain", "digest-md5", "anonymous", "scram"}
+local load_mechs = {"plain", "digest-md5", "anonymous", "scram"}
 for _, mech in ipairs(load_mechs) do
 	local name = "util.sasl."..mech;
 	local m = require(name);
--- a/util/sasl/digest-md5.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/sasl/digest-md5.lua	Fri May 21 19:45:33 2010 +0100
@@ -35,8 +35,6 @@
 	local function serialize(message)
 		local data = ""
 
-		if type(message) ~= "table" then error("serialize needs an argument of type table.") end
-
 		-- testing all possible values
 		if message["realm"] then data = data..[[realm="]]..message.realm..[[",]] end
 		if message["nonce"] then data = data..[[nonce="]]..message.nonce..[[",]] end
--- a/util/sasl/scram.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/sasl/scram.lua	Fri May 21 19:45:33 2010 +0100
@@ -15,7 +15,6 @@
 local type = type
 local string = string
 local base64 = require "util.encodings".base64;
-local xor = require "bit".bxor
 local hmac_sha1 = require "util.hmac".sha1;
 local sha1 = require "util.hashes".sha1;
 local generate_uuid = require "util.uuid".generate;
--- a/util/sasl_cyrus.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/sasl_cyrus.lua	Fri May 21 19:45:33 2010 +0100
@@ -39,24 +39,37 @@
 		if st then
 			initialized = true;
 		else
-			log("error", "Failed to initialize CyrusSASL: %s", errmsg);
+			log("error", "Failed to initialize Cyrus SASL: %s", errmsg);
 		end
 	end
 end
 
 -- create a new SASL object which can be used to authenticate clients
-function new(realm, service_name)
+function new(realm, service_name, app_name)
 	local sasl_i = {};
 
-	init(service_name);
+	init(app_name or service_name);
 
 	sasl_i.realm = realm;
 	sasl_i.service_name = service_name;
-	sasl_i.cyrus = cyrussasl.server_new(service_name, nil, nil, nil, nil)
-	if sasl_i.cyrus == 0 then
-		log("error", "got NULL return value from server_new")
+
+	local st, ret = pcall(cyrussasl.server_new, service_name, nil, realm, nil, nil)
+	if st then
+		sasl_i.cyrus = ret;
+	else
+		log("error", "Creating SASL server connection failed: %s", ret);
 		return nil;
 	end
+
+	if cyrussasl.set_canon_cb then
+		local c14n_cb = function (user)
+			local node = s_match(user, "^([^@]+)");
+			log("debug", "Canonicalizing username %s to %s", user, node)
+			return node
+		end
+		cyrussasl.set_canon_cb(sasl_i.cyrus, c14n_cb);
+	end
+
 	cyrussasl.setssf(sasl_i.cyrus, 0, 0xffffffff)
 	local s = setmetatable(sasl_i, method);
 	return s;
@@ -69,7 +82,7 @@
 
 -- set the forbidden mechanisms
 function method:forbidden( restrict )
-	log("debug", "Called method:forbidden. NOT IMPLEMENTED.")
+	log("warn", "Called method:forbidden. NOT IMPLEMENTED.")
 	return {}
 end
 
@@ -87,6 +100,7 @@
 -- select a mechanism to use
 function method:select(mechanism)
 	self.mechanism = mechanism;
+	if not self.mechs then self:mechanisms(); end
 	return self.mechs[mechanism];
 end
 
@@ -109,16 +123,12 @@
 	   return "challenge", data
 	elseif (err == -4) then -- SASL_NOMECH
 	   log("debug", "SASL mechanism not available from remote end")
-	   return "failure", 
-	     "undefined-condition",
-	     "SASL mechanism not available"
+	   return "failure", "invalid-mechanism", "SASL mechanism not available"
 	elseif (err == -13) then -- SASL_BADAUTH
 	   return "failure", "not-authorized", cyrussasl.get_message( self.cyrus )
 	else
 	   log("debug", "Got SASL error condition %d", err)
-	   return "failure", 
-	     "undefined-condition",
-	     cyrussasl.get_message( self.cyrus )
+	   return "failure", "undefined-condition", cyrussasl.get_message( self.cyrus )
 	end
 end
 
--- a/util/serialization.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/serialization.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/set.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/set.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/stanza.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/stanza.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -247,14 +247,14 @@
 		for i=1,#attr do attr[i] = nil; end
 		local attrx = {};
 		for att in pairs(attr) do
-			if s_find(att, "|", 1, true) and not s_find(k, "\1", 1, true) then
-				local ns,na = s_match(k, "^([^|]+)|(.+)$");
+			if s_find(att, "|", 1, true) and not s_find(att, "\1", 1, true) then
+				local ns,na = s_match(att, "^([^|]+)|(.+)$");
 				attrx[ns.."\1"..na] = attr[att];
 				attr[att] = nil;
 			end
 		end
 		for a,v in pairs(attrx) do
-			attr[x] = v;
+			attr[a] = v;
 		end
 		setmetatable(stanza, stanza_mt);
 		for _, child in ipairs(stanza) do
--- a/util/termcolours.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/termcolours.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/timer.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/timer.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -55,11 +55,12 @@
 else
 	local EVENT_LEAVE = (event.core and event.core.LEAVE) or -1;
 	function _add_task(delay, func)
-		event_base:addevent(nil, 0, function ()
+		local event_handle;
+		event_handle = event_base:addevent(nil, 0, function ()
 			local ret = func();
 			if ret then
 				return 0, ret;
-			else
+			elseif event_handle then
 				return EVENT_LEAVE;
 			end
 		end
--- a/util/uuid.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/uuid.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
@@ -32,7 +32,7 @@
 	buffer = new_random(buffer..x);
 end
 local function get_nibbles(n)
-	if #buffer < n then seed(uniq_time()); end
+	if #buffer < n then _seed(uniq_time()); end
 	local r = buffer:sub(0, n);
 	buffer = buffer:sub(n+1);
 	return r;
--- a/util/xmlrpc.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/xmlrpc.lua	Fri May 21 19:45:33 2010 +0100
@@ -1,6 +1,6 @@
 -- Prosody IM
--- Copyright (C) 2008-2009 Matthew Wild
--- Copyright (C) 2008-2009 Waqas Hussain
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
 -- 
 -- This project is MIT/X11 licensed. Please see the
 -- COPYING file in the source package for more information.
--- a/util/ztact.lua	Fri May 21 19:44:31 2010 +0100
+++ b/util/ztact.lua	Fri May 21 19:45:33 2010 +0100
@@ -114,7 +114,7 @@
 
 function tostring_r (d, indent, tab0)    -- - - - - - - - - - - - -  tostring_r
 
-  tab1 = tab0 or {}
+  local tab1 = tab0 or {}
   local rep = string.rep ('  ', indent or 0)
   if type (d) == 'table' then
     for k,v in pairs (d) do
@@ -210,7 +210,7 @@
 
 
 local function test_queue ()
-  t = {}
+  local t = {}
   enqueue (t, 1)
   enqueue (t, 2)
   enqueue (t, 3)

mercurial