# HG changeset patch # User nicoco # Date 1780951325 -7200 # Node ID 93544117ddcd8097ad68a04e42e188cea47e99fb # Parent 7dee00093c8804e20f3cc4a59131cf507cd1e772 muc_invite_remote_affiliated_jids: new module diff -r 7dee00093c88 -r 93544117ddcd mod_muc_invite_remote_affiliated_jids/README.md --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_muc_invite_remote_affiliated_jids/README.md Mon Jun 08 22:42:05 2026 +0200 @@ -0,0 +1,35 @@ +--- +labels: +- 'Stage-Alpha' +summary: 'Send invites to MUC affiliated remote JIDs on startup' +... + +Purpose +======= + +This module sends invites to non-local JIDs that are affiliated as "member", +"owner" or "admin" of rooms. It is a workaround for situations where +participants are kicked of a room by a server shutdown, to signal to their +client that they can join the room again. + +Configuration +============= + +Add the module to the MUC host (not the global modules\_enabled): + +```lua +Component "conference.example.com" "muc" + modules_enabled = { "muc_invite_remote_affiliated_jids" } +``` + +You can configure a message associated to the invite with the +`muc_invite_remote_affiliated_jids_reason` configuration entry. + +Compatibility +============= + + ------- ------- + trunk* Works + ------- ------- + +*as of 2026-06-08 diff -r 7dee00093c88 -r 93544117ddcd mod_muc_invite_remote_affiliated_jids/mod_muc_invite_remote_affiliated_jids.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_muc_invite_remote_affiliated_jids/mod_muc_invite_remote_affiliated_jids.lua Mon Jun 08 22:42:05 2026 +0200 @@ -0,0 +1,61 @@ +local st = require "util.stanza" +local jid = require "util.jid" + +local module_host = module:get_host() + +local mod_muc = module:depends("muc") --[[@as muc_module]] + +local reason = module:get_option_string( + "muc_invite_remote_affiliated_jids_reason", + "You are a member of this room, please join it." +) + +local function is_remote(bare_jid) + local _user, jid_host = jid.split(bare_jid) + return not prosody.hosts[jid_host] +end + +local function build_invite(room_jid, to_jid, room_name, from_jid) + local invite = st.message({ to = to_jid, from = module_host }) + :tag("x", { + xmlns = "jabber:x:conference", + jid = room_jid, + reason = reason + }) + + if room_name and room_name ~= "" then + invite:attr("name", room_name) + end + + return invite +end + +local function invite_remote_members() + local invite_count = 0 + local room_count = 0 + + for room in mod_muc.all_rooms() do + if room:get_members_only() then + room_count = room_count + 1 + local room_jid = room.jid + local room_name = room:get_name() + + for member_jid, aff in room:each_affiliation() do + if aff == "owner" or aff == "admin" or aff == "member" then + local bare = jid.bare(member_jid) + if is_remote(bare) then + local invite_stanza = build_invite(room_jid, bare, room_name) + module:send(invite_stanza) + module:log("debug", "Sent invite for %s to %s", room_jid, bare) + invite_count = invite_count + 1 + end + end + end + end + end + + module:log("info", "Sent %d invite(s) across %d members-only room(s)", + invite_count, room_count) +end + +module:hook_global("server-started", invite_remote_members)