summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Culverhouse <tim@timculverhouse.com>2022-07-24 10:13:43 -0500
committerRobin Jarry <robin@jarry.cc>2022-07-24 23:06:10 +0200
commitfb5558da811a49031922ee5582f61ac1d9b08d3c (patch)
treea46c5ba47429dabfbcb42d7f2f11891ef2a62503
parent9bfcec56600a20f3e84404e4ddba7d0a5ceecbd9 (diff)
downloadaerc-fb5558da811a49031922ee5582f61ac1d9b08d3c.zip
seqmap: sync seqNum to uid after expunge
This patch updates the seqNums after an Expunge operation. When an expunge operation occurs, the seqNum of the deleted message is reported. The Imap spec [0] states that an immediate decrement of all seqnums greater than the deleted occurs, even before the next reporting of an expunge update. [0]: https://datatracker.ietf.org/doc/html/rfc3501#section-7.4.1 Fixes: https://todo.sr.ht/~rjarry/aerc/61 Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Signed-off-by: Robin Jarry <robin@jarry.cc>
-rw-r--r--worker/imap/seqmap.go16
-rw-r--r--worker/imap/seqmap_test.go9
2 files changed, 20 insertions, 5 deletions
diff --git a/worker/imap/seqmap.go b/worker/imap/seqmap.go
index 2752cc8..093bbc5 100644
--- a/worker/imap/seqmap.go
+++ b/worker/imap/seqmap.go
@@ -1,6 +1,8 @@
package imap
-import "sync"
+import (
+ "sync"
+)
type SeqMap struct {
lock sync.Mutex
@@ -35,7 +37,17 @@ func (s *SeqMap) Pop(seqnum uint32) (uint32, bool) {
s.lock.Lock()
uid, found := s.m[seqnum]
if found {
- delete(s.m, seqnum)
+ m := make(map[uint32]uint32)
+ for s, u := range s.m {
+ if s > seqnum {
+ // All sequence numbers greater than the removed one must be decremented by one
+ // https://datatracker.ietf.org/doc/html/rfc3501#section-7.4.1
+ m[s-1] = u
+ } else if s < seqnum {
+ m[s] = u
+ }
+ }
+ s.m = m
}
s.lock.Unlock()
return uid, found
diff --git a/worker/imap/seqmap_test.go b/worker/imap/seqmap_test.go
index 0ee0738..0fa8711 100644
--- a/worker/imap/seqmap_test.go
+++ b/worker/imap/seqmap_test.go
@@ -39,12 +39,15 @@ func TestSeqMap(t *testing.T) {
assert.Equal(found, true)
assert.Equal(seqmap.Size(), 2)
+ // Repop the same seqnum should work because of the syncing
_, found = seqmap.Pop(1)
- assert.Equal(found, false)
- assert.Equal(seqmap.Size(), 2)
+ assert.Equal(found, true)
+ assert.Equal(seqmap.Size(), 1)
+ // sync means we already have a 1. This is replacing that UID so the size
+ // shouldn't increase
seqmap.Put(1, 7331)
- assert.Equal(seqmap.Size(), 3)
+ assert.Equal(seqmap.Size(), 1)
seqmap.Clear()
assert.Equal(seqmap.Size(), 0)