This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
The following commit(s) were added to refs/heads/master by this push: new a190bf8555 JAMES-2128 IMAP list should skip mailboxes not handled by the naming schema (#2506) a190bf8555 is described below commit a190bf855565225696b76f66b1ef0834078b7cfb Author: Benoit TELLIER <btell...@linagora.com> AuthorDate: Tue Nov 19 15:07:57 2024 +0700 JAMES-2128 IMAP list should skip mailboxes not handled by the naming schema (#2506) --- .../org/apache/james/imap/main/PathConverter.java | 9 +++-- .../apache/james/imap/processor/LSubProcessor.java | 2 +- .../apache/james/imap/processor/ListProcessor.java | 46 ++++++++++++---------- .../james/imap/processor/StatusProcessor.java | 5 ++- .../apache/james/imap/main/PathConverterTest.java | 28 ++++++------- 5 files changed, 49 insertions(+), 41 deletions(-) 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 5164f14602..7987eafd24 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 @@ -20,6 +20,7 @@ package org.apache.james.imap.main; import java.util.List; +import java.util.Optional; import org.apache.james.core.Domain; import org.apache.james.core.Username; @@ -160,11 +161,11 @@ public interface PathConverter { return sb.toString(); } - public String mailboxName(boolean relative, MailboxPath path, MailboxSession session) { + public Optional<String> mailboxName(boolean relative, MailboxPath path, MailboxSession session) { if (relative && path.belongsTo(session)) { - return path.getName(); + return Optional.of(path.getName()); } else { - return joinMailboxPath(path, session); + return Optional.of(joinMailboxPath(path, session)); } } @@ -250,7 +251,7 @@ public interface PathConverter { MailboxPath buildFullPath(String mailboxName); - String mailboxName(boolean relative, MailboxPath path, MailboxSession session); + Optional<String> mailboxName(boolean relative, MailboxPath path, MailboxSession session); MailboxQuery mailboxQuery(String finalReferencename, String mailboxName, ImapSession session); } diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/LSubProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/LSubProcessor.java index 581b0472e0..1ba7850434 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/processor/LSubProcessor.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/LSubProcessor.java @@ -81,7 +81,7 @@ public class LSubProcessor extends AbstractMailboxProcessor<LsubRequest> { try { PathConverter pathConverter = pathConverterFactory.forSession(session); Mono<List<String>> mailboxesMono = Flux.from(subscriptionManager.subscriptionsReactive(mailboxSession)) - .map(path -> pathConverter.mailboxName(RELATIVE, path, mailboxSession)) + .<String>handle((path, sink) -> pathConverter.mailboxName(RELATIVE, path, mailboxSession).ifPresent(sink::next)) .collectList(); String decodedMailName = ModifiedUtf7.decodeModifiedUTF7(referenceName); diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/ListProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/ListProcessor.java index ee3cce3edc..17c92b022a 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/processor/ListProcessor.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/ListProcessor.java @@ -213,13 +213,14 @@ public class ListProcessor<T extends ListRequest> extends AbstractMailboxProcess .doOnNext(metaData -> { MailboxType mailboxType = getMailboxType(request, session, metaData.getPath()); if (!request.getSelectOptions().contains(SPECIAL_USE) || mailboxType.getRfc6154attributeName() != null) { - responder.respond( - createResponse(metaData.inferiors(), - metaData.getSelectability(), - pathConverterFactory.forSession(session).mailboxName(isRelative, metaData.getPath(), mailboxSession), - metaData.getHierarchyDelimiter(), - mailboxType, - isSubscribed.test(metaData.getPath()))); + pathConverterFactory.forSession(session).mailboxName(isRelative, metaData.getPath(), mailboxSession) + .ifPresent(mailboxName -> responder.respond( + createResponse(metaData.inferiors(), + metaData.getSelectability(), + mailboxName, + metaData.getHierarchyDelimiter(), + mailboxType, + isSubscribed.test(metaData.getPath())))); } }) .doOnNext(metaData -> respondMyRights(request, responder, mailboxSession, metaData, isRelative)) @@ -267,23 +268,24 @@ public class ListProcessor<T extends ListRequest> extends AbstractMailboxProcess allSubscribedSearch.stream() .filter(subscribed -> !listRecursiveMatchPath.contains(subscribed)) .filter(mailboxQuery::isPathMatch) - .map(subscribed -> buildListResponse(listRequest, searchedResultMap, session, relative, subscribed)) + .flatMap(subscribed -> buildListResponse(listRequest, searchedResultMap, session, relative, subscribed).stream()) .filter(pair -> !listRequest.getSelectOptions().contains(SPECIAL_USE) || mailboxTyper.getMailboxType(session, pair.getKey()).getRfc6154attributeName() != null) .forEach(pair -> responseBuilders.add(Triple.of(pair.getLeft(), pair.getRight(), Optional.ofNullable(searchedResultMap.get(pair.getLeft()))))); return responseBuilders.build(); } - private Pair<MailboxPath, ListResponse> buildListResponse(ListRequest listRequest, Map<MailboxPath, MailboxMetaData> searchedResultMap, ImapSession session, boolean relative, MailboxPath subscribed) { - return Pair.of(subscribed, Optional.ofNullable(searchedResultMap.get(subscribed)) + private Optional<Pair<MailboxPath, ListResponse>> buildListResponse(ListRequest listRequest, Map<MailboxPath, MailboxMetaData> searchedResultMap, ImapSession session, boolean relative, MailboxPath subscribed) { + return pathConverterFactory.forSession(session).mailboxName(relative, subscribed, session.getMailboxSession()) + .map(name -> Pair.of(subscribed, Optional.ofNullable(searchedResultMap.get(subscribed)) .map(mailboxMetaData -> ListResponse.builder() .returnSubscribed(RETURN_SUBSCRIBED) .forMetaData(mailboxMetaData) - .name(pathConverterFactory.forSession(session).mailboxName(relative, subscribed, session.getMailboxSession())) + .name(name) .returnNonExistent(!RETURN_NON_EXISTENT) .mailboxType(getMailboxType(listRequest, session, mailboxMetaData.getPath()))) .orElseGet(() -> ListResponse.builder().nonExitingSubscribedMailbox(subscribed)) - .build()); + .build())); } private List<Pair<MailboxPath, ListResponse>> listRecursiveMatch(ImapSession session, Map<MailboxPath, MailboxMetaData> searchedResultMap, @@ -299,26 +301,28 @@ public class ListProcessor<T extends ListRequest> extends AbstractMailboxProcess return searchedResultMap.entrySet().stream() .filter(pair -> allSubscribedSearchParent.contains(pair.getKey())) - .map(pair -> { + .flatMap(pair -> { MailboxMetaData metaData = pair.getValue(); - ListResponse listResponse = ListResponse.builder() + Optional<String> maybeMailboxName = pathConverterFactory.forSession(session).mailboxName(relative, metaData.getPath(), mailboxSession); + return maybeMailboxName.map(mailboxName -> Pair.of(pair.getKey(), ListResponse.builder() .forMetaData(metaData) - .name(pathConverterFactory.forSession(session).mailboxName(relative, metaData.getPath(), mailboxSession)) + .name(mailboxName) .childInfos(ListResponse.ChildInfo.SUBSCRIBED) .returnSubscribed(allSubscribedSearch.contains(pair.getKey())) .mailboxType(getMailboxType(listRequest, session, metaData.getPath())) - .build(); - return Pair.of(pair.getKey(), listResponse); + .build())) + .stream(); }) .collect(Collectors.toList()); } private void respondMyRights(T request, Responder responder, MailboxSession mailboxSession, MailboxMetaData metaData, boolean isRelative) { if (request.getReturnOptions().contains(ListRequest.ListReturnOption.MYRIGHTS)) { - MailboxName mailboxName = new MailboxName(pathConverterFactory.forSession(mailboxSession) - .mailboxName(isRelative, metaData.getPath(), mailboxSession)); - MyRightsResponse myRightsResponse = new MyRightsResponse(mailboxName, getRfc4314Rights(mailboxSession, metaData)); - responder.respond(myRightsResponse); + pathConverterFactory.forSession(mailboxSession) + .mailboxName(isRelative, metaData.getPath(), mailboxSession) + .map(MailboxName::new) + .map(mailboxName -> new MyRightsResponse(mailboxName, getRfc4314Rights(mailboxSession, metaData))) + .ifPresent(responder::respond); } } diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/StatusProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/StatusProcessor.java index bade56b99b..2c8d0ac79c 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/processor/StatusProcessor.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/StatusProcessor.java @@ -186,12 +186,15 @@ public class StatusProcessor extends AbstractMailboxProcessor<StatusRequest> imp Long unseen = unseen(statusDataItems, metaData); ModSeq highestModSeq = highestModSeq(statusDataItems, metaData); MailboxId mailboxId = mailboxId(statusDataItems, mailbox); + String mailboxName = pathConverterFactory.forSession(mailboxSession) + .mailboxName(RELATIVE, mailbox.getMailboxPath(), mailboxSession) + .orElseThrow(() -> new RuntimeException("Not exposed mailbox")); return new MailboxStatusResponse( appendLimit, maybeIterationResult.flatMap(result -> result.getSize(statusDataItems)).orElse(null), maybeIterationResult.flatMap(result -> result.getDeleted(statusDataItems)).orElse(null), maybeIterationResult.flatMap(result -> result.getDeletedStorage(statusDataItems)).orElse(null), - messages, recent, uidNext, highestModSeq, uidValidity, unseen, pathConverterFactory.forSession(mailboxSession).mailboxName(RELATIVE, mailbox.getMailboxPath(), mailboxSession), mailboxId); + messages, recent, uidNext, highestModSeq, uidValidity, unseen, mailboxName, mailboxId); }); } 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 02a9a12807..3541ad53e3 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 @@ -137,49 +137,49 @@ class PathConverterTest { @Test void mailboxNameShouldReturnNameOnlyWhenRelativeAndUserMailbox() { assertThat(pathConverter.mailboxName(RELATIVE, MailboxPath.forUser(USERNAME, "abc"), mailboxSession)) - .isEqualTo("abc"); + .contains("abc"); } @Test void mailboxNameShouldReturnFQDNWhenRelativeAndOtherUserMailbox() { assertThat(pathConverter.mailboxName(RELATIVE, MailboxPath.forUser(USERNAME2, "abc"), mailboxSession)) - .isEqualTo("#user.username2.abc"); + .contains("#user.username2.abc"); } @Test void mailboxNameShouldEscapeDotInUsername() { assertThat(pathConverter.mailboxName(RELATIVE, MailboxPath.forUser(USERNAME_WITH_DOT, "abc"), mailboxSession)) - .isEqualTo("#user.username__with__dot.abc"); + .contains("#user.username__with__dot.abc"); } @Test void mailboxNameShouldEscapeUnderscoreInUsername() { assertThat(pathConverter.mailboxName(RELATIVE, MailboxPath.forUser(USERNAME_WITH_UNDERSCORE, "abc"), mailboxSession)) - .isEqualTo("#user.username_-with_-underscore.abc"); + .contains("#user.username_-with_-underscore.abc"); } @Test void mailboxNameShouldReturnFQDNWhenRelativeAndSharedMailbox() { assertThat(pathConverter.mailboxName(RELATIVE, new MailboxPath("#Shared", Username.of("marketing"), "abc"), mailboxSession)) - .isEqualTo("#Shared.marketing.abc"); + .contains("#Shared.marketing.abc"); } @Test void mailboxNameShouldReturnFQDNWhenNotRelativeAndUserMailbox() { assertThat(pathConverter.mailboxName(!RELATIVE, MailboxPath.forUser(USERNAME, "abc"), mailboxSession)) - .isEqualTo("#private.abc"); + .contains("#private.abc"); } @Test void mailboxNameShouldReturnFQDNWhenNotRelativeAndOtherUserMailbox() { assertThat(pathConverter.mailboxName(!RELATIVE, MailboxPath.forUser(USERNAME2, "abc"), mailboxSession)) - .isEqualTo("#user.username2.abc"); + .contains("#user.username2.abc"); } @Test void mailboxNameShouldReturnFQDNWhenNotRelativeAndSharedMailbox() { assertThat(pathConverter.mailboxName(!RELATIVE, new MailboxPath("#Shared", Username.of("marketing"), "abc"), mailboxSession)) - .isEqualTo("#Shared.marketing.abc"); + .contains("#Shared.marketing.abc"); } @Nested @@ -257,37 +257,37 @@ class PathConverterTest { @Test void mailboxNameShouldReturnNameOnlyWhenRelativeAndUserMailbox() { assertThat(pathConverter.mailboxName(RELATIVE, MailboxPath.forUser(USERNAME_WITH_MAIL, "abc"), mailboxSession)) - .isEqualTo("abc"); + .contains("abc"); } @Test void mailboxNameShouldReturnFQDNWhenRelativeAndOtherUserMailbox() { assertThat(pathConverter.mailboxName(RELATIVE, MailboxPath.forUser(USERNAME2_WITH_MAIL, "abc"), mailboxSession)) - .isEqualTo("#user.username2.abc"); + .contains("#user.username2.abc"); } @Test void mailboxNameShouldReturnFQDNWhenRelativeAndSharedMailbox() { assertThat(pathConverter.mailboxName(RELATIVE, new MailboxPath("#Shared", Username.of("market...@apache.org"), "abc"), mailboxSession)) - .isEqualTo("#Shared.marketing.abc"); + .contains("#Shared.marketing.abc"); } @Test void mailboxNameShouldReturnFQDNWhenNotRelativeAndUserMailbox() { assertThat(pathConverter.mailboxName(!RELATIVE, MailboxPath.forUser(USERNAME_WITH_MAIL, "abc"), mailboxSession)) - .isEqualTo("#private.abc"); + .contains("#private.abc"); } @Test void mailboxNameShouldReturnFQDNWhenNotRelativeAndOtherUserMailbox() { assertThat(pathConverter.mailboxName(!RELATIVE, MailboxPath.forUser(USERNAME2_WITH_MAIL, "abc"), mailboxSession)) - .isEqualTo("#user.username2.abc"); + .contains("#user.username2.abc"); } @Test void mailboxNameShouldReturnFQDNWhenNotRelativeAndSharedMailbox() { assertThat(pathConverter.mailboxName(!RELATIVE, new MailboxPath("#Shared", Username.of("market...@apache.org"), "abc"), mailboxSession)) - .isEqualTo("#Shared.marketing.abc"); + .contains("#Shared.marketing.abc"); } } } --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org