diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java
index 51f267694..f7480becd 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChat.java
@@ -1,6 +1,6 @@
/**
*
- * Copyright 2003-2007 Jive Software. 2020 Florian Schmaus
+ * Copyright 2003-2007 Jive Software. 2020-2021 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -149,6 +149,8 @@ public class MultiUserChat {
private EntityFullJid myRoomJid;
private StanzaCollector messageCollector;
+ private DiscoverInfo mucServiceDiscoInfo;
+
/**
* Used to signal that the reflected self-presence was received and processed by us.
*/
@@ -342,7 +344,8 @@ public class MultiUserChat {
private Presence enter(MucEnterConfiguration conf) throws NotConnectedException, NoResponseException,
XMPPErrorException, InterruptedException, NotAMucServiceException {
final DomainBareJid mucService = room.asDomainBareJid();
- if (!multiUserChatManager.providesMucService(mucService)) {
+ mucServiceDiscoInfo = multiUserChatManager.getMucServiceDiscoInfo(mucService);
+ if (mucServiceDiscoInfo == null) {
throw new NotAMucServiceException(this);
}
// We enter a room by sending a presence packet where the "to"
@@ -757,6 +760,10 @@ public class MultiUserChat {
throw new MucNotJoinedException(this);
}
+ // TODO: Consider adding a origin-id to the presence, once it is moved form smack-experimental into
+ // smack-extensions, in case the MUC service does not support stable IDs, and modify
+ // reflectedLeavePresenceFilters accordingly.
+
// We leave a room by sending a presence packet where the "to"
// field is in the form "roomName@service/nickname"
Presence leavePresence = connection.getStanzaFactory().buildPresenceStanza()
@@ -764,14 +771,19 @@ public class MultiUserChat {
.to(myRoomJid)
.build();
- StanzaFilter reflectedLeavePresenceFilter = new AndFilter(
- StanzaTypeFilter.PRESENCE,
- new StanzaIdFilter(leavePresence),
- new OrFilter(
- new AndFilter(FromMatchesFilter.createFull(myRoomJid), PresenceTypeFilter.UNAVAILABLE, MUCUserStatusCodeFilter.STATUS_110_PRESENCE_TO_SELF),
- new AndFilter(fromRoomFilter, PresenceTypeFilter.ERROR)
- )
- );
+ List reflectedLeavePresenceFilters = new ArrayList<>(3);
+ reflectedLeavePresenceFilters.add(StanzaTypeFilter.PRESENCE);
+ reflectedLeavePresenceFilters.add(new OrFilter(
+ new AndFilter(FromMatchesFilter.createFull(myRoomJid), PresenceTypeFilter.UNAVAILABLE,
+ MUCUserStatusCodeFilter.STATUS_110_PRESENCE_TO_SELF),
+ new AndFilter(fromRoomFilter, PresenceTypeFilter.ERROR)));
+
+ boolean supportsStableId = mucServiceDiscoInfo.containsFeature(MultiUserChatConstants.STABLE_ID_FEATURE);
+ if (supportsStableId) {
+ reflectedLeavePresenceFilters.add(new StanzaIdFilter(leavePresence));
+ }
+
+ StanzaFilter reflectedLeavePresenceFilter = new AndFilter(reflectedLeavePresenceFilters);
// Reset occupant information first so that we are assume that we left the room even if sendStanza() would
// throw.
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatConstants.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatConstants.java
index ffc00a5a9..35167c081 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatConstants.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatConstants.java
@@ -1,6 +1,6 @@
/**
*
- * Copyright 2020 Florian Schmaus
+ * Copyright 2020-2021 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,4 +20,6 @@ public class MultiUserChatConstants {
public static final String NAMESPACE = "http://jabber.org/protocol/muc";
+ public static final String STABLE_ID_FEATURE = NAMESPACE + "#stable_id";
+
}
diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java
index 7d92e9817..2cf5778ff 100644
--- a/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java
+++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatManager.java
@@ -1,6 +1,6 @@
/**
*
- * Copyright © 2014-2020 Florian Schmaus
+ * Copyright © 2014-2021 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -137,7 +137,7 @@ public final class MultiUserChatManager extends Manager {
private static final StanzaFilter INVITATION_FILTER = new AndFilter(StanzaTypeFilter.MESSAGE, new StanzaExtensionFilter(new MUCUser()),
new NotFilter(MessageTypeFilter.ERROR));
- private static final ExpirationCache KNOWN_MUC_SERVICES = new ExpirationCache<>(
+ private static final ExpirationCache KNOWN_MUC_SERVICES = new ExpirationCache<>(
100, 1000 * 60 * 60 * 24);
private final Set invitationsListeners = new CopyOnWriteArraySet();
@@ -396,16 +396,23 @@ public final class MultiUserChatManager extends Manager {
*/
public boolean providesMucService(DomainBareJid domainBareJid) throws NoResponseException,
XMPPErrorException, NotConnectedException, InterruptedException {
- boolean contains = KNOWN_MUC_SERVICES.containsKey(domainBareJid);
- if (!contains) {
- if (serviceDiscoveryManager.supportsFeature(domainBareJid,
- MUCInitialPresence.NAMESPACE)) {
- KNOWN_MUC_SERVICES.put(domainBareJid, null);
- return true;
- }
+ return getMucServiceDiscoInfo(domainBareJid) != null;
+ }
+
+ DiscoverInfo getMucServiceDiscoInfo(DomainBareJid mucServiceAddress)
+ throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException {
+ DiscoverInfo discoInfo = KNOWN_MUC_SERVICES.get(mucServiceAddress);
+ if (discoInfo != null) {
+ return discoInfo;
}
- return contains;
+ discoInfo = serviceDiscoveryManager.discoverInfo(mucServiceAddress);
+ if (!discoInfo.containsFeature(MUCInitialPresence.NAMESPACE)) {
+ return null;
+ }
+
+ KNOWN_MUC_SERVICES.put(mucServiceAddress, discoInfo);
+ return discoInfo;
}
/**