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
...@@ -23,6 +23,7 @@ package org.jivesoftware.openfire.muc.spi; ...@@ -23,6 +23,7 @@ package org.jivesoftware.openfire.muc.spi;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectInput; import java.io.ObjectInput;
import java.io.ObjectOutput; import java.io.ObjectOutput;
import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
...@@ -31,7 +32,6 @@ import java.util.Iterator; ...@@ -31,7 +32,6 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
...@@ -109,17 +109,17 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -109,17 +109,17 @@ public class LocalMUCRoom implements MUCRoom {
/** /**
* The occupants of the room accessible by the occupants nickname. * The occupants of the room accessible by the occupants nickname.
*/ */
private Map<String,MUCRole> occupants = new ConcurrentHashMap<String, MUCRole>(); private Map<String, List<MUCRole>> occupantsByNickname = new ConcurrentHashMap<String, List<MUCRole>>();
/** /**
* The occupants of the room accessible by the occupants bare JID. * The occupants of the room accessible by the occupants bare JID.
*/ */
private ConcurrentMap<JID, List<MUCRole>> occupantsByBareJID = new ConcurrentHashMap<JID, List<MUCRole>>(); private Map<JID, List<MUCRole>> occupantsByBareJID = new ConcurrentHashMap<JID, List<MUCRole>>();
/** /**
* The occupants of the room accessible by the occupants full JID. * The occupants of the room accessible by the occupants full JID.
*/ */
private ConcurrentMap<JID, MUCRole> occupantsByFullJID = new ConcurrentHashMap<JID, MUCRole>(); private Map<JID, MUCRole> occupantsByFullJID = new ConcurrentHashMap<JID, MUCRole>();
/** /**
* The name of the room. * The name of the room.
...@@ -182,7 +182,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -182,7 +182,7 @@ public class LocalMUCRoom implements MUCRoom {
/** /**
* List of chatroom's members. The list contains only bare jid, mapped to a nickname. * List of chatroom's members. The list contains only bare jid, mapped to a nickname.
*/ */
private ConcurrentMap<JID, String> members = new ConcurrentHashMap<JID,String>(); private Map<JID, String> members = new ConcurrentHashMap<JID,String>();
/** /**
* List of chatroom's outcast. The list contains only bare jid of not allowed users. * List of chatroom's outcast. The list contains only bare jid of not allowed users.
...@@ -437,13 +437,27 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -437,13 +437,27 @@ public class LocalMUCRoom implements MUCRoom {
return role; return role;
} }
/**
* @deprecated Prefer {@link #getOccupantsByNickname(String)} (user can be connected more than once)
*/
public MUCRole getOccupant(String nickname) throws UserNotFoundException { public MUCRole getOccupant(String nickname) throws UserNotFoundException {
if (nickname == null) { if (nickname == null) {
throw new UserNotFoundException(); throw new UserNotFoundException();
} }
MUCRole role = occupants.get(nickname.toLowerCase()); List<MUCRole> roles = getOccupantsByNickname(nickname);
if (role != null) { if (roles != null && roles.size() > 0) {
return role; return roles.get(0);
}
throw new UserNotFoundException();
}
public List<MUCRole> getOccupantsByNickname(String nickname) throws UserNotFoundException {
if (nickname == null) {
throw new UserNotFoundException();
}
List<MUCRole> roles = occupantsByNickname.get(nickname.toLowerCase());
if (roles != null && roles.size() > 0) {
return roles;
} }
throw new UserNotFoundException(); throw new UserNotFoundException();
} }
...@@ -465,15 +479,15 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -465,15 +479,15 @@ public class LocalMUCRoom implements MUCRoom {
} }
public Collection<MUCRole> getOccupants() { public Collection<MUCRole> getOccupants() {
return Collections.unmodifiableCollection(occupants.values()); return Collections.unmodifiableCollection(occupantsByFullJID.values());
} }
public int getOccupantsCount() { public int getOccupantsCount() {
return occupants.size(); return occupantsByFullJID.size();
} }
public boolean hasOccupant(String nickname) { public boolean hasOccupant(String nickname) {
return occupants.containsKey(nickname.toLowerCase()); return occupantsByNickname.containsKey(nickname.toLowerCase());
} }
public String getReservedNickname(JID jid) { public String getReservedNickname(JID jid) {
...@@ -530,29 +544,10 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -530,29 +544,10 @@ public class LocalMUCRoom implements MUCRoom {
} }
} }
// Check if the nickname is already used in the room // Check if the nickname is already used in the room
if (occupants.containsKey(nickname.toLowerCase())) { if (occupantsByNickname.containsKey(nickname.toLowerCase())) {
if (occupants.get(nickname.toLowerCase()).getUserAddress().toBareJID().equals(bareJID.toBareJID())) { List<MUCRole> occupants = occupantsByNickname.get(nickname.toLowerCase());
// Nickname exists in room, and belongs to this user, pretend to kick the previous instance. MUCRole occupant = occupants.size() > 0 ? occupants.get(0) : null;
// The previous instance will see that they are disconnected, and the new instance will if (occupant != null && !occupant.getUserAddress().toBareJID().equals(bareJID.toBareJID())) {
// "take over" the previous role. Participants in the room shouldn't notice anything
// has occurred.
String reason = "Your account signed into this chatroom with the same nickname from another location.";
Presence updatedPresence = new Presence(Presence.Type.unavailable);
updatedPresence.setFrom(occupants.get(nickname.toLowerCase()).getRoleAddress());
updatedPresence.setTo(occupants.get(nickname.toLowerCase()).getUserAddress());
Element frag = updatedPresence.addChildElement(
"x", "http://jabber.org/protocol/muc#user");
// Set the person who performed the kick ("you" effectively)
frag.addElement("item").addElement("actor").setText(user.getAddress().toString());
// Add the reason why the user was kicked
frag.element("item").addElement("reason").setText(reason);
// Add the status code 307 that indicates that the user was kicked
frag.addElement("status").addAttribute("code", "307");
router.route(updatedPresence);
}
else {
// Nickname is already used, and not by the same JID // Nickname is already used, and not by the same JID
throw new UserAlreadyExistsException(); throw new UserAlreadyExistsException();
} }
...@@ -566,14 +561,14 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -566,14 +561,14 @@ public class LocalMUCRoom implements MUCRoom {
} }
// If another user attempts to join the room with a nickname reserved by the first user // If another user attempts to join the room with a nickname reserved by the first user
// raise a ConflictException // raise a ConflictException
if (members.containsValue(nickname)) { if (members.containsValue(nickname.toLowerCase())) {
if (!nickname.equals(members.get(bareJID))) { if (!nickname.toLowerCase().equals(members.get(bareJID))) {
throw new ConflictException(); throw new ConflictException();
} }
} }
if (isLoginRestrictedToNickname()) { if (isLoginRestrictedToNickname()) {
String reservedNickname = members.get(bareJID); String reservedNickname = members.get(bareJID);
if (reservedNickname != null && !nickname.equals(reservedNickname)) { if (reservedNickname != null && !nickname.toLowerCase().equals(reservedNickname)) {
throw new NotAcceptableException(); throw new NotAcceptableException();
} }
} }
...@@ -619,7 +614,12 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -619,7 +614,12 @@ public class LocalMUCRoom implements MUCRoom {
// Create a new role for this user in this room // Create a new role for this user in this room
joinRole = new LocalMUCRole(mucService, this, nickname, role, affiliation, user, presence, router); joinRole = new LocalMUCRole(mucService, this, nickname, role, affiliation, user, presence, router);
// Add the new user as an occupant of this room // Add the new user as an occupant of this room
occupants.put(nickname.toLowerCase(), joinRole); List<MUCRole> occupants = occupantsByNickname.get(nickname.toLowerCase());
if (occupants == null) {
occupants = new ArrayList<MUCRole>();
occupantsByNickname.put(nickname.toLowerCase(), occupants);
}
occupants.add(joinRole);
// Update the tables of occupants based on the bare and full JID // Update the tables of occupants based on the bare and full JID
List<MUCRole> list = occupantsByBareJID.get(bareJID); List<MUCRole> list = occupantsByBareJID.get(bareJID);
if (list == null) { if (list == null) {
...@@ -650,44 +650,13 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -650,44 +650,13 @@ public class LocalMUCRoom implements MUCRoom {
} }
// If the room has just been created send the "room locked until configuration is // If the room has just been created send the "room locked until configuration is
// confirmed" message // confirmed" message
if (isRoomNew) { if (isLocked()) {
// Nothing in XEP-0045 says, that a message must be sent upon entering a room.
// Instead, only MUC status code 201 MUST be included in the initial presence.
// Message message = new Message();
// message.setType(Message.Type.groupchat);
// message.setBody(LocaleUtils.getLocalizedString("muc.new"));
// message.setFrom(role.getRoleAddress());
// joinRole.send(message);
}
else if (isLocked()) {
// http://xmpp.org/extensions/xep-0045.html#enter-locked // http://xmpp.org/extensions/xep-0045.html#enter-locked
Presence presenceItemNotFound = new Presence(Presence.Type.error); Presence presenceItemNotFound = new Presence(Presence.Type.error);
presenceItemNotFound.setError(PacketError.Condition.item_not_found); presenceItemNotFound.setError(PacketError.Condition.item_not_found);
presenceItemNotFound.setFrom(role.getRoleAddress()); presenceItemNotFound.setFrom(role.getRoleAddress());
joinRole.send(presenceItemNotFound); joinRole.send(presenceItemNotFound);
// // Warn the owner that the room is locked but it's not new
// Message message = new Message();
// message.setType(Message.Type.groupchat);
// message.setBody(LocaleUtils.getLocalizedString("muc.locked"));
// message.setFrom(role.getRoleAddress());
// joinRole.send(message);
}
else if (canAnyoneDiscoverJID()) {
// Warn the new occupant that the room is non-anonymous (i.e. his JID will be
// public)
// The following warning should not be sent as message, but instead as status code 100 in presence.
// XEP-0045: Example 26.
// If the user is entering a room that is non-anonymous (i.e., which informs all occupants of each occupant's full JID as shown above), the service MUST warn the user by including a status code of "100" in the initial presence that the room sends to the new occupant
// Message message = new Message();
// message.setType(Message.Type.groupchat);
// message.setBody(LocaleUtils.getLocalizedString("muc.warnnonanonymous"));
// message.setFrom(role.getRoleAddress());
// Element frag = message.addChildElement("x", "http://jabber.org/protocol/muc#user");
// frag.addElement("status").addAttribute("code", "100");
// joinRole.send(message);
} }
if (historyRequest == null) { if (historyRequest == null) {
Iterator<Message> history = roomHistory.getMessageHistory(); Iterator<Message> history = roomHistory.getMessageHistory();
...@@ -732,7 +701,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -732,7 +701,7 @@ public class LocalMUCRoom implements MUCRoom {
* @param joinRole the role of the new occupant in the room. * @param joinRole the role of the new occupant in the room.
*/ */
private void sendInitialPresences(LocalMUCRole joinRole) { private void sendInitialPresences(LocalMUCRole joinRole) {
for (MUCRole occupant : occupants.values()) { for (MUCRole occupant : occupantsByFullJID.values()) {
if (occupant == joinRole) { if (occupant == joinRole) {
continue; continue;
} }
...@@ -759,17 +728,28 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -759,17 +728,28 @@ public class LocalMUCRoom implements MUCRoom {
} }
public void occupantAdded(OccupantAddedEvent event) { public void occupantAdded(OccupantAddedEvent event) {
// Do not add new occupant with one with same nickname already exists
if (occupants.containsKey(event.getNickname().toLowerCase())) {
// TODO Handle conflict of nicknames
return;
}
// Create a proxy for the occupant that joined the room from another cluster node // Create a proxy for the occupant that joined the room from another cluster node
RemoteMUCRole joinRole = new RemoteMUCRole(mucService, event); RemoteMUCRole joinRole = new RemoteMUCRole(mucService, event);
JID bareJID = event.getUserAddress().asBareJID();
String nickname = event.getNickname();
List<MUCRole> occupants = occupantsByNickname.get(nickname.toLowerCase());
// Do not add new occupant with one with same nickname already exists
if (occupants == null) {
occupants = new ArrayList<MUCRole>();
occupantsByNickname.put(nickname.toLowerCase(), occupants);
} else {
// sanity check; make sure the nickname is owned by the same JID
if (occupants.size() > 0) {
String existingJID = occupants.get(0).getUserAddress().toBareJID();
if (!bareJID.equals(existingJID)) {
Log.warn(MessageFormat.format("Conflict detected; {0} requested nickname '{1}'; already being used by {2}", bareJID, nickname, existingJID));
return;
}
}
}
// Add the new user as an occupant of this room // Add the new user as an occupant of this room
occupants.put(event.getNickname().toLowerCase(), joinRole); occupants.add(joinRole);
// Update the tables of occupants based on the bare and full JID // Update the tables of occupants based on the bare and full JID
JID bareJID = event.getUserAddress().asBareJID();
List<MUCRole> list = occupantsByBareJID.get(bareJID); List<MUCRole> list = occupantsByBareJID.get(bareJID);
if (list == null) { if (list == null) {
list = new ArrayList<MUCRole>(); list = new ArrayList<MUCRole>();
...@@ -786,7 +766,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -786,7 +766,7 @@ public class LocalMUCRoom implements MUCRoom {
} }
// Check if we need to send presences of the new occupant to occupants hosted by this JVM // Check if we need to send presences of the new occupant to occupants hosted by this JVM
if (event.isSendPresence()) { if (event.isSendPresence()) {
for (MUCRole occupant : occupants.values()) { for (MUCRole occupant : occupantsByFullJID.values()) {
if (occupant.isLocal()) { if (occupant.isLocal()) {
occupant.send(event.getPresence().createCopy()); occupant.send(event.getPresence().createCopy());
} }
...@@ -858,7 +838,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -858,7 +838,7 @@ public class LocalMUCRoom implements MUCRoom {
// Remove the room from the service only if there are no more occupants and the room is // Remove the room from the service only if there are no more occupants and the room is
// not persistent // not persistent
if (occupants.isEmpty() && !isPersistent()) { if (occupantsByFullJID.isEmpty() && !isPersistent()) {
endTime = System.currentTimeMillis(); endTime = System.currentTimeMillis();
if (event.isOriginator()) { if (event.isOriginator()) {
mucService.removeChatRoom(name); mucService.removeChatRoom(name);
...@@ -866,7 +846,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -866,7 +846,7 @@ public class LocalMUCRoom implements MUCRoom {
MUCEventDispatcher.roomDestroyed(getRole().getRoleAddress()); MUCEventDispatcher.roomDestroyed(getRole().getRoleAddress());
} }
} }
if (occupants.isEmpty()) { if (occupantsByFullJID.isEmpty()) {
// Update the date when the last occupant left the room // Update the date when the last occupant left the room
setEmptyDate(new Date()); setEmptyDate(new Date());
} }
...@@ -884,14 +864,21 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -884,14 +864,21 @@ public class LocalMUCRoom implements MUCRoom {
* @param originator true if this JVM is the one that originated the event. * @param originator true if this JVM is the one that originated the event.
*/ */
private void removeOccupantRole(MUCRole leaveRole, boolean originator) { private void removeOccupantRole(MUCRole leaveRole, boolean originator) {
occupants.remove(leaveRole.getNickname().toLowerCase());
JID userAddress = leaveRole.getUserAddress(); JID userAddress = leaveRole.getUserAddress();
// Notify the user that he/she is no longer in the room // Notify the user that he/she is no longer in the room
leaveRole.destroy(); leaveRole.destroy();
// Update the tables of occupants based on the bare and full JID // Update the tables of occupants based on the bare and full JID
JID bareJID = userAddress.asBareJID(); JID bareJID = userAddress.asBareJID();
List<MUCRole> list = occupantsByBareJID.get(bareJID);
String nickname = leaveRole.getNickname();
List<MUCRole> occupants = occupantsByNickname.get(nickname.toLowerCase());
if (occupants != null) {
occupants.remove(leaveRole);
if (occupants.isEmpty()) {
occupantsByNickname.remove(nickname.toLowerCase());
}
}
List<MUCRole> list = occupantsByBareJID.get(bareJID);
if (list != null) { if (list != null) {
list.remove(leaveRole); list.remove(leaveRole);
if (list.isEmpty()) { if (list.isEmpty()) {
...@@ -908,14 +895,12 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -908,14 +895,12 @@ public class LocalMUCRoom implements MUCRoom {
public void destroyRoom(DestroyRoomRequest destroyRequest) { public void destroyRoom(DestroyRoomRequest destroyRequest) {
JID alternateJID = destroyRequest.getAlternateJID(); JID alternateJID = destroyRequest.getAlternateJID();
String reason = destroyRequest.getReason(); String reason = destroyRequest.getReason();
MUCRole leaveRole;
Collection<MUCRole> removedRoles = new ArrayList<MUCRole>(); Collection<MUCRole> removedRoles = new ArrayList<MUCRole>();
lock.writeLock().lock(); lock.writeLock().lock();
try { try {
boolean hasRemoteOccupants = false; boolean hasRemoteOccupants = false;
// Remove each occupant // Remove each occupant
for (String nickname: occupants.keySet()) { for (MUCRole leaveRole : occupantsByFullJID.values()) {
leaveRole = occupants.remove(nickname);
if (leaveRole != null) { if (leaveRole != null) {
// Add the removed occupant to the list of removed occupants. We are keeping a // Add the removed occupant to the list of removed occupants. We are keeping a
...@@ -1010,15 +995,18 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1010,15 +995,18 @@ public class LocalMUCRoom implements MUCRoom {
// Send the message to all occupants // Send the message to all occupants
message.setFrom(senderRole.getRoleAddress()); message.setFrom(senderRole.getRoleAddress());
send(message); send(message);
// Fire event that message was receibed by the room // Fire event that message was received by the room
MUCEventDispatcher.messageReceived(getRole().getRoleAddress(), senderRole.getUserAddress(), MUCEventDispatcher.messageReceived(getRole().getRoleAddress(), senderRole.getUserAddress(),
senderRole.getNickname(), message); senderRole.getNickname(), message);
} }
public void sendPrivatePacket(Packet packet, MUCRole senderRole) throws NotFoundException { public void sendPrivatePacket(Packet packet, MUCRole senderRole) throws NotFoundException {
String resource = packet.getTo().getResource(); String resource = packet.getTo().getResource();
MUCRole occupant = occupants.get(resource.toLowerCase()); List<MUCRole> occupants = occupantsByNickname.get(resource.toLowerCase());
if (occupant != null) { if (occupants == null || occupants.size() == 0) {
throw new NotFoundException();
}
for (MUCRole occupant : occupants) {
packet.setFrom(senderRole.getRoleAddress()); packet.setFrom(senderRole.getRoleAddress());
occupant.send(packet); occupant.send(packet);
if(packet instanceof Message) { if(packet instanceof Message) {
...@@ -1027,9 +1015,6 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1027,9 +1015,6 @@ public class LocalMUCRoom implements MUCRoom {
message); message);
} }
} }
else {
throw new NotFoundException();
}
} }
public void send(Packet packet) { public void send(Packet packet) {
...@@ -1083,8 +1068,9 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1083,8 +1068,9 @@ public class LocalMUCRoom implements MUCRoom {
if (!shouldBroadcastPresence(presence)) { if (!shouldBroadcastPresence(presence)) {
// Just send the presence to the sender of the presence // Just send the presence to the sender of the presence
try { try {
MUCRole occupant = getOccupant(presence.getFrom().getResource()); for (MUCRole occupant : getOccupantsByNickname(presence.getFrom().getResource())) {
occupant.send(presence); occupant.send(presence);
}
} }
catch (UserNotFoundException e) { catch (UserNotFoundException e) {
// Do nothing // Do nothing
...@@ -1111,7 +1097,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1111,7 +1097,7 @@ public class LocalMUCRoom implements MUCRoom {
if (!canAnyoneDiscoverJID()) { if (!canAnyoneDiscoverJID()) {
jid = frag.element("item").attributeValue("jid"); jid = frag.element("item").attributeValue("jid");
} }
for (MUCRole occupant : occupants.values()) { for (MUCRole occupant : occupantsByFullJID.values()) {
if (!occupant.isLocal()) { if (!occupant.isLocal()) {
continue; continue;
} }
...@@ -1154,11 +1140,11 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1154,11 +1140,11 @@ public class LocalMUCRoom implements MUCRoom {
private void broadcast(Message message) { private void broadcast(Message message) {
// Broadcast message to occupants hosted by other cluster nodes // Broadcast message to occupants hosted by other cluster nodes
BroadcastMessageRequest request = new BroadcastMessageRequest(this, message, occupants.size()); BroadcastMessageRequest request = new BroadcastMessageRequest(this, message, occupantsByFullJID.size());
CacheFactory.doClusterTask(request); CacheFactory.doClusterTask(request);
// Broadcast message to occupants connected to this JVM // Broadcast message to occupants connected to this JVM
request = new BroadcastMessageRequest(this, message, occupants.size()); request = new BroadcastMessageRequest(this, message, occupantsByFullJID.size());
request.setOriginator(true); request.setOriginator(true);
request.run(); request.run();
} }
...@@ -1168,7 +1154,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1168,7 +1154,7 @@ public class LocalMUCRoom implements MUCRoom {
// Add message to the room history // Add message to the room history
roomHistory.addMessage(message); roomHistory.addMessage(message);
// Send message to occupants connected to this JVM // Send message to occupants connected to this JVM
for (MUCRole occupant : occupants.values()) { for (MUCRole occupant : occupantsByFullJID.values()) {
// Do not send broadcast messages to deaf occupants or occupants hosted in // Do not send broadcast messages to deaf occupants or occupants hosted in
// other cluster nodes // other cluster nodes
if (occupant.isLocal() && !occupant.isVoiceOnly()) { if (occupant.isLocal() && !occupant.isVoiceOnly()) {
...@@ -1179,7 +1165,9 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1179,7 +1165,9 @@ public class LocalMUCRoom implements MUCRoom {
MUCRole senderRole = null; MUCRole senderRole = null;
JID senderAddress; JID senderAddress;
if (message.getFrom() != null && message.getFrom().getResource() != null) { if (message.getFrom() != null && message.getFrom().getResource() != null) {
senderRole = occupants.get(message.getFrom().getResource().toLowerCase()); // get the first MUCRole for the sender
List<MUCRole> occupants = occupantsByNickname.get(message.getFrom().getResource().toLowerCase());
senderRole = occupants == null ? null : occupants.get(0);
} }
if (senderRole == null) { if (senderRole == null) {
// The room itself is sending the message // The room itself is sending the message
...@@ -1304,7 +1292,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1304,7 +1292,7 @@ public class LocalMUCRoom implements MUCRoom {
if (role.isLocal()) { if (role.isLocal()) {
role.setAffiliation(newAffiliation); role.setAffiliation(newAffiliation);
role.setRole(newRole); role.setRole(newRole);
// Notify the othe cluster nodes to update the occupant // Notify the other cluster nodes to update the occupant
CacheFactory.doClusterTask(new UpdateOccupant(this, role)); CacheFactory.doClusterTask(new UpdateOccupant(this, role));
// Prepare a new presence to be sent to all the room occupants // Prepare a new presence to be sent to all the room occupants
presences.add(role.getPresence().createCopy()); presences.add(role.getPresence().createCopy());
...@@ -1344,7 +1332,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1344,7 +1332,7 @@ public class LocalMUCRoom implements MUCRoom {
if (role.isLocal()) { if (role.isLocal()) {
// Update the presence with the new role // Update the presence with the new role
role.setRole(newRole); role.setRole(newRole);
// Notify the othe cluster nodes to update the occupant // Notify the other cluster nodes to update the occupant
CacheFactory.doClusterTask(new UpdateOccupant(this, role)); CacheFactory.doClusterTask(new UpdateOccupant(this, role));
// Prepare a new presence to be sent to all the room occupants // Prepare a new presence to be sent to all the room occupants
return role.getPresence().createCopy(); return role.getPresence().createCopy();
...@@ -1502,7 +1490,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1502,7 +1490,7 @@ public class LocalMUCRoom implements MUCRoom {
} }
} }
// Check if the desired nickname is already reserved for another member // Check if the desired nickname is already reserved for another member
if (nickname != null && nickname.trim().length() > 0 && members.containsValue(nickname)) { if (nickname != null && nickname.trim().length() > 0 && members.containsValue(nickname.toLowerCase())) {
if (!nickname.equals(members.get(bareJID))) { if (!nickname.equals(members.get(bareJID))) {
throw new ConflictException(); throw new ConflictException();
} }
...@@ -1513,7 +1501,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1513,7 +1501,7 @@ public class LocalMUCRoom implements MUCRoom {
} }
// Associate the reserved nickname with the bareJID. If nickname is null then associate an // Associate the reserved nickname with the bareJID. If nickname is null then associate an
// empty string // empty string
members.put(bareJID, (nickname == null ? "" : nickname)); members.put(bareJID, (nickname == null ? "" : nickname.toLowerCase()));
// Remove the user from other affiliation lists // Remove the user from other affiliation lists
if (removeOwner(bareJID)) { if (removeOwner(bareJID)) {
oldAffiliation = MUCRole.Affiliation.owner; oldAffiliation = MUCRole.Affiliation.owner;
...@@ -1735,54 +1723,59 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1735,54 +1723,59 @@ public class LocalMUCRoom implements MUCRoom {
* @param updatePresence request to update an occupant's presence. * @param updatePresence request to update an occupant's presence.
*/ */
public void presenceUpdated(UpdatePresence updatePresence) { public void presenceUpdated(UpdatePresence updatePresence) {
MUCRole occupantRole = occupants.get(updatePresence.getNickname().toLowerCase()); List <MUCRole> occupants = occupantsByNickname.get(updatePresence.getNickname().toLowerCase());
if (occupantRole != null) { if (occupants == null || occupants.size() == 0) {
occupantRole.setPresence(updatePresence.getPresence());
}
else {
Log.debug("LocalMUCRoom: Failed to update presence of room occupant. Occupant nickname: " + updatePresence.getNickname()); Log.debug("LocalMUCRoom: Failed to update presence of room occupant. Occupant nickname: " + updatePresence.getNickname());
} } else {
for (MUCRole occupant : occupants) {
occupant.setPresence(updatePresence.getPresence());
}
}
} }
public void occupantUpdated(UpdateOccupant update) { public void occupantUpdated(UpdateOccupant update) {
MUCRole occupantRole = occupants.get(update.getNickname().toLowerCase()); List <MUCRole> occupants = occupantsByNickname.get(update.getNickname().toLowerCase());
if (occupantRole != null) { if (occupants == null || occupants.size() == 0) {
if (!occupantRole.isLocal()) { Log.debug("LocalMUCRoom: Failed to update information of room occupant. Occupant nickname: " + update.getNickname());
occupantRole.setPresence(update.getPresence()); } else {
try { for (MUCRole occupant : occupants) {
occupantRole.setRole(update.getRole()); if (!occupant.isLocal()) {
occupantRole.setAffiliation(update.getAffiliation()); occupant.setPresence(update.getPresence());
} catch (NotAllowedException e) { try {
// Ignore. Should never happen with remote roles occupant.setRole(update.getRole());
occupant.setAffiliation(update.getAffiliation());
} catch (NotAllowedException e) {
// Ignore. Should never happen with remote roles
}
}
else {
Log.error(MessageFormat.format("Ignoring update of local occupant with info from a remote occupant. "
+ "Occupant nickname: {0} new role: {1} new affiliation: {2}",
update.getNickname(), update.getRole(), update.getAffiliation()));
} }
} }
else { }
Log.error("Tried to update local occupant with info of local occupant?. Occupant nickname: " +
update.getNickname() + " new role: " + update.getRole() + " new affiliation: " +
update.getAffiliation());
}
}
else {
Log.debug("LocalMUCRoom: Failed to update information of room occupant. Occupant nickname: " + update.getNickname());
}
} }
public Presence updateOccupant(UpdateOccupantRequest updateRequest) throws NotAllowedException { public Presence updateOccupant(UpdateOccupantRequest updateRequest) throws NotAllowedException {
MUCRole occupantRole = occupants.get(updateRequest.getNickname().toLowerCase()); Presence result = null;
if (occupantRole != null) { List <MUCRole> occupants = occupantsByNickname.get(updateRequest.getNickname().toLowerCase());
if (updateRequest.isAffiliationChanged()) { if (occupants == null || occupants.size() == 0) {
occupantRole.setAffiliation(updateRequest.getAffiliation()); Log.debug("Failed to update information of local room occupant; nickname: " + updateRequest.getNickname());
} } else {
occupantRole.setRole(updateRequest.getRole()); for (MUCRole occupant : occupants) {
// Notify the othe cluster nodes to update the occupant if (updateRequest.isAffiliationChanged()) {
CacheFactory.doClusterTask(new UpdateOccupant(this, occupantRole)); occupant.setAffiliation(updateRequest.getAffiliation());
return occupantRole.getPresence(); }
} occupant.setRole(updateRequest.getRole());
else { // Notify the the cluster nodes to update the occupant
Log.debug("LocalMUCRoom: Failed to update information of local room occupant. Occupant nickname: " + CacheFactory.doClusterTask(new UpdateOccupant(this, occupant));
updateRequest.getNickname()); if (result == null) {
} result = occupant.getPresence();
return null; }
}
}
return result;
} }
public void memberAdded(AddMember addMember) { public void memberAdded(AddMember addMember) {
...@@ -1791,7 +1784,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1791,7 +1784,7 @@ public class LocalMUCRoom implements MUCRoom {
removeAdmin(bareJID); removeAdmin(bareJID);
removeOutcast(bareJID); removeOutcast(bareJID);
// Associate the reserved nickname with the bareJID // Associate the reserved nickname with the bareJID
members.put(addMember.getBareJID(), addMember.getNickname()); members.put(addMember.getBareJID(), addMember.getNickname().toLowerCase());
} }
public void affiliationAdded(AddAffiliation affiliation) { public void affiliationAdded(AddAffiliation affiliation) {
...@@ -1840,21 +1833,23 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1840,21 +1833,23 @@ public class LocalMUCRoom implements MUCRoom {
} }
public void nicknameChanged(ChangeNickname changeNickname) { public void nicknameChanged(ChangeNickname changeNickname) {
MUCRole occupantRole = occupants.get(changeNickname.getOldNick().toLowerCase()); List<MUCRole> occupants = occupantsByNickname.get(changeNickname.getOldNick().toLowerCase());
if (occupantRole != null) { if (occupants != null && occupants.size() > 0) {
// Update the role with the new info for (MUCRole occupant : occupants) {
occupantRole.setPresence(changeNickname.getPresence()); // Update the role with the new info
occupantRole.changeNickname(changeNickname.getNewNick()); occupant.setPresence(changeNickname.getPresence());
if (changeNickname.isOriginator()) { occupant.changeNickname(changeNickname.getNewNick());
// Fire event that user changed his nickname }
MUCEventDispatcher.nicknameChanged(getRole().getRoleAddress(), occupantRole.getUserAddress(), if (changeNickname.isOriginator()) {
changeNickname.getOldNick(), changeNickname.getNewNick()); // Fire event that user changed his nickname
} MUCEventDispatcher.nicknameChanged(getRole().getRoleAddress(), occupants.get(0).getUserAddress(),
// Associate the existing MUCRole with the new nickname changeNickname.getOldNick(), changeNickname.getNewNick());
occupants.put(changeNickname.getNewNick().toLowerCase(), occupantRole); }
// Remove the old nickname // Associate the existing MUCRole with the new nickname
occupants.remove(changeNickname.getOldNick().toLowerCase()); occupantsByNickname.put(changeNickname.getNewNick().toLowerCase(), occupants);
} // Remove the old nickname
occupantsByNickname.remove(changeNickname.getOldNick().toLowerCase());
}
} }
public void changeSubject(Message packet, MUCRole role) throws ForbiddenException { public void changeSubject(Message packet, MUCRole role) throws ForbiddenException {
...@@ -1996,7 +1991,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -1996,7 +1991,7 @@ public class LocalMUCRoom implements MUCRoom {
public Collection<MUCRole> getModerators() { public Collection<MUCRole> getModerators() {
List<MUCRole> moderators = new ArrayList<MUCRole>(); List<MUCRole> moderators = new ArrayList<MUCRole>();
for (MUCRole role : occupants.values()) { for (MUCRole role : occupantsByFullJID.values()) {
if (MUCRole.Role.moderator == role.getRole()) { if (MUCRole.Role.moderator == role.getRole()) {
moderators.add(role); moderators.add(role);
} }
...@@ -2006,7 +2001,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -2006,7 +2001,7 @@ public class LocalMUCRoom implements MUCRoom {
public Collection<MUCRole> getParticipants() { public Collection<MUCRole> getParticipants() {
List<MUCRole> participants = new ArrayList<MUCRole>(); List<MUCRole> participants = new ArrayList<MUCRole>();
for (MUCRole role : occupants.values()) { for (MUCRole role : occupantsByFullJID.values()) {
if (MUCRole.Role.participant == role.getRole()) { if (MUCRole.Role.participant == role.getRole()) {
participants.add(role); participants.add(role);
} }
...@@ -2089,10 +2084,9 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -2089,10 +2084,9 @@ public class LocalMUCRoom implements MUCRoom {
* was not provided. * was not provided.
*/ */
private void kickPresence(Presence kickPresence, JID actorJID) { private void kickPresence(Presence kickPresence, JID actorJID) {
MUCRole kickedRole; // Get the role(s) to kick
// Get the role to kick List<MUCRole> occupants = occupantsByNickname.get(kickPresence.getFrom().getResource().toLowerCase());
kickedRole = occupants.get(kickPresence.getFrom().getResource().toLowerCase()); for (MUCRole kickedRole : occupants) {
if (kickedRole != null) {
kickPresence = kickPresence.createCopy(); kickPresence = kickPresence.createCopy();
// Add the actor's JID that kicked this user from the room // Add the actor's JID that kicked this user from the room
if (actorJID != null && actorJID.toString().length() > 0) { if (actorJID != null && actorJID.toString().length() > 0) {
...@@ -2162,7 +2156,7 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -2162,7 +2156,7 @@ public class LocalMUCRoom implements MUCRoom {
if (membersOnly && !this.membersOnly) { if (membersOnly && !this.membersOnly) {
// If the room was not members-only and now it is, kick occupants that aren't member // If the room was not members-only and now it is, kick occupants that aren't member
// of the room // of the room
for (MUCRole occupant : occupants.values()) { for (MUCRole occupant : occupantsByFullJID.values()) {
if (occupant.getAffiliation().compareTo(MUCRole.Affiliation.member) > 0) { if (occupant.getAffiliation().compareTo(MUCRole.Affiliation.member) > 0) {
try { try {
presences.add(kickOccupant(occupant.getRoleAddress(), null, presences.add(kickOccupant(occupant.getRoleAddress(), null,
...@@ -2295,14 +2289,6 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -2295,14 +2289,6 @@ public class LocalMUCRoom implements MUCRoom {
return; return;
} }
setLocked(true); setLocked(true);
// if (senderRole.getUserAddress() != null) {
// // Send to the occupant that locked the room a message saying so
// Message message = new Message();
// message.setType(Message.Type.groupchat);
// message.setBody(LocaleUtils.getLocalizedString("muc.locked"));
// message.setFrom(getRole().getRoleAddress());
// senderRole.send(message);
// }
} }
public void unlock(MUCRole senderRole) throws ForbiddenException { public void unlock(MUCRole senderRole) throws ForbiddenException {
...@@ -2314,17 +2300,6 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -2314,17 +2300,6 @@ public class LocalMUCRoom implements MUCRoom {
return; return;
} }
setLocked(false); setLocked(false);
// Nothing in XEP-0045 says, that a message must be sent upon unlocking a room, only this:
// Once the service receives the completed configuration form from the initial room owner (or receives a request for an instant room), the service MUST "unlock" the room (i.e., allow other users to enter the room) and send an IQ of type "result" to the room owner.
// if (senderRole.getUserAddress() != null) {
// // Send to the occupant that unlocked the room a message saying so
// Message message = new Message();
// message.setType(Message.Type.groupchat);
// message.setBody(LocaleUtils.getLocalizedString("muc.unlocked"));
// message.setFrom(getRole().getRoleAddress());
// senderRole.send(message);
// }
} }
private void setLocked(boolean locked) { private void setLocked(boolean locked) {
...@@ -2547,4 +2522,53 @@ public class LocalMUCRoom implements MUCRoom { ...@@ -2547,4 +2522,53 @@ public class LocalMUCRoom implements MUCRoom {
// name is unique for each one particular MUC service. // name is unique for each one particular MUC service.
return name; return name;
} }
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((creationDate == null) ? 0 : creationDate.hashCode());
result = prime * result
+ ((description == null) ? 0 : description.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result
+ ((password == null) ? 0 : password.hashCode());
result = prime * result + (int) (roomID ^ (roomID >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
LocalMUCRoom other = (LocalMUCRoom) obj;
if (creationDate == null) {
if (other.creationDate != null)
return false;
} else if (!creationDate.equals(other.creationDate))
return false;
if (description == null) {
if (other.description != null)
return false;
} else if (!description.equals(other.description))
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (password == null) {
if (other.password != null)
return false;
} else if (!password.equals(other.password))
return false;
if (roomID != other.roomID)
return false;
return true;
}
} }
...@@ -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