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 |
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) |