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;