Changeset

1144:fbd65e966316

Merge with 0.4
author Matthew Wild <mwild1@gmail.com>
date Wed, 13 May 2009 16:55:20 +0100
parents 1142:0e02b3301e80 (diff) 1143:5bab3eb566ad (current diff)
children 1145:06051191913d
files core/stanza_router.lua
diffstat 16 files changed, 539 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/core/componentmanager.lua	Wed May 13 16:54:46 2009 +0100
+++ b/core/componentmanager.lua	Wed May 13 16:55:20 2009 +0100
@@ -80,8 +80,7 @@
 
 function create_component(host, component)
 	-- TODO check for host well-formedness
-	local session = session or { type = "component", host = host, connected = true, s2sout = {} };
-	return session;
+	return { type = "component", host = host, connected = true, s2sout = {} };
 end
 
 function register_component(host, component, session)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/eventmanager2.lua	Wed May 13 16:55:20 2009 +0100
@@ -0,0 +1,6 @@
+
+local events = require "util.events".new();
+
+module "eventmanager"
+
+return events;
--- a/core/stanza_router.lua	Wed May 13 16:54:46 2009 +0100
+++ b/core/stanza_router.lua	Wed May 13 16:55:20 2009 +0100
@@ -10,6 +10,8 @@
 
 local log = require "util.logger".init("stanzarouter")
 
+local hosts = _G.hosts;
+
 local st = require "util.stanza";
 local send_s2s = require "core.s2smanager".send_to_host;
 local user_exists = require "core.usermanager".user_exists;
@@ -24,9 +26,9 @@
 local modules_handle_stanza = require "core.modulemanager".handle_stanza;
 local component_handle_stanza = require "core.componentmanager".handle_stanza;
 
-local handle_outbound_presence_subscriptions_and_probes = require "core.presencemanager".handle_outbound_presence_subscriptions_and_probes;
-local handle_inbound_presence_subscriptions_and_probes = require "core.presencemanager".handle_inbound_presence_subscriptions_and_probes;
-local handle_normal_presence = require "core.presencemanager".handle_normal_presence;
+local handle_outbound_presence_subscriptions_and_probes = function()end;--require "core.presencemanager".handle_outbound_presence_subscriptions_and_probes;
+local handle_inbound_presence_subscriptions_and_probes = function()end;--require "core.presencemanager".handle_inbound_presence_subscriptions_and_probes;
+local handle_normal_presence = function()end;--require "core.presencemanager".handle_normal_presence;
 
 local format = string.format;
 local tostring = tostring;
@@ -40,6 +42,7 @@
 local jid_split = require "util.jid".split;
 local jid_prepped_split = require "util.jid".prepped_split;
 local print = print;
+local fire_event = require "core.eventmanager2".fire_event;
 local function checked_error_reply(origin, stanza)
 	if (stanza.attr.xmlns == "jabber:client" or stanza.attr.xmlns == "jabber:server") and stanza.attr.type ~= "error" and stanza.attr.type ~= "result" then
 		origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); -- FIXME correct error?
@@ -105,6 +108,8 @@
 
 	-- FIXME do stanzas not of jabber:client get handled by components?
 	if (origin.type == "s2sin" or origin.type == "c2s" or origin.type == "component") and (not xmlns or xmlns == "jabber:server" or xmlns == "jabber:client") then			
+		local event_data = {origin=origin, stanza=stanza};
+		fire_event(tostring(host or origin.host).."/"..stanza.name, event_data);
 		if origin.type == "s2sin" and not origin.dummy then
 			local host_status = origin.hosts[from_host];
 			if not host_status or not host_status.authed then -- remote server trying to impersonate some other server?
@@ -145,7 +150,7 @@
 -- that is, they are handled by this server
 function core_handle_stanza(origin, stanza)
 	-- Handlers
