From 26cd73ad688969a6fb0b13dbca633900fe04ad9f Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Mon, 28 May 2018 21:30:32 +0200 Subject: mod_disco: Skip code specific to disco on user accounts (avoids invoking usermanager, fixes #1150) --- plugins/mod_disco.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/mod_disco.lua b/plugins/mod_disco.lua index cd07934f..6d3e7753 100644 --- a/plugins/mod_disco.lua +++ b/plugins/mod_disco.lua @@ -154,6 +154,7 @@ module:hook("stream-features", function (event) end); -- Handle disco requests to user accounts +if module:get_host_type() ~= "local" then return end -- skip for components module:hook("iq/bare/http://jabber.org/protocol/disco#info:query", function(event) local origin, stanza = event.origin, event.stanza; if stanza.attr.type ~= "get" then return; end -- cgit v1.2.3 From bdc12e4516ba8abe608f27fdc55c8e411093e051 Mon Sep 17 00:00:00 2001 From: Jonas Wielicki Date: Thu, 17 May 2018 17:11:00 +0200 Subject: MUC: fix set_role invocation --- plugins/muc/muc.lib.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index a1b42c87..870bd53c 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -852,7 +852,7 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha if item.attr.affiliation and item.attr.jid and not item.attr.role then jid_affiliation[item.attr.jid] = { ["affiliation"] = item.attr.affiliation, ["reason"] = reason }; elseif item.attr.role and item.attr.nick and not item.attr.affiliation then - jidnick_role[item.attr.jid.."/"..item.attr.nick] = { ["role"] = item.attr.role, ["reason"] = reason }; + jidnick_role[self.jid.."/"..item.attr.nick] = { ["role"] = item.attr.role, ["reason"] = reason }; else origin.send(st.error_reply(stanza, "cancel", "bad-request")); return; @@ -1213,7 +1213,8 @@ end --- Checks whether the given role changes in jidnick_role can be applied by actor. -- Note: Empty tables can always be applied and won't have any effect. function room_mt:can_set_roles(actor, jidnick_role) - for jidnick, role in pairs(jidnick_role) do + for jidnick, role_info in pairs(jidnick_role) do + local role = role_info["role"]; if role == "none" then role = nil; end if role and role ~= "moderator" and role ~= "participant" and role ~= "visitor" then return false, "modify", "not-acceptable"; end local can_set, err_type, err_condition = self:can_set_role(actor, jidnick, role) @@ -1249,7 +1250,7 @@ function room_mt:set_roles(actor, jidnick_role, callback) :tag("reason"):text(reason or ""):up() :up(); local presence_type = nil; - if not role then -- kick + if not role or role == "none" then -- kick presence_type = "unavailable"; self._occupants[occupant_jid] = nil; for jid in pairs(occupant.sessions) do -- remove for all sessions of the nick @@ -1271,7 +1272,7 @@ function room_mt:set_roles(actor, jidnick_role, callback) if occupant.jid == jid then bp = st.clone(p); bp:add_child(x); - modified_nicks[occupant_jid] = p; + modified_nicks[occupant_jid] = bp; nb_modified_nicks = nb_modified_nicks + 1; end p:add_child(self_x); -- cgit v1.2.3 From 3443da43a22c6c9b32023f0a7273f5d3cdeb3f58 Mon Sep 17 00:00:00 2001 From: Jonas Wielicki Date: Thu, 17 May 2018 17:11:25 +0200 Subject: MUC: reject non-bare JIDs in set_affiliation requests with not-acceptable --- plugins/muc/muc.lib.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 870bd53c..12ecdbda 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -1076,6 +1076,9 @@ function room_mt:can_set_affiliations(actor, jid_affiliation) for jid, value in pairs(jid_affiliation) do local affiliation = value["affiliation"]; + if jid ~= jid_bare(jid) then + return false, "modify", "not-acceptable"; + end jid = jid_bare(jid); if affiliation == "none" then affiliation = nil; end if affiliation and affiliation ~= "outcast" and affiliation ~= "owner" and affiliation ~= "admin" and affiliation ~= "member" then -- cgit v1.2.3 From 95ffd552f0bb05d6d9b96d68441a2c357200cca7 Mon Sep 17 00:00:00 2001 From: Jonas Wielicki Date: Thu, 17 May 2018 17:11:42 +0200 Subject: MUC: correctly emit tags --- plugins/muc/muc.lib.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 12ecdbda..08c563c5 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -1134,7 +1134,7 @@ function room_mt:set_affiliations(actor, jid_affiliation, callback) :tag("reason"):text(reason or ""):up() :up(); local self_x = st.clone(x); - self_x:tag("status", {code="110"}); + self_x:tag("status", {code="110"}):up(); local presence_type = nil; if not role then -- getting kicked presence_type = "unavailable"; -- cgit v1.2.3 From 409cae1fc70dbb8adfc6d554b995198d0ba477e3 Mon Sep 17 00:00:00 2001 From: Jonas Wielicki Date: Thu, 17 May 2018 17:12:07 +0200 Subject: MUC: ensure that x/item/@jid is always a bare JID --- plugins/muc/muc.lib.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 08c563c5..31c28df9 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -1311,9 +1311,9 @@ function room_mt:_route_stanza(stanza) for _, item in pairs(muc_child.tags) do if item.name == "item" then if from_occupant == to_occupant then - item.attr.jid = stanza.attr.to; + item.attr.jid = jid_bare(stanza.attr.to); else - item.attr.jid = from_occupant.jid; + item.attr.jid = jid_bare(from_occupant.jid); end end end -- cgit v1.2.3 From 6a1f58031623c6e032a04adbaf95ffcf95b98156 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Tue, 29 May 2018 22:33:22 +0200 Subject: MUC: Handle setting default history messages when history length is unset (thanks tmolitor) --- plugins/muc/muc.lib.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 31c28df9..38eb980e 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -365,7 +365,7 @@ function room_mt:get_defaulthistorymessages() return self._data.default_history_messages or default_history_length; end function room_mt:set_defaulthistorymessages(number) - number = math.min(tonumber(number) or default_history_length, self._data.history_length); + number = math.min(tonumber(number) or default_history_length, self._data.history_length or default_history_length); if number == default_history_length then number = nil; end -- cgit v1.2.3 From 4aa93b912ff74a2fd9e34001370f433da928ee08 Mon Sep 17 00:00:00 2001 From: Kim Alvefur Date: Wed, 30 May 2018 10:58:19 +0200 Subject: mod_bosh: Store the normalized hostname on session (fixes #1151) --- plugins/mod_bosh.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua index 9ef4a41e..8cda4a23 100644 --- a/plugins/mod_bosh.lua +++ b/plugins/mod_bosh.lua @@ -281,7 +281,7 @@ function stream_callbacks.streamopened(context, attr) -- New session sid = new_uuid(); local session = { - type = "c2s_unauthed", conn = request.conn, sid = sid, rid = rid, host = attr.to, + type = "c2s_unauthed", conn = request.conn, sid = sid, rid = rid, host = to_host, bosh_version = attr.ver, bosh_wait = wait, streamid = sid, bosh_max_inactive = bosh_max_inactivity, requests = { }, send_buffer = {}, reset_stream = bosh_reset_stream, -- cgit v1.2.3 From bf1391b08e71d1f6d077c6ef392a0a4e541b7e78 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 30 May 2018 21:02:09 +0100 Subject: MUC: Fix error logged when no persistent rooms present --- plugins/muc/mod_muc.lua | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index 7304b5b1..0f58bfbc 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -39,8 +39,11 @@ local rooms = rooms; local persistent_rooms_storage = module:open_store("persistent"); local persistent_rooms, err = persistent_rooms_storage:get(); if not persistent_rooms then - module:log("error", "Error loading list of persistent rooms from storage. Reload mod_muc or restart to recover."); - assert(not err, err); + if err then + module:log("error", "Error loading list of persistent rooms from storage. Reload mod_muc or restart to recover."); + error("Storage error: "..err); + end + module:log("debug", "No persistent rooms found in the database"); persistent_rooms = {}; end local room_configs = module:open_store("config"); -- cgit v1.2.3 From 41e736bbb5e097bfde3d4b7590614912852cc445 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Wed, 30 May 2018 21:33:53 +0100 Subject: MUC: Revert unstable MUC commits since 0.10.1 These have caused too many issue reports to be included in the stable branch at this time. Affected issues: #345, #397 Reverted commits: dcd53a565c01 6d4b0895f76d 1b10802a770e 564e897f0790 a7221ada9368 aaff40ec7001 05a3275b6873 c2b99fa134b3 8da11142fabf --- plugins/muc/muc.lib.lua | 360 ++++++++++++++---------------------------------- 1 file changed, 104 insertions(+), 256 deletions(-) diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 38eb980e..5d8c6df5 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -171,7 +171,7 @@ function room_mt:send_history(to, stanza) if maxchars then maxchars = math.floor(maxchars); end local maxstanzas = math.floor(history_tag and tonumber(history_tag.attr.maxstanzas) or #history); - if not history_tag then maxstanzas = self._data.default_history_messages; end + if not history_tag then maxstanzas = 20; end local seconds = history_tag and tonumber(history_tag.attr.seconds); if seconds then seconds = datetime.datetime(os.time() - math.floor(seconds)); end @@ -359,20 +359,6 @@ function room_mt:set_historylength(length) self._data.history_length = length; end --- Fix for clients who don't support XEP-0045 correctly --- Default number of history messages the room returns -function room_mt:get_defaulthistorymessages() - return self._data.default_history_messages or default_history_length; -end -function room_mt:set_defaulthistorymessages(number) - number = math.min(tonumber(number) or default_history_length, self._data.history_length or default_history_length); - if number == default_history_length then - number = nil; - end - self._data.default_history_messages = number; -end - - local valid_whois = { moderators = true, anyone = true }; @@ -712,12 +698,6 @@ function room_mt:get_form_layout(actor) type = 'text-single', label = 'Maximum Number of History Messages Returned by Room', value = tostring(self:get_historylength()) - }, - { - name = 'muc#roomconfig_defaulthistorymessages', - type = 'text-single', - label = 'Default Number of History Messages Returned by Room', - value = tostring(self:get_defaulthistorymessages()) } }); return module:fire_event("muc-config-form", { room = self, actor = actor, form = form }) or form; @@ -766,7 +746,6 @@ function room_mt:process_form(origin, stanza) handle_option("public", "muc#roomconfig_publicroom"); handle_option("changesubject", "muc#roomconfig_changesubject"); handle_option("historylength", "muc#roomconfig_historylength"); - handle_option("defaulthistorymessages", "muc#roomconfig_defaulthistorymessages"); handle_option("whois", "muc#roomconfig_whois", valid_whois); handle_option("password", "muc#roomconfig_roomsecret"); @@ -823,16 +802,10 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha local affiliation = self:get_affiliation(actor); local current_nick = self._jid_nick[actor]; local role = current_nick and self._occupants[current_nick].role or self:get_default_role(affiliation); - if type == "set" then - local at_least_one_item_provided = false; - local callback = function() origin.send(st.reply(stanza)); end - - -- Gather all changes to affiliations and roles - local jid_affiliation = {}; - local jidnick_role = {}; - for item in stanza.tags[1]:childtags("item") do - at_least_one_item_provided = true; - + local item = stanza.tags[1].tags[1]; + if item and item.name == "item" then + if type == "set" then + local callback = function() origin.send(st.reply(stanza)); end if item.attr.jid then -- Validate provided JID item.attr.jid = jid_prep(item.attr.jid); if not item.attr.jid then @@ -847,55 +820,17 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha local nick = self._jid_nick[item.attr.jid]; if nick then item.attr.nick = select(3, jid_split(nick)); end end - local reason = item.tags[1] and item.tags[1].name == "reason" and #item.tags[1] == 1 and item.tags[1][1]; if item.attr.affiliation and item.attr.jid and not item.attr.role then - jid_affiliation[item.attr.jid] = { ["affiliation"] = item.attr.affiliation, ["reason"] = reason }; + local success, errtype, err = self:set_affiliation(actor, item.attr.jid, item.attr.affiliation, callback, reason); + if not success then origin.send(st.error_reply(stanza, errtype, err)); end elseif item.attr.role and item.attr.nick and not item.attr.affiliation then - jidnick_role[self.jid.."/"..item.attr.nick] = { ["role"] = item.attr.role, ["reason"] = reason }; + local success, errtype, err = self:set_role(actor, self.jid.."/"..item.attr.nick, item.attr.role, callback, reason); + if not success then origin.send(st.error_reply(stanza, errtype, err)); end else origin.send(st.error_reply(stanza, "cancel", "bad-request")); - return; end - end - - if not at_least_one_item_provided then - origin.send(st.error_reply(stanza, "cancel", "bad-request")); - return; - else - local can_set_affiliations, errtype_aff, err_aff = self:can_set_affiliations(actor, jid_affiliation) - local can_set_roles, errtype_role, err_role = self:can_set_roles(actor, jidnick_role) - - if can_set_affiliations and can_set_roles then - local nb_affiliation_changes = 0; - for _ in pairs(jid_affiliation) do nb_affiliation_changes = nb_affiliation_changes + 1; end - local nb_role_changes = 0; - for _ in pairs(jidnick_role) do nb_role_changes = nb_role_changes + 1; end - - if nb_affiliation_changes > 0 and nb_role_changes > 0 then - origin.send(st.error_reply(stanza, "cancel", "bad-request")); - end - if nb_affiliation_changes > 0 then - self:set_affiliations(actor, jid_affiliation, callback); - end - if nb_role_changes > 0 then - self:set_roles(actor, jidnick_role, callback); - end - else - if not can_set_affiliations then - origin.send(st.error_reply(stanza, errtype_aff, err_aff)); - elseif not can_set_roles then - origin.send(st.error_reply(stanza, errtype_role, err_role)); - else - origin.send(st.error_reply(stanza, "cancel", "bad-request")); - end - - return; - end - end - elseif type == "get" then - local item = stanza.tags[1].tags[1]; - if item and item.name == "item" then + elseif type == "get" then local _aff = item.attr.affiliation; local _rol = item.attr.role; if _aff and not _rol then @@ -933,9 +868,9 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha else origin.send(st.error_reply(stanza, "cancel", "bad-request")); end - else - origin.send(st.error_reply(stanza, "cancel", "bad-request")); end + elseif type == "set" or type == "get" then + origin.send(st.error_reply(stanza, "cancel", "bad-request")); end elseif xmlns == "http://jabber.org/protocol/muc#owner" and (type == "get" or type == "set") and stanza.tags[1].name == "query" then if self:get_affiliation(stanza.attr.from) ~= "owner" then @@ -1063,132 +998,82 @@ function room_mt:get_affiliation(jid) if not result and self._affiliations[host] == "outcast" then result = "outcast"; end -- host banned return result; end ---- Checks whether the given affiliation changes in jid_affiliation can be applied by actor. --- Note: Empty tables can always be applied and won't have any effect. -function room_mt:can_set_affiliations(actor, jid_affiliation) - local actor_affiliation; - if actor ~= true then - actor_affiliation = self:get_affiliation(actor); +function room_mt:set_affiliation(actor, jid, affiliation, callback, reason) + jid = jid_bare(jid); + if affiliation == "none" then affiliation = nil; end + if affiliation and affiliation ~= "outcast" and affiliation ~= "owner" and affiliation ~= "admin" and affiliation ~= "member" then + return nil, "modify", "not-acceptable"; end - - -- First let's see if there are any problems with the affiliations given - -- in jid_affiliation - for jid, value in pairs(jid_affiliation) do - local affiliation = value["affiliation"]; - - if jid ~= jid_bare(jid) then - return false, "modify", "not-acceptable"; - end - jid = jid_bare(jid); - if affiliation == "none" then affiliation = nil; end - if affiliation and affiliation ~= "outcast" and affiliation ~= "owner" and affiliation ~= "admin" and affiliation ~= "member" then - return false, "modify", "not-acceptable"; - end - + if actor ~= true then + local actor_affiliation = self:get_affiliation(actor); local target_affiliation = self:get_affiliation(jid); - if target_affiliation == affiliation then - -- no change, no error checking necessary - else - if actor ~= true and actor_affiliation ~= "owner" then - if affiliation == "owner" or affiliation == "admin" or actor_affiliation ~= "admin" or target_affiliation == "owner" or target_affiliation == "admin" then - return false, "cancel", "not-allowed"; - end - elseif target_affiliation == "owner" and jid_bare(actor) == jid then -- self change - local is_last = true; - for j, aff in pairs(self._affiliations) do if j ~= jid and aff == "owner" then is_last = false; break; end end - if is_last then - return false, "cancel", "conflict"; - end + if target_affiliation == affiliation then -- no change, shortcut + if callback then callback(); end + return true; + end + if actor_affiliation ~= "owner" then + if affiliation == "owner" or affiliation == "admin" or actor_affiliation ~= "admin" or target_affiliation == "owner" or target_affiliation == "admin" then + return nil, "cancel", "not-allowed"; + end + elseif target_affiliation == "owner" and jid_bare(actor) == jid then -- self change + local is_last = true; + for j, aff in pairs(self._affiliations) do if j ~= jid and aff == "owner" then is_last = false; break; end end + if is_last then + return nil, "cancel", "conflict"; end end end - - return true; -end ---- Updates the room affiliations by applying the ones given here. --- Takes the affiliations given in jid_affiliation and applies them to --- the room, overwriting a potentially existing affiliation for any given --- jid. --- @param jid_affiliation A table associating a jid with a table consisting --- of two subkeys: `affilation` and `reason`. The jids --- within must not be malformed. -function room_mt:set_affiliations(actor, jid_affiliation, callback) - local can_set, err_type, err_condition = self:can_set_affiliations(actor, jid_affiliation) - - if not can_set then - return false, err_type, err_condition; + self._affiliations[jid] = affiliation; + local role = self:get_default_role(affiliation); + local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}) + :tag("item", {affiliation=affiliation or "none", role=role or "none"}) + :tag("reason"):text(reason or ""):up() + :up(); + local presence_type = nil; + if not role then -- getting kicked + presence_type = "unavailable"; + if affiliation == "outcast" then + x:tag("status", {code="301"}):up(); -- banned + else + x:tag("status", {code="321"}):up(); -- affiliation change + end end -- Your own presence should have status 110 + local self_x = st.clone(x); + self_x:tag("status", {code="110"}); local modified_nicks = {}; - local nb_modified_nicks = 0; - -- Now we can be sure that jid_affiliation causes no problems - -- We can actually set them - for jid, value in pairs(jid_affiliation) do - local affiliation = value["affiliation"]; - local reason = value["reason"]; - - self._affiliations[jid] = affiliation; - local role = self:get_default_role(affiliation); - local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}) - :tag("item", {affiliation=affiliation or "none", role=role or "none"}) - :tag("reason"):text(reason or ""):up() - :up(); - local self_x = st.clone(x); - self_x:tag("status", {code="110"}):up(); - local presence_type = nil; - if not role then -- getting kicked - presence_type = "unavailable"; - if affiliation == "outcast" then - -- banned - x:tag("status", {code="301"}):up(); - self_x:tag("status", {code="301"}):up(); + for nick, occupant in pairs(self._occupants) do + if jid_bare(occupant.jid) == jid then + if not role then -- getting kicked + self._occupants[nick] = nil; else - -- affiliation change - x:tag("status", {code="321"}):up(); - self_x:tag("status", {code="321"}):up(); + occupant.affiliation, occupant.role = affiliation, role; end - end - for nick, occupant in pairs(self._occupants) do - if jid_bare(occupant.jid) == jid then - if not role then -- getting kicked - self._occupants[nick] = nil; - else - occupant.affiliation, occupant.role = affiliation, role; - end - for jid,pres in pairs(occupant.sessions) do -- remove for all sessions of the nick - if not role then self._jid_nick[jid] = nil; end - local p = st.clone(pres); - p.attr.from = nick; - p.attr.type = presence_type; - p.attr.to = jid; - self:_route_stanza(p); - if occupant.jid == jid then + for jid,pres in pairs(occupant.sessions) do -- remove for all sessions of the nick + if not role then self._jid_nick[jid] = nil; end + local p = st.clone(pres); + p.attr.from = nick; + p.attr.type = presence_type; + p.attr.to = jid; + if occupant.jid == jid then -- Broadcast this presence to everyone else later, with the public variant - local bp = st.clone(p); - bp:add_child(x); - modified_nicks[nick] = bp; - nb_modified_nicks = nb_modified_nicks + 1; - end - p:add_child(self_x); - self:_route_stanza(p); + local bp = st.clone(p); + bp:add_child(x); + modified_nicks[nick] = bp; end + p:add_child(self_x); + self:_route_stanza(p); end end end - - if nb_modified_nicks > 0 then - if self.save then self:save(); end - if callback then callback(); end - end + if self.save then self:save(); end + if callback then callback(); end for nick,p in pairs(modified_nicks) do p.attr.from = nick; self:broadcast_except_nick(p, nick); end return true; end -function room_mt:set_affiliation(actor, jid, affiliation, callback, reason) - return self.set_affiliations(actor, { [jid] = { ["affiliation"] = affiliation, ["reason"] = reason } }, callback) -end function room_mt:get_role(nick) local session = self._occupants[nick]; @@ -1212,82 +1097,45 @@ function room_mt:can_set_role(actor_jid, occupant_jid, role) end return nil, "cancel", "not-allowed"; end - ---- Checks whether the given role changes in jidnick_role can be applied by actor. --- Note: Empty tables can always be applied and won't have any effect. -function room_mt:can_set_roles(actor, jidnick_role) - for jidnick, role_info in pairs(jidnick_role) do - local role = role_info["role"]; - if role == "none" then role = nil; end - if role and role ~= "moderator" and role ~= "participant" and role ~= "visitor" then return false, "modify", "not-acceptable"; end - local can_set, err_type, err_condition = self:can_set_role(actor, jidnick, role) - if not can_set then - return false, err_type, err_condition; - end - end - - return true; -end - ---- Updates the room roles by applying the ones given here. --- Takes the roles given in jidnick_role and applies them to --- the room, overwriting a potentially existing role for any given --- jid. --- @param jidnick_role A table associating a jid/nick with a table consisting --- of two subkeys: `role` and `reason`. The jids within --- must not be malformed. -function room_mt:set_roles(actor, jidnick_role, callback) - local allowed, err_type, err_condition = self:can_set_roles(actor, jidnick_role); +function room_mt:set_role(actor, occupant_jid, role, callback, reason) + if role == "none" then role = nil; end + if role and role ~= "moderator" and role ~= "participant" and role ~= "visitor" then return nil, "modify", "not-acceptable"; end + local allowed, err_type, err_condition = self:can_set_role(actor, occupant_jid, role); if not allowed then return allowed, err_type, err_condition; end - - local modified_nicks = {}; - local nb_modified_nicks = 0; - for jidnick, value in pairs(jidnick_role) do - local occupant_jid = jidnick; - local role = value["role"]; - local reason = value["reason"]; - - local occupant = self._occupants[occupant_jid]; - local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}) - :tag("item", {affiliation=occupant.affiliation or "none", nick=select(3, jid_split(occupant_jid)), role=role or "none"}) - :tag("reason"):text(reason or ""):up() - :up(); - local presence_type = nil; - if not role or role == "none" then -- kick - presence_type = "unavailable"; - self._occupants[occupant_jid] = nil; - for jid in pairs(occupant.sessions) do -- remove for all sessions of the nick - self._jid_nick[jid] = nil; - end - x:tag("status", {code = "307"}):up(); - else - occupant.role = role; - end - local self_x = st.clone(x); - self_x:tag("status", {code = "110"}):up(); - local bp; - for jid,pres in pairs(occupant.sessions) do -- send to all sessions of the nick - local p = st.clone(pres); - p.attr.from = occupant_jid; - p.attr.type = presence_type; - p.attr.to = jid; - self:_route_stanza(p); - if occupant.jid == jid then - bp = st.clone(p); - bp:add_child(x); - modified_nicks[occupant_jid] = bp; - nb_modified_nicks = nb_modified_nicks + 1; - end - p:add_child(self_x); - self:route_stanza(p); + local occupant = self._occupants[occupant_jid]; + local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}) + :tag("item", {affiliation=occupant.affiliation or "none", nick=select(3, jid_split(occupant_jid)), role=role or "none"}) + :tag("reason"):text(reason or ""):up() + :up(); + local presence_type = nil; + if not role then -- kick + presence_type = "unavailable"; + self._occupants[occupant_jid] = nil; + for jid in pairs(occupant.sessions) do -- remove for all sessions of the nick + self._jid_nick[jid] = nil; end + x:tag("status", {code = "307"}):up(); + else + occupant.role = role; end - - if nb_modified_nicks > 0 then - if callback then callback(); end + local self_x = st.clone(x); + self_x:tag("status", {code = "110"}):up(); + local bp; + for jid,pres in pairs(occupant.sessions) do -- send to all sessions of the nick + local p = st.clone(pres); + p.attr.from = occupant_jid; + p.attr.type = presence_type; + p.attr.to = jid; + if occupant.jid == jid then + bp = st.clone(p); + bp:add_child(x); + end + p:add_child(self_x); + self:_route_stanza(p); end - for nick,p in pairs(modified_nicks) do - self:broadcast_except_nick(p, nick); + if callback then callback(); end + if bp then + self:broadcast_except_nick(bp, occupant_jid); end return true; end @@ -1311,9 +1159,9 @@ function room_mt:_route_stanza(stanza) for _, item in pairs(muc_child.tags) do if item.name == "item" then if from_occupant == to_occupant then - item.attr.jid = jid_bare(stanza.attr.to); + item.attr.jid = stanza.attr.to; else - item.attr.jid = jid_bare(from_occupant.jid); + item.attr.jid = from_occupant.jid; end end end -- cgit v1.2.3