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 { ...@@ -152,14 +152,24 @@ public interface MUCRoom extends Externalizable, Result {
MUCRole getRole(); 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>) * @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 * @return The user's role in the room
* @throws UserNotFoundException If there is no user with the given nickname * @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; 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, * 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. * one for each client resource from which the user has joined the room.
......
...@@ -247,7 +247,6 @@ public class IQAdminHandler { ...@@ -247,7 +247,6 @@ public class IQAdminHandler {
} }
else { else {
// The client is modifying the list of moderators/members/participants/outcasts // The client is modifying the list of moderators/members/participants/outcasts
JID jid;
String nick; String nick;
String target; String target;
boolean hasAffiliation = itemsList.get(0).attributeValue("affiliation") != boolean hasAffiliation = itemsList.get(0).attributeValue("affiliation") !=
...@@ -262,59 +261,66 @@ public class IQAdminHandler { ...@@ -262,59 +261,66 @@ public class IQAdminHandler {
item = (Element) anItem; item = (Element) anItem;
target = (hasAffiliation ? item.attributeValue("affiliation") : item target = (hasAffiliation ? item.attributeValue("affiliation") : item
.attributeValue("role")); .attributeValue("role"));
List<JID> jids = new ArrayList<JID>();
// jid could be of the form "full JID" or "bare JID" depending if we are // jid could be of the form "full JID" or "bare JID" depending if we are
// going to change a role or an affiliation // going to change a role or an affiliation
if (hasJID) { if (hasJID) {
jid = new JID(item.attributeValue("jid")); jids.add(new JID(item.attributeValue("jid")));
nick = null; nick = null;
} else { } else {
// Get the JID based on the requested nick // Get the JID based on the requested nick
nick = item.attributeValue("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)) { for (JID jid : jids) {
// Add the user as a moderator of the room based on the full JID if ("moderator".equals(target)) {
presences.add(room.addModerator(jid, senderRole)); // Add the user as a moderator of the room based on the full JID
} else if ("owner".equals(target)) { presences.add(room.addModerator(jid, senderRole));
presences.addAll(room.addOwner(jid, senderRole)); } else if ("owner".equals(target)) {
} else if ("admin".equals(target)) { presences.addAll(room.addOwner(jid, senderRole));
presences.addAll(room.addAdmin(jid, senderRole)); } else if ("admin".equals(target)) {
} else if ("participant".equals(target)) { presences.addAll(room.addAdmin(jid, senderRole));
// Add the user as a participant of the room based on the full JID } else if ("participant".equals(target)) {
presences.add(room.addParticipant(jid, // Add the user as a participant of the room based on the full JID
item.elementTextTrim("reason"), presences.add(room.addParticipant(jid,
senderRole)); item.elementTextTrim("reason"),
} else if ("visitor".equals(target)) { senderRole));
// Add the user as a visitor of the room based on the full JID } else if ("visitor".equals(target)) {
presences.add(room.addVisitor(jid, senderRole)); // Add the user as a visitor of the room based on the full JID
} else if ("member".equals(target)) { presences.add(room.addVisitor(jid, senderRole));
// Add the user as a member of the room based on the bare JID } else if ("member".equals(target)) {
boolean hadAffiliation = room.getAffiliation(jid) != MUCRole.Affiliation.none; // Add the user as a member of the room based on the bare JID
presences.addAll(room.addMember(jid, nick, senderRole)); boolean hadAffiliation = room.getAffiliation(jid) != MUCRole.Affiliation.none;
// If the user had an affiliation don't send an invitation. Otherwise presences.addAll(room.addMember(jid, nick, senderRole));
// send an invitation if the room is members-only and skipping invites // If the user had an affiliation don't send an invitation. Otherwise
// are not disabled system-wide xmpp.muc.skipInvite // send an invitation if the room is members-only and skipping invites
if (!skipInvite && !hadAffiliation && room.isMembersOnly()) { // are not disabled system-wide xmpp.muc.skipInvite
room.sendInvitation(jid, null, senderRole, null); 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();
} }
presences.add(room.kickOccupant(jid, senderRole.getUserAddress(), } else if ("outcast".equals(target)) {
item.elementTextTrim("reason"))); // 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) { catch (UserNotFoundException e) {
......
...@@ -237,15 +237,18 @@ public class IQOwnerHandler { ...@@ -237,15 +237,18 @@ public class IQOwnerHandler {
for (final Element item : itemsList) { for (final Element item : itemsList) {
try { try {
String affiliation = item.attributeValue("affiliation"); String affiliation = item.attributeValue("affiliation");
JID jid;
if (hasJID) { if (hasJID) {
jid = new JID(item.attributeValue("jid")); jids.put(new JID(item.attributeValue("jid")), affiliation);
} else { } else {
// Get the bare JID based on the requested nick // Get the bare JID based on the requested nick
nick = item.attributeValue("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) { catch (UserNotFoundException e) {
// Do nothing // Do nothing
......
...@@ -276,4 +276,48 @@ public class LocalMUCRole implements MUCRole { ...@@ -276,4 +276,48 @@ public class LocalMUCRole implements MUCRole {
ElementUtil.setProperty(extendedInformation, "x.item:affiliation", affiliation.toString()); ElementUtil.setProperty(extendedInformation, "x.item:affiliation", affiliation.toString());
ElementUtil.setProperty(extendedInformation, "x.item:role", role.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 { ...@@ -351,7 +351,7 @@ public class LocalMUCUser implements MUCUser {
sendErrorPacket(packet, PacketError.Condition.forbidden); sendErrorPacket(packet, PacketError.Condition.forbidden);
} }
catch (NotFoundException e) { catch (NotFoundException e) {
sendErrorPacket(packet, PacketError.Condition.item_not_found); sendErrorPacket(packet, PacketError.Condition.recipient_unavailable);
} }
catch (ConflictException e) { catch (ConflictException e) {
sendErrorPacket(packet, PacketError.Condition.conflict); sendErrorPacket(packet, PacketError.Condition.conflict);
...@@ -603,4 +603,29 @@ public class LocalMUCUser implements MUCUser { ...@@ -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 @@ ...@@ -21,7 +21,8 @@
org.jivesoftware.openfire.muc.MUCRoom, org.jivesoftware.openfire.muc.MUCRoom,
org.jivesoftware.util.ParamUtils, org.jivesoftware.util.ParamUtils,
java.net.URLEncoder, java.net.URLEncoder,
java.text.DateFormat" java.text.DateFormat,
java.util.List"
errorPage="error.jsp" errorPage="error.jsp"
%> %>
<%@ page import="org.jivesoftware.openfire.XMPPServer" %> <%@ page import="org.jivesoftware.openfire.XMPPServer" %>
...@@ -49,10 +50,12 @@ ...@@ -49,10 +50,12 @@
// Kick nick specified // Kick nick specified
if (kick != null) { if (kick != null) {
MUCRole role = room.getOccupant(nickName); List<MUCRole> roles = room.getOccupantsByNickname(nickName);
if (role != null) { if (roles != null && roles.size() > 0) {
try { 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 // Log the event
webManager.logEvent("kicked MUC occupant "+nickName+" from "+roomName, null); webManager.logEvent("kicked MUC occupant "+nickName+" from "+roomName, null);
// Done, so redirect // 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