changeset 461:bbea8081c865

Revert various changes accidentally included in previous commit
author Kim Alvefur <zash@zash.se>
date Sat, 29 Oct 2011 13:34:15 +0200
parents 9bb9343f3c7a
children f28a3f260fc2
files mod_auth_sql/mod_auth_sql.lua mod_data_access/mod_data_access.lua mod_ircd/mod_ircd_broke.lua mod_ircd/squishy mod_pubsub_feed/mod_pubsub_feed.lua
diffstat 5 files changed, 52 insertions(+), 5477 deletions(-) [+]
line wrap: on
line diff
--- a/mod_auth_sql/mod_auth_sql.lua	Mon Oct 24 00:20:51 2011 +0000
+++ b/mod_auth_sql/mod_auth_sql.lua	Sat Oct 29 13:34:15 2011 +0200
@@ -7,16 +7,11 @@
 local new_sasl = require "util.sasl".new;
 local nodeprep = require "util.encodings".stringprep.nodeprep;
 local DBI = require "DBI"
-local crypt = require "crypt";
 
 local connection;
 local params = module:get_option("sql");
-local host = module.host;
-local realm = module:get_option_string("realm", host);
-local mitm_mode = module:get_option_boolean("mitm_mode");
 
 local resolve_relative_path = require "core.configmanager".resolve_relative_path;
-local datamanager = require "util.datamanager";
 
 local function test_connection()
 	if not connection then return nil; end
@@ -77,7 +72,7 @@
 end
 
 local function get_password(username)
-	local stmt, err = getsql("SELECT `password` FROM `users` WHERE `email`=?", username .. "@" .. realm);
+	local stmt, err = getsql("SELECT `password` FROM `authreg` WHERE `username`=? AND `realm`=?", username, module.host);
 	if stmt then
 		for row in stmt:rows(true) do
 			return row.password;
@@ -85,56 +80,38 @@
 	end
 end
 
+
 provider = { name = "sql" };
 
 function provider.test_password(username, password)
-	local local_data = datamanager.load(username, realm, "accounts") or {};
-	if data.password == password then return true end
-	local dirty;
-	local hash = data.crypted_password;
-	if not hash then
-		hash = get_password(username);
-		if hash then
-			data.crypted_password = hash;
-			dirty = true;
-		else
-			return false
-		end
-	end
-	local ok = password and crypt(password, hash) == password;
-	if ok and mitm_mode then
-		local_data.password = password;
-		dirty = true
-	end
-	if dirty then
-		datamanager.store(username, realm, "accounts", local_data);
-	end
-	return ok
+	return password and get_password(username) == password;
 end
 function provider.get_password(username)
-	return nil, "Getting password is not supported.";
+	return get_password(username);
 end
 function provider.set_password(username, password)
 	return nil, "Setting password is not supported.";
 end
 function provider.user_exists(username)
-	return datamanager.load(username, realm, "accounts") or get_password(username) and true;
+	return get_password(username) and true;
 end
 function provider.create_user(username, password)
 	return nil, "Account creation/modification not supported.";
 end
 function provider.get_sasl_handler()
 	local profile = {
-		plain_test = function(sasl, username, password, realm)
+		plain = function(sasl, username, realm)
 			local prepped_username = nodeprep(username);
 			if not prepped_username then
 				module:log("debug", "NODEprep failed on username: %s", username);
-				return nil;
+				return "", nil;
 			end
-			return provider.test_password(prepped_username, password);
+			local password = get_password(prepped_username);
+			if not password then return "", nil; end
+			return password, true;
 		end
 	};
-	return new_sasl(host, profile);
+	return new_sasl(module.host, profile);
 end
 
 module:add_item("auth-provider", provider);
--- a/mod_data_access/mod_data_access.lua	Mon Oct 24 00:20:51 2011 +0000
+++ b/mod_data_access/mod_data_access.lua	Sat Oct 29 13:34:15 2011 +0200
@@ -1,19 +1,26 @@
 -- HTTP Access to datamanager
 -- By Kim Alvefur <zash@zash.se>
 
-local t_concat = table.concat;
 local jid_prep = require "util.jid".prep;
 local jid_split = require "util.jid".split;
 local um_test_pw = require "core.usermanager".test_password;
 local is_admin = require "core.usermanager".is_admin
 local dm_load = require "util.datamanager".load;
-local dm_store = require "util.datamanager".store;
 local dm_list_load = require "util.datamanager".list_load;
-local dm_list_append = require "util.datamanager".list_append;
 local b64_decode = require "util.encodings".base64.decode;
-local http = require "net.http";
-local urldecode  = http.urldecode;
-local urlencode  = http.urlencode;
+--local urldecode = require "net.http".urldecode;
+--[[local urlparams = --require "net.http".getQueryParams or whatever MattJ names it
+function(s)
+	if not s:match("=") then return urldecode(s); end
+	local r = {}
+	s:gsub("([^=&]*)=([^&]*)", function(k,v)
+		r[ urldecode(k) ] = urldecode(v);
+		return nil
+	end)
+	return r
+end;
+--]]
+
 local function http_response(code, message, extra_headers)
 	local response = {
 		status = code .. " " .. message;
@@ -26,29 +33,15 @@
 	lua = require "util.serialization".serialize,
 	json = require "util.json".encode
 };
-local decoders = {
-	lua = require "util.serialization".deserialize,
-	json = require "util.json".decode,
-};
-local content_type_map = {
-	["text/x-lua"] = "lua"; lua = "text/x-lua";
-	["application/json"] = "json"; json = "application/json";
-}
 --[[
 encoders.xml = function(data)
 	return "<?xml version='1.0' encoding='utf-8'?><todo:write-this-serializer/>";
 end --]]
 
-local allowed_methods = {
-	GET = true, "GET",
-	PUT = true, "PUT",
-	POST = true, "POST",
-}
-
 local function handle_request(method, body, request)
