imapserver: fix interpreting the first "*" in sequence/uid patterns, like "*:123" or plain "*"

in some cases, they were interpreted as meaning "the first sequence/uid", but
it should always be "the last sequence/uid", just like patterns of the form
"123:*".

this wrong interpretation was used in the "fetch" command when combined with
"changedsince", and in the search command for some parameters, and during
expunge with an explicit uid range. the form "*" and "*:123" aren't very
common.
This commit is contained in:
Mechiel Lukkien
2024-01-23 21:21:08 +01:00
parent d9dde0d89e
commit 14aa85482e
2 changed files with 71 additions and 55 deletions

View File

@ -38,29 +38,37 @@ func TestNumSetContains(t *testing.T) {
// 2:*
ss2 := numSet{false, []numRange{{*num(2), star}}}
check(!ss2.containsSeq(1, []store.UID{2}, nil))
check(ss2.containsSeq(1, []store.UID{2}, nil))
check(!ss2.containsSeq(2, []store.UID{2}, nil))
check(ss2.containsSeq(2, []store.UID{4, 5}, nil))
check(ss2.containsSeq(3, []store.UID{4, 5, 6}, nil))
check(!ss2.containsSeq(4, []store.UID{4, 5, 6}, nil))
check(ss2.containsUID(2, []store.UID{2}, nil))
check(!ss2.containsUID(1, []store.UID{1, 2, 3}, nil))
check(ss2.containsUID(3, []store.UID{1, 2, 3}, nil))
check(ss2.containsUID(2, []store.UID{2}, nil))
check(!ss2.containsUID(2, []store.UID{4, 5}, nil))
check(!ss2.containsUID(2, []store.UID{1}, nil))
check(ss2.containsUID(2, []store.UID{2, 6}, nil))
check(ss2.containsUID(6, []store.UID{2, 6}, nil))
// *:2
// *:2, same as 2:*
ss3 := numSet{false, []numRange{{*star, num(2)}}}
check(ss3.containsSeq(1, []store.UID{2}, nil))
check(!ss3.containsSeq(2, []store.UID{2}, nil))
check(ss3.containsSeq(2, []store.UID{4, 5}, nil))
check(!ss3.containsSeq(3, []store.UID{1, 2, 3}, nil))
check(ss3.containsSeq(3, []store.UID{4, 5, 6}, nil))
check(!ss3.containsSeq(4, []store.UID{4, 5, 6}, nil))
check(ss3.containsUID(1, []store.UID{1}, nil))
check(ss3.containsUID(2, []store.UID{1, 2, 3}, nil))
check(!ss3.containsUID(1, []store.UID{2, 3}, nil))
check(!ss3.containsUID(3, []store.UID{1, 2, 3}, nil))
check(ss3.containsUID(2, []store.UID{2}, nil))
check(!ss3.containsUID(1, []store.UID{1, 2, 3}, nil))
check(ss3.containsUID(3, []store.UID{1, 2, 3}, nil))
check(!ss3.containsUID(2, []store.UID{4, 5}, nil))
check(!ss3.containsUID(2, []store.UID{1}, nil))
check(ss3.containsUID(2, []store.UID{2, 6}, nil))
check(ss3.containsUID(6, []store.UID{2, 6}, nil))
}
func TestNumSetInterpret(t *testing.T) {
@ -82,10 +90,25 @@ func TestNumSetInterpret(t *testing.T) {
checkEqual([]store.UID{1}, "1:*", "1")
checkEqual([]store.UID{1, 3}, "1:*", "1:3")
checkEqual([]store.UID{1, 3}, "4:*", "3")
checkEqual([]store.UID{2, 3}, "*:4", "2:4")
checkEqual([]store.UID{2, 3}, "*:1", "2")
checkEqual([]store.UID{1, 3}, "*:4", "3")
checkEqual([]store.UID{2, 3}, "*:4", "3")
checkEqual([]store.UID{2, 3}, "*:1", "1:3")
checkEqual([]store.UID{2, 3}, "1:*", "1:3")
checkEqual([]store.UID{1, 2, 3}, "1,2,3", "1,2,3")
checkEqual([]store.UID{}, "1,2,3", "1,2,3")
checkEqual([]store.UID{}, "1:3", "1:3")
checkEqual([]store.UID{}, "3:1", "1:3")
checkEqual([]store.UID{}, "1,2,3", "")
checkEqual([]store.UID{}, "1:3", "")
checkEqual([]store.UID{}, "3:1", "")
iter := parseNumSet("1:3").interpretStar([]store.UID{}).newIter()
if _, ok := iter.Next(); ok {
t.Fatalf("expected immediate end for empty iter")
}
iter = parseNumSet("3:1").interpretStar([]store.UID{1, 2}).newIter()
v0, _ := iter.Next()
v1, _ := iter.Next()
_, ok := iter.Next()
if v0 != 1 || v1 != 2 || ok {
t.Fatalf("got %v %v %v, expected 1, 2, false", v0, v1, ok)
}
}