This is an automated email from the ASF dual-hosted git repository.

rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit b4723b0f0218c7239eadcb5ae0d4021f59c7ce01
Author: Benoit TELLIER <btell...@linagora.com>
AuthorDate: Wed Oct 9 14:32:21 2024 +0200

    JAMES-2182 PathConverter: handle encoding for mailboxes belonging to others
---
 .../james/imap/scripts/ListWithSharedMailbox.test  |  2 +-
 .../org/apache/james/imap/scripts/Namespace.test   |  2 +-
 .../org/apache/james/imap/main/PathConverter.java  | 53 +++++++++++++---------
 .../james/imap/processor/NamespaceSupplier.java    |  2 +-
 .../apache/james/imap/main/PathConverterTest.java  | 18 ++++++--
 5 files changed, 49 insertions(+), 28 deletions(-)

diff --git 
a/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/ListWithSharedMailbox.test
 
b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/ListWithSharedMailbox.test
index 2d01957135..eba7f0dd17 100644
--- 
a/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/ListWithSharedMailbox.test
+++ 
b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/ListWithSharedMailbox.test
@@ -24,7 +24,7 @@ S: \* LIST \(\\HasNoChildren\) \"\.\" \"INBOX\"
 S: a0 OK LIST completed.
 
 C: a1 LIST "#private" "%"
-S: \* LIST \(\\HasNoChildren\) \"\.\" \"#private.imapuser.INBOX\"
+S: \* LIST \(\\HasNoChildren\) \"\.\" \"#private.INBOX\"
 S: a1 OK LIST completed.
 
 C: a3 LIST "#private" sharedMailbox*
diff --git 
a/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/Namespace.test
 
b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/Namespace.test
index 42cc371ccb..bb67da2bca 100644
--- 
a/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/Namespace.test
+++ 
b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/Namespace.test
@@ -17,6 +17,6 @@
 # under the License.                                           #
 ################################################################
 C: A001 NAMESPACE
