Mercurial > prosody-hg
comparison plugins/muc/muc.lib.lua @ 6215:1dd09dc04945
plugins/muc: Move history to an external module
This resulted in the split up of the main muc-occupant-joined event handler into 3 seperate ones, handling occupant list, history and subject
| author | daurnimator <quae@daurnimator.com> |
|---|---|
| date | Thu, 03 Apr 2014 15:14:52 -0400 |
| parents | 9813c74ce006 |
| children | 50b8b7caf200 |
comparison
equal
deleted
inserted
replaced
| 6214:9813c74ce006 | 6215:1dd09dc04945 |
|---|---|
| 9 | 9 |
| 10 local select = select; | 10 local select = select; |
| 11 local pairs, ipairs = pairs, ipairs; | 11 local pairs, ipairs = pairs, ipairs; |
| 12 local next = next; | 12 local next = next; |
| 13 local setmetatable = setmetatable; | 13 local setmetatable = setmetatable; |
| 14 local t_insert, t_remove = table.insert, table.remove; | |
| 15 | |
| 16 local gettime = os.time; | |
| 17 local datetime = require "util.datetime"; | |
| 18 | 14 |
| 19 local dataform = require "util.dataforms"; | 15 local dataform = require "util.dataforms"; |
| 20 | |
| 21 local jid_split = require "util.jid".split; | 16 local jid_split = require "util.jid".split; |
| 22 local jid_bare = require "util.jid".bare; | 17 local jid_bare = require "util.jid".bare; |
| 23 local jid_prep = require "util.jid".prep; | 18 local jid_prep = require "util.jid".prep; |
| 24 local st = require "util.stanza"; | 19 local st = require "util.stanza"; |
| 25 local log = require "util.logger".init("mod_muc"); | 20 local log = require "util.logger".init("mod_muc"); |
| 26 local base64 = require "util.encodings".base64; | 21 local base64 = require "util.encodings".base64; |
| 27 local md5 = require "util.hashes".md5; | 22 local md5 = require "util.hashes".md5; |
| 28 | 23 |
| 29 local occupant_lib = module:require "muc/occupant" | 24 local occupant_lib = module:require "muc/occupant" |
| 30 | 25 |
| 31 local default_history_length, max_history_length = 20, math.huge; | |
| 32 | 26 |
| 33 local is_kickable_error do | 27 local is_kickable_error do |
| 34 local kickable_error_conditions = { | 28 local kickable_error_conditions = { |
| 35 ["gone"] = true; | 29 ["gone"] = true; |
| 36 ["internal-server-error"] = true; | 30 ["internal-server-error"] = true; |
| 183 end | 177 end |
| 184 end | 178 end |
| 185 return x | 179 return x |
| 186 end | 180 end |
| 187 | 181 |
| 188 function room_mt:broadcast_message(stanza, historic) | 182 function room_mt:broadcast_message(stanza) |
| 189 module:fire_event("muc-broadcast-message", {room = self, stanza = stanza, historic = historic}); | 183 module:fire_event("muc-broadcast-message", {room = self, stanza = stanza}); |
| 190 self:broadcast(stanza); | 184 self:broadcast(stanza); |
| 191 end | 185 end |
| 192 | |
| 193 -- add to history | |
| 194 module:hook("muc-broadcast-message", function(event) | |
| 195 if event.historic then | |
| 196 local room = event.room | |
| 197 local history = room._data['history']; | |
| 198 if not history then history = {}; room._data['history'] = history; end | |
| 199 local stanza = st.clone(event.stanza); | |
| 200 stanza.attr.to = ""; | |
| 201 local ts = gettime(); | |
| 202 local stamp = datetime.datetime(ts); | |
| 203 stanza:tag("delay", {xmlns = "urn:xmpp:delay", from = module.host, stamp = stamp}):up(); -- XEP-0203 | |
| 204 stanza:tag("x", {xmlns = "jabber:x:delay", from = module.host, stamp = datetime.legacy()}):up(); -- XEP-0091 (deprecated) | |
| 205 local entry = { stanza = stanza, timestamp = ts }; | |
| 206 t_insert(history, entry); | |
| 207 while #history > room:get_historylength() do t_remove(history, 1) end | |
| 208 end | |
| 209 end); | |
| 210 | 186 |
| 211 -- Broadcast a stanza to all occupants in the room. | 187 -- Broadcast a stanza to all occupants in the room. |
| 212 -- optionally checks conditional called with (nick, occupant) | 188 -- optionally checks conditional called with (nick, occupant) |
| 213 function room_mt:broadcast(stanza, cond_func) | 189 function room_mt:broadcast(stanza, cond_func) |
| 214 for nick, occupant in self:each_occupant() do | 190 for nick, occupant in self:each_occupant() do |
| 310 self:route_stanza(pres); | 286 self:route_stanza(pres); |
| 311 end | 287 end |
| 312 end | 288 end |
| 313 end | 289 end |
| 314 | 290 |
| 315 local function parse_history(stanza) | |
| 316 local x_tag = stanza:get_child("x", "http://jabber.org/protocol/muc"); | |
| 317 local history_tag = x_tag and x_tag:get_child("history", "http://jabber.org/protocol/muc"); | |
| 318 if not history_tag then | |
| 319 return nil, 20, nil | |
| 320 end | |
| 321 | |
| 322 local maxchars = tonumber(history_tag.attr.maxchars); | |
| 323 | |
| 324 local maxstanzas = tonumber(history_tag.attr.maxstanzas); | |
| 325 | |
| 326 -- messages received since the UTC datetime specified | |
| 327 local since = history_tag.attr.since; | |
| 328 if since then | |
| 329 since = datetime.parse(since); | |
| 330 end | |
| 331 | |
| 332 -- messages received in the last "X" seconds. | |
| 333 local seconds = tonumber(history_tag.attr.seconds); | |
| 334 if seconds then | |
| 335 seconds = gettime() - seconds | |
| 336 if since then | |
| 337 since = math.max(since, seconds); | |
| 338 else | |
| 339 since = seconds; | |
| 340 end | |
| 341 end | |
| 342 | |
| 343 return maxchars, maxstanzas, since | |
| 344 end | |
| 345 | |
| 346 module:hook("muc-get-history", function(event) | |
| 347 local room = event.room | |
| 348 local history = room._data['history']; -- send discussion history | |
| 349 if not history then return nil end | |
| 350 local history_len = #history | |
| 351 | |
| 352 local to = event.to | |
| 353 local maxchars = event.maxchars | |
| 354 local maxstanzas = event.maxstanzas or history_len | |
| 355 local since = event.since | |
| 356 local n = 0; | |
| 357 local charcount = 0; | |
| 358 for i=history_len,1,-1 do | |
| 359 local entry = history[i]; | |
| 360 if maxchars then | |
| 361 if not entry.chars then | |
| 362 entry.stanza.attr.to = ""; | |
| 363 entry.chars = #tostring(entry.stanza); | |
| 364 end | |
| 365 charcount = charcount + entry.chars + #to; | |
| 366 if charcount > maxchars then break; end | |
| 367 end | |
| 368 if since and since > entry.timestamp then break; end | |
| 369 if n + 1 > maxstanzas then break; end | |
| 370 n = n + 1; | |
| 371 end | |
| 372 | |
| 373 local i = history_len-n+1 | |
| 374 function event:next_stanza() | |
| 375 if i > history_len then return nil end | |
| 376 local entry = history[i] | |
| 377 local msg = entry.stanza | |
| 378 msg.attr.to = to; | |
| 379 i = i + 1 | |
| 380 return msg | |
| 381 end | |
| 382 return true; | |
| 383 end); | |
| 384 | |
| 385 function room_mt:send_history(stanza) | |
| 386 local maxchars, maxstanzas, since = parse_history(stanza) | |
| 387 local event = { | |
| 388 room = self; | |
| 389 to = stanza.attr.from; -- `to` is required to calculate the character count for `maxchars` | |
| 390 maxchars = maxchars, maxstanzas = maxstanzas, since = since; | |
| 391 next_stanza = function() end; -- events should define this iterator | |
| 392 } | |
| 393 module:fire_event("muc-get-history", event) | |
| 394 for msg in event.next_stanza , event do | |
| 395 self:route_stanza(msg); | |
| 396 end | |
| 397 end | |
| 398 | |
| 399 function room_mt:get_disco_info(stanza) | 291 function room_mt:get_disco_info(stanza) |
| 400 local reply = st.reply(stanza):query("http://jabber.org/protocol/disco#info"); | 292 local reply = st.reply(stanza):query("http://jabber.org/protocol/disco#info"); |
| 401 local form = dataform.new { | 293 local form = dataform.new { |
| 402 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/muc#roominfo" }; | 294 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/protocol/muc#roominfo" }; |
| 403 }; | 295 }; |
| 449 if subject == "" then subject = nil; end | 341 if subject == "" then subject = nil; end |
| 450 self._data['subject'] = subject; | 342 self._data['subject'] = subject; |
| 451 self._data['subject_from'] = current_nick; | 343 self._data['subject_from'] = current_nick; |
| 452 if self.save then self:save(); end | 344 if self.save then self:save(); end |
| 453 local msg = create_subject_message(current_nick, subject); | 345 local msg = create_subject_message(current_nick, subject); |
| 454 self:broadcast_message(msg, false); | 346 self:broadcast_message(msg); |
| 455 return true; | 347 return true; |
| 456 end | 348 end |
| 457 | 349 |
| 458 function room_mt:handle_kickable(origin, stanza) | 350 function room_mt:handle_kickable(origin, stanza) |
| 459 local real_jid = stanza.attr.from; | 351 local real_jid = stanza.attr.from; |
| 527 end | 419 end |
| 528 end | 420 end |
| 529 function room_mt:get_changesubject() | 421 function room_mt:get_changesubject() |
| 530 return self._data.changesubject; | 422 return self._data.changesubject; |
| 531 end | 423 end |
| 532 function room_mt:get_historylength() | |
| 533 return self._data.history_length or default_history_length; | |
| 534 end | |
| 535 function room_mt:set_historylength(length) | |
| 536 length = math.min(tonumber(length) or default_history_length, max_history_length or math.huge); | |
| 537 if length == default_history_length then | |
| 538 length = nil; | |
| 539 end | |
| 540 self._data.history_length = length; | |
| 541 end | |
| 542 | 424 |
| 543 -- Give the room creator owner affiliation | 425 -- Give the room creator owner affiliation |
| 544 module:hook("muc-room-pre-create", function(event) | 426 module:hook("muc-room-pre-create", function(event) |
| 545 event.room:set_affiliation(true, jid_bare(event.stanza.attr.from), "owner"); | 427 event.room:set_affiliation(true, jid_bare(event.stanza.attr.from), "owner"); |
| 546 end, -1); | 428 end, -1); |
| 567 event.origin.send(reply:tag("x", {xmlns = "http://jabber.org/protocol/muc"})); | 449 event.origin.send(reply:tag("x", {xmlns = "http://jabber.org/protocol/muc"})); |
| 568 return true; | 450 return true; |
| 569 end | 451 end |
| 570 end, -10); | 452 end, -10); |
| 571 | 453 |
| 454 -- Send occupant list to newly joined user | |
| 572 module:hook("muc-occupant-joined", function(event) | 455 module:hook("muc-occupant-joined", function(event) |
| 573 local room, stanza = event.room, event.stanza; | 456 local real_jid = event.stanza.attr.from; |
| 574 local real_jid = stanza.attr.from; | 457 event.room:send_occupant_list(real_jid, function(nick, occupant) |
| 575 room:send_occupant_list(real_jid, function(nick, occupant) | |
| 576 -- Don't include self | 458 -- Don't include self |
| 577 return occupant:get_presence(real_jid) == nil; | 459 return occupant:get_presence(real_jid) == nil; |
| 578 end); | 460 end); |
| 579 room:send_history(stanza); | 461 end, 80); |
| 580 room:send_subject(real_jid); | 462 |
| 581 end, -1); | 463 -- Send subject to joining user |
| 464 module:hook("muc-occupant-joined", function(event) | |
| 465 event.room:send_subject(event.stanza.attr.from); | |
| 466 end, 20); | |
| 582 | 467 |
| 583 function room_mt:handle_presence_to_occupant(origin, stanza) | 468 function room_mt:handle_presence_to_occupant(origin, stanza) |
| 584 local type = stanza.attr.type; | 469 local type = stanza.attr.type; |
| 585 if type == "error" then -- error, kick em out! | 470 if type == "error" then -- error, kick em out! |
| 586 return self:handle_kickable(origin, stanza) | 471 return self:handle_kickable(origin, stanza) |
| 869 type = 'boolean', | 754 type = 'boolean', |
| 870 label = 'Make Room Members-Only?', | 755 label = 'Make Room Members-Only?', |
| 871 value = event.room:get_members_only() | 756 value = event.room:get_members_only() |
| 872 }); | 757 }); |
| 873 end); | 758 end); |
| 874 module:hook("muc-config-form", function(event) | |
| 875 table.insert(event.form, { | |
| 876 name = 'muc#roomconfig_historylength', | |
| 877 type = 'text-single', | |
| 878 label = 'Maximum Number of History Messages Returned by Room', | |
| 879 value = tostring(event.room:get_historylength()) | |
| 880 }); | |
| 881 end); | |
| 882 | 759 |
| 883 function room_mt:process_form(origin, stanza) | 760 function room_mt:process_form(origin, stanza) |
| 884 local form = stanza.tags[1]:get_child("x", "jabber:x:data"); | 761 local form = stanza.tags[1]:get_child("x", "jabber:x:data"); |
| 885 if form.attr.type == "cancel" then | 762 if form.attr.type == "cancel" then |
| 886 origin.send(st.reply(stanza)); | 763 origin.send(st.reply(stanza)); |
| 911 :tag('x', {xmlns='http://jabber.org/protocol/muc#user'}) | 788 :tag('x', {xmlns='http://jabber.org/protocol/muc#user'}) |
| 912 for code in pairs(event.status_codes) do | 789 for code in pairs(event.status_codes) do |
| 913 msg:tag("status", {code = code;}):up(); | 790 msg:tag("status", {code = code;}):up(); |
| 914 end | 791 end |
| 915 msg:up(); | 792 msg:up(); |
| 916 self:broadcast_message(msg, false) | 793 self:broadcast_message(msg); |
| 917 end | 794 end |
| 918 else | 795 else |
| 919 origin.send(st.error_reply(stanza, "cancel", "bad-request", "Not a submitted form")); | 796 origin.send(st.error_reply(stanza, "cancel", "bad-request", "Not a submitted form")); |
| 920 end | 797 end |
| 921 return true; | 798 return true; |
| 932 module:hook("muc-config-submitted", function(event) | 809 module:hook("muc-config-submitted", function(event) |
| 933 event.update_option("public", "muc#roomconfig_publicroom"); | 810 event.update_option("public", "muc#roomconfig_publicroom"); |
| 934 end); | 811 end); |
| 935 module:hook("muc-config-submitted", function(event) | 812 module:hook("muc-config-submitted", function(event) |
| 936 event.update_option("changesubject", "muc#roomconfig_changesubject"); | 813 event.update_option("changesubject", "muc#roomconfig_changesubject"); |
| 937 end); | |
| 938 module:hook("muc-config-submitted", function(event) | |
| 939 event.update_option("historylength", "muc#roomconfig_historylength"); | |
| 940 end); | 814 end); |
| 941 | 815 |
| 942 -- Removes everyone from the room | 816 -- Removes everyone from the room |
| 943 function room_mt:clear(x) | 817 function room_mt:clear(x) |
| 944 x = x or st.stanza("x", {xmlns='http://jabber.org/protocol/muc#user'}); | 818 x = x or st.stanza("x", {xmlns='http://jabber.org/protocol/muc#user'}); |
| 1097 else | 971 else |
| 1098 stanza.attr.from = from; | 972 stanza.attr.from = from; |
| 1099 origin.send(st.error_reply(stanza, "auth", "forbidden")); | 973 origin.send(st.error_reply(stanza, "auth", "forbidden")); |
| 1100 end | 974 end |
| 1101 else | 975 else |
| 1102 self:broadcast_message(stanza, self:get_historylength() > 0 and stanza:get_child("body")); | 976 self:broadcast_message(stanza); |
| 1103 end | 977 end |
| 1104 stanza.attr.from = from; | 978 stanza.attr.from = from; |
| 1105 return true; | 979 return true; |
| 1106 end | 980 end |
| 1107 end | 981 end |
| 1410 | 1284 |
| 1411 local whois = module:require "muc/whois"; | 1285 local whois = module:require "muc/whois"; |
| 1412 room_mt.get_whois = whois.get; | 1286 room_mt.get_whois = whois.get; |
| 1413 room_mt.set_whois = whois.set; | 1287 room_mt.set_whois = whois.set; |
| 1414 | 1288 |
| 1289 local history = module:require "muc/history"; | |
| 1290 room_mt.send_history = history.send; | |
| 1291 room_mt.get_historylength = history.get_length; | |
| 1292 room_mt.set_historylength = history.set_length; | |
| 1293 | |
| 1415 local _M = {}; -- module "muc" | 1294 local _M = {}; -- module "muc" |
| 1295 | |
| 1296 _M.set_max_history_length = history.set_max_length; | |
| 1416 | 1297 |
| 1417 function _M.new_room(jid, config) | 1298 function _M.new_room(jid, config) |
| 1418 return setmetatable({ | 1299 return setmetatable({ |
| 1419 jid = jid; | 1300 jid = jid; |
| 1420 _jid_nick = {}; | 1301 _jid_nick = {}; |
| 1421 _occupants = {}; | 1302 _occupants = {}; |
| 1422 _data = { | 1303 _data = { |
| 1423 history_length = math.min((config and config.history_length) | |
| 1424 or default_history_length, max_history_length); | |
| 1425 }; | 1304 }; |
| 1426 _affiliations = {}; | 1305 _affiliations = {}; |
| 1427 }, room_mt); | 1306 }, room_mt); |
| 1428 end | 1307 end |
| 1429 | 1308 |
| 1430 function _M.set_max_history_length(_max_history_length) | |
| 1431 max_history_length = _max_history_length or math.huge; | |
| 1432 end | |
| 1433 | |
| 1434 _M.room_mt = room_mt; | 1309 _M.room_mt = room_mt; |
| 1435 | 1310 |
| 1436 return _M; | 1311 return _M; |
