Software /
code /
prosody
Comparison
plugins/muc/muc.lib.lua @ 10061:5c71693c8345
Merge 0.11->trunk
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Mon, 08 Jul 2019 02:44:32 +0200 |
parent | 10048:e5532fbdd163 |
child | 10212:a53126b7fe22 |
comparison
equal
deleted
inserted
replaced
10060:7a36b7ac309b | 10061:5c71693c8345 |
---|---|
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 |
277 self_x = st.clone(x.self or base_x); | 278 self_x = st.clone(x.self or base_x); |
278 self:build_item_list(occupant, self_x, false, nick, actor_nick, nil, reason); | 279 self:build_item_list(occupant, self_x, false, nick, actor_nick, nil, reason); |
279 self_p = st.clone(base_presence):add_child(self_x); | 280 self_p = st.clone(base_presence):add_child(self_x); |
280 end | 281 end |
281 | 282 |
282 -- General populance | 283 -- General populace |
283 for occupant_nick, n_occupant in self:each_occupant() do | 284 for occupant_nick, n_occupant in self:each_occupant() do |
284 if occupant_nick ~= occupant.nick then | 285 if occupant_nick ~= occupant.nick then |
285 local pr; | 286 local pr; |
286 if can_see_real_jids(whois, n_occupant) then | 287 if can_see_real_jids(whois, n_occupant) then |
287 pr = get_full_p(); | 288 pr = get_full_p(); |
388 if is_last_session then | 389 if is_last_session then |
389 x:tag("status", {code = "333"}); | 390 x:tag("status", {code = "333"}); |
390 end | 391 end |
391 self:publicise_occupant_status(new_occupant or occupant, x); | 392 self:publicise_occupant_status(new_occupant or occupant, x); |
392 if is_last_session then | 393 if is_last_session then |
393 module:fire_event("muc-occupant-left", {room = self; nick = occupant.nick; occupant = occupant;}); | 394 module:fire_event("muc-occupant-left", { |
395 room = self; | |
396 nick = occupant.nick; | |
397 occupant = occupant; | |
398 }); | |
394 end | 399 end |
395 return true; | 400 return true; |
396 end | 401 end |
397 | 402 |
398 -- Give the room creator owner affiliation | 403 -- Give the room creator owner affiliation |
426 return true; | 431 return true; |
427 end | 432 end |
428 end, 1); | 433 end, 1); |
429 | 434 |
430 function room_mt:handle_first_presence(origin, stanza) | 435 function room_mt:handle_first_presence(origin, stanza) |
431 if not stanza:get_child("x", "http://jabber.org/protocol/muc") then | |
432 module:log("debug", "Room creation without <x>, possibly desynced"); | |
433 | |
434 origin.send(st.error_reply(stanza, "cancel", "item-not-found")); | |
435 return true; | |
436 end | |
437 | |
438 local real_jid = stanza.attr.from; | 436 local real_jid = stanza.attr.from; |
439 local dest_jid = stanza.attr.to; | 437 local dest_jid = stanza.attr.to; |
440 local bare_jid = jid_bare(real_jid); | 438 local bare_jid = jid_bare(real_jid); |
441 if module:fire_event("muc-room-pre-create", { | 439 if module:fire_event("muc-room-pre-create", { |
442 room = self; | 440 room = self; |
502 local muc_x = stanza:get_child("x", "http://jabber.org/protocol/muc"); | 500 local muc_x = stanza:get_child("x", "http://jabber.org/protocol/muc"); |
503 | 501 |
504 if orig_occupant == nil and not muc_x and stanza.attr.type == nil then | 502 if orig_occupant == nil and not muc_x and stanza.attr.type == nil then |
505 module:log("debug", "Attempted join without <x>, possibly desynced"); | 503 module:log("debug", "Attempted join without <x>, possibly desynced"); |
506 origin.send(st.error_reply(stanza, "cancel", "item-not-found", | 504 origin.send(st.error_reply(stanza, "cancel", "item-not-found", |
507 "You must join the room before sending presence updates")); | 505 "You are not currently connected to this chat")); |
508 return true; | 506 return true; |
509 end | 507 end |
510 | 508 |
511 local is_first_dest_session; | 509 local is_first_dest_session; |
512 local dest_occupant; | 510 local dest_occupant; |
607 -- self:build_item_list(orig_occupant, x, false, dest_nick); | 605 -- self:build_item_list(orig_occupant, x, false, dest_nick); |
608 add_item(x, self:get_affiliation(bare_jid), orig_occupant.role, real_jid, dest_nick); | 606 add_item(x, self:get_affiliation(bare_jid), orig_occupant.role, real_jid, dest_nick); |
609 x:tag("status", {code = "303";}):up(); | 607 x:tag("status", {code = "303";}):up(); |
610 x:tag("status", {code = "110";}):up(); | 608 x:tag("status", {code = "110";}):up(); |
611 self:route_stanza(generated_unavail:add_child(x)); | 609 self:route_stanza(generated_unavail:add_child(x)); |
612 dest_nick = nil; -- set dest_nick to nil; so general populance doesn't see it for whole orig_occupant | 610 dest_nick = nil; -- set dest_nick to nil; so general populace doesn't see it for whole orig_occupant |
613 end | 611 end |
614 end | 612 end |
615 | 613 |
616 self:save_occupant(orig_occupant); | 614 self:save_occupant(orig_occupant); |
617 self:publicise_occupant_status(orig_occupant, orig_x, dest_nick); | 615 self:publicise_occupant_status(orig_occupant, orig_x, dest_nick); |
872 self:save_occupant(occupant); | 870 self:save_occupant(occupant); |
873 occupants_updated[occupant] = true; | 871 occupants_updated[occupant] = true; |
874 end | 872 end |
875 for occupant in pairs(occupants_updated) do | 873 for occupant in pairs(occupants_updated) do |
876 self:publicise_occupant_status(occupant, x); | 874 self:publicise_occupant_status(occupant, x); |
877 module:fire_event("muc-occupant-left", { room = self; nick = occupant.nick; occupant = occupant;}); | 875 module:fire_event("muc-occupant-left", { |
876 room = self; | |
877 nick = occupant.nick; | |
878 occupant = occupant; | |
879 }); | |
878 end | 880 end |
879 end | 881 end |
880 | 882 |
881 function room_mt:destroy(newjid, reason, password) | 883 function room_mt:destroy(newjid, reason, password) |
882 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}) | 884 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}) |
965 local item = stanza.tags[1].tags[1]; | 967 local item = stanza.tags[1].tags[1]; |
966 local _aff = item.attr.affiliation; | 968 local _aff = item.attr.affiliation; |
967 local _aff_rank = valid_affiliations[_aff or "none"]; | 969 local _aff_rank = valid_affiliations[_aff or "none"]; |
968 local _rol = item.attr.role; | 970 local _rol = item.attr.role; |
969 if _aff and _aff_rank and not _rol then | 971 if _aff and _aff_rank and not _rol then |
970 -- You need to be at least an admin, and be requesting info about your affifiliation or lower | 972 -- You need to be at least an admin, and be requesting info about your affiliation or lower |
971 -- e.g. an admin can't ask for a list of owners | 973 -- e.g. an admin can't ask for a list of owners |
972 local affiliation_rank = valid_affiliations[affiliation or "none"]; | 974 local affiliation_rank = valid_affiliations[affiliation or "none"]; |
973 if (affiliation_rank >= valid_affiliations.admin and affiliation_rank >= _aff_rank) | 975 if (affiliation_rank >= valid_affiliations.admin and affiliation_rank >= _aff_rank) |
974 or (self:get_whois() == "anyone") then | 976 or (self:get_whois() == "anyone") then |
975 local reply = st.reply(stanza):query("http://jabber.org/protocol/muc#admin"); | 977 local reply = st.reply(stanza):query("http://jabber.org/protocol/muc#admin"); |
1042 end | 1044 end |
1043 | 1045 |
1044 function room_mt:handle_groupchat_to_room(origin, stanza) | 1046 function room_mt:handle_groupchat_to_room(origin, stanza) |
1045 local from = stanza.attr.from; | 1047 local from = stanza.attr.from; |
1046 local occupant = self:get_occupant_by_real_jid(from); | 1048 local occupant = self:get_occupant_by_real_jid(from); |
1049 if not stanza.attr.id then | |
1050 stanza.attr.id = new_id() | |
1051 end | |
1047 if module:fire_event("muc-occupant-groupchat", { | 1052 if module:fire_event("muc-occupant-groupchat", { |
1048 room = self; origin = origin; stanza = stanza; from = from; occupant = occupant; | 1053 room = self; origin = origin; stanza = stanza; from = from; occupant = occupant; |
1049 }) then return true; end | 1054 }) then return true; end |
1050 stanza.attr.from = occupant.nick; | 1055 stanza.attr.from = occupant.nick; |
1051 self:broadcast_message(stanza); | 1056 self:broadcast_message(stanza); |
1290 for nick, occupant in self:each_occupant() do -- luacheck: ignore 213 | 1295 for nick, occupant in self:each_occupant() do -- luacheck: ignore 213 |
1291 if occupant.bare_jid == jid or ( | 1296 if occupant.bare_jid == jid or ( |
1292 -- Outcast can be by host. | 1297 -- Outcast can be by host. |
1293 is_host_only and affiliation == "outcast" and select(2, jid_split(occupant.bare_jid)) == host | 1298 is_host_only and affiliation == "outcast" and select(2, jid_split(occupant.bare_jid)) == host |
1294 ) then | 1299 ) then |
1295 -- need to publcize in all cases; as affiliation in <item/> has changed. | 1300 -- need to publicize in all cases; as affiliation in <item/> has changed. |
1296 occupants_updated[occupant] = occupant.role; | 1301 occupants_updated[occupant] = occupant.role; |
1297 if occupant.role ~= role and ( | 1302 if occupant.role ~= role and ( |
1298 is_downgrade or | 1303 is_downgrade or |
1299 valid_roles[occupant.role or "none"] < role_rank -- upgrade | 1304 valid_roles[occupant.role or "none"] < role_rank -- upgrade |
1300 ) then | 1305 ) then |
1317 | 1322 |
1318 if next(occupants_updated) ~= nil then | 1323 if next(occupants_updated) ~= nil then |
1319 for occupant, old_role in pairs(occupants_updated) do | 1324 for occupant, old_role in pairs(occupants_updated) do |
1320 self:publicise_occupant_status(occupant, x, nil, actor, reason); | 1325 self:publicise_occupant_status(occupant, x, nil, actor, reason); |
1321 if occupant.role == nil then | 1326 if occupant.role == nil then |
1322 module:fire_event("muc-occupant-left", {room = self; nick = occupant.nick; occupant = occupant;}); | 1327 module:fire_event("muc-occupant-left", { |
1328 room = self; | |
1329 nick = occupant.nick; | |
1330 occupant = occupant; | |
1331 }); | |
1323 elseif is_semi_anonymous and | 1332 elseif is_semi_anonymous and |
1324 (old_role == "moderator" and occupant.role ~= "moderator") or | 1333 (old_role == "moderator" and occupant.role ~= "moderator") or |
1325 (old_role ~= "moderator" and occupant.role == "moderator") then -- Has gained or lost moderator status | 1334 (old_role ~= "moderator" and occupant.role == "moderator") then -- Has gained or lost moderator status |
1326 -- Send everyone else's presences (as jid visibility has changed) | 1335 -- Send everyone else's presences (as jid visibility has changed) |
1327 for real_jid in occupant:each_session() do | 1336 for real_jid in occupant:each_session() do |
1369 function room_mt:get_role(nick) | 1378 function room_mt:get_role(nick) |
1370 local occupant = self:get_occupant_by_nick(nick); | 1379 local occupant = self:get_occupant_by_nick(nick); |
1371 return occupant and occupant.role or nil; | 1380 return occupant and occupant.role or nil; |
1372 end | 1381 end |
1373 | 1382 |
1383 function room_mt:may_set_role(actor, occupant, role) | |
1384 local event = { | |
1385 room = self, | |
1386 actor = actor, | |
1387 occupant = occupant, | |
1388 role = role, | |
1389 }; | |
1390 | |
1391 module:fire_event("muc-pre-set-role", event); | |
1392 if event.allowed ~= nil then | |
1393 return event.allowed, event.error, event.condition; | |
1394 end | |
1395 | |
1396 -- Can't do anything to other owners or admins | |
1397 local occupant_affiliation = self:get_affiliation(occupant.bare_jid); | |
1398 if occupant_affiliation == "owner" or occupant_affiliation == "admin" then | |
1399 return nil, "cancel", "not-allowed"; | |
1400 end | |
1401 | |
1402 -- If you are trying to give or take moderator role you need to be an owner or admin | |
1403 if occupant.role == "moderator" or role == "moderator" then | |
1404 local actor_affiliation = self:get_affiliation(actor); | |
1405 if actor_affiliation ~= "owner" and actor_affiliation ~= "admin" then | |
1406 return nil, "cancel", "not-allowed"; | |
1407 end | |
1408 end | |
1409 | |
1410 -- Need to be in the room and a moderator | |
1411 local actor_occupant = self:get_occupant_by_real_jid(actor); | |
1412 if not actor_occupant or actor_occupant.role ~= "moderator" then | |
1413 return nil, "cancel", "not-allowed"; | |
1414 end | |
1415 | |
1416 return true; | |
1417 end | |
1418 | |
1374 function room_mt:set_role(actor, occupant_jid, role, reason) | 1419 function room_mt:set_role(actor, occupant_jid, role, reason) |
1375 if not actor then return nil, "modify", "not-acceptable"; end | 1420 if not actor then return nil, "modify", "not-acceptable"; end |
1376 | 1421 |
1377 local occupant = self:get_occupant_by_nick(occupant_jid); | 1422 local occupant = self:get_occupant_by_nick(occupant_jid); |
1378 if not occupant then return nil, "modify", "item-not-found"; end | 1423 if not occupant then return nil, "modify", "item-not-found"; end |
1383 role = role ~= "none" and role or nil; -- coerces `role == false` to `nil` | 1428 role = role ~= "none" and role or nil; -- coerces `role == false` to `nil` |
1384 | 1429 |
1385 if actor == true then | 1430 if actor == true then |
1386 actor = nil -- So we can pass it safely to 'publicise_occupant_status' below | 1431 actor = nil -- So we can pass it safely to 'publicise_occupant_status' below |
1387 else | 1432 else |
1388 -- Can't do anything to other owners or admins | 1433 local allowed, err, condition = self:may_set_role(actor, occupant, role) |
1389 local occupant_affiliation = self:get_affiliation(occupant.bare_jid); | 1434 if not allowed then |
1390 if occupant_affiliation == "owner" or occupant_affiliation == "admin" then | 1435 return allowed, err, condition; |
1391 return nil, "cancel", "not-allowed"; | |
1392 end | |
1393 | |
1394 -- If you are trying to give or take moderator role you need to be an owner or admin | |
1395 if occupant.role == "moderator" or role == "moderator" then | |
1396 local actor_affiliation = self:get_affiliation(actor); | |
1397 if actor_affiliation ~= "owner" and actor_affiliation ~= "admin" then | |
1398 return nil, "cancel", "not-allowed"; | |
1399 end | |
1400 end | |
1401 | |
1402 -- Need to be in the room and a moderator | |
1403 local actor_occupant = self:get_occupant_by_real_jid(actor); | |
1404 if not actor_occupant or actor_occupant.role ~= "moderator" then | |
1405 return nil, "cancel", "not-allowed"; | |
1406 end | 1436 end |
1407 end | 1437 end |
1408 | 1438 |
1409 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}); | 1439 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}); |
1410 if not role then | 1440 if not role then |
1412 end | 1442 end |
1413 occupant.role = role; | 1443 occupant.role = role; |
1414 self:save_occupant(occupant); | 1444 self:save_occupant(occupant); |
1415 self:publicise_occupant_status(occupant, x, nil, actor, reason); | 1445 self:publicise_occupant_status(occupant, x, nil, actor, reason); |
1416 if role == nil then | 1446 if role == nil then |
1417 module:fire_event("muc-occupant-left", {room = self; nick = occupant.nick; occupant = occupant;}); | 1447 module:fire_event("muc-occupant-left", { |
1448 room = self; | |
1449 nick = occupant.nick; | |
1450 occupant = occupant; | |
1451 }); | |
1418 end | 1452 end |
1419 return true; | 1453 return true; |
1420 end | 1454 end |
1421 | 1455 |
1422 local whois = module:require "muc/whois"; | 1456 local whois = module:require "muc/whois"; |