-	if modules_handle_stanza(select(2, jid_split(stanza.attr.to)) or origin.host, origin, stanza) then return; end
+	if modules_handle_stanza(select(2, jid_split(stanza.attr.to)) or origin.host or origin.to_host, origin, stanza) then return; end
 	if origin.type == "c2s" or origin.type == "s2sin" then
 		if origin.type == "c2s" then
 			if stanza.name == "presence" and origin.roster then
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fallbacks/bit.lua	Wed May 13 16:55:20 2009 +0100
@@ -0,0 +1,137 @@
+
+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;
--- a/net/http.lua	Wed May 13 16:54:46 2009 +0100
+++ b/net/http.lua	Wed May 13 16:55:20 2009 +0100
@@ -9,8 +9,8 @@
 local listener = connlisteners_get("httpclient") or error("No httpclient listener!");
 
 local t_insert, t_concat = table.insert, table.concat;
-local tonumber, tostring, pairs, xpcall, select, debug_traceback = 
-        tonumber, tostring, pairs, xpcall, select, debug.traceback;
+local tonumber, tostring, pairs, xpcall, select, debug_traceback, char = 
+        tonumber, tostring, pairs, xpcall, select, debug.traceback, string.char;
 
 local log = require "util.logger".init("http");
 local print = function () end
--- a/net/server.lua	Wed May 13 16:54:46 2009 +0100
+++ b/net/server.lua	Wed May 13 16:55:20 2009 +0100
@@ -791,7 +791,7 @@
 end
 
 local addclient = function( address, port, listeners, pattern, sslctx, startssl )
-    local client, err = socket.tcp( )
+    local client, err = luasocket.tcp( )
     if err then
         return nil, err
     end
@@ -800,7 +800,7 @@
     if err then    -- try again
         local handler = wrapclient( client, address, port, listeners )
     else
-        wrapconnection( server, listeners, socket, address, port, "clientport", pattern, sslctx, startssl )
+        wrapconnection( nil, listeners, client, address, port, "clientport", pattern, sslctx, startssl )
     end
 end
 
--- a/net/xmppclient_listener.lua	Wed May 13 16:54:46 2009 +0100
+++ b/net/xmppclient_listener.lua	Wed May 13 16:55:20 2009 +0100
@@ -9,6 +9,7 @@
 
 
 local logger = require "logger";
+local log = logger.init("xmppclient_listener");
 local lxp = require "lxp"
 local init_xmlhandlers = require "core.xmlhandlers"
 local sm_new_session = require "core.sessionmanager".new_session;
@@ -20,10 +21,11 @@
 local t_concatall = function (t, sep) local tt = {}; for _, s in ipairs(t) do t_insert(tt, tostring(s)); end return t_concat(tt, sep); end
 local m_random = math.random;
 local format = string.format;
-local sm_new_session, sm_destroy_session = sessionmanager.new_session, sessionmanager.destroy_session; --import("core.sessionmanager", "new_session", "destroy_session");
+local sessionmanager = require "core.sessionmanager";
+local sm_new_session, sm_destroy_session = sessionmanager.new_session, sessionmanager.destroy_session;
 local sm_streamopened = sessionmanager.streamopened;
 local sm_streamclosed = sessionmanager.streamclosed;