-S: \* NAMESPACE \(\((\"\"|\"#private\.\") \".\"\)\) NIL NIL
+S: \* NAMESPACE \(\((\"\"|\"#private\.\") \".\"\)\) \(\(\"#user.\" \".\"\)\) 
NIL
 S: A001 OK NAMESPACE completed.
 
diff --git 
a/protocols/imap/src/main/java/org/apache/james/imap/main/PathConverter.java 
b/protocols/imap/src/main/java/org/apache/james/imap/main/PathConverter.java
index 09702031d1..151e503f39 100644
--- a/protocols/imap/src/main/java/org/apache/james/imap/main/PathConverter.java
+++ b/protocols/imap/src/main/java/org/apache/james/imap/main/PathConverter.java
@@ -21,6 +21,7 @@ package org.apache.james.imap.main;
 
 import java.util.List;
 
+import org.apache.james.core.Domain;
 import org.apache.james.core.Username;
 import org.apache.james.imap.api.process.ImapSession;
 import org.apache.james.mailbox.MailboxSession;
@@ -48,6 +49,7 @@ public interface PathConverter {
 
     class Default implements PathConverter{
         private static final int NAMESPACE = 0;
+        private static final int USER = 1;
 
         private final ImapSession session;
 
@@ -72,29 +74,29 @@ public interface PathConverter {
         }
 
         private MailboxPath buildRelativePath(String mailboxName) {
-            return buildMailboxPath(MailboxConstants.USER_NAMESPACE, 
session.getUserName(), mailboxName);
+            return new MailboxPath(MailboxConstants.USER_NAMESPACE, 
session.getUserName(), sanitizeMailboxName(mailboxName));
         }
 
         private MailboxPath buildAbsolutePath(String absolutePath) {
-            char pathDelimiter = 
session.getMailboxSession().getPathDelimiter();
-            List<String> mailboxPathParts = 
Splitter.on(pathDelimiter).splitToList(absolutePath);
-            String namespace = mailboxPathParts.get(NAMESPACE);
-            String mailboxName = 
Joiner.on(pathDelimiter).join(Iterables.skip(mailboxPathParts, 1));
-            return buildMailboxPath(namespace, retrieveUserName(namespace), 
mailboxName);
+            MailboxSession mailboxSession = session.getMailboxSession();
+            return 
asMailboxPath(Splitter.on(mailboxSession.getPathDelimiter()).splitToList(absolutePath),
 mailboxSession);
         }
 
-        private Username retrieveUserName(String namespace) {
-            if (namespace.equals(MailboxConstants.USER_NAMESPACE)) {
-                return session.getUserName();
-            }
-            throw new DeniedAccessOnSharedMailboxException();
-        }
+        private MailboxPath asMailboxPath(List<String> mailboxPathParts, 
MailboxSession session) {
+            String namespace = mailboxPathParts.get(NAMESPACE);
+            if (namespace.equalsIgnoreCase("#private")) {
+                String mailboxName = 
Joiner.on(session.getPathDelimiter()).join(Iterables.skip(mailboxPathParts, 1));
+                return new MailboxPath(MailboxConstants.USER_NAMESPACE, 
session.getUser(), sanitizeMailboxName(mailboxName));
+            } else if (namespace.equalsIgnoreCase("#user")) {
+                Preconditions.checkArgument(mailboxPathParts.size() > 2, 
"Expecting at least 2 parts");
+                String username = mailboxPathParts.get(USER);
+                Username user = Username.from(username, 
session.getUser().getDomainPart().map(Domain::asString));
+                String mailboxName = 
Joiner.on(session.getPathDelimiter()).join(Iterables.skip(mailboxPathParts, 2));
+                return new MailboxPath(MailboxConstants.USER_NAMESPACE, user, 
sanitizeMailboxName(mailboxName));
 
-        private MailboxPath buildMailboxPath(String namespace, Username user, 
String mailboxName) {
-            if (!namespace.equals(MailboxConstants.USER_NAMESPACE)) {
+            } else {
                 throw new DeniedAccessOnSharedMailboxException();
             }
-            return new MailboxPath(namespace, user, 
sanitizeMailboxName(mailboxName));
         }
 
         private String sanitizeMailboxName(String mailboxName) {
@@ -109,20 +111,27 @@ public interface PathConverter {
         /**
          * Joins the elements of a mailboxPath together and returns them as a 
string
          */
-        private String joinMailboxPath(MailboxPath mailboxPath, char 
delimiter) {
+        private String joinMailboxPath(MailboxPath mailboxPath, MailboxSession 
session) {
             StringBuilder sb = new StringBuilder();
             if (mailboxPath.getNamespace() != null && 
!mailboxPath.getNamespace().equals("")) {
-                sb.append(mailboxPath.getNamespace());
+                if 
(mailboxPath.getNamespace().equalsIgnoreCase(MailboxConstants.USER_NAMESPACE)
+                    && !mailboxPath.belongsTo(session)) {
+                    sb.append("#user");
+                } else {
+                    sb.append(mailboxPath.getNamespace());
+                }
             }
             if (mailboxPath.getUser() != null && 
!mailboxPath.getUser().equals("")) {
-                if (sb.length() > 0) {
-                    sb.append(delimiter);
+                if (!mailboxPath.belongsTo(session)) {
+                    if (sb.length() > 0) {
+                        sb.append(session.getPathDelimiter());
+                    }
+                    sb.append(mailboxPath.getUser().asString());
                 }
-                sb.append(mailboxPath.getUser().asString());
             }
             if (mailboxPath.getName() != null && 
!mailboxPath.getName().equals("")) {
                 if (sb.length() > 0) {
-                    sb.append(delimiter);
+                    sb.append(session.getPathDelimiter());
                 }
                 sb.append(mailboxPath.getName());
             }
@@ -133,7 +142,7 @@ public interface PathConverter {
             if (relative && path.belongsTo(session)) {
                 return path.getName();
             } else {
-                return joinMailboxPath(path, session.getPathDelimiter());
+                return joinMailboxPath(path, session);
             }
         }
     }
diff --git 
a/protocols/imap/src/main/java/org/apache/james/imap/processor/NamespaceSupplier.java
 
b/protocols/imap/src/main/java/org/apache/james/imap/processor/NamespaceSupplier.java
index 90fe3c91ad..c706266cef 100644
--- 
a/protocols/imap/src/main/java/org/apache/james/imap/processor/NamespaceSupplier.java
+++ 
b/protocols/imap/src/main/java/org/apache/james/imap/processor/NamespaceSupplier.java
@@ -19,7 +19,7 @@ public interface NamespaceSupplier {
 
         @Override
         public Collection<Namespace> otherUsersNamespaces(MailboxSession 
session) {
-            return ImmutableList.of();
+            return ImmutableList.of(new NamespaceResponse.Namespace("#user", 
session.getPathDelimiter()));
         }
 
         @Override
diff --git 
a/protocols/imap/src/test/java/org/apache/james/imap/main/PathConverterTest.java
 
b/protocols/imap/src/test/java/org/apache/james/imap/main/PathConverterTest.java
index b98c995532..eedc447b97 100644
--- 
a/protocols/imap/src/test/java/org/apache/james/imap/main/PathConverterTest.java
+++ 
b/protocols/imap/src/test/java/org/apache/james/imap/main/PathConverterTest.java
@@ -102,6 +102,18 @@ class PathConverterTest {
             .isEqualTo(MailboxPath.forUser(USERNAME, mailboxName));
     }
 
+    @Test
+    void buildFullPathShouldAcceptAbsoluteOtherUserPath() {
+        assertThat(pathConverter.buildFullPath("#user.username2.abc"))
+            .isEqualTo(MailboxPath.forUser(USERNAME2, "abc"));
+    }
+
+    @Test
+    void buildFullPathShouldAcceptAbsoluteOtherUserPathWithSubfolder() {
+        assertThat(pathConverter.buildFullPath("#user.username2.abc.def"))
+            .isEqualTo(MailboxPath.forUser(USERNAME2, "abc.def"));
+    }
+
     @Test
     void buildFullPathShouldDenyMailboxPathNotBelongingToTheUser() {
         assertThatThrownBy(() -> pathConverter.buildFullPath("#any"))
@@ -117,7 +129,7 @@ class PathConverterTest {
     @Test
     void mailboxNameShouldReturnFQDNWhenRelativeAndOtherUserMailbox() {
         assertThat(pathConverter.mailboxName(RELATIVE, 
MailboxPath.forUser(USERNAME2, "abc"), mailboxSession))
-            .isEqualTo("#private.username2.abc");
+            .isEqualTo("#user.username2.abc");
     }
 
     @Test
@@ -129,13 +141,13 @@ class PathConverterTest {
     @Test
     void mailboxNameShouldReturnFQDNWhenNotRelativeAndUserMailbox() {
         assertThat(pathConverter.mailboxName(!RELATIVE, 
MailboxPath.forUser(USERNAME, "abc"), mailboxSession))
-            .isEqualTo("#private.username.abc");
+            .isEqualTo("#private.abc");
     }
 
     @Test
     void mailboxNameShouldReturnFQDNWhenNotRelativeAndOtherUserMailbox() {
         assertThat(pathConverter.mailboxName(!RELATIVE, 
MailboxPath.forUser(USERNAME2, "abc"), mailboxSession))
-            .isEqualTo("#private.username2.abc");
+            .isEqualTo("#user.username2.abc");
     }
 
     @Test


---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org
For additional commands, e-mail: notifications-h...@james.apache.org

Reply via email to