implement the imap metadata extension, rfc 5464

this allows setting per-mailbox and per-server annotations (metadata). we have
a fixed maximum for total number of annotations (1000) and their total size
(1000000 bytes). this size isn't held against the regular quota for simplicity.
we send unsolicited metadata responses when a connection is in the idle
command and a change to a metadata item is made.

we currently only implement the /private/ namespace.  we should implement the
/shared/ namespace, for mox-global metadata annotations.  only the admin should
be able to configure those, probably through the config file, cli, or admin web
interface.

for issue #290
This commit is contained in:
Mechiel Lukkien
2025-02-17 22:44:51 +01:00
parent 9dff879164
commit f30c44eddb
17 changed files with 820 additions and 41 deletions

View File

@ -10,27 +10,29 @@ import (
type Capability string
const (
CapIMAP4rev1 Capability = "IMAP4rev1"
CapIMAP4rev2 Capability = "IMAP4rev2"
CapLoginDisabled Capability = "LOGINDISABLED"
CapStarttls Capability = "STARTTLS"
CapAuthPlain Capability = "AUTH=PLAIN"
CapLiteralPlus Capability = "LITERAL+"
CapLiteralMinus Capability = "LITERAL-"
CapIdle Capability = "IDLE"
CapNamespace Capability = "NAMESPACE"
CapBinary Capability = "BINARY"
CapUnselect Capability = "UNSELECT"
CapUidplus Capability = "UIDPLUS"
CapEsearch Capability = "ESEARCH"
CapEnable Capability = "ENABLE"
CapSave Capability = "SAVE"
CapListExtended Capability = "LIST-EXTENDED"
CapSpecialUse Capability = "SPECIAL-USE"
CapMove Capability = "MOVE"
CapUTF8Only Capability = "UTF8=ONLY"
CapUTF8Accept Capability = "UTF8=ACCEPT"
CapID Capability = "ID" // ../rfc/2971:80
CapIMAP4rev1 Capability = "IMAP4rev1"
CapIMAP4rev2 Capability = "IMAP4rev2"
CapLoginDisabled Capability = "LOGINDISABLED"
CapStarttls Capability = "STARTTLS"
CapAuthPlain Capability = "AUTH=PLAIN"
CapLiteralPlus Capability = "LITERAL+"
CapLiteralMinus Capability = "LITERAL-"
CapIdle Capability = "IDLE"
CapNamespace Capability = "NAMESPACE"
CapBinary Capability = "BINARY"
CapUnselect Capability = "UNSELECT"
CapUidplus Capability = "UIDPLUS"
CapEsearch Capability = "ESEARCH"
CapEnable Capability = "ENABLE"
CapSave Capability = "SAVE"
CapListExtended Capability = "LIST-EXTENDED"
CapSpecialUse Capability = "SPECIAL-USE"
CapMove Capability = "MOVE"
CapUTF8Only Capability = "UTF8=ONLY"
CapUTF8Accept Capability = "UTF8=ACCEPT"
CapID Capability = "ID" // ../rfc/2971:80
CapMetadata Capability = "METADATA" // ../rfc/5464:124
CapMetadataServer Capability = "METADATA-SERVER" // ../rfc/5464:124
)
// Status is the tagged final result of a command.
@ -227,6 +229,27 @@ type UntaggedStatus struct {
Attrs map[StatusAttr]int64 // Upper case status attributes.
}
// ../rfc/5464:716 Unsolicited response, indicating an annotation has changed.
type UntaggedMetadataKeys struct {
Mailbox string // Empty means not specific to mailbox.
// Keys that have changed. To get values (or determine absence), the server must be
// queried.
Keys []string
}
type Annotation struct {
Key string
IsString bool
Value []byte
}
// ../rfc/5464:683
type UntaggedMetadataAnnotations struct {
Mailbox string // Empty means not specific to mailbox.
Annotations []Annotation
}
// ../rfc/9051:7059 ../9208:712
type StatusAttr string