Mercurial > prosody-hg
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 |
