X-Git-Url: https://git.enpas.org/?a=blobdiff_plain;f=plugins%2Fmuc%2Fmod_muc.lua;h=16727f268d794a27c085124919eb94bb2c7cd734;hb=8dcebf9a034d176ce017ef5d28a638854a3bca0a;hp=db85a73fdf03511b90cd3b0574c2afa570fa37bd;hpb=08cba26d87fc68ef70ccff6edaeccbd88539f7ed;p=prosody.git diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index db85a73f..5ac230ad 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -7,19 +7,66 @@ -- if module:get_host_type() ~= "component" then - error("MUC should be loaded as a component, please see http://prosody.im/doc/components", 0); + error("MUC should be loaded as a component, please see https://prosody.im/doc/components", 0); end local muclib = module:require "muc"; room_mt = muclib.room_mt; -- Yes, global. -local iterators = require "util.iterators"; + +local affiliation_notify = module:require "muc/affiliation_notify"; -- luacheck: ignore 211 + +local name = module:require "muc/name"; +room_mt.get_name = name.get; +room_mt.set_name = name.set; + +local description = module:require "muc/description"; +room_mt.get_description = description.get; +room_mt.set_description = description.set; + +local hidden = module:require "muc/hidden"; +room_mt.get_hidden = hidden.get; +room_mt.set_hidden = hidden.set; +function room_mt:get_public() + return not self:get_hidden(); +end +function room_mt:set_public(public) + return self:set_hidden(not public); +end + +local password = module:require "muc/password"; +room_mt.get_password = password.get; +room_mt.set_password = password.set; + +local members_only = module:require "muc/members_only"; +room_mt.get_members_only = members_only.get; +room_mt.set_members_only = members_only.set; + +local moderated = module:require "muc/moderated"; +room_mt.get_moderated = moderated.get; +room_mt.set_moderated = moderated.set; + +local persistent = module:require "muc/persistent"; +room_mt.get_persistent = persistent.get; +room_mt.set_persistent = persistent.set; + +local subject = module:require "muc/subject"; +room_mt.get_changesubject = subject.get_changesubject; +room_mt.set_changesubject = subject.set_changesubject; +room_mt.get_subject = subject.get; +room_mt.set_subject = subject.set; +room_mt.send_subject = subject.send; + +local history = module:require "muc/history"; +room_mt.send_history = history.send; +room_mt.get_historylength = history.get_length; +room_mt.set_historylength = history.set_length; + local jid_split = require "util.jid".split; local jid_bare = require "util.jid".bare; local st = require "util.stanza"; +local cache = require "util.cache"; local um_is_admin = require "core.usermanager".is_admin; -local rooms = module:shared "rooms"; - module:depends("disco"); module:add_identity("conference", "text", module:get_option_string("name", "Prosody Chatrooms")); module:add_feature("http://jabber.org/protocol/muc"); @@ -38,13 +85,12 @@ do -- Monkey patch to make server admins room owners end local _set_affiliation = room_mt.set_affiliation; - function room_mt:set_affiliation(actor, jid, ...) - if is_admin(jid) then return nil, "modify", "not-acceptable"; end - return _set_affiliation(self, actor, jid, ...); + function room_mt:set_affiliation(actor, jid, affiliation, reason) + if affiliation ~= "owner" and is_admin(jid) then return nil, "modify", "not-acceptable"; end + return _set_affiliation(self, actor, jid, affiliation, reason); end end -local persistent = module:require "muc/persistent"; local persistent_rooms_storage = module:open_store("persistent"); local persistent_rooms = module:open_store("persistent", "map"); local room_configs = module:open_store("config"); @@ -52,25 +98,21 @@ local room_configs = module:open_store("config"); local function room_save(room, forced) local node = jid_split(room.jid); local is_persistent = persistent.get(room); - persistent_rooms:set(nil, room.jid, is_persistent); - if is_persistent then - local history = room._data.history; - room._data.history = nil; - local data = { - jid = room.jid; - _data = room._data; - _affiliations = room._affiliations; - }; - room_configs:set(node, data); - room._data.history = history; - elseif forced then - room_configs:set(node, nil); - if not next(room._occupants) then -- Room empty - rooms[room.jid] = nil; - end + if is_persistent or forced then + persistent_rooms:set(nil, room.jid, true); + local data = room:freeze(forced); + return room_configs:set(node, data); + else + persistent_rooms:set(nil, room.jid, nil); + return room_configs:set(node, nil); end end +local rooms = cache.new(module:get_option_number("muc_room_cache_size", 100), function (_, room) + module:log("debug", "%s evicted", room); + room_save(room, true); -- Force to disk +end); + -- Automatically destroy empty non-persistent rooms module:hook("muc-occupant-left",function(event) local room = event.room @@ -80,7 +122,7 @@ module:hook("muc-occupant-left",function(event) end); function track_room(room) - rooms[room.jid] = room; + rooms:set(room.jid, room); -- When room is created, over-ride 'save' method room.save = room_save; end @@ -89,51 +131,61 @@ local function restore_room(jid) local node = jid_split(jid); local data = room_configs:get(node); if data then - local room = muclib.new_room(jid); - room._data = data._data; - room._affiliations = data._affiliations; + local room = muclib.restore_room(data); track_room(room); return room; end end function forget_room(room) - local room_jid = room.jid; - local node = jid_split(room.jid); - rooms[room_jid] = nil; - room_configs:set(node, nil); - if persistent.get(room) then - persistent_rooms:set(nil, room_jid, nil); + module:log("debug", "Forgetting %s", room); + rooms.save = nil; + rooms:set(room.jid, nil); +end + +function delete_room(room) + module:log("debug", "Deleting %s", room); + room_configs:set(jid_split(room.jid), nil); + persistent_rooms:set(nil, room.jid, nil); +end + +function module.unload() + for room in rooms:values() do + room:save(true); + forget_room(room); end end function get_room_from_jid(room_jid) - local room = rooms[room_jid]; - if room == nil then - -- Check if in persistent storage - if persistent_rooms:get(nil, room_jid) then - room = restore_room(room_jid); - if room == nil then - module:log("error", "Missing data for room '%s', removing from persistent room list", room_jid); - persistent_rooms:set(nil, room_jid, nil); - end - end + local room = rooms:get(room_jid); + if room then + rooms:set(room_jid, room); -- bump to top; + return room; end - return room + return restore_room(room_jid); end function each_room(local_only) - if not local_only then + if local_only then + return rooms:values(); + end + return coroutine.wrap(function () + local seen = {}; -- Don't iterate over persistent rooms twice + for room in rooms:values() do + coroutine.yield(room); + seen[room.jid] = true; + end for room_jid in pairs(persistent_rooms_storage:get(nil) or {}) do - if rooms[room_jid] == nil then -- Don't restore rooms that already exist + if seen[room_jid] then local room = restore_room(room_jid); if room == nil then module:log("error", "Missing data for room '%s', omitting from iteration", room_jid); + else + coroutine.yield(room); end end end - end - return iterators.values(rooms); + end); end module:hook("host-disco-items", function(event) @@ -151,8 +203,10 @@ module:hook("muc-room-pre-create", function(event) end, -1000); module:hook("muc-room-destroyed",function(event) - return forget_room(event.room); -end) + local room = event.room; + forget_room(room); + delete_room(room); +end); do local restrict_room_creation = module:get_option("restrict_room_creation"); @@ -207,9 +261,11 @@ for event_name, method in pairs { -- Watch presence to create rooms if stanza.attr.type == nil and stanza.name == "presence" then room = muclib.new_room(room_jid); - else + elseif stanza.attr.type ~= "error" then origin.send(st.error_reply(stanza, "cancel", "not-allowed")); return true; + else + return; end end return room[method](room, origin, stanza); @@ -246,8 +302,8 @@ do -- Ad-hoc commands end, function(fields, errors) if errors then local errmsg = {}; - for name, err in pairs(errors) do - errmsg[#errmsg + 1] = name .. ": " .. err; + for field, err in pairs(errors) do + errmsg[#errmsg + 1] = field .. ": " .. err; end return { status = "completed", error = { message = t_concat(errmsg, "\n") } }; end