XEP-0313 MAM: offline messages are stored twice
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInternalInboundStanzaRelay.java b/server/core/src/main/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInternalInboundStanzaRelay.java
index 7993ea4..6e05961 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInternalInboundStanzaRelay.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/delivery/inbound/DeliveringInternalInboundStanzaRelay.java
@@ -96,8 +96,6 @@
 
     private InboundStanzaProtocolWorker inboundStanzaProtocolWorker;
 
-    private UnconnectedProtocolWorker unconnectedProtocolWorker;
-
     private final ComponentRegistry componentRegistry;
 
     private static final Integer PRIO_THRESHOLD = 0;
@@ -149,7 +147,6 @@
 
     public void setStanzaHandlerExecutorFactory(StanzaHandlerExecutorFactory stanzaHandlerExecutorFactory) {
         this.inboundStanzaProtocolWorker = new InboundStanzaProtocolWorker(stanzaHandlerExecutorFactory);
-        this.unconnectedProtocolWorker = new UnconnectedProtocolWorker(stanzaHandlerExecutorFactory);
     }
 
     public final void setLogStorageProvider(final LogStorageProvider logStorageProvider) {
@@ -385,7 +382,7 @@
                 LOG.warn("cannot relay to offline receiver {} stanza {}", receiver.getFullQualifiedName(), stanza);
                 return new RelayResult(new LocalRecipientOfflineException());
             }
-            unconnectedProtocolWorker.processStanza(serverRuntimeContext, null, sessionStateHolder, stanza,
+            inboundStanzaProtocolWorker.processStanza(serverRuntimeContext, null, sessionStateHolder, stanza,
                     stanzaHandler);
             return new RelayResult().setProcessed();
         }
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailabilityHandler.java b/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailabilityHandler.java
index 477e5ff..de8865d 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailabilityHandler.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailabilityHandler.java
@@ -273,7 +273,7 @@
             Collection<Stanza> offlineStanzas = offlineProvider.getStanzasFor(user);
             for (Stanza stanza : offlineStanzas) {
                 logger.debug("Sending out delayed offline stanza");
-                relayStanza(user, stanza, stanzaBroker);
+                stanzaBroker.writeToSession(stanza);
             }
         }
 
diff --git a/server/core/src/main/java/org/apache/vysper/xmpp/protocol/worker/AbstractStateAwareProtocolWorker.java b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/worker/AbstractStateAwareProtocolWorker.java
index bebdefc..c4d7551 100644
--- a/server/core/src/main/java/org/apache/vysper/xmpp/protocol/worker/AbstractStateAwareProtocolWorker.java
+++ b/server/core/src/main/java/org/apache/vysper/xmpp/protocol/worker/AbstractStateAwareProtocolWorker.java
@@ -58,7 +58,7 @@
 
     protected boolean checkState(InternalSessionContext sessionContext, SessionStateHolder sessionStateHolder,
             Stanza stanza, StanzaHandler stanzaHandler) {
-        return sessionContext != null && getHandledState() == sessionContext.getState();
+        return getHandledState() == sessionStateHolder.getState();
     }
 
     private void executeHandler(ServerRuntimeContext serverRuntimeContext, InternalSessionContext sessionContext,
diff --git a/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/in_memory/InMemoryMessageArchive.java b/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/in_memory/InMemoryMessageArchive.java
index 208bcae..f928625 100644
--- a/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/in_memory/InMemoryMessageArchive.java
+++ b/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/in_memory/InMemoryMessageArchive.java
@@ -19,12 +19,16 @@
  */
 package org.apache.vysper.xmpp.modules.extension.xep0313_mam.in_memory;
 
+import static java.util.Objects.requireNonNull;
+
 import java.util.ArrayList;
 import java.util.List;
+import java.util.StringJoiner;
 import java.util.UUID;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
+import org.apache.vysper.xmpp.addressing.Entity;
 import org.apache.vysper.xmpp.modules.extension.xep0313_mam.spi.ArchivedMessage;
 import org.apache.vysper.xmpp.modules.extension.xep0313_mam.spi.ArchivedMessages;
 import org.apache.vysper.xmpp.modules.extension.xep0313_mam.spi.Message;
@@ -38,8 +42,14 @@
  */
 public class InMemoryMessageArchive implements MessageArchive {
 
+    private final Entity archiveId;
+
     private final List<SimpleArchivedMessage> messages = new ArrayList<>();
 
+    public InMemoryMessageArchive(Entity archiveId) {
+        this.archiveId = requireNonNull(archiveId);
+    }
+
     @Override
     public ArchivedMessage archive(Message message) {
         SimpleArchivedMessage archivedMessage = new SimpleArchivedMessage(UUID.randomUUID().toString(), message);
@@ -63,4 +73,9 @@
         return messages.stream().filter(predicate).collect(Collectors.toList());
     }
 
+    @Override
+    public String toString() {
+        return new StringJoiner(", ", InMemoryMessageArchive.class.getSimpleName() + "[", "]")
+                .add("archiveId=" + archiveId).toString();
+    }
 }
diff --git a/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/in_memory/InMemoryMessageArchives.java b/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/in_memory/InMemoryMessageArchives.java
index a5d4073..ae491e5 100644
--- a/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/in_memory/InMemoryMessageArchives.java
+++ b/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/in_memory/InMemoryMessageArchives.java
@@ -37,7 +37,7 @@
     @Override
     public Optional<UserMessageArchive> retrieveUserMessageArchive(Entity userBareJid) {
         UserMessageArchive messageArchive = userMessageArchiveById.computeIfAbsent(userBareJid,
-                id -> new InMemoryUserMessageArchive());
+                id -> new InMemoryUserMessageArchive(userBareJid));
         return Optional.of(messageArchive);
     }
 }
