Skip to content

Commit 5e4d80d

Browse files
committed
implement the WITHIN IMAP extension, rfc 5032
for IMAP "SEARCH" command criteria "YOUNGER" and "OLDER".
1 parent dcaa99a commit 5e4d80d

File tree

6 files changed

+23
-5
lines changed

6 files changed

+23
-5
lines changed

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,8 @@ https://nlnet.nl/project/Mox/.
138138
- "mox setup" command, with webapp for interactive setup
139139
- Automate DNS management, for setup and maintenance, such as DANE/DKIM key rotation.
140140
- Calendaring with CalDAV/iCal
141-
- More IMAP extensions (PREVIEW, WITHIN, IMPORTANT, COMPRESS=DEFLATE,
142-
CREATE-SPECIAL-USE, SAVEDATE, UNAUTHENTICATE, REPLACE, QUOTA, NOTIFY,
143-
MULTIAPPEND, OBJECTID, MULTISEARCH, THREAD, SORT)
141+
- More IMAP extensions (PREVIEW, IMPORTANT, COMPRESS=DEFLATE, UNAUTHENTICATE,
142+
REPLACE, QUOTA, NOTIFY, MULTIAPPEND, OBJECTID, MULTISEARCH, THREAD, SORT)
144143
- Introbox, to which first-time senders are delivered
145144
- ARC, with forwarded email from trusted source
146145
- Add special IMAP mailbox ("Queue?") that contains queued but

imapserver/parse.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,7 @@ var searchKeyWords = []string{
793793
"BEFORE", "BODY",
794794
"CC", "DELETED", "FLAGGED",
795795
"FROM", "KEYWORD",
796+
"OLDER", "YOUNGER", // WITHIN extension, ../rfc/5032:72
796797
"NEW", "OLD", "ON", "RECENT", "SEEN",
797798
"SINCE", "SUBJECT",
798799
"TEXT", "TO",
@@ -933,6 +934,9 @@ func (p *parser) xsearchKey() *searchKey {
933934
p.xspace()
934935
sk.date = p.xdate() // ../rfc/8514:267
935936
case "SAVEDATESUPPORTED":
937+
case "OLDER", "YOUNGER":
938+
p.xspace()
939+
sk.number = int64(p.xnznumber())
936940
default:
937941
p.xerrorf("missing case for op %q", sk.op)
938942
}

imapserver/search.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"log/slog"
66
"net/textproto"
77
"strings"
8+
"time"
89

910
"github.com/mjl-/bstore"
1011

@@ -539,6 +540,13 @@ func (s *search) match0(sk searchKey) bool {
539540
// mailboxes, but we only have this metadata from the time we implemented this
540541
// feature.
541542
return s.m.SaveDate != nil
543+
case "OLDER":
544+
// ../rfc/5032:76
545+
seconds := int64(time.Since(s.m.Received) / time.Second)
546+
return seconds >= sk.number
547+
case "YOUNGER":
548+
seconds := int64(time.Since(s.m.Received) / time.Second)
549+
return seconds <= sk.number
542550
}
543551

544552
if s.p == nil {

imapserver/search_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ func TestSearch(t *testing.T) {
111111
tc.transactf("ok", "search before 1-Jan-2020")
112112
tc.xsearch() // Before is about received, not date header of message.
113113

114+
// WITHIN extension with OLDER & YOUNGER.
115+
tc.transactf("ok", "search older 60")
116+
tc.xsearch(1, 2, 3)
117+
tc.transactf("ok", "search younger 60")
118+
tc.xsearch()
119+
114120
// SAVEDATE extension.
115121
tc.transactf("ok", "search savedbefore %s", saveDate.Add(24*time.Hour).Format("2-Jan-2006"))
116122
tc.xsearch(1, 2, 3)

imapserver/server.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,13 @@ var authFailDelay = time.Second // After authentication failure.
160160
// QUOTA QUOTA=RES-STORAGE: ../rfc/9208:111
161161
// METADATA: ../rfc/5464
162162
// SAVEDATE: ../rfc/8514
163+
// WITHIN: ../rfc/5032
163164
//
164165
// We always announce support for SCRAM PLUS-variants, also on connections without
165166
// TLS. The client should not be selecting PLUS variants on non-TLS connections,
166167
// instead opting to do the bare SCRAM variant without indicating the server claims
167168
// to support the PLUS variant (skipping the server downgrade detection check).
168-
const serverCapabilities = "IMAP4rev2 IMAP4rev1 ENABLE LITERAL+ IDLE SASL-IR BINARY UNSELECT UIDPLUS ESEARCH SEARCHRES MOVE UTF8=ACCEPT LIST-EXTENDED SPECIAL-USE CREATE-SPECIAL-USE LIST-STATUS AUTH=SCRAM-SHA-256-PLUS AUTH=SCRAM-SHA-256 AUTH=SCRAM-SHA-1-PLUS AUTH=SCRAM-SHA-1 AUTH=CRAM-MD5 ID APPENDLIMIT=9223372036854775807 CONDSTORE QRESYNC STATUS=SIZE QUOTA QUOTA=RES-STORAGE METADATA SAVEDATE"
169+
const serverCapabilities = "IMAP4rev2 IMAP4rev1 ENABLE LITERAL+ IDLE SASL-IR BINARY UNSELECT UIDPLUS ESEARCH SEARCHRES MOVE UTF8=ACCEPT LIST-EXTENDED SPECIAL-USE CREATE-SPECIAL-USE LIST-STATUS AUTH=SCRAM-SHA-256-PLUS AUTH=SCRAM-SHA-256 AUTH=SCRAM-SHA-1-PLUS AUTH=SCRAM-SHA-1 AUTH=CRAM-MD5 ID APPENDLIMIT=9223372036854775807 CONDSTORE QRESYNC STATUS=SIZE QUOTA QUOTA=RES-STORAGE METADATA SAVEDATE WITHIN"
169170

170171
type conn struct {
171172
cid int64

rfc/index.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ https://www.iana.org/assignments/message-headers/message-headers.xhtml
190190
4731 Yes - IMAP4 Extension to SEARCH Command for Controlling What Kind of Information Is Returned
191191
4959 Yes - IMAP Extension for Simple Authentication and Security Layer (SASL) Initial Client Response
192192
4978 Roadmap - The IMAP COMPRESS Extension
193-
5032 Roadmap - WITHIN Search Extension to the IMAP Protocol
193+
5032 Yes - WITHIN Search Extension to the IMAP Protocol
194194
5092 Roadmap - IMAP URL Scheme
195195
5161 Yes - The IMAP ENABLE Extension
196196
5162 Yes Obs (RFC 7162) IMAP4 Extensions for Quick Mailbox Resynchronization

0 commit comments

Comments
 (0)