(geronimo-mail) 03/07: GERONIMO-6897 - Folder.create() sends the uninitialized hierarchy separator, creating a mailbox named "name\0"

[email protected] Sat, 18 Jul 2026 18:49:02 +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 f09957901b3d63af6b8cc20ebeddaeff8ee34590
Author: Richard Zowalla <[email protected]>
AuthorDate: Sat Jul 18 20:48:28 2026 +0200

    GERONIMO-6897 - Folder.create() sends the uninitialized hierarchy separator, creating a mailbox named "name\0"
---
 .../geronimo/mail/store/imap/IMAPFolder.java       | 20 +++++++++++---
 .../mail/store/imap/IMAPTckRegressionTest.java     | 31 ++++++++++++++++++++++
 geronimo-mail_2.1_tck/src/tck/geronimo.jtx         |  3 ---
 3 files changed, 48 insertions(+), 6 deletions(-)

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 f228d24..d94d6e8 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
@@ -326,9 +326,19 @@ public class IMAPFolder extends Folder implements UIDFolder, IMAPUntaggedRespons
                 List responses = connection.list("", fullname);
                 IMAPListResponse info = findListResponse(responses, fullname);
 
-                // if we didn't get any hits, then we just assume a reasonable default.
+                // if we didn't get any hits (e.g., the folder does not exist yet),
+                // ask the server for the hierarchy delimiter directly.  RFC 3501
+                // defines the special form LIST "" "" as returning the hierarchy
+                // delimiter and the root name without matching any mailboxes.
                 if (info == null) {
-                    separator = '/';
+                    List delimiterResponses = connection.list("", "");
+                    if (!delimiterResponses.isEmpty()) {
+                        separator = ((IMAPListResponse)delimiterResponses.get(0)).separator;
+                    }
+                    // no useful answer from the server, assume a reasonable default.
+                    if (separator == '\0') {
+                        separator = '/';
+                    }
                 }
                 else {
                     separator = info.separator;
@@ -384,7 +394,11 @@ public class IMAPFolder extends Folder implements UIDFolder, IMAPUntaggedRespons
             // if this folder is expected to only hold additional folders, we need to
             // add a separator on to the end when we create this.
             if ((newType & HOLDS_MESSAGES) == 0) {
-                newPath = fullname + separator;
+                // NB:  we must use getSeparator() here, not the raw field.  For folders
+                // obtained from the default folder the separator is still UNDETERMINED
+                // ('\0'), and appending that raw character would send a corrupted
+                // (modified-UTF-7 encoded) mailbox name to the server.
+                newPath = fullname + getSeparator();
             }
             try {
                 // go create 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 667f94f..57c11d8 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
@@ -27,7 +27,9 @@ import jakarta.mail.Store;
 import org.apache.geronimo.mail.testserver.AbstractProtocolTest;
 import org.junit.jupiter.api.Test;
 
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 /**
  * Regression tests for a set of IMAP provider defects surfaced by the
@@ -62,6 +64,35 @@ public class IMAPTckRegressionTest extends AbstractProtocolTest {
         server.appendToUserMailbox(name, readMessageResource("/messages/simple.msg"));
     }
 
+    /**
+     * Folder#create_Test/delete_Test/getType_Test: a top-level folder obtained
+     * via the default folder has an UNDETERMINED separator; create() used to
+     * append the raw '\0' separator to the mailbox name on the wire
+     * ("CREATE topdog&AAA-"), so the folder was created under a mangled name
+     * and create() reported failure.  The James hierarchy delimiter is '.',
+     * not the '/' fallback, so the separator must be obtained from the server.
+     */
+    @Test
+    public void testCreateDeleteGetTypeRoundTrip() throws Exception {
+        start();
+
+        final Store store = connect();
+        try {
+            final Folder folder = store.getDefaultFolder().getFolder("topdog");
+            assertFalse(folder.exists(), "folder must not exist before creation");
+
+            assertTrue(folder.create(Folder.HOLDS_FOLDERS), "create must succeed");
+            assertTrue(folder.exists(), "created folder must exist under its own name");
+            assertTrue((folder.getType() & Folder.HOLDS_FOLDERS) != 0,
+                    "created folder must be able to hold folders");
+
+            assertTrue(folder.delete(false), "delete must succeed");
+            assertFalse(folder.exists(), "deleted folder must no longer exist");
+        } 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 0cbef10..9a534c2 100644
--- a/geronimo-mail_2.1_tck/src/tck/geronimo.jtx
+++ b/geronimo-mail_2.1_tck/src/tck/geronimo.jtx
@@ -43,10 +43,7 @@ javasoft/sqe/tests/jakarta/mail/Folder/testlist.html#appendMessages_Test
 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#create_Test
-javasoft/sqe/tests/jakarta/mail/Folder/testlist.html#delete_Test
 javasoft/sqe/tests/jakarta/mail/Folder/testlist.html#getPermanentFlags_Test
-javasoft/sqe/tests/jakarta/mail/Folder/testlist.html#getType_Test
 javasoft/sqe/tests/jakarta/mail/Folder/testlist.html#list_Test
 javasoft/sqe/tests/jakarta/mail/Folder/testlist.html#listSubscribed_Test
 javasoft/sqe/tests/jakarta/mail/internet/InternetAddress/testlist.html#unicode_Test