mirror of
https://github.com/mjl-/mox.git
synced 2025-07-19 03:26:37 +03:00
imapserver: implement UIDONLY extension, RFC 9586
Once clients enable this extension, commands can no longer refer to "message sequence numbers" (MSNs), but can only refer to messages with UIDs. This means both sides no longer have to carefully keep their sequence numbers in sync (error-prone), and don't have to keep track of a mapping of sequence numbers to UIDs (saves resources). With UIDONLY enabled, all FETCH responses are replaced with UIDFETCH response.
This commit is contained in:
@ -7,22 +7,30 @@ import (
|
||||
)
|
||||
|
||||
func TestAppend(t *testing.T) {
|
||||
testAppend(t, false)
|
||||
}
|
||||
|
||||
func TestAppendUIDOnly(t *testing.T) {
|
||||
testAppend(t, true)
|
||||
}
|
||||
|
||||
func testAppend(t *testing.T, uidonly bool) {
|
||||
defer mockUIDValidity()()
|
||||
|
||||
tc := start(t) // note: with switchboard because this connection stays alive unlike tc2.
|
||||
tc := start(t, uidonly) // note: with switchboard because this connection stays alive unlike tc2.
|
||||
defer tc.close()
|
||||
|
||||
tc2 := startNoSwitchboard(t) // note: without switchboard because this connection will break during tests.
|
||||
tc2 := startNoSwitchboard(t, uidonly) // note: without switchboard because this connection will break during tests.
|
||||
defer tc2.closeNoWait()
|
||||
|
||||
tc3 := startNoSwitchboard(t)
|
||||
tc3 := startNoSwitchboard(t, uidonly)
|
||||
defer tc3.closeNoWait()
|
||||
|
||||
tc2.client.Login("mjl@mox.example", password0)
|
||||
tc2.login("mjl@mox.example", password0)
|
||||
tc2.client.Select("inbox")
|
||||
tc.client.Login("mjl@mox.example", password0)
|
||||
tc.login("mjl@mox.example", password0)
|
||||
tc.client.Select("inbox")
|
||||
tc3.client.Login("mjl@mox.example", password0)
|
||||
tc3.login("mjl@mox.example", password0)
|
||||
|
||||
tc2.transactf("bad", "append") // Missing params.
|
||||
tc2.transactf("bad", `append inbox`) // Missing message.
|
||||
@ -30,15 +38,15 @@ func TestAppend(t *testing.T) {
|
||||
|
||||
// Syntax error for line ending in literal causes connection abort.
|
||||
tc2.transactf("bad", "append inbox (\\Badflag) {1+}\r\nx") // Unknown flag.
|
||||
tc2 = startNoSwitchboard(t)
|
||||
tc2 = startNoSwitchboard(t, uidonly)
|
||||
defer tc2.closeNoWait()
|
||||
tc2.client.Login("mjl@mox.example", password0)
|
||||
tc2.login("mjl@mox.example", password0)
|
||||
tc2.client.Select("inbox")
|
||||
|
||||
tc2.transactf("bad", "append inbox () \"bad time\" {1+}\r\nx") // Bad time.
|
||||
tc2 = startNoSwitchboard(t)
|
||||
tc2 = startNoSwitchboard(t, uidonly)
|
||||
defer tc2.closeNoWait()
|
||||
tc2.client.Login("mjl@mox.example", password0)
|
||||
tc2.login("mjl@mox.example", password0)
|
||||
tc2.client.Select("inbox")
|
||||
|
||||
tc2.transactf("no", "append nobox (\\Seen) \" 1-Jan-2022 10:10:00 +0100\" {1}")
|
||||
@ -52,9 +60,8 @@ func TestAppend(t *testing.T) {
|
||||
tc2.xcodeArg(imapclient.CodeAppendUID{UIDValidity: 1, UIDs: xparseUIDRange("1")})
|
||||
|
||||
tc.transactf("ok", "noop")
|
||||
uid1 := imapclient.FetchUID(1)
|
||||
flags := imapclient.FetchFlags{`\Seen`, "$label2", "label1"}
|
||||
tc.xuntagged(imapclient.UntaggedExists(1), imapclient.UntaggedFetch{Seq: 1, Attrs: []imapclient.FetchAttr{uid1, flags}})
|
||||
tc.xuntagged(imapclient.UntaggedExists(1), tc.untaggedFetch(1, 1, flags))
|
||||
tc3.transactf("ok", "noop")
|
||||
tc3.xuntagged() // Inbox is not selected, nothing to report.
|
||||
|
||||
@ -69,7 +76,6 @@ func TestAppend(t *testing.T) {
|
||||
// Messages that we cannot parse are marked as application/octet-stream. Perhaps
|
||||
// the imap client knows how to deal with them.
|
||||
tc2.transactf("ok", "uid fetch 2 body")
|
||||
uid2 := imapclient.FetchUID(2)
|
||||
xbs := imapclient.FetchBodystructure{
|
||||
RespAttr: "BODY",
|
||||
Body: imapclient.BodyTypeBasic{
|
||||
@ -80,7 +86,7 @@ func TestAppend(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
tc2.xuntagged(imapclient.UntaggedFetch{Seq: 2, Attrs: []imapclient.FetchAttr{uid2, xbs}})
|
||||
tc2.xuntagged(tc.untaggedFetch(2, 2, xbs))
|
||||
|
||||
// Multiappend with two messages.
|
||||
tc.transactf("ok", "noop") // Flush pending untagged responses.
|
||||
@ -91,9 +97,9 @@ func TestAppend(t *testing.T) {
|
||||
// Cancelled with zero-length message.
|
||||
tc.transactf("no", "append inbox {6+}\r\ntest\r\n {0+}\r\n")
|
||||
|
||||
tclimit := startArgs(t, false, false, true, true, "limit")
|
||||
tclimit := startArgs(t, uidonly, false, false, true, true, "limit")
|
||||
defer tclimit.close()
|
||||
tclimit.client.Login("limit@mox.example", password0)
|
||||
tclimit.login("limit@mox.example", password0)
|
||||
tclimit.client.Select("inbox")
|
||||
// First message of 1 byte is within limits.
|
||||
tclimit.transactf("ok", "append inbox (\\Seen Label1 $label2) \" 1-Jan-2022 10:10:00 +0100\" {1+}\r\nx")
|
||||
@ -103,7 +109,11 @@ func TestAppend(t *testing.T) {
|
||||
tclimit.xcode("OVERQUOTA")
|
||||
|
||||
// Empty mailbox.
|
||||
tclimit.transactf("ok", `store 1 flags (\deleted)`)
|
||||
if uidonly {
|
||||
tclimit.transactf("ok", `uid store 1 flags (\deleted)`)
|
||||
} else {
|
||||
tclimit.transactf("ok", `store 1 flags (\deleted)`)
|
||||
}
|
||||
tclimit.transactf("ok", "expunge")
|
||||
|
||||
// Multiappend with first message within quota, and second message with sync
|
||||
|
Reference in New Issue
Block a user