Mercurial > prosody-hg
comparison plugins/muc/muc.lib.lua @ 11200:bf8f2da84007
Merge 0.11->trunk
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Thu, 05 Nov 2020 22:31:25 +0100 |
| parents | 818255f49297 |
| children | b1d7027be61e |
comparison
equal
deleted
inserted
replaced
| 11199:6c7c50a4de32 | 11200:bf8f2da84007 |
|---|---|
| 21 local jid_resource = require "util.jid".resource; | 21 local jid_resource = require "util.jid".resource; |
| 22 local resourceprep = require "util.encodings".stringprep.resourceprep; | 22 local resourceprep = require "util.encodings".stringprep.resourceprep; |
| 23 local st = require "util.stanza"; | 23 local st = require "util.stanza"; |
| 24 local base64 = require "util.encodings".base64; | 24 local base64 = require "util.encodings".base64; |
| 25 local md5 = require "util.hashes".md5; | 25 local md5 = require "util.hashes".md5; |
| 26 local new_id = require "util.id".medium; | |
| 26 | 27 |
| 27 local log = module._log; | 28 local log = module._log; |
| 28 | 29 |
| 29 local occupant_lib = module:require "muc/occupant" | 30 local occupant_lib = module:require "muc/occupant" |
| 30 local muc_util = module:require "muc/util"; | 31 local muc_util = module:require "muc/util"; |
| 37 function room_mt:__tostring() | 38 function room_mt:__tostring() |
| 38 return "MUC room ("..self.jid..")"; | 39 return "MUC room ("..self.jid..")"; |
| 39 end | 40 end |
| 40 | 41 |
| 41 function room_mt.save() | 42 function room_mt.save() |
| 42 -- overriden by mod_muc.lua | 43 -- overridden by mod_muc.lua |
| 43 end | 44 end |
| 44 | 45 |
| 45 function room_mt:get_occupant_jid(real_jid) | 46 function room_mt:get_occupant_jid(real_jid) |
| 46 return self._jid_nick[real_jid] | 47 return self._jid_nick[real_jid] |
| 47 end | 48 end |
| 215 end | 216 end |
| 216 end | 217 end |
| 217 | 218 |
| 218 -- Broadcasts an occupant's presence to the whole room | 219 -- Broadcasts an occupant's presence to the whole room |
| 219 -- Takes the x element that goes into the stanzas | 220 -- Takes the x element that goes into the stanzas |
| 220 function room_mt:publicise_occupant_status(occupant, x, nick, actor, reason) | 221 function room_mt:publicise_occupant_status(occupant, x, nick, actor, reason, prev_role, force_unavailable) |
| 221 local base_x = x.base or x; | 222 local base_x = x.base or x; |
| 222 -- Build real jid and (optionally) occupant jid template presences | 223 -- Build real jid and (optionally) occupant jid template presences |
| 223 local base_presence do | 224 local base_presence do |
| 224 -- Try to use main jid's presence | 225 -- Try to use main jid's presence |
| 225 local pr = occupant:get_presence(); | 226 local pr = occupant:get_presence(); |
| 226 if pr and (occupant.role ~= nil or pr.attr.type == "unavailable") then | 227 if pr and (occupant.role ~= nil or pr.attr.type == "unavailable") and not force_unavailable then |
| 227 base_presence = st.clone(pr); | 228 base_presence = st.clone(pr); |
| 228 else -- user is leaving but didn't send a leave presence. make one for them | 229 else -- user is leaving but didn't send a leave presence. make one for them |
| 229 base_presence = st.presence {from = occupant.nick; type = "unavailable";}; | 230 base_presence = st.presence {from = occupant.nick; type = "unavailable";}; |
| 230 end | 231 end |
| 231 end | 232 end |
| 234 local event = { | 235 local event = { |
| 235 room = self; stanza = base_presence; x = base_x; | 236 room = self; stanza = base_presence; x = base_x; |
| 236 occupant = occupant; nick = nick; actor = actor; | 237 occupant = occupant; nick = nick; actor = actor; |
| 237 reason = reason; | 238 reason = reason; |
| 238 } | 239 } |
| 240 module:fire_event("muc-build-occupant-presence", event); | |
| 239 module:fire_event("muc-broadcast-presence", event); | 241 module:fire_event("muc-broadcast-presence", event); |
| 240 | 242 |
| 241 -- Allow muc-broadcast-presence listeners to change things | 243 -- Allow muc-broadcast-presence listeners to change things |
| 242 nick = event.nick; | 244 nick = event.nick; |
| 243 actor = event.actor; | 245 actor = event.actor; |
| 277 self_x = st.clone(x.self or base_x); | 279 self_x = st.clone(x.self or base_x); |
| 278 self:build_item_list(occupant, self_x, false, nick, actor_nick, nil, reason); | 280 self:build_item_list(occupant, self_x, false, nick, actor_nick, nil, reason); |
| 279 self_p = st.clone(base_presence):add_child(self_x); | 281 self_p = st.clone(base_presence):add_child(self_x); |
| 280 end | 282 end |
| 281 | 283 |
| 282 -- General populance | 284 local broadcast_roles = self:get_presence_broadcast(); |
| 285 | |
| 286 -- General populace | |
| 283 for occupant_nick, n_occupant in self:each_occupant() do | 287 for occupant_nick, n_occupant in self:each_occupant() do |
| 284 if occupant_nick ~= occupant.nick then | 288 if occupant_nick ~= occupant.nick then |
| 285 local pr; | 289 local pr; |
| 286 if can_see_real_jids(whois, n_occupant) then | 290 if can_see_real_jids(whois, n_occupant) then |
| 287 pr = get_full_p(); | 291 pr = get_full_p(); |
| 288 elseif occupant.bare_jid == n_occupant.bare_jid then | 292 elseif occupant.bare_jid == n_occupant.bare_jid then |
| 289 pr = self_p; | 293 pr = self_p; |
| 290 else | 294 else |
| 291 pr = get_anon_p(); | 295 pr = get_anon_p(); |
| 292 end | 296 end |
| 293 self:route_to_occupant(n_occupant, pr); | 297 if broadcast_roles[occupant.role or "none"] or force_unavailable then |
| 298 self:route_to_occupant(n_occupant, pr); | |
| 299 elseif prev_role and broadcast_roles[prev_role] then | |
| 300 pr.attr.type = 'unavailable'; | |
| 301 self:route_to_occupant(n_occupant, pr); | |
| 302 end | |
| 303 | |
| 294 end | 304 end |
| 295 end | 305 end |
| 296 | 306 |
| 297 -- Presences for occupant itself | 307 -- Presences for occupant itself |
| 298 self_x:tag("status", {code = "110";}):up(); | 308 self_x:tag("status", {code = "110";}):up(); |
| 301 self:route_to_occupant(occupant, self_p); | 311 self:route_to_occupant(occupant, self_p); |
| 302 else | 312 else |
| 303 -- use their own presences as templates | 313 -- use their own presences as templates |
| 304 for full_jid, pr in occupant:each_session() do | 314 for full_jid, pr in occupant:each_session() do |
| 305 pr = st.clone(pr); | 315 pr = st.clone(pr); |
| 316 module:fire_event("muc-build-occupant-presence", { room = self, occupant = occupant, stanza = pr }); | |
| 306 pr.attr.to = full_jid; | 317 pr.attr.to = full_jid; |
| 307 pr:add_child(self_x); | 318 pr:add_child(self_x); |
| 308 self:route_stanza(pr); | 319 self:route_stanza(pr); |
| 309 end | 320 end |
| 310 end | 321 end |
| 312 | 323 |
| 313 function room_mt:send_occupant_list(to, filter) | 324 function room_mt:send_occupant_list(to, filter) |
| 314 local to_bare = jid_bare(to); | 325 local to_bare = jid_bare(to); |
| 315 local is_anonymous = false; | 326 local is_anonymous = false; |
| 316 local whois = self:get_whois(); | 327 local whois = self:get_whois(); |
| 328 local broadcast_roles = self:get_presence_broadcast(); | |
| 317 if whois ~= "anyone" then | 329 if whois ~= "anyone" then |
| 318 local affiliation = self:get_affiliation(to); | 330 local affiliation = self:get_affiliation(to); |
| 319 if affiliation ~= "admin" and affiliation ~= "owner" then | 331 if affiliation ~= "admin" and affiliation ~= "owner" then |
| 320 local occupant = self:get_occupant_by_real_jid(to); | 332 local occupant = self:get_occupant_by_real_jid(to); |
| 321 if not (occupant and can_see_real_jids(whois, occupant)) then | 333 if not (occupant and can_see_real_jids(whois, occupant)) then |
| 322 is_anonymous = true; | 334 is_anonymous = true; |
| 323 end | 335 end |
| 324 end | 336 end |
| 325 end | 337 end |
| 338 local broadcast_bare_jids = {}; -- Track which bare JIDs we have sent presence for | |
| 326 for occupant_jid, occupant in self:each_occupant() do | 339 for occupant_jid, occupant in self:each_occupant() do |
| 340 broadcast_bare_jids[occupant.bare_jid] = true; | |
| 327 if filter == nil or filter(occupant_jid, occupant) then | 341 if filter == nil or filter(occupant_jid, occupant) then |
| 328 local x = st.stanza("x", {xmlns='http://jabber.org/protocol/muc#user'}); | 342 local x = st.stanza("x", {xmlns='http://jabber.org/protocol/muc#user'}); |
| 329 self:build_item_list(occupant, x, is_anonymous and to_bare ~= occupant.bare_jid); -- can always see your own jids | 343 self:build_item_list(occupant, x, is_anonymous and to_bare ~= occupant.bare_jid); -- can always see your own jids |
| 330 local pres = st.clone(occupant:get_presence()); | 344 local pres = st.clone(occupant:get_presence()); |
| 331 pres.attr.to = to; | 345 pres.attr.to = to; |
| 332 pres:add_child(x); | 346 pres:add_child(x); |
| 333 self:route_stanza(pres); | 347 module:fire_event("muc-build-occupant-presence", { room = self, occupant = occupant, stanza = pres }); |
| 348 if to_bare == occupant.bare_jid or broadcast_roles[occupant.role or "none"] then | |
| 349 self:route_stanza(pres); | |
| 350 end | |
| 351 end | |
| 352 end | |
| 353 if broadcast_roles.none then | |
| 354 -- Broadcast stanzas for affiliated users not currently in the MUC | |
| 355 for affiliated_jid, affiliation, affiliation_data in self:each_affiliation() do | |
| 356 local nick = affiliation_data and affiliation_data.reserved_nickname; | |
| 357 if (nick or not is_anonymous) and not broadcast_bare_jids[affiliated_jid] | |
| 358 and (filter == nil or filter(affiliated_jid, nil)) then | |
| 359 local from = nick and (self.jid.."/"..nick) or self.jid; | |
| 360 local pres = st.presence({ to = to, from = from, type = "unavailable" }) | |
| 361 :tag("x", { xmlns = 'http://jabber.org/protocol/muc#user' }) | |
| 362 :tag("item", { | |
| 363 affiliation = affiliation; | |
| 364 role = "none"; | |
| 365 nick = nick; | |
| 366 jid = not is_anonymous and affiliated_jid or nil }):up() | |
| 367 :up(); | |
| 368 self:route_stanza(pres); | |
| 369 end | |
| 334 end | 370 end |
| 335 end | 371 end |
| 336 end | 372 end |
| 337 | 373 |
| 338 function room_mt:get_disco_info(stanza) | 374 function room_mt:get_disco_info(stanza) |
| 371 | 407 |
| 372 function room_mt:handle_kickable(origin, stanza) -- luacheck: ignore 212 | 408 function room_mt:handle_kickable(origin, stanza) -- luacheck: ignore 212 |
| 373 local real_jid = stanza.attr.from; | 409 local real_jid = stanza.attr.from; |
| 374 local occupant = self:get_occupant_by_real_jid(real_jid); | 410 local occupant = self:get_occupant_by_real_jid(real_jid); |
| 375 if occupant == nil then return nil; end | 411 if occupant == nil then return nil; end |
| 376 local type, condition, text = stanza:get_error(); | 412 local _, condition, text = stanza:get_error(); |
| 377 local error_message = "Kicked: "..(condition and condition:gsub("%-", " ") or "presence error"); | 413 local error_message = "Kicked: "..(condition and condition:gsub("%-", " ") or "presence error"); |
| 378 if text and self:get_whois() == "anyone" then | 414 if text and self:get_whois() == "anyone" then |
| 379 error_message = error_message..": "..text; | 415 error_message = error_message..": "..text; |
| 380 end | 416 end |
| 381 occupant:set_session(real_jid, st.presence({type="unavailable"}) | 417 occupant:set_session(real_jid, st.presence({type="unavailable"}) |
| 382 :tag('status'):text(error_message)); | 418 :tag('status'):text(error_message)); |
| 419 local orig_role = occupant.role; | |
| 383 local is_last_session = occupant.jid == real_jid; | 420 local is_last_session = occupant.jid == real_jid; |
| 384 if is_last_session then | 421 if is_last_session then |
| 385 occupant.role = nil; | 422 occupant.role = nil; |
| 386 end | 423 end |
| 387 local new_occupant = self:save_occupant(occupant); | 424 local new_occupant = self:save_occupant(occupant); |
| 388 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user";}); | 425 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user";}); |
| 389 if is_last_session then | 426 if is_last_session then |
| 390 x:tag("status", {code = "333"}); | 427 x:tag("status", {code = "333"}); |
| 391 end | 428 end |
| 392 self:publicise_occupant_status(new_occupant or occupant, x); | 429 self:publicise_occupant_status(new_occupant or occupant, x, nil, nil, nil, orig_role); |
| 393 if is_last_session then | 430 if is_last_session then |
| 394 module:fire_event("muc-occupant-left", {room = self; nick = occupant.nick; occupant = occupant;}); | 431 module:fire_event("muc-occupant-left", { |
| 432 room = self; | |
| 433 nick = occupant.nick; | |
| 434 occupant = occupant; | |
| 435 }); | |
| 395 end | 436 end |
| 396 return true; | 437 return true; |
| 397 end | 438 end |
| 398 | 439 |
| 399 -- Give the room creator owner affiliation | 440 -- Give the room creator owner affiliation |
| 404 -- check if user is banned | 445 -- check if user is banned |
| 405 module:hook("muc-occupant-pre-join", function(event) | 446 module:hook("muc-occupant-pre-join", function(event) |
| 406 local room, stanza = event.room, event.stanza; | 447 local room, stanza = event.room, event.stanza; |
| 407 local affiliation = room:get_affiliation(stanza.attr.from); | 448 local affiliation = room:get_affiliation(stanza.attr.from); |
| 408 if affiliation == "outcast" then | 449 if affiliation == "outcast" then |
| 409 local reply = st.error_reply(stanza, "auth", "forbidden"):up(); | 450 local reply = st.error_reply(stanza, "auth", "forbidden", nil, room.jid):up(); |
| 410 reply.tags[1].attr.code = "403"; | 451 reply.tags[1].attr.code = "403"; |
| 411 event.origin.send(reply:tag("x", {xmlns = "http://jabber.org/protocol/muc"})); | 452 event.origin.send(reply:tag("x", {xmlns = "http://jabber.org/protocol/muc"})); |
| 412 return true; | 453 return true; |
| 413 end | 454 end |
| 414 end, -10); | 455 end, -10); |
| 415 | 456 |
| 416 module:hook("muc-occupant-pre-join", function(event) | 457 module:hook("muc-occupant-pre-join", function(event) |
| 458 local room = event.room; | |
| 417 local nick = jid_resource(event.occupant.nick); | 459 local nick = jid_resource(event.occupant.nick); |
| 418 if not nick:find("%S") then | 460 if not nick:find("%S") then |
| 419 event.origin.send(st.error_reply(event.stanza, "modify", "not-allowed", "Invisible Nicknames are forbidden")); | 461 event.origin.send(st.error_reply(event.stanza, "modify", "not-allowed", "Invisible Nicknames are forbidden", room.jid)); |
| 420 return true; | 462 return true; |
| 421 end | 463 end |
| 422 end, 1); | 464 end, 1); |
| 423 | 465 |
| 424 module:hook("muc-occupant-pre-change", function(event) | 466 module:hook("muc-occupant-pre-change", function(event) |
| 467 local room = event.room; | |
| 425 if not jid_resource(event.dest_occupant.nick):find("%S") then | 468 if not jid_resource(event.dest_occupant.nick):find("%S") then |
| 426 event.origin.send(st.error_reply(event.stanza, "modify", "not-allowed", "Invisible Nicknames are forbidden")); | 469 event.origin.send(st.error_reply(event.stanza, "modify", "not-allowed", "Invisible Nicknames are forbidden", room.jid)); |
| 427 return true; | 470 return true; |
| 428 end | 471 end |
| 429 end, 1); | 472 end, 1); |
| 430 | 473 |
| 474 module:hook("muc-occupant-pre-join", function(event) | |
| 475 local room = event.room; | |
| 476 local nick = jid_resource(event.occupant.nick); | |
| 477 if not resourceprep(nick, true) then -- strict | |
| 478 event.origin.send(st.error_reply(event.stanza, "modify", "jid-malformed", "Nickname must pass strict validation", room.jid)); | |
| 479 return true; | |
| 480 end | |
| 481 end, 2); | |
| 482 | |
| 483 module:hook("muc-occupant-pre-change", function(event) | |
| 484 local room = event.room; | |
| 485 local nick = jid_resource(event.dest_occupant.nick); | |
| 486 if not resourceprep(nick, true) then -- strict | |
| 487 event.origin.send(st.error_reply(event.stanza, "modify", "jid-malformed", "Nickname must pass strict validation", room.jid)); | |
| 488 return true; | |
| 489 end | |
| 490 end, 2); | |
| 491 | |
| 431 function room_mt:handle_first_presence(origin, stanza) | 492 function room_mt:handle_first_presence(origin, stanza) |
| 432 if not stanza:get_child("x", "http://jabber.org/protocol/muc") then | |
| 433 module:log("debug", "Room creation without <x>, possibly desynced"); | |
| 434 | |
| 435 origin.send(st.error_reply(stanza, "cancel", "item-not-found")); | |
| 436 return true; | |
| 437 end | |
| 438 | |
| 439 local real_jid = stanza.attr.from; | 493 local real_jid = stanza.attr.from; |
| 440 local dest_jid = stanza.attr.to; | 494 local dest_jid = stanza.attr.to; |
| 441 local bare_jid = jid_bare(real_jid); | 495 local bare_jid = jid_bare(real_jid); |
| 442 if module:fire_event("muc-room-pre-create", { | 496 if module:fire_event("muc-room-pre-create", { |
| 443 room = self; | 497 room = self; |
| 503 local muc_x = stanza:get_child("x", "http://jabber.org/protocol/muc"); | 557 local muc_x = stanza:get_child("x", "http://jabber.org/protocol/muc"); |
| 504 | 558 |
| 505 if orig_occupant == nil and not muc_x and stanza.attr.type == nil then | 559 if orig_occupant == nil and not muc_x and stanza.attr.type == nil then |
| 506 module:log("debug", "Attempted join without <x>, possibly desynced"); | 560 module:log("debug", "Attempted join without <x>, possibly desynced"); |
| 507 origin.send(st.error_reply(stanza, "cancel", "item-not-found", | 561 origin.send(st.error_reply(stanza, "cancel", "item-not-found", |
| 508 "You must join the room before sending presence updates")); | 562 "You are not currently connected to this chat", self.jid)); |
| 509 return true; | 563 return true; |
| 510 end | 564 end |
| 511 | 565 |
| 512 local is_first_dest_session; | 566 local is_first_dest_session; |
| 513 local dest_occupant; | 567 local dest_occupant; |
| 565 -- Check for nick conflicts | 619 -- Check for nick conflicts |
| 566 if dest_occupant ~= nil and not is_first_dest_session | 620 if dest_occupant ~= nil and not is_first_dest_session |
| 567 and bare_jid ~= jid_bare(dest_occupant.bare_jid) then | 621 and bare_jid ~= jid_bare(dest_occupant.bare_jid) then |
| 568 -- new nick or has different bare real jid | 622 -- new nick or has different bare real jid |
| 569 log("debug", "%s couldn't join due to nick conflict: %s", real_jid, dest_occupant.nick); | 623 log("debug", "%s couldn't join due to nick conflict: %s", real_jid, dest_occupant.nick); |
| 570 local reply = st.error_reply(stanza, "cancel", "conflict"):up(); | 624 local reply = st.error_reply(stanza, "cancel", "conflict", nil, self.jid):up(); |
| 571 reply.tags[1].attr.code = "409"; | 625 reply.tags[1].attr.code = "409"; |
| 572 origin.send(reply:tag("x", {xmlns = "http://jabber.org/protocol/muc"})); | 626 origin.send(reply:tag("x", {xmlns = "http://jabber.org/protocol/muc"})); |
| 573 return true; | 627 return true; |
| 574 end | 628 end |
| 575 | 629 |
| 576 -- Send presence stanza about original occupant | 630 -- Send presence stanza about original occupant |
| 577 if orig_occupant ~= nil and orig_occupant ~= dest_occupant then | 631 if orig_occupant ~= nil and orig_occupant ~= dest_occupant then |
| 578 local orig_x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user";}); | 632 local orig_x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user";}); |
| 633 local orig_role = orig_occupant.role; | |
| 579 local dest_nick; | 634 local dest_nick; |
| 580 if dest_occupant == nil then -- Session is leaving | 635 if dest_occupant == nil then -- Session is leaving |
| 581 log("debug", "session %s is leaving occupant %s", real_jid, orig_occupant.nick); | 636 log("debug", "session %s is leaving occupant %s", real_jid, orig_occupant.nick); |
| 582 if is_last_orig_session then | 637 if is_last_orig_session then |
| 583 orig_occupant.role = nil; | 638 orig_occupant.role = nil; |
| 611 -- self:build_item_list(orig_occupant, x, false, dest_nick); | 666 -- self:build_item_list(orig_occupant, x, false, dest_nick); |
| 612 add_item(x, self:get_affiliation(bare_jid), orig_occupant.role, real_jid, dest_nick); | 667 add_item(x, self:get_affiliation(bare_jid), orig_occupant.role, real_jid, dest_nick); |
| 613 x:tag("status", {code = "303";}):up(); | 668 x:tag("status", {code = "303";}):up(); |
| 614 x:tag("status", {code = "110";}):up(); | 669 x:tag("status", {code = "110";}):up(); |
| 615 self:route_stanza(generated_unavail:add_child(x)); | 670 self:route_stanza(generated_unavail:add_child(x)); |
| 616 dest_nick = nil; -- set dest_nick to nil; so general populance doesn't see it for whole orig_occupant | 671 dest_nick = nil; -- set dest_nick to nil; so general populace doesn't see it for whole orig_occupant |
| 617 end | 672 end |
| 618 end | 673 end |
| 619 | 674 |
| 620 self:save_occupant(orig_occupant); | 675 self:save_occupant(orig_occupant); |
| 621 self:publicise_occupant_status(orig_occupant, orig_x, dest_nick); | 676 self:publicise_occupant_status(orig_occupant, orig_x, dest_nick, nil, nil, orig_role); |
| 622 | 677 |
| 623 if is_last_orig_session then | 678 if is_last_orig_session then |
| 624 module:fire_event("muc-occupant-left", { | 679 module:fire_event("muc-occupant-left", { |
| 625 room = self; | 680 room = self; |
| 626 nick = orig_occupant.nick; | 681 nick = orig_occupant.nick; |
| 637 | 692 |
| 638 if orig_occupant == nil or muc_x then | 693 if orig_occupant == nil or muc_x then |
| 639 -- Send occupant list to newly joined or desynced user | 694 -- Send occupant list to newly joined or desynced user |
| 640 self:send_occupant_list(real_jid, function(nick, occupant) -- luacheck: ignore 212 | 695 self:send_occupant_list(real_jid, function(nick, occupant) -- luacheck: ignore 212 |
| 641 -- Don't include self | 696 -- Don't include self |
| 642 return occupant:get_presence(real_jid) == nil; | 697 return (not occupant) or occupant:get_presence(real_jid) == nil; |
| 643 end) | 698 end) |
| 644 end | 699 end |
| 645 local dest_x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user";}); | 700 local dest_x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user";}); |
| 646 local self_x = st.clone(dest_x); | 701 local self_x = st.clone(dest_x); |
| 647 if orig_occupant == nil and self:get_whois() == "anyone" then | 702 if orig_occupant == nil and self:get_whois() == "anyone" then |
| 648 self_x:tag("status", {code = "100"}):up(); | 703 self_x:tag("status", {code = "100"}):up(); |
| 649 end | 704 end |
| 650 if nick_changed then | 705 if nick_changed then |
| 651 self_x:tag("status", {code="210"}):up(); | 706 self_x:tag("status", {code="210"}):up(); |
| 652 end | 707 end |
| 653 self:publicise_occupant_status(dest_occupant, {base=dest_x,self=self_x}); | 708 self:publicise_occupant_status(dest_occupant, {base=dest_x,self=self_x}, nil, nil, nil, orig_occupant and orig_occupant.role or nil); |
| 654 | 709 |
| 655 if orig_occupant ~= nil and orig_occupant ~= dest_occupant and not is_last_orig_session then | 710 if orig_occupant ~= nil and orig_occupant ~= dest_occupant and not is_last_orig_session then |
| 656 -- If user is swapping and wasn't last original session | 711 -- If user is swapping and wasn't last original session |
| 657 log("debug", "session %s split nicks; showing %s rejoining", real_jid, orig_occupant.nick); | 712 log("debug", "session %s split nicks; showing %s rejoining", real_jid, orig_occupant.nick); |
| 658 -- Show the original nick joining again | 713 -- Show the original nick joining again |
| 694 return self:handle_kickable(origin, stanza) | 749 return self:handle_kickable(origin, stanza) |
| 695 elseif type == nil or type == "unavailable" then | 750 elseif type == nil or type == "unavailable" then |
| 696 return self:handle_normal_presence(origin, stanza); | 751 return self:handle_normal_presence(origin, stanza); |
| 697 elseif type ~= 'result' then -- bad type | 752 elseif type ~= 'result' then -- bad type |
| 698 if type ~= 'visible' and type ~= 'invisible' then -- COMPAT ejabberd can broadcast or forward XEP-0018 presences | 753 if type ~= 'visible' and type ~= 'invisible' then -- COMPAT ejabberd can broadcast or forward XEP-0018 presences |
| 699 origin.send(st.error_reply(stanza, "modify", "bad-request")); -- FIXME correct error? | 754 origin.send(st.error_reply(stanza, "modify", "bad-request", nil, self.jid)); -- FIXME correct error? |
| 700 end | 755 end |
| 701 end | 756 end |
| 702 return true; | 757 return true; |
| 703 end | 758 end |
| 704 | 759 |
| 729 stanza.attr.from, stanza.attr.to, stanza.attr.id = from, to, id; | 784 stanza.attr.from, stanza.attr.to, stanza.attr.id = from, to, id; |
| 730 return true; | 785 return true; |
| 731 else -- Type is "get" or "set" | 786 else -- Type is "get" or "set" |
| 732 local current_nick = self:get_occupant_jid(from); | 787 local current_nick = self:get_occupant_jid(from); |
| 733 if not current_nick then | 788 if not current_nick then |
| 734 origin.send(st.error_reply(stanza, "cancel", "not-acceptable", "You are not currently connected to this chat")); | 789 origin.send(st.error_reply(stanza, "cancel", "not-acceptable", "You are not currently connected to this chat", self.jid)); |
| 735 return true; | 790 return true; |
| 736 end | 791 end |
| 737 if not occupant then -- recipient not in room | 792 if not occupant then -- recipient not in room |
| 738 origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Recipient not in room")); | 793 origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Recipient not in room", self.jid)); |
| 739 return true; | 794 return true; |
| 740 end | 795 end |
| 741 -- XEP-0410 MUC Self-Ping #1220 | 796 -- XEP-0410 MUC Self-Ping #1220 |
| 742 if to == current_nick and stanza.attr.type == "get" and stanza:get_child("ping", "urn:xmpp:ping") then | 797 if to == current_nick and stanza.attr.type == "get" and stanza:get_child("ping", "urn:xmpp:ping") then |
| 743 self:route_stanza(st.reply(stanza)); | 798 self:route_stanza(st.reply(stanza)); |
| 762 local from, to = stanza.attr.from, stanza.attr.to; | 817 local from, to = stanza.attr.from, stanza.attr.to; |
| 763 local current_nick = self:get_occupant_jid(from); | 818 local current_nick = self:get_occupant_jid(from); |
| 764 local type = stanza.attr.type; | 819 local type = stanza.attr.type; |
| 765 if not current_nick then -- not in room | 820 if not current_nick then -- not in room |
| 766 if type ~= "error" then | 821 if type ~= "error" then |
| 767 origin.send(st.error_reply(stanza, "cancel", "not-acceptable", "You are not currently connected to this chat")); | 822 origin.send(st.error_reply(stanza, "cancel", "not-acceptable", "You are not currently connected to this chat", self.jid)); |
| 768 end | 823 end |
| 769 return true; | 824 return true; |
| 770 end | 825 end |
| 771 if type == "groupchat" then -- groupchat messages not allowed in PM | 826 if type == "groupchat" then -- groupchat messages not allowed in PM |
| 772 origin.send(st.error_reply(stanza, "modify", "bad-request")); | 827 origin.send(st.error_reply(stanza, "modify", "bad-request", nil, self.jid)); |
| 773 return true; | 828 return true; |
| 774 elseif type == "error" and is_kickable_error(stanza) then | 829 elseif type == "error" and is_kickable_error(stanza) then |
| 775 log("debug", "%s kicked from %s for sending an error message", current_nick, self.jid); | 830 log("debug", "%s kicked from %s for sending an error message", current_nick, self.jid); |
| 776 return self:handle_kickable(origin, stanza); -- send unavailable | 831 return self:handle_kickable(origin, stanza); -- send unavailable |
| 777 end | 832 end |
| 778 | 833 |
| 779 local o_data = self:get_occupant_by_nick(to); | 834 local o_data = self:get_occupant_by_nick(to); |
| 780 if not o_data then | 835 if not o_data then |
| 781 origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Recipient not in room")); | 836 origin.send(st.error_reply(stanza, "cancel", "item-not-found", "Recipient not in room", self.jid)); |
| 782 return true; | 837 return true; |
| 783 end | 838 end |
| 784 log("debug", "%s sent private message stanza to %s (%s)", from, to, o_data.jid); | 839 log("debug", "%s sent private message stanza to %s (%s)", from, to, o_data.jid); |
| 785 stanza = muc_util.filter_muc_x(st.clone(stanza)); | 840 stanza = muc_util.filter_muc_x(st.clone(stanza)); |
| 786 stanza:tag("x", { xmlns = "http://jabber.org/protocol/muc#user" }):up(); | 841 stanza:tag("x", { xmlns = "http://jabber.org/protocol/muc#user" }):up(); |
| 787 stanza.attr.from = current_nick; | 842 stanza.attr.from = current_nick; |
| 788 self:route_to_occupant(o_data, stanza) | 843 if module:fire_event("muc-private-message", { room = self, origin = origin, stanza = stanza }) ~= false then |
| 844 self:route_to_occupant(o_data, stanza) | |
| 845 end | |
| 789 -- TODO: Remove x tag? | 846 -- TODO: Remove x tag? |
| 790 stanza.attr.from = from; | 847 stanza.attr.from = from; |
| 791 return true; | 848 return true; |
| 792 end | 849 end |
| 793 | 850 |
| 813 function room_mt:process_form(origin, stanza) | 870 function room_mt:process_form(origin, stanza) |
| 814 local form = stanza.tags[1]:get_child("x", "jabber:x:data"); | 871 local form = stanza.tags[1]:get_child("x", "jabber:x:data"); |
| 815 if form.attr.type == "cancel" then | 872 if form.attr.type == "cancel" then |
| 816 origin.send(st.reply(stanza)); | 873 origin.send(st.reply(stanza)); |
| 817 elseif form.attr.type == "submit" then | 874 elseif form.attr.type == "submit" then |
| 875 -- luacheck: ignore 231/errors | |
| 818 local fields, errors, present; | 876 local fields, errors, present; |
| 819 if form.tags[1] == nil then -- Instant room | 877 if form.tags[1] == nil then -- Instant room |
| 820 fields, present = {}, {}; | 878 fields, present = {}, {}; |
| 821 else | 879 else |
| 880 -- FIXME handle form errors | |
| 822 fields, errors, present = self:get_form_layout(stanza.attr.from):data(form); | 881 fields, errors, present = self:get_form_layout(stanza.attr.from):data(form); |
| 823 if fields.FORM_TYPE ~= "http://jabber.org/protocol/muc#roomconfig" then | 882 if fields.FORM_TYPE ~= "http://jabber.org/protocol/muc#roomconfig" then |
| 824 origin.send(st.error_reply(stanza, "cancel", "bad-request", "Form is not of type room configuration")); | 883 origin.send(st.error_reply(stanza, "cancel", "bad-request", "Form is not of type room configuration")); |
| 825 return true; | 884 return true; |
| 826 end | 885 end |
| 871 -- Removes everyone from the room | 930 -- Removes everyone from the room |
| 872 function room_mt:clear(x) | 931 function room_mt:clear(x) |
| 873 x = x or st.stanza("x", {xmlns='http://jabber.org/protocol/muc#user'}); | 932 x = x or st.stanza("x", {xmlns='http://jabber.org/protocol/muc#user'}); |
| 874 local occupants_updated = {}; | 933 local occupants_updated = {}; |
| 875 for nick, occupant in self:each_occupant() do -- luacheck: ignore 213 | 934 for nick, occupant in self:each_occupant() do -- luacheck: ignore 213 |
| 935 local prev_role = occupant.role; | |
| 876 occupant.role = nil; | 936 occupant.role = nil; |
| 877 self:save_occupant(occupant); | 937 self:save_occupant(occupant); |
| 878 occupants_updated[occupant] = true; | 938 occupants_updated[occupant] = prev_role; |
| 879 end | 939 end |
| 880 for occupant in pairs(occupants_updated) do | 940 for occupant, prev_role in pairs(occupants_updated) do |
| 881 self:publicise_occupant_status(occupant, x); | 941 self:publicise_occupant_status(occupant, x, nil, nil, nil, prev_role); |
| 882 module:fire_event("muc-occupant-left", { room = self; nick = occupant.nick; occupant = occupant;}); | 942 module:fire_event("muc-occupant-left", { |
| 943 room = self; | |
| 944 nick = occupant.nick; | |
| 945 occupant = occupant; | |
| 946 }); | |
| 883 end | 947 end |
| 884 end | 948 end |
| 885 | 949 |
| 886 function room_mt:destroy(newjid, reason, password) | 950 function room_mt:destroy(newjid, reason, password) |
| 887 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}) | 951 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}) |
| 970 local item = stanza.tags[1].tags[1]; | 1034 local item = stanza.tags[1].tags[1]; |
| 971 local _aff = item.attr.affiliation; | 1035 local _aff = item.attr.affiliation; |
| 972 local _aff_rank = valid_affiliations[_aff or "none"]; | 1036 local _aff_rank = valid_affiliations[_aff or "none"]; |
| 973 local _rol = item.attr.role; | 1037 local _rol = item.attr.role; |
| 974 if _aff and _aff_rank and not _rol then | 1038 if _aff and _aff_rank and not _rol then |
| 975 -- You need to be at least an admin, and be requesting info about your affifiliation or lower | 1039 -- You need to be at least an admin, and be requesting info about your affiliation or lower |
| 976 -- e.g. an admin can't ask for a list of owners | 1040 -- e.g. an admin can't ask for a list of owners |
| 977 local affiliation_rank = valid_affiliations[affiliation or "none"]; | 1041 local affiliation_rank = valid_affiliations[affiliation or "none"]; |
| 978 if (affiliation_rank >= valid_affiliations.admin and affiliation_rank >= _aff_rank) | 1042 if (affiliation_rank >= valid_affiliations.admin and affiliation_rank >= _aff_rank) |
| 979 or (self:get_whois() == "anyone") then | 1043 or (self:get_whois() == "anyone") then |
| 980 local reply = st.reply(stanza):query("http://jabber.org/protocol/muc#admin"); | 1044 local reply = st.reply(stanza):query("http://jabber.org/protocol/muc#admin"); |
| 1047 end | 1111 end |
| 1048 | 1112 |
| 1049 function room_mt:handle_groupchat_to_room(origin, stanza) | 1113 function room_mt:handle_groupchat_to_room(origin, stanza) |
| 1050 local from = stanza.attr.from; | 1114 local from = stanza.attr.from; |
| 1051 local occupant = self:get_occupant_by_real_jid(from); | 1115 local occupant = self:get_occupant_by_real_jid(from); |
| 1116 if not stanza.attr.id then | |
| 1117 stanza.attr.id = new_id() | |
| 1118 end | |
| 1052 if module:fire_event("muc-occupant-groupchat", { | 1119 if module:fire_event("muc-occupant-groupchat", { |
| 1053 room = self; origin = origin; stanza = stanza; from = from; occupant = occupant; | 1120 room = self; origin = origin; stanza = stanza; from = from; occupant = occupant; |
| 1054 }) then return true; end | 1121 }) then return true; end |
| 1055 stanza.attr.from = occupant.nick; | 1122 stanza.attr.from = occupant.nick; |
| 1056 self:broadcast_message(stanza); | 1123 self:broadcast_message(stanza); |
| 1216 function room_mt:route_stanza(stanza) -- luacheck: ignore 212 | 1283 function room_mt:route_stanza(stanza) -- luacheck: ignore 212 |
| 1217 module:send(stanza); | 1284 module:send(stanza); |
| 1218 end | 1285 end |
| 1219 | 1286 |
| 1220 function room_mt:get_affiliation(jid) | 1287 function room_mt:get_affiliation(jid) |
| 1221 local node, host, resource = jid_split(jid); | 1288 local node, host = jid_split(jid); |
| 1222 -- Affiliations are granted, revoked, and maintained based on the user's bare JID. | 1289 -- Affiliations are granted, revoked, and maintained based on the user's bare JID. |
| 1223 local bare = node and node.."@"..host or host; | 1290 local bare = node and node.."@"..host or host; |
| 1224 local result = self._affiliations[bare]; | 1291 local result = self._affiliations[bare]; |
| 1225 if not result and self._affiliations[host] == "outcast" then result = "outcast"; end -- host banned | 1292 if not result and self._affiliations[host] == "outcast" then result = "outcast"; end -- host banned |
| 1226 return result; | 1293 return result; |
| 1239 end | 1306 end |
| 1240 | 1307 |
| 1241 function room_mt:set_affiliation(actor, jid, affiliation, reason, data) | 1308 function room_mt:set_affiliation(actor, jid, affiliation, reason, data) |
| 1242 if not actor then return nil, "modify", "not-acceptable"; end; | 1309 if not actor then return nil, "modify", "not-acceptable"; end; |
| 1243 | 1310 |
| 1244 local node, host, resource = jid_split(jid); | 1311 local node, host = jid_split(jid); |
| 1245 if not host then return nil, "modify", "not-acceptable"; end | 1312 if not host then return nil, "modify", "not-acceptable"; end |
| 1246 jid = jid_join(node, host); -- Bare | 1313 jid = jid_join(node, host); -- Bare |
| 1247 local is_host_only = node == nil; | 1314 local is_host_only = node == nil; |
| 1248 | 1315 |
| 1249 if valid_affiliations[affiliation or "none"] == nil then | 1316 if valid_affiliations[affiliation or "none"] == nil then |
| 1295 for nick, occupant in self:each_occupant() do -- luacheck: ignore 213 | 1362 for nick, occupant in self:each_occupant() do -- luacheck: ignore 213 |
| 1296 if occupant.bare_jid == jid or ( | 1363 if occupant.bare_jid == jid or ( |
| 1297 -- Outcast can be by host. | 1364 -- Outcast can be by host. |
| 1298 is_host_only and affiliation == "outcast" and select(2, jid_split(occupant.bare_jid)) == host | 1365 is_host_only and affiliation == "outcast" and select(2, jid_split(occupant.bare_jid)) == host |
| 1299 ) then | 1366 ) then |
| 1300 -- need to publcize in all cases; as affiliation in <item/> has changed. | 1367 -- need to publicize in all cases; as affiliation in <item/> has changed. |
| 1301 occupants_updated[occupant] = occupant.role; | 1368 occupants_updated[occupant] = occupant.role; |
| 1302 if occupant.role ~= role and ( | 1369 if occupant.role ~= role and ( |
| 1303 is_downgrade or | 1370 is_downgrade or |
| 1304 valid_roles[occupant.role or "none"] < role_rank -- upgrade | 1371 valid_roles[occupant.role or "none"] < role_rank -- upgrade |
| 1305 ) then | 1372 ) then |
| 1320 end | 1387 end |
| 1321 local is_semi_anonymous = self:get_whois() == "moderators"; | 1388 local is_semi_anonymous = self:get_whois() == "moderators"; |
| 1322 | 1389 |
| 1323 if next(occupants_updated) ~= nil then | 1390 if next(occupants_updated) ~= nil then |
| 1324 for occupant, old_role in pairs(occupants_updated) do | 1391 for occupant, old_role in pairs(occupants_updated) do |
| 1325 self:publicise_occupant_status(occupant, x, nil, actor, reason); | 1392 self:publicise_occupant_status(occupant, x, nil, actor, reason, old_role); |
| 1326 if occupant.role == nil then | 1393 if occupant.role == nil then |
| 1327 module:fire_event("muc-occupant-left", {room = self; nick = occupant.nick; occupant = occupant;}); | 1394 module:fire_event("muc-occupant-left", { |
| 1395 room = self; | |
| 1396 nick = occupant.nick; | |
| 1397 occupant = occupant; | |
| 1398 }); | |
| 1328 elseif is_semi_anonymous and | 1399 elseif is_semi_anonymous and |
| 1329 (old_role == "moderator" and occupant.role ~= "moderator") or | 1400 (old_role == "moderator" and occupant.role ~= "moderator") or |
| 1330 (old_role ~= "moderator" and occupant.role == "moderator") then -- Has gained or lost moderator status | 1401 (old_role ~= "moderator" and occupant.role == "moderator") then -- Has gained or lost moderator status |
| 1331 -- Send everyone else's presences (as jid visibility has changed) | 1402 -- Send everyone else's presences (as jid visibility has changed) |
| 1332 for real_jid in occupant:each_session() do | 1403 for real_jid in occupant:each_session() do |
| 1333 self:send_occupant_list(real_jid, function(occupant_jid, occupant) --luacheck: ignore 212 433 | 1404 self:send_occupant_list(real_jid, function(occupant_jid, occupant) --luacheck: ignore 212 433 |
| 1334 return occupant.bare_jid ~= jid; | 1405 return (not occupant) or occupant.bare_jid ~= jid; |
| 1335 end); | 1406 end); |
| 1336 end | 1407 end |
| 1337 end | 1408 end |
| 1338 end | 1409 end |
| 1339 else | 1410 else |
| 1374 function room_mt:get_role(nick) | 1445 function room_mt:get_role(nick) |
| 1375 local occupant = self:get_occupant_by_nick(nick); | 1446 local occupant = self:get_occupant_by_nick(nick); |
| 1376 return occupant and occupant.role or nil; | 1447 return occupant and occupant.role or nil; |
| 1377 end | 1448 end |
| 1378 | 1449 |
| 1450 function room_mt:may_set_role(actor, occupant, role) | |
| 1451 local event = { | |
| 1452 room = self, | |
| 1453 actor = actor, | |
| 1454 occupant = occupant, | |
| 1455 role = role, | |
| 1456 }; | |
| 1457 | |
| 1458 module:fire_event("muc-pre-set-role", event); | |
| 1459 if event.allowed ~= nil then | |
| 1460 return event.allowed, event.error, event.condition; | |
| 1461 end | |
| 1462 | |
| 1463 -- Can't do anything to other owners or admins | |
| 1464 local occupant_affiliation = self:get_affiliation(occupant.bare_jid); | |
| 1465 if occupant_affiliation == "owner" or occupant_affiliation == "admin" then | |
| 1466 return nil, "cancel", "not-allowed"; | |
| 1467 end | |
| 1468 | |
| 1469 -- If you are trying to give or take moderator role you need to be an owner or admin | |
| 1470 if occupant.role == "moderator" or role == "moderator" then | |
| 1471 local actor_affiliation = self:get_affiliation(actor); | |
| 1472 if actor_affiliation ~= "owner" and actor_affiliation ~= "admin" then | |
| 1473 return nil, "cancel", "not-allowed"; | |
| 1474 end | |
| 1475 end | |
| 1476 | |
| 1477 -- Need to be in the room and a moderator | |
| 1478 local actor_occupant = self:get_occupant_by_real_jid(actor); | |
| 1479 if not actor_occupant or actor_occupant.role ~= "moderator" then | |
| 1480 return nil, "cancel", "not-allowed"; | |
| 1481 end | |
| 1482 | |
| 1483 return true; | |
| 1484 end | |
| 1485 | |
| 1379 function room_mt:set_role(actor, occupant_jid, role, reason) | 1486 function room_mt:set_role(actor, occupant_jid, role, reason) |
| 1380 if not actor then return nil, "modify", "not-acceptable"; end | 1487 if not actor then return nil, "modify", "not-acceptable"; end |
| 1381 | 1488 |
| 1382 local occupant = self:get_occupant_by_nick(occupant_jid); | 1489 local occupant = self:get_occupant_by_nick(occupant_jid); |
| 1383 if not occupant then return nil, "modify", "item-not-found"; end | 1490 if not occupant then return nil, "modify", "item-not-found"; end |
| 1388 role = role ~= "none" and role or nil; -- coerces `role == false` to `nil` | 1495 role = role ~= "none" and role or nil; -- coerces `role == false` to `nil` |
| 1389 | 1496 |
| 1390 if actor == true then | 1497 if actor == true then |
| 1391 actor = nil -- So we can pass it safely to 'publicise_occupant_status' below | 1498 actor = nil -- So we can pass it safely to 'publicise_occupant_status' below |
| 1392 else | 1499 else |
| 1393 -- Can't do anything to other owners or admins | 1500 local allowed, err, condition = self:may_set_role(actor, occupant, role) |
| 1394 local occupant_affiliation = self:get_affiliation(occupant.bare_jid); | 1501 if not allowed then |
| 1395 if occupant_affiliation == "owner" or occupant_affiliation == "admin" then | 1502 return allowed, err, condition; |
| 1396 return nil, "cancel", "not-allowed"; | |
| 1397 end | |
| 1398 | |
| 1399 -- If you are trying to give or take moderator role you need to be an owner or admin | |
| 1400 if occupant.role == "moderator" or role == "moderator" then | |
| 1401 local actor_affiliation = self:get_affiliation(actor); | |
| 1402 if actor_affiliation ~= "owner" and actor_affiliation ~= "admin" then | |
| 1403 return nil, "cancel", "not-allowed"; | |
| 1404 end | |
| 1405 end | |
| 1406 | |
| 1407 -- Need to be in the room and a moderator | |
| 1408 local actor_occupant = self:get_occupant_by_real_jid(actor); | |
| 1409 if not actor_occupant or actor_occupant.role ~= "moderator" then | |
| 1410 return nil, "cancel", "not-allowed"; | |
| 1411 end | 1503 end |
| 1412 end | 1504 end |
| 1413 | 1505 |
| 1414 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}); | 1506 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}); |
| 1415 if not role then | 1507 if not role then |
| 1416 x:tag("status", {code = "307"}):up(); | 1508 x:tag("status", {code = "307"}):up(); |
| 1417 end | 1509 end |
| 1510 | |
| 1511 local prev_role = occupant.role; | |
| 1418 occupant.role = role; | 1512 occupant.role = role; |
| 1419 self:save_occupant(occupant); | 1513 self:save_occupant(occupant); |
| 1420 self:publicise_occupant_status(occupant, x, nil, actor, reason); | 1514 self:publicise_occupant_status(occupant, x, nil, actor, reason, prev_role); |
| 1421 if role == nil then | 1515 if role == nil then |
| 1422 module:fire_event("muc-occupant-left", {room = self; nick = occupant.nick; occupant = occupant;}); | 1516 module:fire_event("muc-occupant-left", { |
| 1517 room = self; | |
| 1518 nick = occupant.nick; | |
| 1519 occupant = occupant; | |
| 1520 }); | |
| 1423 end | 1521 end |
| 1424 return true; | 1522 return true; |
| 1425 end | 1523 end |
| 1426 | 1524 |
| 1427 local whois = module:require "muc/whois"; | 1525 local whois = module:require "muc/whois"; |
| 1439 _affiliations = {}; | 1537 _affiliations = {}; |
| 1440 _affiliation_data = {}; | 1538 _affiliation_data = {}; |
| 1441 }, room_mt); | 1539 }, room_mt); |
| 1442 end | 1540 end |
| 1443 | 1541 |
| 1444 local new_format = module:get_option_boolean("new_muc_storage_format", false); | 1542 local new_format = module:get_option_boolean("new_muc_storage_format", true); |
| 1445 | 1543 |
| 1446 function room_mt:freeze(live) | 1544 function room_mt:freeze(live) |
| 1447 local frozen, state; | 1545 local frozen, state; |
| 1448 if new_format then | 1546 if new_format then |
| 1449 frozen = { | 1547 frozen = { |
| 1503 -- Old storage format | 1601 -- Old storage format |
| 1504 room._affiliations = frozen._affiliations; | 1602 room._affiliations = frozen._affiliations; |
| 1505 else | 1603 else |
| 1506 -- New storage format | 1604 -- New storage format |
| 1507 for jid, data in pairs(frozen) do | 1605 for jid, data in pairs(frozen) do |
| 1508 local node, host, resource = jid_split(jid); | 1606 local _, host, resource = jid_split(jid); |
| 1509 if host:sub(1,1) ~= "_" and not resource and type(data) == "string" then | 1607 if host:sub(1,1) ~= "_" and not resource and type(data) == "string" then |
| 1510 -- bare jid: affiliation | 1608 -- bare jid: affiliation |
| 1511 room._affiliations[jid] = data; | 1609 room._affiliations[jid] = data; |
| 1512 end | 1610 end |
| 1513 end | 1611 end |
