Changeset

1742:1483a62d69bb

MUC: Owners can now modify roles and affiliations
author Waqas Hussain <waqas20@gmail.com>
date Mon, 07 Sep 2009 20:30:16 +0500
parents 1741:2919f3b985fc
children 1743:d00b144f4bcf
files plugins/muc/muc.lib.lua
diffstat 1 files changed, 104 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/plugins/muc/muc.lib.lua	Mon Sep 07 20:29:04 2009 +0500
+++ b/plugins/muc/muc.lib.lua	Mon Sep 07 20:30:16 2009 +0500
@@ -147,7 +147,16 @@
 		while #history > history_length do t_remove(history, 1) end
 	end
 end
-
+function room_mt:broadcast_except_nick(stanza, nick)
+	for nick, occupant in pairs(self._occupants) do
+		if nick ~= nick then
+			for jid in pairs(occupant.sessions) do
+				stanza.attr.to = jid;
+				self:route_stanza(stanza);
+			end
+		end
+	end
+end
 
 function room_mt:send_occupant_list(to)
 	local current_nick = self._jid_nick[to];
@@ -309,6 +318,26 @@
 		else
 			origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
 		end
+	elseif stanza.name == "iq" and type == "set" and stanza.tags[1].attr.xmlns == "http://jabber.org/protocol/muc#admin" then
+		local actor = stanza.attr.from;
+		local affiliation = self:get_affiliation(actor);
+		local current_nick = self._jid_nick[actor];
+		local role = current_nick and self._occupants[current_nick].role or self:get_default_role(affiliation);
+		local item = stanza.tags[1].tags[1];
+		if item and item.name == "item" then
+			local callback = function() origin.send(st.reply(stanza)); end
+			if item.attr.affiliation and item.attr.jid and not item.attr.role and not item.attr.nick then
+				local success, errtype, err = self:set_affiliation(actor, item.attr.jid, item.attr.affiliation, callback);
+				if not success then origin.send(st.error_reply(stanza, errtype, err)); end
+			elseif item.attr.role and item.attr.nick and not item.attr.affiliation and not item.attr.jid then
+				local success, errtype, err = self:set_role(actor, item.attr.nick, item.attr.role, callback);
+				if not success then origin.send(st.error_reply(stanza, errtype, err)); end
+			else
+				origin.send(st.error_reply(stanza, "cancel", "bad-request"));
+			end
+		else
+			origin.send(st.error_reply(stanza, "cancel", "bad-request"));
+		end
 	elseif stanza.name == "message" and type == "groupchat" then
 		local from, to = stanza.attr.from, stanza.attr.to;
 		local room = jid_bare(to);
@@ -369,14 +398,81 @@
 	if not result and self._affiliations[host] == "outcast" then result = "outcast"; end -- host banned
 	return result;
 end
+function room_mt:set_affiliation(actor, jid, affiliation, callback)
+	jid = jid_bare(jid);
+	if affiliation == "none" then affiliation = nil; end
+	if affiliation and affiliation ~= "outcast" and affiliation ~= "owner" and affiliation ~= "admin" and affiliation ~= "member" then
+		return nil, "modify", "not-acceptable";
+	end
+	if self:get_affiliation(actor) ~= "owner" then return nil, "cancel", "not-allowed"; end
+	if jid_bare(actor) == jid then return nil, "cancel", "not-allowed"; end
+	self._affiliations[jid] = affiliation;
+	local role = self:get_default_role(affiliation);
+	local p = st.presence({type = "unavailable"})
+		:tag("x", {xmlns = "http://jabber.org/protocol/muc#user"})
+			:tag("item", {affiliation=affiliation, role=role or "none"}):up();
+	local x = p.tags[1];
+	local item = x.tags[1];
+	if not role then -- getting kicked
+		if affiliation == "outcast" then
+			x:tag("status", {code="301"}):up(); -- banned
+		else
+			x:tag("status", {code="321"}):up(); -- affiliation change
+		end
+	end
+	local modified_nicks = {};
+	for nick, occupant in pairs(self._occupants) do
+		if jid_bare(occupant.jid) == jid then
+			if not role then -- getting kicked
+				self._occupants[nick] = nil;
+			else
+				t_insert(modified_nicks, nick);
+				occupant.affiliation, occupant.role = affiliation, role;
+			end
+			p.attr.from = nick;
+			for jid in pairs(occupant.sessions) do -- remove for all sessions of the nick
+				if not role then self._jid_nick[jid] = nil; end
+				p.attr.to = jid;
+				self:route_stanza(p);
+			end
+		end
+	end
+	if callback then callback(); end
+	for _, nick in ipairs(modified_nicks) do
+		p.attr.from = nick;
+		self:broadcast_except_nick(p, nick);
+	end
+	return true;
+end
 
-function room_mt:set_affiliation(jid, affiliation)
-	local node, host, resource = jid_split(jid);
-	local bare = node and node.."@"..host or host;
-	if affiliation == "none" then affiliation = nil; end
-	if affiliation and affiliation ~= "outcast" and affiliation ~= "owner" and affiliation ~= "admin" and affiliation ~= "member" then return false; end
-	self._affiliations[bare] = affiliation;
-	-- TODO set roles based on new affiliation
+function room_mt:get_role(nick)
+	local session = self._occupants[nick];
+	return session and session.role or nil;
+end
+function room_mt:set_role(actor, nick, role, callback)
+	if role and role ~= "moderator" and role ~= "participant" and role ~= "visitor" then return nil, "modify", "not-acceptable"; end
+	if self:get_affiliation(actor) ~= "owner" then return nil, "cancel", "not-allowed"; end
+	local occupant = self._occupants[nick];
+	if not occupant then return nil, "modify", "not-acceptable"; end
+	if jid_bare(actor) == occupant.jid then return nil, "cancel", "not-allowed"; end
+	local p = st.presence({from = nick, type = "unavailable"})
+		:tag("x", {xmlns = "http://jabber.org/protocol/muc#user"})
+			:tag("item", {affiliation=occupant.affiliation, nick=nick, role=role or "none"}):up();
+	if not role then -- kick
+		self._occupants[nick] = nil;
+		for jid in pairs(occupant.sessions) do -- remove for all sessions of the nick
+			self._jid_nick[jid] = nil;
+		end
+		p:tag("status", {code = "307"}):up();
+	else
+		occupant.role = role;
+	end
+	for jid in pairs(occupant.sessions) do -- send to all sessions of the nick
+		p.attr.to = jid;
+		self:route_stanza(p);
+	end
+	if callback then callback(); end
+	self:broadcast_except_nick(p, nick);
 	return true;
 end