Mercurial > prosody-hg
comparison plugins/muc/muc.lib.lua @ 8842:463505cc75d5
MUC: Revert unstable MUC commits since 0.10.1
These have caused too many issue reports to be included in
the stable branch at this time.
Affected issues: #345, #397
Reverted commits:
dcd53a565c01
6d4b0895f76d
1b10802a770e
564e897f0790
a7221ada9368
aaff40ec7001
05a3275b6873
c2b99fa134b3
8da11142fabf
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Wed, 30 May 2018 21:33:53 +0100 |
| parents | dcd53a565c01 |
| children | 041ddc670934 c47f220580fd |
comparison
equal
deleted
inserted
replaced
| 8841:bc8558bbc797 | 8842:463505cc75d5 |
|---|---|
| 169 | 169 |
| 170 local maxchars = history_tag and tonumber(history_tag.attr.maxchars); | 170 local maxchars = history_tag and tonumber(history_tag.attr.maxchars); |
| 171 if maxchars then maxchars = math.floor(maxchars); end | 171 if maxchars then maxchars = math.floor(maxchars); end |
| 172 | 172 |
| 173 local maxstanzas = math.floor(history_tag and tonumber(history_tag.attr.maxstanzas) or #history); | 173 local maxstanzas = math.floor(history_tag and tonumber(history_tag.attr.maxstanzas) or #history); |
| 174 if not history_tag then maxstanzas = self._data.default_history_messages; end | 174 if not history_tag then maxstanzas = 20; end |
| 175 | 175 |
| 176 local seconds = history_tag and tonumber(history_tag.attr.seconds); | 176 local seconds = history_tag and tonumber(history_tag.attr.seconds); |
| 177 if seconds then seconds = datetime.datetime(os.time() - math.floor(seconds)); end | 177 if seconds then seconds = datetime.datetime(os.time() - math.floor(seconds)); end |
| 178 | 178 |
| 179 local since = history_tag and history_tag.attr.since; | 179 local since = history_tag and history_tag.attr.since; |
| 356 if length == default_history_length then | 356 if length == default_history_length then |
| 357 length = nil; | 357 length = nil; |
| 358 end | 358 end |
| 359 self._data.history_length = length; | 359 self._data.history_length = length; |
| 360 end | 360 end |
| 361 | |
| 362 -- Fix for clients who don't support XEP-0045 correctly | |
| 363 -- Default number of history messages the room returns | |
| 364 function room_mt:get_defaulthistorymessages() | |
| 365 return self._data.default_history_messages or default_history_length; | |
| 366 end | |
| 367 function room_mt:set_defaulthistorymessages(number) | |
| 368 number = math.min(tonumber(number) or default_history_length, self._data.history_length or default_history_length); | |
| 369 if number == default_history_length then | |
| 370 number = nil; | |
| 371 end | |
| 372 self._data.default_history_messages = number; | |
| 373 end | |
| 374 | |
| 375 | 361 |
| 376 | 362 |
| 377 local valid_whois = { moderators = true, anyone = true }; | 363 local valid_whois = { moderators = true, anyone = true }; |
| 378 | 364 |
| 379 function room_mt:set_whois(whois) | 365 function room_mt:set_whois(whois) |
| 710 { | 696 { |
| 711 name = 'muc#roomconfig_historylength', | 697 name = 'muc#roomconfig_historylength', |
| 712 type = 'text-single', | 698 type = 'text-single', |
| 713 label = 'Maximum Number of History Messages Returned by Room', | 699 label = 'Maximum Number of History Messages Returned by Room', |
| 714 value = tostring(self:get_historylength()) | 700 value = tostring(self:get_historylength()) |
| 715 }, | |
| 716 { | |
| 717 name = 'muc#roomconfig_defaulthistorymessages', | |
| 718 type = 'text-single', | |
| 719 label = 'Default Number of History Messages Returned by Room', | |
| 720 value = tostring(self:get_defaulthistorymessages()) | |
| 721 } | 701 } |
| 722 }); | 702 }); |
| 723 return module:fire_event("muc-config-form", { room = self, actor = actor, form = form }) or form; | 703 return module:fire_event("muc-config-form", { room = self, actor = actor, form = form }) or form; |
| 724 end | 704 end |
| 725 | 705 |
| 764 handle_option("moderated", "muc#roomconfig_moderatedroom"); | 744 handle_option("moderated", "muc#roomconfig_moderatedroom"); |
| 765 handle_option("members_only", "muc#roomconfig_membersonly"); | 745 handle_option("members_only", "muc#roomconfig_membersonly"); |
| 766 handle_option("public", "muc#roomconfig_publicroom"); | 746 handle_option("public", "muc#roomconfig_publicroom"); |
| 767 handle_option("changesubject", "muc#roomconfig_changesubject"); | 747 handle_option("changesubject", "muc#roomconfig_changesubject"); |
| 768 handle_option("historylength", "muc#roomconfig_historylength"); | 748 handle_option("historylength", "muc#roomconfig_historylength"); |
| 769 handle_option("defaulthistorymessages", "muc#roomconfig_defaulthistorymessages"); | |
| 770 handle_option("whois", "muc#roomconfig_whois", valid_whois); | 749 handle_option("whois", "muc#roomconfig_whois", valid_whois); |
| 771 handle_option("password", "muc#roomconfig_roomsecret"); | 750 handle_option("password", "muc#roomconfig_roomsecret"); |
| 772 | 751 |
| 773 if self.save then self:save(true); end | 752 if self.save then self:save(true); end |
| 774 if self.locked then | 753 if self.locked then |
| 821 elseif xmlns == "http://jabber.org/protocol/muc#admin" then | 800 elseif xmlns == "http://jabber.org/protocol/muc#admin" then |
| 822 local actor = stanza.attr.from; | 801 local actor = stanza.attr.from; |
| 823 local affiliation = self:get_affiliation(actor); | 802 local affiliation = self:get_affiliation(actor); |
| 824 local current_nick = self._jid_nick[actor]; | 803 local current_nick = self._jid_nick[actor]; |
| 825 local role = current_nick and self._occupants[current_nick].role or self:get_default_role(affiliation); | 804 local role = current_nick and self._occupants[current_nick].role or self:get_default_role(affiliation); |
| 826 if type == "set" then | 805 local item = stanza.tags[1].tags[1]; |
| 827 local at_least_one_item_provided = false; | 806 if item and item.name == "item" then |
| 828 local callback = function() origin.send(st.reply(stanza)); end | 807 if type == "set" then |
| 829 | 808 local callback = function() origin.send(st.reply(stanza)); end |
| 830 -- Gather all changes to affiliations and roles | |
| 831 local jid_affiliation = {}; | |
| 832 local jidnick_role = {}; | |
| 833 for item in stanza.tags[1]:childtags("item") do | |
| 834 at_least_one_item_provided = true; | |
| 835 | |
| 836 if item.attr.jid then -- Validate provided JID | 809 if item.attr.jid then -- Validate provided JID |
| 837 item.attr.jid = jid_prep(item.attr.jid); | 810 item.attr.jid = jid_prep(item.attr.jid); |
| 838 if not item.attr.jid then | 811 if not item.attr.jid then |
| 839 origin.send(st.error_reply(stanza, "modify", "jid-malformed")); | 812 origin.send(st.error_reply(stanza, "modify", "jid-malformed")); |
| 840 return; | 813 return; |
| 845 if occupant then item.attr.jid = occupant.jid; end | 818 if occupant then item.attr.jid = occupant.jid; end |
| 846 elseif not item.attr.nick and item.attr.jid then | 819 elseif not item.attr.nick and item.attr.jid then |
| 847 local nick = self._jid_nick[item.attr.jid]; | 820 local nick = self._jid_nick[item.attr.jid]; |
| 848 if nick then item.attr.nick = select(3, jid_split(nick)); end | 821 if nick then item.attr.nick = select(3, jid_split(nick)); end |
| 849 end | 822 end |
| 850 | |
| 851 local reason = item.tags[1] and item.tags[1].name == "reason" and #item.tags[1] == 1 and item.tags[1][1]; | 823 local reason = item.tags[1] and item.tags[1].name == "reason" and #item.tags[1] == 1 and item.tags[1][1]; |
| 852 if item.attr.affiliation and item.attr.jid and not item.attr.role then | 824 if item.attr.affiliation and item.attr.jid and not item.attr.role then |
| 853 jid_affiliation[item.attr.jid] = { ["affiliation"] = item.attr.affiliation, ["reason"] = reason }; | 825 local success, errtype, err = self:set_affiliation(actor, item.attr.jid, item.attr.affiliation, callback, reason); |
| 826 if not success then origin.send(st.error_reply(stanza, errtype, err)); end | |
| 854 elseif item.attr.role and item.attr.nick and not item.attr.affiliation then | 827 elseif item.attr.role and item.attr.nick and not item.attr.affiliation then |
| 855 jidnick_role[self.jid.."/"..item.attr.nick] = { ["role"] = item.attr.role, ["reason"] = reason }; | 828 local success, errtype, err = self:set_role(actor, self.jid.."/"..item.attr.nick, item.attr.role, callback, reason); |
| 829 if not success then origin.send(st.error_reply(stanza, errtype, err)); end | |
| 856 else | 830 else |
| 857 origin.send(st.error_reply(stanza, "cancel", "bad-request")); | 831 origin.send(st.error_reply(stanza, "cancel", "bad-request")); |
| 858 return; | |
| 859 end | 832 end |
| 860 end | 833 elseif type == "get" then |
| 861 | |
| 862 if not at_least_one_item_provided then | |
| 863 origin.send(st.error_reply(stanza, "cancel", "bad-request")); | |
| 864 return; | |
| 865 else | |
| 866 local can_set_affiliations, errtype_aff, err_aff = self:can_set_affiliations(actor, jid_affiliation) | |
| 867 local can_set_roles, errtype_role, err_role = self:can_set_roles(actor, jidnick_role) | |
| 868 | |
| 869 if can_set_affiliations and can_set_roles then | |
| 870 local nb_affiliation_changes = 0; | |
| 871 for _ in pairs(jid_affiliation) do nb_affiliation_changes = nb_affiliation_changes + 1; end | |
| 872 local nb_role_changes = 0; | |
| 873 for _ in pairs(jidnick_role) do nb_role_changes = nb_role_changes + 1; end | |
| 874 | |
| 875 if nb_affiliation_changes > 0 and nb_role_changes > 0 then | |
| 876 origin.send(st.error_reply(stanza, "cancel", "bad-request")); | |
| 877 end | |
| 878 if nb_affiliation_changes > 0 then | |
| 879 self:set_affiliations(actor, jid_affiliation, callback); | |
| 880 end | |
| 881 if nb_role_changes > 0 then | |
| 882 self:set_roles(actor, jidnick_role, callback); | |
| 883 end | |
| 884 else | |
| 885 if not can_set_affiliations then | |
| 886 origin.send(st.error_reply(stanza, errtype_aff, err_aff)); | |
| 887 elseif not can_set_roles then | |
| 888 origin.send(st.error_reply(stanza, errtype_role, err_role)); | |
| 889 else | |
| 890 origin.send(st.error_reply(stanza, "cancel", "bad-request")); | |
| 891 end | |
| 892 | |
| 893 return; | |
| 894 end | |
| 895 end | |
| 896 elseif type == "get" then | |
| 897 local item = stanza.tags[1].tags[1]; | |
| 898 if item and item.name == "item" then | |
| 899 local _aff = item.attr.affiliation; | 834 local _aff = item.attr.affiliation; |
| 900 local _rol = item.attr.role; | 835 local _rol = item.attr.role; |
| 901 if _aff and not _rol then | 836 if _aff and not _rol then |
| 902 if affiliation == "owner" or (affiliation == "admin" and _aff ~= "owner" and _aff ~= "admin") | 837 if affiliation == "owner" or (affiliation == "admin" and _aff ~= "owner" and _aff ~= "admin") |
| 903 or (affiliation and affiliation ~= "outcast" and self:get_members_only() and self:get_whois() == "anyone") then | 838 or (affiliation and affiliation ~= "outcast" and self:get_members_only() and self:get_whois() == "anyone") then |
| 931 origin.send(st.error_reply(stanza, "auth", "forbidden")); | 866 origin.send(st.error_reply(stanza, "auth", "forbidden")); |
| 932 end | 867 end |
| 933 else | 868 else |
| 934 origin.send(st.error_reply(stanza, "cancel", "bad-request")); | 869 origin.send(st.error_reply(stanza, "cancel", "bad-request")); |
| 935 end | 870 end |
| 936 else | 871 end |
| 937 origin.send(st.error_reply(stanza, "cancel", "bad-request")); | 872 elseif type == "set" or type == "get" then |
| 938 end | 873 origin.send(st.error_reply(stanza, "cancel", "bad-request")); |
| 939 end | 874 end |
| 940 elseif xmlns == "http://jabber.org/protocol/muc#owner" and (type == "get" or type == "set") and stanza.tags[1].name == "query" then | 875 elseif xmlns == "http://jabber.org/protocol/muc#owner" and (type == "get" or type == "set") and stanza.tags[1].name == "query" then |
| 941 if self:get_affiliation(stanza.attr.from) ~= "owner" then | 876 if self:get_affiliation(stanza.attr.from) ~= "owner" then |
| 942 origin.send(st.error_reply(stanza, "auth", "forbidden", "Only owners can configure rooms")); | 877 origin.send(st.error_reply(stanza, "auth", "forbidden", "Only owners can configure rooms")); |
| 943 elseif stanza.attr.type == "get" then | 878 elseif stanza.attr.type == "get" then |
| 1061 local bare = node and node.."@"..host or host; | 996 local bare = node and node.."@"..host or host; |
| 1062 local result = self._affiliations[bare]; -- Affiliations are granted, revoked, and maintained based on the user's bare JID. | 997 local result = self._affiliations[bare]; -- Affiliations are granted, revoked, and maintained based on the user's bare JID. |
| 1063 if not result and self._affiliations[host] == "outcast" then result = "outcast"; end -- host banned | 998 if not result and self._affiliations[host] == "outcast" then result = "outcast"; end -- host banned |
| 1064 return result; | 999 return result; |
| 1065 end | 1000 end |
| 1066 --- Checks whether the given affiliation changes in jid_affiliation can be applied by actor. | 1001 function room_mt:set_affiliation(actor, jid, affiliation, callback, reason) |
| 1067 -- Note: Empty tables can always be applied and won't have any effect. | 1002 jid = jid_bare(jid); |
| 1068 function room_mt:can_set_affiliations(actor, jid_affiliation) | 1003 if affiliation == "none" then affiliation = nil; end |
| 1069 local actor_affiliation; | 1004 if affiliation and affiliation ~= "outcast" and affiliation ~= "owner" and affiliation ~= "admin" and affiliation ~= "member" then |
| 1005 return nil, "modify", "not-acceptable"; | |
| 1006 end | |
| 1070 if actor ~= true then | 1007 if actor ~= true then |
| 1071 actor_affiliation = self:get_affiliation(actor); | 1008 local actor_affiliation = self:get_affiliation(actor); |
| 1072 end | |
| 1073 | |
| 1074 -- First let's see if there are any problems with the affiliations given | |
| 1075 -- in jid_affiliation | |
| 1076 for jid, value in pairs(jid_affiliation) do | |
| 1077 local affiliation = value["affiliation"]; | |
| 1078 | |
| 1079 if jid ~= jid_bare(jid) then | |
| 1080 return false, "modify", "not-acceptable"; | |
| 1081 end | |
| 1082 jid = jid_bare(jid); | |
| 1083 if affiliation == "none" then affiliation = nil; end | |
| 1084 if affiliation and affiliation ~= "outcast" and affiliation ~= "owner" and affiliation ~= "admin" and affiliation ~= "member" then | |
| 1085 return false, "modify", "not-acceptable"; | |
| 1086 end | |
| 1087 | |
| 1088 local target_affiliation = self:get_affiliation(jid); | 1009 local target_affiliation = self:get_affiliation(jid); |
| 1089 if target_affiliation == affiliation then | 1010 if target_affiliation == affiliation then -- no change, shortcut |
| 1090 -- no change, no error checking necessary | 1011 if callback then callback(); end |
| 1012 return true; | |
| 1013 end | |
| 1014 if actor_affiliation ~= "owner" then | |
| 1015 if affiliation == "owner" or affiliation == "admin" or actor_affiliation ~= "admin" or target_affiliation == "owner" or target_affiliation == "admin" then | |
| 1016 return nil, "cancel", "not-allowed"; | |
| 1017 end | |
| 1018 elseif target_affiliation == "owner" and jid_bare(actor) == jid then -- self change | |
| 1019 local is_last = true; | |
| 1020 for j, aff in pairs(self._affiliations) do if j ~= jid and aff == "owner" then is_last = false; break; end end | |
| 1021 if is_last then | |
| 1022 return nil, "cancel", "conflict"; | |
| 1023 end | |
| 1024 end | |
| 1025 end | |
| 1026 self._affiliations[jid] = affiliation; | |
| 1027 local role = self:get_default_role(affiliation); | |
| 1028 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}) | |
| 1029 :tag("item", {affiliation=affiliation or "none", role=role or "none"}) | |
| 1030 :tag("reason"):text(reason or ""):up() | |
| 1031 :up(); | |
| 1032 local presence_type = nil; | |
| 1033 if not role then -- getting kicked | |
| 1034 presence_type = "unavailable"; | |
| 1035 if affiliation == "outcast" then | |
| 1036 x:tag("status", {code="301"}):up(); -- banned | |
| 1091 else | 1037 else |
| 1092 if actor ~= true and actor_affiliation ~= "owner" then | 1038 x:tag("status", {code="321"}):up(); -- affiliation change |
| 1093 if affiliation == "owner" or affiliation == "admin" or actor_affiliation ~= "admin" or target_affiliation == "owner" or target_affiliation == "admin" then | 1039 end |
| 1094 return false, "cancel", "not-allowed"; | |
| 1095 end | |
| 1096 elseif target_affiliation == "owner" and jid_bare(actor) == jid then -- self change | |
| 1097 local is_last = true; | |
| 1098 for j, aff in pairs(self._affiliations) do if j ~= jid and aff == "owner" then is_last = false; break; end end | |
| 1099 if is_last then | |
| 1100 return false, "cancel", "conflict"; | |
| 1101 end | |
| 1102 end | |
| 1103 end | |
| 1104 end | |
| 1105 | |
| 1106 return true; | |
| 1107 end | |
| 1108 --- Updates the room affiliations by applying the ones given here. | |
| 1109 -- Takes the affiliations given in jid_affiliation and applies them to | |
| 1110 -- the room, overwriting a potentially existing affiliation for any given | |
| 1111 -- jid. | |
| 1112 -- @param jid_affiliation A table associating a jid with a table consisting | |
| 1113 -- of two subkeys: `affilation` and `reason`. The jids | |
| 1114 -- within must not be malformed. | |
| 1115 function room_mt:set_affiliations(actor, jid_affiliation, callback) | |
| 1116 local can_set, err_type, err_condition = self:can_set_affiliations(actor, jid_affiliation) | |
| 1117 | |
| 1118 if not can_set then | |
| 1119 return false, err_type, err_condition; | |
| 1120 end | 1040 end |
| 1121 -- Your own presence should have status 110 | 1041 -- Your own presence should have status 110 |
| 1042 local self_x = st.clone(x); | |
| 1043 self_x:tag("status", {code="110"}); | |
| 1122 local modified_nicks = {}; | 1044 local modified_nicks = {}; |
| 1123 local nb_modified_nicks = 0; | 1045 for nick, occupant in pairs(self._occupants) do |
| 1124 -- Now we can be sure that jid_affiliation causes no problems | 1046 if jid_bare(occupant.jid) == jid then |
| 1125 -- We can actually set them | 1047 if not role then -- getting kicked |
| 1126 for jid, value in pairs(jid_affiliation) do | 1048 self._occupants[nick] = nil; |
| 1127 local affiliation = value["affiliation"]; | |
| 1128 local reason = value["reason"]; | |
| 1129 | |
| 1130 self._affiliations[jid] = affiliation; | |
| 1131 local role = self:get_default_role(affiliation); | |
| 1132 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}) | |
| 1133 :tag("item", {affiliation=affiliation or "none", role=role or "none"}) | |
| 1134 :tag("reason"):text(reason or ""):up() | |
| 1135 :up(); | |
| 1136 local self_x = st.clone(x); | |
| 1137 self_x:tag("status", {code="110"}):up(); | |
| 1138 local presence_type = nil; | |
| 1139 if not role then -- getting kicked | |
| 1140 presence_type = "unavailable"; | |
| 1141 if affiliation == "outcast" then | |
| 1142 -- banned | |
| 1143 x:tag("status", {code="301"}):up(); | |
| 1144 self_x:tag("status", {code="301"}):up(); | |
| 1145 else | 1049 else |
| 1146 -- affiliation change | 1050 occupant.affiliation, occupant.role = affiliation, role; |
| 1147 x:tag("status", {code="321"}):up(); | 1051 end |
| 1148 self_x:tag("status", {code="321"}):up(); | 1052 for jid,pres in pairs(occupant.sessions) do -- remove for all sessions of the nick |
| 1149 end | 1053 if not role then self._jid_nick[jid] = nil; end |
| 1150 end | 1054 local p = st.clone(pres); |
| 1151 for nick, occupant in pairs(self._occupants) do | 1055 p.attr.from = nick; |
| 1152 if jid_bare(occupant.jid) == jid then | 1056 p.attr.type = presence_type; |
| 1153 if not role then -- getting kicked | 1057 p.attr.to = jid; |
| 1154 self._occupants[nick] = nil; | 1058 if occupant.jid == jid then |
| 1155 else | |
| 1156 occupant.affiliation, occupant.role = affiliation, role; | |
| 1157 end | |
| 1158 for jid,pres in pairs(occupant.sessions) do -- remove for all sessions of the nick | |
| 1159 if not role then self._jid_nick[jid] = nil; end | |
| 1160 local p = st.clone(pres); | |
| 1161 p.attr.from = nick; | |
| 1162 p.attr.type = presence_type; | |
| 1163 p.attr.to = jid; | |
| 1164 self:_route_stanza(p); | |
| 1165 if occupant.jid == jid then | |
| 1166 -- Broadcast this presence to everyone else later, with the public <x> variant | 1059 -- Broadcast this presence to everyone else later, with the public <x> variant |
| 1167 local bp = st.clone(p); | 1060 local bp = st.clone(p); |
| 1168 bp:add_child(x); | 1061 bp:add_child(x); |
| 1169 modified_nicks[nick] = bp; | 1062 modified_nicks[nick] = bp; |
| 1170 nb_modified_nicks = nb_modified_nicks + 1; | 1063 end |
| 1171 end | 1064 p:add_child(self_x); |
| 1172 p:add_child(self_x); | 1065 self:_route_stanza(p); |
| 1173 self:_route_stanza(p); | 1066 end |
| 1174 end | 1067 end |
| 1175 end | 1068 end |
| 1176 end | 1069 if self.save then self:save(); end |
| 1177 end | 1070 if callback then callback(); end |
| 1178 | |
| 1179 if nb_modified_nicks > 0 then | |
| 1180 if self.save then self:save(); end | |
| 1181 if callback then callback(); end | |
| 1182 end | |
| 1183 for nick,p in pairs(modified_nicks) do | 1071 for nick,p in pairs(modified_nicks) do |
| 1184 p.attr.from = nick; | 1072 p.attr.from = nick; |
| 1185 self:broadcast_except_nick(p, nick); | 1073 self:broadcast_except_nick(p, nick); |
| 1186 end | 1074 end |
| 1187 return true; | 1075 return true; |
| 1188 end | |
| 1189 function room_mt:set_affiliation(actor, jid, affiliation, callback, reason) | |
| 1190 return self.set_affiliations(actor, { [jid] = { ["affiliation"] = affiliation, ["reason"] = reason } }, callback) | |
| 1191 end | 1076 end |
| 1192 | 1077 |
| 1193 function room_mt:get_role(nick) | 1078 function room_mt:get_role(nick) |
| 1194 local session = self._occupants[nick]; | 1079 local session = self._occupants[nick]; |
| 1195 return session and session.role or nil; | 1080 return session and session.role or nil; |
| 1210 end | 1095 end |
| 1211 end | 1096 end |
| 1212 end | 1097 end |
| 1213 return nil, "cancel", "not-allowed"; | 1098 return nil, "cancel", "not-allowed"; |
| 1214 end | 1099 end |
| 1215 | 1100 function room_mt:set_role(actor, occupant_jid, role, callback, reason) |
| 1216 --- Checks whether the given role changes in jidnick_role can be applied by actor. | 1101 if role == "none" then role = nil; end |
| 1217 -- Note: Empty tables can always be applied and won't have any effect. | 1102 if role and role ~= "moderator" and role ~= "participant" and role ~= "visitor" then return nil, "modify", "not-acceptable"; end |
| 1218 function room_mt:can_set_roles(actor, jidnick_role) | 1103 local allowed, err_type, err_condition = self:can_set_role(actor, occupant_jid, role); |
| 1219 for jidnick, role_info in pairs(jidnick_role) do | |
| 1220 local role = role_info["role"]; | |
| 1221 if role == "none" then role = nil; end | |
| 1222 if role and role ~= "moderator" and role ~= "participant" and role ~= "visitor" then return false, "modify", "not-acceptable"; end | |
| 1223 local can_set, err_type, err_condition = self:can_set_role(actor, jidnick, role) | |
| 1224 if not can_set then | |
| 1225 return false, err_type, err_condition; | |
| 1226 end | |
| 1227 end | |
| 1228 | |
| 1229 return true; | |
| 1230 end | |
| 1231 | |
| 1232 --- Updates the room roles by applying the ones given here. | |
| 1233 -- Takes the roles given in jidnick_role and applies them to | |
| 1234 -- the room, overwriting a potentially existing role for any given | |
| 1235 -- jid. | |
| 1236 -- @param jidnick_role A table associating a jid/nick with a table consisting | |
| 1237 -- of two subkeys: `role` and `reason`. The jids within | |
| 1238 -- must not be malformed. | |
| 1239 function room_mt:set_roles(actor, jidnick_role, callback) | |
| 1240 local allowed, err_type, err_condition = self:can_set_roles(actor, jidnick_role); | |
| 1241 if not allowed then return allowed, err_type, err_condition; end | 1104 if not allowed then return allowed, err_type, err_condition; end |
| 1242 | 1105 local occupant = self._occupants[occupant_jid]; |
| 1243 local modified_nicks = {}; | 1106 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}) |
| 1244 local nb_modified_nicks = 0; | 1107 :tag("item", {affiliation=occupant.affiliation or "none", nick=select(3, jid_split(occupant_jid)), role=role or "none"}) |
| 1245 for jidnick, value in pairs(jidnick_role) do | 1108 :tag("reason"):text(reason or ""):up() |
| 1246 local occupant_jid = jidnick; | 1109 :up(); |
| 1247 local role = value["role"]; | 1110 local presence_type = nil; |
| 1248 local reason = value["reason"]; | 1111 if not role then -- kick |
| 1249 | 1112 presence_type = "unavailable"; |
| 1250 local occupant = self._occupants[occupant_jid]; | 1113 self._occupants[occupant_jid] = nil; |
| 1251 local x = st.stanza("x", {xmlns = "http://jabber.org/protocol/muc#user"}) | 1114 for jid in pairs(occupant.sessions) do -- remove for all sessions of the nick |
| 1252 :tag("item", {affiliation=occupant.affiliation or "none", nick=select(3, jid_split(occupant_jid)), role=role or "none"}) | 1115 self._jid_nick[jid] = nil; |
| 1253 :tag("reason"):text(reason or ""):up() | 1116 end |
| 1254 :up(); | 1117 x:tag("status", {code = "307"}):up(); |
| 1255 local presence_type = nil; | 1118 else |
| 1256 if not role or role == "none" then -- kick | 1119 occupant.role = role; |
| 1257 presence_type = "unavailable"; | 1120 end |
| 1258 self._occupants[occupant_jid] = nil; | 1121 local self_x = st.clone(x); |
| 1259 for jid in pairs(occupant.sessions) do -- remove for all sessions of the nick | 1122 self_x:tag("status", {code = "110"}):up(); |
| 1260 self._jid_nick[jid] = nil; | 1123 local bp; |
| 1261 end | 1124 for jid,pres in pairs(occupant.sessions) do -- send to all sessions of the nick |
| 1262 x:tag("status", {code = "307"}):up(); | 1125 local p = st.clone(pres); |
| 1263 else | 1126 p.attr.from = occupant_jid; |
| 1264 occupant.role = role; | 1127 p.attr.type = presence_type; |
| 1265 end | 1128 p.attr.to = jid; |
| 1266 local self_x = st.clone(x); | 1129 if occupant.jid == jid then |
| 1267 self_x:tag("status", {code = "110"}):up(); | 1130 bp = st.clone(p); |
| 1268 local bp; | 1131 bp:add_child(x); |
| 1269 for jid,pres in pairs(occupant.sessions) do -- send to all sessions of the nick | 1132 end |
| 1270 local p = st.clone(pres); | 1133 p:add_child(self_x); |
| 1271 p.attr.from = occupant_jid; | 1134 self:_route_stanza(p); |
| 1272 p.attr.type = presence_type; | 1135 end |
| 1273 p.attr.to = jid; | 1136 if callback then callback(); end |
| 1274 self:_route_stanza(p); | 1137 if bp then |
| 1275 if occupant.jid == jid then | 1138 self:broadcast_except_nick(bp, occupant_jid); |
| 1276 bp = st.clone(p); | |
| 1277 bp:add_child(x); | |
| 1278 modified_nicks[occupant_jid] = bp; | |
| 1279 nb_modified_nicks = nb_modified_nicks + 1; | |
| 1280 end | |
| 1281 p:add_child(self_x); | |
| 1282 self:route_stanza(p); | |
| 1283 end | |
| 1284 end | |
| 1285 | |
| 1286 if nb_modified_nicks > 0 then | |
| 1287 if callback then callback(); end | |
| 1288 end | |
| 1289 for nick,p in pairs(modified_nicks) do | |
| 1290 self:broadcast_except_nick(p, nick); | |
| 1291 end | 1139 end |
| 1292 return true; | 1140 return true; |
| 1293 end | 1141 end |
| 1294 | 1142 |
| 1295 function room_mt:_route_stanza(stanza) | 1143 function room_mt:_route_stanza(stanza) |
| 1309 end | 1157 end |
| 1310 if muc_child then | 1158 if muc_child then |
| 1311 for _, item in pairs(muc_child.tags) do | 1159 for _, item in pairs(muc_child.tags) do |
| 1312 if item.name == "item" then | 1160 if item.name == "item" then |
| 1313 if from_occupant == to_occupant then | 1161 if from_occupant == to_occupant then |
| 1314 item.attr.jid = jid_bare(stanza.attr.to); | 1162 item.attr.jid = stanza.attr.to; |
| 1315 else | 1163 else |
| 1316 item.attr.jid = jid_bare(from_occupant.jid); | 1164 item.attr.jid = from_occupant.jid; |
| 1317 end | 1165 end |
| 1318 end | 1166 end |
| 1319 end | 1167 end |
| 1320 end | 1168 end |
| 1321 self:route_stanza(stanza); | 1169 self:route_stanza(stanza); |
