plugins/muc/muc.lib.lua
changeset 6119 c13f5d6b9b16
parent 6118 aae3d6daa50d
child 6120 4520439227fc
equal deleted inserted replaced
6118:aae3d6daa50d 6119:c13f5d6b9b16
    67 
    67 
    68 function room_mt:__tostring()
    68 function room_mt:__tostring()
    69 	return "MUC room ("..self.jid..")";
    69 	return "MUC room ("..self.jid..")";
    70 end
    70 end
    71 
    71 
       
    72 function room_mt:get_occupant_jid(real_jid)
       
    73 	return self._jid_nick[real_jid]
       
    74 end
       
    75 
    72 function room_mt:get_default_role(affiliation)
    76 function room_mt:get_default_role(affiliation)
    73 	if affiliation == "owner" or affiliation == "admin" then
    77 	if affiliation == "owner" or affiliation == "admin" then
    74 		return "moderator";
    78 		return "moderator";
    75 	elseif affiliation == "member" then
    79 	elseif affiliation == "member" then
    76 		return "participant";
    80 		return "participant";
   132 		end
   136 		end
   133 	end
   137 	end
   134 end
   138 end
   135 
   139 
   136 function room_mt:send_occupant_list(to)
   140 function room_mt:send_occupant_list(to)
   137 	local current_nick = self._jid_nick[to];
   141 	local current_nick = self:get_occupant_jid(to);
   138 	for occupant, o_data in pairs(self._occupants) do
   142 	for occupant, o_data in pairs(self._occupants) do
   139 		if occupant ~= current_nick then
   143 		if occupant ~= current_nick then
   140 			local pres = get_filtered_presence(o_data.sessions[o_data.jid]);
   144 			local pres = get_filtered_presence(o_data.sessions[o_data.jid]);
   141 			pres.attr.to, pres.attr.from = to, occupant;
   145 			pres.attr.to, pres.attr.from = to, occupant;
   142 			pres:tag("x", {xmlns='http://jabber.org/protocol/muc#user'})
   146 			pres:tag("x", {xmlns='http://jabber.org/protocol/muc#user'})
   381 	return self._data.whois;
   385 	return self._data.whois;
   382 end
   386 end
   383 
   387 
   384 function room_mt:handle_unavailable_to_occupant(origin, stanza)
   388 function room_mt:handle_unavailable_to_occupant(origin, stanza)
   385 	local from = stanza.attr.from;
   389 	local from = stanza.attr.from;
   386 	local current_nick = self._jid_nick[from];
   390 	local current_nick = self:get_occupant_jid(from);
   387 	if not current_nick then
   391 	if not current_nick then
   388 		return true; -- discard
   392 		return true; -- discard
   389 	end
   393 	end
   390 	local pr = get_filtered_presence(stanza);
   394 	local pr = get_filtered_presence(stanza);
   391 	pr.attr.from = current_nick;
   395 	pr.attr.from = current_nick;
   512 	end
   516 	end
   513 end
   517 end
   514 
   518 
   515 function room_mt:handle_available_to_occupant(origin, stanza)
   519 function room_mt:handle_available_to_occupant(origin, stanza)
   516 	local from, to = stanza.attr.from, stanza.attr.to;
   520 	local from, to = stanza.attr.from, stanza.attr.to;
   517 	local current_nick = self._jid_nick[from];
   521 	local current_nick = self:get_occupant_jid(from);
   518 	if current_nick then
   522 	if current_nick then
   519 		--if #pr == #stanza or current_nick ~= to then -- commented because google keeps resending directed presence
   523 		--if #pr == #stanza or current_nick ~= to then -- commented because google keeps resending directed presence
   520 			if current_nick == to then -- simple presence
   524 			if current_nick == to then -- simple presence
   521 				return self:handle_occupant_presence(origin, stanza)
   525 				return self:handle_occupant_presence(origin, stanza)
   522 			else -- change nick
   526 			else -- change nick
   574 
   578 
   575 function room_mt:handle_iq_to_occupant(origin, stanza)
   579 function room_mt:handle_iq_to_occupant(origin, stanza)
   576 	local from, to = stanza.attr.from, stanza.attr.to;
   580 	local from, to = stanza.attr.from, stanza.attr.to;
   577 	local type = stanza.attr.type;
   581 	local type = stanza.attr.type;
   578 	local id = stanza.attr.id;
   582 	local id = stanza.attr.id;
   579 	local current_nick = self._jid_nick[from];
   583 	local current_nick = self:get_occupant_jid(from);
   580 	local o_data = self._occupants[to];
   584 	local o_data = self._occupants[to];
   581 	if (type == "error" or type == "result") then
   585 	if (type == "error" or type == "result") then
   582 		do -- deconstruct_stanza_id
   586 		do -- deconstruct_stanza_id
   583 			if not current_nick or not o_data then return nil; end
   587 			if not current_nick or not o_data then return nil; end
   584 			local from_jid, id, to_jid_hash = (base64.decode(stanza.attr.id) or ""):match("^(.+)%z(.*)%z(.+)$");
   588 			local from_jid, id, to_jid_hash = (base64.decode(stanza.attr.id) or ""):match("^(.+)%z(.*)%z(.+)$");
   620 	end
   624 	end
   621 end
   625 end
   622 
   626 
   623 function room_mt:handle_message_to_occupant(origin, stanza)
   627 function room_mt:handle_message_to_occupant(origin, stanza)
   624 	local from, to = stanza.attr.from, stanza.attr.to;
   628 	local from, to = stanza.attr.from, stanza.attr.to;
   625 	local current_nick = self._jid_nick[from];
   629 	local current_nick = self:get_occupant_jid(from);
   626 	local type = stanza.attr.type;
   630 	local type = stanza.attr.type;
   627 	if not current_nick then -- not in room
   631 	if not current_nick then -- not in room
   628 		if type ~= "error" then
   632 		if type ~= "error" then
   629 			origin.send(st.error_reply(stanza, "cancel", "not-acceptable"));
   633 			origin.send(st.error_reply(stanza, "cancel", "not-acceptable"));
   630 		end
   634 		end
   834 	end
   838 	end
   835 	if not item.attr.jid and item.attr.nick then -- COMPAT Workaround for Miranda sending 'nick' instead of 'jid' when changing affiliation
   839 	if not item.attr.jid and item.attr.nick then -- COMPAT Workaround for Miranda sending 'nick' instead of 'jid' when changing affiliation
   836 		local occupant = self._occupants[self.jid.."/"..item.attr.nick];
   840 		local occupant = self._occupants[self.jid.."/"..item.attr.nick];
   837 		if occupant then item.attr.jid = occupant.jid; end
   841 		if occupant then item.attr.jid = occupant.jid; end
   838 	elseif not item.attr.nick and item.attr.jid then
   842 	elseif not item.attr.nick and item.attr.jid then
   839 		local nick = self._jid_nick[item.attr.jid];
   843 		local nick = self:get_occupant_jid(item.attr.jid);
   840 		if nick then item.attr.nick = select(3, jid_split(nick)); end
   844 		if nick then item.attr.nick = select(3, jid_split(nick)); end
   841 	end
   845 	end
   842 	local actor = stanza.attr.from;
   846 	local actor = stanza.attr.from;
   843 	local callback = function() origin.send(st.reply(stanza)); end
   847 	local callback = function() origin.send(st.reply(stanza)); end
   844 	local reason = item:get_child_text("reason");
   848 	local reason = item:get_child_text("reason");
   857 end
   861 end
   858 
   862 
   859 function room_mt:handle_admin_item_get_command(origin, stanza)
   863 function room_mt:handle_admin_item_get_command(origin, stanza)
   860 	local actor = stanza.attr.from;
   864 	local actor = stanza.attr.from;
   861 	local affiliation = self:get_affiliation(actor);
   865 	local affiliation = self:get_affiliation(actor);
   862 	local current_nick = self._jid_nick[actor];
   866 	local current_nick = self:get_occupant_jid(actor);
   863 	local role = current_nick and self._occupants[current_nick].role or self:get_default_role(affiliation);
   867 	local role = current_nick and self._occupants[current_nick].role or self:get_default_role(affiliation);
   864 	local item = stanza.tags[1].tags[1];
   868 	local item = stanza.tags[1].tags[1];
   865 	local _aff = item.attr.affiliation;
   869 	local _aff = item.attr.affiliation;
   866 	local _rol = item.attr.role;
   870 	local _rol = item.attr.role;
   867 	if _aff and not _rol then
   871 	if _aff and not _rol then
   937 	end
   941 	end
   938 end
   942 end
   939 
   943 
   940 function room_mt:handle_groupchat_to_room(origin, stanza)
   944 function room_mt:handle_groupchat_to_room(origin, stanza)
   941 	local from = stanza.attr.from;
   945 	local from = stanza.attr.from;
   942 	local current_nick = self._jid_nick[from];
   946 	local current_nick = self:get_occupant_jid(from);
   943 	local occupant = self._occupants[current_nick];
   947 	local occupant = self._occupants[current_nick];
   944 	if not occupant then -- not in room
   948 	if not occupant then -- not in room
   945 		origin.send(st.error_reply(stanza, "cancel", "not-acceptable"));
   949 		origin.send(st.error_reply(stanza, "cancel", "not-acceptable"));
   946 		return true;
   950 		return true;
   947 	elseif occupant.role == "visitor" then
   951 	elseif occupant.role == "visitor" then
   967 	end
   971 	end
   968 end
   972 end
   969 
   973 
   970 -- hack - some buggy clients send presence updates to the room rather than their nick
   974 -- hack - some buggy clients send presence updates to the room rather than their nick
   971 function room_mt:handle_presence_to_room(origin, stanza)
   975 function room_mt:handle_presence_to_room(origin, stanza)
   972 	local current_nick = self._jid_nick[stanza.attr.from];
   976 	local current_nick = self:get_occupant_jid(stanza.attr.from);
   973 	local handled
   977 	local handled
   974 	if current_nick then
   978 	if current_nick then
   975 		local to = stanza.attr.to;
   979 		local to = stanza.attr.to;
   976 		stanza.attr.to = current_nick;
   980 		stanza.attr.to = current_nick;
   977 		handled = self:handle_presence_to_occupant(origin, stanza);
   981 		handled = self:handle_presence_to_occupant(origin, stanza);
   980 	return handled;
   984 	return handled;
   981 end
   985 end
   982 
   986 
   983 function room_mt:handle_mediated_invite(origin, stanza, payload)
   987 function room_mt:handle_mediated_invite(origin, stanza, payload)
   984 	local _from, _to = stanza.attr.from, stanza.attr.to;
   988 	local _from, _to = stanza.attr.from, stanza.attr.to;
   985 	if not self._jid_nick[_from] then -- Should be in room to send invite TODO: allow admins to send at any time
   989 	local current_nick = self:get_occupant_jid(_from)
       
   990 	if not current_nick then -- Should be in room to send invite TODO: allow admins to send at any time
   986 		origin.send(st.error_reply(stanza, "auth", "forbidden"));
   991 		origin.send(st.error_reply(stanza, "auth", "forbidden"));
   987 		return true;
   992 		return true;
   988 	end
   993 	end
   989 	local _invitee = jid_prep(payload.attr.to);
   994 	local _invitee = jid_prep(payload.attr.to);
   990 	if _invitee then
   995 	if _invitee then
  1005 			:tag('body') -- Add a plain message for clients which don't support invites
  1010 			:tag('body') -- Add a plain message for clients which don't support invites
  1006 				:text(_from..' invited you to the room '.._to..(_reason and (' ('.._reason..')') or ""))
  1011 				:text(_from..' invited you to the room '.._to..(_reason and (' ('.._reason..')') or ""))
  1007 			:up();
  1012 			:up();
  1008 		if self:get_members_only() and not self:get_affiliation(_invitee) then
  1013 		if self:get_members_only() and not self:get_affiliation(_invitee) then
  1009 			log("debug", "%s invited %s into members only room %s, granting membership", _from, _invitee, _to);
  1014 			log("debug", "%s invited %s into members only room %s, granting membership", _from, _invitee, _to);
  1010 			self:set_affiliation(_from, _invitee, "member", nil, "Invited by " .. self._jid_nick[_from])
  1015 			self:set_affiliation(_from, _invitee, "member", nil, "Invited by " .. current_nick)
  1011 		end
  1016 		end
  1012 		self:_route_stanza(invite);
  1017 		self:_route_stanza(invite);
  1013 		return true;
  1018 		return true;
  1014 	else
  1019 	else
  1015 		origin.send(st.error_reply(stanza, "cancel", "jid-malformed"));
  1020 		origin.send(st.error_reply(stanza, "cancel", "jid-malformed"));
  1155 	local occupant = self._occupants[occupant_jid];
  1160 	local occupant = self._occupants[occupant_jid];
  1156 	if not occupant or not actor_jid then return nil, "modify", "not-acceptable"; end
  1161 	if not occupant or not actor_jid then return nil, "modify", "not-acceptable"; end
  1157 
  1162 
  1158 	if actor_jid == true then return true; end
  1163 	if actor_jid == true then return true; end
  1159 
  1164 
  1160 	local actor = self._occupants[self._jid_nick[actor_jid]];
  1165 	local actor = self._occupants[self:get_occupant_jid(actor_jid)];
  1161 	if actor.role == "moderator" then
  1166 	if actor.role == "moderator" then
  1162 		if occupant.affiliation ~= "owner" and occupant.affiliation ~= "admin" then
  1167 		if occupant.affiliation ~= "owner" and occupant.affiliation ~= "admin" then
  1163 			if actor.affiliation == "owner" or actor.affiliation == "admin" then
  1168 			if actor.affiliation == "owner" or actor.affiliation == "admin" then
  1164 				return true;
  1169 				return true;
  1165 			elseif occupant.role ~= "moderator" and role ~= "moderator" then
  1170 			elseif occupant.role ~= "moderator" and role ~= "moderator" then
  1210 end
  1215 end
  1211 
  1216 
  1212 function room_mt:_route_stanza(stanza)
  1217 function room_mt:_route_stanza(stanza)
  1213 	local muc_child;
  1218 	local muc_child;
  1214 	if stanza.name == "presence" then
  1219 	if stanza.name == "presence" then
  1215 		local to_occupant = self._occupants[self._jid_nick[stanza.attr.to]];
  1220 		local to_occupant = self._occupants[self:get_occupant_jid(stanza.attr.to)];
  1216 		local from_occupant = self._occupants[stanza.attr.from];
  1221 		local from_occupant = self._occupants[stanza.attr.from];
  1217 		if to_occupant and from_occupant then
  1222 		if to_occupant and from_occupant then
  1218 			if self:get_whois() == 'anyone' then
  1223 			if self:get_whois() == 'anyone' then
  1219 			    muc_child = stanza:get_child("x", "http://jabber.org/protocol/muc#user");
  1224 			    muc_child = stanza:get_child("x", "http://jabber.org/protocol/muc#user");
  1220 			else
  1225 			else