mirror of
https://github.com/mjl-/mox.git
synced 2025-07-14 17:34:37 +03:00
imapserver: implement rfc 9590, returning metadata in the extended list command
only with "return" including "metadata". so clients can quickly get certain metadata (eg for display, such as a color) for mailboxes. this also adds a protocol token type "mailboxt" that properly encodes to utf7 if required.
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
package imapserver
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"path"
|
||||
"sort"
|
||||
@ -60,6 +61,7 @@ func (c *conn) cmdList(tag, cmd string, p *parser) {
|
||||
isExtended = isExtended || isList
|
||||
var retSubscribed, retChildren bool
|
||||
var retStatusAttrs []string
|
||||
var retMetadata []string
|
||||
if p.take(" RETURN (") {
|
||||
isExtended = true
|
||||
// ../rfc/9051:6613 ../rfc/9051:6915 ../rfc/9051:7072 ../rfc/9051:6821 ../rfc/5819:95
|
||||
@ -90,6 +92,18 @@ func (c *conn) cmdList(tag, cmd string, p *parser) {
|
||||
retStatusAttrs = append(retStatusAttrs, p.xstatusAtt())
|
||||
}
|
||||
p.xtake(")")
|
||||
case "METADATA":
|
||||
// ../rfc/9590:167
|
||||
p.xspace()
|
||||
p.xtake("(")
|
||||
for {
|
||||
s := p.xmetadataKey()
|
||||
retMetadata = append(retMetadata, s)
|
||||
if !p.space() {
|
||||
break
|
||||
}
|
||||
}
|
||||
p.xtake(")")
|
||||
default:
|
||||
// ../rfc/9051:2398
|
||||
xsyntaxErrorf("bad list return option %q", w)
|
||||
@ -117,6 +131,7 @@ func (c *conn) cmdList(tag, cmd string, p *parser) {
|
||||
}
|
||||
re := xmailboxPatternMatcher(reference, patterns)
|
||||
var responseLines []string
|
||||
var respMetadata []concatspace
|
||||
|
||||
c.account.WithRLock(func() {
|
||||
c.xdbread(func(tx *bstore.Tx) {
|
||||
@ -208,12 +223,34 @@ func (c *conn) cmdList(tag, cmd string, p *parser) {
|
||||
if extended != nil {
|
||||
extStr = " " + extended.pack(c)
|
||||
}
|
||||
line := fmt.Sprintf(`* LIST %s "/" %s%s`, flags.pack(c), astring(c.encodeMailbox(name)).pack(c), extStr)
|
||||
line := fmt.Sprintf(`* LIST %s "/" %s%s`, flags.pack(c), mailboxt(name).pack(c), extStr)
|
||||
responseLines = append(responseLines, line)
|
||||
|
||||
if retStatusAttrs != nil && info.mailbox != nil {
|
||||
responseLines = append(responseLines, c.xstatusLine(tx, *info.mailbox, retStatusAttrs))
|
||||
}
|
||||
|
||||
// ../rfc/9590:101
|
||||
if info.mailbox != nil && len(retMetadata) > 0 {
|
||||
var meta listspace
|
||||
for _, k := range retMetadata {
|
||||
a, err := bstore.QueryTx[store.Annotation](tx).FilterNonzero(store.Annotation{MailboxID: info.mailbox.ID, Key: k}).Get()
|
||||
var v token
|
||||
if err == bstore.ErrAbsent {
|
||||
v = nilt
|
||||
} else {
|
||||
xcheckf(err, "get annotation")
|
||||
if a.IsString {
|
||||
v = string0(string(a.Value))
|
||||
} else {
|
||||
v = readerSizeSyncliteral{bytes.NewReader(a.Value), int64(len(a.Value)), true}
|
||||
}
|
||||
}
|
||||
meta = append(meta, astring(k), v)
|
||||
}
|
||||
line := concatspace{bare("*"), bare("METADATA"), mailboxt(info.mailbox.Name), meta}
|
||||
respMetadata = append(respMetadata, line)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -221,5 +258,9 @@ func (c *conn) cmdList(tag, cmd string, p *parser) {
|
||||
for _, line := range responseLines {
|
||||
c.bwritelinef("%s", line)
|
||||
}
|
||||
for _, meta := range respMetadata {
|
||||
meta.writeTo(c, c.bw)
|
||||
c.bwritelinef("")
|
||||
}
|
||||
c.ok(tag, cmd)
|
||||
}
|
||||
|
Reference in New Issue
Block a user