Skip to content

Instantly share code, notes, and snippets.

@legastero
Last active June 26, 2019 20:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save legastero/219702bc69724f2e1f03469954547235 to your computer and use it in GitHub Desktop.
Save legastero/219702bc69724f2e1f03469954547235 to your computer and use it in GitHub Desktop.
Experiment enabling presence broadcast controls in MUC
diff -r 5c9341a1b36f plugins/muc/mod_muc.lua
--- a/plugins/muc/mod_muc.lua Thu Jun 20 22:25:46 2019 +0200
+++ b/plugins/muc/mod_muc.lua Wed Jun 26 13:34:55 2019 -0700
@@ -86,6 +86,12 @@
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 @@
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 -r 5c9341a1b36f plugins/muc/muc.lib.lua
--- a/plugins/muc/muc.lib.lua Thu Jun 20 22:25:46 2019 +0200
+++ b/plugins/muc/muc.lib.lua Wed Jun 26 13:34:55 2019 -0700
@@ -217,13 +217,13 @@
-- 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";};
@@ -279,6 +279,8 @@
self_p = st.clone(base_presence):add_child(self_x);
end
+ local broadcast_roles = self:get_presence_broadcast();
+
-- General populance
for occupant_nick, n_occupant in self:each_occupant() do
if occupant_nick ~= occupant.nick then
@@ -290,7 +292,13 @@
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
@@ -314,6 +322,7 @@
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
@@ -330,7 +339,9 @@
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
@@ -1410,9 +1421,11 @@
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; nick = occupant.nick; occupant = occupant;});
end
diff -r 5c9341a1b36f plugins/muc/presence_broadcast.lib.lua
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/muc/presence_broadcast.lib.lua Wed Jun 26 13:34:55 2019 -0700
@@ -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, 90-3);
+
+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;
+};
@Zash
Copy link

Zash commented Apr 2, 2019

Nice!

Some small issues I notice:

for role of ipairs(valid_roles) do

ITYM for ... in ... do

value = options;

Should be values?

@legastero
Copy link
Author

I've been working with too much javascript. 😬

Updated to fix luacheck errors.

@Zash
Copy link

Zash commented Jun 26, 2019

diff -r 4810d636d380

I don't have this revision, could be why I'm having trouble applying the patch.

@legastero
Copy link
Author

That should be updated to apply to latest 0.11 rev now (5c9341a1b36f)

@legastero
Copy link
Author

Ugh, never mind. Messed up generating new patch. Will get this cleaned up. 😭

@legastero
Copy link
Author

Ok, there we go. All cleaned up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment