Comparison

plugins/muc/muc.lib.lua @ 8791:8da11142fabf

muc: Allow clients to change multiple affiliations or roles at once (#345) According to XEP-0045 sections 9.2, 9.5 and 9.8 affiliation lists and role lists should allow mass-modification. Prosody however would just use the first entry of the list and ignore the rest. This is fixed by introducing a `for` loop to `set` stanzas of the respective `muc#admin` namespace. In order for this loop to work, the error handling was changed a little. Prosody no longer returns after the first error. Instead, an error reply is sent for each malformed or otherwise wrong entry, but the loop keeps going over the other entries. This may lead to multiple error messages being sent for one client request. A notable exception from this is when the XML Schema for `muc#admin` requests is violated. In that case the loop is aborted with an error message to the client. The change is a bit bigger than that in order to have the loop only for `set` stanzas without changing the behaviour of the `get` stanzas. This is now more in line with trunk, where there are separate methods for each stanza type. References: #345
author Lennart Sauerbeck <devel@lennart.sauerbeck.org>
date Sat, 18 Mar 2017 18:47:28 +0100
parent 8590:4b5a00fffb22
child 8792:c2b99fa134b3
comparison
equal deleted inserted replaced
8790:85f13967eb07 8791:8da11142fabf
800 elseif xmlns == "http://jabber.org/protocol/muc#admin" then 800 elseif xmlns == "http://jabber.org/protocol/muc#admin" then
801 local actor = stanza.attr.from; 801 local actor = stanza.attr.from;
802 local affiliation = self:get_affiliation(actor); 802 local affiliation = self:get_affiliation(actor);
803 local current_nick = self._jid_nick[actor]; 803 local current_nick = self._jid_nick[actor];
804 local role = current_nick and self._occupants[current_nick].role or self:get_default_role(affiliation); 804 local role = current_nick and self._occupants[current_nick].role or self:get_default_role(affiliation);
805 local item = stanza.tags[1].tags[1]; 805 if type == "set" then
806 if item and item.name == "item" then 806 local at_least_one_item_provided = false;
807 if type == "set" then 807
808 for item in stanza.tags[1]:childtags("item") do
809 at_least_one_item_provided = true;
810
808 local callback = function() origin.send(st.reply(stanza)); end 811 local callback = function() origin.send(st.reply(stanza)); end
809 if item.attr.jid then -- Validate provided JID 812 if item.attr.jid then -- Validate provided JID
810 item.attr.jid = jid_prep(item.attr.jid); 813 item.attr.jid = jid_prep(item.attr.jid);
811 if not item.attr.jid then 814 if not item.attr.jid then
812 origin.send(st.error_reply(stanza, "modify", "jid-malformed")); 815 origin.send(st.error_reply(stanza, "modify", "jid-malformed"));
813 return;
814 end 816 end
815 end 817 end
816 if not item.attr.jid and item.attr.nick then -- COMPAT Workaround for Miranda sending 'nick' instead of 'jid' when changing affiliation 818 if not item.attr.jid and item.attr.nick then -- COMPAT Workaround for Miranda sending 'nick' instead of 'jid' when changing affiliation
817 local occupant = self._occupants[self.jid.."/"..item.attr.nick]; 819 local occupant = self._occupants[self.jid.."/"..item.attr.nick];
818 if occupant then item.attr.jid = occupant.jid; end 820 if occupant then item.attr.jid = occupant.jid; end
827 elseif item.attr.role and item.attr.nick and not item.attr.affiliation then 829 elseif item.attr.role and item.attr.nick and not item.attr.affiliation then
828 local success, errtype, err = self:set_role(actor, self.jid.."/"..item.attr.nick, item.attr.role, callback, reason); 830 local success, errtype, err = self:set_role(actor, self.jid.."/"..item.attr.nick, item.attr.role, callback, reason);
829 if not success then origin.send(st.error_reply(stanza, errtype, err)); end 831 if not success then origin.send(st.error_reply(stanza, errtype, err)); end
830 else 832 else
831 origin.send(st.error_reply(stanza, "cancel", "bad-request")); 833 origin.send(st.error_reply(stanza, "cancel", "bad-request"));
834 return;
832 end 835 end
833 elseif type == "get" then 836 end
837
838 if not at_least_one_item_provided then
839 origin.send(st.error_reply(stanza, "cancel", "bad-request"));
840 return;
841 end
842 elseif type == "get" then
843 local item = stanza.tags[1].tags[1];
844 if item and item.name == "item" then
834 local _aff = item.attr.affiliation; 845 local _aff = item.attr.affiliation;
835 local _rol = item.attr.role; 846 local _rol = item.attr.role;
836 if _aff and not _rol then 847 if _aff and not _rol then
837 if affiliation == "owner" or (affiliation == "admin" and _aff ~= "owner" and _aff ~= "admin") 848 if affiliation == "owner" or (affiliation == "admin" and _aff ~= "owner" and _aff ~= "admin")
838 or (affiliation and affiliation ~= "outcast" and self:get_members_only() and self:get_whois() == "anyone") then 849 or (affiliation and affiliation ~= "outcast" and self:get_members_only() and self:get_whois() == "anyone") then
866 origin.send(st.error_reply(stanza, "auth", "forbidden")); 877 origin.send(st.error_reply(stanza, "auth", "forbidden"));
867 end 878 end
868 else 879 else
869 origin.send(st.error_reply(stanza, "cancel", "bad-request")); 880 origin.send(st.error_reply(stanza, "cancel", "bad-request"));
870 end 881 end
871 end 882 else
872 elseif type == "set" or type == "get" then 883 origin.send(st.error_reply(stanza, "cancel", "bad-request"));
873 origin.send(st.error_reply(stanza, "cancel", "bad-request")); 884 end
874 end 885 end
875 elseif xmlns == "http://jabber.org/protocol/muc#owner" and (type == "get" or type == "set") and stanza.tags[1].name == "query" then 886 elseif xmlns == "http://jabber.org/protocol/muc#owner" and (type == "get" or type == "set") and stanza.tags[1].name == "query" then
876 if self:get_affiliation(stanza.attr.from) ~= "owner" then 887 if self:get_affiliation(stanza.attr.from) ~= "owner" then
877 origin.send(st.error_reply(stanza, "auth", "forbidden", "Only owners can configure rooms")); 888 origin.send(st.error_reply(stanza, "auth", "forbidden", "Only owners can configure rooms"));
878 elseif stanza.attr.type == "get" then 889 elseif stanza.attr.type == "get" then