Mercurial > prosody-hg
comparison plugins/muc/mod_muc.lua @ 6145:69bc9dfcbd89
Merge daurnimator->trunk
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Mon, 21 Apr 2014 17:42:44 +0100 |
| parents | bf6de8ef66c2 |
| children | e488a90195bc |
comparison
equal
deleted
inserted
replaced
| 6090:61403eb023bf | 6145:69bc9dfcbd89 |
|---|---|
| 29 local muclib = module:require "muc"; | 29 local muclib = module:require "muc"; |
| 30 local muc_new_room = muclib.new_room; | 30 local muc_new_room = muclib.new_room; |
| 31 local jid_split = require "util.jid".split; | 31 local jid_split = require "util.jid".split; |
| 32 local jid_bare = require "util.jid".bare; | 32 local jid_bare = require "util.jid".bare; |
| 33 local st = require "util.stanza"; | 33 local st = require "util.stanza"; |
| 34 local uuid_gen = require "util.uuid".generate; | |
| 35 local um_is_admin = require "core.usermanager".is_admin; | 34 local um_is_admin = require "core.usermanager".is_admin; |
| 36 local hosts = prosody.hosts; | 35 local hosts = prosody.hosts; |
| 37 | 36 |
| 38 rooms = {}; | 37 rooms = {}; |
| 39 local rooms = rooms; | 38 local rooms = rooms; |
| 45 muclib.set_max_history_length(module:get_option_number("max_history_messages")); | 44 muclib.set_max_history_length(module:get_option_number("max_history_messages")); |
| 46 | 45 |
| 47 module:depends("disco"); | 46 module:depends("disco"); |
| 48 module:add_identity("conference", "text", muc_name); | 47 module:add_identity("conference", "text", muc_name); |
| 49 module:add_feature("http://jabber.org/protocol/muc"); | 48 module:add_feature("http://jabber.org/protocol/muc"); |
| 49 module:depends "muc_unique" | |
| 50 | 50 |
| 51 local function is_admin(jid) | 51 local function is_admin(jid) |
| 52 return um_is_admin(jid, module.host); | 52 return um_is_admin(jid, module.host); |
| 53 end | 53 end |
| 54 | 54 |
| 62 function muclib.room_mt:set_affiliation(actor, jid, affiliation, callback, reason) | 62 function muclib.room_mt:set_affiliation(actor, jid, affiliation, callback, reason) |
| 63 if is_admin(jid) then return nil, "modify", "not-acceptable"; end | 63 if is_admin(jid) then return nil, "modify", "not-acceptable"; end |
| 64 return _set_affiliation(self, actor, jid, affiliation, callback, reason); | 64 return _set_affiliation(self, actor, jid, affiliation, callback, reason); |
| 65 end | 65 end |
| 66 | 66 |
| 67 local function room_route_stanza(room, stanza) module:send(stanza); end | |
| 68 local function room_save(room, forced) | 67 local function room_save(room, forced) |
| 69 local node = jid_split(room.jid); | 68 local node = jid_split(room.jid); |
| 70 persistent_rooms[room.jid] = room._data.persistent; | 69 persistent_rooms[room.jid] = room._data.persistent; |
| 71 if room._data.persistent then | 70 if room._data.persistent then |
| 72 local history = room._data.history; | 71 local history = room._data.history; |
| 87 if forced then persistent_rooms_storage:set(nil, persistent_rooms); end | 86 if forced then persistent_rooms_storage:set(nil, persistent_rooms); end |
| 88 end | 87 end |
| 89 | 88 |
| 90 function create_room(jid) | 89 function create_room(jid) |
| 91 local room = muc_new_room(jid); | 90 local room = muc_new_room(jid); |
| 92 room.route_stanza = room_route_stanza; | |
| 93 room.save = room_save; | 91 room.save = room_save; |
| 94 rooms[jid] = room; | 92 rooms[jid] = room; |
| 95 if lock_rooms then | 93 if lock_rooms then |
| 96 room.locked = true; | 94 room:lock(); |
| 97 if lock_room_timeout and lock_room_timeout > 0 then | 95 if lock_room_timeout and lock_room_timeout > 0 then |
| 98 module:add_timer(lock_room_timeout, function () | 96 module:add_timer(lock_room_timeout, function () |
| 99 if room.locked then | 97 if room:is_locked() then |
| 100 room:destroy(); -- Not unlocked in time | 98 room:destroy(); -- Not unlocked in time |
| 101 end | 99 end |
| 102 end); | 100 end); |
| 103 end | 101 end |
| 104 end | 102 end |
| 105 module:fire_event("muc-room-created", { room = room }); | 103 module:fire_event("muc-room-created", { room = room }); |
| 106 return room; | 104 return room; |
| 105 end | |
| 106 | |
| 107 function forget_room(jid) | |
| 108 rooms[jid] = nil; | |
| 109 end | |
| 110 | |
| 111 function get_room_from_jid(room_jid) | |
| 112 return rooms[room_jid] | |
| 107 end | 113 end |
| 108 | 114 |
| 109 local persistent_errors = false; | 115 local persistent_errors = false; |
| 110 for jid in pairs(persistent_rooms) do | 116 for jid in pairs(persistent_rooms) do |
| 111 local node = jid_split(jid); | 117 local node = jid_split(jid); |
| 121 end | 127 end |
| 122 end | 128 end |
| 123 if persistent_errors then persistent_rooms_storage:set(nil, persistent_rooms); end | 129 if persistent_errors then persistent_rooms_storage:set(nil, persistent_rooms); end |
| 124 | 130 |
| 125 local host_room = muc_new_room(muc_host); | 131 local host_room = muc_new_room(muc_host); |
| 126 host_room.route_stanza = room_route_stanza; | |
| 127 host_room.save = room_save; | 132 host_room.save = room_save; |
| 133 rooms[muc_host] = host_room; | |
| 128 | 134 |
| 129 module:hook("host-disco-items", function(event) | 135 module:hook("host-disco-items", function(event) |
| 130 local reply = event.reply; | 136 local reply = event.reply; |
| 131 module:log("debug", "host-disco-items called"); | 137 module:log("debug", "host-disco-items called"); |
| 132 for jid, room in pairs(rooms) do | 138 for jid, room in pairs(rooms) do |
| 134 reply:tag("item", {jid=jid, name=room:get_name()}):up(); | 140 reply:tag("item", {jid=jid, name=room:get_name()}):up(); |
| 135 end | 141 end |
| 136 end | 142 end |
| 137 end); | 143 end); |
| 138 | 144 |
| 139 local function handle_to_domain(event) | 145 module:hook("muc-room-destroyed",function(event) |
| 146 local room = event.room | |
| 147 forget_room(room.jid) | |
| 148 end) | |
| 149 | |
| 150 module:hook("muc-occupant-left",function(event) | |
| 151 local room = event.room | |
| 152 if not next(room._occupants) and not persistent_rooms[room.jid] then -- empty, non-persistent room | |
| 153 module:fire_event("muc-room-destroyed", { room = room }); | |
| 154 end | |
| 155 end); | |
| 156 | |
| 157 -- Watch presence to create rooms | |
| 158 local function attempt_room_creation(event) | |
| 140 local origin, stanza = event.origin, event.stanza; | 159 local origin, stanza = event.origin, event.stanza; |
| 141 local type = stanza.attr.type; | 160 local room_jid = jid_bare(stanza.attr.to); |
| 142 if type == "error" or type == "result" then return; end | 161 if stanza.attr.type == nil and |
| 143 if stanza.name == "iq" and type == "get" then | 162 get_room_from_jid(room_jid) == nil and |
| 144 local xmlns = stanza.tags[1].attr.xmlns; | 163 ( |
| 145 local node = stanza.tags[1].attr.node; | 164 not(restrict_room_creation) or |
| 146 if xmlns == "http://jabber.org/protocol/muc#unique" then | 165 is_admin(stanza.attr.from) or |
| 147 origin.send(st.reply(stanza):tag("unique", {xmlns = xmlns}):text(uuid_gen())); -- FIXME Random UUIDs can theoretically have collisions | 166 ( |
| 148 else | 167 restrict_room_creation == "local" and |
| 149 origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); -- TODO disco/etc | 168 select(2, jid_split(stanza.attr.from)) == module.host:gsub("^[^%.]+%.", "") |
| 150 end | 169 ) |
| 151 else | 170 ) then |
| 152 host_room:handle_stanza(origin, stanza); | 171 create_room(room_jid); |
| 153 --origin.send(st.error_reply(stanza, "cancel", "service-unavailable", "The muc server doesn't deal with messages and presence directed at it")); | 172 end |
| 154 end | 173 end |
| 155 return true; | 174 module:hook("presence/full", attempt_room_creation, -1) |
| 156 end | 175 module:hook("presence/bare", attempt_room_creation, -1) |
| 157 | 176 module:hook("presence/host", attempt_room_creation, -1) |
| 158 function stanza_handler(event) | 177 |
| 159 local origin, stanza = event.origin, event.stanza; | 178 for event_name, method in pairs { |
| 160 local bare = jid_bare(stanza.attr.to); | 179 -- Normal room interactions |
| 161 local room = rooms[bare]; | 180 ["iq-get/bare/http://jabber.org/protocol/disco#info:query"] = "handle_disco_info_get_query" ; |
| 162 if not room then | 181 ["iq-get/bare/http://jabber.org/protocol/disco#items:query"] = "handle_disco_items_get_query" ; |
| 163 if stanza.name ~= "presence" then | 182 ["iq-set/bare/http://jabber.org/protocol/muc#admin:query"] = "handle_admin_query_set_command" ; |
| 164 origin.send(st.error_reply(stanza, "cancel", "item-not-found")); | 183 ["iq-get/bare/http://jabber.org/protocol/muc#admin:query"] = "handle_admin_query_get_command" ; |
| 184 ["iq-set/bare/http://jabber.org/protocol/muc#owner:query"] = "handle_owner_query_set_to_room" ; | |
| 185 ["iq-get/bare/http://jabber.org/protocol/muc#owner:query"] = "handle_owner_query_get_to_room" ; | |
| 186 ["message/bare"] = "handle_message_to_room" ; | |
| 187 ["presence/bare"] = "handle_presence_to_room" ; | |
| 188 -- Host room | |
| 189 ["iq-get/host/http://jabber.org/protocol/disco#info:query"] = "handle_disco_info_get_query" ; | |
| 190 ["iq-get/host/http://jabber.org/protocol/disco#items:query"] = "handle_disco_items_get_query" ; | |
| 191 ["iq-set/host/http://jabber.org/protocol/muc#admin:query"] = "handle_admin_query_set_command" ; | |
| 192 ["iq-get/host/http://jabber.org/protocol/muc#admin:query"] = "handle_admin_query_get_command" ; | |
| 193 ["iq-set/host/http://jabber.org/protocol/muc#owner:query"] = "handle_owner_query_set_to_room" ; | |
| 194 ["iq-get/host/http://jabber.org/protocol/muc#owner:query"] = "handle_owner_query_get_to_room" ; | |
| 195 ["message/host"] = "handle_message_to_room" ; | |
| 196 ["presence/host"] = "handle_presence_to_room" ; | |
| 197 -- Direct to occupant (normal rooms and host room) | |
| 198 ["presence/full"] = "handle_presence_to_occupant" ; | |
| 199 ["iq/full"] = "handle_iq_to_occupant" ; | |
| 200 ["message/full"] = "handle_message_to_occupant" ; | |
| 201 } do | |
| 202 module:hook(event_name, function (event) | |
| 203 local origin, stanza = event.origin, event.stanza; | |
| 204 local room = get_room_from_jid(jid_bare(stanza.attr.to)) | |
| 205 if room == nil then | |
| 206 origin.send(st.error_reply(stanza, "cancel", "not-allowed")); | |
| 165 return true; | 207 return true; |
| 166 end | 208 end |
| 167 if not(restrict_room_creation) or | 209 return room[method](room, origin, stanza); |
| 168 is_admin(stanza.attr.from) or | 210 end, -2) |
| 169 (restrict_room_creation == "local" and select(2, jid_split(stanza.attr.from)) == module.host:gsub("^[^%.]+%.", "")) then | |
| 170 room = create_room(bare); | |
| 171 end | |
| 172 end | |
| 173 if room then | |
| 174 room:handle_stanza(origin, stanza); | |
| 175 if not next(room._occupants) and not persistent_rooms[room.jid] then -- empty, non-persistent room | |
| 176 module:fire_event("muc-room-destroyed", { room = room }); | |
| 177 rooms[bare] = nil; -- discard room | |
| 178 end | |
| 179 else | |
| 180 origin.send(st.error_reply(stanza, "cancel", "not-allowed")); | |
| 181 end | |
| 182 return true; | |
| 183 end | |
| 184 module:hook("iq/bare", stanza_handler, -1); | |
| 185 module:hook("message/bare", stanza_handler, -1); | |
| 186 module:hook("presence/bare", stanza_handler, -1); | |
| 187 module:hook("iq/full", stanza_handler, -1); | |
| 188 module:hook("message/full", stanza_handler, -1); | |
| 189 module:hook("presence/full", stanza_handler, -1); | |
| 190 module:hook("iq/host", handle_to_domain, -1); | |
| 191 module:hook("message/host", handle_to_domain, -1); | |
| 192 module:hook("presence/host", handle_to_domain, -1); | |
| 193 | |
| 194 hosts[module.host].send = function(stanza) -- FIXME do a generic fix | |
| 195 if stanza.attr.type == "result" or stanza.attr.type == "error" then | |
| 196 module:send(stanza); | |
| 197 else error("component.send only supports result and error stanzas at the moment"); end | |
| 198 end | 211 end |
| 199 | 212 |
| 200 hosts[module:get_host()].muc = { rooms = rooms }; | 213 hosts[module:get_host()].muc = { rooms = rooms }; |
| 201 | 214 |
| 202 local saved = false; | 215 local saved = false; |
