comparison plugins/muc/muc.lib.lua @ 13904:f8779be95156

MUC: Support for filtering presence broadcasts with per-session filters Currently no filters are defined, but could be added by modules (hint hint).
author Matthew Wild <mwild1@gmail.com>
date Mon, 11 Nov 2024 12:52:54 +0000
parents ccf389f54a93
children 0749265327d2
comparison
equal deleted inserted replaced
13903:4af7d00a2966 13904:f8779be95156
131 end 131 end
132 self._occupants[id] = occupant 132 self._occupants[id] = occupant
133 return occupant 133 return occupant
134 end 134 end
135 135
136 function room_mt:route_to_occupant(occupant, stanza) 136 function room_mt:route_to_occupant(occupant, stanza, session_filter)
137 local to = stanza.attr.to; 137 local to = stanza.attr.to;
138 for jid in occupant:each_session() do 138 for session_jid, session_pres, session_meta in occupant:each_session() do
139 stanza.attr.to = jid; 139 if session_filter then
140 self:route_stanza(stanza); 140 stanza = session_filter(session_jid, session_pres, session_meta, stanza);
141 end
142 if stanza then
143 stanza.attr.to = session_jid;
144 self:route_stanza(stanza);
145 end
146 end
147 stanza.attr.to = to;
148 end
149
150 function room_mt:route_presence_to_occupant(occupant, stanza)
151 local to = stanza.attr.to;
152 for jid, _, session_meta in occupant:each_session() do
153 if not session_meta.filter_presence then
154 stanza.attr.to = jid;
155 self:route_stanza(stanza);
156 end
141 end 157 end
142 stanza.attr.to = to; 158 stanza.attr.to = to;
143 end 159 end
144 160
145 -- actor is the attribute table 161 -- actor is the attribute table
295 end 311 end
296 return pr 312 return pr
297 end 313 end
298 314
299 if recipient then 315 if recipient then
300 return self:route_to_occupant(recipient, get_p(recipient)); 316 return self:route_presence_to_occupant(recipient, get_p(recipient));
301 end 317 end
302 318
303 local broadcast_roles = self:get_presence_broadcast(); 319 local broadcast_roles = self:get_presence_broadcast();
304 -- General populace 320 -- General populace
305 for occupant_nick, n_occupant in self:each_occupant() do 321 for occupant_nick, n_occupant in self:each_occupant() do
306 if occupant_nick ~= occupant.nick then 322 if occupant_nick ~= occupant.nick then
307 if broadcast_roles[occupant.role or "none"] or force_unavailable then 323 if broadcast_roles[occupant.role or "none"] or force_unavailable then
308 self:route_to_occupant(n_occupant, get_p(n_occupant)); 324 self:route_presence_to_occupant(n_occupant, get_p(n_occupant));
309 elseif prev_role and broadcast_roles[prev_role] then 325 elseif prev_role and broadcast_roles[prev_role] then
310 local pr = get_p(n_occupant); 326 local pr = get_p(n_occupant);
311 pr.attr.type = 'unavailable'; 327 pr.attr.type = 'unavailable';
312 self:route_to_occupant(n_occupant, pr); 328 self:route_presence_to_occupant(n_occupant, pr);
313 end 329 end
314 330
315 end 331 end
316 end 332 end
317 333
330 self:route_stanza(pr); 346 self:route_stanza(pr);
331 end 347 end
332 end 348 end
333 end 349 end
334 350
335 function room_mt:send_occupant_list(to, filter) 351 -- Send the current room list to an occupant (specifically to the real jid 'to',
336 local to_bare = jid_bare(to); 352 -- which is one of the occupant's sessions).
353 function room_mt:send_occupant_list(to_occupant, to_jid, filter)
354 local to_session = to_occupant:get_session(to_jid);
355 if to_session.filter_presence then return; end
356 local to_bare = to_occupant.bare_jid;
337 local broadcast_roles = self:get_presence_broadcast(); 357 local broadcast_roles = self:get_presence_broadcast();
338 local is_anonymous = self:is_anonymous_for(to); 358 local is_anonymous = self:is_anonymous_for(to_jid);
339 local broadcast_bare_jids = {}; -- Track which bare JIDs we have sent presence for 359 local broadcast_bare_jids = {}; -- Track which bare JIDs we have sent presence for
340 for occupant_jid, occupant in self:each_occupant() do 360 for occupant_jid, occupant in self:each_occupant() do
341 broadcast_bare_jids[occupant.bare_jid] = true; 361 broadcast_bare_jids[occupant.bare_jid] = true;
342 if (filter == nil or filter(occupant_jid, occupant)) and (to_bare == occupant.bare_jid or broadcast_roles[occupant.role or "none"]) then 362 if (filter == nil or filter(occupant_jid, occupant)) and (to_bare == occupant.bare_jid or broadcast_roles[occupant.role or "none"]) then
343 local x = st.stanza("x", {xmlns='http://jabber.org/protocol/muc#user'}); 363 local x = st.stanza("x", {xmlns='http://jabber.org/protocol/muc#user'});
344 self:build_item_list(occupant, x, is_anonymous and to_bare ~= occupant.bare_jid); -- can always see your own jids 364 self:build_item_list(occupant, x, is_anonymous and to_bare ~= occupant.bare_jid); -- can always see your own jids
345 local pres = st.clone(occupant:get_presence()); 365 local pres = st.clone(occupant:get_presence());
346 pres.attr.to = to; 366 pres.attr.to = to_jid;
347 pres:add_child(x); 367 pres:add_child(x);
348 module:fire_event("muc-build-occupant-presence", { room = self, occupant = occupant, stanza = pres }); 368 module:fire_event("muc-build-occupant-presence", { room = self, occupant = occupant, stanza = pres });
349 self:route_stanza(pres); 369 self:route_stanza(pres);
350 end 370 end
351 end 371 end
354 for affiliated_jid, affiliation, affiliation_data in self:each_affiliation() do 374 for affiliated_jid, affiliation, affiliation_data in self:each_affiliation() do
355 local nick = affiliation_data and affiliation_data.reserved_nickname; 375 local nick = affiliation_data and affiliation_data.reserved_nickname;
356 if (nick or not is_anonymous) and not broadcast_bare_jids[affiliated_jid] 376 if (nick or not is_anonymous) and not broadcast_bare_jids[affiliated_jid]
357 and (filter == nil or filter(affiliated_jid, nil)) then 377 and (filter == nil or filter(affiliated_jid, nil)) then
358 local from = nick and (self.jid.."/"..nick) or self.jid; 378 local from = nick and (self.jid.."/"..nick) or self.jid;
359 local pres = st.presence({ to = to, from = from, type = "unavailable" }) 379 local pres = st.presence({ to = to_jid, from = from, type = "unavailable" })
360 :tag("x", { xmlns = 'http://jabber.org/protocol/muc#user' }) 380 :tag("x", { xmlns = 'http://jabber.org/protocol/muc#user' })
361 :tag("item", { 381 :tag("item", {
362 affiliation = affiliation; 382 affiliation = affiliation;
363 role = "none"; 383 role = "none";
364 nick = nick; 384 nick = nick;
756 dest_occupant:set_session(real_jid, stanza); 776 dest_occupant:set_session(real_jid, stanza);
757 self:save_occupant(dest_occupant); 777 self:save_occupant(dest_occupant);
758 778
759 if orig_occupant == nil or muc_x then 779 if orig_occupant == nil or muc_x then
760 -- Send occupant list to newly joined or desynced user 780 -- Send occupant list to newly joined or desynced user
761 self:send_occupant_list(real_jid, function(nick, occupant) -- luacheck: ignore 212 781 self:send_occupant_list(dest_occupant, real_jid, function(nick, occupant) -- luacheck: ignore 212
762 -- Don't include self 782 -- Don't include self
763 return (not occupant) or occupant:get_presence(real_jid) == nil; 783 return (not occupant) or occupant:get_presence(real_jid) == nil;
764 end) 784 end)
765 end 785 end
766 local dest_x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user";}); 786 local dest_x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user";});
1512 elseif is_semi_anonymous and 1532 elseif is_semi_anonymous and
1513 ((old_role == "moderator" and occupant.role ~= "moderator") or 1533 ((old_role == "moderator" and occupant.role ~= "moderator") or
1514 (old_role ~= "moderator" and occupant.role == "moderator")) then -- Has gained or lost moderator status 1534 (old_role ~= "moderator" and occupant.role == "moderator")) then -- Has gained or lost moderator status
1515 -- Send everyone else's presences (as jid visibility has changed) 1535 -- Send everyone else's presences (as jid visibility has changed)
1516 for real_jid in occupant:each_session() do 1536 for real_jid in occupant:each_session() do
1517 self:send_occupant_list(real_jid, function(occupant_jid, occupant) --luacheck: ignore 212 433 1537 self:send_occupant_list(occupant, real_jid, function(occupant_jid, occupant) --luacheck: ignore 212 433
1518 return (not occupant) or occupant.bare_jid ~= jid; 1538 return (not occupant) or occupant.bare_jid ~= jid;
1519 end); 1539 end);
1520 end 1540 end
1521 end 1541 end
1522 end 1542 end