Skip to content

Instantly share code, notes, and snippets.

@legastero
Last active June 26, 2019 20:35
Show Gist options
  • Select an option

  • Save legastero/219702bc69724f2e1f03469954547235 to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown

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
Copy Markdown
Author

I've been working with too much javascript. 😬

Updated to fix luacheck errors.

@Zash
Copy link
Copy Markdown

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
Copy Markdown
Author

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

@legastero
Copy link
Copy Markdown
Author

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

@legastero
Copy link
Copy Markdown
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