aboutsummaryrefslogtreecommitdiffstats
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/mod_admin_adhoc.lua20
-rw-r--r--plugins/mod_admin_shell.lua21
-rw-r--r--plugins/mod_authz_internal.lua2
-rw-r--r--plugins/mod_bookmarks.lua15
-rw-r--r--plugins/mod_csi.lua4
-rw-r--r--plugins/mod_http_file_share.lua4
-rw-r--r--plugins/mod_invites_adhoc.lua30
-rw-r--r--plugins/mod_pubsub/mod_pubsub.lua23
-rw-r--r--plugins/mod_pubsub/pubsub.lib.lua56
-rw-r--r--plugins/mod_s2s.lua30
-rw-r--r--plugins/mod_smacks.lua12
-rw-r--r--plugins/muc/hats.lib.lua2
-rw-r--r--plugins/muc/muc.lib.lua10
13 files changed, 146 insertions, 83 deletions
diff --git a/plugins/mod_admin_adhoc.lua b/plugins/mod_admin_adhoc.lua
index ee26b7e5..ca84f975 100644
--- a/plugins/mod_admin_adhoc.lua
+++ b/plugins/mod_admin_adhoc.lua
@@ -592,15 +592,15 @@ end, function(fields, err, data)
return generate_error_message(err);
end
local ok_list, err_list = {}, {};
- for _, module in ipairs(fields.modules) do
- local ok, err = modulemanager.reload(module_host, module);
+ for _, module_ in ipairs(fields.modules) do
+ local ok, err = modulemanager.reload(module_host, module_);
if ok then
- ok_list[#ok_list + 1] = module;
+ ok_list[#ok_list + 1] = module_;
else
- err_list[#err_list + 1] = module .. "(Error: " .. tostring(err) .. ")";
+ err_list[#err_list + 1] = module_ .. "(Error: " .. tostring(err) .. ")";
end
+ module:log("info", "mod_%s reloaded by %s", module_, jid.bare(data.from));
end
- module:log("info", "mod_%s reloaded by %s", fields.module, jid.bare(data.from));
local info = (#ok_list > 0 and ("The following modules were successfully reloaded on host "..module_host..":\n"..t_concat(ok_list, "\n")) or "")
.. ((#ok_list > 0 and #err_list > 0) and "\n" or "") ..
(#err_list > 0 and ("Failed to reload the following modules on host "..module_host..":\n"..t_concat(err_list, "\n")) or "");
@@ -742,15 +742,15 @@ end, function(fields, err, data)
return generate_error_message(err);
end
local ok_list, err_list = {}, {};
- for _, module in ipairs(fields.modules) do
- local ok, err = modulemanager.unload(module_host, module);
+ for _, module_ in ipairs(fields.modules) do
+ local ok, err = modulemanager.unload(module_host, module_);
if ok then
- ok_list[#ok_list + 1] = module;
+ ok_list[#ok_list + 1] = module_;
else
- err_list[#err_list + 1] = module .. "(Error: " .. tostring(err) .. ")";
+ err_list[#err_list + 1] = module_ .. "(Error: " .. tostring(err) .. ")";
end
+ module:log("info", "mod_%s unloaded by %s", module_, jid.bare(data.from));
end
- module:log("info", "mod_%s unloaded by %s", fields.module, jid.bare(data.from));
local info = (#ok_list > 0 and ("The following modules were successfully unloaded on host "..module_host..":\n"..t_concat(ok_list, "\n")) or "")
.. ((#ok_list > 0 and #err_list > 0) and "\n" or "") ..
(#err_list > 0 and ("Failed to unload the following modules on host "..module_host..":\n"..t_concat(err_list, "\n")) or "");
diff --git a/plugins/mod_admin_shell.lua b/plugins/mod_admin_shell.lua
index e6b44f00..0b8d3c43 100644
--- a/plugins/mod_admin_shell.lua
+++ b/plugins/mod_admin_shell.lua
@@ -631,6 +631,7 @@ describe_command [[module:load(module, host) - Load the specified module on the
function def_env.module:load(name, hosts)
hosts = get_hosts_with_module(hosts);
+ local already_loaded = set.new();
-- Load the module for each host
local ok, err, count, mod = true, nil, 0;
for host in hosts do
@@ -655,10 +656,18 @@ function def_env.module:load(name, hosts)
self.session.print("Note: Module will not be loaded after restart unless enabled in configuration");
end
end
+ else
+ already_loaded:add(host);
end
end
- return ok, (ok and "Module loaded onto "..count.." host"..(count ~= 1 and "s" or "")) or ("Last error: "..tostring(err));
+ if not ok then
+ return ok, "Last error: "..tostring(err);
+ end
+ if already_loaded == hosts then
+ return ok, "Module already loaded";
+ end
+ return ok, "Module loaded onto "..count.." host"..(count ~= 1 and "s" or "");
end
describe_command [[module:unload(module, host) - The same, but just unloads the module from memory]]
@@ -1770,7 +1779,11 @@ function def_env.user:setrole(jid, host, new_role)
elseif prosody.hosts[userhost] and not um.user_exists(username, userhost) then
return nil, "No such user";
end
- return um.set_user_role(username, host, new_role);
+ if userhost == host then
+ return um.set_user_role(username, userhost, new_role);
+ else
+ return um.set_jid_role(jid, host, new_role);
+ end
end
describe_command [[user:addrole(jid, host, role) - Add a secondary role to a user]]
@@ -1781,6 +1794,8 @@ function def_env.user:addrole(jid, host, new_role)
return nil, "No such host: "..host;
elseif prosody.hosts[userhost] and not um.user_exists(username, userhost) then
return nil, "No such user";
+ elseif userhost ~= host then
+ return nil, "Can't add roles outside users own host"
end
return um.add_user_secondary_role(username, host, new_role);
end
@@ -1793,6 +1808,8 @@ function def_env.user:delrole(jid, host, role_name)
return nil, "No such host: "..host;
elseif prosody.hosts[userhost] and not um.user_exists(username, userhost) then
return nil, "No such user";
+ elseif userhost ~= host then
+ return nil, "Can't remove roles outside users own host"
end
return um.remove_user_secondary_role(username, host, role_name);
end
diff --git a/plugins/mod_authz_internal.lua b/plugins/mod_authz_internal.lua
index 96324734..07091a04 100644
--- a/plugins/mod_authz_internal.lua
+++ b/plugins/mod_authz_internal.lua
@@ -265,7 +265,7 @@ function get_jid_role(jid)
end
function set_jid_role(jid, role_name) -- luacheck: ignore 212
- return false;
+ return false, "not-implemented";
end
function get_jids_with_role(role_name)
diff --git a/plugins/mod_bookmarks.lua b/plugins/mod_bookmarks.lua
index be665d0f..e6e74f56 100644
--- a/plugins/mod_bookmarks.lua
+++ b/plugins/mod_bookmarks.lua
@@ -167,10 +167,15 @@ local function publish_to_pep(jid, bookmarks, synchronise)
if synchronise then
-- If we set zero legacy bookmarks, purge the bookmarks 2 node.
module:log("debug", "No bookmark in the set, purging instead.");
- return service:purge(namespace, jid, true);
- else
- return true;
+ local ok, err = service:purge(namespace, jid, true);
+ -- It's okay if no node exists when purging, user has
+ -- no bookmarks anyway.
+ if not ok and err ~= "item-not-found" then
+ module:log("error", "Failed to clear items from bookmarks 2 node: %s", err);
+ return ok, err;
+ end
end
+ return true;
end
-- Retrieve the current bookmarks2.
@@ -309,7 +314,7 @@ local function on_publish_legacy_pep(event)
local ok, err = publish_to_pep(session.full_jid, bookmarks, true);
if not ok then
- module:log("error", "Failed to publish to PEP bookmarks for %s@%s: %s", session.username, session.host, err);
+ module:log("error", "Failed to sync legacy bookmarks to PEP for %s@%s: %s", session.username, session.host, err);
session.send(st.error_reply(stanza, "cancel", "internal-server-error", "Failed to store bookmarks to PEP"));
return true;
end
@@ -335,7 +340,7 @@ local function on_publish_private_xml(event)
local ok, err = publish_to_pep(session.full_jid, bookmarks, true);
if not ok then
- module:log("error", "Failed to publish to PEP bookmarks for %s@%s: %s", session.username, session.host, err);
+ module:log("error", "Failed to sync private XML bookmarks to PEP for %s@%s: %s", session.username, session.host, err);
session.send(st.error_reply(stanza, "cancel", "internal-server-error", "Failed to store bookmarks to PEP"));
return true;
end
diff --git a/plugins/mod_csi.lua b/plugins/mod_csi.lua
index 73c081b1..76a5afd4 100644
--- a/plugins/mod_csi.lua
+++ b/plugins/mod_csi.lua
@@ -34,9 +34,9 @@ module:hook_global("stats-update", function()
if session.state == "inactive" then
inactive = inactive + 1;
elseif session.state == "active" then
- inactive = inactive + 1;
+ active = active + 1;
elseif session.state == "flushing" then
- inactive = inactive + 1;
+ flushing = flushing + 1;
end
end
end
diff --git a/plugins/mod_http_file_share.lua b/plugins/mod_http_file_share.lua
index cfc647d4..48972067 100644
--- a/plugins/mod_http_file_share.lua
+++ b/plugins/mod_http_file_share.lua
@@ -79,12 +79,12 @@ local measure_upload_cache_size = module:measure("upload_cache", "amount");
local measure_quota_cache_size = module:measure("quota_cache", "amount");
local measure_total_storage_usage = module:measure("total_storage", "amount", { unit = "bytes" });
-module:on_ready(function ()
+do
local total, err = persist_stats:get(nil, "total");
if not err then
total_storage_usage = tonumber(total) or 0;
end
-end)
+end
module:hook_global("stats-update", function ()
measure_upload_cache_size(upload_cache:count());
diff --git a/plugins/mod_invites_adhoc.lua b/plugins/mod_invites_adhoc.lua
index c9954d8c..3ef4116d 100644
--- a/plugins/mod_invites_adhoc.lua
+++ b/plugins/mod_invites_adhoc.lua
@@ -2,6 +2,7 @@
local dataforms = require "prosody.util.dataforms";
local datetime = require "prosody.util.datetime";
local split_jid = require "prosody.util.jid".split;
+local adhocutil = require "prosody.util.adhoc";
local new_adhoc = module:require("adhoc").new;
@@ -98,3 +99,32 @@ module:provides("adhoc", new_adhoc("Create new account invite", "urn:xmpp:invite
};
};
end, "admin"));
+
+local password_reset_form = dataforms.new({
+ title = "Generate Password Reset Invite";
+ {
+ name = "accountjid";
+ type = "jid-single";
+ required = true;
+ label = "The XMPP ID for the account to generate a password reset invite for";
+ };
+});
+
+module:provides("adhoc", new_adhoc("Create password reset invite", "xmpp:prosody.im/mod_invites_adhoc#password-reset",
+ adhocutil.new_simple_form(password_reset_form,
+ function (fields, err)
+ if err then return { status = "completed"; error = { message = "Fill in the form correctly" } }; end
+ local username = split_jid(fields.accountjid);
+ local invite = invites.create_account_reset(username);
+ return {
+ status = "completed";
+ result = {
+ layout = invite_result_form;
+ values = {
+ uri = invite.uri;
+ url = invite.landing_page;
+ expire = datetime.datetime(invite.expires);
+ };
+ };
+ };
+ end), "admin"));
diff --git a/plugins/mod_pubsub/mod_pubsub.lua b/plugins/mod_pubsub/mod_pubsub.lua
index 4f83088a..c17d9e63 100644
--- a/plugins/mod_pubsub/mod_pubsub.lua
+++ b/plugins/mod_pubsub/mod_pubsub.lua
@@ -190,10 +190,22 @@ module:hook("host-disco-items", function (event)
end);
local admin_aff = module:get_option_enum("default_admin_affiliation", "owner", "publisher", "member", "outcast", "none");
+
module:default_permission("prosody:admin", ":service-admin");
-local function get_affiliation(jid)
+module:default_permission("prosody:admin", ":create-node");
+
+local function get_affiliation(jid, _, action)
local bare_jid = jid_bare(jid);
- if bare_jid == module.host or module:may(":service-admin", bare_jid) then
+ if bare_jid == module.host then
+ -- The host itself (i.e. local modules) is treated as an admin.
+ -- Check this first as to avoid sendig a host JID to :may()
+ return admin_aff;
+ end
+ if action == "create" and module:may(":create-node", bare_jid) then
+ -- Only one affiliation is allowed to create nodes by default
+ return "owner";
+ end
+ if module:may(":service-admin", bare_jid) then
return admin_aff;
end
end
@@ -244,6 +256,13 @@ function module.load()
broadcaster = simple_broadcast;
itemcheck = is_item_stanza;
check_node_config = check_node_config;
+ metadata_subset = {
+ "title";
+ "description";
+ "payload_type";
+ "access_model";
+ "publish_model";
+ };
get_affiliation = get_affiliation;
jid = module.host;
diff --git a/plugins/mod_pubsub/pubsub.lib.lua b/plugins/mod_pubsub/pubsub.lib.lua
index 8ae0a896..f4d44f36 100644
--- a/plugins/mod_pubsub/pubsub.lib.lua
+++ b/plugins/mod_pubsub/pubsub.lib.lua
@@ -1,4 +1,3 @@
-local t_unpack = table.unpack;
local time_now = os.time;
local jid_prep = require "prosody.util.jid".prep;
@@ -18,7 +17,7 @@ local _M = {};
local handlers = {};
_M.handlers = handlers;
-local pubsub_errors = {
+local pubsub_errors = errors.init("pubsub", xmlns_pubsub_errors, {
["conflict"] = { "cancel", "conflict" };
["invalid-jid"] = { "modify", "bad-request", nil, "invalid-jid" };
["jid-required"] = { "modify", "bad-request", nil, "jid-required" };
@@ -33,16 +32,13 @@ local pubsub_errors = {
["precondition-not-met"] = { "cancel", "conflict", nil, "precondition-not-met" };
["invalid-item"] = { "modify", "bad-request", "invalid item" };
["persistent-items-unsupported"] = { "cancel", "feature-not-implemented", nil, "persistent-items" };
-};
-local function pubsub_error_reply(stanza, error)
- local e = pubsub_errors[error];
- if not e and errors.is_err(error) then
- e = { error.type, error.condition, error.text, error.pubsub_condition };
- end
- local reply = st.error_reply(stanza, t_unpack(e, 1, 3));
- if e[4] then
- reply:tag(e[4], { xmlns = xmlns_pubsub_errors }):up();
+});
+local function pubsub_error_reply(stanza, error, context)
+ local err = pubsub_errors.wrap(error, context);
+ if error == "precondition-not-met" and type(context) == "table" and type(context.field) == "string" then
+ err.text = "Field does not match: " .. context.field;
end
+ local reply = st.error_reply(stanza, err);
return reply;
end
_M.pubsub_error_reply = pubsub_error_reply;
@@ -206,23 +202,28 @@ local node_metadata_form = dataform {
};
{
type = "text-single";
- name = "pubsub#title";
+ name = "title";
+ var = "pubsub#title";
};
{
type = "text-single";
- name = "pubsub#description";
+ name = "description";
+ var = "pubsub#description";
};
{
type = "text-single";
- name = "pubsub#type";
+ name = "payload_type";
+ var = "pubsub#type";
};
{
type = "text-single";
- name = "pubsub#access_model";
+ name = "access_model";
+ var = "pubsub#access_model";
};
{
type = "text-single";
- name = "pubsub#publish_model";
+ name = "publish_model";
+ var = "pubsub#publish_model";
};
};
_M.node_metadata_form = node_metadata_form;
@@ -294,27 +295,14 @@ end
function _M.handle_disco_info_node(event, service)
local stanza, reply, node = event.stanza, event.reply, event.node;
- local ok, ret = service:get_nodes(stanza.attr.from);
+ local ok, meta = service:get_node_metadata(node, stanza.attr.from);
if not ok then
- event.origin.send(pubsub_error_reply(stanza, ret));
- return true;
- end
- local node_obj = ret[node];
- if not node_obj then
- event.origin.send(pubsub_error_reply(stanza, "item-not-found"));
+ event.origin.send(pubsub_error_reply(stanza, meta));
return true;
end
event.exists = true;
reply:tag("identity", { category = "pubsub", type = "leaf" }):up();
- if node_obj.config then
- reply:add_child(node_metadata_form:form({
- ["pubsub#title"] = node_obj.config.title;
- ["pubsub#description"] = node_obj.config.description;
- ["pubsub#type"] = node_obj.config.payload_type;
- ["pubsub#access_model"] = node_obj.config.access_model;
- ["pubsub#publish_model"] = node_obj.config.publish_model;
- }, "result"));
- end
+ reply:add_child(node_metadata_form:form(meta, "result"));
end
function _M.handle_disco_items_node(event, service)
@@ -685,7 +673,7 @@ function handlers.set_publish(origin, stanza, publish, service)
if item then
item.attr.publisher = service.config.normalize_jid(stanza.attr.from);
end
- local ok, ret = service:publish(node, stanza.attr.from, id, item, required_config);
+ local ok, ret, context = service:publish(node, stanza.attr.from, id, item, required_config);
local reply;
if ok then
if type(ok) == "string" then
@@ -696,7 +684,7 @@ function handlers.set_publish(origin, stanza, publish, service)
:tag("publish", { node = node })
:tag("item", { id = id });
else
- reply = pubsub_error_reply(stanza, ret);
+ reply = pubsub_error_reply(stanza, ret, context);
end
origin.send(reply);
return true;
diff --git a/plugins/mod_s2s.lua b/plugins/mod_s2s.lua
index 04fd5bc3..638ace3d 100644
--- a/plugins/mod_s2s.lua
+++ b/plugins/mod_s2s.lua
@@ -13,7 +13,6 @@ local hosts = prosody.hosts;
local core_process_stanza = prosody.core_process_stanza;
local tostring, type = tostring, type;
-local t_insert = table.insert;
local traceback = debug.traceback;
local add_task = require "prosody.util.timer".add_task;
@@ -33,6 +32,7 @@ local service = require "prosody.net.resolvers.service";
local resolver_chain = require "prosody.net.resolvers.chain";
local errors = require "prosody.util.error";
local set = require "prosody.util.set";
+local queue = require "prosody.util.queue";
local connect_timeout = module:get_option_period("s2s_timeout", 90);
local stream_close_timeout = module:get_option_period("s2s_close_timeout", 5);
@@ -42,6 +42,7 @@ local secure_domains, insecure_domains =
module:get_option_set("s2s_secure_domains", {})._items, module:get_option_set("s2s_insecure_domains", {})._items;
local require_encryption = module:get_option_boolean("s2s_require_encryption", true);
local stanza_size_limit = module:get_option_integer("s2s_stanza_size_limit", 1024*512, 10000);
+local sendq_size = module:get_option_integer("s2s_send_queue_size", 1024*32, 1);
local advertised_idle_timeout = 14*60; -- default in all net.server implementations
local network_settings = module:get_option("network_settings");
@@ -134,7 +135,7 @@ local bouncy_stanzas = { message = true, presence = true, iq = true };
local function bounce_sendq(session, reason)
local sendq = session.sendq;
if not sendq then return; end
- session.log("info", "Sending error replies for %d queued stanzas because of failed outgoing connection to %s", #sendq, session.to_host);
+ session.log("info", "Sending error replies for %d queued stanzas because of failed outgoing connection to %s", sendq.count(), session.to_host);
local dummy = {
type = "s2sin";
send = function ()
@@ -153,12 +154,12 @@ local function bounce_sendq(session, reason)
if session.had_stream then -- set when a stream is opened by the remote
error_type, condition = "wait", "remote-server-timeout";
end
- if errors.is_err(reason) then
+ if errors.is_error(reason) then
error_type, condition, reason_text = reason.type, reason.condition, reason.text;
elseif type(reason) == "string" then
reason_text = reason;
end
- for i, stanza in ipairs(sendq) do
+ for stanza in sendq:consume() do
if not stanza.attr.xmlns and bouncy_stanzas[stanza.name] and stanza.attr.type ~= "error" and stanza.attr.type ~= "result" then
local reply = st.error_reply(
stanza,
@@ -170,7 +171,6 @@ local function bounce_sendq(session, reason)
else
(session.log or log)("debug", "Not eligible for bouncing, discarding %s", stanza:top_tag());
end
- sendq[i] = nil;
end
session.sendq = nil;
end
@@ -194,11 +194,14 @@ function route_to_existing_session(event)
(host.log or log)("debug", "trying to send over unauthed s2sout to "..to_host);
-- Queue stanza until we are able to send it
- if host.sendq then
- t_insert(host.sendq, st.clone(stanza));
- else
+ if not host.sendq then
-- luacheck: ignore 122
- host.sendq = { st.clone(stanza) };
+ host.sendq = queue.new(sendq_size);
+ end
+ if not host.sendq:push(st.clone(stanza)) then
+ host.log("warn", "stanza [%s] not queued ", stanza.name);
+ event.origin.send(st.error_reply(stanza, "wait", "resource-constraint", "Outgoing stanza queue full"));
+ return true;
end
host.log("debug", "stanza [%s] queued ", stanza.name);
return true;
@@ -223,7 +226,8 @@ function route_to_new_session(event)
-- Store in buffer
host_session.bounce_sendq = bounce_sendq;
- host_session.sendq = { st.clone(stanza) };
+ host_session.sendq = queue.new(sendq_size);
+ host_session.sendq:push(st.clone(stanza));
log("debug", "stanza [%s] queued until connection complete", stanza.name);
-- FIXME Cleaner solution to passing extra data from resolvers to net.server
-- This mt-clone allows resolvers to add extra data, currently used for DANE TLSA records
@@ -362,11 +366,11 @@ function mark_connected(session)
if session.direction == "outgoing" then
if sendq then
- session.log("debug", "sending %d queued stanzas across new outgoing connection to %s", #sendq, session.to_host);
+ session.log("debug", "sending %d queued stanzas across new outgoing connection to %s", sendq.count(), session.to_host);
local send = session.sends2s;
- for i, stanza in ipairs(sendq) do
+ for stanza in sendq:consume() do
+ -- TODO check send success
send(stanza);
- sendq[i] = nil;
end
session.sendq = nil;
end
diff --git a/plugins/mod_smacks.lua b/plugins/mod_smacks.lua
index d4f0f371..7a9a67b3 100644
--- a/plugins/mod_smacks.lua
+++ b/plugins/mod_smacks.lua
@@ -541,11 +541,13 @@ module:hook("pre-resource-unbind", function (event)
return
end
- session.log("debug", "Destroying session for hibernating too long");
- save_old_session(session);
- session.resumption_token = nil;
- sessionmanager.destroy_session(session, "Hibernating too long");
- sessions_expired(1);
+ prosody.main_thread:run(function ()
+ session.log("debug", "Destroying session for hibernating too long");
+ save_old_session(session);
+ session.resumption_token = nil;
+ sessionmanager.destroy_session(session, "Hibernating too long");
+ sessions_expired(1);
+ end);
end);
if session.conn then
local conn = session.conn;
diff --git a/plugins/muc/hats.lib.lua b/plugins/muc/hats.lib.lua
index 492dc72c..7eb71eb4 100644
--- a/plugins/muc/hats.lib.lua
+++ b/plugins/muc/hats.lib.lua
@@ -25,7 +25,7 @@ module:hook("muc-build-occupant-presence", function (event)
hats_el:tag("hat", { uri = hat_id, title = hat_data.title }):up();
if hats_compat then
- if not hats_el then
+ if not legacy_hats_el then
legacy_hats_el = st.stanza("hats", { xmlns = xmlns_hats_legacy });
end
legacy_hats_el:tag("hat", { uri = hat_id, title = hat_data.title }):up();
diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua
index b8f276cf..359afc87 100644
--- a/plugins/muc/muc.lib.lua
+++ b/plugins/muc/muc.lib.lua
@@ -304,10 +304,10 @@ function room_mt:publicise_occupant_status(occupant, x, nick, actor, reason, pre
-- General populace
for occupant_nick, n_occupant in self:each_occupant() do
if occupant_nick ~= occupant.nick then
- local pr = get_p(n_occupant);
if broadcast_roles[occupant.role or "none"] or force_unavailable then
- self:route_to_occupant(n_occupant, pr);
+ self:route_to_occupant(n_occupant, get_p(n_occupant));
elseif prev_role and broadcast_roles[prev_role] then
+ local pr = get_p(n_occupant);
pr.attr.type = 'unavailable';
self:route_to_occupant(n_occupant, pr);
end
@@ -339,16 +339,14 @@ function room_mt:send_occupant_list(to, filter)
local broadcast_bare_jids = {}; -- Track which bare JIDs we have sent presence for
for occupant_jid, occupant in self:each_occupant() do
broadcast_bare_jids[occupant.bare_jid] = true;
- if filter == nil or filter(occupant_jid, occupant) then
+ if (filter == nil or filter(occupant_jid, occupant)) and (to_bare == occupant.bare_jid or broadcast_roles[occupant.role or "none"]) then
local x = st.stanza("x", {xmlns='http://jabber.org/protocol/muc#user'});
self:build_item_list(occupant, x, is_anonymous and to_bare ~= occupant.bare_jid); -- can always see your own jids
local pres = st.clone(occupant:get_presence());
pres.attr.to = to;
pres:add_child(x);
module:fire_event("muc-build-occupant-presence", { room = self, occupant = occupant, stanza = pres });
- if to_bare == occupant.bare_jid or broadcast_roles[occupant.role or "none"] then
- self:route_stanza(pres);
- end
+ self:route_stanza(pres);
end
end
if broadcast_roles.none then