X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=plugins%2Fmuc%2Fmuc.lib.lua;h=552b9e49970a5e6e5f950d6b598316d6d65008dc;hb=2c5b77cf0f73aa0c7408d61195e438e0de59a0b1;hp=483b0812b0d7e538c90a64b435f9bda0938158c6;hpb=6f472e97f9fa97e19d1053fdf7507b6b4e99d925;p=prosody.git diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 483b0812..552b9e49 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -1,7 +1,7 @@ -- Prosody IM -- Copyright (C) 2008-2010 Matthew Wild -- Copyright (C) 2008-2010 Waqas Hussain --- +-- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- @@ -107,18 +107,21 @@ function room_mt:broadcast_message(stanza, historic) end stanza.attr.to = to; if historic then -- add to history - local history = self._data['history']; - if not history then history = {}; self._data['history'] = history; end - stanza = st.clone(stanza); - stanza.attr.to = ""; - local stamp = datetime.datetime(); - stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = muc_domain, stamp = stamp}):up(); -- XEP-0203 - stanza:tag("x", {xmlns = "jabber:x:delay", from = muc_domain, stamp = datetime.legacy()}):up(); -- XEP-0091 (deprecated) - local entry = { stanza = stanza, stamp = stamp }; - t_insert(history, entry); - while #history > (self._data.history_length or default_history_length) do t_remove(history, 1) end + return self:save_to_history(stanza) end end +function room_mt:save_to_history(stanza) + local history = self._data['history']; + if not history then history = {}; self._data['history'] = history; end + stanza = st.clone(stanza); + stanza.attr.to = ""; + local stamp = datetime.datetime(); + stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = muc_domain, stamp = stamp}):up(); -- XEP-0203 + stanza:tag("x", {xmlns = "jabber:x:delay", from = muc_domain, stamp = datetime.legacy()}):up(); -- XEP-0091 (deprecated) + local entry = { stanza = stanza, stamp = stamp }; + t_insert(history, entry); + while #history > (self._data.history_length or default_history_length) do t_remove(history, 1) end +end function room_mt:broadcast_except_nick(stanza, nick) for rnick, occupant in pairs(self._occupants) do if rnick ~= nick then @@ -147,10 +150,10 @@ function room_mt:send_history(to, stanza) if history then local x_tag = stanza and stanza:get_child("x", "http://jabber.org/protocol/muc"); local history_tag = x_tag and x_tag:get_child("history", "http://jabber.org/protocol/muc"); - + local maxchars = history_tag and tonumber(history_tag.attr.maxchars); 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 = 20; end @@ -163,7 +166,7 @@ function room_mt:send_history(to, stanza) local n = 0; local charcount = 0; - + for i=#history,1,-1 do local entry = history[i]; if maxchars then @@ -184,6 +187,8 @@ function room_mt:send_history(to, stanza) self:_route_stanza(msg); end end +end +function room_mt:send_subject(to) if self._data['subject'] then self:_route_stanza(st.message({type='groupchat', from=self._data['subject_from'] or self.jid, to=to}):tag("subject"):text(self._data['subject'])); end @@ -191,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() @@ -200,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"}, - { 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"); @@ -351,12 +363,12 @@ local function construct_stanza_id(room, stanza) local from_nick = room._jid_nick[from_jid]; local occupant = room._occupants[to_nick]; local to_jid = occupant.jid; - + return from_nick, to_jid, base64.encode(to_jid.."\0"..stanza.attr.id.."\0"..md5(from_jid)); 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 @@ -480,6 +492,12 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc log("debug", "%s joining as %s", from, to); if not next(self._affiliations) then -- new room, no owners self._affiliations[jid_bare(from)] = "owner"; + if self.locked and not stanza:get_child("x", "http://jabber.org/protocol/muc") then + self.locked = nil; -- Older groupchat protocol doesn't lock + end + elseif self.locked then -- Deny entry + origin.send(st.error_reply(stanza, "cancel", "item-not-found")); + return; end local affiliation = self:get_affiliation(from); local role = self:get_default_role(affiliation) @@ -501,9 +519,13 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc if self._data.whois == 'anyone' then pr:tag("status", {code='100'}):up(); end + if self.locked then + pr:tag("status", {code='201'}):up(); + end pr.attr.to = from; self:_route_stanza(pr); self:send_history(from, stanza); + self:send_subject(from); elseif not affiliation then -- registration required for entering members-only room local reply = st.error_reply(stanza, "auth", "registration-required"):up(); reply.tags[1].attr.code = "407"; @@ -555,6 +577,7 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc end stanza.attr.from, stanza.attr.to, stanza.attr.id = from, to, id; else -- message + stanza:tag("x", { xmlns = "http://jabber.org/protocol/muc#user" }):up(); stanza.attr.from = current_nick; for jid in pairs(o_data.sessions) do stanza.attr.to = jid; @@ -658,15 +681,17 @@ 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 - + 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; @@ -688,11 +713,15 @@ function room_mt:process_form(origin, stanza) handle_option("password", "muc#roomconfig_roomsecret"); if self.save then self:save(true); end + if self.locked then + module:fire_event("muc-room-unlocked", { room = self }); + self.locked = nil; + end origin.send(st.reply(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"; @@ -1012,7 +1041,7 @@ function room_mt:can_set_role(actor_jid, occupant_jid, role) if actor_jid == true then return true; end local actor = self._occupants[self._jid_nick[actor_jid]]; - if actor.role == "moderator" then + if actor and actor.role == "moderator" then if occupant.affiliation ~= "owner" and occupant.affiliation ~= "admin" then if actor.affiliation == "owner" or actor.affiliation == "admin" then return true;