aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLance Stout <lancestout@gmail.com>2019-10-20 21:58:16 +0200
committerLance Stout <lancestout@gmail.com>2019-10-20 21:58:16 +0200
commit190c1e7772fe11c353ce0c0e001490e29734a63a (patch)
tree5969220742b0ca10b2b71b5a3c95d177f7b9f895
parent9889cb8bb4c614939a4a82624b0e7e3539b80b63 (diff)
downloadprosody-190c1e7772fe11c353ce0c0e001490e29734a63a.tar.gz
prosody-190c1e7772fe11c353ce0c0e001490e29734a63a.zip
MUC: Add controls for whose presence is broadcast (closes #1335)
Committed by Zash
-rw-r--r--plugins/muc/mod_muc.lua7
-rw-r--r--plugins/muc/muc.lib.lua23
-rw-r--r--plugins/muc/presence_broadcast.lib.lua87
3 files changed, 112 insertions, 5 deletions
diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua
index 89e67744..e55bd6a2 100644
--- a/plugins/muc/mod_muc.lua
+++ b/plugins/muc/mod_muc.lua
@@ -86,6 +86,12 @@ room_mt.get_registered_nick = register.get_registered_nick;
room_mt.get_registered_jid = register.get_registered_jid;
room_mt.handle_register_iq = register.handle_register_iq;
+local presence_broadcast = module:require "muc/presence_broadcast";
+room_mt.get_presence_broadcast = presence_broadcast.get;
+room_mt.set_presence_broadcast = presence_broadcast.set;
+room_mt.get_valid_broadcast_roles = presence_broadcast.get_valid_broadcast_roles;
+
+
local jid_split = require "util.jid".split;
local jid_bare = require "util.jid".bare;
local st = require "util.stanza";
@@ -263,6 +269,7 @@ local function set_room_defaults(room, lang)
room:set_changesubject(module:get_option_boolean("muc_room_default_change_subject", room:get_changesubject()));
room:set_historylength(module:get_option_number("muc_room_default_history_length", room:get_historylength()));
room:set_language(lang or module:get_option_string("muc_room_default_language"));
+ room:set_presence_broadcast(module:get_option("muc_room_default_presence_broadcast", room:get_presence_broadcast()));
end
function create_room(room_jid, config)
diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua
index d84f4ac1..200f69f9 100644
--- a/plugins/muc/muc.lib.lua
+++ b/plugins/muc/muc.lib.lua
@@ -218,13 +218,13 @@ end
-- Broadcasts an occupant's presence to the whole room
-- Takes the x element that goes into the stanzas
-function room_mt:publicise_occupant_status(occupant, x, nick, actor, reason)
+function room_mt:publicise_occupant_status(occupant, x, nick, actor, reason, prev_role, force_unavailable)
local base_x = x.base or x;
-- Build real jid and (optionally) occupant jid template presences
local base_presence do
-- Try to use main jid's presence
local pr = occupant:get_presence();
- if pr and (occupant.role ~= nil or pr.attr.type == "unavailable") then
+ if pr and (occupant.role ~= nil or pr.attr.type == "unavailable") and not force_unavailable then
base_presence = st.clone(pr);
else -- user is leaving but didn't send a leave presence. make one for them
base_presence = st.presence {from = occupant.nick; type = "unavailable";};
@@ -280,6 +280,8 @@ function room_mt:publicise_occupant_status(occupant, x, nick, actor, reason)
self_p = st.clone(base_presence):add_child(self_x);
end
+ local broadcast_roles = self:get_presence_broadcast();
+
-- General populace
for occupant_nick, n_occupant in self:each_occupant() do
if occupant_nick ~= occupant.nick then
@@ -291,7 +293,13 @@ function room_mt:publicise_occupant_status(occupant, x, nick, actor, reason)
else
pr = get_anon_p();
end
- self:route_to_occupant(n_occupant, pr);
+ if broadcast_roles[occupant.role or "none"] or force_unavailable then
+ self:route_to_occupant(n_occupant, pr);
+ elseif prev_role and broadcast_roles[prev_role] then
+ pr.attr.type = 'unavailable';
+ self:route_to_occupant(n_occupant, pr);
+ end
+
end
end
@@ -315,6 +323,7 @@ function room_mt:send_occupant_list(to, filter)
local to_bare = jid_bare(to);
local is_anonymous = false;
local whois = self:get_whois();
+ local broadcast_roles = self:get_presence_broadcast();
if whois ~= "anyone" then
local affiliation = self:get_affiliation(to);
if affiliation ~= "admin" and affiliation ~= "owner" then
@@ -331,7 +340,9 @@ function room_mt:send_occupant_list(to, filter)
local pres = st.clone(occupant:get_presence());
pres.attr.to = to;
pres:add_child(x);
- self:route_stanza(pres);
+ if to_bare == occupant.bare_jid or broadcast_roles[occupant.role or "none"] then
+ self:route_stanza(pres);
+ end
end
end
end
@@ -1442,9 +1453,11 @@ function room_mt:set_role(actor, occupant_jid, role, reason)
if not role then
x:tag("status", {code = "307"}):up();
end
+
+ local prev_role = occupant.role;
occupant.role = role;
self:save_occupant(occupant);
- self:publicise_occupant_status(occupant, x, nil, actor, reason);
+ self:publicise_occupant_status(occupant, x, nil, actor, reason, prev_role);
if role == nil then
module:fire_event("muc-occupant-left", {
room = self;
diff --git a/plugins/muc/presence_broadcast.lib.lua b/plugins/muc/presence_broadcast.lib.lua
new file mode 100644
index 00000000..ace614b3
--- /dev/null
+++ b/plugins/muc/presence_broadcast.lib.lua
@@ -0,0 +1,87 @@
+-- Prosody IM
+-- Copyright (C) 2008-2010 Matthew Wild
+-- Copyright (C) 2008-2010 Waqas Hussain
+-- Copyright (C) 2014 Daurnimator
+--
+-- This project is MIT/X11 licensed. Please see the
+-- COPYING file in the source package for more information.
+--
+
+local st = require "util.stanza";
+
+local valid_roles = { "visitor", "participant", "moderator" };
+local default_broadcast = {
+ none = true;
+ visitor = true;
+ participant = true;
+ moderator = true;
+};
+
+local function get_presence_broadcast(room)
+ return room._data.presence_broadcast or default_broadcast;
+end
+
+local function set_presence_broadcast(room, broadcast_roles)
+ broadcast_roles = broadcast_roles or default_broadcast;
+
+ -- Ensure that unavailable presence is always sent when role changes to none
+ broadcast_roles.none = true;
+
+ local changed = false;
+ local old_broadcast_roles = get_presence_broadcast(room);
+ for _, role in ipairs(valid_roles) do
+ if old_broadcast_roles[role] ~= broadcast_roles[role] then
+ changed = true;
+ end
+ end
+
+ if not changed then return false; end
+
+ room._data.presence_broadcast = broadcast_roles;
+
+ for _, occupant in room:each_occupant() do
+ local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user";});
+ local role = occupant.role or "none";
+ if broadcast_roles[role] and not old_broadcast_roles[role] then
+ -- Presence broadcast is now enabled, so announce existing user
+ room:publicise_occupant_status(occupant, x);
+ elseif old_broadcast_roles[role] and not broadcast_roles[role] then
+ -- Presence broadcast is now disabled, so mark existing user as unavailable
+ room:publicise_occupant_status(occupant, x, nil, nil, nil, nil, true);
+ end
+ end
+
+ return true;
+end
+
+module:hook("muc-config-form", function(event)
+ local values = {};
+ for role, value in pairs(get_presence_broadcast(event.room)) do
+ if value then
+ values[#values + 1] = role;
+ end
+ end
+
+ table.insert(event.form, {
+ name = "muc#roomconfig_presencebroadcast";
+ type = "list-multi";
+ label = "Roles for which Presence is Broadcasted";
+ value = values;
+ options = valid_roles;
+ });
+end, 70-7);
+
+module:hook("muc-config-submitted/muc#roomconfig_presencebroadcast", function(event)
+ local broadcast_roles = {};
+ for _, role in ipairs(event.value) do
+ broadcast_roles[role] = true;
+ end
+ if set_presence_broadcast(event.room, broadcast_roles) then
+ event.status_codes["104"] = true;
+ end
+end);
+
+return {
+ get = get_presence_broadcast;
+ set = set_presence_broadcast;
+};