aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/componentmanager.lua3
-rw-r--r--core/eventmanager2.lua6
-rw-r--r--core/stanza_router.lua13
-rw-r--r--fallbacks/bit.lua137
-rw-r--r--net/http.lua4
-rw-r--r--net/server.lua4
-rw-r--r--net/xmppclient_listener.lua6
-rw-r--r--net/xmppserver_listener.lua7
-rw-r--r--plugins/mod_bosh.lua1
-rw-r--r--plugins/mod_muc.lua65
-rw-r--r--plugins/mod_pep.lua48
-rw-r--r--plugins/mod_presence.lua279
-rw-r--r--plugins/mod_roster.lua8
-rw-r--r--prosody.cfg.lua.dist1
-rw-r--r--util/sasl.lua2
-rw-r--r--util/serialization.lua2
16 files changed, 539 insertions, 47 deletions
diff --git a/core/componentmanager.lua b/core/componentmanager.lua
index 93e2ae7b..d76b7849 100644
--- a/core/componentmanager.lua
+++ b/core/componentmanager.lua
@@ -80,8 +80,7 @@ end
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)
diff --git a/core/eventmanager2.lua b/core/eventmanager2.lua
new file mode 100644
index 00000000..4783d0a9
--- /dev/null
+++ b/core/eventmanager2.lua
@@ -0,0 +1,6 @@
+
+local events = require "util.events".new();
+
+module "eventmanager"
+
+return events;
diff --git a/core/stanza_router.lua b/core/stanza_router.lua
index 29840d76..eb5bf410 100644
--- a/core/stanza_router.lua
+++ b/core/stanza_router.lua
@@ -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 s2s_make_authenticated = require "core.s2smanager".make_authenticated;
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 ipairs = ipairs;
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 @@ function core_process_stanza(origin, stanza)
-- 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 @@ end
-- 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
diff --git a/fallbacks/bit.lua b/fallbacks/bit.lua
new file mode 100644
index 00000000..86e3b4a4
--- /dev/null
+++ b/fallbacks/bit.lua
@@ -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;
diff --git a/net/http.lua b/net/http.lua
index 0910944e..b39cc6fb 100644
--- a/net/http.lua
+++ b/net/http.lua
@@ -9,8 +9,8 @@ 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 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
diff --git a/net/server.lua b/net/server.lua
index b2b19c70..9e42b8ff 100644
--- a/net/server.lua
+++ b/net/server.lua
@@ -791,7 +791,7 @@ local wrapclient = function( socket, ip, serverport, listeners, pattern, sslctx,
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 @@ local addclient = function( address, port, listeners, pattern, sslctx, startssl
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
diff --git a/net/xmppclient_listener.lua b/net/xmppclient_listener.lua
index 44852834..dbb87b91 100644
--- a/net/xmppclient_listener.lua
+++ b/net/xmppclient_listener.lua
@@ -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_concat = table.concat;
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",
diff --git a/net/xmppserver_listener.lua b/net/xmppserver_listener.lua
index 0216e8dc..ddfb185e 100644
--- a/net/xmppserver_listener.lua
+++ b/net/xmppserver_listener.lua
@@ -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_concat = table.concat;
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" };
diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua
index 5aa8ff34..46e9a95f 100644
--- a/plugins/mod_bosh.lua
+++ b/plugins/mod_bosh.lua
@@ -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";
diff --git a/plugins/mod_muc.lua b/plugins/mod_muc.lua
index ffa0bb85..38f21b4a 100644
--- a/plugins/mod_muc.lua
+++ b/plugins/mod_muc.lua
@@ -205,6 +205,34 @@ function broadcast_presence_stanza(room, stanza, code, nick)
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 @@ function handle_to_occupant(origin, stanza) -- PM, vCards, etc
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 @@ function handle_to_occupant(origin, stanza) -- PM, vCards, etc
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 @@ function handle_to_occupant(origin, stanza) -- PM, vCards, etc
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
diff --git a/plugins/mod_pep.lua b/plugins/mod_pep.lua
new file mode 100644
index 00000000..438b077d
--- /dev/null
+++ b/plugins/mod_pep.lua
@@ -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);
+
diff --git a/plugins/mod_presence.lua b/plugins/mod_presence.lua
new file mode 100644
index 00000000..2fb976b5
--- /dev/null
+++ b/plugins/mod_presence.lua
@@ -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
diff --git a/plugins/mod_roster.lua b/plugins/mod_roster.lua
index e30bc1f9..554ef2e5 100644
--- a/plugins/mod_roster.lua
+++ b/plugins/mod_roster.lua
@@ -23,6 +23,14 @@ local core_route_stanza = core_route_stanza;
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
diff --git a/prosody.cfg.lua.dist b/prosody.cfg.lua.dist
index dc636192..c945e343 100644
--- a/prosody.cfg.lua.dist
+++ b/prosody.cfg.lua.dist
@@ -38,6 +38,7 @@ Host "*"
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
diff --git a/util/sasl.lua b/util/sasl.lua
index 2740b427..a36aa9ca 100644
--- a/util/sasl.lua
+++ b/util/sasl.lua
@@ -26,8 +26,6 @@ local math = require "math"
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"
diff --git a/util/serialization.lua b/util/serialization.lua
index 4da811ae..1ffd3e16 100644
--- a/util/serialization.lua
+++ b/util/serialization.lua
@@ -53,7 +53,7 @@ local function _simplesave(o, ind, t, func)
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