Commit b853644c authored by Dave Cridland's avatar Dave Cridland

Assume a client with MUC elements in presence needs to join

XEP-0045 discusses how a request to join a room is the only case where a MUC
element should exist in presence. Therefore, a conformant client will always
send this whenever it believes it is not joined. This can happen in cases of
stanza loss (due to network outage) or remote server crash.

This patch assumes that a client sending a MUC element is trying to join, and
will go through much of the motions of the join, including sending history as
required, existing occupants' presence, and so on. To other existing occupants,
however, it'll look like an ordinary presence update.
parent 4d6a8055
......@@ -563,6 +563,8 @@ public class LocalMUCRoom implements MUCRoom, GroupEventListener {
}
LocalMUCRole joinRole = null;
lock.writeLock().lock();
boolean clientOnlyJoin = false;
// A "client only join" here is one where the client is already joined, but has re-joined.
try {
// If the room has a limit of max user then check if the limit has been reached
if (!canJoinRoom(user)) {
......@@ -584,6 +586,9 @@ public class LocalMUCRoom implements MUCRoom, GroupEventListener {
// Nickname is already used, and not by the same JID
throw new UserAlreadyExistsException();
}
if (occupant.getUserAddress().equals(user.getAddress())) {
clientOnlyJoin = true; // This user is already an occupant. The client thinks it isn't. (Or else this is a broken gmail).
}
}
// If the room is password protected and the provided password is incorrect raise a
// Unauthorized exception
......@@ -650,23 +655,29 @@ public class LocalMUCRoom implements MUCRoom, GroupEventListener {
role = (isModerated() ? MUCRole.Role.visitor : MUCRole.Role.participant);
affiliation = MUCRole.Affiliation.none;
}
// Create a new role for this user in this room
joinRole = new LocalMUCRole(mucService, this, nickname, role, affiliation, user, presence, router);
// Add the new user as an occupant of this room
List<MUCRole> occupants = occupantsByNickname.get(nickname.toLowerCase());
if (occupants == null) {
occupants = new ArrayList<>();
occupantsByNickname.put(nickname.toLowerCase(), occupants);
}
occupants.add(joinRole);
// Update the tables of occupants based on the bare and full JID
List<MUCRole> list = occupantsByBareJID.get(bareJID);
if (list == null) {
list = new ArrayList<>();
occupantsByBareJID.put(bareJID, list);
}
list.add(joinRole);
occupantsByFullJID.put(user.getAddress(), joinRole);
if (!clientOnlyJoin) {
// Create a new role for this user in this room
joinRole = new LocalMUCRole(mucService, this, nickname, role,
affiliation, user, presence, router);
// Add the new user as an occupant of this room
List<MUCRole> occupants = occupantsByNickname.get(nickname.toLowerCase());
if (occupants == null) {
occupants = new ArrayList<>();
occupantsByNickname.put(nickname.toLowerCase(), occupants);
}
occupants.add(joinRole);
// Update the tables of occupants based on the bare and full JID
List<MUCRole> list = occupantsByBareJID.get(bareJID);
if (list == null) {
list = new ArrayList<>();
occupantsByBareJID.put(bareJID, list);
}
list.add(joinRole);
occupantsByFullJID.put(user.getAddress(), joinRole);
} else {
// Grab the existing one.
joinRole = (LocalMUCRole) occupantsByFullJID.get(user.getAddress());
}
}
finally {
lock.writeLock().unlock();
......@@ -706,10 +717,13 @@ public class LocalMUCRoom implements MUCRoom, GroupEventListener {
else {
historyRequest.sendHistory(joinRole, roomHistory);
}
// Update the date when the last occupant left the room
setEmptyDate(null);
// Fire event that occupant joined the room
MUCEventDispatcher.occupantJoined(getRole().getRoleAddress(), user.getAddress(), joinRole.getNickname());
if (!clientOnlyJoin) {
// Update the date when the last occupant left the room
setEmptyDate(null);
// Fire event that occupant joined the room
MUCEventDispatcher.occupantJoined(getRole().getRoleAddress(),
user.getAddress(), joinRole.getNickname());
}
return joinRole;
}
......
......@@ -71,7 +71,7 @@ import org.xmpp.packet.Presence;
*/
public class LocalMUCUser implements MUCUser {
private static final Logger Log = LoggerFactory.getLogger(LocalMUCUser.class);
private static final Logger Log = LoggerFactory.getLogger(LocalMUCUser.class);
/** The chat server this user belongs to. */
private MultiUserChatService server;
......@@ -462,9 +462,12 @@ public class LocalMUCUser implements MUCUser {
String group = recipient.getNode();
if (group != null) {
MUCRole role = roles.get(group);
if (role == null) {
// If we're not already in a room, we either are joining it or it's not
Element mucInfo = packet.getChildElement("x",
"http://jabber.org/protocol/muc");
if (role == null || mucInfo != null) {
// If we're not already in a room (role == null), we either are joining it or it's not
// properly addressed and we drop it silently
// Alternative is that mucInfo is not null, in which case the client thinks it isn't in the room, so we should join anyway.
if (recipient.getResource() != null
&& recipient.getResource().trim().length() > 0) {
if (packet.isAvailable()) {
......@@ -472,8 +475,6 @@ public class LocalMUCUser implements MUCUser {
// Get or create the room
MUCRoom room = server.getChatRoom(group, packet.getFrom());
// User must support MUC in order to create a room
Element mucInfo = packet.getChildElement("x",
"http://jabber.org/protocol/muc");
HistoryRequest historyRequest = null;
String password = null;
// Check for password & requested history if client supports MUC
......
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