aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/componentmanager.lua4
-rw-r--r--core/modulemanager.lua57
-rw-r--r--core/stanza_router.lua7
-rw-r--r--plugins/muc/muc.lib.lua58
4 files changed, 79 insertions, 47 deletions
diff --git a/core/componentmanager.lua b/core/componentmanager.lua
index 2d292c8f..833b1fc0 100644
--- a/core/componentmanager.lua
+++ b/core/componentmanager.lua
@@ -67,6 +67,7 @@ function handle_stanza(origin, stanza)
component(origin, stanza, hosts[host]);
else
log("error", "Component manager recieved a stanza for a non-existing component: "..tostring(stanza));
+ default_component_handler(origin, stanza);
end
end
@@ -113,6 +114,7 @@ end
function deregister_component(host)
if components[host] then
+ modulemanager.unload(host, "tls");
modulemanager.unload(host, "dialback");
hosts[host].connected = nil;
local host_config = configmanager.getconfig()[host];
@@ -121,7 +123,7 @@ function deregister_component(host)
components[host] = default_component_handler;
else
-- Component not in config, or disabled, remove
- hosts[host] = nil;
+ hosts[host] = nil; -- FIXME do proper unload of all modules and other cleanup before removing
components[host] = nil;
end
-- remove from disco_items
diff --git a/core/modulemanager.lua b/core/modulemanager.lua
index 312ca738..88d07f43 100644
--- a/core/modulemanager.lua
+++ b/core/modulemanager.lua
@@ -65,9 +65,11 @@ function load_modules_for_host(host)
end
-- Load auto-loaded modules for this host
- for _, module in ipairs(autoload_modules) do
- if not disabled_set[module] then
- load(host, module);
+ if hosts[host].type == "local" then
+ for _, module in ipairs(autoload_modules) do
+ if not disabled_set[module] then
+ load(host, module);
+ end
end
end
@@ -104,7 +106,6 @@ function load(host, module_name, config)
if not modulemap[host] then
modulemap[host] = {};
- hosts[host].modules = modulemap[host];
end
if modulemap[host][module_name] then
@@ -127,29 +128,39 @@ function load(host, module_name, config)
local pluginenv = setmetatable({ module = api_instance }, { __index = _G });
setfenv(mod, pluginenv);
- if not hosts[host] then hosts[host] = { type = "component", host = host, connected = false, s2sout = {} }; end
-
- local success, ret = pcall(mod);
- if not success then
- log("error", "Error initialising module '%s': %s", module_name or "nil", ret or "nil");
- return nil, ret;
+ if not hosts[host] then
+ local create_component = _G.require "core.componentmanager".create_component;
+ hosts[host] = create_component(host);
+ hosts[host].connected = false;
+ log("debug", "Created new component: %s", host);
end
+ hosts[host].modules = modulemap[host];
+ modulemap[host][module_name] = pluginenv;
- if module_has_method(pluginenv, "load") then
- local ok, err = call_module_method(pluginenv, "load");
- if (not ok) and err then
- log("warn", "Error loading module '%s' on '%s': %s", module_name, host, err);
+ local success, err = pcall(mod);
+ if success then
+ if module_has_method(pluginenv, "load") then
+ success, err = call_module_method(pluginenv, "load");
+ if not success then
+ log("warn", "Error loading module '%s' on '%s': %s", module_name, host, err or "nil");
+ end
end
- end
- -- Use modified host, if the module set one
- modulemap[api_instance.host][module_name] = pluginenv;
-
- if api_instance.host == "*" and host ~= "*" then
- api_instance:set_global();
+ -- Use modified host, if the module set one
+ if api_instance.host == "*" and host ~= "*" then
+ modulemap[host][module_name] = nil;
+ modulemap["*"][module_name] = pluginenv;
+ api_instance:set_global();
+ end
+ else
+ log("error", "Error initializing module '%s' on '%s': %s", module_name, host, err or "nil");
+ end
+ if success then
+ return true;
+ else -- load failed, unloading
+ unload(api_instance.host, module_name);
+ return nil, err;
end
-
- return true;
end
function get_module(host, name)
@@ -170,7 +181,6 @@ function unload(host, name, ...)
log("warn", "Non-fatal error unloading module '%s' on '%s': %s", name, host, err);
end
end
- modulemap[host][name] = nil;
local params = handler_table:get(host, name); -- , {module.host, origin_type, tag, xmlns}
for _, param in pairs(params or NULL) do
local handlers = stanza_handlers:get(param[1], param[2], param[3], param[4]);
@@ -187,6 +197,7 @@ function unload(host, name, ...)
end
end
hooks:remove(host, name);
+ modulemap[host][name] = nil;
return true;
end
diff --git a/core/stanza_router.lua b/core/stanza_router.lua
index ef4f3695..00c37ed7 100644
--- a/core/stanza_router.lua
+++ b/core/stanza_router.lua
@@ -29,13 +29,10 @@ function core_process_stanza(origin, stanza)
-- TODO verify validity of stanza (as well as JID validity)
if stanza.attr.type == "error" and #stanza.tags == 0 then return; end -- TODO invalid stanza, log
if stanza.name == "iq" then
- local can_reply = stanza.attr.type == "set" or stanza.attr.type == "get"
- local missing_id = not stanza.attr.id;
- if can_reply and (#stanza.tags ~= 1 or missing_id) then
+ if not stanza.attr.id then stanza.attr.id = ""; end -- COMPAT Jabiru doesn't send the id attribute on roster requests
+ if (stanza.attr.type == "set" or stanza.attr.type == "get") and (#stanza.tags ~= 1) then
origin.send(st.error_reply(stanza, "modify", "bad-request"));
return;
- elseif missing_id then
- return;
end
end
diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua
index 93706b07..7a8e3c8c 100644
--- a/plugins/muc/muc.lib.lua
+++ b/plugins/muc/muc.lib.lua
@@ -106,7 +106,7 @@ function room_mt:get_default_role(affiliation)
end
end
-function room_mt:broadcast_presence(stanza, code, nick)
+function room_mt:broadcast_presence(stanza, sid, code, nick)
stanza = get_filtered_presence(stanza);
local occupant = self._occupants[stanza.attr.from];
stanza:tag("x", {xmlns='http://jabber.org/protocol/muc#user'})
@@ -118,10 +118,8 @@ function room_mt:broadcast_presence(stanza, code, nick)
local me = self._occupants[stanza.attr.from];
if me then
stanza:tag("status", {code='110'});
- for jid in pairs(me.sessions) do
- stanza.attr.to = jid;
- self:route_stanza(stanza);
- end
+ stanza.attr.to = sid;
+ self:route_stanza(stanza);
end
end
function room_mt:broadcast_message(stanza, historic)
@@ -217,19 +215,26 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc
if current_nick then
log("debug", "%s leaving %s", current_nick, room);
local occupant = self._occupants[current_nick];
- local old_session = occupant.sessions[from];
local new_jid = next(occupant.sessions);
if new_jid == from then new_jid = next(occupant.sessions, new_jid); end
if new_jid then
+ local jid = occupant.jid;
occupant.jid = new_jid;
occupant.sessions[from] = nil;
- local pr = st.clone(occupant[new_jid])
- :tag("x", {xmlns='http://jabber.org/protocol/muc#user'})
- :tag("item", {affiliation=occupant.affiliation, role=occupant.role});
- self:broadcast_except_nick(pr, current_nick);
+ pr.attr.to = from;
+ pr:tag("x", {xmlns='http://jabber.org/protocol/muc#user'})
+ :tag("item", {affiliation=occupant.affiliation, role='none'}):up()
+ :tag("status", {code='110'});
+ self:route_stanza(pr);
+ if jid ~= new_jid then
+ pr = st.clone(occupant.sessions[new_jid])
+ :tag("x", {xmlns='http://jabber.org/protocol/muc#user'})
+ :tag("item", {affiliation=occupant.affiliation, role=occupant.role});
+ self:broadcast_except_nick(pr, current_nick);
+ end
else
occupant.role = 'none';
- self:broadcast_presence(pr);
+ self:broadcast_presence(pr, from);
self._occupants[current_nick] = nil;
end
self._jid_nick[from] = nil;
@@ -240,9 +245,11 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc
if current_nick == to then -- simple presence
log("debug", "%s broadcasted presence", current_nick);
self._occupants[current_nick].sessions[from] = pr;
- self:broadcast_presence(pr);
+ self:broadcast_presence(pr, from);
else -- change nick
- if self._occupants[to] then
+ local occupant = self._occupants[current_nick];
+ local is_multisession = next(occupant, next(occupant));
+ if self._occupants[to] or is_multisession then
log("debug", "%s couldn't change nick", current_nick);
local reply = st.error_reply(stanza, "cancel", "conflict"):up();
reply.tags[1].attr.code = "409";
@@ -253,13 +260,13 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc
if to_nick then
log("debug", "%s (%s) changing nick to %s", current_nick, data.jid, to);
local p = st.presence({type='unavailable', from=current_nick});
- self:broadcast_presence(p, '303', to_nick);
+ self:broadcast_presence(p, from, '303', to_nick);
self._occupants[current_nick] = nil;
self._occupants[to] = data;
self._jid_nick[from] = to;
pr.attr.from = to;
self._occupants[to].sessions[from] = pr;
- self:broadcast_presence(pr);
+ self:broadcast_presence(pr, from);
else
--TODO malformed-jid
end
@@ -273,8 +280,12 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc
--end
else -- enter room
local new_nick = to;
+ local is_merge;
if self._occupants[to] then
- new_nick = nil;
+ if jid_bare(from) ~= jid_bare(self._occupants[to].jid) then
+ new_nick = nil;
+ end
+ is_merge = true;
end
if not new_nick then
log("debug", "%s couldn't join due to nick conflict: %s", from, to);
@@ -289,11 +300,22 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc
local affiliation = self:get_affiliation(from);
local role = self:get_default_role(affiliation)
if role then -- new occupant
- self._occupants[to] = {affiliation=affiliation, role=role, jid=from, sessions={[from]=get_filtered_presence(stanza)}};
+ if not is_merge then
+ self._occupants[to] = {affiliation=affiliation, role=role, jid=from, sessions={[from]=get_filtered_presence(stanza)}};
+ else
+ self._occupants[to].sessions[from] = get_filtered_presence(stanza);
+ end
self._jid_nick[from] = to;
self:send_occupant_list(from);
pr.attr.from = to;
- self:broadcast_presence(pr);
+ if not is_merge then
+ self:broadcast_presence(pr, from);
+ else
+ pr.attr.to = from;
+ self:route_stanza(pr:tag("x", {xmlns='http://jabber.org/protocol/muc#user'})
+ :tag("item", {affiliation=affiliation, role=role}):up()
+ :tag("status", {code='110'}));
+ end
self:send_history(from);
else -- banned
local reply = st.error_reply(stanza, "auth", "forbidden"):up();