From 4db96d1b1f410f99994962c41e0ab1428f7b9027 Mon Sep 17 00:00:00 2001 From: Waqas Hussain Date: Mon, 7 Sep 2009 20:51:59 +0500 Subject: MUC: Added support for room configuration forms, persistence and hidden rooms. --- plugins/muc/mod_muc.lua | 51 +++++++++++++++++++++++++++++++++++++++++++---- plugins/muc/muc.lib.lua | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 4 deletions(-) diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index c61ac238..41c8a749 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -21,11 +21,50 @@ local deregister_component = require "core.componentmanager".deregister_componen local jid_split = require "util.jid".split; local st = require "util.stanza"; local uuid_gen = require "util.uuid".generate; +local datamanager = require "util.datamanager"; local rooms = {}; +local persistent_rooms = datamanager.load(nil, muc_host, "persistent") or {}; local component; + +local function room_route_stanza(room, stanza) core_post_stanza(component, stanza); end +local function room_save(room, forced) + local node = jid_split(room.jid); + persistent_rooms[room.jid] = room._data.persistent; + module:log("debug", "1, %s, %s", room.jid, tostring(room._data.persistent)); + if room._data.persistent then + module:log("debug", "2"); + local history = room._data.history; + room._data.history = nil; + local data = { + jid = room.jid; + _data = room._data; + _affiliations = room._affiliations; + }; + datamanager.store(node, muc_host, "config", data); + room._data.history = history; + elseif forced then + module:log("debug", "3"); + datamanager.store(node, muc_host, "config", nil); + end + module:log("debug", "4"); + if forced then datamanager.store(nil, muc_host, "persistent", persistent_rooms); end +end + +for jid in pairs(persistent_rooms) do + local node = jid_split(jid); + local data = datamanager.load(node, muc_host, "config") or {}; + local room = muc_new_room(jid); + room._data = data._data; + room._affiliations = data._affiliations; + room.route_stanza = room_route_stanza; + room.save = room_save; + rooms[jid] = room; +end + local host_room = muc_new_room(muc_host); -host_room.route_stanza = function(room, stanza) core_post_stanza(component, stanza); end; +host_room.route_stanza = room_route_stanza; +host_room.save = room_save; local function get_disco_info(stanza) return st.iq({type='result', id=stanza.attr.id, from=muc_host, to=stanza.attr.from}):query("http://jabber.org/protocol/disco#info") @@ -35,7 +74,9 @@ end local function get_disco_items(stanza) local reply = st.iq({type='result', id=stanza.attr.id, from=muc_host, to=stanza.attr.from}):query("http://jabber.org/protocol/disco#items"); for jid, room in pairs(rooms) do - reply:tag("item", {jid=jid, name=jid}):up(); + if not room._data.hidden then + reply:tag("item", {jid=jid, name=jid}):up(); + end end return reply; -- TODO cache disco reply end @@ -68,7 +109,8 @@ component = register_component(muc_host, function(origin, stanza) local room = rooms[bare]; if not room then room = muc_new_room(bare); - room.route_stanza = function(room, stanza) core_post_stanza(component, stanza); end; + room.route_stanza = room_route_stanza; + room.save = room_save; rooms[bare] = room; end room:handle_stanza(origin, stanza); @@ -95,7 +137,8 @@ module.restore = function(data) room._occupants = oldroom._occupants; room._data = oldroom._data; room._affiliations = oldroom._affiliations; - room.route_stanza = function(room, stanza) core_post_stanza(component, stanza); end; + room.route_stanza = room_route_stanza; + room.save = room_save; rooms[jid] = room; end prosody.hosts[module:get_host()].muc = { rooms = rooms }; diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index b0d2b73d..0d7e2581 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -190,6 +190,7 @@ function room_mt:set_subject(current_nick, subject) -- TODO check nick's authority if subject == "" then subject = nil; end self._data['subject'] = subject; + if self.save then self:save(); end local msg = st.message({type='groupchat', from=current_nick}) :tag('subject'):text(subject):up(); self:broadcast_message(msg, false); @@ -307,6 +308,53 @@ function room_mt:handle_to_occupant(origin, stanza) -- PM, vCards, etc end end +function room_mt:handle_form(origin, stanza) + if self:get_affiliation(stanza.attr.from) ~= "owner" then origin.send(st.error_reply(nil, "auth", "forbidden")); return; end + if stanza.attr.type == "get" then + local title = "Configuration for "..self.jid; + origin.send(st.reply(stanza):query("http://jabber.org/protocol/muc#owner") + :tag("x", {xmlns='jabber:x:data', type='form'}) + :tag("title"):text(title):up() + :tag("instructions"):text(title):up() + :tag("field", {type='hidden', var='FORM_TYPE'}):tag("value"):text("http://jabber.org/protocol/muc#roomconfig"):up():up() + :tag("field", {type='boolean', label='Make Room Persistent?', var='muc#roomconfig_persistentroom'}) + :tag("value"):text(self._data.persistent and "1" or "0"):up() + :up() + :tag("field", {type='boolean', label='Make Room Publicly Searchable?', var='muc#roomconfig_publicroom'}) + :tag("value"):text(self._data.hidden and "0" or "1"):up() + :up() + ); + elseif stanza.attr.type == "set" then + local query = stanza.tags[1]; + local form; + for _, tag in ipairs(query.tags) do if tag.name == "x" and tag.attr.xmlns == "jabber:x:data" then form = tag; break; end end + if not form then origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); return; end + 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")); return; end + local fields = {}; + for _, field in pairs(form.tags) do + if field.name == "field" and field.attr.var and field.tags[1].name == "value" and #field.tags[1].tags == 0 then + fields[field.attr.var] = field.tags[1][1] or ""; + end + end + if fields.FORM_TYPE ~= "http://jabber.org/protocol/muc#roomconfig" then origin.send(st.error_reply(stanza, "cancel", "bad-request")); return; end + + local persistent = fields['muc#roomconfig_persistentroom']; + if persistent == "0" or persistent == "false" then persistent = nil; elseif persistent == "1" or persistent == "true" then persistent = true; + else origin.send(st.error_reply(stanza, "cancel", "bad-request")); return; end + self._data.persistent = persistent; + module:log("debug", "persistent=%s", tostring(persistent)); + + local public = fields['muc#roomconfig_publicroom']; + if public == "0" or public == "false" then public = nil; elseif public == "1" or public == "true" then public = true; + else origin.send(st.error_reply(stanza, "cancel", "bad-request")); return; end + self._data.hidden = not public and true or nil; + + if self.save then self:save(true); end + origin.send(st.reply(stanza)); + end +end + function room_mt:handle_to_room(origin, stanza) -- presence changes and groupchat messages, along with disco/etc local type = stanza.attr.type; local xmlns = stanza.tags[1] and stanza.tags[1].attr.xmlns; @@ -373,6 +421,10 @@ function room_mt:handle_to_room(origin, stanza) -- presence changes and groupcha elseif type == "set" or type == "get" then origin.send(st.error_reply(stanza, "cancel", "bad-request")); end + elseif xmlns == "http://jabber.org/protocol/muc#owner" and (type == "get" or type == "set") and stanza.tags[1].name == "query" then + self:handle_form(origin, stanza); + elseif type == "set" or type == "get" then + origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); end elseif stanza.name == "message" and type == "groupchat" then local from, to = stanza.attr.from, stanza.attr.to; @@ -474,6 +526,7 @@ function room_mt:set_affiliation(actor, jid, affiliation, callback) end end end + if room.save then room:save(); end if callback then callback(); end for _, nick in ipairs(modified_nicks) do p.attr.from = nick; -- cgit v1.2.3