From 9d1b88a87726d7f4867a01d643f6fbd4007c7e7b Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 12 Mar 2021 22:26:36 +0100 Subject: [PATCH] [muc] Do not filter for presence ID if #stable_id is not announced On leave(), do not filter for presence ID if the MUC service does not announce #stable_id. --- .../smackx/muc/MultiUserChat.java | 32 +++++++++++++------ .../smackx/muc/MultiUserChatConstants.java | 4 ++- .../smackx/muc/MultiUserChatManager.java | 27 ++++++++++------ 3 files changed, 42 insertions(+), 21 deletions(-) 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; } /**