(geronimo-mail) 05/07: GERONIMO-6899 - Single-message Message.setFlags() never fires MessageChangedEvent

[email protected] Sat, 18 Jul 2026 18:49:04 +0000
Newsgroups gmane.comp.java.geronimo.cvs
Message-ID <[email protected]>
This is an automated email from the ASF dual-hosted git repository.

rzo1 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/geronimo-mail.git

commit b5bb2d2faa17cc11b0189fc0c5af1276776cbcad
Author: Richard Zowalla <[email protected]>
AuthorDate: Sat Jul 18 20:48:28 2026 +0200

    GERONIMO-6899 - Single-message Message.setFlags() never fires MessageChangedEvent
---
 .../geronimo/mail/store/imap/IMAPFolder.java       | 14 +++++++
 .../geronimo/mail/store/imap/IMAPMessage.java      |  6 +++
 .../mail/store/imap/IMAPTckRegressionTest.java     | 45 ++++++++++++++++++++++
 geronimo-mail_2.1_tck/src/tck/geronimo.jtx         |  1 -
 4 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/main/java/org/apache/geronimo/mail/store/imap/IMAPFolder.java b/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/main/java/org/apache/geronimo/mail/store/imap/IMAPFolder.java
index 62bebeb..1309793 100644
--- a/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/main/java/org/apache/geronimo/mail/store/imap/IMAPFolder.java
+++ b/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/main/java/org/apache/geronimo/mail/store/imap/IMAPFolder.java
@@ -1753,6 +1753,20 @@ public class IMAPFolder extends Folder implements UIDFolder, IMAPUntaggedRespons
     }
 
 
+    /**
+     * Notify the message changed listeners that the flags of a
+     * message contained in the folder have been updated.  Used by
+     * IMAPMessage.setFlags(), where the untagged FETCH reply to the
+     * STORE command is consumed by the connection, so the generic
+     * unsolicited-response handling never sees a flag update.
+     *
+     * @param m      The message whose flags were changed.
+     */
+    void notifyMessageFlagsChanged(Message m) {
+        notifyMessageChangedListeners(MessageChangedEvent.FLAGS_CHANGED, m);
+    }
+
+
     /**
      * Retrieve the connection attached to this folder.  Throws an
      * exception if we don't have an active connection.
diff --git a/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/main/java/org/apache/geronimo/mail/store/imap/IMAPMessage.java b/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/main/java/org/apache/geronimo/mail/store/imap/IMAPMessage.java
index 722bfb0..d18881e 100644
--- a/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/main/java/org/apache/geronimo/mail/store/imap/IMAPMessage.java
+++ b/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/main/java/org/apache/geronimo/mail/store/imap/IMAPMessage.java
@@ -199,6 +199,12 @@ public class IMAPMessage extends MimeMessage {
                 releaseConnection(connection);
             }
         }
+
+        // the untagged FETCH response to the STORE command was consumed above,
+        // so the folder never sees it as an unsolicited flag update.  Notify the
+        // listeners directly.  This is done outside the folder lock, matching the
+        // bulk Folder.setFlags() behavior.
+        ((IMAPFolder)folder).notifyMessageFlagsChanged(this);
     }
 
 
diff --git a/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/test/java/org/apache/geronimo/mail/store/imap/IMAPTckRegressionTest.java b/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/test/java/org/apache/geronimo/mail/store/imap/IMAPTckRegressionTest.java
index 6cb5727..40ef672 100644
--- a/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/test/java/org/apache/geronimo/mail/store/imap/IMAPTckRegressionTest.java
+++ b/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/test/java/org/apache/geronimo/mail/store/imap/IMAPTckRegressionTest.java
@@ -20,9 +20,16 @@ import java.io.ByteArrayOutputStream;
 import java.io.InputStream;
 import java.util.Properties;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import jakarta.mail.Flags;
 import jakarta.mail.Folder;
+import jakarta.mail.Message;
 import jakarta.mail.Session;
 import jakarta.mail.Store;
+import jakarta.mail.event.MessageChangedEvent;
+import jakarta.mail.event.MessageChangedListener;
 
 import org.apache.geronimo.mail.testserver.AbstractProtocolTest;
 import org.junit.jupiter.api.Test;
@@ -119,6 +126,44 @@ public class IMAPTckRegressionTest extends AbstractProtocolTest {
         }
     }
 
+    /**
+     * event/FolderEvent#addMsgChangeList_Test: a MessageChangedListener must
+     * fire when a flag is changed through a single message (Message.setFlags).
+     * The untagged FETCH reply to the STORE command is consumed inside
+     * IMAPConnection.setFlags, so the folder must notify the listeners itself.
+     */
+    @Test
+    public void testMessageChangedListenerFiresOnSingleMessageSetFlag() throws Exception {
+        start();
+        createMailboxWithMessage("test1");
+
+        final Store store = connect();
+        try {
+            final Folder folder = store.getDefaultFolder().getFolder("test1");
+            folder.open(Folder.READ_WRITE);
+            try {
+                final CountDownLatch changed = new CountDownLatch(1);
+                folder.addMessageChangedListener(new MessageChangedListener() {
+                    public void messageChanged(final MessageChangedEvent e) {
+                        if (e.getMessageChangeType() == MessageChangedEvent.FLAGS_CHANGED) {
+                            changed.countDown();
+                        }
+                    }
+                });
+
+                final Message msg = folder.getMessage(1);
+                msg.setFlag(Flags.Flag.ANSWERED, true);
+
+                assertTrue(changed.await(10, TimeUnit.SECONDS),
+                        "a MessageChangedEvent must be delivered for a single-message setFlag");
+            } finally {
+                folder.close(false);
+            }
+        } finally {
+            store.close();
+        }
+    }
+
     /**
      * MimeMessage#getContentLanguage_Test: a message whose BODYSTRUCTURE
      * carries no language information used to trigger a NullPointerException;
diff --git a/geronimo-mail_2.1_tck/src/tck/geronimo.jtx b/geronimo-mail_2.1_tck/src/tck/geronimo.jtx
index c00fe5a..460fa6b 100644
--- a/geronimo-mail_2.1_tck/src/tck/geronimo.jtx
+++ b/geronimo-mail_2.1_tck/src/tck/geronimo.jtx
@@ -40,7 +40,6 @@ javasoft/sqe/tests/jakarta/mail/Folder/testlist.html#appendMessages_Test
 # IMAPFolder.renameTo fix removed a ~90-test cascade). Distinct defects:
 # folder create/delete (topdog), permanent flags, list/listSubscribed,
 # several MIME encoding/decoding and unicode behaviours.
-javasoft/sqe/tests/jakarta/mail/event/FolderEvent/testlist.html#addMsgChangeList_Test
 javasoft/sqe/tests/jakarta/mail/exception/testlist.html#folderNotFoundExp_Test
 javasoft/sqe/tests/jakarta/mail/exception/testlist.html#msgRemoveExp_Test
 javasoft/sqe/tests/jakarta/mail/Folder/testlist.html#getPermanentFlags_Test