-local st = stanza;
+local st = require "util.stanza";
 
 local stream_callbacks = { stream_tag = "http://etherx.jabber.org/streams|stream", 
 		default_ns = "jabber:client",
--- a/net/xmppserver_listener.lua	Wed May 13 16:54:46 2009 +0100
+++ b/net/xmppserver_listener.lua	Wed May 13 16:55:20 2009 +0100
@@ -9,9 +9,9 @@
 
 
 local logger = require "logger";
+local log = logger.init("xmppserver_listener");
 local lxp = require "lxp"
 local init_xmlhandlers = require "core.xmlhandlers"
-local sm_new_session = require "core.sessionmanager".new_session;
 local s2s_new_incoming = require "core.s2smanager".new_incoming;
 local s2s_streamopened = require "core.s2smanager".streamopened;
 local s2s_streamclosed = require "core.s2smanager".streamclosed;
@@ -42,8 +42,9 @@
 local t_concatall = function (t, sep) local tt = {}; for _, s in ipairs(t) do t_insert(tt, tostring(s)); end return t_concat(tt, sep); end
 local m_random = math.random;
 local format = string.format;
-local sm_new_session, sm_destroy_session = sessionmanager.new_session, sessionmanager.destroy_session; --import("core.sessionmanager", "new_session", "destroy_session");
-local st = stanza;
+local sessionmanager = require "core.sessionmanager";
+local sm_new_session, sm_destroy_session = sessionmanager.new_session, sessionmanager.destroy_session;
+local st = require "util.stanza";
 
 local sessions = {};
 local xmppserver = { default_port = 5269, default_mode = "*a" };
--- a/plugins/mod_bosh.lua	Wed May 13 16:54:46 2009 +0100
+++ b/plugins/mod_bosh.lua	Wed May 13 16:55:20 2009 +0100
@@ -1,6 +1,7 @@
 
 module.host = "*" -- Global module
 
+local hosts = _G.hosts;
 local lxp = require "lxp";
 local init_xmlhandlers = require "core.xmlhandlers"
 local server = require "net.server";
--- a/plugins/mod_muc.lua	Wed May 13 16:54:46 2009 +0100
+++ b/plugins/mod_muc.lua	Wed May 13 16:55:20 2009 +0100
@@ -205,6 +205,34 @@
 		end
 	end
 end
+function send_history(room, to)
+	local history = rooms_info:get(room, 'history'); -- send discussion history
+	if history then
+		for _, msg in ipairs(history) do
+			msg = st.deserialize(msg);
+			msg.attr.to=to;
+			core_route_stanza(component, msg);
+		end
+	end
+	if rooms_info:get(room, 'subject') then
+		core_route_stanza(component, st.message({type='groupchat', from=room, to=to}):tag("subject"):text(rooms_info:get(room, 'subject')));
+	end
+end
+function send_occupant_list(room, to)
+	local r = rooms:get(room);
+	if r then
+		local current_nick = jid_nick:get(to, room);
+		for occupant, o_data in pairs(r) do
+			if occupant ~= current_nick then
+				local pres = get_filtered_presence(o_data.sessions[o_data.jid]);
+				pres.attr.to, pres.attr.from = to, occupant;
+				pres:tag("x", {xmlns='http://jabber.org/protocol/muc#user'})
+					:tag("item", {affiliation=o_data.affiliation, role=o_data.role}):up();
+				core_route_stanza(component, pres);
+			end
+		end
+	end
+end
 
 function handle_to_occupant(origin, stanza) -- PM, vCards, etc
 	local from, to = stanza.attr.from, stanza.attr.to;
@@ -232,7 +260,7 @@
 			end
 		elseif not type then -- available
 			if current_nick then
-				if #pr == #stanza or current_nick ~= to then
+				--if #pr == #stanza or current_nick ~= to then -- commented because google keeps resending directed presence
 					if current_nick == to then -- simple presence
 						log("debug", "%s broadcasted presence", current_nick);
 						rooms:get(room, current_nick).sessions[from] = pr;
@@ -259,11 +287,11 @@
 							end
 						end
 					end
-				else -- possible rejoin
-					log("debug", "%s had connection replaced", current_nick);
-					handle_to_occupant(origin, st.presence({type='unavailable', from=from, to=to}):tag('status'):text('Replaced by new connection'):up()); -- send unavailable
-					handle_to_occupant(origin, stanza); -- resend available
-				end
+				--else -- possible rejoin
+				--	log("debug", "%s had connection replaced", current_nick);
+				--	handle_to_occupant(origin, st.presence({type='unavailable', from=from, to=to}):tag('status'):text('Replaced by new connection'):up()); -- send unavailable
+				--	handle_to_occupant(origin, stanza); -- resend available
+				--end
 			else -- enter room
 				local new_nick = to;
 				if rooms:get(room, to) then
@@ -284,31 +312,10 @@
 					end
 					rooms:set(room, to, data);
 					jid_nick:set(from, room, to);
-					local r = rooms:get(room);
-					if r then
-						for occupant, o_data in pairs(r) do
-							if occupant ~= to then
-								local pres = get_filtered_presence(o_data.sessions[o_data.jid]);
-								pres.attr.to, pres.attr.from = from, occupant;
-								pres:tag("x", {xmlns='http://jabber.org/protocol/muc#user'})
-									:tag("item", {affiliation=o_data.affiliation, role=o_data.role}):up();
-								core_route_stanza(component, pres);
-							end
-						end
-					end
+					send_occupant_list(room, from);
 					pr.attr.from = to;
 					broadcast_presence_stanza(room, pr);
-					local history = rooms_info:get(room, 'history'); -- send discussion history
-					if history then
-						for _, msg in ipairs(history) do
-							msg = st.deserialize(msg);
-							msg.attr.to=from;
-							core_route_stanza(component, msg);
-						end
-					end
-					if rooms_info:get(room, 'subject') then
-						core_route_stanza(component, st.message({type='groupchat', from=room, to=from}):tag("subject"):text(rooms_info:get(room, 'subject')));
-					end
+					send_history(room, from);
 				end
 			end
 		elseif type ~= 'result' then -- bad type
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mod_pep.lua	Wed May 13 16:55:20 2009 +0100
@@ -0,0 +1,48 @@
+
+local jid_bare = require "util.jid".bare;
+local jid_split = require "util.jid".split;
+local st = require "util.stanza";
+local hosts = hosts;
+local user_exists = require "core.usermanager".user_exists;
+local is_contact_subscribed = require "core.rostermanager".is_contact_subscribed;
+local pairs, ipairs = pairs, ipairs;
+
+local function publish(session, node, item)
+	local stanza = st.message({from=session.full_jid, type='headline'})
+		:tag('event', {xmlns='http://jabber.org/protocol/pubsub#event'})
+			:tag('items', {node=node})
+				:add_child(item)
+			:up()
+		:up();
+
+	-- broadcast to resources
+	stanza.attr.to = session.username..'@'..session.host;
+	core_route_stanza(session, stanza);
+
+	-- broadcast to contacts
+	for jid, item in pairs(session.roster) do
+		if jid and jid ~= "pending" and (item.subscription == 'from' or item.subscription == 'both') then
+			stanza.attr.to = jid;
+			core_route_stanza(session, stanza);
+		end
+	end
+end
+
+module:add_iq_handler("c2s", "http://jabber.org/protocol/pubsub", function (session, stanza)
+	if stanza.attr.type == 'set' and (not stanza.attr.to or jid_bare(stanza.attr.from) == stanza.attr.to) then
+		local payload = stanza.tags[1];
+		if payload.name == 'pubsub' then
+			payload = payload.tags[1];
+			if payload and payload.name == 'publish' and payload.attr.node then
+				local node = payload.attr.node;
+				payload = payload.tags[1];
+				if payload then
+					publish(session, node, payload);
+					return true;
+				end -- TODO else error
+			end -- TODO else error
+		end
+	end
+	origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
+end);
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/mod_presence.lua	Wed May 13 16:55:20 2009 +0100
@@ -0,0 +1,279 @@
+-- Prosody IM v0.4
+-- Copyright (C) 2008-2009 Matthew Wild
+-- Copyright (C) 2008-2009 Waqas Hussain
+-- 
+-- This project is MIT/X11 licensed. Please see the
+-- COPYING file in the source package for more information.
+--
+
+
+
+local log = require "util.logger".init("mod_presence")
+
+local require = require;
+local pairs, ipairs = pairs, ipairs;
+local t_concat = table.concat;
+local s_find = string.find;
+local tonumber = tonumber;
+
+local st = require "util.stanza";
+local jid_split = require "util.jid".split;
+local jid_bare = require "util.jid".bare;
+local hosts = hosts;
+
+local rostermanager = require "core.rostermanager";
+local sessionmanager = require "core.sessionmanager";
+local offlinemanager = require "core.offlinemanager";
+
+local _core_route_stanza = core_route_stanza;
+local core_route_stanza;
+function core_route_stanza(origin, stanza)
+	if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" and stanza.attr.type ~= "error" then
+		local node, host = jid_split(stanza.attr.to);
+		host = hosts[host];
+		if host and host.type == "local" then
+			handle_inbound_presence_subscriptions_and_probes(origin, stanza, jid_bare(stanza.attr.from), jid_bare(stanza.attr.to), core_route_stanza);
+			return;
+		end
+	end
+	_core_route_stanza(origin, stanza);
+end
+
+function handle_presence(origin, stanza, from_bare, to_bare, core_route_stanza, inbound)
+	local type = stanza.attr.type;
+	if type and type ~= "unavailable" and type ~= "error" then
+		if inbound then
+			handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza);
+		else
+			handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza);
+		end
+	elseif not inbound and not stanza.attr.to then
+		handle_normal_presence(origin, stanza, core_route_stanza);
+	else
+		core_route_stanza(origin, stanza);
+	end
+end
+
+function handle_normal_presence(origin, stanza, core_route_stanza)
+	if origin.roster then
+		for jid in pairs(origin.roster) do -- broadcast to all interested contacts
+			local subscription = origin.roster[jid].subscription;
+			if subscription == "both" or subscription == "from" then
+				stanza.attr.to = jid;
+				core_route_stanza(origin, stanza);
+			end
+		end
+		local node, host = jid_split(stanza.attr.from);
+		for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast to all resources
+			if res ~= origin and res.presence then -- to resource
+				stanza.attr.to = res.full_jid;
+				core_route_stanza(origin, stanza);
+			end
+		end
+		if stanza.attr.type == nil and not origin.presence then -- initial presence
+			local probe = st.presence({from = origin.full_jid, type = "probe"});
+			for jid in pairs(origin.roster) do -- probe all contacts we are subscribed to
+				local subscription = origin.roster[jid].subscription;
+				if subscription == "both" or subscription == "to" then
+					probe.attr.to = jid;
+					core_route_stanza(origin, probe);
+				end
+			end
+			for _, res in pairs(hosts[host].sessions[node].sessions) do -- broadcast from all available resources
+				if res ~= origin and res.presence then
+					res.presence.attr.to = origin.full_jid;
+					core_route_stanza(res, res.presence);
+					res.presence.attr.to = nil;
+				end
+			end
+			if origin.roster.pending then -- resend incoming subscription requests
+				for jid in pairs(origin.roster.pending) do
+					origin.send(st.presence({type="subscribe", from=jid})); -- TODO add to attribute? Use original?
+				end
+			end
+			local request = st.presence({type="subscribe", from=origin.username.."@"..origin.host});
+			for jid, item in pairs(origin.roster) do -- resend outgoing subscription requests
+				if item.ask then
+					request.attr.to = jid;
+					core_route_stanza(origin, request);
+				end
+			end
+			local offline = offlinemanager.load(node, host);
+			if offline then
+				for _, msg in ipairs(offline) do
+					origin.send(msg); -- FIXME do we need to modify to/from in any way?
+				end
+				offlinemanager.deleteAll(node, host);
+			end
+		end
+		origin.priority = 0;
+		if stanza.attr.type == "unavailable" then
+			origin.presence = nil;
+			if origin.directed then
+				local old_from = stanza.attr.from;
+				stanza.attr.from = origin.full_jid;
+				for jid in pairs(origin.directed) do
+					stanza.attr.to = jid;
+					core_route_stanza(origin, stanza);
+				end
+				stanza.attr.from = old_from;
+				origin.directed = nil;
+			end
+		else
+			origin.presence = stanza;
+			local priority = stanza:child_with_name("priority");
+			if priority and #priority > 0 then
+				priority = t_concat(priority);
+				if s_find(priority, "^[+-]?[0-9]+$") then
+					priority = tonumber(priority);
+					if priority < -128 then priority = -128 end
+					if priority > 127 then priority = 127 end
+					origin.priority = priority;
+				end
+			end
+		end
+		stanza.attr.to = nil; -- reset it
+	else
+		log("error", "presence recieved from client with no roster");
+	end
+end
+
+function send_presence_of_available_resources(user, host, jid, recipient_session, core_route_stanza)
+	local h = hosts[host];
+	local count = 0;
+	if h and h.type == "local" then
+		local u = h.sessions[user];
+		if u then
+			for k, session in pairs(u.sessions) do
+				local pres = session.presence;
+				if pres then
+					pres.attr.to = jid;
+					pres.attr.from = session.full_jid;
+					core_route_stanza(session, pres);
+					pres.attr.to = nil;
+					pres.attr.from = nil;
+					count = count + 1;
+				end
+			end
+		end
+	end
+	log("info", "broadcasted presence of "..count.." resources from "..user.."@"..host.." to "..jid);
+	return count;
+end
+
+function handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza)
+	local node, host = jid_split(from_bare);
+	local st_from, st_to = stanza.attr.from, stanza.attr.to;
+	stanza.attr.from, stanza.attr.to = from_bare, to_bare;
+	log("debug", "outbound presence "..stanza.attr.type.." from "..from_bare.." for "..to_bare);
+	if stanza.attr.type == "subscribe" then
+		-- 1. route stanza
+		-- 2. roster push (subscription = none, ask = subscribe)
+		if rostermanager.set_contact_pending_out(node, host, to_bare) then
+			rostermanager.roster_push(node, host, to_bare);
+		end -- else file error
+		core_route_stanza(origin, stanza);
+	elseif stanza.attr.type == "unsubscribe" then
+		-- 1. route stanza
+		-- 2. roster push (subscription = none or from)
+		if rostermanager.unsubscribe(node, host, to_bare) then
+			rostermanager.roster_push(node, host, to_bare); -- FIXME do roster push when roster has in fact not changed?
+		end -- else file error
+		core_route_stanza(origin, stanza);
+	elseif stanza.attr.type == "subscribed" then
+		-- 1. route stanza
+		-- 2. roster_push ()
+		-- 3. send_presence_of_available_resources
+		if rostermanager.subscribed(node, host, to_bare) then
+			rostermanager.roster_push(node, host, to_bare);
+		end
+		core_route_stanza(origin, stanza);
+		send_presence_of_available_resources(node, host, to_bare, origin, core_route_stanza);
+	elseif stanza.attr.type == "unsubscribed" then
+		-- 1. route stanza
+		-- 2. roster push (subscription = none or to)
+		if rostermanager.unsubscribed(node, host, to_bare) then
+			rostermanager.roster_push(node, host, to_bare);
+		end
+		core_route_stanza(origin, stanza);
+	end
+	stanza.attr.from, stanza.attr.to = st_from, st_to;
+end
+
+function handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza)
+	local node, host = jid_split(to_bare);
+	local st_from, st_to = stanza.attr.from, stanza.attr.to;
+	stanza.attr.from, stanza.attr.to = from_bare, to_bare;
+	log("debug", "inbound presence "..stanza.attr.type.." from "..from_bare.." for "..to_bare);
+	if stanza.attr.type == "probe" then
+		if rostermanager.is_contact_subscribed(node, host, from_bare) then
+			if 0 == send_presence_of_available_resources(node, host, from_bare, origin, core_route_stanza) then
+				-- TODO send last recieved unavailable presence (or we MAY do nothing, which is fine too)
+			end
+		else
+			core_route_stanza(origin, st.presence({from=to_bare, to=from_bare, type="unsubscribed"}));
+		end
+	elseif stanza.attr.type == "subscribe" then
+		if rostermanager.is_contact_subscribed(node, host, from_bare) then
+			core_route_stanza(origin, st.presence({from=to_bare, to=from_bare, type="subscribed"})); -- already subscribed
+			-- Sending presence is not clearly stated in the RFC, but it seems appropriate
+			if 0 == send_presence_of_available_resources(node, host, from_bare, origin, core_route_stanza) then
+				-- TODO send last recieved unavailable presence (or we MAY do nothing, which is fine too)
+			end
+		else
+			if not rostermanager.is_contact_pending_in(node, host, from_bare) then
+				if rostermanager.set_contact_pending_in(node, host, from_bare) then
+					sessionmanager.send_to_available_resources(node, host, stanza);
+				end -- TODO else return error, unable to save
+			end
+		end
+	elseif stanza.attr.type == "unsubscribe" then
+		if rostermanager.process_inbound_unsubscribe(node, host, from_bare) then
+			rostermanager.roster_push(node, host, from_bare);
+		end
+	elseif stanza.attr.type == "subscribed" then
+		if rostermanager.process_inbound_subscription_approval(node, host, from_bare) then
+			rostermanager.roster_push(node, host, from_bare);
+		end
+	elseif stanza.attr.type == "unsubscribed" then
+		if rostermanager.process_inbound_subscription_cancellation(node, host, from_bare) then
+			rostermanager.roster_push(node, host, from_bare);
+		end
+	end -- discard any other type
+	stanza.attr.from, stanza.attr.to = st_from, st_to;
+end
+
+local function presence_handler(data)
+	local origin, stanza = data.origin, data.stanza;
+	local to = stanza.attr.to;
+	local node, host = jid_split(to);
+	local to_bare = jid_bare(to);
+	local from_bare = jid_bare(stanza.attr.from);
+	if origin.type == "c2s" then
+		if to ~= nil and not(origin.roster[to_bare] and (origin.roster[to_bare].subscription == "both" or origin.roster[to_bare].subscription == "from")) then -- directed presence
+			origin.directed = origin.directed or {};
+			origin.directed[to] = true;
+		end
+		if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" and stanza.attr.type ~= "error" then
+			handle_outbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza);
+		elseif not to then
+			handle_normal_presence(origin, stanza, core_route_stanza);
+		else
+			core_route_stanza(origin, stanza);
+		end
+	elseif (origin.type == "s2sin" or origin.type == "component") and hosts[host] then
+		if stanza.attr.type ~= nil and stanza.attr.type ~= "unavailable" and stanza.attr.type ~= "error" then
+			handle_inbound_presence_subscriptions_and_probes(origin, stanza, from_bare, to_bare, core_route_stanza);
+		else
+			core_route_stanza(origin, stanza);
+		end
+	end
+end
+
+local add_handler = require "core.eventmanager2".add_handler;
+local remove_handler = require "core.eventmanager2".remove_handler;
+
+add_handler(module:get_host().."/presence", presence_handler);
+module.unload = function()
+	remove_handler(module:get_host().."/presence", presence_handler);
+end
--- a/plugins/mod_roster.lua	Wed May 13 16:54:46 2009 +0100
+++ b/plugins/mod_roster.lua	Wed May 13 16:55:20 2009 +0100
@@ -23,6 +23,14 @@
 
 module:add_feature("jabber:iq:roster");
 
