MUC: Allow members (or above) in members-only non-anonymous rooms to see the member...
[prosody.git] / plugins / muc / muc.lib.lua
index 8cf8d882e5895962a2a3e779267a52e9d6cc4e46..4018489ad7832f70970813b7b15aa122309b398b 100644 (file)
@@ -196,7 +196,7 @@ end
 
 function room_mt:get_disco_info(stanza)
        local count = 0; for _ in pairs(self._occupants) do count = count + 1; end
-       return st.reply(stanza):query("http://jabber.org/protocol/disco#info")
+       local reply = st.reply(stanza):query("http://jabber.org/protocol/disco#info")
                :tag("identity", {category="conference", type="text", name=self:get_name()}):up()
                :tag("feature", {var="http://jabber.org/protocol/muc"}):up()
                :tag("feature", {var=self:get_password() and "muc_passwordprotected" or "muc_unsecured"}):up()
@@ -205,12 +205,19 @@ function room_mt:get_disco_info(stanza)
                :tag("feature", {var=self:get_persistent() and "muc_persistent" or "muc_temporary"}):up()
                :tag("feature", {var=self:get_hidden() and "muc_hidden" or "muc_public"}):up()
                :tag("feature", {var=self._data.whois ~= "anyone" and "muc_semianonymous" or "muc_nonanonymous"}):up()
-               :add_child(dataform.new({
-                       { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/muc#roominfo" },
-                       { name = "muc#roominfo_description", label = "Description", value = "" },
-                       { name = "muc#roominfo_occupants", label = "Number of occupants", value = tostring(count) }
-               }):form({["muc#roominfo_description"] = self:get_description()}, 'result'))
        ;
+       local dataform = dataform.new({
+               { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/muc#roominfo" },
+               { name = "muc#roominfo_description", label = "Description", value = "" },
+               { name = "muc#roominfo_occupants", label = "Number of occupants", value = "" }
+       });
+       local formdata = {
+               ["muc#roominfo_description"] = self:get_description(),
+               ["muc#roominfo_occupants"] = tostring(count),
+       };
+       module:fire_event("muc-disco#info", { room = self, reply = reply, form = dataform, formdata = formdata });
+       reply:add_child(dataform:form(formdata, 'result'))
+       return reply;
 end
 function room_mt:get_disco_items(stanza)
        local reply = st.reply(stanza):query("http://jabber.org/protocol/disco#items");
@@ -361,7 +368,7 @@ local function construct_stanza_id(room, stanza)
 end
 local function deconstruct_stanza_id(room, stanza)
        local from_jid_possiblybare, to_nick = stanza.attr.from, stanza.attr.to;
-       local from_jid, id, to_jid_hash = (base64.decode(stanza.attr.id) or ""):match("^(.+)%z(.*)%z(.+)$");
+       local from_jid, id, to_jid_hash = (base64.decode(stanza.attr.id) or ""):match("^(%Z+)%z(%Z*)%z(.+)$");
        local from_nick = room._jid_nick[from_jid];
 
        if not(from_nick) then return; end
@@ -674,15 +681,24 @@ function room_mt:process_form(origin, stanza)
        if form.attr.type == "cancel" then origin.send(st.reply(stanza)); return; end
        if form.attr.type ~= "submit" then origin.send(st.error_reply(stanza, "cancel", "bad-request", "Not a submitted form")); return; end
 
-       local fields = 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")); return; end
+       if form.tags[1] == nil then
+               -- instant room
+               if self.save then self:save(true); end
+               origin.send(st.reply(stanza));
+               return true;
+       end
 
+       local 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"));
+               return;
+       end
 
        local changed = {};
 
        local function handle_option(name, field, allowed)
+               if not present[field] then return; end
                local new = fields[field];
-               if new == nil then return; end
                if allowed and not allowed[new] then return; end
                if new == self["get_"..name](self) then return; end
                changed[name] = true;
@@ -712,7 +728,7 @@ function room_mt:process_form(origin, stanza)
 
        if next(changed) then
                local msg = st.message({type='groupchat', from=self.jid})
-                       :tag('x', {xmlns='http://jabber.org/protocol/muc#user'}):up()
+                       :tag('x', {xmlns='http://jabber.org/protocol/muc#user'})
                                :tag('status', {code = '104'}):up();
                if changed.whois then
                        local code = (self:get_whois() == 'moderators') and "173" or "172";
@@ -787,7 +803,8 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha
                                        local _aff = item.attr.affiliation;
                                        local _rol = item.attr.role;
                                        if _aff and not _rol then
-                                               if affiliation == "owner" or (affiliation == "admin" and _aff ~= "owner" and _aff ~= "admin") then
+                                               if affiliation == "owner" or (affiliation == "admin" and _aff ~= "owner" and _aff ~= "admin")
+                                               or (affiliation and affiliation ~= "outcast" and self:get_members_only() and self:get_whois() == "anyone") then
                                                        local reply = st.reply(stanza):query("http://jabber.org/protocol/muc#admin");
                                                        for jid, affiliation in pairs(self._affiliations) do
                                                                if affiliation == _aff then