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
commit 4cf94690e9731dbadc34afd5794fd4883ba3ca37 Author: Quan Tran <hqt...@linagora.com> AuthorDate: Thu Dec 8 13:35:46 2022 +0700 JAMES-3754 IMAP SEARCH for SaveDate extension --- .../james/mpt/imapmailbox/suite/SelectedState.java | 6 ++ .../apache/james/imap/scripts/SearchSaveDate.test | 53 ++++++++++++++++++ .../mpt/imapmailbox/jpa/JpaSelectedStateTest.java | 6 ++ .../james/imap/api/message/request/SearchKey.java | 28 +++++++++- .../imap/decode/parser/SearchCommandParser.java | 65 ++++++++++++++++++++++ .../james/imap/processor/SearchProcessor.java | 8 +++ .../james/imap/processor/SearchProcessorTest.java | 25 +++++++++ 7 files changed, 189 insertions(+), 2 deletions(-) diff --git a/mpt/impl/imap-mailbox/core/src/main/java/org/apache/james/mpt/imapmailbox/suite/SelectedState.java b/mpt/impl/imap-mailbox/core/src/main/java/org/apache/james/mpt/imapmailbox/suite/SelectedState.java index f699880cd7..9b49406980 100644 --- a/mpt/impl/imap-mailbox/core/src/main/java/org/apache/james/mpt/imapmailbox/suite/SelectedState.java +++ b/mpt/impl/imap-mailbox/core/src/main/java/org/apache/james/mpt/imapmailbox/suite/SelectedState.java @@ -255,4 +255,10 @@ public abstract class SelectedState implements ImapTestConstants { .withLocale(Locale.KOREA) .run("Namespace"); } + + @Test + public void testSearchSaveDate() throws Exception { + simpleScriptedTestProtocol + .run("SearchSaveDate"); + } } diff --git a/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/SearchSaveDate.test b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/SearchSaveDate.test new file mode 100644 index 0000000000..f14e857772 --- /dev/null +++ b/mpt/impl/imap-mailbox/core/src/main/resources/org/apache/james/imap/scripts/SearchSaveDate.test @@ -0,0 +1,53 @@ +################################################################ +# Licensed to the Apache Software Foundation (ASF) under one # +# or more contributor license agreements. See the NOTICE file # +# distributed with this work for additional information # +# regarding copyright ownership. The ASF licenses this file # +# to you under the Apache License, Version 2.0 (the # +# "License"); you may not use this file except in compliance # +# with the License. You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, # +# software distributed under the License is distributed on an # +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # +# KIND, either express or implied. See the License for the # +# specific language governing permissions and limitations # +# under the License. # +################################################################ +C: f CREATE anothermailbox +S: f OK \[MAILBOXID \(.+\)\] CREATE completed\. +C: g APPEND anothermailbox {704+} +C: Received: by 10.114.81.13 with HTTP; Sat, 2 Feb 2008 05:14:19 -0800 (PST) +C: Message-ID: <f470f68e0802020514m6eaba233u96a9021a2697a...@mail.gmail.com> +C: Date: Sat, 2 Feb 2008 13:14:19 +0000 +C: From: "Robert Burrell Donkin" <robertburrelldon...@gmail.com> +C: To: "James Developers List" <server-...@james.apache.org> +C: Subject: JCR -> trunk ...? +C: MIME-Version: 1.0 +C: Content-Type: text/plain; charset=ISO-8859-1 +C: Content-Transfer-Encoding: 7bit +C: Content-Disposition: inline +C: Delivered-To: robertburrelldon...@gmail.com +C: +C: i'd like to copy james-jcr into trunk and add some example +C: configurations. development can continue in the sandbox (or not) and +C: merged in later (if necessary). +C: +C: any objections? +C: +C: - robert +S: g OK (\[.+\] )?APPEND completed\. +C: f SEARCH SAVEDON 28-Dec-2014 +S: \* SEARCH +S: f OK SEARCH completed. +C: g SEARCH SAVEDBEFORE 28-Dec-2014 +S: \* SEARCH +S: g OK SEARCH completed. +C: g SEARCH SAVEDSINCE 28-Dec-2014 +S: \* SEARCH 1 2 3 4 +S: g OK SEARCH completed. +C: g SEARCH SAVEDATESUPPORTED +S: \* SEARCH 1 2 3 4 +S: g OK SEARCH completed. \ No newline at end of file diff --git a/mpt/impl/imap-mailbox/jpa/src/test/java/org/apache/james/mpt/imapmailbox/jpa/JpaSelectedStateTest.java b/mpt/impl/imap-mailbox/jpa/src/test/java/org/apache/james/mpt/imapmailbox/jpa/JpaSelectedStateTest.java index 6cdd380fb9..099c3d3d4d 100644 --- a/mpt/impl/imap-mailbox/jpa/src/test/java/org/apache/james/mpt/imapmailbox/jpa/JpaSelectedStateTest.java +++ b/mpt/impl/imap-mailbox/jpa/src/test/java/org/apache/james/mpt/imapmailbox/jpa/JpaSelectedStateTest.java @@ -22,6 +22,7 @@ package org.apache.james.mpt.imapmailbox.jpa; import org.apache.james.mpt.api.ImapHostSystem; import org.apache.james.mpt.imapmailbox.jpa.host.JPAHostSystemExtension; import org.apache.james.mpt.imapmailbox.suite.SelectedState; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.extension.RegisterExtension; public class JpaSelectedStateTest extends SelectedState { @@ -56,4 +57,9 @@ public class JpaSelectedStateTest extends SelectedState { @Override public void testUidUS() { } + + @Override + @Disabled("SEARCH save date just return empty result for JPA") + public void testSearchSaveDate() { + } } diff --git a/protocols/imap/src/main/java/org/apache/james/imap/api/message/request/SearchKey.java b/protocols/imap/src/main/java/org/apache/james/imap/api/message/request/SearchKey.java index c052cca700..6da831c86f 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/api/message/request/SearchKey.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/api/message/request/SearchKey.java @@ -42,6 +42,10 @@ import static org.apache.james.imap.api.message.request.SearchKey.Type.TYPE_OLDE import static org.apache.james.imap.api.message.request.SearchKey.Type.TYPE_ON; import static org.apache.james.imap.api.message.request.SearchKey.Type.TYPE_OR; import static org.apache.james.imap.api.message.request.SearchKey.Type.TYPE_RECENT; +import static org.apache.james.imap.api.message.request.SearchKey.Type.TYPE_SAVEDATESUPPORTED; +import static org.apache.james.imap.api.message.request.SearchKey.Type.TYPE_SAVEDBEFORE; +import static org.apache.james.imap.api.message.request.SearchKey.Type.TYPE_SAVEDON; +import static org.apache.james.imap.api.message.request.SearchKey.Type.TYPE_SAVEDSINCE; import static org.apache.james.imap.api.message.request.SearchKey.Type.TYPE_SEEN; import static org.apache.james.imap.api.message.request.SearchKey.Type.TYPE_SENTBEFORE; import static org.apache.james.imap.api.message.request.SearchKey.Type.TYPE_SENTON; @@ -121,7 +125,11 @@ public final class SearchKey { TYPE_OLDER, TYPE_MODSEQ, TYPE_THREADID, - TYPE_EMAILID + TYPE_EMAILID, + TYPE_SAVEDBEFORE, + TYPE_SAVEDON, + TYPE_SAVEDSINCE, + TYPE_SAVEDATESUPPORTED } private static final SearchKey UNSEEN = new SearchKey(TYPE_UNSEEN, null, null, 0, null, null, null, null, -1, -1, null, null); @@ -282,10 +290,18 @@ public final class SearchKey { return new SearchKey(TYPE_ON, date, null, 0, null, null, null, null, -1, -1, null, null); } + public static SearchKey buildSavedOn(DayMonthYear date) { + return new SearchKey(TYPE_SAVEDON, date, null, 0, null, null, null, null, -1, -1, null, null); + } + public static SearchKey buildSentBefore(DayMonthYear date) { return new SearchKey(TYPE_SENTBEFORE, date, null, 0, null, null, null, null, -1, -1, null, null); } + public static SearchKey buildSavedBefore(DayMonthYear date) { + return new SearchKey(TYPE_SAVEDBEFORE, date, null, 0, null, null, null, null, -1, -1, null, null); + } + public static SearchKey buildSentOn(DayMonthYear date) { return new SearchKey(TYPE_SENTON, date, null, 0, null, null, null, null, -1, -1, null, null); } @@ -298,6 +314,14 @@ public final class SearchKey { return new SearchKey(TYPE_SINCE, date, null, 0, null, null, null, null, -1, -1, null, null); } + public static SearchKey buildSavedSince(DayMonthYear date) { + return new SearchKey(TYPE_SAVEDSINCE, date, null, 0, null, null, null, null, -1, -1, null, null); + } + + public static SearchKey buildSaveDateSupported() { + return new SearchKey(TYPE_SAVEDATESUPPORTED, null, null, 0, null, null, null, null, -1, -1, null, null); + } + // FIELD VALUE public static SearchKey buildHeader(String name, String value) { return new SearchKey(TYPE_HEADER, null, null, 0, name, value, null, null, -1, -1, null, null); @@ -393,7 +417,7 @@ public final class SearchKey { * Gets a date value to be search upon. * * @return the date when: TYPE_BEFORE, TYPE_ON, - * TYPE_SENTBEFORE, TYPE_SENTON, TYPE_SENTSINCE, TYPE_SINCE, otherwise null + * TYPE_SENTBEFORE, TYPE_SENTON, TYPE_SENTSINCE, TYPE_SINCE, TYPE_SAVEBEFORE, TYPE_SAVEON, TYPE_SAVESINCE otherwise null */ public DayMonthYear getDate() { return date; diff --git a/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/SearchCommandParser.java b/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/SearchCommandParser.java index e4e898d330..c5a80e46cd 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/SearchCommandParser.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/decode/parser/SearchCommandParser.java @@ -291,6 +291,8 @@ public class SearchCommandParser extends AbstractUidCommandParser { return smaller(request); case 'U': return subject(request, charset); + case 'A': + return saved(request); default: throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unknown search key"); } @@ -332,6 +334,26 @@ public class SearchCommandParser extends AbstractUidCommandParser { } } + private SearchKey saved(ImapRequestLineReader request) throws DecodingException { + nextIsV(request); + nextIsE(request); + nextIsD(request); + + final int next = consumeAndCap(request); + switch (next) { + case 'A': + return saveDateSupported(request); + case 'B': + return savedBefore(request); + case 'O': + return savedOn(request); + case 'S': + return savedSince(request); + default: + throw new DecodingException(HumanReadableText.ILLEGAL_ARGUMENTS, "Unknown search key"); + } + } + private SearchKey o(ImapSession session, ImapRequestLineReader request, Context context) throws DecodingException { final int next = consumeAndCap(request); switch (next) { @@ -668,6 +690,16 @@ public class SearchCommandParser extends AbstractUidCommandParser { return result; } + private SearchKey savedBefore(ImapRequestLineReader request) throws DecodingException { + nextIsE(request); + nextIsF(request); + nextIsO(request); + nextIsR(request); + nextIsE(request); + nextIsSpace(request); + return SearchKey.buildSavedBefore(request.date()); + } + private SearchKey sentSince(ImapRequestLineReader request) throws DecodingException { final SearchKey result; nextIsI(request); @@ -680,6 +712,30 @@ public class SearchCommandParser extends AbstractUidCommandParser { return result; } + private SearchKey savedSince(ImapRequestLineReader request) throws DecodingException { + nextIsI(request); + nextIsN(request); + nextIsC(request); + nextIsE(request); + nextIsSpace(request); + return SearchKey.buildSavedSince(request.date()); + } + + private SearchKey saveDateSupported(ImapRequestLineReader request) throws DecodingException { + nextIsT(request); + nextIsE(request); + nextIsS(request); + nextIsU(request); + nextIsP(request); + nextIsP(request); + nextIsO(request); + nextIsR(request); + nextIsT(request); + nextIsE(request); + nextIsD(request); + return SearchKey.buildSaveDateSupported(); + } + private SearchKey since(ImapRequestLineReader request) throws DecodingException { final SearchKey result; nextIsN(request); @@ -700,6 +756,12 @@ public class SearchCommandParser extends AbstractUidCommandParser { return result; } + private SearchKey savedOn(ImapRequestLineReader request) throws DecodingException { + nextIsN(request); + nextIsSpace(request); + return SearchKey.buildSavedOn(request.date()); + } + private SearchKey before(ImapRequestLineReader request) throws DecodingException { final SearchKey result; nextIsF(request); @@ -912,6 +974,9 @@ public class SearchCommandParser extends AbstractUidCommandParser { nextIs(request, 'L', 'l'); } + private void nextIsP(ImapRequestLineReader request) throws DecodingException { + nextIs(request, 'P', 'p'); + } private void nextIsV(ImapRequestLineReader request) throws DecodingException { nextIs(request, 'V', 'v'); diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/SearchProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/SearchProcessor.java index eb3ea375f2..3ab4073b44 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/processor/SearchProcessor.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/SearchProcessor.java @@ -380,6 +380,14 @@ public class SearchProcessor extends AbstractMailboxProcessor<SearchRequest> imp return SearchQuery.threadId(ThreadId.fromBaseMessageId(getMailboxManager().getMessageIdFactory().fromString(key.getThreadId()))); case TYPE_EMAILID: return SearchQuery.hasMessageId(getMailboxManager().getMessageIdFactory().fromString(key.getMessageId())); + case TYPE_SAVEDBEFORE: + return SearchQuery.saveDateBefore(date.toDate(), DateResolution.Day); + case TYPE_SAVEDON: + return SearchQuery.saveDateOn(date.toDate(), DateResolution.Day); + case TYPE_SAVEDSINCE: + return SearchQuery.or(SearchQuery.saveDateOn(date.toDate(), DateResolution.Day), SearchQuery.saveDateAfter(date.toDate(), DateResolution.Day)); + case TYPE_SAVEDATESUPPORTED: + return SearchQuery.saveDateSupported(); default: LOGGER.warn("Ignoring unknown search key {}", type); return SearchQuery.all(); diff --git a/protocols/imap/src/test/java/org/apache/james/imap/processor/SearchProcessorTest.java b/protocols/imap/src/test/java/org/apache/james/imap/processor/SearchProcessorTest.java index 477e3c64ac..8658605fde 100644 --- a/protocols/imap/src/test/java/org/apache/james/imap/processor/SearchProcessorTest.java +++ b/protocols/imap/src/test/java/org/apache/james/imap/processor/SearchProcessorTest.java @@ -238,6 +238,12 @@ public class SearchProcessorTest { .internalDateBefore(getDate(DAY, MONTH, YEAR), DateResolution.Day)); } + @Test + void testSAVEDBEFORE() throws Exception { + expectsGetSelectedMailbox(); + check(SearchKey.buildSavedBefore(DAY_MONTH_YEAR), SearchQuery.saveDateBefore(getDate(DAY, MONTH, YEAR), DateResolution.Day)); + } + @Test void testBODY() throws Exception { expectsGetSelectedMailbox(); @@ -326,6 +332,12 @@ public class SearchProcessorTest { DAY, MONTH, YEAR), DateResolution.Day)); } + @Test + void testSAVEDON() throws Exception { + expectsGetSelectedMailbox(); + check(SearchKey.buildSavedOn(DAY_MONTH_YEAR), SearchQuery.saveDateOn(getDate(DAY, MONTH, YEAR), DateResolution.Day)); + } + @Test void testAND() throws Exception { expectsGetSelectedMailbox(); @@ -390,6 +402,19 @@ public class SearchProcessorTest { .internalDateAfter(getDate(DAY, MONTH, YEAR), DateResolution.Day))); } + @Test + void testSAVEDSINCE() throws Exception { + expectsGetSelectedMailbox(); + check(SearchKey.buildSavedSince(DAY_MONTH_YEAR), SearchQuery.or(SearchQuery.saveDateOn(getDate(DAY, MONTH, YEAR), DateResolution.Day), + SearchQuery.saveDateAfter(getDate(DAY, MONTH, YEAR), DateResolution.Day))); + } + + @Test + void testSAVEDATESUPPORTED() throws Exception { + expectsGetSelectedMailbox(); + check(SearchKey.buildSaveDateSupported(), SearchQuery.saveDateSupported()); + } + @Test void testSMALLER() throws Exception { expectsGetSelectedMailbox(); --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@james.apache.org For additional commands, e-mail: notifications-h...@james.apache.org