implement the WITHIN IMAP extension, rfc 5032

for IMAP "SEARCH" command criteria "YOUNGER" and "OLDER".
This commit is contained in:
Mechiel Lukkien 2025-02-19 21:29:14 +01:00
parent dcaa99a85c
commit 5e4d80d48e
No known key found for this signature in database
6 changed files with 23 additions and 5 deletions

View File

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

View File

@ -793,6 +793,7 @@ var searchKeyWords = []string{
"BEFORE", "BODY",
"CC", "DELETED", "FLAGGED",
"FROM", "KEYWORD",
"OLDER", "YOUNGER", // WITHIN extension, ../rfc/5032:72
"NEW", "OLD", "ON", "RECENT", "SEEN",
"SINCE", "SUBJECT",
"TEXT", "TO",
@ -933,6 +934,9 @@ func (p *parser) xsearchKey() *searchKey {
p.xspace()
sk.date = p.xdate() // ../rfc/8514:267
case "SAVEDATESUPPORTED":
case "OLDER", "YOUNGER":
p.xspace()
sk.number = int64(p.xnznumber())
default:
p.xerrorf("missing case for op %q", sk.op)
}

View File

@ -5,6 +5,7 @@ import (
"log/slog"
"net/textproto"
"strings"
"time"
"github.com/mjl-/bstore"
@ -539,6 +540,13 @@ func (s *search) match0(sk searchKey) bool {
// mailboxes, but we only have this metadata from the time we implemented this
// feature.
return s.m.SaveDate != nil
case "OLDER":
// ../rfc/5032:76
seconds := int64(time.Since(s.m.Received) / time.Second)
return seconds >= sk.number
case "YOUNGER":
seconds := int64(time.Since(s.m.Received) / time.Second)
return seconds <= sk.number
}
if s.p == nil {

View File

@ -111,6 +111,12 @@ func TestSearch(t *testing.T) {
tc.transactf("ok", "search before 1-Jan-2020")
tc.xsearch() // Before is about received, not date header of message.
// WITHIN extension with OLDER & YOUNGER.
tc.transactf("ok", "search older 60")
tc.xsearch(1, 2, 3)
tc.transactf("ok", "search younger 60")
tc.xsearch()
// SAVEDATE extension.
tc.transactf("ok", "search savedbefore %s", saveDate.Add(24*time.Hour).Format("2-Jan-2006"))
tc.xsearch(1, 2, 3)

View File

@ -160,12 +160,13 @@ var authFailDelay = time.Second // After authentication failure.
// QUOTA QUOTA=RES-STORAGE: ../rfc/9208:111
// METADATA: ../rfc/5464
// SAVEDATE: ../rfc/8514
// WITHIN: ../rfc/5032
//
// We always announce support for SCRAM PLUS-variants, also on connections without
// TLS. The client should not be selecting PLUS variants on non-TLS connections,
// instead opting to do the bare SCRAM variant without indicating the server claims
// to support the PLUS variant (skipping the server downgrade detection check).
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"
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"
type conn struct {
cid int64

View File

@ -190,7 +190,7 @@ https://www.iana.org/assignments/message-headers/message-headers.xhtml
4731 Yes - IMAP4 Extension to SEARCH Command for Controlling What Kind of Information Is Returned
4959 Yes - IMAP Extension for Simple Authentication and Security Layer (SASL) Initial Client Response
4978 Roadmap - The IMAP COMPRESS Extension
5032 Roadmap - WITHIN Search Extension to the IMAP Protocol
5032 Yes - WITHIN Search Extension to the IMAP Protocol
5092 Roadmap - IMAP URL Scheme
5161 Yes - The IMAP ENABLE Extension
5162 Yes Obs (RFC 7162) IMAP4 Extensions for Quick Mailbox Resynchronization