You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by bt...@apache.org on 2022/12/28 02:05:31 UTC
[james-project] 02/04: JAMES-3754 IMAP SEARCH for SaveDate extension
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 <hq...@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: <f4...@mail.gmail.com>
+C: Date: Sat, 2 Feb 2008 13:14:19 +0000
+C: From: "Robert Burrell Donkin" <ro...@gmail.com>
+C: To: "James Developers List" <se...@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: robertburrelldonkin@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-unsubscribe@james.apache.org
For additional commands, e-mail: notifications-help@james.apache.org