Commit 79775981 authored by Tom Evans's avatar Tom Evans

OF-103: Allow multiple MUC connections per user/nickname

Fixes a long-standing issue with Openfire's MUC implementation. See
http://community.igniterealtime.org/thread/35355 for more information.
parent a0fba82c
......@@ -152,14 +152,24 @@ public interface MUCRoom extends Externalizable, Result {
MUCRole getRole();
/**
* Obtain the role of a given user by nickname.
* Obtain the first role of a given user by nickname.
*
* @param nickname The nickname of the user you'd like to obtain (cannot be <tt>null</tt>)
* @return The user's role in the room
* @throws UserNotFoundException If there is no user with the given nickname
* @deprecated Prefer {@link #getOccupantsByNickname(String)} instead (a user may be connected more than once)
*/
MUCRole getOccupant(String nickname) throws UserNotFoundException;
/**
* Obtain the roles of a given user by nickname. A user can be connected to a room more than once.
*
* @param nickname The nickname of the user you'd like to obtain (cannot be <tt>null</tt>)
* @return The user's role in the room
* @throws UserNotFoundException If there is no user with the given nickname
*/
List<MUCRole> getOccupantsByNickname(String nickname) throws UserNotFoundException;
/**
* Obtain the roles of a given user in the room by his bare JID. A user can have several roles,
* one for each client resource from which the user has joined the room.
......
......@@ -247,7 +247,6 @@ public class IQAdminHandler {
}
else {
// The client is modifying the list of moderators/members/participants/outcasts
JID jid;
String nick;
String target;
boolean hasAffiliation = itemsList.get(0).attributeValue("affiliation") !=
......@@ -262,59 +261,66 @@ public class IQAdminHandler {
item = (Element) anItem;
target = (hasAffiliation ? item.attributeValue("affiliation") : item
.attributeValue("role"));
List<JID> jids = new ArrayList<JID>();
// jid could be of the form "full JID" or "bare JID" depending if we are
// going to change a role or an affiliation
if (hasJID) {
jid = new JID(item.attributeValue("jid"));
jids.add(new JID(item.attributeValue("jid")));
nick = null;
} else {
// Get the JID based on the requested nick
nick = item.attributeValue("nick");
jid = room.getOccupant(nick).getUserAddress();
for (MUCRole role : room.getOccupantsByNickname(nick)) {
if (!jids.contains(role.getUserAddress())) {
jids.add(role.getUserAddress());
}
}
}
if ("moderator".equals(target)) {
// Add the user as a moderator of the room based on the full JID
presences.add(room.addModerator(jid, senderRole));
} else if ("owner".equals(target)) {
presences.addAll(room.addOwner(jid, senderRole));
} else if ("admin".equals(target)) {
presences.addAll(room.addAdmin(jid, senderRole));
} else if ("participant".equals(target)) {
// Add the user as a participant of the room based on the full JID
presences.add(room.addParticipant(jid,
item.elementTextTrim("reason"),
senderRole));
} else if ("visitor".equals(target)) {
// Add the user as a visitor of the room based on the full JID
presences.add(room.addVisitor(jid, senderRole));
} else if ("member".equals(target)) {
// Add the user as a member of the room based on the bare JID
boolean hadAffiliation = room.getAffiliation(jid) != MUCRole.Affiliation.none;
presences.addAll(room.addMember(jid, nick, senderRole));
// If the user had an affiliation don't send an invitation. Otherwise
// send an invitation if the room is members-only and skipping invites
// are not disabled system-wide xmpp.muc.skipInvite
if (!skipInvite && !hadAffiliation && room.isMembersOnly()) {
room.sendInvitation(jid, null, senderRole, null);
}
} else if ("outcast".equals(target)) {
// Add the user as an outcast of the room based on the bare JID
presences.addAll(room.addOutcast(jid, item.elementTextTrim("reason"), senderRole));
} else if ("none".equals(target)) {
if (hasAffiliation) {
// Set that this jid has a NONE affiliation based on the bare JID
presences.addAll(room.addNone(jid, senderRole));
} else {
// Kick the user from the room
if (MUCRole.Role.moderator != senderRole.getRole()) {
throw new ForbiddenException();
for (JID jid : jids) {
if ("moderator".equals(target)) {
// Add the user as a moderator of the room based on the full JID
presences.add(room.addModerator(jid, senderRole));
} else if ("owner".equals(target)) {
presences.addAll(room.addOwner(jid, senderRole));
} else if ("admin".equals(target)) {
presences.addAll(room.addAdmin(jid, senderRole));
} else if ("participant".equals(target)) {
// Add the user as a participant of the room based on the full JID
presences.add(room.addParticipant(jid,
item.elementTextTrim("reason"),
senderRole));
} else if ("visitor".equals(target)) {
// Add the user as a visitor of the room based on the full JID
presences.add(room.addVisitor(jid, senderRole));
} else if ("member".equals(target)) {
// Add the user as a member of the room based on the bare JID
boolean hadAffiliation = room.getAffiliation(jid) != MUCRole.Affiliation.none;
presences.addAll(room.addMember(jid, nick, senderRole));
// If the user had an affiliation don't send an invitation. Otherwise
// send an invitation if the room is members-only and skipping invites
// are not disabled system-wide xmpp.muc.skipInvite
if (!skipInvite && !hadAffiliation && room.isMembersOnly()) {
room.sendInvitation(jid, null, senderRole, null);
}
presences.add(room.kickOccupant(jid, senderRole.getUserAddress(),
item.elementTextTrim("reason")));
} else if ("outcast".equals(target)) {
// Add the user as an outcast of the room based on the bare JID
presences.addAll(room.addOutcast(jid, item.elementTextTrim("reason"), senderRole));
} else if ("none".equals(target)) {
if (hasAffiliation) {
// Set that this jid has a NONE affiliation based on the bare JID
presences.addAll(room.addNone(jid, senderRole));
} else {
// Kick the user from the room
if (MUCRole.Role.moderator != senderRole.getRole()) {
throw new ForbiddenException();
}
presences.add(room.kickOccupant(jid, senderRole.getUserAddress(),
item.elementTextTrim("reason")));
}
} else {
reply.setError(PacketError.Condition.bad_request);
}
} else {
reply.setError(PacketError.Condition.bad_request);
}
}
catch (UserNotFoundException e) {
......
......@@ -237,15 +237,18 @@ public class IQOwnerHandler {
for (final Element item : itemsList) {
try {
String affiliation = item.attributeValue("affiliation");
JID jid;
if (hasJID) {
jid = new JID(item.attributeValue("jid"));
jids.put(new JID(item.attributeValue("jid")), affiliation);
} else {
// Get the bare JID based on the requested nick
nick = item.attributeValue("nick");
jid = room.getOccupant(nick).getUserAddress();
for (MUCRole role : room.getOccupantsByNickname(nick)) {
JID jid = role.getUserAddress();
if (!jids.containsKey(jid)) {
jids.put(jid, affiliation);
}
}
}
jids.put(jid, affiliation);
}
catch (UserNotFoundException e) {
// Do nothing
......
......@@ -276,4 +276,48 @@ public class LocalMUCRole implements MUCRole {
ElementUtil.setProperty(extendedInformation, "x.item:affiliation", affiliation.toString());
ElementUtil.setProperty(extendedInformation, "x.item:role", role.toString());
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((nick == null) ? 0 : nick.hashCode());
result = prime * result + ((rJID == null) ? 0 : rJID.hashCode());
result = prime * result + ((room == null) ? 0 : room.hashCode());
result = prime * result + ((user == null) ? 0 : user.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LocalMUCRole other = (LocalMUCRole) obj;
if (nick == null) {
if (other.nick != null)
return false;
} else if (!nick.equals(other.nick))
return false;
if (rJID == null) {
if (other.rJID != null)
return false;
} else if (!rJID.equals(other.rJID))
return false;
if (room == null) {
if (other.room != null)
return false;
} else if (!room.equals(other.room))
return false;
if (user == null) {
if (other.user != null)
return false;
} else if (!user.equals(other.user))
return false;
return true;
}
}
\ No newline at end of file
......@@ -351,7 +351,7 @@ public class LocalMUCUser implements MUCUser {
sendErrorPacket(packet, PacketError.Condition.forbidden);
}
catch (NotFoundException e) {
sendErrorPacket(packet, PacketError.Condition.item_not_found);
sendErrorPacket(packet, PacketError.Condition.recipient_unavailable);
}
catch (ConflictException e) {
sendErrorPacket(packet, PacketError.Condition.conflict);
......@@ -603,4 +603,29 @@ public class LocalMUCUser implements MUCUser {
}
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((realjid == null) ? 0 : realjid.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LocalMUCUser other = (LocalMUCUser) obj;
if (realjid == null) {
if (other.realjid != null)
return false;
} else if (!realjid.equals(other.realjid))
return false;
return true;
}
}
\ No newline at end of file
......@@ -21,7 +21,8 @@
org.jivesoftware.openfire.muc.MUCRoom,
org.jivesoftware.util.ParamUtils,
java.net.URLEncoder,
java.text.DateFormat"
java.text.DateFormat,
java.util.List"
errorPage="error.jsp"
%>
<%@ page import="org.jivesoftware.openfire.XMPPServer" %>
......@@ -49,10 +50,12 @@
// Kick nick specified
if (kick != null) {
MUCRole role = room.getOccupant(nickName);
if (role != null) {
List<MUCRole> roles = room.getOccupantsByNickname(nickName);
if (roles != null && roles.size() > 0) {
try {
room.kickOccupant(role.getUserAddress(), XMPPServer.getInstance().createJID(webManager.getUser().getUsername(), null), "");
for (MUCRole role : roles) {
room.kickOccupant(role.getUserAddress(), XMPPServer.getInstance().createJID(webManager.getUser().getUsername(), null), "");
}
// Log the event
webManager.logEvent("kicked MUC occupant "+nickName+" from "+roomName, null);
// Done, so redirect
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment