fix the Status command on imapclient.Conn

it needs at least 1 attribute.
also make types for those attributes, so its harder to get them wrong.
nothing was using this function.
This commit is contained in:
Mechiel Lukkien 2024-03-11 15:22:41 +01:00
parent 4dea2de343
commit bcf737cbec
No known key found for this signature in database
9 changed files with 83 additions and 26 deletions

View file

@ -206,10 +206,15 @@ func (c *Conn) Namespace() (untagged []Untagged, result Result, rerr error) {
return c.Transactf("namespace")
}
// Status requests information about a mailbox, such as number of messages, size, etc.
func (c *Conn) Status(mailbox string) (untagged []Untagged, result Result, rerr error) {
// Status requests information about a mailbox, such as number of messages, size,
// etc. At least one attribute required.
func (c *Conn) Status(mailbox string, attrs ...StatusAttr) (untagged []Untagged, result Result, rerr error) {
defer c.recover(&rerr)
return c.Transactf("status %s", astring(mailbox))
l := make([]string, len(attrs))
for i, a := range attrs {
l[i] = string(a)
}
return c.Transactf("status %s (%s)", astring(mailbox), strings.Join(l, " "))
}
// Append adds message to mailbox with flags and optional receive time.

View file

@ -363,14 +363,14 @@ func (c *Conn) xuntagged() Untagged {
mailbox := c.xastring()
c.xspace()
c.xtake("(")
attrs := map[string]int64{}
attrs := map[StatusAttr]int64{}
for !c.take(')') {
if len(attrs) > 0 {
c.xspace()
}
s := c.xatom()
c.xspace()
S := strings.ToUpper(s)
S := StatusAttr(strings.ToUpper(s))
var num int64
// ../rfc/9051:7059
switch S {

View file

@ -224,8 +224,25 @@ type UntaggedSearchModSeq struct {
}
type UntaggedStatus struct {
Mailbox string
Attrs map[string]int64 // Upper case status attributes. ../rfc/9051:7059
Attrs map[StatusAttr]int64 // Upper case status attributes.
}
// ../rfc/9051:7059 ../9208:712
type StatusAttr string
const (
StatusMessages StatusAttr = "MESSAGES"
StatusUIDNext StatusAttr = "UIDNEXT"
StatusUIDValidity StatusAttr = "UIDVALIDITY"
StatusUnseen StatusAttr = "UNSEEN"
StatusDeleted StatusAttr = "DELETED"
StatusSize StatusAttr = "SIZE"
StatusRecent StatusAttr = "RECENT"
StatusAppendLimit StatusAttr = "APPENDLIMIT"
StatusHighestModSeq StatusAttr = "HIGHESTMODSEQ"
StatusDeletedStorage StatusAttr = "DELETED-STORAGE"
)
type UntaggedNamespace struct {
Personal, Other, Shared []NamespaceDescr
}

View file

@ -42,7 +42,7 @@ func testCondstoreQresync(t *testing.T, qresync bool) {
// First some tests without any messages.
tc.transactf("ok", "Status inbox (Highestmodseq)")
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[string]int64{"HIGHESTMODSEQ": 1}})
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[imapclient.StatusAttr]int64{imapclient.StatusHighestModSeq: 1}})
// No messages, no matches.
tc.transactf("ok", "Uid Fetch 1:* (Flags) (Changedsince 12345)")
@ -160,10 +160,10 @@ func testCondstoreQresync(t *testing.T, qresync bool) {
// Check highestmodseq for mailboxes.
tc.transactf("ok", "Status inbox (highestmodseq)")
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[string]int64{"HIGHESTMODSEQ": clientModseq}})
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[imapclient.StatusAttr]int64{imapclient.StatusHighestModSeq: clientModseq}})
tc.transactf("ok", "Status otherbox (highestmodseq)")
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "otherbox", Attrs: map[string]int64{"HIGHESTMODSEQ": 3}})
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "otherbox", Attrs: map[imapclient.StatusAttr]int64{imapclient.StatusHighestModSeq: 3}})
// Check highestmodseq when we select.
tc.transactf("ok", "Examine otherbox")
@ -297,7 +297,7 @@ func testCondstoreQresync(t *testing.T, qresync bool) {
// Again after expunge: status, select, conditional store/fetch/search
tc.transactf("ok", "Status inbox (Highestmodseq Messages Unseen Deleted)")
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[string]int64{"MESSAGES": 4, "UNSEEN": 4, "DELETED": 0, "HIGHESTMODSEQ": clientModseq}})
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[imapclient.StatusAttr]int64{imapclient.StatusMessages: 4, imapclient.StatusUnseen: 4, imapclient.StatusDeleted: 0, imapclient.StatusHighestModSeq: clientModseq}})
tc.transactf("ok", "Close")
tc.transactf("ok", "Select inbox")

View file

@ -90,15 +90,15 @@ func TestListExtended(t *testing.T) {
}
ustatus := func(name string) imapclient.UntaggedStatus {
attrs := map[string]int64{
"MESSAGES": 0,
"UIDNEXT": 1,
"UIDVALIDITY": int64(uidval(name)),
"UNSEEN": 0,
"DELETED": 0,
"SIZE": 0,
"RECENT": 0,
"APPENDLIMIT": 0,
attrs := map[imapclient.StatusAttr]int64{
imapclient.StatusMessages: 0,
imapclient.StatusUIDNext: 1,
imapclient.StatusUIDValidity: int64(uidval(name)),
imapclient.StatusUnseen: 0,
imapclient.StatusDeleted: 0,
imapclient.StatusSize: 0,
imapclient.StatusRecent: 0,
imapclient.StatusAppendLimit: 0,
}
return imapclient.UntaggedStatus{Mailbox: name, Attrs: attrs}
}

View file

@ -32,7 +32,7 @@ func TestQuota1(t *testing.T) {
// Check that we get a DELETED-STORAGE status attribute with value 0, also if
// messages are marked deleted. We don't go through the trouble.
tc.transactf("ok", "status inbox (DELETED-STORAGE)")
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[string]int64{"DELETED-STORAGE": 0}})
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[imapclient.StatusAttr]int64{imapclient.StatusDeletedStorage: 0}})
// tclimit does have a limit.
tclimit := startArgs(t, false, false, true, true, "limit")
@ -50,5 +50,5 @@ func TestQuota1(t *testing.T) {
tclimit.xuntagged(imapclient.UntaggedQuota{Root: "", Resources: []imapclient.QuotaResource{{Name: imapclient.QuotaResourceStorage, Usage: 0, Limit: 1}}})
tclimit.transactf("ok", "status inbox (DELETED-STORAGE)")
tclimit.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[string]int64{"DELETED-STORAGE": 0}})
tclimit.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[imapclient.StatusAttr]int64{imapclient.StatusDeletedStorage: 0}})
}

View file

@ -692,7 +692,7 @@ func DisabledTestReference(t *testing.T) {
defer tc3.close()
tc3.client.Login("mjl@mox.example", password0)
tc3.transactf("ok", `list "" "inbox" return (status (messages))`)
tc3.xuntagged(imapclient.UntaggedList{Separator: '/', Mailbox: "Inbox"}, imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[string]int64{"MESSAGES": 0}})
tc3.xuntagged(imapclient.UntaggedList{Separator: '/', Mailbox: "Inbox"}, imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[imapclient.StatusAttr]int64{imapclient.StatusMessages: 0}})
tc2.transactf("ok", "fetch 1 rfc822.size")
tc.xuntagged(imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{imapclient.FetchRFC822Size(len(exampleMsg))}})

View file

@ -20,15 +20,50 @@ func TestStatus(t *testing.T) {
tc.transactf("bad", "status inbox (unknown)") // Unknown attribute.
tc.transactf("ok", "status inbox (messages uidnext uidvalidity unseen deleted size recent appendlimit)")
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[string]int64{"MESSAGES": 0, "UIDVALIDITY": 1, "UIDNEXT": 1, "UNSEEN": 0, "DELETED": 0, "SIZE": 0, "RECENT": 0, "APPENDLIMIT": 0}})
tc.xuntagged(imapclient.UntaggedStatus{
Mailbox: "Inbox",
Attrs: map[imapclient.StatusAttr]int64{imapclient.StatusMessages: 0,
imapclient.StatusUIDValidity: 1,
imapclient.StatusUIDNext: 1,
imapclient.StatusUnseen: 0,
imapclient.StatusDeleted: 0,
imapclient.StatusSize: 0,
imapclient.StatusRecent: 0,
imapclient.StatusAppendLimit: 0,
},
})
// Again, now with a message in the mailbox.
tc.transactf("ok", "append inbox {4+}\r\ntest")
tc.transactf("ok", "status inbox (messages uidnext uidvalidity unseen deleted size recent appendlimit)")
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[string]int64{"MESSAGES": 1, "UIDVALIDITY": 1, "UIDNEXT": 2, "UNSEEN": 1, "DELETED": 0, "SIZE": 4, "RECENT": 0, "APPENDLIMIT": 0}})
tc.xuntagged(imapclient.UntaggedStatus{
Mailbox: "Inbox",
Attrs: map[imapclient.StatusAttr]int64{imapclient.StatusMessages: 1,
imapclient.StatusUIDValidity: 1,
imapclient.StatusUIDNext: 2,
imapclient.StatusUnseen: 1,
imapclient.StatusDeleted: 0,
imapclient.StatusSize: 4,
imapclient.StatusRecent: 0,
imapclient.StatusAppendLimit: 0,
},
})
tc.client.Select("inbox")
tc.client.StoreFlagsSet("1", true, `\Deleted`)
tc.transactf("ok", "status inbox (messages uidnext uidvalidity unseen deleted size recent appendlimit)")
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[string]int64{"MESSAGES": 1, "UIDVALIDITY": 1, "UIDNEXT": 2, "UNSEEN": 1, "DELETED": 1, "SIZE": 4, "RECENT": 0, "APPENDLIMIT": 0}})
tc.xuntagged(imapclient.UntaggedStatus{
Mailbox: "Inbox",
Attrs: map[imapclient.StatusAttr]int64{imapclient.StatusMessages: 1,
imapclient.StatusUIDValidity: 1,
imapclient.StatusUIDNext: 2,
imapclient.StatusUnseen: 1,
imapclient.StatusDeleted: 1,
imapclient.StatusSize: 4,
imapclient.StatusRecent: 0,
imapclient.StatusAppendLimit: 0,
},
})
}

View file

@ -22,5 +22,5 @@ func TestUnselect(t *testing.T) {
tc.client.StoreFlagsAdd("1", true, `\Deleted`)
tc.transactf("ok", "unselect")
tc.transactf("ok", "status inbox (messages)")
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[string]int64{"MESSAGES": 1}}) // Message not removed.
tc.xuntagged(imapclient.UntaggedStatus{Mailbox: "Inbox", Attrs: map[imapclient.StatusAttr]int64{imapclient.StatusMessages: 1}}) // Message not removed.
}