Software /
code /
prosody
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 |