-	if not allowed_methods[method] then
-		return http_response(405, "Method Not Allowed", {["Allow"] = t_concat(allowed_methods, ", ")});
-	end
+	if request.method ~= "GET" then
+		return http_response(405, "Method Not Allowed", {["Allow"] = "GET"});
+	end -- TODO Maybe PUT?
 
 	if not request.headers["authorization"] then
 		return http_response(401, "Unauthorized",
@@ -85,59 +78,29 @@
 		return http_response(404, "Not Found");
 	end
 
-	local p_host, p_user, p_store, p_type = unpack(path);
-	
-	if not p_store or not p_store:match("^[%a_]+$") then
-		return http_response(404, "Not Found");
-	end
-
 	if user_host ~= path[1] or user_node ~= path[2] then
 		-- To only give admins acces to anything, move the inside of this block after authz
-		module:log("debug", "%s wants access to %s@%s[%s], is admin?", user, p_user, p_host, p_store)
-		if not is_admin(user, p_host) then
+		module:log("debug", "%s wants access to %s@%s[%s], is admin?", user, path[2], path[1], path[3])
+		if not is_admin(user, path[1]) then
 			return http_response(403, "Forbidden");
 		end
 	end
 
-	if method == "GET" then
-		local data = dm_load(p_user, p_host, p_store);
-
-		data = data or dm_load_list(p_user, p_host, p_store);
+	local data = dm_load(path[2], path[1], path[3]);
+	
+	data = data or dm_list_load(path[2], path[1], path[3]);
 
-		--TODO Use the Accept header
-		content_type = p_type or "json";
-		if data and encoders[content_type] then 
-			return {
-				status = "200 OK",
-				body = encoders[content_type](data) .. "\n",
-				headers = {["content-type"] = content_type_map[content_type].."; charset=utf-8"}
-			};
-		else
-			return http_response(404, "Not Found");
-		end
-	else -- POST or PUT
-		if not body then
-			return http_response(400, "Bad Request")
-		end
-		local content_type, content = request.headers["content-type"], body;
-		content_type = content_type and content_type_map[content_type]
-		module:log("debug", "%s: %s", content_type, tostring(content));
-		content = content_type and decoders[content_type] and decoders[content_type](content);
-		module:log("debug", "%s: %s", type(content), tostring(content));
-		if not content then
-			return http_response(400, "Bad Request")
-		end
-		local ok, err
-		if method == "PUT" then
-			ok, err = dm_store(p_user, p_host, p_store, content);
-		elseif method == "POST" then
-			ok, err = dm_list_append(p_user, p_host, p_store, content);
-		end
-		if ok then
-			return http_response(201, "Created", { Location = t_concat({"/data",p_host,p_user,p_store}, "/") });
-		else
-			return { status = "500 Internal Server Error", body = err }
-		end
+	if data and encoders[path[4] or "json"] then 
+		return {
+			status = "200 OK",
+			body = encoders[path[4] or "json"](data) .. "\n",
+			headers = {["content-type"] = "text/plain; charset=utf-8"}
+			--headers = {["content-type"] = encoders[data[4] or "json"].mime .. "; charset=utf-8"}
+			-- FIXME a little nicer that the above
+			-- Also, would be cooler to use the Accept header, but parsing it ...
+		};
+	else
+		return http_response(404, "Not Found");
 	end
 end
 
--- a/mod_ircd/mod_ircd_broke.lua	Mon Oct 24 00:20:51 2011 +0000
+++ b/mod_ircd/mod_ircd_broke.lua	Sat Oct 29 13:34:15 2011 +0200
@@ -1,5321 +1,3 @@
-package.preload['verse'] = (function (...)
-package.preload['util.encodings'] = (function (...)
-local function not_impl()
-	error("Function not implemented");
-end
-
-local mime = require "mime";
-
-module "encodings"
-
-stringprep = {};
-base64 = { encode = mime.b64, decode = not_impl }; --mime.unb64 is buggy with \0
-
-return _M;
- end)
-package.preload['util.hashes'] = (function (...)
-local sha1 = require "util.sha1";
-
-return { sha1 = sha1.sha1 };
- end)
-package.preload['util.logger'] = (function (...)
-local select, tostring = select, tostring;
-local io_write = function(...) return io.stderr:write(...) end;
-module "logger"
-
-local function format(format, ...)
-	local n, maxn = 0, #arg;
-	return (format:gsub("%%(.)", function (c) if c ~= "%" and n <= maxn then n = n + 1; return tostring(arg[n]); end end));
-end
-
-local function format(format, ...)
-	local n, maxn = 0, select('#', ...);
-	local arg = { ... };
-	return (format:gsub("%%(.)", function (c) if n <= maxn then n = n + 1; return tostring(arg[n]); end end));
-end
-
-function init(name)
-	return function (level, message, ...)
-		io_write(level, "\t", format(message, ...), "\n");
-	end
-end
-
-return _M;
- end)
-package.preload['util.sha1'] = (function (...)
--------------------------------------------------
----      *** SHA-1 algorithm for Lua ***      ---
--------------------------------------------------
---- Author:  Martin Huesser                   ---
---- Date:    2008-06-16                       ---
---- License: You may use this code in your    ---
----          projects as long as this header  ---
----          stays intact.                    ---
--------------------------------------------------
-
-local strlen  = string.len
-local strchar = string.char
-local strbyte = string.byte
-local strsub  = string.sub
-local floor   = math.floor
-local bit     = require "bit"
-local bnot    = bit.bnot
-local band    = bit.band
-local bor     = bit.bor
-local bxor    = bit.bxor
-local shl     = bit.lshift
-local shr     = bit.rshift
-local h0, h1, h2, h3, h4
-
--------------------------------------------------
-
-local function LeftRotate(val, nr)
-	return shl(val, nr) + shr(val, 32 - nr)
-end
-
--------------------------------------------------
-
-local function ToHex(num)
-	local i, d
-	local str = ""
-	for i = 1, 8 do
-		d = band(num, 15)
-		if (d < 10) then
-			str = strchar(d + 48) .. str
-		else
-			str = strchar(d + 87) .. str
-		end
-		num = floor(num / 16)
-	end
-	return str
-end
-
--------------------------------------------------
-
-local function PreProcess(str)
-	local bitlen, i
-	local str2 = ""
-	bitlen = strlen(str) * 8
-	str = str .. strchar(128)
-	i = 56 - band(strlen(str), 63)
-	if (i < 0) then
-		i = i + 64
-	end
-	for i = 1, i do
-		str = str .. strchar(0)
-	end
-	for i = 1, 8 do
-		str2 = strchar(band(bitlen, 255)) .. str2
-		bitlen = floor(bitlen / 256)
-	end
-	return str .. str2
-end
-
--------------------------------------------------
-
-local function MainLoop(str)
-	local a, b, c, d, e, f, k, t
-	local i, j
-	local w = {}
-	while (str ~= "") do
-		for i = 0, 15 do
-			w[i] = 0
-			for j = 1, 4 do
-				w[i] = w[i] * 256 + strbyte(str, i * 4 + j)
-			end
-		end
-		for i = 16, 79 do
-			w[i] = LeftRotate(bxor(bxor(w[i - 3], w[i - 8]), bxor(w[i - 14], w[i - 16])), 1)
-		end
-		a = h0
-		b = h1
-		c = h2
-		d = h3
-		e = h4
-		for i = 0, 79 do
-			if (i < 20) then
-				f = bor(band(b, c), band(bnot(b), d))
-				k = 1518500249
-			elseif (i < 40) then
-				f = bxor(bxor(b, c), d)
-				k = 1859775393
-			elseif (i < 60) then
-				f = bor(bor(band(b, c), band(b, d)), band(c, d))
-				k = 2400959708
-			else
-				f = bxor(bxor(b, c), d)
-				k = 3395469782
-			end
-			t = LeftRotate(a, 5) + f + e + k + w[i]	
-			e = d
-			d = c
-			c = LeftRotate(b, 30)
-			b = a
-			a = t
-		end
-		h0 = band(h0 + a, 4294967295)
-		h1 = band(h1 + b, 4294967295)
-		h2 = band(h2 + c, 4294967295)
-		h3 = band(h3 + d, 4294967295)
-		h4 = band(h4 + e, 4294967295)
-		str = strsub(str, 65)
-	end
-end
-
--------------------------------------------------
-
-local function sha1(str, hexres)
-	str = PreProcess(str)
-	h0  = 1732584193
-	h1  = 4023233417
-	h2  = 2562383102
-	h3  = 0271733878
-	h4  = 3285377520
-	MainLoop(str)
-	local hex = ToHex(h0)..ToHex(h1)..ToHex(h2)
-	            ..ToHex(h3)..ToHex(h4);
-	if hexres then
-		return  hex;
-	else
-		return (hex:gsub("..", function (byte)
-			return string.char(tonumber(byte, 16));
-		end));
-	end
-end
-
-_G.sha1 = {sha1 = sha1};
-return _G.sha1;
-
--------------------------------------------------
--------------------------------------------------
--------------------------------------------------
- end)
-package.preload['lib.adhoc'] = (function (...)
--- Copyright (C) 2009-2010 Florian Zeitz
---
--- This file is MIT/X11 licensed. Please see the
--- COPYING file in the source package for more information.
---
-
-local st, uuid = require "util.stanza", require "util.uuid";
-
-local xmlns_cmd = "http://jabber.org/protocol/commands";
-
-local states = {}
-
-local _M = {};
-
-function _cmdtag(desc, status, sessionid, action)
-	local cmd = st.stanza("command", { xmlns = xmlns_cmd, node = desc.node, status = status });
-	if sessionid then cmd.attr.sessionid = sessionid; end
-	if action then cmd.attr.action = action; end
-
-	return cmd;
-end
-
-function _M.new(name, node, handler, permission)
-	return { name = name, node = node, handler = handler, cmdtag = _cmdtag, permission = (permission or "user") };
-end
-
-function _M.handle_cmd(command, origin, stanza)
-	local sessionid = stanza.tags[1].attr.sessionid or uuid.generate();
-	local dataIn = {};
-	dataIn.to = stanza.attr.to;
-	dataIn.from = stanza.attr.from;
-	dataIn.action = stanza.tags[1].attr.action or "execute";
-	dataIn.form = stanza.tags[1]:child_with_ns("jabber:x:data");
-
-	local data, state = command:handler(dataIn, states[sessionid]);
-	states[sessionid] = state;
-	local stanza = st.reply(stanza);
-	if data.status == "completed" then
-		states[sessionid] = nil;
-		cmdtag = command:cmdtag("completed", sessionid);
-	elseif data.status == "canceled" then
-		states[sessionid] = nil;
-		cmdtag = command:cmdtag("canceled", sessionid);
-	elseif data.status == "error" then
-		states[sessionid] = nil;
-		stanza = st.error_reply(stanza, data.error.type, data.error.condition, data.error.message);
-		origin.send(stanza);
-		return true;
-	else
-		cmdtag = command:cmdtag("executing", sessionid);
-	end
-
-	for name, content in pairs(data) do
-		if name == "info" then
-			cmdtag:tag("note", {type="info"}):text(content):up();
-		elseif name == "warn" then
-			cmdtag:tag("note", {type="warn"}):text(content):up();
-		elseif name == "error" then
-			cmdtag:tag("note", {type="error"}):text(content.message):up();
-		elseif name =="actions" then
-			local actions = st.stanza("actions");
-			for _, action in ipairs(content) do
-				if (action == "prev") or (action == "next") or (action == "complete") then
-					actions:tag(action):up();
-				else
-					module:log("error", 'Command "'..command.name..
-						'" at node "'..command.node..'" provided an invalid action "'..action..'"');
-				end
-			end
-			cmdtag:add_child(actions);
-		elseif name == "form" then
-			cmdtag:add_child((content.layout or content):form(content.values));
-		elseif name == "result" then
-			cmdtag:add_child((content.layout or content):form(content.values, "result"));
-		elseif name == "other" then
-			cmdtag:add_child(content);
-		end
-	end
-	stanza:add_child(cmdtag);
-	origin.send(stanza);
-
-	return true;
-end
-
-return _M;
- end)
-package.preload['util.stanza'] = (function (...)
--- 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 t_insert      =  table.insert;
-local t_concat      =  table.concat;
-local t_remove      =  table.remove;
-local t_concat      =  table.concat;
-local s_format      = string.format;
-local s_match       =  string.match;
-local tostring      =      tostring;
-local setmetatable  =  setmetatable;
-local getmetatable  =  getmetatable;
-local pairs         =         pairs;
-local ipairs        =        ipairs;
-local type          =          type;
-local next          =          next;
-local print         =         print;
-local unpack        =        unpack;
-local s_gsub        =   string.gsub;
-local s_char        =   string.char;
-local s_find        =   string.find;
-local os            =            os;
-
-local do_pretty_printing = not os.getenv("WINDIR");
-local getstyle, getstring;
-if do_pretty_printing then
-	local ok, termcolours = pcall(require, "util.termcolours");
-	if ok then
-		getstyle, getstring = termcolours.getstyle, termcolours.getstring;
-	else
-		do_pretty_printing = nil;
-	end
-end
-
-local xmlns_stanzas = "urn:ietf:params:xml:ns:xmpp-stanzas";
-
-module "stanza"
-
-stanza_mt = { __type = "stanza" };
-stanza_mt.__index = stanza_mt;
-local stanza_mt = stanza_mt;
-
-function stanza(name, attr)
-	local stanza = { name = name, attr = attr or {}, tags = {} };
-	return setmetatable(stanza, stanza_mt);
-end
-local stanza = stanza;
-
-function stanza_mt:query(xmlns)
-	return self:tag("query", { xmlns = xmlns });
-end
-
-function stanza_mt:body(text, attr)
-	return self:tag("body", attr):text(text);
-end
-
-function stanza_mt:tag(name, attrs)
-	local s = stanza(name, attrs);
-	local last_add = self.last_add;
-	if not last_add then last_add = {}; self.last_add = last_add; end
-	(last_add[#last_add] or self):add_direct_child(s);
-	t_insert(last_add, s);
-	return self;
-end
-
-function stanza_mt:text(text)
-	local last_add = self.last_add;
-	(last_add and last_add[#last_add] or self):add_direct_child(text);
-	return self;
-end
-
-function stanza_mt:up()
-	local last_add = self.last_add;
-	if last_add then t_remove(last_add); end
-	return self;
-end
-
-function stanza_mt:reset()
-	self.last_add = nil;
-	return self;
-end
-
-function stanza_mt:add_direct_child(child)
-	if type(child) == "table" then
-		t_insert(self.tags, child);
-	end
-	t_insert(self, child);
-end
-
-function stanza_mt:add_child(child)
-	local last_add = self.last_add;
-	(last_add and last_add[#last_add] or self):add_direct_child(child);
-	return self;
-end
-
-function stanza_mt:get_child(name, xmlns)
-	for _, child in ipairs(self.tags) do
-		if (not name or child.name == name)
-			and ((not xmlns and self.attr.xmlns == child.attr.xmlns)
-				or child.attr.xmlns == xmlns) then
-			
-			return child;
-		end
-	end
-end
-
-function stanza_mt:get_child_text(name, xmlns)
-	local tag = self:get_child(name, xmlns);
-	if tag then
-		return tag:get_text();
-	end
-	return nil;
-end
-
-function stanza_mt:child_with_name(name)
-	for _, child in ipairs(self.tags) do
-		if child.name == name then return child; end
-	end
-end
-
-function stanza_mt:child_with_ns(ns)
-	for _, child in ipairs(self.tags) do
-		if child.attr.xmlns == ns then return child; end
-	end
-end
-
-function stanza_mt:children()
-	local i = 0;
-	return function (a)
-			i = i + 1
-			return a[i];
-		end, self, i;
-end
-
-function stanza_mt:childtags(name, xmlns)
-	xmlns = xmlns or self.attr.xmlns;
-	local tags = self.tags;
-	local start_i, max_i = 1, #tags;
-	return function ()
-		for i = start_i, max_i do
-			local v = tags[i];
-			if (not name or v.name == name)
-			and (not xmlns or xmlns == v.attr.xmlns) then
-				start_i = i+1;
-				return v;
-			end
-		end
-	end;
-end
-
-function stanza_mt:maptags(callback)
-	local tags, curr_tag = self.tags, 1;
-	local n_children, n_tags = #self, #tags;
-	
-	local i = 1;
-	while curr_tag <= n_tags do
-		if self[i] == tags[curr_tag] then
-			local ret = callback(self[i]);
-			if ret == nil then
-				t_remove(self, i);
-				t_remove(tags, curr_tag);
-				n_children = n_children - 1;
-				n_tags = n_tags - 1;
-			else
-				self[i] = ret;
-				tags[i] = ret;
-			end
-			i = i + 1;
-			curr_tag = curr_tag + 1;
-		end
-	end
-	return self;
-end
-
-local xml_escape
-do
-	local escape_table = { ["'"] = "&apos;", ["\""] = "&quot;", ["<"] = "&lt;", [">"] = "&gt;", ["&"] = "&amp;" };
-	function xml_escape(str) return (s_gsub(str, "['&<>\"]", escape_table)); end
-	_M.xml_escape = xml_escape;
-end
-
-local function _dostring(t, buf, self, xml_escape, parentns)
-	local nsid = 0;
-	local name = t.name
-	t_insert(buf, "<"..name);
-	for k, v in pairs(t.attr) do
-		if s_find(k, "\1", 1, true) then
-			local ns, attrk = s_match(k, "^([^\1]*)\1?(.*)$");
-			nsid = nsid + 1;
-			t_insert(buf, " xmlns:ns"..nsid.."='"..xml_escape(ns).."' ".."ns"..nsid..":"..attrk.."='"..xml_escape(v).."'");
-		elseif not(k == "xmlns" and v == parentns) then
-			t_insert(buf, " "..k.."='"..xml_escape(v).."'");
-		end
-	end
-	local len = #t;
-	if len == 0 then
-		t_insert(buf, "/>");
-	else
-		t_insert(buf, ">");
-		for n=1,len do
-			local child = t[n];
-			if child.name then
-				self(child, buf, self, xml_escape, t.attr.xmlns);
-			else
-				t_insert(buf, xml_escape(child));
-			end
-		end
-		t_insert(buf, "</"..name..">");
-	end
-end
-function stanza_mt.__tostring(t)
-	local buf = {};
-	_dostring(t, buf, _dostring, xml_escape, nil);
-	return t_concat(buf);
-end
-
-function stanza_mt.top_tag(t)
-	local attr_string = "";
-	if t.attr then
-		for k, v in pairs(t.attr) do if type(k) == "string" then attr_string = attr_string .. s_format(" %s='%s'", k, xml_escape(tostring(v))); end end
-	end
-	return s_format("<%s%s>", t.name, attr_string);
-end
-
-function stanza_mt.get_text(t)
-	if #t.tags == 0 then
-		return t_concat(t);
-	end
-end
-
-function stanza_mt.get_error(stanza)
-	local type, condition, text;
-	
-	local error_tag = stanza:get_child("error");
-	if not error_tag then
-		return nil, nil, nil;
-	end
-	type = error_tag.attr.type;
-	
-	for child in error_tag:childtags() do
-		if child.attr.xmlns == xmlns_stanzas then
-			if not text and child.name == "text" then
-				text = child:get_text();
-			elseif not condition then
-				condition = child.name;
-			end
-			if condition and text then
-				break;
-			end
-		end
-	end
-	return type, condition or "undefined-condition", text;
-end
-
-function stanza_mt.__add(s1, s2)
-	return s1:add_direct_child(s2);
-end
-
-
-do
-	local id = 0;
-	function new_id()
-		id = id + 1;
-		return "lx"..id;
-	end
-end
-
-function preserialize(stanza)
-	local s = { name = stanza.name, attr = stanza.attr };
-	for _, child in ipairs(stanza) do
-		if type(child) == "table" then
-			t_insert(s, preserialize(child));
-		else
-			t_insert(s, child);
-		end
-	end
-	return s;
-end
-
-function deserialize(stanza)
-	-- Set metatable
-	if stanza then
-		local attr = stanza.attr;
-		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(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[a] = v;
-		end
-		setmetatable(stanza, stanza_mt);
-		for _, child in ipairs(stanza) do
-			if type(child) == "table" then
-				deserialize(child);
-			end
-		end
-		if not stanza.tags then
-			-- Rebuild tags
-			local tags = {};
-			for _, child in ipairs(stanza) do
-				if type(child) == "table" then
-					t_insert(tags, child);
-				end
-			end
-			stanza.tags = tags;
-		end
-	end
-	
-	return stanza;
-end
-
-local function _clone(stanza)
-	local attr, tags = {}, {};
-	for k,v in pairs(stanza.attr) do attr[k] = v; end
-	local new = { name = stanza.name, attr = attr, tags = tags };
-	for i=1,#stanza do
-		local child = stanza[i];
-		if child.name then
-			child = _clone(child);
-			t_insert(tags, child);
-		end
-		t_insert(new, child);
-	end
-	return setmetatable(new, stanza_mt);
-end
-clone = _clone;
-
-function message(attr, body)
-	if not body then
-		return stanza("message", attr);
-	else
-		return stanza("message", attr):tag("body"):text(body):up();
-	end
-end
-function iq(attr)
-	if attr and not attr.id then attr.id = new_id(); end
-	return stanza("iq", attr or { id = new_id() });
-end
-
-function reply(orig)
-	return stanza(orig.name, orig.attr and { to = orig.attr.from, from = orig.attr.to, id = orig.attr.id, type = ((orig.name == "iq" and "result") or orig.attr.type) });
-end
-
-do
-	local xmpp_stanzas_attr = { xmlns = xmlns_stanzas };
-	function error_reply(orig, type, condition, message)
-		local t = reply(orig);
-		t.attr.type = "error";
-		t:tag("error", {type = type}) --COMPAT: Some day xmlns:stanzas goes here
-			:tag(condition, xmpp_stanzas_attr):up();
-		if (message) then t:tag("text", xmpp_stanzas_attr):text(message):up(); end
-		return t; -- stanza ready for adding app-specific errors
-	end
-end
-
-function presence(attr)
-	return stanza("presence", attr);
-end
-
-if do_pretty_printing then
-	local style_attrk = getstyle("yellow");
-	local style_attrv = getstyle("red");
-	local style_tagname = getstyle("red");
-	local style_punc = getstyle("magenta");
-	
-	local attr_format = " "..getstring(style_attrk, "%s")..getstring(style_punc, "=")..getstring(style_attrv, "'%s'");
-	local top_tag_format = getstring(style_punc, "<")..getstring(style_tagname, "%s").."%s"..getstring(style_punc, ">");
-	--local tag_format = getstring(style_punc, "<")..getstring(style_tagname, "%s").."%s"..getstring(style_punc, ">").."%s"..getstring(style_punc, "</")..getstring(style_tagname, "%s")..getstring(style_punc, ">");
-	local tag_format = top_tag_format.."%s"..getstring(style_punc, "</")..getstring(style_tagname, "%s")..getstring(style_punc, ">");
-	function stanza_mt.pretty_print(t)
-		local children_text = "";
-		for n, child in ipairs(t) do
-			if type(child) == "string" then
-				children_text = children_text .. xml_escape(child);
-			else
-				children_text = children_text .. child:pretty_print();
-			end
-		end
-
-		local attr_string = "";
-		if t.attr then
-			for k, v in pairs(t.attr) do if type(k) == "string" then attr_string = attr_string .. s_format(attr_format, k, tostring(v)); end end
-		end
-		return s_format(tag_format, t.name, attr_string, children_text, t.name);
-	end
-	
-	function stanza_mt.pretty_top_tag(t)
-		local attr_string = "";
-		if t.attr then
-			for k, v in pairs(t.attr) do if type(k) == "string" then attr_string = attr_string .. s_format(attr_format, k, tostring(v)); end end
-		end
-		return s_format(top_tag_format, t.name, attr_string);
-	end
-else
-	-- Sorry, fresh out of colours for you guys ;)
-	stanza_mt.pretty_print = stanza_mt.__tostring;
-	stanza_mt.pretty_top_tag = stanza_mt.top_tag;
-end
-
-return _M;
- end)
-package.preload['util.timer'] = (function (...)
--- 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 ns_addtimer = require "net.server".addtimer;
-local event = require "net.server".event;
-local event_base = require "net.server".event_base;
-
-local math_min = math.min
-local math_huge = math.huge
-local get_time = require "socket".gettime;
-local t_insert = table.insert;
-local t_remove = table.remove;
-local ipairs, pairs = ipairs, pairs;
-local type = type;
-
-local data = {};
-local new_data = {};
-
-module "timer"
-
-local _add_task;
-if not event then
-	function _add_task(delay, func)
-		local current_time = get_time();
-		delay = delay + current_time;
-		if delay >= current_time then
-			t_insert(new_data, {delay, func});
-		else
-			func();
-		end
-	end
-
-	ns_addtimer(function()
-		local current_time = get_time();
-		if #new_data > 0 then
-			for _, d in pairs(new_data) do
-				t_insert(data, d);
-			end
-			new_data = {};
-		end
-		
-		local next_time = math_huge;
-		for i, d in pairs(data) do
-			local t, func = d[1], d[2];
-			if t <= current_time then
-				data[i] = nil;
-				local r = func(current_time);
-				if type(r) == "number" then
-					_add_task(r, func);
-					next_time = math_min(next_time, r);
-				end
-			else
-				next_time = math_min(next_time, t - current_time);
-			end
-		end
-		return next_time;
-	end);
-else
-	local EVENT_LEAVE = (event.core and event.core.LEAVE) or -1;
-	function _add_task(delay, func)
-		local event_handle;
-		event_handle = event_base:addevent(nil, 0, function ()
-			local ret = func();
-			if ret then
-				return 0, ret;
-			elseif event_handle then
-				return EVENT_LEAVE;
-			end
-		end
-		, delay);
-	end
-end
-
-add_task = _add_task;
-
-return _M;
- end)
-package.preload['util.termcolours'] = (function (...)
--- 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 t_concat, t_insert = table.concat, table.insert;
-local char, format = string.char, string.format;
-local ipairs = ipairs;
-local io_write = io.write;
-
-local windows;
-if os.getenv("WINDIR") then
-	windows = require "util.windows";
-end
-local orig_color = windows and windows.get_consolecolor and windows.get_consolecolor();
-
-module "termcolours"
-
-local stylemap = {
-			reset = 0; bright = 1, dim = 2, underscore = 4, blink = 5, reverse = 7, hidden = 8;
-			black = 30; red = 31; green = 32; yellow = 33; blue = 34; magenta = 35; cyan = 36; white = 37;
-			["black background"] = 40; ["red background"] = 41; ["green background"] = 42; ["yellow background"] = 43; ["blue background"] = 44; ["magenta background"] = 45; ["cyan background"] = 46; ["white background"] = 47;
-			bold = 1, dark = 2, underline = 4, underlined = 4, normal = 0;
-		}
-
-local winstylemap = {
-	["0"] = orig_color, -- reset
-	["1"] = 7+8, -- bold
-	["1;33"] = 2+4+8, -- bold yellow
-	["1;31"] = 4+8 -- bold red
-}
-
-local fmt_string = char(0x1B).."[%sm%s"..char(0x1B).."[0m";
-function getstring(style, text)
-	if style then
-		return format(fmt_string, style, text);
-	else
-		return text;
-	end
-end
-
-function getstyle(...)
-	local styles, result = { ... }, {};
-	for i, style in ipairs(styles) do
-		style = stylemap[style];
-		if style then
-			t_insert(result, style);
-		end
-	end
-	return t_concat(result, ";");
-end
-
-local last = "0";
-function setstyle(style)
-	style = style or "0";
-	if style ~= last then
-		io_write("\27["..style.."m");
-		last = style;
-	end
-end
-
-if windows then
-	function setstyle(style)
-		style = style or "0";
-		if style ~= last then
-			windows.set_consolecolor(winstylemap[style] or orig_color);
-			last = style;
-		end
-	end
-	if not orig_color then
-		function setstyle(style) end
-	end
-end
-
-return _M;
- end)
-package.preload['util.uuid'] = (function (...)
--- 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 m_random = math.random;
-local tostring = tostring;
-local os_time = os.time;
-local os_clock = os.clock;
-local sha1 = require "util.hashes".sha1;
-
-module "uuid"
-
-local last_uniq_time = 0;
-local function uniq_time()
-	local new_uniq_time = os_time();
-	if last_uniq_time >= new_uniq_time then new_uniq_time = last_uniq_time + 1; end
-	last_uniq_time = new_uniq_time;
-	return new_uniq_time;
-end
-
-local function new_random(x)
-	return sha1(x..os_clock()..tostring({}), true);
-end
-
-local buffer = new_random(uniq_time());
-local function _seed(x)
-	buffer = new_random(buffer..x);
-end
-local function get_nibbles(n)
-	if #buffer < n then _seed(uniq_time()); end
-	local r = buffer:sub(0, n);
-	buffer = buffer:sub(n+1);
-	return r;
-end
-local function get_twobits()
-	return ("%x"):format(get_nibbles(1):byte() % 4 + 8);
-end
-
-function generate()
-	-- generate RFC 4122 complaint UUIDs (version 4 - random)
-	return get_nibbles(8).."-"..get_nibbles(4).."-4"..get_nibbles(3).."-"..(get_twobits())..get_nibbles(3).."-"..get_nibbles(12);
-end
-seed = _seed;
-
-return _M;
- end)
-package.preload['net.dns'] = (function (...)
--- Prosody IM
--- This file is included with Prosody IM. It has modifications,
--- which are hereby placed in the public domain.
-
-
--- todo: quick (default) header generation
--- todo: nxdomain, error handling
--- todo: cache results of encodeName
-
-
--- reference: http://tools.ietf.org/html/rfc1035
--- reference: http://tools.ietf.org/html/rfc1876 (LOC)
-
-
-local socket = require "socket";
-local timer = require "util.timer";
-
-local _, windows = pcall(require, "util.windows");
-local is_windows = (_ and windows) or os.getenv("WINDIR");
-
-local coroutine, io, math, string, table =
-      coroutine, io, math, string, table;
-
-local ipairs, next, pairs, print, setmetatable, tostring, assert, error, unpack, select, type=
-      ipairs, next, pairs, print, setmetatable, tostring, assert, error, unpack, select, type;
-
-local ztact = { -- public domain 20080404 lua@ztact.com
-	get = function(parent, ...)
-		local len = select('#', ...);
-		for i=1,len do
-			parent = parent[select(i, ...)];
-			if parent == nil then break; end
-		end
-		return parent;
-	end;
-	set = function(parent, ...)
-		local len = select('#', ...);
-		local key, value = select(len-1, ...);
-		local cutpoint, cutkey;
-
-		for i=1,len-2 do
-			local key = select (i, ...)
-			local child = parent[key]
-
-			if value == nil then
-				if child == nil then
-					return;
-				elseif next(child, next(child)) then
-					cutpoint = nil; cutkey = nil;
-				elseif cutpoint == nil then
-					cutpoint = parent; cutkey = key;
-				end
-			elseif child == nil then
-				child = {};
-				parent[key] = child;
-			end
-			parent = child
-		end
-
-		if value == nil and cutpoint then
-			cutpoint[cutkey] = nil;
-		else
-			parent[key] = value;
-			return value;
-		end
-	end;
-};
-local get, set = ztact.get, ztact.set;
-
-local default_timeout = 15;
-
--------------------------------------------------- module dns
-module('dns')
-local dns = _M;
-
-
--- dns type & class codes ------------------------------ dns type & class codes
-
-
-local append = table.insert
-
-
-local function highbyte(i)    -- - - - - - - - - - - - - - - - - - -  highbyte
-	return (i-(i%0x100))/0x100;
-end
-
-
-local function augment (t)    -- - - - - - - - - - - - - - - - - - - -  augment
-	local a = {};
-	for i,s in pairs(t) do
-		a[i] = s;
-		a[s] = s;
-		a[string.lower(s)] = s;
-	end
-	return a;
-end
-
-
-local function encode (t)    -- - - - - - - - - - - - - - - - - - - - -  encode
-	local code = {};
-	for i,s in pairs(t) do
-		local word = string.char(highbyte(i), i%0x100);
-		code[i] = word;
-		code[s] = word;
-		code[string.lower(s)] = word;
-	end
-	return code;
-end
-
-
-dns.types = {
-	'A', 'NS', 'MD', 'MF', 'CNAME', 'SOA', 'MB', 'MG', 'MR', 'NULL', 'WKS',
-	'PTR', 'HINFO', 'MINFO', 'MX', 'TXT',
-	[ 28] = 'AAAA', [ 29] = 'LOC',   [ 33] = 'SRV',
-	[252] = 'AXFR', [253] = 'MAILB', [254] = 'MAILA', [255] = '*' };
-
-
-dns.classes = { 'IN', 'CS', 'CH', 'HS', [255] = '*' };
-
-
-dns.type      = augment (dns.types);
-dns.class     = augment (dns.classes);
-dns.typecode  = encode  (dns.types);
-dns.classcode = encode  (dns.classes);
-
-
-
-local function standardize(qname, qtype, qclass)    -- - - - - - - standardize
-	if string.byte(qname, -1) ~= 0x2E then qname = qname..'.';  end
-	qname = string.lower(qname);
-	return qname, dns.type[qtype or 'A'], dns.class[qclass or 'IN'];
-end
-
-
-local function prune(rrs, time, soft)    -- - - - - - - - - - - - - - -  prune
-	time = time or socket.gettime();
-	for i,rr in pairs(rrs) do
-		if rr.tod then
-			-- rr.tod = rr.tod - 50    -- accelerated decripitude
-			rr.ttl = math.floor(rr.tod - time);
-			if rr.ttl <= 0 then
-				table.remove(rrs, i);
-				return prune(rrs, time, soft); -- Re-iterate
-			end
-		elseif soft == 'soft' then    -- What is this?  I forget!
-			assert(rr.ttl == 0);
-			rrs[i] = nil;
-		end
-	end
-end
-
-
--- metatables & co. ------------------------------------------ metatables & co.
-
-
-local resolver = {};
-resolver.__index = resolver;
-
-resolver.timeout = default_timeout;
-
-local function default_rr_tostring(rr)
-	local rr_val = rr.type and rr[rr.type:lower()];
-	if type(rr_val) ~= "string" then
-		return "<UNKNOWN RDATA TYPE>";
-	end
-	return rr_val;
-end
-
-local special_tostrings = {
-	LOC = resolver.LOC_tostring;
-	MX  = function (rr)
-		return string.format('%2i %s', rr.pref, rr.mx);
-	end;
-	SRV = function (rr)
-		local s = rr.srv;
-		return string.format('%5d %5d %5d %s', s.priority, s.weight, s.port, s.target);
-	end;
-};
-
-local rr_metatable = {};   -- - - - - - - - - - - - - - - - - - -  rr_metatable
-function rr_metatable.__tostring(rr)
-	local rr_string = (special_tostrings[rr.type] or default_rr_tostring)(rr);
-	return string.format('%2s %-5s %6i %-28s %s', rr.class, rr.type, rr.ttl, rr.name, rr_string);
-end
-
-
-local rrs_metatable = {};    -- - - - - - - - - - - - - - - - - -  rrs_metatable
-function rrs_metatable.__tostring(rrs)
-	local t = {};
-	for i,rr in pairs(rrs) do
-		append(t, tostring(rr)..'\n');
-	end
-	return table.concat(t);
-end
-
-
-local cache_metatable = {};    -- - - - - - - - - - - - - - - -  cache_metatable
-function cache_metatable.__tostring(cache)
-	local time = socket.gettime();
-	local t = {};
-	for class,types in pairs(cache) do
-		for type,names in pairs(types) do
-			for name,rrs in pairs(names) do
-				prune(rrs, time);
-				append(t, tostring(rrs));
-			end
-		end
-	end
-	return table.concat(t);
-end
-
-
-function resolver:new()    -- - - - - - - - - - - - - - - - - - - - - resolver
-	local r = { active = {}, cache = {}, unsorted = {} };
-	setmetatable(r, resolver);
-	setmetatable(r.cache, cache_metatable);
-	setmetatable(r.unsorted, { __mode = 'kv' });
-	return r;
-end
-
-
--- packet layer -------------------------------------------------- packet layer
-
-
-function dns.random(...)    -- - - - - - - - - - - - - - - - - - -  dns.random
-	math.randomseed(math.floor(10000*socket.gettime()));
-	dns.random = math.random;
-	return dns.random(...);
-end
-
-
-local function encodeHeader(o)    -- - - - - - - - - - - - - - -  encodeHeader
-	o = o or {};
-	o.id = o.id or dns.random(0, 0xffff); -- 16b	(random) id
-
-	o.rd = o.rd or 1;		--  1b  1 recursion desired
-	o.tc = o.tc or 0;		--  1b	1 truncated response
-	o.aa = o.aa or 0;		--  1b	1 authoritative response
-	o.opcode = o.opcode or 0;	--  4b	0 query
-				--  1 inverse query
-				--	2 server status request
-				--	3-15 reserved
-	o.qr = o.qr or 0;		--  1b	0 query, 1 response
-
-	o.rcode = o.rcode or 0;	--  4b  0 no error
-				--	1 format error
-				--	2 server failure
-				--	3 name error
-				--	4 not implemented
-				--	5 refused
-				--	6-15 reserved
-	o.z = o.z  or 0;		--  3b  0 resvered
-	o.ra = o.ra or 0;		--  1b  1 recursion available
-
-	o.qdcount = o.qdcount or 1;	-- 16b	number of question RRs
-	o.ancount = o.ancount or 0;	-- 16b	number of answers RRs
-	o.nscount = o.nscount or 0;	-- 16b	number of nameservers RRs
-	o.arcount = o.arcount or 0;	-- 16b  number of additional RRs
-
-	-- string.char() rounds, so prevent roundup with -0.4999
-	local header = string.char(
-		highbyte(o.id), o.id %0x100,
-		o.rd + 2*o.tc + 4*o.aa + 8*o.opcode + 128*o.qr,
-		o.rcode + 16*o.z + 128*o.ra,
-		highbyte(o.qdcount),  o.qdcount %0x100,
-		highbyte(o.ancount),  o.ancount %0x100,
-		highbyte(o.nscount),  o.nscount %0x100,
-		highbyte(o.arcount),  o.arcount %0x100
-	);
-
-	return header, o.id;
-end
-
-
-local function encodeName(name)    -- - - - - - - - - - - - - - - - encodeName
-	local t = {};
-	for part in string.gmatch(name, '[^.]+') do
-		append(t, string.char(string.len(part)));
-		append(t, part);
-	end
-	append(t, string.char(0));
-	return table.concat(t);
-end
-
-
-local function encodeQuestion(qname, qtype, qclass)    -- - - - encodeQuestion
-	qname  = encodeName(qname);
-	qtype  = dns.typecode[qtype or 'a'];
-	qclass = dns.classcode[qclass or 'in'];
-	return qname..qtype..qclass;
-end
-
-
-function resolver:byte(len)    -- - - - - - - - - - - - - - - - - - - - - byte
-	len = len or 1;
-	local offset = self.offset;
-	local last = offset + len - 1;
-	if last > #self.packet then
-		error(string.format('out of bounds: %i>%i', last, #self.packet));
-	end
-	self.offset = offset + len;
-	return string.byte(self.packet, offset, last);
-end
-
-
-function resolver:word()    -- - - - - - - - - - - - - - - - - - - - - -  word
-	local b1, b2 = self:byte(2);
-	return 0x100*b1 + b2;
-end
-
-
-function resolver:dword ()    -- - - - - - - - - - - - - - - - - - - - -  dword
-	local b1, b2, b3, b4 = self:byte(4);
-	--print('dword', b1, b2, b3, b4);
-	return 0x1000000*b1 + 0x10000*b2 + 0x100*b3 + b4;
-end
-
-
-function resolver:sub(len)    -- - - - - - - - - - - - - - - - - - - - - - sub
-	len = len or 1;
-	local s = string.sub(self.packet, self.offset, self.offset + len - 1);
-	self.offset = self.offset + len;
-	return s;
-end
-
-
-function resolver:header(force)    -- - - - - - - - - - - - - - - - - - header
-	local id = self:word();
-	--print(string.format(':header  id  %x', id));
-	if not self.active[id] and not force then return nil; end
-
-	local h = { id = id };
-
-	local b1, b2 = self:byte(2);
-
-	h.rd      = b1 %2;
-	h.tc      = b1 /2%2;
-	h.aa      = b1 /4%2;
-	h.opcode  = b1 /8%16;
-	h.qr      = b1 /128;
-
-	h.rcode   = b2 %16;
-	h.z       = b2 /16%8;
-	h.ra      = b2 /128;
-
-	h.qdcount = self:word();
-	h.ancount = self:word();
-	h.nscount = self:word();
-	h.arcount = self:word();
-
-	for k,v in pairs(h) do h[k] = v-v%1; end
-
-	return h;
-end
-
-
-function resolver:name()    -- - - - - - - - - - - - - - - - - - - - - -  name
-	local remember, pointers = nil, 0;
-	local len = self:byte();
-	local n = {};
-	while len > 0 do
-		if len >= 0xc0 then    -- name is "compressed"
-			pointers = pointers + 1;
-			if pointers >= 20 then error('dns error: 20 pointers'); end;
-			local offset = ((len-0xc0)*0x100) + self:byte();
-			remember = remember or self.offset;
-			self.offset = offset + 1;    -- +1 for lua
-		else    -- name is not compressed
-			append(n, self:sub(len)..'.');
-		end
-		len = self:byte();
-	end
-	self.offset = remember or self.offset;
-	return table.concat(n);
-end
-
-
-function resolver:question()    -- - - - - - - - - - - - - - - - - -  question
-	local q = {};
-	q.name  = self:name();
-	q.type  = dns.type[self:word()];
-	q.class = dns.class[self:word()];
-	return q;
-end
-
-
-function resolver:A(rr)    -- - - - - - - - - - - - - - - - - - - - - - - -  A
-	local b1, b2, b3, b4 = self:byte(4);
-	rr.a = string.format('%i.%i.%i.%i', b1, b2, b3, b4);
-end
-
-function resolver:AAAA(rr)
-	local addr = {};
-	for i = 1, rr.rdlength, 2 do
-		local b1, b2 = self:byte(2);
-		table.insert(addr, ("%02x%02x"):format(b1, b2));
-	end
-	rr.aaaa = table.concat(addr, ":");
-end
-
-function resolver:CNAME(rr)    -- - - - - - - - - - - - - - - - - - - -  CNAME
-	rr.cname = self:name();
-end
-
-
-function resolver:MX(rr)    -- - - - - - - - - - - - - - - - - - - - - - -  MX
-	rr.pref = self:word();
-	rr.mx   = self:name();
-end
-
-
-function resolver:LOC_nibble_power()    -- - - - - - - - - -  LOC_nibble_power
-	local b = self:byte();
-	--print('nibbles', ((b-(b%0x10))/0x10), (b%0x10));
-	return ((b-(b%0x10))/0x10) * (10^(b%0x10));
-end
-
-
-function resolver:LOC(rr)    -- - - - - - - - - - - - - - - - - - - - - -  LOC
-	rr.version = self:byte();
-	if rr.version == 0 then
-		rr.loc           = rr.loc or {};
-		rr.loc.size      = self:LOC_nibble_power();
-		rr.loc.horiz_pre = self:LOC_nibble_power();
-		rr.loc.vert_pre  = self:LOC_nibble_power();
-		rr.loc.latitude  = self:dword();
-		rr.loc.longitude = self:dword();
-		rr.loc.altitude  = self:dword();
-	end
-end
-
-
-local function LOC_tostring_degrees(f, pos, neg)    -- - - - - - - - - - - - -
-	f = f - 0x80000000;
-	if f < 0 then pos = neg; f = -f; end
-	local deg, min, msec;
-	msec = f%60000;
-	f    = (f-msec)/60000;
-	min  = f%60;
-	deg = (f-min)/60;
-	return string.format('%3d %2d %2.3f %s', deg, min, msec/1000, pos);
-end
-
-
-function resolver.LOC_tostring(rr)    -- - - - - - - - - - - - -  LOC_tostring
-	local t = {};
-
-	--[[
-	for k,name in pairs { 'size', 'horiz_pre', 'vert_pre', 'latitude', 'longitude', 'altitude' } do
-		append(t, string.format('%4s%-10s: %12.0f\n', '', name, rr.loc[name]));
-	end
-	--]]
-
-	append(t, string.format(
-		'%s    %s    %.2fm %.2fm %.2fm %.2fm',
-		LOC_tostring_degrees (rr.loc.latitude, 'N', 'S'),
-		LOC_tostring_degrees (rr.loc.longitude, 'E', 'W'),
-		(rr.loc.altitude - 10000000) / 100,
-		rr.loc.size / 100,
-		rr.loc.horiz_pre / 100,
-		rr.loc.vert_pre / 100
-	));
-
-	return table.concat(t);
-end
-
-
-function resolver:NS(rr)    -- - - - - - - - - - - - - - - - - - - - - - -  NS
-	rr.ns = self:name();
-end
-
-
-function resolver:SOA(rr)    -- - - - - - - - - - - - - - - - - - - - - -  SOA
-end
-
-
-function resolver:SRV(rr)    -- - - - - - - - - - - - - - - - - - - - - -  SRV
-	  rr.srv = {};
-	  rr.srv.priority = self:word();
-	  rr.srv.weight   = self:word();
-	  rr.srv.port     = self:word();
-	  rr.srv.target   = self:name();
-end
-
-function resolver:PTR(rr)
-	rr.ptr = self:name();
-end
-
-function resolver:TXT(rr)    -- - - - - - - - - - - - - - - - - - - - - -  TXT
-	rr.txt = self:sub (self:byte());
-end
-
-
-function resolver:rr()    -- - - - - - - - - - - - - - - - - - - - - - - -  rr
-	local rr = {};
-	setmetatable(rr, rr_metatable);
-	rr.name     = self:name(self);
-	rr.type     = dns.type[self:word()] or rr.type;
-	rr.class    = dns.class[self:word()] or rr.class;
-	rr.ttl      = 0x10000*self:word() + self:word();
-	rr.rdlength = self:word();
-
-	if rr.ttl <= 0 then
-		rr.tod = self.time + 30;
-	else
-		rr.tod = self.time + rr.ttl;
-	end
-
-	local remember = self.offset;
-	local rr_parser = self[dns.type[rr.type]];
-	if rr_parser then rr_parser(self, rr); end
-	self.offset = remember;
-	rr.rdata = self:sub(rr.rdlength);
-	return rr;
-end
-
-
-function resolver:rrs (count)    -- - - - - - - - - - - - - - - - - - - - - rrs
-	local rrs = {};
-	for i = 1,count do append(rrs, self:rr()); end
-	return rrs;
-end
-
-
-function resolver:decode(packet, force)    -- - - - - - - - - - - - - - decode
-	self.packet, self.offset = packet, 1;
-	local header = self:header(force);
-	if not header then return nil; end
-	local response = { header = header };
-
-	response.question = {};
-	local offset = self.offset;
-	for i = 1,response.header.qdcount do
-		append(response.question, self:question());
-	end
-	response.question.raw = string.sub(self.packet, offset, self.offset - 1);
-
-	if not force then
-		if not self.active[response.header.id] or not self.active[response.header.id][response.question.raw] then
-			return nil;
-		end
-	end
-
-	response.answer     = self:rrs(response.header.ancount);
-	response.authority  = self:rrs(response.header.nscount);
-	response.additional = self:rrs(response.header.arcount);
-
-	return response;
-end
-
-
--- socket layer -------------------------------------------------- socket layer
-
-
-resolver.delays = { 1, 3 };
-
-
-function resolver:addnameserver(address)    -- - - - - - - - - - addnameserver
-	self.server = self.server or {};
-	append(self.server, address);
-end
-
-
-function resolver:setnameserver(address)    -- - - - - - - - - - setnameserver
-	self.server = {};
-	self:addnameserver(address);
-end
-
-
-function resolver:adddefaultnameservers()    -- - - - -  adddefaultnameservers
-	if is_windows then
-		if windows and windows.get_nameservers then
-			for _, server in ipairs(windows.get_nameservers()) do
-				self:addnameserver(server);
-			end
-		end
-		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");
-		end
-	else -- posix
-		local resolv_conf = io.open("/etc/resolv.conf");
-		if resolv_conf then
-			for line in resolv_conf:lines() do
-				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
-			-- TODO log warning about no nameservers, adding localhost as the default nameserver
-			self:addnameserver("127.0.0.1");
-		end
-	end
-end
-
-
-function resolver:getsocket(servernum)    -- - - - - - - - - - - - - getsocket
-	self.socket = self.socket or {};
-	self.socketset = self.socketset or {};
-
-	local sock = self.socket[servernum];
-	if sock then return sock; end
-
-	local err;
-	sock, err = socket.udp();
-	if not sock then
-		return nil, err;
-	end
-	if self.socket_wrapper then sock = self.socket_wrapper(sock, self); end
-	sock:settimeout(0);
-	-- todo: attempt to use a random port, fallback to 0
-	sock:setsockname('*', 0);
-	sock:setpeername(self.server[servernum], 53);
-	self.socket[servernum] = sock;
-	self.socketset[sock] = servernum;
-	return sock;
-end
-
-function resolver:voidsocket(sock)
-	if self.socket[sock] then
-		self.socketset[self.socket[sock]] = nil;
-		self.socket[sock] = nil;
-	elseif self.socketset[sock] then
-		self.socket[self.socketset[sock]] = nil;
-		self.socketset[sock] = nil;
-	end
-end
-
-function resolver:socket_wrapper_set(func)  -- - - - - - - socket_wrapper_set
-	self.socket_wrapper = func;
-end
-
-
-function resolver:closeall ()    -- - - - - - - - - - - - - - - - - -  closeall
-	for i,sock in ipairs(self.socket) do
-		self.socket[i] = nil;
-		self.socketset[sock] = nil;
-		sock:close();
-	end
-end
-
-
-function resolver:remember(rr, type)    -- - - - - - - - - - - - - -  remember
-	--print ('remember', type, rr.class, rr.type, rr.name)
-	local qname, qtype, qclass = standardize(rr.name, rr.type, rr.class);
-
-	if type ~= '*' then
-		type = qtype;
-		local all = get(self.cache, qclass, '*', qname);
-		--print('remember all', all);
-		if all then append(all, rr); end
-	end
-
-	self.cache = self.cache or setmetatable({}, cache_metatable);
-	local rrs = get(self.cache, qclass, type, qname) or
-		set(self.cache, qclass, type, qname, setmetatable({}, rrs_metatable));
-	append(rrs, rr);
-
-	if type == 'MX' then self.unsorted[rrs] = true; end
-end
-
-
-local function comp_mx(a, b)    -- - - - - - - - - - - - - - - - - - - comp_mx
-	return (a.pref == b.pref) and (a.mx < b.mx) or (a.pref < b.pref);
-end
-
-
-function resolver:peek (qname, qtype, qclass)    -- - - - - - - - - - - -  peek
-	qname, qtype, qclass = standardize(qname, qtype, qclass);
-	local rrs = get(self.cache, qclass, qtype, qname);
-	if not rrs then return nil; end
-	if prune(rrs, socket.gettime()) and qtype == '*' or not next(rrs) then
-		set(self.cache, qclass, qtype, qname, nil);
-		return nil;
-	end
-	if self.unsorted[rrs] then table.sort (rrs, comp_mx); end
-	return rrs;
-end
-
-
-function resolver:purge(soft)    -- - - - - - - - - - - - - - - - - - -  purge
-	if soft == 'soft' then
-		self.time = socket.gettime();
-		for class,types in pairs(self.cache or {}) do
-			for type,names in pairs(types) do
-				for name,rrs in pairs(names) do
-					prune(rrs, self.time, 'soft')
-				end
-			end
-		end
-	else self.cache = {}; end
-end
-
-
-function resolver:query(qname, qtype, qclass)    -- - - - - - - - - - -- query
-	qname, qtype, qclass = standardize(qname, qtype, qclass)
-
-	if not self.server then self:adddefaultnameservers(); end
-
-	local question = encodeQuestion(qname, qtype, qclass);
-	local peek = self:peek (qname, qtype, qclass);
-	if peek then return peek; end
-
-	local header, id = encodeHeader();
-	--print ('query  id', id, qclass, qtype, qname)
-	local o = {
-		packet = header..question,
-		server = self.best_server,
-		delay  = 1,
-		retry  = socket.gettime() + self.delays[1]
-	};
-
-	-- remember the query
-	self.active[id] = self.active[id] or {};
-	self.active[id][question] = o;
-
-	-- remember which coroutine wants the answer
-	local co = coroutine.running();
-	if co then
-		set(self.wanted, qclass, qtype, qname, co, true);
-		--set(self.yielded, co, qclass, qtype, qname, true);
-	end
-
-	local conn, err = self:getsocket(o.server)
-	if not conn then
-		return nil, err;
-	end
-	conn:send (o.packet)
-	
-	if timer and self.timeout then
-		local num_servers = #self.server;
-		local i = 1;
-		timer.add_task(self.timeout, function ()
-			if get(self.wanted, qclass, qtype, qname, co) then
-				if i < num_servers then
-					i = i + 1;
-					self:servfail(conn);
-					o.server = self.best_server;
-					conn, err = self:getsocket(o.server);
-					if conn then
-						conn:send(o.packet);
-						return self.timeout;
-					end
-				end
-				-- Tried everything, failed
-				self:cancel(qclass, qtype, qname, co, true);
-			end
-		end)
-	end
-	return true;
-end
-
-function resolver:servfail(sock)
-	-- Resend all queries for this server
-
-	local num = self.socketset[sock]
-
-	-- Socket is dead now
-	self:voidsocket(sock);
-
-	-- Find all requests to the down server, and retry on the next server
-	self.time = socket.gettime();
-	for id,queries in pairs(self.active) do
-		for question,o in pairs(queries) do
-			if o.server == num then -- This request was to the broken server
-				o.server = o.server + 1 -- Use next server
-				if o.server > #self.server then
-					o.server = 1;
-				end
-
-				o.retries = (o.retries or 0) + 1;
-				if o.retries >= #self.server then
-					--print('timeout');
-					queries[question] = nil;
-				else
-					local _a = self:getsocket(o.server);
-					if _a then _a:send(o.packet); end
-				end
-			end
-		end
-	end
-
-	if num == self.best_server then
-		self.best_server = self.best_server + 1;
-		if self.best_server > #self.server then
-			-- Exhausted all servers, try first again
-			self.best_server = 1;
-		end
-	end
-end
-
-function resolver:settimeout(seconds)
-	self.timeout = seconds;
-end
-
-function resolver:receive(rset)    -- - - - - - - - - - - - - - - - -  receive
-	--print('receive');  print(self.socket);
-	self.time = socket.gettime();
-	rset = rset or self.socket;
-
-	local response;
-	for i,sock in pairs(rset) do
-
-		if self.socketset[sock] then
-			local packet = sock:receive();
-			if packet then
-				response = self:decode(packet);
-				if response and self.active[response.header.id]
-					and self.active[response.header.id][response.question.raw] then
-					--print('received response');
-					--self.print(response);
-
-					for j,rr in pairs(response.answer) do
-						if rr.name:sub(-#response.question[1].name, -1) == response.question[1].name then
-							self:remember(rr, response.question[1].type)
-						end
-					end
-
-					-- retire the query
-					local queries = self.active[response.header.id];
-					queries[response.question.raw] = nil;
-					
-					if not next(queries) then self.active[response.header.id] = nil; end
-					if not next(self.active) then self:closeall(); end
-
-					-- was the query on the wanted list?
-					local q = response.question[1];
-					local cos = get(self.wanted, q.class, q.type, q.name);
-					if cos then
-						for co in pairs(cos) do
-							set(self.yielded, co, q.class, q.type, q.name, nil);
-							if coroutine.status(co) == "suspended" then coroutine.resume(co); end
-						end
-						set(self.wanted, q.class, q.type, q.name, nil);
-					end
-				end
-			end
-		end
-	end
-
-	return response;
-end
-
-
-function resolver:feed(sock, packet, force)
-	--print('receive'); print(self.socket);
-	self.time = socket.gettime();
-
-	local response = self:decode(packet, force);
-	if response and self.active[response.header.id]
-		and self.active[response.header.id][response.question.raw] then
-		--print('received response');
-		--self.print(response);
-
-		for j,rr in pairs(response.answer) do
-			self:remember(rr, response.question[1].type);
-		end
-
-		-- retire the query
-		local queries = self.active[response.header.id];
-		queries[response.question.raw] = nil;
-		if not next(queries) then self.active[response.header.id] = nil; end
-		if not next(self.active) then self:closeall(); end
-
-		-- was the query on the wanted list?
-		local q = response.question[1];
-		if q then
-			local cos = get(self.wanted, q.class, q.type, q.name);
-			if cos then
-				for co in pairs(cos) do
-					set(self.yielded, co, q.class, q.type, q.name, nil);
-					if coroutine.status(co) == "suspended" then coroutine.resume(co); end
-				end
-				set(self.wanted, q.class, q.type, q.name, nil);
-			end
-		end
-	end
-
-	return response;
-end
-
-function resolver:cancel(qclass, qtype, qname, co, call_handler)
-	local cos = get(self.wanted, qclass, qtype, qname);
-	if cos then
-		if call_handler then
-			coroutine.resume(co);
-		end
-		cos[co] = nil;
-	end
-end
-
-function resolver:pulse()    -- - - - - - - - - - - - - - - - - - - - -  pulse
-	--print(':pulse');
-	while self:receive() do end
-	if not next(self.active) then return nil; end
-
-	self.time = socket.gettime();
-	for id,queries in pairs(self.active) do
-		for question,o in pairs(queries) do
-			if self.time >= o.retry then
-
-				o.server = o.server + 1;
-				if o.server > #self.server then
-					o.server = 1;
-					o.delay = o.delay + 1;
-				end
-
-				if o.delay > #self.delays then
-					--print('timeout');
-					queries[question] = nil;
-					if not next(queries) then self.active[id] = nil; end
-					if not next(self.active) then return nil; end
-				else
-					--print('retry', o.server, o.delay);
-					local _a = self.socket[o.server];
-					if _a then _a:send(o.packet); end
-					o.retry = self.time + self.delays[o.delay];
-				end
-			end
-		end
-	end
-
-	if next(self.active) then return true; end
-	return nil;
-end
-
-
-function resolver:lookup(qname, qtype, qclass)    -- - - - - - - - - -  lookup
-	self:query (qname, qtype, qclass)
-	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
-
-function resolver:lookupex(handler, qname, qtype, qclass)    -- - - - - - - - - -  lookup
-	return self:peek(qname, qtype, qclass) or self:query(qname, qtype, qclass);
-end
-
-function resolver:tohostname(ip)
-	return dns.lookup(ip:gsub("(%d+)%.(%d+)%.(%d+)%.(%d+)", "%4.%3.%2.%1.in-addr.arpa."), "PTR");
-end
-
---print ---------------------------------------------------------------- print
-
-
-local hints = {    -- - - - - - - - - - - - - - - - - - - - - - - - - - - hints
-	qr = { [0]='query', 'response' },
-	opcode = { [0]='query', 'inverse query', 'server status request' },
-	aa = { [0]='non-authoritative', 'authoritative' },
-	tc = { [0]='complete', 'truncated' },
-	rd = { [0]='recursion not desired', 'recursion desired' },
-	ra = { [0]='recursion not available', 'recursion available' },
-	z  = { [0]='(reserved)' },
-	rcode = { [0]='no error', 'format error', 'server failure', 'name error', 'not implemented' },
-
-	type = dns.type,
-	class = dns.class
-};
-
-
-local function hint(p, s)    -- - - - - - - - - - - - - - - - - - - - - - hint
-	return (hints[s] and hints[s][p[s]]) or '';
-end
-
-
-function resolver.print(response)    -- - - - - - - - - - - - - resolver.print
-	for s,s in pairs { 'id', 'qr', 'opcode', 'aa', 'tc', 'rd', 'ra', 'z',
-						'rcode', 'qdcount', 'ancount', 'nscount', 'arcount' } do
-		print( string.format('%-30s', 'header.'..s), response.header[s], hint(response.header, s) );
-	end
-
-	for i,question in ipairs(response.question) do
-		print(string.format ('question[%i].name         ', i), question.name);
-		print(string.format ('question[%i].type         ', i), question.type);
-		print(string.format ('question[%i].class        ', i), question.class);
-	end
-
-	local common = { name=1, type=1, class=1, ttl=1, rdlength=1, rdata=1 };
-	local tmp;
-	for s,s in pairs({'answer', 'authority', 'additional'}) do
-		for i,rr in pairs(response[s]) do
-			for j,t in pairs({ 'name', 'type', 'class', 'ttl', 'rdlength' }) do
-				tmp = string.format('%s[%i].%s', s, i, t);
-				print(string.format('%-30s', tmp), rr[t], hint(rr, t));
-			end
-			for j,t in pairs(rr) do
-				if not common[j] then
-					tmp = string.format('%s[%i].%s', s, i, j);
-					print(string.format('%-30s  %s', tostring(tmp), tostring(t)));
-				end
-			end
-		end
-	end
-end
-
-
--- module api ------------------------------------------------------ module api
-
-
-function dns.resolver ()    -- - - - - - - - - - - - - - - - - - - - - resolver
-	-- this function seems to be redundant with resolver.new ()
-
-	local r = { active = {}, cache = {}, unsorted = {}, wanted = {}, yielded = {}, best_server = 1 };
-	setmetatable (r, resolver);
-	setmetatable (r.cache, cache_metatable);
-	setmetatable (r.unsorted, { __mode = 'kv' });
-	return r;
-end
-
-local _resolver = dns.resolver();
-dns._resolver = _resolver;
-
-function dns.lookup(...)    -- - - - - - - - - - - - - - - - - - - - -  lookup
-	return _resolver:lookup(...);
-end
-
-function dns.tohostname(...)
-	return _resolver:tohostname(...);
-end
-
-function dns.purge(...)    -- - - - - - - - - - - - - - - - - - - - - -  purge
-	return _resolver:purge(...);
-end
-
-function dns.peek(...)    -- - - - - - - - - - - - - - - - - - - - - - -  peek
-	return _resolver:peek(...);
-end
-
-function dns.query(...)    -- - - - - - - - - - - - - - - - - - - - - -  query
-	return _resolver:query(...);
-end
-
-function dns.feed(...)    -- - - - - - - - - - - - - - - - - - - - - - -  feed
-	return _resolver:feed(...);
-end
-
-function dns.cancel(...)  -- - - - - - - - - - - - - - - - - - - - - -  cancel
-	return _resolver:cancel(...);
-end
-
-function dns.settimeout(...)
-	return _resolver:settimeout(...);
-end
-
-function dns.socket_wrapper_set(...)    -- - - - - - - - -  socket_wrapper_set
-	return _resolver:socket_wrapper_set(...);
-end
-
-return dns;
- end)
-package.preload['net.adns'] = (function (...)
--- 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 server = require "net.server";
-local dns = require "net.dns";
-
-local log = require "util.logger".init("adns");
-
-local t_insert, t_remove = table.insert, table.remove;
-local coroutine, tostring, pcall = coroutine, tostring, pcall;
-
-local function dummy_send(sock, data, i, j) return (j-i)+1; end
-
-module "adns"
-
-function lookup(handler, qname, qtype, qclass)
-	return coroutine.wrap(function (peek)
-				if peek then
-					log("debug", "Records for %s already cached, using those...", qname);
-					handler(peek);
-					return;
-				end
-				log("debug", "Records for %s not in cache, sending query (%s)...", qname, tostring(coroutine.running()));
-				local ok, err = dns.query(qname, qtype, qclass);
-				if ok then
-					coroutine.yield({ qclass or "IN", qtype or "A", qname, coroutine.running()}); -- Wait for reply
-					log("debug", "Reply for %s (%s)", qname, tostring(coroutine.running()));
-				end
-				if ok then
-					ok, err = pcall(handler, dns.peek(qname, qtype, qclass));
-				else
-					log("error", "Error sending DNS query: %s", err);
-					ok, err = pcall(handler, nil, err);
-				end
-				if not ok then
-					log("error", "Error in DNS response handler: %s", tostring(err));
-				end
-			end)(dns.peek(qname, qtype, qclass));
-end
-
-function cancel(handle, call_handler, reason)
-	log("warn", "Cancelling DNS lookup for %s", tostring(handle[3]));
-	dns.cancel(handle[1], handle[2], handle[3], handle[4], call_handler);
-end
-
-function new_async_socket(sock, resolver)
-	local peername = "<unknown>";
-	local listener = {};
-	local handler = {};
-	function listener.onincoming(conn, data)
-		if data then
-			dns.feed(handler, data);
-		end
-	end
-	function listener.ondisconnect(conn, err)
-		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
-	end
-	handler = server.wrapclient(sock, "dns", 53, listener);
-	if not handler then
-		log("warn", "handler is nil");
-	end
-	
-	handler.settimeout = function () end
-	handler.setsockname = function (_, ...) return sock:setsockname(...); end
-	handler.setpeername = function (_, ...) peername = (...); local ret = sock:setpeername(...); _:set_send(dummy_send); return ret; end
-	handler.connect = function (_, ...) return sock:connect(...) end
-	--handler.send = function (_, data) _:write(data);  return _.sendbuffer and _.sendbuffer(); end
-	handler.send = function (_, data)
-		local getpeername = sock.getpeername;
-		log("debug", "Sending DNS query to %s", (getpeername and getpeername(sock)) or "<unconnected>");
-		return sock:send(data);
-	end
-	return handler;
-end
-
-dns.socket_wrapper_set(new_async_socket);
-
-return _M;
- end)
-package.preload['net.server'] = (function (...)
--- 
--- server.lua by blastbeat of the luadch project
--- Re-used here under the MIT/X Consortium License
--- 
--- Modifications (C) 2008-2010 Matthew Wild, Waqas Hussain
---
-
--- // wrapping luadch stuff // --
-
-local use = function( what )
-	return _G[ what ]
-end
-local clean = function( tbl )
-	for i, k in pairs( tbl ) do
-		tbl[ i ] = nil
-	end
-end
-
-local log, table_concat = require ("util.logger").init("socket"), table.concat;
-local out_put = function (...) return log("debug", table_concat{...}); end
-local out_error = function (...) return log("warn", table_concat{...}); end
-local mem_free = collectgarbage
-
-----------------------------------// DECLARATION //--
-
---// constants //--
-
-local STAT_UNIT = 1 -- byte
-
---// lua functions //--
-
-local type = use "type"
-local pairs = use "pairs"
-local ipairs = use "ipairs"
-local tonumber = use "tonumber"
-local tostring = use "tostring"
-local collectgarbage = use "collectgarbage"
-
---// lua libs //--
-
-local os = use "os"
-local table = use "table"
-local string = use "string"
-local coroutine = use "coroutine"
-
---// lua lib methods //--
-
-local os_difftime = os.difftime
-local math_min = math.min
-local math_huge = math.huge
-local table_concat = table.concat
-local table_remove = table.remove
-local string_len = string.len
-local string_sub = string.sub
-local coroutine_wrap = coroutine.wrap
-local coroutine_yield = coroutine.yield
-
---// extern libs //--
-
-local luasec = use "ssl"
-local luasocket = use "socket" or require "socket"
-local luasocket_gettime = luasocket.gettime
-
---// extern lib methods //--
-
-local ssl_wrap = ( luasec and luasec.wrap )
-local socket_bind = luasocket.bind
-local socket_sleep = luasocket.sleep
-local socket_select = luasocket.select
-local ssl_newcontext = ( luasec and luasec.newcontext )
-
---// functions //--
-
-local id
-local loop
-local stats
-local idfalse
-local addtimer
-local closeall
-local addsocket
-local addserver
-local getserver
-local wrapserver
-local getsettings
-local closesocket
-local removesocket
-local removeserver
-local changetimeout
-local wrapconnection
-local changesettings
-
---// tables //--
-
-local _server
-local _readlist
-local _timerlist
-local _sendlist
-local _socketlist
-local _closelist
-local _readtimes
-local _writetimes
-
---// simple data types //--
-
-local _
-local _readlistlen
-local _sendlistlen
-local _timerlistlen
-
-local _sendtraffic
-local _readtraffic
-
-local _selecttimeout
-local _sleeptime
-
-local _starttime
-local _currenttime
-
-local _maxsendlen
-local _maxreadlen
-
-local _checkinterval
-local _sendtimeout
-local _readtimeout
-
-local _cleanqueue
-
-local _timer
-
-local _maxclientsperserver
-
-local _maxsslhandshake
-
-----------------------------------// DEFINITION //--
-
-_server = { } -- key = port, value = table; list of listening servers
-_readlist = { } -- array with sockets to read from
-_sendlist = { } -- arrary with sockets to write to
-_timerlist = { } -- array of timer functions
-_socketlist = { } -- key = socket, value = wrapped socket (handlers)
-_readtimes = { } -- key = handler, value = timestamp of last data reading
-_writetimes = { } -- key = handler, value = timestamp of last data writing/sending
-_closelist = { } -- handlers to close
-
-_readlistlen = 0 -- length of readlist
-_sendlistlen = 0 -- length of sendlist
-_timerlistlen = 0 -- lenght of timerlist
-
-_sendtraffic = 0 -- some stats
-_readtraffic = 0
-
-_selecttimeout = 1 -- timeout of socket.select
-_sleeptime = 0 -- time to wait at the end of every loop
-
-_maxsendlen = 51000 * 1024 -- max len of send buffer
-_maxreadlen = 25000 * 1024 -- max len of read buffer
-
-_checkinterval = 1200000 -- interval in secs to check idle clients
-_sendtimeout = 60000 -- allowed send idle time in secs
-_readtimeout = 6 * 60 * 60 -- allowed read idle time in secs
-
-_cleanqueue = false -- clean bufferqueue after using
-
-_maxclientsperserver = 1000
-
-_maxsslhandshake = 30 -- max handshake round-trips
-
-----------------------------------// PRIVATE //--
-
-wrapserver = function( listeners, socket, ip, serverport, pattern, sslctx, maxconnections ) -- this function wraps a server
-
-	maxconnections = maxconnections or _maxclientsperserver
-
-	local connections = 0
-
-	local dispatch, disconnect = listeners.onconnect or listeners.onincoming, listeners.ondisconnect
-
-	local accept = socket.accept
-
-	--// public methods of the object //--
-
-	local handler = { }
-
-	handler.shutdown = function( ) end
-
-	handler.ssl = function( )
-		return sslctx ~= nil
-	end
-	handler.sslctx = function( )
-		return sslctx
-	end
-	handler.remove = function( )
-		connections = connections - 1
-	end
-	handler.close = function( )
-		for _, handler in pairs( _socketlist ) do
-			if handler.serverport == serverport then
-				handler.disconnect( handler, "server closed" )
-				handler:close( true )
-			end
-		end
-		socket:close( )
-		_sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
-		_readlistlen = removesocket( _readlist, socket, _readlistlen )
-		_socketlist[ socket ] = nil
-		handler = nil
-		socket = nil
-		--mem_free( )
-		out_put "server.lua: closed server handler and removed sockets from list"
-	end
-	handler.ip = function( )
-		return ip
-	end
-	handler.serverport = function( )
-		return serverport
-	end
-	handler.socket = function( )
-		return socket
-	end
-	handler.readbuffer = function( )
-		if connections > maxconnections then
-			out_put( "server.lua: refused new client connection: server full" )
-			return false
-		end
-		local client, err = accept( socket )	-- try to accept
-		if client then
-			local ip, clientport = client:getpeername( )
-			client:settimeout( 0 )
-			local handler, client, err = wrapconnection( handler, listeners, client, ip, serverport, clientport, pattern, sslctx ) -- wrap new client socket
-			if err then -- error while wrapping ssl socket
-				return false
-			end
-			connections = connections + 1
-			out_put( "server.lua: accepted new client connection from ", tostring(ip), ":", tostring(clientport), " to ", tostring(serverport))
-			return dispatch( handler )
-		elseif err then -- maybe timeout or something else
-			out_put( "server.lua: error with new client connection: ", tostring(err) )
-			return false
-		end
-	end
-	return handler
-end
-
-wrapconnection = function( server, listeners, socket, ip, serverport, clientport, pattern, sslctx ) -- this function wraps a client to a handler object
-
-	socket:settimeout( 0 )
-
-	--// local import of socket methods //--
-
-	local send
-	local receive
-	local shutdown
-
-	--// private closures of the object //--
-
-	local ssl
-
-	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
-
-	local toclose
-	local fatalerror
-	local needtls
-
-	local bufferlen = 0
-
-	local noread = false
-	local nosend = false
-
-	local sendtraffic, readtraffic = 0, 0
-
-	local maxsendlen = _maxsendlen
-	local maxreadlen = _maxreadlen
-
-	--// public methods of the object //--
-
-	local handler = bufferqueue -- saves a table ^_^
-
-	handler.dispatch = function( )
-		return dispatch
-	end
-	handler.disconnect = function( )
-		return disconnect
-	end
-	handler.setlistener = function( self, listeners )
-		dispatch = listeners.onincoming
-		disconnect = listeners.ondisconnect
-		status = listeners.onstatus
-		drain = listeners.ondrain
-	end
-	handler.getstats = function( )
-		return readtraffic, sendtraffic
-	end
-	handler.ssl = function( )
-		return ssl
-	end
-	handler.sslctx = function ( )
-		return sslctx
-	end
-	handler.send = function( _, data, i, j )
-		return send( socket, data, i, j )
-	end
-	handler.receive = function( pattern, prefix )
-		return receive( socket, pattern, prefix )
-	end
-	handler.shutdown = function( pattern )
-		return shutdown( socket, pattern )
-	end
-	handler.setoption = function (self, option, value)
-		if socket.setoption then
-			return socket:setoption(option, value);
-		end
-		return false, "setoption not implemented";
-	end
-	handler.close = function( self, forced )
-		if not handler then return true; end
-		_readlistlen = removesocket( _readlist, socket, _readlistlen )
-		_readtimes[ handler ] = nil
-		if bufferqueuelen ~= 0 then
-			if not ( forced or fatalerror ) then
-				handler.sendbuffer( )
-				if bufferqueuelen ~= 0 then -- try again...
-					if handler then
-						handler.write = nil -- ... but no further writing allowed
-					end
-					toclose = true
-					return false
-				end
-			else
-				send( socket, table_concat( bufferqueue, "", 1, bufferqueuelen ), 1, bufferlen )	-- forced send
-			end
-		end
-		if socket then
-			_ = shutdown and shutdown( socket )
-			socket:close( )
-			_sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
-			_socketlist[ socket ] = nil
-			socket = nil
-		else
-			out_put "server.lua: socket already closed"
-		end
-		if handler then
-			_writetimes[ handler ] = nil
-			_closelist[ handler ] = nil
-			handler = nil
-		end
-		if server then
-			server.remove( )
-		end
-		out_put "server.lua: closed client handler and removed socket from list"
-		return true
-	end
-	handler.ip = function( )
-		return ip
-	end
-	handler.serverport = function( )
-		return serverport
-	end
-	handler.clientport = function( )
-		return clientport
-	end
-	local write = function( self, data )
-		bufferlen = bufferlen + string_len( data )
-		if bufferlen > maxsendlen then
-			_closelist[ handler ] = "send buffer exceeded"	 -- cannot close the client at the moment, have to wait to the end of the cycle
-			handler.write = idfalse -- dont write anymore
-			return false
-		elseif socket and not _sendlist[ socket ] then
-			_sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
-		end
-		bufferqueuelen = bufferqueuelen + 1
-		bufferqueue[ bufferqueuelen ] = data
-		if handler then
-			_writetimes[ handler ] = _writetimes[ handler ] or _currenttime
-		end
-		return true
-	end
-	handler.write = write
-	handler.bufferqueue = function( self )
-		return bufferqueue
-	end
-	handler.socket = function( self )
-		return socket
-	end
-	handler.set_mode = function( self, new )
-		pattern = new or pattern
-		return pattern
-	end
-	handler.set_send = function ( self, newsend )
-		send = newsend or send
-		return send
-	end
-	handler.bufferlen = function( self, readlen, sendlen )
-		maxsendlen = sendlen or maxsendlen
-		maxreadlen = readlen or maxreadlen
-		return bufferlen, maxreadlen, maxsendlen
-	end
-	--TODO: Deprecate
-	handler.lock_read = function (self, switch)
-		if switch == true then
-			local tmp = _readlistlen
-			_readlistlen = removesocket( _readlist, socket, _readlistlen )
-			_readtimes[ handler ] = nil
-			if _readlistlen ~= tmp then
-				noread = true
-			end
-		elseif switch == false then
-			if noread then
-				noread = false
-				_readlistlen = addsocket(_readlist, socket, _readlistlen)
-				_readtimes[ handler ] = _currenttime
-			end
-		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
-			handler.write = idfalse
-			local tmp = _sendlistlen
-			_sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
-			_writetimes[ handler ] = nil
-			if _sendlistlen ~= tmp then
-				nosend = true
-			end
-		elseif switch == false then
-			handler.write = write
-			if nosend then
-				nosend = false
-				write( "" )
-			end
-		end
-		return noread, nosend
-	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") 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 )
-				return false
-			end
-			local count = len * STAT_UNIT
-			readtraffic = readtraffic + count
-			_readtraffic = _readtraffic + count
-			_readtimes[ handler ] = _currenttime
-			--out_put( "server.lua: read data '", buffer:gsub("[^%w%p ]", "."), "', error: ", err )
-			return dispatch( handler, buffer, err )
-		else	-- connections was closed or fatal error
-			out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " read error: ", tostring(err) )
-			fatalerror = true
-			disconnect( handler, err )
-		_ = handler and handler:close( )
-			return false
-		end
-	end
-	local _sendbuffer = function( ) -- this function sends data
-		local succ, err, byte, buffer, count;
-		local count;
-		if socket then
-			buffer = table_concat( bufferqueue, "", 1, bufferqueuelen )
-			succ, err, byte = send( socket, buffer, 1, bufferlen )
-			count = ( succ or byte or 0 ) * STAT_UNIT
-			sendtraffic = sendtraffic + count
-			_sendtraffic = _sendtraffic + count
-			_ = _cleanqueue and clean( bufferqueue )
-			--out_put( "server.lua: sended '", buffer, "', bytes: ", tostring(succ), ", error: ", tostring(err), ", part: ", tostring(byte), ", to: ", tostring(ip), ":", tostring(clientport) )
-		else
-			succ, err, count = false, "closed", 0;
-		end
-		if succ then	-- sending succesful
-			bufferqueuelen = 0
-			bufferlen = 0
-			_sendlistlen = removesocket( _sendlist, socket, _sendlistlen ) -- delete socket from writelist
-			_writetimes[ handler ] = nil
-			if drain then
-				drain(handler)
-			end
-			_ = needtls and handler:starttls(nil)
-			_ = 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
-			bufferqueue[ 1 ] = buffer	 -- insert new buffer in queue
-			bufferqueuelen = 1
-			bufferlen = bufferlen - byte
-			_writetimes[ handler ] = _currenttime
-			return true
-		else	-- connection was closed during sending or fatal error
-			out_put( "server.lua: client ", tostring(ip), ":", tostring(clientport), " write error: ", tostring(err) )
-			fatalerror = true
-			disconnect( handler, err )
-			_ = handler and handler:close( )
-			return false
-		end
-	end
-
-	-- Set the sslctx
-	local handshake;
-	function handler.set_sslctx(self, new_sslctx)
-		ssl = true
-		sslctx = new_sslctx;
-		local wrote
-		local read
-		handshake = coroutine_wrap( function( client ) -- create handshake coroutine
-				local err
-				for i = 1, _maxsslhandshake do
-					_sendlistlen = ( wrote and removesocket( _sendlist, client, _sendlistlen ) ) or _sendlistlen
-					_readlistlen = ( read and removesocket( _readlist, client, _readlistlen ) ) or _readlistlen
-					read, wrote = nil, nil
-					_, err = client:dohandshake( )
-					if not err then
-						out_put( "server.lua: ssl handshake done" )
-						handler.readbuffer = _readbuffer	-- when handshake is done, replace the handshake function with regular functions
-						handler.sendbuffer = _sendbuffer
-						_ = status and status( handler, "ssl-handshake-complete" )
-						_readlistlen = addsocket(_readlist, client, _readlistlen)
-						return true
-					else
-						if err == "wantwrite" and not wrote then
-							_sendlistlen = addsocket(_sendlist, client, _sendlistlen)
-							wrote = true
-						elseif err == "wantread" and not read then
-							_readlistlen = addsocket(_readlist, client, _readlistlen)
-							read = true
-						else
-							out_put( "server.lua: ssl handshake error: ", tostring(err) )
-							break;
-						end
-						--coroutine_yield( handler, nil, err )	 -- handshake not finished
-						coroutine_yield( )
-					end
-				end
-				disconnect( handler, "ssl handshake failed" )
-				_ = handler and handler:close( true )	 -- forced disconnect
-				return false	-- handshake failed
-			end
-		)
-	end
-	if luasec then
-		if sslctx then -- ssl?
-			handler:set_sslctx(sslctx);
-			out_put("server.lua: ", "starting ssl handshake")
-			local err
-			socket, err = ssl_wrap( socket, sslctx )	-- wrap socket
-			if err then
-				out_put( "server.lua: ssl error: ", tostring(err) )
-				--mem_free( )
-				return nil, nil, err	-- fatal error
-			end
-			socket:settimeout( 0 )
-			handler.readbuffer = handshake
-			handler.sendbuffer = handshake
-			handshake( socket ) -- do handshake
-			if not socket then
-				return nil, nil, "ssl handshake failed";
-			end
-		else
-			local sslctx;
-			handler.starttls = function( self, _sslctx)
-				if _sslctx then
-					sslctx = _sslctx;
-					handler:set_sslctx(sslctx);
-				end
-				if bufferqueuelen > 0 then
-					out_put "server.lua: we need to do tls, but delaying until send buffer empty"
-					needtls = true
-					return
-				end
-				out_put( "server.lua: attempting to start tls on " .. tostring( socket ) )
-				local oldsocket, err = socket
-				socket, err = ssl_wrap( socket, sslctx )	-- wrap socket
-				--out_put( "server.lua: sslwrapped socket is " .. tostring( socket ) )
-				if err then
-					out_put( "server.lua: error while starting tls on client: ", tostring(err) )
-					return nil, err -- fatal error
-				end
-
-				socket:settimeout( 0 )
-	
-				-- add the new socket to our system
-	
-				send = socket.send
-				receive = socket.receive
-				shutdown = id
-
-				_socketlist[ socket ] = handler
-				_readlistlen = addsocket(_readlist, socket, _readlistlen)
-
-				-- remove traces of the old socket
-
-				_readlistlen = removesocket( _readlist, oldsocket, _readlistlen )
-				_sendlistlen = removesocket( _sendlist, oldsocket, _sendlistlen )
-				_socketlist[ oldsocket ] = nil
-
-				handler.starttls = nil
-				needtls = nil
-
-				-- Secure now
-				ssl = true
-
-				handler.readbuffer = handshake
-				handler.sendbuffer = handshake
-				handshake( socket ) -- do handshake
-			end
-			handler.readbuffer = _readbuffer
-			handler.sendbuffer = _sendbuffer
-		end
-	else
-		handler.readbuffer = _readbuffer
-		handler.sendbuffer = _sendbuffer
-	end
-	send = socket.send
-	receive = socket.receive
-	shutdown = ( ssl and id ) or socket.shutdown
-
-	_socketlist[ socket ] = handler
-	_readlistlen = addsocket(_readlist, socket, _readlistlen)
-	return handler, socket
-end
-
-id = function( )
-end
-
-idfalse = function( )
-	return false
-end
-
-addsocket = function( list, socket, len )
-	if not list[ socket ] then
-		len = len + 1
-		list[ len ] = socket
-		list[ socket ] = len
-	end
-	return len;
-end
-
-removesocket = function( list, socket, len )	-- this function removes sockets from a list ( copied from copas )
-	local pos = list[ socket ]
-	if pos then
-		list[ socket ] = nil
-		local last = list[ len ]
-		list[ len ] = nil
-		if last ~= socket then
-			list[ last ] = pos
-			list[ pos ] = last
-		end
-		return len - 1
-	end
-	return len
-end
-
-closesocket = function( socket )
-	_sendlistlen = removesocket( _sendlist, socket, _sendlistlen )
-	_readlistlen = removesocket( _readlist, socket, _readlistlen )
-	_socketlist[ socket ] = nil
-	socket:close( )
-	--mem_free( )
-end
-
-local function link(sender, receiver, 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
-	local err
-	if type( listeners ) ~= "table" then
-		err = "invalid listener table"
-	end
-	if type( port ) ~= "number" or not ( port >= 0 and port <= 65535 ) then
-		err = "invalid port"
-	elseif _server[ addr..":"..port ] then
-		err = "listeners on '[" .. addr .. "]:" .. port .. "' already exist"
-	elseif sslctx and not luasec then
-		err = "luasec not found"
-	end
-	if err then
-		out_error( "server.lua, [", addr, "]:", port, ": ", err )
-		return nil, err
-	end
-	addr = addr or "*"
-	local server, err = socket_bind( addr, port )
-	if err then
-		out_error( "server.lua, [", addr, "]:", port, ": ", err )
-		return nil, err
-	end
-	local handler, err = wrapserver( listeners, server, addr, port, pattern, sslctx, _maxclientsperserver ) -- wrap new server socket
-	if not handler then
-		server:close( )
-		return nil, err
-	end
-	server:settimeout( 0 )
-	_readlistlen = addsocket(_readlist, server, _readlistlen)
-	_server[ addr..":"..port ] = handler
-	_socketlist[ server ] = handler
-	out_put( "server.lua: new "..(sslctx and "ssl " or "").."server listener on '[", addr, "]:", port, "'" )
-	return handler
-end
-
-getserver = function ( addr, port )
-	return _server[ addr..":"..port ];
-end
-
-removeserver = function( addr, port )
-	local handler = _server[ addr..":"..port ]
-	if not handler then
-		return nil, "no server found on '[" .. addr .. "]:" .. tostring( port ) .. "'"
-	end
-	handler:close( )
-	_server[ addr..":"..port ] = nil
-	return true
-end
-
-closeall = function( )
-	for _, handler in pairs( _socketlist ) do
-		handler:close( )
-		_socketlist[ _ ] = nil
-	end
-	_readlistlen = 0
-	_sendlistlen = 0
-	_timerlistlen = 0
-	_server = { }
-	_readlist = { }
-	_sendlist = { }
-	_timerlist = { }
-	_socketlist = { }
-	--mem_free( )
-end
-
-getsettings = function( )
-	return	_selecttimeout, _sleeptime, _maxsendlen, _maxreadlen, _checkinterval, _sendtimeout, _readtimeout, _cleanqueue, _maxclientsperserver, _maxsslhandshake
-end
-
-changesettings = function( new )
-	if type( new ) ~= "table" then
-		return nil, "invalid settings table"
-	end
-	_selecttimeout = tonumber( new.timeout ) or _selecttimeout
-	_sleeptime = tonumber( new.sleeptime ) or _sleeptime
-	_maxsendlen = tonumber( new.maxsendlen ) or _maxsendlen
-	_maxreadlen = tonumber( new.maxreadlen ) or _maxreadlen
-	_checkinterval = tonumber( new.checkinterval ) or _checkinterval
-	_sendtimeout = tonumber( new.sendtimeout ) or _sendtimeout
-	_readtimeout = tonumber( new.readtimeout ) or _readtimeout
-	_cleanqueue = new.cleanqueue
-	_maxclientsperserver = new._maxclientsperserver or _maxclientsperserver
-	_maxsslhandshake = new._maxsslhandshake or _maxsslhandshake
-	return true
-end
-
-addtimer = function( listener )
-	if type( listener ) ~= "function" then
-		return nil, "invalid listener function"
-	end
-	_timerlistlen = _timerlistlen + 1
-	_timerlist[ _timerlistlen ] = listener
-	return true
-end
-
-stats = function( )
-	return _readtraffic, _sendtraffic, _readlistlen, _sendlistlen, _timerlistlen
-end
-
-local quitting;
-
-setquitting = function (quit)
-	quitting = not not quit;
-end
-
-loop = function(once) -- this is the main loop of the program
-	if quitting then return "quitting"; end
-	if once then quitting = "once"; end
-	local next_timer_time = math_huge;
-	repeat
-		local read, write, err = socket_select( _readlist, _sendlist, math_min(_selecttimeout, next_timer_time) )
-		for i, socket in ipairs( write ) do -- send data waiting in writequeues
-			local handler = _socketlist[ socket ]
-			if handler then
-				handler.sendbuffer( )
-			else
-				closesocket( socket )
-				out_put "server.lua: found no handler and closed socket (writelist)"	-- this should not happen
-			end
-		end
-		for i, socket in ipairs( read ) do -- receive data
-			local handler = _socketlist[ socket ]
-			if handler then
-				handler.readbuffer( )
-			else
-				closesocket( socket )
-				out_put "server.lua: found no handler and closed socket (readlist)" -- this can happen
-			end
-		end
-		for handler, err in pairs( _closelist ) do
-			handler.disconnect( )( handler, err )
-			handler:close( true )	 -- forced disconnect
-		end
-		clean( _closelist )
-		_currenttime = luasocket_gettime( )
-		if _currenttime - _timer >= math_min(next_timer_time, 1) then
-			next_timer_time = math_huge;
-			for i = 1, _timerlistlen do
-				local t = _timerlist[ i ]( _currenttime ) -- fire timers
-				if t then next_timer_time = math_min(next_timer_time, t); end
-			end
-			_timer = _currenttime
-		else
-			next_timer_time = next_timer_time - (_currenttime - _timer);
-		end
-		socket_sleep( _sleeptime ) -- wait some time
-		--collectgarbage( )
-	until quitting;
-	if once and quitting == "once" then quitting = nil; return; end
-	return "quitting"
-end
-
-step = function ()
-	return loop(true);
-end
-
-local function get_backend()
-	return "select";
-end
-
---// EXPERIMENTAL //--
-
-local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx )
-	local handler = wrapconnection( nil, listeners, socket, ip, serverport, "clientport", pattern, sslctx )
-	_socketlist[ socket ] = handler
-	_sendlistlen = addsocket(_sendlist, socket, _sendlistlen)
-	if listeners.onconnect then
-		-- When socket is writeable, call onconnect
-		local _sendbuffer = handler.sendbuffer;
-		handler.sendbuffer = function ()
-			handler.sendbuffer = _sendbuffer;
-			listeners.onconnect(handler);
-			-- If there was data with the incoming packet, handle it now.
-			if #handler:bufferqueue() > 0 then
-				return _sendbuffer();
-			end
-		end
-	end
-	return handler, socket
-end
-
-local addclient = function( address, port, listeners, pattern, sslctx )
-	local client, err = luasocket.tcp( )
-	if err then
-		return nil, err
-	end
-	client:settimeout( 0 )
-	_, err = client:connect( address, port )
-	if err then -- try again
-		local handler = wrapclient( client, address, port, listeners )
-	else
-		wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx )
-	end
-end
-
---// EXPERIMENTAL //--
-
-----------------------------------// BEGIN //--
-
-use "setmetatable" ( _socketlist, { __mode = "k" } )
-use "setmetatable" ( _readtimes, { __mode = "k" } )
-use "setmetatable" ( _writetimes, { __mode = "k" } )
-
-_timer = luasocket_gettime( )
-_starttime = luasocket_gettime( )
-
-addtimer( function( )
-		local difftime = os_difftime( _currenttime - _starttime )
-		if difftime > _checkinterval then
-			_starttime = _currenttime
-			for handler, timestamp in pairs( _writetimes ) do
-				if os_difftime( _currenttime - timestamp ) > _sendtimeout then
-					--_writetimes[ handler ] = nil
-					handler.disconnect( )( handler, "send timeout" )
-					handler:close( true )	 -- forced disconnect
-				end
-			end
-			for handler, timestamp in pairs( _readtimes ) do
-				if os_difftime( _currenttime - timestamp ) > _readtimeout then
-					--_readtimes[ handler ] = nil
-					handler.disconnect( )( handler, "read timeout" )
-					handler:close( )	-- forced disconnect?
-				end
-			end
-		end
-	end
-)
-
-local function setlogger(new_logger)
-	local old_logger = log;
-	if new_logger then
-		log = new_logger;
-	end
-	return old_logger;
-end
-
-----------------------------------// PUBLIC INTERFACE //--
-
-return {
-
-	addclient = addclient,
-	wrapclient = wrapclient,
-	
-	loop = loop,
-	link = link,
-	step = step,
-	stats = stats,
-	closeall = closeall,
-	addtimer = addtimer,
-	addserver = addserver,
-	getserver = getserver,
-	setlogger = setlogger,
-	getsettings = getsettings,
-	setquitting = setquitting,
-	removeserver = removeserver,
-	get_backend = get_backend,
-	changesettings = changesettings,
-}
- end)
-package.preload['util.xmppstream'] = (function (...)
--- 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 lxp = require "lxp";
-local st = require "util.stanza";
-local stanza_mt = st.stanza_mt;
-
-local tostring = tostring;
-local t_insert = table.insert;
-local t_concat = table.concat;
-local t_remove = table.remove;
-local setmetatable = setmetatable;
-
-local default_log = require "util.logger".init("xmppstream");
-
--- COMPAT: w/LuaExpat 1.1.0
-local lxp_supports_doctype = pcall(lxp.new, { StartDoctypeDecl = false });
-
-if not lxp_supports_doctype then
-	default_log("warn", "The version of LuaExpat on your system leaves Prosody "
-		.."vulnerable to denial-of-service attacks. You should upgrade to "
-		.."LuaExpat 1.1.1 or higher as soon as possible. See "
-		.."http://prosody.im/doc/depends#luaexpat for more information.");
-end
-
-local error = error;
-
-module "xmppstream"
-
-local new_parser = lxp.new;
-
-local ns_prefixes = {
-	["http://www.w3.org/XML/1998/namespace"] = "xml";
-};
-
-local xmlns_streams = "http://etherx.jabber.org/streams";
-
-local ns_separator = "\1";
-local ns_pattern = "^([^"..ns_separator.."]*)"..ns_separator.."?(.*)$";
-
-_M.ns_separator = ns_separator;
-_M.ns_pattern = ns_pattern;
-
-function new_sax_handlers(session, stream_callbacks)
-	local xml_handlers = {};
-	
-	local log = session.log or default_log;
-	
-	local cb_streamopened = stream_callbacks.streamopened;
-	local cb_streamclosed = stream_callbacks.streamclosed;
-	local cb_error = stream_callbacks.error or function(session, e) error("XML stream error: "..tostring(e)); end;
-	local cb_handlestanza = stream_callbacks.handlestanza;
-	
-	local stream_ns = stream_callbacks.stream_ns or xmlns_streams;
-	local stream_tag = stream_callbacks.stream_tag or "stream";
-	if stream_ns ~= "" then
-		stream_tag = stream_ns..ns_separator..stream_tag;
-	end
-	local stream_error_tag = stream_ns..ns_separator..(stream_callbacks.error_tag or "error");
-	
-	local stream_default_ns = stream_callbacks.default_ns;
-	
-	local stack = {};
-	local chardata, stanza = {};
-	local non_streamns_depth = 0;
-	function xml_handlers:StartElement(tagname, attr)
-		if stanza and #chardata > 0 then
-			-- We have some character data in the buffer
-			t_insert(stanza, t_concat(chardata));
-			chardata = {};
-		end
-		local curr_ns,name = tagname:match(ns_pattern);
-		if name == "" then
-			curr_ns, name = "", curr_ns;
-		end
-
-		if curr_ns ~= stream_default_ns or non_streamns_depth > 0 then
-			attr.xmlns = curr_ns;
-			non_streamns_depth = non_streamns_depth + 1;
-		end
-		
-		-- FIXME !!!!!
-		for i=1,#attr do
-			local k = attr[i];
-			attr[i] = nil;
-			local ns, nm = k:match(ns_pattern);
-			if nm ~= "" then
-				ns = ns_prefixes[ns];
-				if ns then
-					attr[ns..":"..nm] = attr[k];
-					attr[k] = nil;
-				end
-			end
-		end
-		
-		if not stanza then --if we are not currently inside a stanza
-			if session.notopen then
-				if tagname == stream_tag then
-					non_streamns_depth = 0;
-					if cb_streamopened then
-						cb_streamopened(session, attr);
-					end
-				else
-					-- Garbage before stream?
-					cb_error(session, "no-stream");
-				end
-				return;
-			end
-			if curr_ns == "jabber:client" and name ~= "iq" and name ~= "presence" and name ~= "message" then
-				cb_error(session, "invalid-top-level-element");
-			end
-			
-			stanza = setmetatable({ name = name, attr = attr, tags = {} }, stanza_mt);
-		else -- we are inside a stanza, so add a tag
-			t_insert(stack, stanza);
-			local oldstanza = stanza;
-			stanza = setmetatable({ name = name, attr = attr, tags = {} }, stanza_mt);
-			t_insert(oldstanza, stanza);
-			t_insert(oldstanza.tags, stanza);
-		end
-	end
-	function xml_handlers:CharacterData(data)
-		if stanza then
-			t_insert(chardata, data);
-		end
-	end
-	function xml_handlers:EndElement(tagname)
-		if non_streamns_depth > 0 then
-			non_streamns_depth = non_streamns_depth - 1;
-		end
-		if stanza then
-			if #chardata > 0 then
-				-- We have some character data in the buffer
-				t_insert(stanza, t_concat(chardata));
-				chardata = {};
-			end
-			-- Complete stanza
-			if #stack == 0 then
-				if tagname ~= stream_error_tag then
-					cb_handlestanza(session, stanza);
-				else
-					cb_error(session, "stream-error", stanza);
-				end
-				stanza = nil;
-			else
-				stanza = t_remove(stack);
-			end
-		else
-			if tagname == stream_tag then
-				if cb_streamclosed then
-					cb_streamclosed(session);
-				end
-			else
-				local curr_ns,name = tagname:match(ns_pattern);
-				if name == "" then
-					curr_ns, name = "", curr_ns;
-				end
-				cb_error(session, "parse-error", "unexpected-element-close", name);
-			end
-			stanza, chardata = nil, {};
-			stack = {};
-		end
-	end
-
-	local function restricted_handler(parser)
-		cb_error(session, "parse-error", "restricted-xml", "Restricted XML, see RFC 6120 section 11.1.");
-		if not parser.stop or not parser:stop() then
-			error("Failed to abort parsing");
-		end
-	end
-	
-	if lxp_supports_doctype then
-		xml_handlers.StartDoctypeDecl = restricted_handler;
-	end
-	xml_handlers.Comment = restricted_handler;
-	xml_handlers.ProcessingInstruction = restricted_handler;
-	
-	local function reset()
-		stanza, chardata = nil, {};
-		stack = {};
-	end
-	
-	local function set_session(stream, new_session)
-		session = new_session;
-		log = new_session.log or default_log;
-	end
-	
-	return xml_handlers, { reset = reset, set_session = set_session };
-end
-
-function new(session, stream_callbacks)
-	local handlers, meta = new_sax_handlers(session, stream_callbacks);
-	local parser = new_parser(handlers, ns_separator);
-	local parse = parser.parse;
-
-	return {
-		reset = function ()
-			parser = new_parser(handlers, ns_separator);
-			parse = parser.parse;
-			meta.reset();
-		end,
-		feed = function (self, data)
-			return parse(parser, data);
-		end,
-		set_session = meta.set_session;
-	};
-end
-
-return _M;
- end)
-package.preload['util.jid'] = (function (...)
--- 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 match = string.match;
-local nodeprep = require "util.encodings".stringprep.nodeprep;
-local nameprep = require "util.encodings".stringprep.nameprep;
-local resourceprep = require "util.encodings".stringprep.resourceprep;
-
-module "jid"
-
-local function _split(jid)
-	if not jid then return; end
-	local node, nodepos = match(jid, "^([^@/]+)@()");
-	local host, hostpos = match(jid, "^([^@/]+)()", nodepos)
-	if node and not host then return nil, nil, nil; end
-	local resource = match(jid, "^/(.+)$", hostpos);
-	if (not host) or ((not resource) and #jid >= hostpos) then return nil, nil, nil; end
-	return node, host, resource;
-end
-split = _split;
-
-function bare(jid)
-	local node, host = _split(jid);
-	if node and host then
-		return node.."@"..host;
-	end
-	return host;
-end
-
-local function _prepped_split(jid)
-	local node, host, resource = _split(jid);
-	if host then
-		host = nameprep(host);
-		if not host then return; end
-		if node then
-			node = nodeprep(node);
-			if not node then return; end
-		end
-		if resource then
-			resource = resourceprep(resource);
-			if not resource then return; end
-		end
-		return node, host, resource;
-	end
-end
-prepped_split = _prepped_split;
-
-function prep(jid)
-	local node, host, resource = _prepped_split(jid);
-	if host then
-		if node then
-			host = node .. "@" .. host;
-		end
-		if resource then
-			host = host .. "/" .. resource;
-		end
-	end
-	return host;
-end
-
-function join(node, host, resource)
-	if node and host and resource then
-		return node.."@"..host.."/"..resource;
-	elseif node and host then
-		return node.."@"..host;
-	elseif host and resource then
-		return host.."/"..resource;
-	elseif host then
-		return host;
-	end
-	return nil; -- Invalid JID
-end
-
-function compare(jid, acl)
-	-- compare jid to single acl rule
-	-- TODO compare to table of rules?
-	local jid_node, jid_host, jid_resource = _split(jid);
-	local acl_node, acl_host, acl_resource = _split(acl);
-	if ((acl_node ~= nil and acl_node == jid_node) or acl_node == nil) and
-		((acl_host ~= nil and acl_host == jid_host) or acl_host == nil) and
-		((acl_resource ~= nil and acl_resource == jid_resource) or acl_resource == nil) then
-		return true
-	end
-	return false
-end
-
-return _M;
- end)
-package.preload['util.events'] = (function (...)
--- 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 pairs = pairs;
-local t_insert = table.insert;
-local t_sort = table.sort;
-local setmetatable = setmetatable;
-local next = next;
-
-module "events"
-
-function new()
-	local handlers = {};
-	local event_map = {};
-	local function _rebuild_index(handlers, event)
-		local _handlers = event_map[event];
-		if not _handlers or next(_handlers) == nil then return; end
-		local index = {};
-		for handler in pairs(_handlers) do
-			t_insert(index, handler);
-		end
-		t_sort(index, function(a, b) return _handlers[a] > _handlers[b]; end);
-		handlers[event] = index;
-		return index;
-	end;
-	setmetatable(handlers, { __index = _rebuild_index });
-	local function add_handler(event, handler, priority)
-		local map = event_map[event];
-		if map then
-			map[handler] = priority or 0;
-		else
-			map = {[handler] = priority or 0};
-			event_map[event] = map;
-		end
-		handlers[event] = nil;
-	end;
-	local function remove_handler(event, handler)
-		local map = event_map[event];
-		if map then
-			map[handler] = nil;
-			handlers[event] = nil;
-			if next(map) == nil then
-				event_map[event] = nil;
-			end
-		end
-	end;
-	local function add_handlers(handlers)
-		for event, handler in pairs(handlers) do
-			add_handler(event, handler);
-		end
-	end;
-	local function remove_handlers(handlers)
-		for event, handler in pairs(handlers) do
-			remove_handler(event, handler);
-		end
-	end;
-	local function fire_event(event, ...)
-		local h = handlers[event];
-		if h then
-			for i=1,#h do
-				local ret = h[i](...);
-				if ret ~= nil then return ret; end
-			end
-		end
-	end;
-	return {
-		add_handler = add_handler;
-		remove_handler = remove_handler;
-		add_handlers = add_handlers;
-		remove_handlers = remove_handlers;
-		fire_event = fire_event;
-		_handlers = handlers;
-		_event_map = event_map;
-	};
-end
-
-return _M;
- end)
-package.preload['util.dataforms'] = (function (...)
--- 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 setmetatable = setmetatable;
-local pairs, ipairs = pairs, ipairs;
-local tostring, type = tostring, type;
-local t_concat = table.concat;
-local st = require "util.stanza";
-
-module "dataforms"
-
-local xmlns_forms = 'jabber:x:data';
-
-local form_t = {};
-local form_mt = { __index = form_t };
-
-function new(layout)
-	return setmetatable(layout, form_mt);
-end
-
-function form_t.form(layout, data, formtype)
-	local form = st.stanza("x", { xmlns = xmlns_forms, type = formtype or "form" });
-	if layout.title then
-		form:tag("title"):text(layout.title):up();
-	end
-	if layout.instructions then
-		form:tag("instructions"):text(layout.instructions):up();
-	end
-	for n, field in ipairs(layout) do
-		local field_type = field.type or "text-single";
-		-- Add field tag
-		form:tag("field", { type = field_type, var = field.name, label = field.label });
-
-		local value = (data and data[field.name]) or field.value;
-		
-		if value then
-			-- Add value, depending on type
-			if field_type == "hidden" then
-				if type(value) == "table" then
-					-- Assume an XML snippet
-					form:tag("value")
-						:add_child(value)
-						:up();
-				else
-					form:tag("value"):text(tostring(value)):up();
-				end
-			elseif field_type == "boolean" then
-				form:tag("value"):text((value and "1") or "0"):up();
-			elseif field_type == "fixed" then
-				
-			elseif field_type == "jid-multi" then
-				for _, jid in ipairs(value) do
-					form:tag("value"):text(jid):up();
-				end
-			elseif field_type == "jid-single" then
-				form:tag("value"):text(value):up();
-			elseif field_type == "text-single" or field_type == "text-private" then
-				form:tag("value"):text(value):up();
-			elseif field_type == "text-multi" then
-				-- Split into multiple <value> tags, one for each line
-				for line in value:gmatch("([^\r\n]+)\r?\n*") do
-					form:tag("value"):text(line):up();
-				end
-			elseif field_type == "list-single" then
-				local has_default = false;
-				if type(value) == "string" then
-					form:tag("value"):text(value):up();
-				else
-					for _, val in ipairs(value) do
-						if type(val) == "table" then
-							form:tag("option", { label = val.label }):tag("value"):text(val.value):up():up();
-							if val.default and (not has_default) then
-								form:tag("value"):text(val.value):up();
-								has_default = true;
-							end
-						else
-							form:tag("option", { label= val }):tag("value"):text(tostring(val)):up():up();
-						end
-					end
-				end
-			elseif field_type == "list-multi" then
-				for _, val in ipairs(value) do
-					if type(val) == "table" then
-						form:tag("option", { label = val.label }):tag("value"):text(val.value):up():up();
-						if val.default then
-							form:tag("value"):text(val.value):up();
-						end
-					else
-						form:tag("option", { label= val }):tag("value"):text(tostring(val)):up():up();
-					end
-				end
-			end
-		end
-		
-		if field.required then
-			form:tag("required"):up();
-		end
-		
-		-- Jump back up to list of fields
-		form:up();
-	end
-	return form;
-end
-
-local field_readers = {};
-
-function form_t.data(layout, stanza)
-	local data = {};
-	
-	for field_tag in stanza:childtags() do
-		local field_type;
-		for n, field in ipairs(layout) do
-			if field.name == field_tag.attr.var then
-				field_type = field.type;
-				break;
-			end
-		end
-		
-		local reader = field_readers[field_type];
-		if reader then
-			data[field_tag.attr.var] = reader(field_tag);
-		end
-		
-	end
-	return data;
-end
-
-field_readers["text-single"] = 
-	function (field_tag)
-		local value = field_tag:child_with_name("value");
-		if value then
-			return value[1];
-		end
-	end
-
-field_readers["text-private"] = 
-	field_readers["text-single"];
-
-field_readers["jid-single"] =
-	field_readers["text-single"];
-
-field_readers["jid-multi"] = 
-	function (field_tag)
-		local result = {};
-		for value_tag in field_tag:childtags() do
-			if value_tag.name == "value" then
-				result[#result+1] = value_tag[1];
-			end
-		end
-		return result;
-	end
-
-field_readers["text-multi"] = 
-	function (field_tag)
-		local result = {};
-		for value_tag in field_tag:childtags() do
-			if value_tag.name == "value" then
-				result[#result+1] = value_tag[1];
-			end
-		end
-		return t_concat(result, "\n");
-	end
-
-field_readers["list-single"] =
-	field_readers["text-single"];
-
-field_readers["list-multi"] =
-	function (field_tag)
-		local result = {};
-		for value_tag in field_tag:childtags() do
-			if value_tag.name == "value" then
-				result[#result+1] = value_tag[1];
-			end
-		end
-		return result;
-	end
-
-field_readers["boolean"] = 
-	function (field_tag)
-		local value = field_tag:child_with_name("value");
-		if value then
-			if value[1] == "1" or value[1] == "true" then
-				return true;
-			else
-				return false;
-			end
-		end		
-	end
-
-field_readers["hidden"] = 
-	function (field_tag)
-		local value = field_tag:child_with_name("value");
-		if value then
-			return value[1];
-		end
-	end
-	
-return _M;
-
-
---[=[
-
-Layout:
-{
-
-	title = "MUC Configuration",
-	instructions = [[Use this form to configure options for this MUC room.]],
-
-	{ name = "FORM_TYPE", type = "hidden", required = true };
-	{ name = "field-name", type = "field-type", required = false };
-}
-
-
---]=]
- end)
-package.preload['util.serialization'] = (function (...)
--- 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 string_rep = string.rep;
-local type = type;
-local tostring = tostring;
-local t_insert = table.insert;
-local t_concat = table.concat;
-local error = error;
-local pairs = pairs;
-local next = next;
-
-local loadstring = loadstring;
-local setfenv = setfenv;
-local pcall = pcall;
-
-local debug_traceback = debug.traceback;
-local log = require "util.logger".init("serialization");
-module "serialization"
-
-local indent = function(i)
-	return string_rep("\t", i);
-end
-local function basicSerialize (o)
-	if type(o) == "number" or type(o) == "boolean" then
-		-- no need to check for NaN, as that's not a valid table index
-		if o == 1/0 then return "(1/0)";
-		elseif o == -1/0 then return "(-1/0)";
-		else return tostring(o); end
-	else -- assume it is a string -- FIXME make sure it's a string. throw an error otherwise.
-		return (("%q"):format(tostring(o)):gsub("\\\n", "\\n"));
-	end
-end
-local function _simplesave(o, ind, t, func)
-	if type(o) == "number" then
-		if o ~= o then func(t, "(0/0)");
-		elseif o == 1/0 then func(t, "(1/0)");
-		elseif o == -1/0 then func(t, "(-1/0)");
-		else func(t, tostring(o)); end
-	elseif type(o) == "string" then
-		func(t, (("%q"):format(o):gsub("\\\n", "\\n")));
-	elseif type(o) == "table" then
-		if next(o) ~= nil then
-			func(t, "{\n");
-			for k,v in pairs(o) do
-				func(t, indent(ind));
-				func(t, "[");
-				func(t, basicSerialize(k));
-				func(t, "] = ");
-				if ind == 0 then
-					_simplesave(v, 0, t, func);
-				else
-					_simplesave(v, ind+1, t, func);
-				end
-				func(t, ";\n");
-			end
-			func(t, indent(ind-1));
-			func(t, "}");
-		else
-			func(t, "{}");
-		end
-	elseif type(o) == "boolean" then
-		func(t, (o and "true" or "false"));
-	else
-		log("error", "cannot serialize a %s: %s", type(o), debug_traceback())
-		func(t, "nil");
-	end
-end
-
-function append(t, o)
-	_simplesave(o, 1, t, t.write or t_insert);
-	return t;
-end
-
-function serialize(o)
-	return t_concat(append({}, o));
-end
-
-function deserialize(str)
-	if type(str) ~= "string" then return nil; end
-	str = "return "..str;
-	local f, err = loadstring(str, "@data");
-	if not f then return nil, err; end
-	setfenv(f, {});
-	local success, ret = pcall(f);
-	if not success then return nil, ret; end
-	return ret;
-end
-
-return _M;
- end)
-package.preload['verse.plugins.presence'] = (function (...)
-function verse.plugins.presence(stream)
-	stream.last_presence = nil;
-
-	stream:hook("presence-out", function (presence)
-		if not presence.attr.to then
-			stream.last_presence = presence; -- Cache non-directed presence
-		end
-	end, 1);
-
-	function stream:resend_presence()
-		if last_presence then
-			stream:send(last_presence);
-		end
-	end
-
-	function stream:set_status(opts)
-		local p = verse.presence();
-		if type(opts) == "table" then
-			if opts.show then
-				p:tag("show"):text(opts.show):up();
-			end
-			if opts.prio then
-				p:tag("priority"):text(tostring(opts.prio)):up();
-			end
-			if opts.msg then
-				p:tag("status"):text(opts.msg):up();
-			end
-		end
-		-- TODO maybe use opts as prio if it's a int,
-		-- or as show or status if it's a string?
-
-		stream:send(p);
-	end
-end
- end)
-package.preload['verse.plugins.groupchat'] = (function (...)
-local events = require "events";
-
-local room_mt = {};
-room_mt.__index = room_mt;
-
-local xmlns_delay = "urn:xmpp:delay";
-local xmlns_muc = "http://jabber.org/protocol/muc";
-
-function verse.plugins.groupchat(stream)
-	stream:add_plugin("presence")
-	stream.rooms = {};
-	
-	stream:hook("stanza", function (stanza)
-		local room_jid = jid.bare(stanza.attr.from);
-		if not room_jid then return end
-		local room = stream.rooms[room_jid]
-		if not room and stanza.attr.to and room_jid then
-			room = stream.rooms[stanza.attr.to.." "..room_jid]
-		end
-		if room and room.opts.source and stanza.attr.to ~= room.opts.source then return end
-		if room then
-			local nick = select(3, jid.split(stanza.attr.from));
-			local body = stanza:get_child("body");
-			local delay = stanza:get_child("delay", xmlns_delay);
-			local event = {
-				room_jid = room_jid;
-				room = room;
-				sender = room.occupants[nick];
-				nick = nick;
-				body = (body and body:get_text()) or nil;
-				stanza = stanza;
-				delay = (delay and delay.attr.stamp);
-			};
-			local ret = room:event(stanza.name, event);
-			return ret or (stanza.name == "message") or nil;
-		end
-	end, 500);
-	
-	function stream:join_room(jid, nick, opts)
-		if not nick then
-			return false, "no nickname supplied"
-		end
-		opts = opts or {};
-		local room = setmetatable({
-			stream = stream, jid = jid, nick = nick,
-			subject = nil,
-			occupants = {},
-			opts = opts,
-			events = events.new()
-		}, room_mt);
-		if opts.source then
-			self.rooms[opts.source.." "..jid] = room;
-		else
-			self.rooms[jid] = room;
-		end
-		local occupants = room.occupants;
-		room:hook("presence", function (presence)
-			local nick = presence.nick or nick;
-			if not occupants[nick] and presence.stanza.attr.type ~= "unavailable" then
-				occupants[nick] = {
-					nick = nick;
-					jid = presence.stanza.attr.from;
-					presence = presence.stanza;
-				};
-				local x = presence.stanza:get_child("x", xmlns_muc .. "#user");
-				if x then
-					local x_item = x:get_child("item");
-					if x_item and x_item.attr then
-						occupants[nick].real_jid    = x_item.attr.jid;
-						occupants[nick].affiliation = x_item.attr.affiliation;
-						occupants[nick].role        = x_item.attr.role;
-					end
-					--TODO Check for status 100?
-				end
-				if nick == room.nick then
-					room.stream:event("groupchat/joined", room);
-				else
-					room:event("occupant-joined", occupants[nick]);
-				end
-			elseif occupants[nick] and presence.stanza.attr.type == "unavailable" then
-				if nick == room.nick then
-					room.stream:event("groupchat/left", room);
-					if room.opts.source then
-						self.rooms[room.opts.source.." "..jid] = nil;
-					else
-						self.rooms[jid] = nil;
-					end
-				else
-					occupants[nick].presence = presence.stanza;
-					room:event("occupant-left", occupants[nick]);
-					occupants[nick] = nil;
-				end
-			end
-		end);
-		room:hook("message", function(msg)
-			local subject = msg.stanza:get_child_text("subject");
-			if not subject then return end
-			subject = #subject > 0 and subject or nil;
-			if subject ~= room.subject then
-				local old_subject = room.subject;
-				room.subject = subject;
-				return self:event("subject-changed", { from = old_subject, to = subject, by = msg.sender });
-			end
-		end, 2000);
-		local join_st = verse.presence():tag("x",{xmlns = xmlns_muc}):reset();
-		self:event("pre-groupchat/joining", join_st);
-		room:send(join_st)
-		self:event("groupchat/joining", room);
-		return room;
-	end
-
-	stream:hook("presence-out", function(presence)
-		if not presence.attr.to then
-			for _, room in pairs(stream.rooms) do
-				room:send(presence);
-			end
-			presence.attr.to = nil;
-		end
-	end);
-end
-
-function room_mt:send(stanza)
-	if stanza.name == "message" and not stanza.attr.type then
-		stanza.attr.type = "groupchat";
-	end
-	if stanza.name == "presence" then
-		stanza.attr.to = self.jid .."/"..self.nick;
-	end
-	if stanza.attr.type == "groupchat" or not stanza.attr.to then
-		stanza.attr.to = self.jid;
-	end
-	if self.opts.source then
-		stanza.attr.from = self.opts.source
-	end
-	self.stream:send(stanza);
-end
-
-function room_mt:send_message(text)
-	self:send(verse.message():tag("body"):text(text));
-end
-
-function room_mt:set_subject(text)
-	self:send(verse.message():tag("subject"):text(text));
-end
-
-function room_mt:leave(message)
-	self.stream:event("groupchat/leaving", self);
-	self:send(verse.presence({type="unavailable"}));
-end
-
-function room_mt:admin_set(nick, what, value, reason)
-	self:send(verse.iq({type="set"})
-		:query(xmlns_muc .. "#admin")
-			:tag("item", {nick = nick, [what] = value})
-				:tag("reason"):text(reason or ""));
-end
-
-function room_mt:set_role(nick, role, reason)
-	self:admin_set(nick, "role", role, reason);
-end
-
-function room_mt:set_affiliation(nick, affiliation, reason)
-	self:admin_set(nick, "affiliation", affiliation, reason);
-end
-
-function room_mt:kick(nick, reason)
-	self:set_role(nick, "none", reason);
-end
-
-function room_mt:ban(nick, reason)
-	self:set_affiliation(nick, "outcast", reason);
-end
-
-function room_mt:event(name, arg)
-	self.stream:debug("Firing room event: %s", name);
-	return self.events.fire_event(name, arg);
-end
-
-function room_mt:hook(name, callback, priority)
-	return self.events.add_handler(name, callback, priority);
-end
- end)
-package.preload['net.httpclient_listener'] = (function (...)
--- 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 log = require "util.logger".init("httpclient_listener");
-
-local connlisteners_register = require "net.connlisteners".register;
-
-local requests = {}; -- Open requests
-local buffers = {}; -- Buffers of partial lines
-
-local httpclient = { default_port = 80, default_mode = "*a" };
-
-function httpclient.onincoming(conn, data)
-	local request = requests[conn];
-
-	if not request then
-		log("warn", "Received response from connection %s with no request attached!", tostring(conn));
-		return;
-	end
-
-	if data and request.reader then
-		request:reader(data);
-	end
-end
-
-function httpclient.ondisconnect(conn, err)
-	local request = requests[conn];
-	if request and err ~= "closed" then
-		request:reader(nil);
-	end
-	requests[conn] = nil;
-end
-
-function httpclient.register_request(conn, req)
-	log("debug", "Attaching request %s to connection %s", tostring(req.id or req), tostring(conn));
-	requests[conn] = req;
-end
-
-connlisteners_register("httpclient", httpclient);
- end)
-package.preload['net.connlisteners'] = (function (...)
--- 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 listeners_dir = (CFG_SOURCEDIR or ".").."/net/";
-local server = require "net.server";
-local log = require "util.logger".init("connlisteners");
-local tostring = tostring;
-local type = type
-local ipairs = ipairs
-
-local dofile, xpcall, error =
-      dofile, xpcall, error
-
-local debug_traceback = debug.traceback;
-
-module "connlisteners"
-
-local listeners = {};
-
-function register(name, listener)
-	if listeners[name] and listeners[name] ~= listener then
-		log("debug", "Listener %s is already registered, not registering any more", name);
-		return false;
-	end
-	listeners[name] = listener;
-	log("debug", "Registered connection listener %s", name);
-	return true;
-end
-
-function deregister(name)
-	listeners[name] = nil;
-end
-
-function get(name)
-	local h = listeners[name];
-	if not h then
-		local ok, ret = xpcall(function() dofile(listeners_dir..name:gsub("[^%w%-]", "_").."_listener.lua") end, debug_traceback);
-		if not ok then
-			log("error", "Error while loading listener '%s': %s", tostring(name), tostring(ret));
-			return nil, ret;
-		end
-		h = listeners[name];
-	end
-	return h;
-end
-
-function start(name, udata)
-	local h, err = get(name);
-	if not h then
-		error("No such connection module: "..name.. (err and (" ("..err..")") or ""), 0);
-	end
-	
-	local interfaces = (udata and udata.interface) or h.default_interface or "*";
-	if type(interfaces) == "string" then interfaces = {interfaces}; end
-	local port = (udata and udata.port) or h.default_port or error("Can't start listener "..name.." because no port was specified, and it has no default port", 0);
-	local mode = (udata and udata.mode) or h.default_mode or 1;
-	local ssl = (udata and udata.ssl) or nil;
-	local autossl = udata and udata.type == "ssl";
-	
-	if autossl and not ssl then
-		return nil, "no ssl context";
-	end
-
-	ok, err = true, {};
-	for _, interface in ipairs(interfaces) do
-		local handler
-		handler, err[interface] = server.addserver(interface, port, h, mode, autossl and ssl or nil);
-		ok = ok and handler;
-	end
-
-	return ok, err;
-end
-
-return _M;
- end)
-package.preload['util.httpstream'] = (function (...)
-
-local coroutine = coroutine;
-local tonumber = tonumber;
-
-local deadroutine = coroutine.create(function() end);
-coroutine.resume(deadroutine);
-
-module("httpstream")
-
-local function parser(success_cb, parser_type, options_cb)
-	local data = coroutine.yield();
-	local function readline()
-		local pos = data:find("\r\n", nil, true);
-		while not pos do
-			data = data..coroutine.yield();
-			pos = data:find("\r\n", nil, true);
-		end
-		local r = data:sub(1, pos-1);
-		data = data:sub(pos+2);
-		return r;
-	end
-	local function readlength(n)
-		while #data < n do
-			data = data..coroutine.yield();
-		end
-		local r = data:sub(1, n);
-		data = data:sub(n + 1);
-		return r;
-	end
-	local function readheaders()
-		local headers = {}; -- read headers
-		while true do
-			local line = readline();
-			if line == "" then break; end -- headers done
-			local key, val = line:match("^([^%s:]+): *(.*)$");
-			if not key then coroutine.yield("invalid-header-line"); end -- TODO handle multi-line and invalid headers
-			key = key:lower();
-			headers[key] = headers[key] and headers[key]..","..val or val;
-		end
-		return headers;
-	end
-	
-	if not parser_type or parser_type == "server" then
-		while true do
-			-- read status line
-			local status_line = readline();
-			local method, path, httpversion = status_line:match("^(%S+)%s+(%S+)%s+HTTP/(%S+)$");
-			if not method then coroutine.yield("invalid-status-line"); end
-			path = path:gsub("^//+", "/"); -- TODO parse url more
-			local headers = readheaders();
-			
-			-- read body
-			local len = tonumber(headers["content-length"]);
-			len = len or 0; -- TODO check for invalid len
-			local body = readlength(len);
-			
-			success_cb({
-				method = method;
-				path = path;
-				httpversion = httpversion;
-				headers = headers;
-				body = body;
-			});
-		end
-	elseif parser_type == "client" then
-		while true do
-			-- read status line
-			local status_line = readline();
-			local httpversion, status_code, reason_phrase = status_line:match("^HTTP/(%S+)%s+(%d%d%d)%s+(.*)$");
-			status_code = tonumber(status_code);
-			if not status_code then coroutine.yield("invalid-status-line"); end
-			local headers = readheaders();
-			
-			-- read body
-			local have_body = not
-				 ( (options_cb and options_cb().method == "HEAD")
-				or (status_code == 204 or status_code == 304 or status_code == 301)
-				or (status_code >= 100 and status_code < 200) );
-			
-			local body;
-			if have_body then
-				local len = tonumber(headers["content-length"]);
-				if headers["transfer-encoding"] == "chunked" then
-					body = "";
-					while true do
-						local chunk_size = readline():match("^%x+");
-						if not chunk_size then coroutine.yield("invalid-chunk-size"); end
-						chunk_size = tonumber(chunk_size, 16)
-						if chunk_size == 0 then break; end
-						body = body..readlength(chunk_size);
-						if readline() ~= "" then coroutine.yield("invalid-chunk-ending"); end
-					end
-					local trailers = readheaders();
-				elseif len then -- TODO check for invalid len
-					body = readlength(len);
-				else -- read to end
-					repeat
-						local newdata = coroutine.yield();
-						data = data..newdata;
-					until newdata == "";
-					body, data = data, "";
-				end
-			end
-			
-			success_cb({
-				code = status_code;
-				httpversion = httpversion;
-				headers = headers;
-				body = body;
-				-- COMPAT the properties below are deprecated
-				responseversion = httpversion;
-				responseheaders = headers;
-			});
-		end
-	else coroutine.yield("unknown-parser-type"); end
-end
-
-function new(success_cb, error_cb, parser_type, options_cb)
-	local co = coroutine.create(parser);
-	coroutine.resume(co, success_cb, parser_type, options_cb)
-	return {
-		feed = function(self, data)
-			if not data then
-				if parser_type == "client" then coroutine.resume(co, ""); end
-				co = deadroutine;
-				return error_cb();
-			end
-			local success, result = coroutine.resume(co, data);
-			if result then
-				co = deadroutine;
-				return error_cb(result);
-			end
-		end;
-	};
-end
-
-return _M;
- end)
-package.preload['net.http'] = (function (...)
--- 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 socket = require "socket"
-local mime = require "mime"
-local url = require "socket.url"
-local httpstream_new = require "util.httpstream".new;
-
-local server = require "net.server"
-
-local connlisteners_get = require "net.connlisteners".get;
-local listener = connlisteners_get("httpclient") or error("No httpclient listener!");
-
-local t_insert, t_concat = table.insert, table.concat;
-local pairs, ipairs = pairs, ipairs;
-local tonumber, tostring, xpcall, select, debug_traceback, char, format =
-      tonumber, tostring, xpcall, select, debug.traceback, string.char, string.format;
-
-local log = require "util.logger".init("http");
-
-module "http"
-
-function urlencode(s) return s and (s:gsub("%W", function (c) return format("%%%02x", c:byte()); end)); end
-function urldecode(s) return s and (s:gsub("%%(%x%x)", function (c) return char(tonumber(c,16)); end)); end
-
-local function _formencodepart(s)
-	return s and (s:gsub("%W", function (c)
-		if c ~= " " then
-			return format("%%%02x", c:byte());
-		else
-			return "+";
-		end
-	end));
-end
-function formencode(form)
-	local result = {};
-	for _, field in ipairs(form) do
-		t_insert(result, _formencodepart(field.name).."=".._formencodepart(field.value));
-	end
-	return t_concat(result, "&");
-end
-
-local function request_reader(request, data, startpos)
-	if not request.parser then
-		local function success_cb(r)
-			if request.callback then
-				for k,v in pairs(r) do request[k] = v; end
-				request.callback(r.body, r.code, request);
-				request.callback = nil;
-			end
-			destroy_request(request);
-		end
-		local function error_cb(r)
-			if request.callback then
-				request.callback(r or "connection-closed", 0, request);
-				request.callback = nil;
-			end
-			destroy_request(request);
-		end
-		local function options_cb()
-			return request;
-		end
-		request.parser = httpstream_new(success_cb, error_cb, "client", options_cb);
-	end
-	request.parser:feed(data);
-end
-
-local function handleerr(err) log("error", "Traceback[http]: %s: %s", tostring(err), debug_traceback()); end
-function request(u, ex, callback)
-	local req = url.parse(u);
-	
-	if not (req and req.host) then
-		callback(nil, 0, req);
-		return nil, "invalid-url";
-	end
-	
-	if not req.path then
-		req.path = "/";
-	end
-	
-	local custom_headers, body;
-	local default_headers = { ["Host"] = req.host, ["User-Agent"] = "Prosody XMPP Server" }
-	
-	
-	if req.userinfo then
-		default_headers["Authorization"] = "Basic "..mime.b64(req.userinfo);
-	end
-	
-	if ex then
-		custom_headers = ex.headers;
-		req.onlystatus = ex.onlystatus;
-		body = ex.body;
-		if body then
-			req.method = "POST ";
-			default_headers["Content-Length"] = tostring(#body);
-			default_headers["Content-Type"] = "application/x-www-form-urlencoded";
-		end
-		if ex.method then req.method = ex.method; end
-	end
-	
-	req.handler, req.conn = server.wrapclient(socket.tcp(), req.host, req.port or 80, listener, "*a");
-	req.write = function (...) return req.handler:write(...); end
-	req.conn:settimeout(0);
-	local ok, err = req.conn:connect(req.host, req.port or 80);
-	if not ok and err ~= "timeout" then
-		callback(nil, 0, req);
-		return nil, err;
-	end
-	
-	local request_line = { req.method or "GET", " ", req.path, " HTTP/1.1\r\n" };
-	
-	if req.query then
-		t_insert(request_line, 4, "?");
-		t_insert(request_line, 5, req.query);
-	end
-	
-	req.write(t_concat(request_line));
-	local t = { [2] = ": ", [4] = "\r\n" };
-	if custom_headers then
-		for k, v in pairs(custom_headers) do
-			t[1], t[3] = k, v;
-			req.write(t_concat(t));
-			default_headers[k] = nil;
-		end
-	end
-	
-	for k, v in pairs(default_headers) do
-		t[1], t[3] = k, v;
-		req.write(t_concat(t));
-		default_headers[k] = nil;
-	end
-	req.write("\r\n");
-	
-	if body then
-		req.write(body);
-	end
-	
-	req.callback = function (content, code, request) log("debug", "Calling callback, status %s", code or "---"); return select(2, xpcall(function () return callback(content, code, request) end, handleerr)); end
-	req.reader = request_reader;
-	req.state = "status";
-	
-	listener.register_request(req.handler, req);
-
-	return req;
-end
-
-function destroy_request(request)
-	if request.conn then
-		request.conn = nil;
-		request.handler:close()
-		listener.ondisconnect(request.handler, "closed");
-	end
-end
-
-_M.urlencode = urlencode;
-
-return _M;
- end)
-package.preload['verse.bosh'] = (function (...)
-
-local new_xmpp_stream = require "util.xmppstream".new;
-local st = require "util.stanza";
-require "net.httpclient_listener"; -- Required for net.http to work
-local http = require "net.http";
-
-local stream_mt = setmetatable({}, { __index = verse.stream_mt });
-stream_mt.__index = stream_mt;
-
-local xmlns_stream = "http://etherx.jabber.org/streams";
-local xmlns_bosh = "http://jabber.org/protocol/httpbind";
-
-local reconnect_timeout = 5;
-
-function verse.new_bosh(logger, url)
-	local stream = {
-		bosh_conn_pool = {};
-		bosh_waiting_requests = {};
-		bosh_rid = math.random(1,999999);
-		bosh_outgoing_buffer = {};
-		bosh_url = url;
-		conn = {};
-	};
-	function stream:reopen()
-		self.bosh_need_restart = true;
-		self:flush();
-	end
-	local conn = verse.new(logger, stream);
-	return setmetatable(conn, stream_mt);
-end
-
-function stream_mt:connect()
-	self:_send_session_request();
-end
-
-function stream_mt:send(data)
-	self:debug("Putting into BOSH send buffer: %s", tostring(data));
-	self.bosh_outgoing_buffer[#self.bosh_outgoing_buffer+1] = st.clone(data);
-	self:flush(); --TODO: Optimize by doing this on next tick (give a chance for data to buffer)
-end
-
-function stream_mt:flush()
-	if self.connected
-	and #self.bosh_waiting_requests < self.bosh_max_requests
-	and (#self.bosh_waiting_requests == 0
-		or #self.bosh_outgoing_buffer > 0
-		or self.bosh_need_restart) then
-		self:debug("Flushing...");
-		local payload = self:_make_body();
-		local buffer = self.bosh_outgoing_buffer;
-		for i, stanza in ipairs(buffer) do
-			payload:add_child(stanza);
-			buffer[i] = nil;
-		end
-		self:_make_request(payload);
-	else
-		self:debug("Decided not to flush.");
-	end
-end
-
-function stream_mt:_make_request(payload)
-	local request, err = http.request(self.bosh_url, { body = tostring(payload) }, function (response, code, request)
-		if code ~= 0 then
-			self.inactive_since = nil;
-			return self:_handle_response(response, code, request);
-		end
-		
-		-- Connection issues, we need to retry this request
-		local time = os.time();
-		if not self.inactive_since then
-			self.inactive_since = time; -- So we know when it is time to give up
-		elseif time - self.inactive_since > self.bosh_max_inactivity then
-			return self:_disconnected();
-		else
-			self:debug("%d seconds left to reconnect, retrying in %d seconds...", 
-				self.bosh_max_inactivity - (time - self.inactive_since), reconnect_timeout);
-		end
-		
-		-- Set up reconnect timer
-		timer.add_task(reconnect_timeout, function ()
-			self:debug("Retrying request...");
-			-- Remove old request
-			for i, waiting_request in ipairs(self.bosh_waiting_requests) do
-				if waiting_request == request then
-					table.remove(self.bosh_waiting_requests, i);
-					break;
-				end
-			end
-			self:_make_request(payload);
-		end);
-	end);
-	if request then
-		table.insert(self.bosh_waiting_requests, request);
-	else
-		self:warn("Request failed instantly: %s", err);
-	end
-end
-
-function stream_mt:_disconnected()
-	self.connected = nil;
-	self:event("disconnected");
-end
-
-function stream_mt:_send_session_request()
-	local body = self:_make_body();
-	
-	-- XEP-0124
-	body.attr.hold = "1";
-	body.attr.wait = "60";
-	body.attr["xml:lang"] = "en";
-	body.attr.ver = "1.6";
-
-	-- XEP-0206
-	body.attr.from = self.jid;
-	body.attr.to = self.host;
-	body.attr.secure = 'true';
-	
-	http.request(self.bosh_url, { body = tostring(body) }, function (response, code)
-		if code == 0 then
-			-- Failed to connect
-			return self:_disconnected();
-		end
-		-- Handle session creation response
-		local payload = self:_parse_response(response)
-		if not payload then
-			self:warn("Invalid session creation response");
-			self:_disconnected();
-			return;
-		end
-		self.bosh_sid = payload.attr.sid; -- Session id
-		self.bosh_wait = tonumber(payload.attr.wait); -- How long the server may hold connections for
-		self.bosh_hold = tonumber(payload.attr.hold); -- How many connections the server may hold
-		self.bosh_max_inactivity = tonumber(payload.attr.inactivity); -- Max amount of time with no connections
-		self.bosh_max_requests = tonumber(payload.attr.requests) or self.bosh_hold; -- Max simultaneous requests we can make
-		self.connected = true;
-		self:event("connected");
-		self:_handle_response_payload(payload);
-	end);
-end
-
-function stream_mt:_handle_response(response, code, request)
-	if self.bosh_waiting_requests[1] ~= request then
-		self:warn("Server replied to request that wasn't the oldest");
-		for i, waiting_request in ipairs(self.bosh_waiting_requests) do
-			if waiting_request == request then
-				self.bosh_waiting_requests[i] = nil;
-				break;
-			end
-		end
-	else
-		table.remove(self.bosh_waiting_requests, 1);
-	end
-	local payload = self:_parse_response(response);
-	if payload then
-		self:_handle_response_payload(payload);
-	end
-	self:flush();
-end
-
-function stream_mt:_handle_response_payload(payload)
-	for stanza in payload:childtags() do
-		if stanza.attr.xmlns == xmlns_stream then
-			self:event("stream-"..stanza.name, stanza);
-		elseif stanza.attr.xmlns then
-			self:event("stream/"..stanza.attr.xmlns, stanza);
-		else
-			self:event("stanza", stanza);
-		end
-	end
-	if payload.attr.type == "terminate" then
-		self:_disconnected({reason = payload.attr.condition});
-	end
-end
-
-local stream_callbacks = {
-	stream_ns = "http://jabber.org/protocol/httpbind", stream_tag = "body",
-	default_ns = "jabber:client",
-	streamopened = function (session, attr) session.notopen = nil; session.payload = verse.stanza("body", attr); return true; end;
-	handlestanza = function (session, stanza) session.payload:add_child(stanza); end;
-};
-function stream_mt:_parse_response(response)
-	self:debug("Parsing response: %s", response);
-	if response == nil then
-		self:debug("%s", debug.traceback());
-		self:_disconnected();
-		return;
-	end
-	local session = { notopen = true, log = self.log };
-	local stream = new_xmpp_stream(session, stream_callbacks);
-	stream:feed(response);
-	return session.payload;
-end
-
-function stream_mt:_make_body()
-	self.bosh_rid = self.bosh_rid + 1;
-	local body = verse.stanza("body", {
-		xmlns = xmlns_bosh;
-		content = "text/xml; charset=utf-8";
-		sid = self.bosh_sid;
-		rid = self.bosh_rid;
-	});
-	if self.bosh_need_restart then
-		self.bosh_need_restart = nil;
-		body.attr.restart = 'true';
-	end
-	return body;
-end
- end)
-package.preload['bit'] = (function (...)
--- 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 type = type;
-local tonumber = tonumber;
-local setmetatable = setmetatable;
-local error = error;
-local tostring = tostring;
-local print = print;
-
-local xor_map = {[0]=0;[1]=1;[2]=2;[3]=3;[4]=4;[5]=5;[6]=6;[7]=7;[8]=8;[9]=9;[10]=10;[11]=11;[12]=12;[13]=13;[14]=14;[15]=15;[16]=1;[17]=0;[18]=3;[19]=2;[20]=5;[21]=4;[22]=7;[23]=6;[24]=9;[25]=8;[26]=11;[27]=10;[28]=13;[29]=12;[30]=15;[31]=14;[32]=2;[33]=3;[34]=0;[35]=1;[36]=6;[37]=7;[38]=4;[39]=5;[40]=10;[41]=11;[42]=8;[43]=9;[44]=14;[45]=15;[46]=12;[47]=13;[48]=3;[49]=2;[50]=1;[51]=0;[52]=7;[53]=6;[54]=5;[55]=4;[56]=11;[57]=10;[58]=9;[59]=8;[60]=15;[61]=14;[62]=13;[63]=12;[64]=4;[65]=5;[66]=6;[67]=7;[68]=0;[69]=1;[70]=2;[71]=3;[72]=12;[73]=13;[74]=14;[75]=15;[76]=8;[77]=9;[78]=10;[79]=11;[80]=5;[81]=4;[82]=7;[83]=6;[84]=1;[85]=0;[86]=3;[87]=2;[88]=13;[89]=12;[90]=15;[91]=14;[92]=9;[93]=8;[94]=11;[95]=10;[96]=6;[97]=7;[98]=4;[99]=5;[100]=2;[101]=3;[102]=0;[103]=1;[104]=14;[105]=15;[106]=12;[107]=13;[108]=10;[109]=11;[110]=8;[111]=9;[112]=7;[113]=6;[114]=5;[115]=4;[116]=3;[117]=2;[118]=1;[119]=0;[120]=15;[121]=14;[122]=13;[123]=12;[124]=11;[125]=10;[126]=9;[127]=8;[128]=8;[129]=9;[130]=10;[131]=11;[132]=12;[133]=13;[134]=14;[135]=15;[136]=0;[137]=1;[138]=2;[139]=3;[140]=4;[141]=5;[142]=6;[143]=7;[144]=9;[145]=8;[146]=11;[147]=10;[148]=13;[149]=12;[150]=15;[151]=14;[152]=1;[153]=0;[154]=3;[155]=2;[156]=5;[157]=4;[158]=7;[159]=6;[160]=10;[161]=11;[162]=8;[163]=9;[164]=14;[165]=15;[166]=12;[167]=13;[168]=2;[169]=3;[170]=0;[171]=1;[172]=6;[173]=7;[174]=4;[175]=5;[176]=11;[177]=10;[178]=9;[179]=8;[180]=15;[181]=14;[182]=13;[183]=12;[184]=3;[185]=2;[186]=1;[187]=0;[188]=7;[189]=6;[190]=5;[191]=4;[192]=12;[193]=13;[194]=14;[195]=15;[196]=8;[197]=9;[198]=10;[199]=11;[200]=4;[201]=5;[202]=6;[203]=7;[204]=0;[205]=1;[206]=2;[207]=3;[208]=13;[209]=12;[210]=15;[211]=14;[212]=9;[213]=8;[214]=11;[215]=10;[216]=5;[217]=4;[218]=7;[219]=6;[220]=1;[221]=0;[222]=3;[223]=2;[224]=14;[225]=15;[226]=12;[227]=13;[228]=10;[229]=11;[230]=8;[231]=9;[232]=6;[233]=7;[234]=4;[235]=5;[236]=2;[237]=3;[238]=0;[239]=1;[240]=15;[241]=14;[242]=13;[243]=12;[244]=11;[245]=10;[246]=9;[247]=8;[248]=7;[249]=6;[250]=5;[251]=4;[252]=3;[253]=2;[254]=1;[255]=0;};
-local or_map = {[0]=0;[1]=1;[2]=2;[3]=3;[4]=4;[5]=5;[6]=6;[7]=7;[8]=8;[9]=9;[10]=10;[11]=11;[12]=12;[13]=13;[14]=14;[15]=15;[16]=1;[17]=1;[18]=3;[19]=3;[20]=5;[21]=5;[22]=7;[23]=7;[24]=9;[25]=9;[26]=11;[27]=11;[28]=13;[29]=13;[30]=15;[31]=15;[32]=2;[33]=3;[34]=2;[35]=3;[36]=6;[37]=7;[38]=6;[39]=7;[40]=10;[41]=11;[42]=10;[43]=11;[44]=14;[45]=15;[46]=14;[47]=15;[48]=3;[49]=3;[50]=3;[51]=3;[52]=7;[53]=7;[54]=7;[55]=7;[56]=11;[57]=11;[58]=11;[59]=11;[60]=15;[61]=15;[62]=15;[63]=15;[64]=4;[65]=5;[66]=6;[67]=7;[68]=4;[69]=5;[70]=6;[71]=7;[72]=12;[73]=13;[74]=14;[75]=15;[76]=12;[77]=13;[78]=14;[79]=15;[80]=5;[81]=5;[82]=7;[83]=7;[84]=5;[85]=5;[86]=7;[87]=7;[88]=13;[89]=13;[90]=15;[91]=15;[92]=13;[93]=13;[94]=15;[95]=15;[96]=6;[97]=7;[98]=6;[99]=7;[100]=6;[101]=7;[102]=6;[103]=7;[104]=14;[105]=15;[106]=14;[107]=15;[108]=14;[109]=15;[110]=14;[111]=15;[112]=7;[113]=7;[114]=7;[115]=7;[116]=7;[117]=7;[118]=7;[119]=7;[120]=15;[121]=15;[122]=15;[123]=15;[124]=15;[125]=15;[126]=15;[127]=15;[128]=8;[129]=9;[130]=10;[131]=11;[132]=12;[133]=13;[134]=14;[135]=15;[136]=8;[137]=9;[138]=10;[139]=11;[140]=12;[141]=13;[142]=14;[143]=15;[144]=9;[145]=9;[146]=11;[147]=11;[148]=13;[149]=13;[150]=15;[151]=15;[152]=9;[153]=9;[154]=11;[155]=11;[156]=13;[157]=13;[158]=15;[159]=15;[160]=10;[161]=11;[162]=10;[163]=11;[164]=14;[165]=15;[166]=14;[167]=15;[168]=10;[169]=11;[170]=10;[171]=11;[172]=14;[173]=15;[174]=14;[175]=15;[176]=11;[177]=11;[178]=11;[179]=11;[180]=15;[181]=15;[182]=15;[183]=15;[184]=11;[185]=11;[186]=11;[187]=11;[188]=15;[189]=15;[190]=15;[191]=15;[192]=12;[193]=13;[194]=14;[195]=15;[196]=12;[197]=13;[198]=14;[199]=15;[200]=12;[201]=13;[202]=14;[203]=15;[204]=12;[205]=13;[206]=14;[207]=15;[208]=13;[209]=13;[210]=15;[211]=15;[212]=13;[213]=13;[214]=15;[215]=15;[216]=13;[217]=13;[218]=15;[219]=15;[220]=13;[221]=13;[222]=15;[223]=15;[224]=14;[225]=15;[226]=14;[227]=15;[228]=14;[229]=15;[230]=14;[231]=15;[232]=14;[233]=15;[234]=14;[235]=15;[236]=14;[237]=15;[238]=14;[239]=15;[240]=15;[241]=15;[242]=15;[243]=15;[244]=15;[245]=15;[246]=15;[247]=15;[248]=15;[249]=15;[250]=15;[251]=15;[252]=15;[253]=15;[254]=15;[255]=15;};
-local and_map = {[0]=0;[1]=0;[2]=0;[3]=0;[4]=0;[5]=0;[6]=0;[7]=0;[8]=0;[9]=0;[10]=0;[11]=0;[12]=0;[13]=0;[14]=0;[15]=0;[16]=0;[17]=1;[18]=0;[19]=1;[20]=0;[21]=1;[22]=0;[23]=1;[24]=0;[25]=1;[26]=0;[27]=1;[28]=0;[29]=1;[30]=0;[31]=1;[32]=0;[33]=0;[34]=2;[35]=2;[36]=0;[37]=0;[38]=2;[39]=2;[40]=0;[41]=0;[42]=2;[43]=2;[44]=0;[45]=0;[46]=2;[47]=2;[48]=0;[49]=1;[50]=2;[51]=3;[52]=0;[53]=1;[54]=2;[55]=3;[56]=0;[57]=1;[58]=2;[59]=3;[60]=0;[61]=1;[62]=2;[63]=3;[64]=0;[65]=0;[66]=0;[67]=0;[68]=4;[69]=4;[70]=4;[71]=4;[72]=0;[73]=0;[74]=0;[75]=0;[76]=4;[77]=4;[78]=4;[79]=4;[80]=0;[81]=1;[82]=0;[83]=1;[84]=4;[85]=5;[86]=4;[87]=5;[88]=0;[89]=1;[90]=0;[91]=1;[92]=4;[93]=5;[94]=4;[95]=5;[96]=0;[97]=0;[98]=2;[99]=2;[100]=4;[101]=4;[102]=6;[103]=6;[104]=0;[105]=0;[106]=2;[107]=2;[108]=4;[109]=4;[110]=6;[111]=6;[112]=0;[113]=1;[114]=2;[115]=3;[116]=4;[117]=5;[118]=6;[119]=7;[120]=0;[121]=1;[122]=2;[123]=3;[124]=4;[125]=5;[126]=6;[127]=7;[128]=0;[129]=0;[130]=0;[131]=0;[132]=0;[133]=0;[134]=0;[135]=0;[136]=8;[137]=8;[138]=8;[139]=8;[140]=8;[141]=8;[142]=8;[143]=8;[144]=0;[145]=1;[146]=0;[147]=1;[148]=0;[149]=1;[150]=0;[151]=1;[152]=8;[153]=9;[154]=8;[155]=9;[156]=8;[157]=9;[158]=8;[159]=9;[160]=0;[161]=0;[162]=2;[163]=2;[164]=0;[165]=0;[166]=2;[167]=2;[168]=8;[169]=8;[170]=10;[171]=10;[172]=8;[173]=8;[174]=10;[175]=10;[176]=0;[177]=1;[178]=2;[179]=3;[180]=0;[181]=1;[182]=2;[183]=3;[184]=8;[185]=9;[186]=10;[187]=11;[188]=8;[189]=9;[190]=10;[191]=11;[192]=0;[193]=0;[194]=0;[195]=0;[196]=4;[197]=4;[198]=4;[199]=4;[200]=8;[201]=8;[202]=8;[203]=8;[204]=12;[205]=12;[206]=12;[207]=12;[208]=0;[209]=1;[210]=0;[211]=1;[212]=4;[213]=5;[214]=4;[215]=5;[216]=8;[217]=9;[218]=8;[219]=9;[220]=12;[221]=13;[222]=12;[223]=13;[224]=0;[225]=0;[226]=2;[227]=2;[228]=4;[229]=4;[230]=6;[231]=6;[232]=8;[233]=8;[234]=10;[235]=10;[236]=12;[237]=12;[238]=14;[239]=14;[240]=0;[241]=1;[242]=2;[243]=3;[244]=4;[245]=5;[246]=6;[247]=7;[248]=8;[249]=9;[250]=10;[251]=11;[252]=12;[253]=13;[254]=14;[255]=15;}
-
-local not_map = {[0]=15;[1]=14;[2]=13;[3]=12;[4]=11;[5]=10;[6]=9;[7]=8;[8]=7;[9]=6;[10]=5;[11]=4;[12]=3;[13]=2;[14]=1;[15]=0;};
-local rshift1_map = {[0]=0;[1]=0;[2]=1;[3]=1;[4]=2;[5]=2;[6]=3;[7]=3;[8]=4;[9]=4;[10]=5;[11]=5;[12]=6;[13]=6;[14]=7;[15]=7;};
-local rshift1carry_map = {[0]=0;[1]=8;[2]=0;[3]=8;[4]=0;[5]=8;[6]=0;[7]=8;[8]=0;[9]=8;[10]=0;[11]=8;[12]=0;[13]=8;[14]=0;[15]=8;};
-local lshift1_map = {[0]=0;[1]=2;[2]=4;[3]=6;[4]=8;[5]=10;[6]=12;[7]=14;[8]=0;[9]=2;[10]=4;[11]=6;[12]=8;[13]=10;[14]=12;[15]=14;};
-local lshift1carry_map = {[0]=0;[1]=0;[2]=0;[3]=0;[4]=0;[5]=0;[6]=0;[7]=0;[8]=1;[9]=1;[10]=1;[11]=1;[12]=1;[13]=1;[14]=1;[15]=1;};
-local arshift1carry_map = {[0]=0;[1]=0;[2]=0;[3]=0;[4]=0;[5]=0;[6]=0;[7]=0;[8]=8;[9]=8;[10]=8;[11]=8;[12]=8;[13]=8;[14]=8;[15]=8;};
-
-module "bit"
-
-local bit_mt = {__tostring = function(t) return ("%x%x%x%x%x%x%x%x"):format(t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8]); end};
-local function do_bop(a, b, op)
-	return setmetatable({
-		op[a[1]*16+b[1]];
-		op[a[2]*16+b[2]];
-		op[a[3]*16+b[3]];
-		op[a[4]*16+b[4]];
-		op[a[5]*16+b[5]];
-		op[a[6]*16+b[6]];
-		op[a[7]*16+b[7]];
-		op[a[8]*16+b[8]];
-	}, bit_mt);
-end
-local function do_uop(a, op)
-	return setmetatable({
-		op[a[1]];
-		op[a[2]];
-		op[a[3]];
-		op[a[4]];
-		op[a[5]];
-		op[a[6]];
-		op[a[7]];
-		op[a[8]];
-	}, bit_mt);
-end
-
-function bxor(a, b) return do_bop(a, b, xor_map); end
-function bor(a, b) return do_bop(a, b, or_map); end
-function band(a, b) return do_bop(a, b, and_map); end
-
-function bnot(a) return do_uop(a, not_map); end
-local function _rshift1(t)
-	local carry = 0;
-	for i=1,8 do
-		local t_i = rshift1_map[t[i]] + carry;
-		carry = rshift1carry_map[t[i]];
-		t[i] = t_i;
-	end
-end
-function rshift(a, i)
-	local t = {a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]};
-	for n = 1,i do _rshift1(t); end
-	return setmetatable(t, bit_mt);
-end
-local function _arshift1(t)
-	local carry = arshift1carry_map[t[1]];
-	for i=1,8 do
-		local t_i = rshift1_map[t[i]] + carry;
-		carry = rshift1carry_map[t[i]];
-		t[i] = t_i;
-	end
-end
-function arshift(a, i)
-	local t = {a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]};
-	for n = 1,i do _arshift1(t); end
-	return setmetatable(t, bit_mt);
-end
-local function _lshift1(t)
-	local carry = 0;
-	for i=8,1,-1 do
-		local t_i = lshift1_map[t[i]] + carry;
-		carry = lshift1carry_map[t[i]];
-		t[i] = t_i;
-	end
-end
-function lshift(a, i)
-	local t = {a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]};
-	for n = 1,i do _lshift1(t); end
-	return setmetatable(t, bit_mt);
-end
-
-local function _cast(a)
-	if type(a) == "number" then a = ("%x"):format(a);
-	elseif type(a) == "table" then return a;
-	elseif type(a) ~= "string" then error("string expected, got "..type(a), 2); end
-	local t = {0,0,0,0,0,0,0,0};
-	a = "00000000"..a;
-	a = a:sub(-8);
-	for i = 1,8 do
-		t[i] = tonumber(a:sub(i,i), 16) or error("Number format error", 2);
-	end
-	return setmetatable(t, bit_mt);
-end
-
-local function wrap1(f)
-	return function(a, ...)
-		if type(a) ~= "table" then a = _cast(a); end
-		a = f(a, ...);
-		a = tonumber(tostring(a), 16);
-		if a > 0x7fffffff then a = a - 1 - 0xffffffff; end
-		return a;
-	end;
-end
-local function wrap2(f)
-	return function(a, b, ...)
-		if type(a) ~= "table" then a = _cast(a); end
-		if type(b) ~= "table" then b = _cast(b); end
-		a = f(a, b, ...);
-		a = tonumber(tostring(a), 16);
-		if a > 0x7fffffff then a = a - 1 - 0xffffffff; end
-		return a;
-	end;
-end
-
-bxor = wrap2(bxor);
-bor = wrap2(bor);
-band = wrap2(band);
-bnot = wrap1(bnot);
-lshift = wrap1(lshift);
-rshift = wrap1(rshift);
-arshift = wrap1(arshift);
-cast = wrap1(_cast);
-
-bits = 32;
-
-return _M;
- end)
-package.preload['verse.client'] = (function (...)
-local verse = require "verse";
-local stream = verse.stream_mt;
-
-local jid_split = require "util.jid".split;
-local adns = require "net.adns";
-local lxp = require "lxp";
-local st = require "util.stanza";
-
--- Shortcuts to save having to load util.stanza
-verse.message, verse.presence, verse.iq, verse.stanza, verse.reply, verse.error_reply =
-	st.message, st.presence, st.iq, st.stanza, st.reply, st.error_reply;
-
-local new_xmpp_stream = require "util.xmppstream".new;
-
-local xmlns_stream = "http://etherx.jabber.org/streams";
-
-local function compare_srv_priorities(a,b)
-	return a.priority < b.priority or (a.priority == b.priority and a.weight > b.weight);
-end
-
-local stream_callbacks = {
-	stream_ns = xmlns_stream,
-	stream_tag = "stream",
-	 default_ns = "jabber:client" };
-	
-function stream_callbacks.streamopened(stream, attr)
-	stream.stream_id = attr.id;
-	if not stream:event("opened", attr) then
-		stream.notopen = nil;
-	end
-	return true;
-end
-
-function stream_callbacks.streamclosed(stream)
-	return stream:event("closed");
-end
-
-function stream_callbacks.handlestanza(stream, stanza)
-	if stanza.attr.xmlns == xmlns_stream then
-		return stream:event("stream-"..stanza.name, stanza);
-	elseif stanza.attr.xmlns then
-		return stream:event("stream/"..stanza.attr.xmlns, stanza);
-	end
-
-	return stream:event("stanza", stanza);
-end
-
-function stream:reset()
-	if self.stream then
-		self.stream:reset();
-	else
-		self.stream = new_xmpp_stream(self, stream_callbacks);
-	end
-	self.notopen = true;
-	return true;
-end
-
-function stream:connect_client(jid, pass)
-	self.jid, self.password = jid, pass;
-	self.username, self.host, self.resource = jid_split(jid);
-	
-	-- Required XMPP features
-	self:add_plugin("tls");
-	self:add_plugin("sasl");
-	self:add_plugin("bind");
-	self:add_plugin("session");
-	
-	function self.data(conn, data)
-		local ok, err = self.stream:feed(data);
-		if ok then return; end
-		self:debug("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "));
-		self:close("xml-not-well-formed");
-	end
-	
-	self:hook("connected", function () self:reopen(); end);
-	self:hook("incoming-raw", function (data) return self.data(self.conn, data); end);
-	
-	self.curr_id = 0;
-	
-	self.tracked_iqs = {};
-	self:hook("stanza", function (stanza)
-		local id, type = stanza.attr.id, stanza.attr.type;
-		if id and stanza.name == "iq" and (type == "result" or type == "error") and self.tracked_iqs[id] then
-			self.tracked_iqs[id](stanza);
-			self.tracked_iqs[id] = nil;
-			return true;
-		end
-	end);
-	
-	self:hook("stanza", function (stanza)
-		if stanza.attr.xmlns == nil or stanza.attr.xmlns == "jabber:client" then
-			if stanza.name == "iq" and (stanza.attr.type == "get" or stanza.attr.type == "set") then
-				local xmlns = stanza.tags[1] and stanza.tags[1].attr.xmlns;
-				if xmlns then
-					ret = self:event("iq/"..xmlns, stanza);
-					if not ret then
-						ret = self:event("iq", stanza);
-					end
-				end
-				if ret == nil then
-					self:send(verse.error_reply(stanza, "cancel", "service-unavailable"));
-					return true;
-				end
-			else
-				ret = self:event(stanza.name, stanza);
-			end
-		end
-		return ret;
-	end, -1);
-
-	self:hook("outgoing", function (data)
-		if data.name then
-			self:event("stanza-out", data);
-		end
-	end);
-	
-	self:hook("stanza-out", function (stanza)
-		if not stanza.attr.xmlns then
-			self:event(stanza.name.."-out", stanza);
-		end
-	end);
-	
-	local function stream_ready()
-		self:event("ready");
-	end
-	self:hook("session-success", stream_ready, -1)
-	self:hook("bind-success", stream_ready, -1);
-
-	local _base_close = self.close;
-	function self:close(reason)
-		if not self.notopen then
-			self:send("</stream:stream>");
-		end
-		return _base_close(self);
-	end
-	
-	local function start_connect()
-		-- Initialise connection
-		self:connect(self.connect_host or self.host, self.connect_port or 5222);
-	end
-	
-	if not (self.connect_host or self.connect_port) then
-		-- Look up SRV records
-		adns.lookup(function (answer)
-			if answer then
-				local srv_hosts = {};
-				self.srv_hosts = srv_hosts;
-				for _, record in ipairs(answer) do
-					table.insert(srv_hosts, record.srv);
-				end
-				table.sort(srv_hosts, compare_srv_priorities);
-				
-				local srv_choice = srv_hosts[1];
-				self.srv_choice = 1;
-				if srv_choice then
-					self.connect_host, self.connect_port = srv_choice.target, srv_choice.port;
-					self:debug("Best record found, will connect to %s:%d", self.connect_host or self.host, self.connect_port or 5222);
-				end
-				
-				self:hook("disconnected", function ()
-					if self.srv_hosts and self.srv_choice < #self.srv_hosts then
-						self.srv_choice = self.srv_choice + 1;
-						local srv_choice = srv_hosts[self.srv_choice];
-						self.connect_host, self.connect_port = srv_choice.target, srv_choice.port;
-						start_connect();
-						return true;
-					end
-				end, 1000);
-				
-				self:hook("connected", function ()
-					self.srv_hosts = nil;
-				end, 1000);
-			end
-			start_connect();
-		end, "_xmpp-client._tcp."..(self.host)..".", "SRV");
-	else
-		start_connect();
-	end
-end
-
-function stream:reopen()
-	self:reset();
-	self:send(st.stanza("stream:stream", { to = self.host, ["xmlns:stream"]='http://etherx.jabber.org/streams',
-		xmlns = "jabber:client", version = "1.0" }):top_tag());
-end
-
-function stream:send_iq(iq, callback)
-	local id = self:new_id();
-	self.tracked_iqs[id] = callback;
-	iq.attr.id = id;
-	self:send(iq);
-end
-
-function stream:new_id()
-	self.curr_id = self.curr_id + 1;
-	return tostring(self.curr_id);
-end
- end)
-package.preload['verse.component'] = (function (...)
-local verse = require "verse";
-local stream = verse.stream_mt;
-
-local jid_split = require "util.jid".split;
-local lxp = require "lxp";
-local st = require "util.stanza";
-local sha1 = require "util.sha1".sha1;
-
--- Shortcuts to save having to load util.stanza
-verse.message, verse.presence, verse.iq, verse.stanza, verse.reply, verse.error_reply =
-	st.message, st.presence, st.iq, st.stanza, st.reply, st.error_reply;
-
-local new_xmpp_stream = require "util.xmppstream".new;
-
-local xmlns_stream = "http://etherx.jabber.org/streams";
-local xmlns_component = "jabber:component:accept";
-
-local stream_callbacks = {
-	stream_ns = xmlns_stream,
-	stream_tag = "stream",
-	 default_ns = xmlns_component };
-	
-function stream_callbacks.streamopened(stream, attr)
-	stream.stream_id = attr.id;
-	if not stream:event("opened", attr) then
-		stream.notopen = nil;
-	end
-	return true;
-end
-
-function stream_callbacks.streamclosed(stream)
-	return stream:event("closed");
-end
-
-function stream_callbacks.handlestanza(stream, stanza)
-	if stanza.attr.xmlns == xmlns_stream then
-		return stream:event("stream-"..stanza.name, stanza);
-	elseif stanza.attr.xmlns or stanza.name == "handshake" then
-		return stream:event("stream/"..(stanza.attr.xmlns or xmlns_component), stanza);
-	end
-
-	return stream:event("stanza", stanza);
-end
-
-function stream:reset()
-	if self.stream then
-		self.stream:reset();
-	else
-		self.stream = new_xmpp_stream(self, stream_callbacks);
-	end
-	self.notopen = true;
-	return true;
-end
-
-function stream:connect_component(jid, pass)
-	self.jid, self.password = jid, pass;
-	self.username, self.host, self.resource = jid_split(jid);
-	
-	function self.data(conn, data)
-		local ok, err = self.stream:feed(data);
-		if ok then return; end
-		stream:debug("debug", "Received invalid XML (%s) %d bytes: %s", tostring(err), #data, data:sub(1, 300):gsub("[\r\n]+", " "));
-		stream:close("xml-not-well-formed");
-	end
-	
-	self:hook("incoming-raw", function (data) return self.data(self.conn, data); end);
-	
-	self.curr_id = 0;
-	
-	self.tracked_iqs = {};
-	self:hook("stanza", function (stanza)
-		local id, type = stanza.attr.id, stanza.attr.type;
-		if id and stanza.name == "iq" and (type == "result" or type == "error") and self.tracked_iqs[id] then
-			self.tracked_iqs[id](stanza);
-			self.tracked_iqs[id] = nil;
-			return true;
-		end
-	end);
-	
-	self:hook("stanza", function (stanza)
-		if stanza.attr.xmlns == nil or stanza.attr.xmlns == "jabber:client" then
-			if stanza.name == "iq" and (stanza.attr.type == "get" or stanza.attr.type == "set") then
-				local xmlns = stanza.tags[1] and stanza.tags[1].attr.xmlns;
-				if xmlns then
-					ret = self:event("iq/"..xmlns, stanza);
-					if not ret then
-						ret = self:event("iq", stanza);
-					end
-				end
-				if ret == nil then
-					self:send(verse.error_reply(stanza, "cancel", "service-unavailable"));
-					return true;
-				end
-			else
-				ret = self:event(stanza.name, stanza);
-			end
-		end
-		return ret;
-	end, -1);
-
-	self:hook("opened", function (attr)
-		print(self.jid, self.stream_id, attr.id);
-		local token = sha1(self.stream_id..pass, true);
-
-		self:send(st.stanza("handshake", { xmlns = xmlns_component }):text(token));
-		self:hook("stream/"..xmlns_component, function (stanza)
-			if stanza.name == "handshake" then
-				self:event("authentication-success");
-			end
-		end);
-	end);
-
-	local function stream_ready()
-		self:event("ready");
-	end
-	self:hook("authentication-success", stream_ready, -1);
-
-	-- Initialise connection
-	self:connect(self.connect_host or self.host, self.connect_port or 5347);
-	self:reopen();
-end
-
-function stream:reopen()
-	self:reset();
-	self:send(st.stanza("stream:stream", { to = self.host, ["xmlns:stream"]='http://etherx.jabber.org/streams',
-		xmlns = xmlns_component, version = "1.0" }):top_tag());
-end
-
-function stream:close(reason)
-	if not self.notopen then
-		self:send("</stream:stream>");
-	end
-	local on_disconnect = self.conn.disconnect();
-	self.conn:close();
-	on_disconnect(conn, reason);
-end
-
-function stream:send_iq(iq, callback)
-	local id = self:new_id();
-	self.tracked_iqs[id] = callback;
-	iq.attr.id = id;
-	self:send(iq);
-end
-
-function stream:new_id()
-	self.curr_id = self.curr_id + 1;
-	return tostring(self.curr_id);
-end
- end)
-
--- Use LuaRocks if available
-pcall(require, "luarocks.require");
-
--- Load LuaSec if available
-pcall(require, "ssl");
-
-local server = require "net.server";
-local events = require "util.events";
-
-module("verse", package.seeall);
-local verse = _M;
-_M.server = server;
-
-local stream = {};
-stream.__index = stream;
-stream_mt = stream;
-
-verse.plugins = {};
-
-function verse.new(logger, base)
-	local t = setmetatable(base or {}, stream);
-	t.id = tostring(t):match("%x*$");
-	t:set_logger(logger, true);
-	t.events = events.new();
-	t.plugins = {};
-	return t;
-end
-
-verse.add_task = require "util.timer".add_task;
-
-verse.logger = logger.init;
-verse.log = verse.logger("verse");
-
-function verse.set_logger(logger)
-	verse.log = logger;
-	server.setlogger(logger);
-end
-
-function verse.filter_log(levels, logger)
-	local level_set = {};
-	for _, level in ipairs(levels) do
-		level_set[level] = true;
-	end
-	return function (level, name, ...)
-		if level_set[level] then
-			return logger(level, name, ...);
-		end
-	end;
-end
-
-local function error_handler(err)
-	verse.log("error", "Error: %s", err);
-	verse.log("error", "Traceback: %s", debug.traceback());
-end
-
-function verse.set_error_handler(new_error_handler)
-	error_handler = new_error_handler;
-end
-
-function verse.loop()
-	return xpcall(server.loop, error_handler);
-end
-
-function verse.step()
-	return xpcall(server.step, error_handler);
-end
-
-function verse.quit()
-	return server.setquitting(true);
-end
-
-function stream:connect(connect_host, connect_port)
-	connect_host = connect_host or "localhost";
-	connect_port = tonumber(connect_port) or 5222;
-	
-	-- Create and initiate connection
-	local conn = socket.tcp()
-	conn:settimeout(0);
-	local success, err = conn:connect(connect_host, connect_port);
-	
-	if not success and err ~= "timeout" then
-		self:warn("connect() to %s:%d failed: %s", connect_host, connect_port, err);
-		return self:event("disconnected", { reason = err }) or false, err;
-	end
-
-	local conn = server.wrapclient(conn, connect_host, connect_port, new_listener(self), "*a");
-	if not conn then
-		self:warn("connection initialisation failed: %s", err);
-		return self:event("disconnected", { reason = err }) or false, err;
-	end
-	
-	self.conn = conn;
-	self.send = function (stream, data)
-		self:event("outgoing", data);
-		data = tostring(data);
-		self:event("outgoing-raw", data);
-		return conn:write(data);
-	end;
-	return true;
-end
-
-function stream:close()
-	if not self.conn then 
-		verse.log("error", "Attempt to close disconnected connection - possibly a bug");
-		return;
-	end
-	local on_disconnect = self.conn.disconnect();
-	self.conn:close();
-	on_disconnect(conn, reason);
-end
-
--- Logging functions
-function stream:debug(...)
-	if self.logger and self.log.debug then
-		return self.logger("debug", ...);
-	end
-end
-
-function stream:warn(...)
-	if self.logger and self.log.warn then
-		return self.logger("warn", ...);
-	end
-end
-
-function stream:error(...)
-	if self.logger and self.log.error then
-		return self.logger("error", ...);
-	end
-end
-
-function stream:set_logger(logger, levels)
-	local old_logger = self.logger;
-	if logger then
-		self.logger = logger;
-	end
-	if levels then
-		if levels == true then
-			levels = { "debug", "info", "warn", "error" };
-		end
-		self.log = {};
-		for _, level in ipairs(levels) do
-			self.log[level] = true;
-		end
-	end
-	return old_logger;
-end
-
-function stream_mt:set_log_levels(levels)
-	self:set_logger(nil, levels);
-end
-
--- Event handling
-function stream:event(name, ...)
-	self:debug("Firing event: "..tostring(name));
-	return self.events.fire_event(name, ...);
-end
-
-function stream:hook(name, ...)
-	return self.events.add_handler(name, ...);
-end
-
-function stream:unhook(name, handler)
-	return self.events.remove_handler(name, handler);
-end
-
-function verse.eventable(object)
-        object.events = events.new();
-        object.hook, object.unhook = stream.hook, stream.unhook;
-        local fire_event = object.events.fire_event;
-        function object:event(name, ...)
-                return fire_event(name, ...);
-        end
-        return object;
-end
-
-function stream:add_plugin(name)
-	if self.plugins[name] then return true; end
-	if require("verse.plugins."..name) then
-		local ok, err = verse.plugins[name](self);
-		if ok ~= false then
-			self:debug("Loaded %s plugin", name);
-			self.plugins[name] = true;
-		else
-			self:warn("Failed to load %s plugin: %s", name, err);
-		end
-	end
-	return self;
-end
-
--- Listener factory
-function new_listener(stream)
-	local conn_listener = {};
-	
-	function conn_listener.onconnect(conn)
-		stream.connected = true;
-		stream:event("connected");
-	end
-	
-	function conn_listener.onincoming(conn, data)
-		stream:event("incoming-raw", data);
-	end
-	
-	function conn_listener.ondisconnect(conn, err)
-		stream.connected = false;
-		stream:event("disconnected", { reason = err });
-	end
-
-	function conn_listener.ondrain(conn)
-		stream:event("drained");
-	end
-	
-	function conn_listener.onstatus(conn, new_status)
-		stream:event("status", new_status);
-	end
-	
-	return conn_listener;
-end
-
-
-local log = require "util.logger".init("verse");
-
-return verse;
- end)
 -- README
 -- Squish verse into this dir, then squish them into one, which you move
 -- and rename to mod_ircd.lua in your prosody modules/plugins dir.
@@ -5499,9 +181,6 @@
 			--FIXME PM's probably won't work
 		end
 	end);
-	room:hook("subject-changed", function(changed) 
-		session.send((":%s TOPIC %s :%s"):format(changed.by, channel, changed.to or ""));
-	end);
 end
 
 c:hook("groupchat/joined", function(room)
@@ -5561,23 +240,6 @@
 	end
 end
 
-function commands.TOPIC(session, message)
-	if not message then return end
-	local channel, topic = message:match("^(%S+) :(.*)$");
-	if not channel then
-		channel = message:match("^(%S+)");
-	end
-	if not channel then return end
-	local room = session.rooms[channel];
-	if topic then
-		room:set_subject(topic)
-	else
-		session.send((":%s TOPIC %s :%s"):format(session.host, channel, room.subject or ""));
-		-- first should be who set it, but verse doesn't provide that yet, so we'll
-		-- just say it was the server
-	end
-end
-
 function commands.PING(session, server)
 	session.send(":"..session.host..": PONG "..server);
 end
@@ -5612,16 +274,11 @@
 	--c:send(data)
 end
 
-local function desetup()
-	require "net.connlisteners".deregister("irc");
-end
-
 --c:hook("ready", function ()
 	require "net.connlisteners".register("irc", irc_listener);
 	require "net.connlisteners".start("irc");
 --end);
 
-module:hook("module-unloaded", desetup)
 --print("Starting loop...")
 --verse.loop()
 
--- a/mod_ircd/squishy	Mon Oct 24 00:20:51 2011 +0000
+++ b/mod_ircd/squishy	Sat Oct 29 13:34:15 2011 +0200
@@ -1,6 +1,6 @@
-Output "mod_ircd.lua"
+Output "mod_ircd.out.lua"
 
 -- In theory, you should be able to leave all but verses groupchat and presence plugins
 Module "verse" "verse.lua"
 
-Main "mod_ircd.in.lua"
+Main "mod_ircd.lua"
--- a/mod_pubsub_feed/mod_pubsub_feed.lua	Mon Oct 24 00:20:51 2011 +0000
+++ b/mod_pubsub_feed/mod_pubsub_feed.lua	Sat Oct 29 13:34:15 2011 +0200
@@ -38,33 +38,19 @@
 local urldecode  = http.urldecode;
 local urlencode  = http.urlencode;
 
-local feed_list = {};
-local refresh_interval;
-
--- Dynamicaly reloadable config.
-local function update_config()
 local config = module:get_option("feeds") or {
 	planet_jabber = "http://planet.jabber.org/atom.xml";
 	prosody_blog = "http://blog.prosody.im/feed/atom.xml";
 };
-	refresh_interval = module:get_option_number("feed_pull_interval", 15) * 60;
-	local new_feed_list;
+local refresh_interval = module:get_option_number("feed_pull_interval", 15) * 60;
+local use_pubsubhubub = module:get_option_boolean("use_pubsubhubub", true); -- HTTP by default or not?
+local httphost = module:get_option_string("pubsubhubub_httphost", module.host); -- If module.host IN A doesn't point to this server, use this to override.
+local feed_list = { }
 for node, url in pairs(config) do
-		local new_feed_list[node] = true;
-		if not feed_list[node] then
 	feed_list[node] = { url = url; node = node; last_update = 0 };
-		else
-			feed_list[node].url = url;
 end
-	end
-	for node in pairs(feed_list) do
-		if not new_feed_list[node] then
-			feed_list[node] = nil;
-		end
-	end
-end
-update_config();
-module:hook("config-reloaded", update_config);
+-- TODO module:hook("config-reloaded", above loop);
+-- Also, keeping it somewhere persistent in order to avoid duplicated publishes?
 
 -- Used to kill the timer
 local module_unloaded = false;
@@ -72,13 +58,6 @@
 	module_unloaded = true;
 end
 
--- Config stuff that can't be reloaded, since it would need to re-bind HTTP stuff.
-
--- If module.host IN A doesn't point to this server, use this to override.
-local httphost = module:get_option_string("pubsubhubub_httphost", module.host);
--- HTTP by default or not?
-local use_pubsubhubub = module:get_option_boolean("use_pubsubhubub", true);
-
 -- Thanks to Maranda for this
 local port, base, ssl = 5280, "callback", false;
 local ports = module:get_option("feeds_ports") or { port = port, base = base, ssl = ssl };
@@ -190,13 +169,12 @@
 end
 
 function refresh_feeds()
-	local now = time();
 	if module_unloaded then return end
 	--module:log("debug", "Refreshing feeds");
 	for node, item in pairs(feed_list) do
 		--FIXME Don't fetch feeds which have a subscription
 		-- Otoho, what if the subscription expires or breaks?
-		if item.last_update + refresh_interval < now then 
+		if item.last_update + refresh_interval < time() then 
 			module:log("debug", "checking %s", item.node);
 			fetch(item, update_entry);
 		end