+local rosterver_stream_feature = st.stanza("ver", {xmlns="urn:xmpp:features:rosterver"}):tag("optional"):up();
+module:add_event_hook("stream-features", 
+		function (session, features)												
+			if session.username then
+				features:add_child(rosterver_stream_feature);
+			end
+		end);
+
 module:add_iq_handler("c2s", "jabber:iq:roster", 
 		function (session, stanza)
 			if stanza.tags[1].name == "query" then
--- a/prosody.cfg.lua.dist	Wed May 13 16:54:46 2009 +0100
+++ b/prosody.cfg.lua.dist	Wed May 13 16:55:20 2009 +0100
@@ -38,6 +38,7 @@
 	modules_enabled = {
 			-- Generally required
 				"roster"; -- Allow users to have a roster. Recommended ;)
+				"presence"; -- See and broadcast status changes to/from contacts
 				"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
 				"tls"; -- Add support for secure TLS on c2s/s2s connections
 				"dialback"; -- s2s dialback support
--- a/util/sasl.lua	Wed May 13 16:54:46 2009 +0100
+++ b/util/sasl.lua	Wed May 13 16:55:20 2009 +0100
@@ -26,8 +26,6 @@
 local type = type
 local error = error
 local print = print
-local idna_ascii = require "util.encodings".idna.to_ascii
-local idna_unicode = require "util.encodings".idna.to_unicode
 
 module "sasl"
 
--- a/util/serialization.lua	Wed May 13 16:54:46 2009 +0100
+++ b/util/serialization.lua	Wed May 13 16:55:20 2009 +0100
@@ -53,7 +53,7 @@
 		func(t, (o and "true" or "false"));
 	else
 		log("error", "cannot serialize a %s: %s", type(o), debug_traceback())
-		func(t, "nil,\n");
+		func(t, "nil");
 	end
 end