From eb0947ba4f77172073a21be7c20e17e5f016c203 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sat, 10 Nov 2018 15:50:32 +0100 Subject: MUC: Fix spelling in comments --- plugins/muc/muc.lib.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 4060535a..d9fa37f5 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -39,7 +39,7 @@ function room_mt:__tostring() end function room_mt.save() - -- overriden by mod_muc.lua + -- overridden by mod_muc.lua end function room_mt:get_occupant_jid(real_jid) @@ -279,7 +279,7 @@ function room_mt:publicise_occupant_status(occupant, x, nick, actor, reason) self_p = st.clone(base_presence):add_child(self_x); end - -- General populance + -- General populace for occupant_nick, n_occupant in self:each_occupant() do if occupant_nick ~= occupant.nick then local pr; @@ -609,7 +609,7 @@ function room_mt:handle_normal_presence(origin, stanza) x:tag("status", {code = "303";}):up(); x:tag("status", {code = "110";}):up(); self:route_stanza(generated_unavail:add_child(x)); - dest_nick = nil; -- set dest_nick to nil; so general populance doesn't see it for whole orig_occupant + dest_nick = nil; -- set dest_nick to nil; so general populace doesn't see it for whole orig_occupant end end @@ -966,7 +966,7 @@ function room_mt:handle_admin_query_get_command(origin, stanza) local _aff_rank = valid_affiliations[_aff or "none"]; local _rol = item.attr.role; if _aff and _aff_rank and not _rol then - -- You need to be at least an admin, and be requesting info about your affifiliation or lower + -- You need to be at least an admin, and be requesting info about your affiliation or lower -- e.g. an admin can't ask for a list of owners local affiliation_rank = valid_affiliations[affiliation or "none"]; if (affiliation_rank >= valid_affiliations.admin and affiliation_rank >= _aff_rank) @@ -1291,7 +1291,7 @@ function room_mt:set_affiliation(actor, jid, affiliation, reason, data) -- Outcast can be by host. is_host_only and affiliation == "outcast" and select(2, jid_split(occupant.bare_jid)) == host ) then - -- need to publcize in all cases; as affiliation in has changed. + -- need to publicize in all cases; as affiliation in has changed. occupants_updated[occupant] = occupant.role; if occupant.role ~= role and ( is_downgrade or -- cgit v1.2.3 From cf22878c983c7ebd6cf2a6bef90ed44b7295298d Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 27 Nov 2018 17:01:47 +0100 Subject: MUC: Move check for explicit room join earlier in room creation flow --- plugins/muc/muc.lib.lua | 7 ------- 1 file changed, 7 deletions(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 96f58023..0009e9b2 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -428,13 +428,6 @@ module:hook("muc-occupant-pre-change", function(event) end, 1); function room_mt:handle_first_presence(origin, stanza) - if not stanza:get_child("x", "http://jabber.org/protocol/muc") then - module:log("debug", "Room creation without , possibly desynced"); - - origin.send(st.error_reply(stanza, "cancel", "item-not-found")); - return true; - end - local real_jid = stanza.attr.from; local dest_jid = stanza.attr.to; local bare_jid = jid_bare(real_jid); -- cgit v1.2.3 From 90f8c75467e26c7a9dc74a55c615304ee4a3569e Mon Sep 17 00:00:00 2001 From: Jonas Wielicki Date: Sun, 6 Jan 2019 11:28:54 +0100 Subject: MUC: add ID to message if no ID is present --- plugins/muc/muc.lib.lua | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index bb79cda6..a34e912b 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -23,6 +23,7 @@ local resourceprep = require "util.encodings".stringprep.resourceprep; local st = require "util.stanza"; local base64 = require "util.encodings".base64; local md5 = require "util.hashes".md5; +local id = require "util.id"; local log = module._log; @@ -1037,6 +1038,9 @@ end function room_mt:handle_groupchat_to_room(origin, stanza) local from = stanza.attr.from; local occupant = self:get_occupant_by_real_jid(from); + if not stanza.attr.id then + stanza.attr.id = id.medium() + end if module:fire_event("muc-occupant-groupchat", { room = self; origin = origin; stanza = stanza; from = from; occupant = occupant; }) then return true; end -- cgit v1.2.3 From f0550233fa24e17773e0c7cc21885cd195ad8c1f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 6 Jan 2019 12:20:57 +0100 Subject: MUC: Rename import to avoid name clash [luacheck] --- plugins/muc/muc.lib.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index a34e912b..7259dde2 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -23,7 +23,7 @@ local resourceprep = require "util.encodings".stringprep.resourceprep; local st = require "util.stanza"; local base64 = require "util.encodings".base64; local md5 = require "util.hashes".md5; -local id = require "util.id"; +local new_id = require "util.id".medium; local log = module._log; @@ -1039,7 +1039,7 @@ function room_mt:handle_groupchat_to_room(origin, stanza) local from = stanza.attr.from; local occupant = self:get_occupant_by_real_jid(from); if not stanza.attr.id then - stanza.attr.id = id.medium() + stanza.attr.id = new_id() end if module:fire_event("muc-occupant-groupchat", { room = self; origin = origin; stanza = stanza; from = from; occupant = occupant; -- cgit v1.2.3 From 10e58af1abd74cd1bb668fc75b506b57fd77d86f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 24 Feb 2019 16:18:30 +0100 Subject: MUC: Factor out role change permission check into its own method I would like to invert this logic so that it checks if the role change is allowed instead of checking if it is not allowed as it does now, in order to make it easier to understand. --- plugins/muc/muc.lib.lua | 45 +++++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 18 deletions(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 9b168e93..2b6a7d76 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -1368,6 +1368,30 @@ function room_mt:get_role(nick) return occupant and occupant.role or nil; end +function room_mt:may_set_role(actor, occupant, role) + -- Can't do anything to other owners or admins + local occupant_affiliation = self:get_affiliation(occupant.bare_jid); + if occupant_affiliation == "owner" or occupant_affiliation == "admin" then + return nil, "cancel", "not-allowed"; + end + + -- If you are trying to give or take moderator role you need to be an owner or admin + if occupant.role == "moderator" or role == "moderator" then + local actor_affiliation = self:get_affiliation(actor); + if actor_affiliation ~= "owner" and actor_affiliation ~= "admin" then + return nil, "cancel", "not-allowed"; + end + end + + -- Need to be in the room and a moderator + local actor_occupant = self:get_occupant_by_real_jid(actor); + if not actor_occupant or actor_occupant.role ~= "moderator" then + return nil, "cancel", "not-allowed"; + end + + return true; +end + function room_mt:set_role(actor, occupant_jid, role, reason) if not actor then return nil, "modify", "not-acceptable"; end @@ -1382,24 +1406,9 @@ function room_mt:set_role(actor, occupant_jid, role, reason) if actor == true then actor = nil -- So we can pass it safely to 'publicise_occupant_status' below else - -- Can't do anything to other owners or admins - local occupant_affiliation = self:get_affiliation(occupant.bare_jid); - if occupant_affiliation == "owner" or occupant_affiliation == "admin" then - return nil, "cancel", "not-allowed"; - end - - -- If you are trying to give or take moderator role you need to be an owner or admin - if occupant.role == "moderator" or role == "moderator" then - local actor_affiliation = self:get_affiliation(actor); - if actor_affiliation ~= "owner" and actor_affiliation ~= "admin" then - return nil, "cancel", "not-allowed"; - end - end - - -- Need to be in the room and a moderator - local actor_occupant = self:get_occupant_by_real_jid(actor); - if not actor_occupant or actor_occupant.role ~= "moderator" then - return nil, "cancel", "not-allowed"; + local allowed, err, condition = self:may_set_role(actor, occupant, role) + if not allowed then + return allowed, err, condition; end end -- cgit v1.2.3 From 8518868d4192e48f1f7529970dca3bae4364f43b Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Sun, 24 Feb 2019 16:30:11 +0100 Subject: MUC: Fire an event to allow affecting decision of whether to allow a role change --- plugins/muc/muc.lib.lua | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 2b6a7d76..a8d3d790 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -1369,6 +1369,18 @@ function room_mt:get_role(nick) end function room_mt:may_set_role(actor, occupant, role) + local event = { + room = self, + actor = actor, + occupant = occupant, + role = role, + }; + + module:fire_event("muc-pre-set-role", event); + if event.allowed ~= nil then + return event.allowed, event.error, event.condition; + end + -- Can't do anything to other owners or admins local occupant_affiliation = self:get_affiliation(occupant.bare_jid); if occupant_affiliation == "owner" or occupant_affiliation == "admin" then -- cgit v1.2.3 From 62f33cd891e824a8d9c5a99c5d1a51af6c23835d Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 18 Mar 2019 09:50:23 +0000 Subject: MUC: Update error message for consistency --- plugins/muc/muc.lib.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index a8d3d790..c828d17d 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -498,7 +498,7 @@ function room_mt:handle_normal_presence(origin, stanza) if orig_occupant == nil and not muc_x and stanza.attr.type == nil then module:log("debug", "Attempted join without , possibly desynced"); origin.send(st.error_reply(stanza, "cancel", "item-not-found", - "You must join the room before sending presence updates")); + "You are not currently connected to this chat")); return true; end -- cgit v1.2.3 From 693a64eedfe149f36b2e3b6374dd41fbfd41cad0 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 19 Jun 2019 08:51:39 +0200 Subject: MUC: Reflow event tables to improve readability Also makes it easier to read diffs of added fields. --- plugins/muc/muc.lib.lua | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index c828d17d..34961558 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -391,7 +391,11 @@ function room_mt:handle_kickable(origin, stanza) -- luacheck: ignore 212 end self:publicise_occupant_status(new_occupant or occupant, x); if is_last_session then - module:fire_event("muc-occupant-left", {room = self; nick = occupant.nick; occupant = occupant;}); + module:fire_event("muc-occupant-left", { + room = self; + nick = occupant.nick; + occupant = occupant; + }); end return true; end @@ -868,7 +872,11 @@ function room_mt:clear(x) end for occupant in pairs(occupants_updated) do self:publicise_occupant_status(occupant, x); - module:fire_event("muc-occupant-left", { room = self; nick = occupant.nick; occupant = occupant;}); + module:fire_event("muc-occupant-left", { + room = self; + nick = occupant.nick; + occupant = occupant; + }); end end @@ -1316,7 +1324,11 @@ function room_mt:set_affiliation(actor, jid, affiliation, reason, data) for occupant, old_role in pairs(occupants_updated) do self:publicise_occupant_status(occupant, x, nil, actor, reason); if occupant.role == nil then - module:fire_event("muc-occupant-left", {room = self; nick = occupant.nick; occupant = occupant;}); + module:fire_event("muc-occupant-left", { + room = self; + nick = occupant.nick; + occupant = occupant; + }); elseif is_semi_anonymous and (old_role == "moderator" and occupant.role ~= "moderator") or (old_role ~= "moderator" and occupant.role == "moderator") then -- Has gained or lost moderator status @@ -1432,7 +1444,11 @@ function room_mt:set_role(actor, occupant_jid, role, reason) self:save_occupant(occupant); self:publicise_occupant_status(occupant, x, nil, actor, reason); if role == nil then - module:fire_event("muc-occupant-left", {room = self; nick = occupant.nick; occupant = occupant;}); + module:fire_event("muc-occupant-left", { + room = self; + nick = occupant.nick; + occupant = occupant; + }); end return true; end -- cgit v1.2.3 From 190c1e7772fe11c353ce0c0e001490e29734a63a Mon Sep 17 00:00:00 2001 From: Lance Stout Date: Sun, 20 Oct 2019 21:58:16 +0200 Subject: MUC: Add controls for whose presence is broadcast (closes #1335) Committed by Zash --- plugins/muc/muc.lib.lua | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index d84f4ac1..200f69f9 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -218,13 +218,13 @@ end -- 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";}; @@ -280,6 +280,8 @@ function room_mt:publicise_occupant_status(occupant, x, nick, actor, reason) self_p = st.clone(base_presence):add_child(self_x); end + local broadcast_roles = self:get_presence_broadcast(); + -- General populace for occupant_nick, n_occupant in self:each_occupant() do if occupant_nick ~= occupant.nick then @@ -291,7 +293,13 @@ function room_mt:publicise_occupant_status(occupant, x, nick, actor, reason) 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 @@ -315,6 +323,7 @@ function room_mt:send_occupant_list(to, filter) 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 @@ -331,7 +340,9 @@ function room_mt:send_occupant_list(to, filter) 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 @@ -1442,9 +1453,11 @@ function room_mt:set_role(actor, occupant_jid, role, reason) 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; -- cgit v1.2.3 From 2834c8aaff68fc71a6ccba394c1c3ccbe06846a1 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 23 Sep 2019 19:13:14 +0200 Subject: MUC: Enforce strict resourceprep on nicknames (bye bye robot face) --- plugins/muc/muc.lib.lua | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 200f69f9..3a228aae 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -444,6 +444,22 @@ module:hook("muc-occupant-pre-change", function(event) end end, 1); +module:hook("muc-occupant-pre-join", function(event) + local nick = jid_resource(event.occupant.nick); + if not resourceprep(nick, true) then -- strict + event.origin.send(st.error_reply(event.stanza, "modify", "jid-malformed", "Nickname must pass strict validation")); + return true; + end +end, 2); + +module:hook("muc-occupant-pre-change", function(event) + local nick = jid_resource(event.dest_occupant.nick); + if not resourceprep(nick, true) then -- strict + event.origin.send(st.error_reply(event.stanza, "modify", "jid-malformed", "Nickname must pass strict validation")); + return true; + end +end, 2); + function room_mt:handle_first_presence(origin, stanza) local real_jid = stanza.attr.from; local dest_jid = stanza.attr.to; -- cgit v1.2.3 From 093ef6bb23e47af21bcb5428386ace5013604424 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 25 Nov 2019 23:52:45 +0100 Subject: MUC: Indicate that the room is the origin of various errors where 'from' is an occupant JID --- plugins/muc/muc.lib.lua | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 4b462631..ed6011e1 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -422,7 +422,7 @@ module:hook("muc-occupant-pre-join", function(event) local room, stanza = event.room, event.stanza; local affiliation = room:get_affiliation(stanza.attr.from); if affiliation == "outcast" then - local reply = st.error_reply(stanza, "auth", "forbidden"):up(); + local reply = st.error_reply(stanza, "auth", "forbidden", nil, room.jid):up(); reply.tags[1].attr.code = "403"; event.origin.send(reply:tag("x", {xmlns = "http://jabber.org/protocol/muc"})); return true; @@ -430,24 +430,27 @@ module:hook("muc-occupant-pre-join", function(event) end, -10); module:hook("muc-occupant-pre-join", function(event) + local room = event.room; local nick = jid_resource(event.occupant.nick); if not nick:find("%S") then - event.origin.send(st.error_reply(event.stanza, "modify", "not-allowed", "Invisible Nicknames are forbidden")); + event.origin.send(st.error_reply(event.stanza, "modify", "not-allowed", "Invisible Nicknames are forbidden", room.jid)); return true; end end, 1); module:hook("muc-occupant-pre-change", function(event) + local room = event.room; if not jid_resource(event.dest_occupant.nick):find("%S") then - event.origin.send(st.error_reply(event.stanza, "modify", "not-allowed", "Invisible Nicknames are forbidden")); + event.origin.send(st.error_reply(event.stanza, "modify", "not-allowed", "Invisible Nicknames are forbidden", room.jid)); return true; end end, 1); module:hook("muc-occupant-pre-join", function(event) + local room = event.room; local nick = jid_resource(event.occupant.nick); if not resourceprep(nick, true) then -- strict - event.origin.send(st.error_reply(event.stanza, "modify", "jid-malformed", "Nickname must pass strict validation")); + event.origin.send(st.error_reply(event.stanza, "modify", "jid-malformed", "Nickname must pass strict validation", room.jid)); return true; end end, 2); @@ -455,7 +458,7 @@ end, 2); module:hook("muc-occupant-pre-change", function(event) local nick = jid_resource(event.dest_occupant.nick); if not resourceprep(nick, true) then -- strict - event.origin.send(st.error_reply(event.stanza, "modify", "jid-malformed", "Nickname must pass strict validation")); + event.origin.send(st.error_reply(event.stanza, "modify", "jid-malformed", "Nickname must pass strict validation", room.jid)); return true; end end, 2); @@ -530,7 +533,7 @@ function room_mt:handle_normal_presence(origin, stanza) if orig_occupant == nil and not muc_x and stanza.attr.type == nil then module:log("debug", "Attempted join without , possibly desynced"); origin.send(st.error_reply(stanza, "cancel", "item-not-found", - "You are not currently connected to this chat")); + "You are not currently connected to this chat", self.jid)); return true; end @@ -592,7 +595,7 @@ function room_mt:handle_normal_presence(origin, stanza) and bare_jid ~= jid_bare(dest_occupant.bare_jid) then -- new nick or has different bare real jid log("debug", "%s couldn't join due to nick conflict: %s", real_jid, dest_occupant.nick); - local reply = st.error_reply(stanza, "cancel", "conflict"):up(); + local reply = st.error_reply(stanza, "cancel", "conflict", nil, self.jid):up(); reply.tags[1].attr.code = "409"; origin.send(reply:tag("x", {xmlns = "http://jabber.org/protocol/muc"})); return true; @@ -721,7 +724,7 @@ function room_mt:handle_presence_to_occupant(origin, stanza) return self:handle_normal_presence(origin, stanza); elseif type ~= 'result' then -- bad type if type ~= 'visible' and type ~= 'invisible' then -- COMPAT ejabberd can broadcast or forward XEP-0018 presences - origin.send(st.error_reply(stanza, "modify", "bad-request")); -- FIXME correct error? + origin.send(st.error_reply(stanza, "modify", "bad-request", nil, self.jid)); -- FIXME correct error? end end return true; @@ -756,11 +759,11 @@ function room_mt:handle_iq_to_occupant(origin, stanza) else -- Type is "get" or "set" local current_nick = self:get_occupant_jid(from); if not current_nick then - origin.send(st.error_reply(stanza, "cancel", "not-acceptable", "You are not currently connected to this chat")); + origin.send(st.error_reply(stanza, "cancel", "not-acceptable", "You are not currently connected to this chat", self.jid)); return true; end if not occupant then -- recipient not in room - origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Recipient not in room")); + origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Recipient not in room", self.jid)); return true; end -- XEP-0410 MUC Self-Ping #1220 @@ -789,12 +792,12 @@ function room_mt:handle_message_to_occupant(origin, stanza) local type = stanza.attr.type; if not current_nick then -- not in room if type ~= "error" then - origin.send(st.error_reply(stanza, "cancel", "not-acceptable", "You are not currently connected to this chat")); + origin.send(st.error_reply(stanza, "cancel", "not-acceptable", "You are not currently connected to this chat", self.jid)); end return true; end if type == "groupchat" then -- groupchat messages not allowed in PM - origin.send(st.error_reply(stanza, "modify", "bad-request")); + origin.send(st.error_reply(stanza, "modify", "bad-request", nil, self.jid)); return true; elseif type == "error" and is_kickable_error(stanza) then log("debug", "%s kicked from %s for sending an error message", current_nick, self.jid); @@ -803,7 +806,7 @@ function room_mt:handle_message_to_occupant(origin, stanza) local o_data = self:get_occupant_by_nick(to); if not o_data then - origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Recipient not in room")); + origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Recipient not in room", self.jid)); return true; end log("debug", "%s sent private message stanza to %s (%s)", from, to, o_data.jid); -- cgit v1.2.3 From 47fd3433fc4ac4d203d2ae9c045e2c5e4356a4f2 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 26 Nov 2019 00:09:51 +0100 Subject: MUC: Add missing reference to room (thanks buildbot) [luacheck] --- plugins/muc/muc.lib.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index ed6011e1..6b5f6068 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -456,6 +456,7 @@ module:hook("muc-occupant-pre-join", function(event) end, 2); module:hook("muc-occupant-pre-change", function(event) + local room = event.room; local nick = jid_resource(event.dest_occupant.nick); if not resourceprep(nick, true) then -- strict event.origin.send(st.error_reply(event.stanza, "modify", "jid-malformed", "Nickname must pass strict validation", room.jid)); -- cgit v1.2.3 From 72a8c497ec2920ec0ab01ce2f5d01b514da58b8a Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 23 Dec 2019 22:23:29 +0100 Subject: MUC: Remove some unused variables [luacheck] --- plugins/muc/muc.lib.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 6b5f6068..7226a7bf 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -385,7 +385,7 @@ function room_mt:handle_kickable(origin, stanza) -- luacheck: ignore 212 local real_jid = stanza.attr.from; local occupant = self:get_occupant_by_real_jid(real_jid); if occupant == nil then return nil; end - local type, condition, text = stanza:get_error(); + local _, condition, text = stanza:get_error(); local error_message = "Kicked: "..(condition and condition:gsub("%-", " ") or "presence error"); if text and self:get_whois() == "anyone" then error_message = error_message..": "..text; @@ -1254,7 +1254,7 @@ function room_mt:route_stanza(stanza) -- luacheck: ignore 212 end function room_mt:get_affiliation(jid) - local node, host, resource = jid_split(jid); + local node, host = jid_split(jid); -- Affiliations are granted, revoked, and maintained based on the user's bare JID. local bare = node and node.."@"..host or host; local result = self._affiliations[bare]; @@ -1277,7 +1277,7 @@ end function room_mt:set_affiliation(actor, jid, affiliation, reason, data) if not actor then return nil, "modify", "not-acceptable"; end; - local node, host, resource = jid_split(jid); + local node, host = jid_split(jid); if not host then return nil, "modify", "not-acceptable"; end jid = jid_join(node, host); -- Bare local is_host_only = node == nil; @@ -1571,7 +1571,7 @@ function _M.restore_room(frozen, state) else -- New storage format for jid, data in pairs(frozen) do - local node, host, resource = jid_split(jid); + local _, host, resource = jid_split(jid); if host:sub(1,1) ~= "_" and not resource and type(data) == "string" then -- bare jid: affiliation room._affiliations[jid] = data; -- cgit v1.2.3 From a95900e81c072dc7956addc70b1664695a18261e Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 23 Dec 2019 22:28:04 +0100 Subject: MUC: Make note to handle configuration form errors [luacheck] --- plugins/muc/muc.lib.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 7226a7bf..399b090e 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -844,10 +844,12 @@ function room_mt:process_form(origin, stanza) if form.attr.type == "cancel" then origin.send(st.reply(stanza)); elseif form.attr.type == "submit" then + -- luacheck: ignore 231/errors local fields, errors, present; if form.tags[1] == nil then -- Instant room fields, present = {}, {}; else + -- FIXME handle form errors fields, errors, present = self:get_form_layout(stanza.attr.from):data(form); if fields.FORM_TYPE ~= "http://jabber.org/protocol/muc#roomconfig" then origin.send(st.error_reply(stanza, "cancel", "bad-request", "Form is not of type room configuration")); -- cgit v1.2.3 From 4a2e73392898afb5f8b380bdef86e438761b3d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Mon, 24 Feb 2020 14:16:45 +0100 Subject: mod_muc: add muc-private-message event This seems to be the one place handling MUC-PMs. This event is added so that plugins (such as muc_occupant_id) can edit them without having to redo the work. --- plugins/muc/muc.lib.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 399b090e..8adb0046 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -814,7 +814,9 @@ function room_mt:handle_message_to_occupant(origin, stanza) stanza = muc_util.filter_muc_x(st.clone(stanza)); stanza:tag("x", { xmlns = "http://jabber.org/protocol/muc#user" }):up(); stanza.attr.from = current_nick; - self:route_to_occupant(o_data, stanza) + if module:fire_event("muc-private-message", { room = self, origin = origin, stanza = stanza }) ~= false then + self:route_to_occupant(o_data, stanza) + end -- TODO: Remove x tag? stanza.attr.from = from; return true; -- cgit v1.2.3 From e30cbeae993803583e1f2ed2085c9be5b5fb6f63 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 12 Mar 2020 14:10:12 +0000 Subject: MUC: Pass previous role to :publicise_occupant_status() whenever possible Currently there is what amounts to a hack in presence_broadcast.lib.lua to make it always broadcast presence with roles of "none". This is to ensure that if you previously saw available presence for someone, you will also see the unavailable presence (which always has role="none"). The correct approach is to take into account what the previous role was ( i.e. answer the question: "Was the available presence for this occupant a role for which presence broadcast is enabled?). The logic is already in place to do this correctly, but most call sites do not provide the previous role (prev_role argument) of the occupant, which causes it to not be used. In its place the hack to always broadcast presence of role="none" has allowed things to continue to work. The intention is that a subsequent commit will remove the unconditional broadcast of role="none". --- plugins/muc/muc.lib.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 8adb0046..2a7952cf 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -392,6 +392,7 @@ function room_mt:handle_kickable(origin, stanza) -- luacheck: ignore 212 end occupant:set_session(real_jid, st.presence({type="unavailable"}) :tag('status'):text(error_message)); + local orig_role = occupant.role; local is_last_session = occupant.jid == real_jid; if is_last_session then occupant.role = nil; @@ -401,7 +402,7 @@ function room_mt:handle_kickable(origin, stanza) -- luacheck: ignore 212 if is_last_session then x:tag("status", {code = "333"}); end - self:publicise_occupant_status(new_occupant or occupant, x); + self:publicise_occupant_status(new_occupant or occupant, x, nil, nil, nil, orig_role); if is_last_session then module:fire_event("muc-occupant-left", { room = self; @@ -605,6 +606,7 @@ function room_mt:handle_normal_presence(origin, stanza) -- Send presence stanza about original occupant if orig_occupant ~= nil and orig_occupant ~= dest_occupant then local orig_x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user";}); + local orig_role = orig_occupant.role; local dest_nick; if dest_occupant == nil then -- Session is leaving log("debug", "session %s is leaving occupant %s", real_jid, orig_occupant.nick); @@ -647,7 +649,7 @@ function room_mt:handle_normal_presence(origin, stanza) end self:save_occupant(orig_occupant); - self:publicise_occupant_status(orig_occupant, orig_x, dest_nick); + self:publicise_occupant_status(orig_occupant, orig_x, dest_nick, nil, nil, orig_role); if is_last_orig_session then module:fire_event("muc-occupant-left", { @@ -679,7 +681,7 @@ function room_mt:handle_normal_presence(origin, stanza) if nick_changed then self_x:tag("status", {code="210"}):up(); end - self:publicise_occupant_status(dest_occupant, {base=dest_x,self=self_x}); + self:publicise_occupant_status(dest_occupant, {base=dest_x,self=self_x}, nil, nil, nil, orig_occupant and orig_occupant.role or nil); if orig_occupant ~= nil and orig_occupant ~= dest_occupant and not is_last_orig_session then -- If user is swapping and wasn't last original session @@ -1362,7 +1364,7 @@ function room_mt:set_affiliation(actor, jid, affiliation, reason, data) if next(occupants_updated) ~= nil then for occupant, old_role in pairs(occupants_updated) do - self:publicise_occupant_status(occupant, x, nil, actor, reason); + self:publicise_occupant_status(occupant, x, nil, actor, reason, old_role); if occupant.role == nil then module:fire_event("muc-occupant-left", { room = self; -- cgit v1.2.3 From 572526d384fa79688a189c2e5d37614036b7ffd3 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 12 Mar 2020 14:35:34 +0000 Subject: MUC: Pass previous role to :publicise_occupant_status() when destroying a MUC --- plugins/muc/muc.lib.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 2a7952cf..42f41831 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -908,12 +908,13 @@ function room_mt:clear(x) x = x or st.stanza("x", {xmlns='http://jabber.org/protocol/muc#user'}); local occupants_updated = {}; for nick, occupant in self:each_occupant() do -- luacheck: ignore 213 + local prev_role = occupant.role; occupant.role = nil; self:save_occupant(occupant); - occupants_updated[occupant] = true; + occupants_updated[occupant] = prev_role; end - for occupant in pairs(occupants_updated) do - self:publicise_occupant_status(occupant, x); + for occupant, prev_role in pairs(occupants_updated) do + self:publicise_occupant_status(occupant, x, nil, nil, nil, prev_role); module:fire_event("muc-occupant-left", { room = self; nick = occupant.nick; -- cgit v1.2.3 From 64bb781dfec9b44618da58991aab292b1e360be1 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 12 Mar 2020 16:01:31 +0000 Subject: MUC: Support for broadcasting unavailable presence for affiliated offline users Activated when muc#roomconfig_presencebroadcast includes the "none" role. --- plugins/muc/muc.lib.lua | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 42f41831..5f45498a 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -333,7 +333,9 @@ function room_mt:send_occupant_list(to, filter) end end end + local broadcast_bare_jids = {}; -- Track which bare JIDs we have sent presence for for occupant_jid, occupant in self:each_occupant() do + broadcast_bare_jids[occupant.bare_jid] = true; if filter == nil or filter(occupant_jid, occupant) then local x = st.stanza("x", {xmlns='http://jabber.org/protocol/muc#user'}); self:build_item_list(occupant, x, is_anonymous and to_bare ~= occupant.bare_jid); -- can always see your own jids @@ -345,6 +347,25 @@ function room_mt:send_occupant_list(to, filter) end end end + if broadcast_roles.none then + -- Broadcast stanzas for affiliated users not currently in the MUC + for affiliated_jid, affiliation, affiliation_data in self:each_affiliation() do + local nick = affiliation_data and affiliation_data.reserved_nickname; + if (nick or not is_anonymous) and not broadcast_bare_jids[affiliated_jid] + and (filter == nil or filter(affiliated_jid, nil)) then + local from = nick and (self.jid.."/"..nick) or self.jid; + local pres = st.presence({ to = to, from = from, type = "unavailable" }) + :tag("x", { xmlns = 'http://jabber.org/protocol/muc#user' }) + :tag("item", { + affiliation = affiliation; + role = "none"; + nick = nick; + jid = not is_anonymous and affiliated_jid or nil }):up() + :up(); + self:route_stanza(pres); + end + end + end end function room_mt:get_disco_info(stanza) @@ -670,7 +691,7 @@ function room_mt:handle_normal_presence(origin, stanza) -- Send occupant list to newly joined or desynced user self:send_occupant_list(real_jid, function(nick, occupant) -- luacheck: ignore 212 -- Don't include self - return occupant:get_presence(real_jid) == nil; + return (not occupant) or occupant:get_presence(real_jid) == nil; end) end local dest_x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user";}); @@ -1378,7 +1399,7 @@ function room_mt:set_affiliation(actor, jid, affiliation, reason, data) -- Send everyone else's presences (as jid visibility has changed) for real_jid in occupant:each_session() do self:send_occupant_list(real_jid, function(occupant_jid, occupant) --luacheck: ignore 212 433 - return occupant.bare_jid ~= jid; + return (not occupant) or occupant.bare_jid ~= jid; end); end end -- cgit v1.2.3 From 818722afb83b3c61c49e75fae338a4140414f84f Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 12 Mar 2020 16:10:44 +0000 Subject: MUC: Switch to new storage format by default Changing the default setting of `new_muc_storage_format` from false to true. The code supports reading both formats since 0.11, but servers with MUCs stored using the new format will not be able to downgrade to 0.10 or earlier. The new format is clearer (less nesting for the most commonly-accessed data), and combined with the new map-store methods, allows for some operations to become more efficient (such as finding out which MUCs on a service a given user is affiliated with). --- plugins/muc/muc.lib.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 5f45498a..2c9139d1 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -1536,7 +1536,7 @@ function _M.new_room(jid, config) }, room_mt); end -local new_format = module:get_option_boolean("new_muc_storage_format", false); +local new_format = module:get_option_boolean("new_muc_storage_format", true); function room_mt:freeze(live) local frozen, state; -- cgit v1.2.3 From 33ee094ac8dca4c4edea0b32d1b984c8b46e63a9 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 12 Mar 2020 20:32:07 +0000 Subject: MUC: Persist affiliation_data in new MUC format! --- plugins/muc/muc.lib.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 2c9139d1..4f265cf8 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -1544,6 +1544,7 @@ function room_mt:freeze(live) frozen = { _jid = self.jid; _data = self._data; + _affiliation_data = self._affiliation_data; }; for user, affiliation in pairs(self._affiliations) do frozen[user] = affiliation; -- cgit v1.2.3 From 007c8b7e64a93a79684b62d8ec888fe2fe1100e4 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Sat, 11 Apr 2020 16:41:52 +0100 Subject: MUC: Add new event 'muc-build-occupant-presence' for plugins to extend occupant presence --- plugins/muc/muc.lib.lua | 2 ++ 1 file changed, 2 insertions(+) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 4f265cf8..3b126522 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -237,6 +237,7 @@ function room_mt:publicise_occupant_status(occupant, x, nick, actor, reason, pre occupant = occupant; nick = nick; actor = actor; reason = reason; } + module:fire_event("muc-build-occupant-presence", event); module:fire_event("muc-broadcast-presence", event); -- Allow muc-broadcast-presence listeners to change things @@ -342,6 +343,7 @@ function room_mt:send_occupant_list(to, filter) local pres = st.clone(occupant:get_presence()); pres.attr.to = to; pres:add_child(x); + module:fire_event("muc-build-occupant-presence", { room = self, occupant = occupant, stanza = pres }); if to_bare == occupant.bare_jid or broadcast_roles[occupant.role or "none"] then self:route_stanza(pres); end -- cgit v1.2.3 From 8da81e9160c093c79754eb7189a2a9fced8df82a Mon Sep 17 00:00:00 2001 From: JC Brand Date: Wed, 22 Apr 2020 16:04:03 +0200 Subject: Fixes #1533 Hats don't get sent out to own MUC user --- plugins/muc/muc.lib.lua | 1 + 1 file changed, 1 insertion(+) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index d785a5a2..65ed8731 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -312,6 +312,7 @@ function room_mt:publicise_occupant_status(occupant, x, nick, actor, reason, pre else -- use their own presences as templates for full_jid, pr in occupant:each_session() do + module:fire_event("muc-build-occupant-presence", { room = self, occupant = occupant, stanza = pr }); pr = st.clone(pr); pr.attr.to = full_jid; pr:add_child(self_x); -- cgit v1.2.3 From b00737a6d32cf4e834cb239172280762e4d620f6 Mon Sep 17 00:00:00 2001 From: JC Brand Date: Wed, 22 Apr 2020 16:12:15 +0200 Subject: mod_muc: let event handlers modify cloned presence Updates #1533 --- plugins/muc/muc.lib.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'plugins/muc/muc.lib.lua') diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 65ed8731..2f72c9eb 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -312,8 +312,8 @@ function room_mt:publicise_occupant_status(occupant, x, nick, actor, reason, pre else -- use their own presences as templates for full_jid, pr in occupant:each_session() do - module:fire_event("muc-build-occupant-presence", { room = self, occupant = occupant, stanza = pr }); pr = st.clone(pr); + module:fire_event("muc-build-occupant-presence", { room = self, occupant = occupant, stanza = pr }); pr.attr.to = full_jid; pr:add_child(self_x); self:route_stanza(pr); -- cgit v1.2.3