From 60fee7b3181f587e6504e643f69ce7c00c32bf6c Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Sat, 21 May 2022 13:42:22 +0200 Subject: [PATCH] [muc] Fix Presence interceptors Presence interceptors where hooked into stanza sending listeners, which are called *after* the stanza has been put on the wire, i.e., to late for interceptors that any modifications, they may perform, to take effect. Fixes SMACK-925. We now also dynamically add the MUC's main presence interceptor to the connection. Reported-by: Damian Minkov --- .../smackx/muc/MultiUserChat.java | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 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 540e419fe..fb03b3b73 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-2021 Florian Schmaus + * Copyright 2003-2007 Jive Software. 2020-2022 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; +import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; @@ -59,7 +60,9 @@ import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.MessageBuilder; import org.jivesoftware.smack.packet.MessageView; import org.jivesoftware.smack.packet.Presence; +import org.jivesoftware.smack.packet.PresenceBuilder; import org.jivesoftware.smack.packet.Stanza; +import org.jivesoftware.smack.util.Consumer; import org.jivesoftware.smack.util.Objects; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; @@ -124,7 +127,7 @@ public class MultiUserChat { private final Set participantStatusListeners = new CopyOnWriteArraySet(); private final Set messageListeners = new CopyOnWriteArraySet(); private final Set presenceListeners = new CopyOnWriteArraySet(); - private final Set presenceInterceptors = new CopyOnWriteArraySet(); + private final Set> presenceInterceptors = new CopyOnWriteArraySet<>(); /** * This filter will match all stanzas send from the groupchat or from one if @@ -138,7 +141,16 @@ public class MultiUserChat { */ private final StanzaFilter fromRoomGroupchatFilter; - private final StanzaListener presenceInterceptor; + private final AtomicInteger presenceInterceptorCount = new AtomicInteger(); + // We want to save the presence interceptor in a variable, using a lambda, (and not use a method reference) to be + // able to dynamically add and remove it from the connection. + @SuppressWarnings("UnnecessaryLambda") + private final Consumer presenceInterceptor = presenceBuilder -> { + for (Consumer interceptor : presenceInterceptors) { + interceptor.accept(presenceBuilder); + } + }; + private final StanzaListener messageListener; private final StanzaListener presenceListener; private final StanzaListener subjectListener; @@ -316,16 +328,6 @@ public class MultiUserChat { fireInvitationRejectionListeners(message, rejection); } }; - - presenceInterceptor = new StanzaListener() { - @Override - public void processStanza(Stanza packet) { - Presence presence = (Presence) packet; - for (PresenceListener interceptor : presenceInterceptors) { - interceptor.processPresence(presence); - } - } - }; } @@ -379,8 +381,6 @@ public class MultiUserChat { ); // @formatter:on connection.addStanzaListener(declinesListener, new AndFilter(fromRoomFilter, DECLINE_FILTER)); - connection.addStanzaSendingListener(presenceInterceptor, new AndFilter(ToMatchesFilter.create(room), - StanzaTypeFilter.PRESENCE)); messageCollector = connection.createStanzaCollector(fromRoomGroupchatFilter); // Wait for a presence packet back from the server. @@ -1112,8 +1112,13 @@ public class MultiUserChat { * * @param presenceInterceptor the new stanza interceptor that will intercept presence packets. */ - public void addPresenceInterceptor(PresenceListener presenceInterceptor) { - presenceInterceptors.add(presenceInterceptor); + public void addPresenceInterceptor(Consumer presenceInterceptor) { + boolean added = presenceInterceptors.add(presenceInterceptor); + if (!added) return; + int currentCount = presenceInterceptorCount.incrementAndGet(); + if (currentCount == 1) { + connection.addPresenceInterceptor(this.presenceInterceptor, ToMatchesFilter.create(room).asPredicate(Presence.class)); + } } /** @@ -1123,8 +1128,13 @@ public class MultiUserChat { * * @param presenceInterceptor the stanza interceptor to remove. */ - public void removePresenceInterceptor(PresenceListener presenceInterceptor) { - presenceInterceptors.remove(presenceInterceptor); + public void removePresenceInterceptor(Consumer presenceInterceptor) { + boolean removed = presenceInterceptors.remove(presenceInterceptor); + if (!removed) return; + int currentCount = presenceInterceptorCount.decrementAndGet(); + if (currentCount == 0) { + connection.removePresenceInterceptor(presenceInterceptor); + } } /** @@ -2180,7 +2190,7 @@ public class MultiUserChat { connection.removeStanzaListener(presenceListener); connection.removeStanzaListener(subjectListener); connection.removeStanzaListener(declinesListener); - connection.removeStanzaSendingListener(presenceInterceptor); + connection.removePresenceInterceptor(presenceInterceptor); if (messageCollector != null) { messageCollector.cancel(); messageCollector = null;