diff --git a/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/in_memory/InMemoryUserMessageArchive.java b/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/in_memory/InMemoryUserMessageArchive.java
index 4042530..424dbcc 100644
--- a/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/in_memory/InMemoryUserMessageArchive.java
+++ b/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/in_memory/InMemoryUserMessageArchive.java
@@ -19,6 +19,7 @@
  */
 package org.apache.vysper.xmpp.modules.extension.xep0313_mam.in_memory;
 
+import org.apache.vysper.xmpp.addressing.Entity;
 import org.apache.vysper.xmpp.modules.extension.xep0313_mam.spi.ArchivedMessage;
 import org.apache.vysper.xmpp.modules.extension.xep0313_mam.spi.ArchivedMessages;
 import org.apache.vysper.xmpp.modules.extension.xep0313_mam.spi.Message;
@@ -38,8 +39,8 @@
 
     private UserMessageArchivePreferences preferences;
 
-    public InMemoryUserMessageArchive() {
-        this.delegate = new InMemoryMessageArchive();
+    public InMemoryUserMessageArchive(Entity archiveId) {
+        this.delegate = new InMemoryMessageArchive(archiveId);
         this.preferences = new SimpleUserMessageArchivePreferences();
     }
 
diff --git a/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserMessageStanzaBroker.java b/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserMessageStanzaBroker.java
index 3ef8a6a..b818253 100644
--- a/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserMessageStanzaBroker.java
+++ b/server/extensions/xep0313-mam/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserMessageStanzaBroker.java
@@ -130,8 +130,13 @@
         // local users MUST expose these archives to the user on the user's bare JID.
         Entity receiverArchiveId = requireNonNull(messageStanza.getTo(), "No 'to' found in " + messageStanza)
                 .getBareJID();
-        return messageArchives().retrieveUserMessageArchive(receiverArchiveId)
-                .map(messageArchive -> messageArchive.archive(new SimpleMessage(messageStanza)));
+        Optional<UserMessageArchive> receiverArchive = messageArchives().retrieveUserMessageArchive(receiverArchiveId);
+        if (!receiverArchive.isPresent()) {
+            LOG.debug("No archive returned for sender with bare JID '{}'", receiverArchiveId);
+            return Optional.empty();
+        }
+
+        return Optional.ofNullable(receiverArchive.get().archive(new SimpleMessage(messageStanza)));
     }
 
     private MessageArchives messageArchives() {
diff --git a/server/extensions/xep0313-mam/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserArchiveTest.java b/server/extensions/xep0313-mam/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserArchiveTest.java
index bef02b9..9e1fbb4 100644
--- a/server/extensions/xep0313-mam/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserArchiveTest.java
+++ b/server/extensions/xep0313-mam/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0313_mam/user/UserArchiveTest.java
@@ -219,16 +219,9 @@
 
         Thread.sleep(200);
 
-        assertNotNull(carolReceivedMessage.get());
-        assertEquals("Hello carol", carolReceivedMessage.get().getBody());
-
         Message archivedMessage = fetchUniqueArchivedMessage(carol());
         String storedStanzaId = extractStanzaId(archivedMessage);
         assertNotNull(storedStanzaId);
-
-        String receivedStanzaId = extractStanzaId(carolReceivedMessage.get());
-
-        assertEquals(storedStanzaId, receivedStanzaId);
     }
 
     @Test