aboutsummaryrefslogtreecommitdiffstats
path: root/worker
diff options
context:
space:
mode:
authorRobin Jarry <robin@jarry.cc>2024-08-14 16:59:11 +0200
committerRobin Jarry <robin@jarry.cc>2024-08-28 12:06:01 +0200
commit73dc39c6ee0827fc68b93af8dc438b0e1c14e929 (patch)
treeaff067600ea6326ff179447ed968b6712013b889 /worker
parent2950d919a5c5a55bd0eb53d6c41f989d8b70bd55 (diff)
downloadaerc-73dc39c6ee0827fc68b93af8dc438b0e1c14e929.tar.gz
treewide: replace uint32 uids with opaque strings
Add a new models.UID type (an alias to string). Replace all occurrences of uint32 being used as message UID or thread UID with models.UID. Update all workers to only expose models.UID values and deal with the conversion internally. Only IMAP needs to convert these to uint32. All other backends already use plain strings as message identifiers, in which case no conversion is even needed. The directory tree implementation needed to be heavily refactored in order to accommodate thread UID not being usable as a list index. Signed-off-by: Robin Jarry <robin@jarry.cc> Tested-by: Inwit <inwit@sindominio.net> Tested-by: Tim Culverhouse <tim@timculverhouse.com>
Diffstat (limited to 'worker')
-rw-r--r--worker/imap/cache.go12
-rw-r--r--worker/imap/extensions/xgmext/client.go21
-rw-r--r--worker/imap/fetch.go22
-rw-r--r--worker/imap/flags.go6
-rw-r--r--worker/imap/imap.go8
-rw-r--r--worker/imap/list.go2
-rw-r--r--worker/imap/open.go8
-rw-r--r--worker/imap/worker.go4
-rw-r--r--worker/jmap/directories.go8
-rw-r--r--worker/jmap/fetch.go22
-rw-r--r--worker/jmap/jmap.go2
-rw-r--r--worker/jmap/push.go5
-rw-r--r--worker/jmap/set.go26
-rw-r--r--worker/jmap/worker.go3
-rw-r--r--worker/lib/search.go4
-rw-r--r--worker/lib/sort.go4
-rw-r--r--worker/maildir/container.go73
-rw-r--r--worker/maildir/message.go4
-rw-r--r--worker/maildir/search.go9
-rw-r--r--worker/maildir/worker.go16
-rw-r--r--worker/mbox/io.go7
-rw-r--r--worker/mbox/models.go42
-rw-r--r--worker/mbox/worker.go6
-rw-r--r--worker/notmuch/lib/database.go14
-rw-r--r--worker/notmuch/message.go4
-rw-r--r--worker/notmuch/worker.go28
-rw-r--r--worker/types/messages.go32
-rw-r--r--worker/types/thread.go29
-rw-r--r--worker/types/thread_test.go86
29 files changed, 224 insertions, 283 deletions
diff --git a/worker/imap/cache.go b/worker/imap/cache.go
index 8ae60f03..0eba7b9d 100644
--- a/worker/imap/cache.go
+++ b/worker/imap/cache.go
@@ -24,7 +24,7 @@ type CachedHeader struct {
BodyStructure models.BodyStructure
Envelope models.Envelope
InternalDate time.Time
- Uid uint32
+ Uid models.UID
Size uint32
Header []byte
Created time.Time
@@ -34,7 +34,7 @@ var (
// cacheTag should be updated when changing the cache
// structure; this will ensure that the user's cache is cleared and
// reloaded when the underlying cache structure changes
- cacheTag = []byte("0002")
+ cacheTag = []byte("0003")
cacheTagKey = []byte("cache.tag")
)
@@ -112,9 +112,9 @@ func (w *IMAPWorker) cacheHeader(mi *models.MessageInfo) {
}
}
-func (w *IMAPWorker) getCachedHeaders(msg *types.FetchMessageHeaders) []uint32 {
+func (w *IMAPWorker) getCachedHeaders(msg *types.FetchMessageHeaders) []models.UID {
w.worker.Tracef("Retrieving headers from cache: %v", msg.Uids)
- var need []uint32
+ var need []models.UID
for _, uid := range msg.Uids {
key := w.headerKey(uid)
data, err := w.cache.Get(key, nil)
@@ -157,8 +157,8 @@ func (w *IMAPWorker) getCachedHeaders(msg *types.FetchMessageHeaders) []uint32 {
return need
}
-func (w *IMAPWorker) headerKey(uid uint32) []byte {
- key := fmt.Sprintf("header.%s.%d.%d",
+func (w *IMAPWorker) headerKey(uid models.UID) []byte {
+ key := fmt.Sprintf("header.%s.%d.%s",
w.selected.Name, w.selected.UidValidity, uid)
return []byte(key)
}
diff --git a/worker/imap/extensions/xgmext/client.go b/worker/imap/extensions/xgmext/client.go
index 65f11e74..e6e34a44 100644
--- a/worker/imap/extensions/xgmext/client.go
+++ b/worker/imap/extensions/xgmext/client.go
@@ -5,6 +5,7 @@ import (
"fmt"
"git.sr.ht/~rjarry/aerc/lib/log"
+ "git.sr.ht/~rjarry/aerc/models"
"github.com/emersion/go-imap"
"github.com/emersion/go-imap/client"
"github.com/emersion/go-imap/commands"
@@ -19,7 +20,7 @@ func NewHandler(c *client.Client) *handler {
return &handler{client: c}
}
-func (h handler) FetchEntireThreads(requested []uint32) ([]uint32, error) {
+func (h handler) FetchEntireThreads(requested []models.UID) ([]models.UID, error) {
threadIds, err := h.fetchThreadIds(requested)
if err != nil {
return nil,
@@ -33,7 +34,7 @@ func (h handler) FetchEntireThreads(requested []uint32) ([]uint32, error) {
return uids, nil
}
-func (h handler) fetchThreadIds(uids []uint32) ([]string, error) {
+func (h handler) fetchThreadIds(uids []models.UID) ([]string, error) {
messages := make(chan *imap.Message)
done := make(chan error)
@@ -58,7 +59,9 @@ func (h handler) fetchThreadIds(uids []uint32) ([]string, error) {
}()
var set imap.SeqSet
- set.AddNum(uids...)
+ for _, uid := range uids {
+ set.AddNum(models.UidToUint32(uid))
+ }
err := h.client.UidFetch(&set, items, messages)
<-done
@@ -69,18 +72,18 @@ func (h handler) fetchThreadIds(uids []uint32) ([]string, error) {
return thrid, err
}
-func (h handler) searchUids(thrid []string) ([]uint32, error) {
+func (h handler) searchUids(thrid []string) ([]models.UID, error) {
if len(thrid) == 0 {
return nil, errors.New("no thread IDs provided")
}
return h.runSearch(NewThreadIDSearch(thrid))
}
-func (h handler) RawSearch(rawSearch string) ([]uint32, error) {
+func (h handler) RawSearch(rawSearch string) ([]models.UID, error) {
return h.runSearch(NewRawSearch(rawSearch))
}
-func (h handler) runSearch(cmd imap.Commander) ([]uint32, error) {
+func (h handler) runSearch(cmd imap.Commander) ([]models.UID, error) {
if h.client.State() != imap.SelectedState {
return nil, errors.New("no mailbox selected")
}
@@ -90,5 +93,9 @@ func (h handler) runSearch(cmd imap.Commander) ([]uint32, error) {
if err != nil {
return nil, fmt.Errorf("imap execute failed: %w", err)
}
- return res.Ids, status.Err()
+ var uids []models.UID
+ for _, i := range res.Ids {
+ uids = append(uids, models.Uint32ToUid(i))
+ }
+ return uids, status.Err()
}
diff --git a/worker/imap/fetch.go b/worker/imap/fetch.go
index 202038fe..9b77c777 100644
--- a/worker/imap/fetch.go
+++ b/worker/imap/fetch.go
@@ -82,7 +82,7 @@ func (imapw *IMAPWorker) handleFetchMessageHeaders(
RFC822Headers: header,
Refs: parse.MsgIDList(header, "references"),
Size: _msg.Size,
- Uid: _msg.Uid,
+ Uid: models.Uint32ToUid(_msg.Uid),
}
imapw.worker.PostMessage(&types.MessageInfo{
Message: types.RespondTo(msg),
@@ -126,7 +126,7 @@ func (imapw *IMAPWorker) handleFetchMessageBodyPart(
partHeaderSection.FetchItem(),
partBodySection.FetchItem(),
}
- imapw.handleFetchMessages(msg, []uint32{msg.Uid}, items,
+ imapw.handleFetchMessages(msg, []models.UID{msg.Uid}, items,
func(_msg *imap.Message) error {
if len(_msg.Body) == 0 {
// ignore duplicate messages with only flag updates
@@ -154,7 +154,7 @@ func (imapw *IMAPWorker) handleFetchMessageBodyPart(
Message: types.RespondTo(msg),
Part: &models.MessageBodyPart{
Reader: part.Body,
- Uid: _msg.Uid,
+ Uid: models.Uint32ToUid(_msg.Uid),
},
}, nil)
// Update flags (to mark message as read)
@@ -162,7 +162,7 @@ func (imapw *IMAPWorker) handleFetchMessageBodyPart(
Message: types.RespondTo(msg),
Info: &models.MessageInfo{
Flags: translateImapFlags(_msg.Flags),
- Uid: _msg.Uid,
+ Uid: models.Uint32ToUid(_msg.Uid),
},
}, nil)
return nil
@@ -196,7 +196,7 @@ func (imapw *IMAPWorker) handleFetchFullMessages(
Message: types.RespondTo(msg),
Content: &models.FullMessage{
Reader: bufio.NewReader(r),
- Uid: _msg.Uid,
+ Uid: models.Uint32ToUid(_msg.Uid),
},
}, nil)
// Update flags (to mark message as read)
@@ -204,7 +204,7 @@ func (imapw *IMAPWorker) handleFetchFullMessages(
Message: types.RespondTo(msg),
Info: &models.MessageInfo{
Flags: translateImapFlags(_msg.Flags),
- Uid: _msg.Uid,
+ Uid: models.Uint32ToUid(_msg.Uid),
},
}, nil)
return nil
@@ -228,7 +228,7 @@ func (imapw *IMAPWorker) handleFetchMessageFlags(msg *types.FetchMessageFlags) {
Message: types.RespondTo(msg),
Info: &models.MessageInfo{
Flags: translateImapFlags(_msg.Flags),
- Uid: _msg.Uid,
+ Uid: models.Uint32ToUid(_msg.Uid),
},
}, nil)
return nil
@@ -236,13 +236,13 @@ func (imapw *IMAPWorker) handleFetchMessageFlags(msg *types.FetchMessageFlags) {
}
func (imapw *IMAPWorker) handleFetchMessages(
- msg types.WorkerMessage, uids []uint32, items []imap.FetchItem,
+ msg types.WorkerMessage, uids []models.UID, items []imap.FetchItem,
procFunc func(*imap.Message) error,
) {
messages := make(chan *imap.Message)
done := make(chan struct{})
- missingUids := make(map[uint32]bool)
+ missingUids := make(map[models.UID]bool)
for _, uid := range uids {
missingUids[uid] = true
}
@@ -251,14 +251,14 @@ func (imapw *IMAPWorker) handleFetchMessages(
defer log.PanicHandler()
for _msg := range messages {
- delete(missingUids, _msg.Uid)
+ delete(missingUids, models.Uint32ToUid(_msg.Uid))
err := procFunc(_msg)
if err != nil {
log.Errorf("failed to process message <%d>: %v", _msg.Uid, err)
imapw.worker.PostMessage(&types.MessageInfo{
Message: types.RespondTo(msg),
Info: &models.MessageInfo{
- Uid: _msg.Uid,
+ Uid: models.Uint32ToUid(_msg.Uid),
Error: err,
},
}, nil)
diff --git a/worker/imap/flags.go b/worker/imap/flags.go
index 60137bd3..31d3bea3 100644
--- a/worker/imap/flags.go
+++ b/worker/imap/flags.go
@@ -81,7 +81,7 @@ func (imapw *IMAPWorker) handleAnsweredMessages(msg *types.AnsweredMessages) {
Message: types.RespondTo(msg),
Info: &models.MessageInfo{
Flags: translateImapFlags(_msg.Flags),
- Uid: _msg.Uid,
+ Uid: models.Uint32ToUid(_msg.Uid),
},
}, nil)
return nil
@@ -100,7 +100,7 @@ func (imapw *IMAPWorker) handleFlagMessages(msg *types.FlagMessages) {
Message: types.RespondTo(msg),
Info: &models.MessageInfo{
Flags: translateImapFlags(_msg.Flags),
- Uid: _msg.Uid,
+ Uid: models.Uint32ToUid(_msg.Uid),
},
}, nil)
return nil
@@ -108,7 +108,7 @@ func (imapw *IMAPWorker) handleFlagMessages(msg *types.FlagMessages) {
}
func (imapw *IMAPWorker) handleStoreOps(
- msg types.WorkerMessage, uids []uint32, item imap.StoreItem, flag interface{},
+ msg types.WorkerMessage, uids []models.UID, item imap.StoreItem, flag interface{},
procFunc func(*imap.Message) error,
) {
messages := make(chan *imap.Message)
diff --git a/worker/imap/imap.go b/worker/imap/imap.go
index fbdcb2b9..67d56264 100644
--- a/worker/imap/imap.go
+++ b/worker/imap/imap.go
@@ -14,12 +14,12 @@ func init() {
imap.CharsetReader = charset.Reader
}
-func toSeqSet(uids []uint32) *imap.SeqSet {
- var set imap.SeqSet
+func toSeqSet(uids []models.UID) *imap.SeqSet {
+ set := new(imap.SeqSet)
for _, uid := range uids {
- set.AddNum(uid)
+ set.AddNum(models.UidToUint32(uid))
}
- return &set
+ return set
}
func translateBodyStructure(bs *imap.BodyStructure) *models.BodyStructure {
diff --git a/worker/imap/list.go b/worker/imap/list.go
index d12ae4bd..e3c9db3e 100644
--- a/worker/imap/list.go
+++ b/worker/imap/list.go
@@ -139,6 +139,6 @@ func (imapw *IMAPWorker) handleSearchDirectory(msg *types.SearchDirectory) {
imapw.worker.PostMessage(&types.SearchResults{
Message: types.RespondTo(msg),
- Uids: uids,
+ Uids: models.Uint32ToUidList(uids),
}, nil)
}
diff --git a/worker/imap/open.go b/worker/imap/open.go
index 355709a7..b1314a4b 100644
--- a/worker/imap/open.go
+++ b/worker/imap/open.go
@@ -5,6 +5,7 @@ import (
sortthread "github.com/emersion/go-imap-sortthread"
+ "git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/worker/types"
)
@@ -85,9 +86,10 @@ func (imapw *IMAPWorker) handleFetchDirectoryContents(
// Only initialize if we are not filtering
imapw.seqMap.Initialize(uids)
}
+
imapw.worker.PostMessage(&types.DirectoryContents{
Message: types.RespondTo(msg),
- Uids: uids,
+ Uids: models.Uint32ToUidList(uids),
}, nil)
imapw.worker.PostMessage(&types.Done{Message: types.RespondTo(msg)}, nil)
}
@@ -146,7 +148,7 @@ func (imapw *IMAPWorker) handleDirectoryThreaded(
var uids []uint32
for i := len(aercThreads) - 1; i >= 0; i-- {
aercThreads[i].Walk(func(t *types.Thread, level int, currentErr error) error { //nolint:errcheck // error indicates skipped threads
- uids = append(uids, t.Uid)
+ uids = append(uids, models.UidToUint32(t.Uid))
return nil
})
}
@@ -175,7 +177,7 @@ func convertThreads(threads []*sortthread.Thread, parent *types.Thread) ([]*type
for i := 0; i < len(threads); i++ {
t := threads[i]
conv[i] = &types.Thread{
- Uid: t.Id,
+ Uid: models.Uint32ToUid(t.Id),
}
// Set the first child node
diff --git a/worker/imap/worker.go b/worker/imap/worker.go
index edb68ec4..28eb907c 100644
--- a/worker/imap/worker.go
+++ b/worker/imap/worker.go
@@ -289,7 +289,7 @@ func (w *IMAPWorker) handleImapUpdate(update client.Update) {
Envelope: translateEnvelope(msg.Envelope),
Flags: translateImapFlags(msg.Flags),
InternalDate: msg.InternalDate,
- Uid: msg.Uid,
+ Uid: models.Uint32ToUid(msg.Uid),
},
}, nil)
case *client.ExpungeUpdate:
@@ -297,7 +297,7 @@ func (w *IMAPWorker) handleImapUpdate(update client.Update) {
w.worker.Errorf("ExpungeUpdate unknown seqnum: %d", update.SeqNum)
} else {
w.worker.PostMessage(&types.MessagesDeleted{
- Uids: []uint32{uid},
+ Uids: []models.UID{models.Uint32ToUid(uid)},
}, nil)
}
}
diff --git a/worker/jmap/directories.go b/worker/jmap/directories.go
index 07bb0762..7ae79ead 100644
--- a/worker/jmap/directories.go
+++ b/worker/jmap/directories.go
@@ -186,9 +186,9 @@ func (w *JMAPWorker) handleFetchDirectoryContents(msg *types.FetchDirectoryConte
}
}
- uids := make([]uint32, 0, len(contents.MessageIDs))
+ uids := make([]models.UID, 0, len(contents.MessageIDs))
for _, id := range contents.MessageIDs {
- uids = append(uids, w.uidStore.GetOrInsert(string(id)))
+ uids = append(uids, models.UID(id))
}
w.w.PostMessage(&types.DirectoryContents{
Message: types.RespondTo(msg),
@@ -214,9 +214,9 @@ func (w *JMAPWorker) handleSearchDirectory(msg *types.SearchDirectory) error {
for _, inv := range resp.Responses {
switch r := inv.Args.(type) {
case *email.QueryResponse:
- var uids []uint32
+ var uids []models.UID
for _, id := range r.IDs {
- uids = append(uids, w.uidStore.GetOrInsert(string(id)))
+ uids = append(uids, models.UID(id))
}
w.w.PostMessage(&types.SearchResults{
Message: types.RespondTo(msg),
diff --git a/worker/jmap/fetch.go b/worker/jmap/fetch.go
index 07579b99..3b3a8460 100644
--- a/worker/jmap/fetch.go
+++ b/worker/jmap/fetch.go
@@ -38,11 +38,7 @@ func (w *JMAPWorker) handleFetchMessageHeaders(msg *types.FetchMessageHeaders) e
emailIdsToFetch := make([]jmap.ID, 0, len(msg.Uids))
currentEmails := make([]*email.Email, 0, len(msg.Uids))
for _, uid := range msg.Uids {
- id, ok := w.uidStore.GetKey(uid)
- if !ok {
- return fmt.Errorf("bug: no jmap id for message uid: %v", uid)
- }
- jid := jmap.ID(id)
+ jid := jmap.ID(uid)
m, err := w.cache.GetEmail(jid)
if err != nil {
// Message wasn't in cache; fetch it
@@ -103,13 +99,9 @@ func (w *JMAPWorker) handleFetchMessageHeaders(msg *types.FetchMessageHeaders) e
}
func (w *JMAPWorker) handleFetchMessageBodyPart(msg *types.FetchMessageBodyPart) error {
- id, ok := w.uidStore.GetKey(msg.Uid)
- if !ok {
- return fmt.Errorf("bug: unknown message uid %d", msg.Uid)
- }
- mail, err := w.cache.GetEmail(jmap.ID(id))
+ mail, err := w.cache.GetEmail(jmap.ID(msg.Uid))
if err != nil {
- return fmt.Errorf("bug: unknown message id %s: %w", id, err)
+ return fmt.Errorf("bug: unknown message id %s: %w", msg.Uid, err)
}
part := mail.BodyStructure
@@ -159,13 +151,9 @@ func (w *JMAPWorker) handleFetchMessageBodyPart(msg *types.FetchMessageBodyPart)
func (w *JMAPWorker) handleFetchFullMessages(msg *types.FetchFullMessages) error {
for _, uid := range msg.Uids {
- id, ok := w.uidStore.GetKey(uid)
- if !ok {
- return fmt.Errorf("bug: unknown message uid %d", uid)
- }
- mail, err := w.cache.GetEmail(jmap.ID(id))
+ mail, err := w.cache.GetEmail(jmap.ID(uid))
if err != nil {
- return fmt.Errorf("bug: unknown message id %s: %w", id, err)
+ return fmt.Errorf("bug: unknown message id %s: %w", uid, err)
}
buf, err := w.cache.GetBlob(mail.BlobID)
if err != nil {
diff --git a/worker/jmap/jmap.go b/worker/jmap/jmap.go
index bb0f75f9..7320ec04 100644
--- a/worker/jmap/jmap.go
+++ b/worker/jmap/jmap.go
@@ -37,7 +37,7 @@ func (w *JMAPWorker) translateMsgInfo(m *email.Email) *models.MessageInfo {
return &models.MessageInfo{
Envelope: env,
Flags: keywordsToFlags(m.Keywords),
- Uid: w.uidStore.GetOrInsert(string(m.ID)),
+ Uid: models.UID(m.ID),
BodyStructure: translateBodyStructure(m.BodyStructure),
RFC822Headers: translateJMAPHeader(m.Headers),
Refs: m.References,
diff --git a/worker/jmap/push.go b/worker/jmap/push.go
index bc90dd77..f2a8ad45 100644
--- a/worker/jmap/push.go
+++ b/worker/jmap/push.go
@@ -247,10 +247,9 @@ func (w *JMAPWorker) refresh(newState jmap.TypeState) error {
}
if w.selectedMbox == mboxId {
- uids := make([]uint32, 0, len(ids))
+ uids := make([]models.UID, 0, len(ids))
for _, id := range ids {
- uid := w.uidStore.GetOrInsert(string(id))
- uids = append(uids, uid)
+ uids = append(uids, models.UID(id))
}
w.w.PostMessage(&types.DirectoryContents{
Uids: uids,
diff --git a/worker/jmap/set.go b/worker/jmap/set.go
index 36b23688..302314c1 100644
--- a/worker/jmap/set.go
+++ b/worker/jmap/set.go
@@ -10,15 +10,11 @@ import (
"git.sr.ht/~rockorager/go-jmap/mail/mailbox"
)
-func (w *JMAPWorker) updateFlags(uids []uint32, flags models.Flags, enable bool) error {
+func (w *JMAPWorker) updateFlags(uids []models.UID, flags models.Flags, enable bool) error {
var req jmap.Request
patches := make(map[jmap.ID]jmap.Patch)
for _, uid := range uids {
- id, ok := w.uidStore.GetKey(uid)
- if !ok {
- return fmt.Errorf("bug: unknown uid %d", uid)
- }
patch := jmap.Patch{}
for kw := range flagsToKeywords(flags) {
path := fmt.Sprintf("keywords/%s", kw)
@@ -28,7 +24,7 @@ func (w *JMAPWorker) updateFlags(uids []uint32, flags models.Flags, enable bool)
patch[path] = nil
}
}
- patches[jmap.ID(id)] = patch
+ patches[jmap.ID(uid)] = patch
}
req.Invoke(&email.Set{
@@ -44,7 +40,7 @@ func (w *JMAPWorker) updateFlags(uids []uint32, flags models.Flags, enable bool)
return checkNotUpdated(resp)
}
-func (w *JMAPWorker) moveCopy(uids []uint32, destDir string, deleteSrc bool) error {
+func (w *JMAPWorker) moveCopy(uids []models.UID, destDir string, deleteSrc bool) error {
var req jmap.Request
var destMbox jmap.ID
var destroy []jmap.ID
@@ -62,13 +58,9 @@ func (w *JMAPWorker) moveCopy(uids []uint32, destDir string, deleteSrc bool) err
for _, uid := range uids {
dest := destMbox
- id, ok := w.uidStore.GetKey(uid)
- if !ok {
- return fmt.Errorf("bug: unknown uid %d", uid)
- }
- mail, err := w.cache.GetEmail(jmap.ID(id))
+ mail, err := w.cache.GetEmail(jmap.ID(uid))
if err != nil {
- return fmt.Errorf("bug: unknown message id %s: %w", id, err)
+ return fmt.Errorf("bug: unknown message id %s: %w", uid, err)
}
patch := w.moveCopyPatch(mail, dest, deleteSrc)
@@ -76,7 +68,7 @@ func (w *JMAPWorker) moveCopy(uids []uint32, destDir string, deleteSrc bool) err
destroy = append(destroy, mail.ID)
w.w.Debugf("destroying <%s>", mail.MessageID[0])
} else {
- patches[jmap.ID(id)] = patch
+ patches[jmap.ID(uid)] = patch
}
}
@@ -161,11 +153,7 @@ func (w *JMAPWorker) handleModifyLabels(msg *types.ModifyLabels) error {
patches := make(map[jmap.ID]jmap.Patch)
for _, uid := range msg.Uids {
- id, ok := w.uidStore.GetKey(uid)
- if !ok {
- return fmt.Errorf("bug: unknown uid %d", uid)
- }
- patches[jmap.ID(id)] = patch
+ patches[jmap.ID(uid)] = patch
}
req.Invoke(&email.Set{
diff --git a/worker/jmap/worker.go b/worker/jmap/worker.go
index 67553272..58883e1e 100644
--- a/worker/jmap/worker.go
+++ b/worker/jmap/worker.go
@@ -6,7 +6,6 @@ import (
"time"
"git.sr.ht/~rjarry/aerc/config"
- "git.sr.ht/~rjarry/aerc/lib/uidstore"
"git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/worker/handlers"
"git.sr.ht/~rjarry/aerc/worker/jmap/cache"
@@ -47,7 +46,6 @@ type JMAPWorker struct {
mbox2dir map[jmap.ID]string
roles map[mailbox.Role]jmap.ID
identities map[string]*identity.Identity
- uidStore *uidstore.Store
changes chan jmap.TypeState
stop chan struct{}
@@ -56,7 +54,6 @@ type JMAPWorker struct {
func NewJMAPWorker(worker *types.Worker) (types.Backend, error) {
return &JMAPWorker{
w: worker,
- uidStore: uidstore.NewStore(),
roles: make(map[mailbox.Role]jmap.ID),
dir2mbox: make(map[string]jmap.ID),
mbox2dir: make(map[jmap.ID]string),
diff --git a/worker/lib/search.go b/worker/lib/search.go
index d44e2ce1..b98e2bbb 100644
--- a/worker/lib/search.go
+++ b/worker/lib/search.go
@@ -13,11 +13,11 @@ import (
"git.sr.ht/~rjarry/go-opt"
)
-func Search(messages []rfc822.RawMessage, criteria *types.SearchCriteria) ([]uint32, error) {
+func Search(messages []rfc822.RawMessage, criteria *types.SearchCriteria) ([]models.UID, error) {
criteria.PrepareHeader()
requiredParts := GetRequiredParts(criteria)
- matchedUids := []uint32{}
+ var matchedUids []models.UID
for _, m := range messages {
success, err := SearchMessage(m, criteria, requiredParts)
if err != nil {
diff --git a/worker/lib/sort.go b/worker/lib/sort.go
index 7af2c6fa..70a64c7b 100644
--- a/worker/lib/sort.go
+++ b/worker/lib/sort.go
@@ -11,7 +11,7 @@ import (
func Sort(messageInfos []*models.MessageInfo,
criteria []*types.SortCriterion,
-) ([]uint32, error) {
+) ([]models.UID, error) {
// loop through in reverse to ensure we sort by non-primary fields first
for i := len(criteria) - 1; i >= 0; i-- {
criterion := criteria[i]
@@ -56,7 +56,7 @@ func Sort(messageInfos []*models.MessageInfo,
})
}
}
- var uids []uint32
+ var uids []models.UID
// copy in reverse as msgList displays backwards
for i := len(messageInfos) - 1; i >= 0; i-- {
uids = append(uids, messageInfos[i].Uid)
diff --git a/worker/maildir/container.go b/worker/maildir/container.go
index dea1ded6..c23825da 100644
--- a/worker/maildir/container.go
+++ b/worker/maildir/container.go
@@ -9,7 +9,7 @@ import (
"github.com/emersion/go-maildir"
"git.sr.ht/~rjarry/aerc/lib/log"
- "git.sr.ht/~rjarry/aerc/lib/uidstore"
+ "git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/worker/lib"
)
@@ -17,8 +17,7 @@ import (
// the Maildir spec
type Container struct {
Store *lib.MaildirStore
- uids *uidstore.Store
- recentUIDS map[uint32]struct{} // used to set the recent flag
+ recentUIDS map[models.UID]struct{} // used to set the recent flag
}
// NewContainer creates a new container at the specified directory
@@ -28,8 +27,8 @@ func NewContainer(dir string, maildirpp bool) (*Container, error) {
return nil, err
}
return &Container{
- Store: store, uids: uidstore.NewStore(),
- recentUIDS: make(map[uint32]struct{}),
+ Store: store,
+ recentUIDS: make(map[models.UID]struct{}),
}, nil
}
@@ -40,8 +39,7 @@ func (c *Container) SyncNewMail(dir maildir.Dir) error {
return err
}
for _, key := range keys {
- uid := c.uids.GetOrInsert(key)
- c.recentUIDS[uid] = struct{}{}
+ c.recentUIDS[models.UID(key)] = struct{}{}
}
return nil
}
@@ -57,18 +55,18 @@ func (c *Container) OpenDirectory(name string) (maildir.Dir, error) {
}
// IsRecent returns if a uid has the Recent flag set
-func (c *Container) IsRecent(uid uint32) bool {
+func (c *Container) IsRecent(uid models.UID) bool {
_, ok := c.recentUIDS[uid]
return ok
}
// ClearRecentFlag removes the Recent flag from the message with the given uid
-func (c *Container) ClearRecentFlag(uid uint32) {
+func (c *Container) ClearRecentFlag(uid models.UID) {
delete(c.recentUIDS, uid)
}
// UIDs fetches the unique message identifiers for the maildir
-func (c *Container) UIDs(d maildir.Dir) ([]uint32, error) {
+func (c *Container) UIDs(d maildir.Dir) ([]models.UID, error) {
keys, err := d.Keys()
if err != nil && len(keys) == 0 {
return nil, fmt.Errorf("could not get keys for %s: %w", d, err)
@@ -77,39 +75,26 @@ func (c *Container) UIDs(d maildir.Dir) ([]uint32, error) {
log.Errorf("could not get all keys for %s: %s", d, err.Error())
}
sort.Strings(keys)
- var uids []uint32
+ var uids []models.UID
for _, key := range keys {
- uids = append(uids, c.uids.GetOrInsert(key))
+ uids = append(uids, models.UID(key))
}
return uids, err
}
// Message returns a Message struct for the given UID and maildir
-func (c *Container) Message(d maildir.Dir, uid uint32) (*Message, error) {
- if key, ok := c.uids.GetKey(uid); ok {
- return &Message{
- dir: d,
- uid: uid,
- key: key,
- }, nil
- }
- return nil, fmt.Errorf("could not find message with uid %d in maildir %s",
- uid, d)
-}
-
-func (c *Container) MessageFromKey(d maildir.Dir, key string) *Message {
- uid := c.uids.GetOrInsert(key)
+func (c *Container) Message(d maildir.Dir, uid models.UID) (*Message, error) {
return &Message{
dir: d,
uid: uid,
- key: key,
- }
+ key: string(uid),
+ }, nil
}
// DeleteAll deletes a set of messages by UID and returns the subset of UIDs
// which were successfully deleted, stopping upon the first error.
-func (c *Container) DeleteAll(d maildir.Dir, uids []uint32) ([]uint32, error) {
- var success []uint32
+func (c *Container) DeleteAll(d maildir.Dir, uids []models.UID) ([]models.UID, error) {
+ var success []models.UID
for _, uid := range uids {
msg, err := c.Message(d, uid)
if err != nil {
@@ -124,46 +109,38 @@ func (c *Container) DeleteAll(d maildir.Dir, uids []uint32) ([]uint32, error) {
}
func (c *Container) CopyAll(
- dest maildir.Dir, src maildir.Dir, uids []uint32,
+ dest maildir.Dir, src maildir.Dir, uids []models.UID,
) error {
for _, uid := range uids {
if err := c.copyMessage(dest, src, uid); err != nil {
- return fmt.Errorf("could not copy message %d: %w", uid, err)
+ return fmt.Errorf("could not copy message %s: %w", uid, err)
}
}
return nil
}
func (c *Container) copyMessage(
- dest maildir.Dir, src maildir.Dir, uid uint32,
+ dest maildir.Dir, src maildir.Dir, uid models.UID,
) error {
- key, ok := c.uids.GetKey(uid)
- if !ok {
- return fmt.Errorf("could not find key for message id %d", uid)
- }
- _, err := src.Copy(dest, key)
+ _, err := src.Copy(dest, string(uid))
return err
}
-func (c *Container) MoveAll(dest maildir.Dir, src maildir.Dir, uids []uint32) ([]uint32, error) {
- var success []uint32
+func (c *Container) MoveAll(dest maildir.Dir, src maildir.Dir, uids []models.UID) ([]models.UID, error) {
+ var success []models.UID
for _, uid := range uids {
if err := c.moveMessage(dest, src, uid); err != nil {
- return success, fmt.Errorf("could not move message %d: %w", uid, err)
+ return success, fmt.Errorf("could not move message %s: %w", uid, err)
}
success = append(success, uid)
}
return success, nil
}
-func (c *Container) moveMessage(dest maildir.Dir, src maildir.Dir, uid uint32) error {
- key, ok := c.uids.GetKey(uid)
- if !ok {
- return fmt.Errorf("could not find key for message id %d", uid)
- }
- path, err := src.Filename(key)
+func (c *Container) moveMessage(dest maildir.Dir, src maildir.Dir, uid models.UID) error {
+ path, err := src.Filename(string(uid))
if err != nil {
- return fmt.Errorf("could not find path for message id %d", uid)
+ return fmt.Errorf("could not find path for message id %s: %w", uid, err)
}
// Remove encoded UID information from the key to prevent sync issues
name := lib.StripUIDFromMessageFilename(filepath.Base(path))
diff --git a/worker/maildir/message.go b/worker/maildir/message.go
index 1d8d26b9..14c83721 100644
--- a/worker/maildir/message.go
+++ b/worker/maildir/message.go
@@ -15,7 +15,7 @@ import (
// A Message is an individual email inside of a maildir.Dir.
type Message struct {
dir maildir.Dir
- uid uint32
+ uid models.UID
key string
}
@@ -135,7 +135,7 @@ func (m Message) NewBodyPartReader(requestedParts []int) (io.Reader, error) {
return rfc822.FetchEntityPartReader(msg, requestedParts)
}
-func (m Message) UID() uint32 {
+func (m Message) UID() models.UID {
return m.uid
}
diff --git a/worker/maildir/search.go b/worker/maildir/search.go
index 90c84087..de2d0530 100644
--- a/worker/maildir/search.go
+++ b/worker/maildir/search.go
@@ -6,11 +6,12 @@ import (
"sync"
"git.sr.ht/~rjarry/aerc/lib/log"
+ "git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/worker/lib"
"git.sr.ht/~rjarry/aerc/worker/types"
)
-func (w *Worker) search(ctx context.Context, criteria *types.SearchCriteria) ([]uint32, error) {
+func (w *Worker) search(ctx context.Context, criteria *types.SearchCriteria) ([]models.UID, error) {
criteria.PrepareHeader()
requiredParts := lib.GetRequiredParts(criteria)
w.worker.Debugf("Required parts bitmask for search: %b", requiredParts)
@@ -20,7 +21,7 @@ func (w *Worker) search(ctx context.Context, criteria *types.SearchCriteria) ([]
return nil, err
}
- matchedUids := []uint32{}
+ var matchedUids []models.UID
mu := sync.Mutex{}
wg := sync.WaitGroup{}
// Hard limit at 2x CPU cores
@@ -33,7 +34,7 @@ func (w *Worker) search(ctx context.Context, criteria *types.SearchCriteria) ([]
default:
limit <- struct{}{}
wg.Add(1)
- go func(key uint32) {
+ go func(key models.UID) {
defer log.PanicHandler()
defer wg.Done()
success, err := w.searchKey(key, criteria, requiredParts)
@@ -55,7 +56,7 @@ func (w *Worker) search(ctx context.Context, criteria *types.SearchCriteria) ([]
}
// Execute the search criteria for the given key, returns true if search succeeded
-func (w *Worker) searchKey(key uint32, criteria *types.SearchCriteria,
+func (w *Worker) searchKey(key models.UID, criteria *types.SearchCriteria,
parts lib.MsgParts,
) (bool, error) {
message, err := w.c.Message(*w.selected, key)
diff --git a/worker/maildir/worker.go b/worker/maildir/worker.go
index 2c5bc893..74efdc3c 100644
--- a/worker/maildir/worker.go
+++ b/worker/maildir/worker.go
@@ -460,7 +460,7 @@ func (w *Worker) handleFetchDirectoryContents(
msg *types.FetchDirectoryContents,
) error {
var (
- uids []uint32
+ uids []models.UID
err error
)
if msg.Filter != nil {
@@ -494,7 +494,7 @@ func (w *Worker) handleFetchDirectoryContents(
return nil
}
-func (w *Worker) sort(ctx context.Context, uids []uint32, criteria []*types.SortCriterion) ([]uint32, error) {
+func (w *Worker) sort(ctx context.Context, uids []models.UID, criteria []*types.SortCriterion) ([]models.UID, error) {
if len(criteria) == 0 {
// At least sort by uid, parallel searching can create random
// order
@@ -516,7 +516,7 @@ func (w *Worker) sort(ctx context.Context, uids []uint32, criteria []*types.Sort
default:
limit <- struct{}{}
wg.Add(1)
- go func(uid uint32) {
+ go func(uid models.UID) {
defer log.PanicHandler()
defer wg.Done()
info, err := w.msgHeadersFromUid(uid)
@@ -546,7 +546,7 @@ func (w *Worker) handleFetchDirectoryThreaded(
msg *types.FetchDirectoryThreaded,
) error {
var (
- uids []uint32
+ uids []models.UID
err error
)
if msg.Filter != nil {
@@ -574,7 +574,7 @@ func (w *Worker) handleFetchDirectoryThreaded(
return nil
}
-func (w *Worker) threads(ctx context.Context, uids []uint32,
+func (w *Worker) threads(ctx context.Context, uids []models.UID,
criteria []*types.SortCriterion,
) ([]*types.Thread, error) {
builder := aercLib.NewThreadBuilder(iterator.NewFactory(false), false)
@@ -590,7 +590,7 @@ func (w *Worker) threads(ctx context.Context, uids []uint32,
default:
limit <- struct{}{}
wg.Add(1)
- go func(uid uint32) {
+ go func(uid models.UID) {
defer log.PanicHandler()
defer wg.Done()
info, err := w.msgHeadersFromUid(uid)
@@ -903,7 +903,7 @@ func (w *Worker) handleSearchDirectory(msg *types.SearchDirectory) error {
return nil
}
-func (w *Worker) msgInfoFromUid(uid uint32) (*models.MessageInfo, error) {
+func (w *Worker) msgInfoFromUid(uid models.UID) (*models.MessageInfo, error) {
m, err := w.c.Message(*w.selected, uid)
if err != nil {
return nil, err
@@ -923,7 +923,7 @@ func (w *Worker) msgInfoFromUid(uid uint32) (*models.MessageInfo, error) {
return info, nil
}
-func (w *Worker) msgHeadersFromUid(uid uint32) (*models.MessageInfo, error) {
+func (w *Worker) msgHeadersFromUid(uid models.UID) (*models.MessageInfo, error) {
m, err := w.c.Message(*w.selected, uid)
if err != nil {
return nil, err
diff --git a/worker/mbox/io.go b/worker/mbox/io.go
index f5fbc596..22d0d023 100644
--- a/worker/mbox/io.go
+++ b/worker/mbox/io.go
@@ -12,7 +12,6 @@ import (
func Read(r io.Reader) ([]rfc822.RawMessage, error) {
mbr := mbox.NewReader(r)
- uid := uint32(0)
messages := make([]rfc822.RawMessage, 0)
for {
msg, err := mbr.NextMessage()
@@ -28,10 +27,10 @@ func Read(r io.Reader) ([]rfc822.RawMessage, error) {
}
messages = append(messages, &message{
- uid: uid, flags: models.SeenFlag, content: content,
+ uid: uidFromContents(content),
+ flags: models.SeenFlag,
+ content: content,
})
-
- uid++
}
return messages, nil
}
diff --git a/worker/mbox/models.go b/worker/mbox/models.go
index 5acd6f5a..ebfe5d32 100644
--- a/worker/mbox/models.go
+++ b/worker/mbox/models.go
@@ -2,6 +2,8 @@ package mboxer
import (
"bytes"
+ "crypto/sha256"
+ "encoding/hex"
"fmt"
"io"
@@ -49,7 +51,7 @@ func (md *mailboxContainer) DirectoryInfo(file string) *models.DirectoryInfo {
}
}
-func (md *mailboxContainer) Copy(dest, src string, uids []uint32) error {
+func (md *mailboxContainer) Copy(dest, src string, uids []models.UID) error {
srcmbox, ok := md.Mailbox(src)
if !ok {
return fmt.Errorf("source %s not found", src)
@@ -69,15 +71,15 @@ func (md *mailboxContainer) Copy(dest, src string, uids []uint32) error {
if found {
msg, err := srcmbox.Message(uidSrc)
if err != nil {
- return fmt.Errorf("could not get message with uid %d from folder %s", uidSrc, src)
+ return fmt.Errorf("could not get message with uid %s from folder %s", uidSrc, src)
}
r, err := msg.NewReader()
if err != nil {
- return fmt.Errorf("could not get reader for message with uid %d", uidSrc)
+ return fmt.Errorf("could not get reader for message with uid %s", uidSrc)
}
flags, err := msg.ModelFlags()
if err != nil {
- return fmt.Errorf("could not get flags for message with uid %d", uidSrc)
+ return fmt.Errorf("could not get flags for message with uid %s", uidSrc)
}
err = destmbox.Append(r, flags)
if err != nil {
@@ -94,24 +96,24 @@ type container struct {
messages []rfc822.RawMessage
}
-func (f *container) Uids() []uint32 {
- uids := make([]uint32, len(f.messages))
+func (f *container) Uids() []models.UID {
+ uids := make([]models.UID, len(f.messages))
for i, m := range f.messages {
uids[i] = m.UID()
}
return uids
}
-func (f *container) Message(uid uint32) (rfc822.RawMessage, error) {
+func (f *container) Message(uid models.UID) (rfc822.RawMessage, error) {
for _, m := range f.messages {
if uid == m.UID() {
return m, nil
}
}
- return &message{}, fmt.Errorf("uid [%d] not found", uid)
+ return &message{}, fmt.Errorf("uid [%s] not found", uid)
}
-func (f *container) Delete(uids []uint32) (deleted []uint32) {
+func (f *container) Delete(uids []models.UID) (deleted []models.UID) {
newMessages := make([]rfc822.RawMessage, 0)
for _, m := range f.messages {
del := false
@@ -131,32 +133,28 @@ func (f *container) Delete(uids []uint32) (deleted []uint32) {
return
}
-func (f *container) newUid() (next uint32) {
- for _, m := range f.messages {
- if uid := m.UID(); uid > next {
- next = uid
- }
- }
- next++
- return
-}
-
func (f *container) Append(r io.Reader, flags models.Flags) error {
data, err := io.ReadAll(r)
if err != nil {
return err
}
f.messages = append(f.messages, &message{
- uid: f.newUid(),
+ uid: uidFromContents(data),
flags: flags,
content: data,
})
return nil
}
+func uidFromContents(data []byte) models.UID {
+ sum := sha256.New()
+ sum.Write(data)
+ return models.UID(hex.EncodeToString(sum.Sum(nil)))
+}
+
// message implements the lib.RawMessage interface
type message struct {
- uid uint32
+ uid models.UID
flags models.Flags
content []byte
}
@@ -173,7 +171,7 @@ func (m *message) Labels() ([]string, error) {
return nil, nil
}
-func (m *message) UID() uint32 {
+func (m *message) UID() models.UID {
return m.uid
}
diff --git a/worker/mbox/worker.go b/worker/mbox/worker.go
index 1f4a4965..72a44368 100644
--- a/worker/mbox/worker.go
+++ b/worker/mbox/worker.go
@@ -405,7 +405,7 @@ func (w *mboxWorker) PathSeparator() string {
return "/"
}
-func filterUids(folder *container, uids []uint32, criteria *types.SearchCriteria) ([]uint32, error) {
+func filterUids(folder *container, uids []models.UID, criteria *types.SearchCriteria) ([]models.UID, error) {
log.Debugf("Search with parsed criteria: %#v", criteria)
m := make([]rfc822.RawMessage, 0, len(uids))
for _, uid := range uids {
@@ -419,9 +419,9 @@ func filterUids(folder *container, uids []uint32, criteria *types.SearchCriteria
return lib.Search(m, criteria)
}
-func sortUids(folder *container, uids []uint32,
+func sortUids(folder *container, uids []models.UID,
criteria []*types.SortCriterion,
-) ([]uint32, error) {
+) ([]models.UID, error) {
var infos []*models.MessageInfo
needSize := false
for _, item := range criteria {
diff --git a/worker/notmuch/lib/database.go b/worker/notmuch/lib/database.go
index 9a8a9a60..2915605d 100644
--- a/worker/notmuch/lib/database.go
+++ b/worker/notmuch/lib/database.go
@@ -10,7 +10,7 @@ import (
"git.sr.ht/~rjarry/aerc/lib/log"
"git.sr.ht/~rjarry/aerc/lib/notmuch"
- "git.sr.ht/~rjarry/aerc/lib/uidstore"
+ "git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/worker/types"
)
@@ -18,7 +18,6 @@ type DB struct {
path string
excludedTags []string
db *notmuch.Database
- uidStore *uidstore.Store
}
func NewDB(path string, excludedTags []string) *DB {
@@ -28,7 +27,6 @@ func NewDB(path string, excludedTags []string) *DB {
db := &DB{
path: path,
excludedTags: excludedTags,
- uidStore: uidstore.NewStore(),
db: nm,
}
return db
@@ -312,14 +310,6 @@ func (db *DB) MsgModifyTags(key string, add, remove []string) error {
return msg.SyncTagsToMaildirFlags()
}
-func (db *DB) UidFromKey(key string) uint32 {
- return db.uidStore.GetOrInsert(key)
-}
-
-func (db *DB) KeyFromUid(uid uint32) (string, bool) {
- return db.uidStore.GetKey(uid)
-}
-
func (db *DB) makeThread(parent *types.Thread, msgs *notmuch.Messages, threadContext bool) []*types.Thread {
var siblings []*types.Thread
for msgs.Next() {
@@ -338,7 +328,7 @@ func (db *DB) makeThread(parent *types.Thread, msgs *notmuch.Messages, threadCon
continue
}
node := &types.Thread{
- Uid: db.uidStore.GetOrInsert(msgID),
+ Uid: models.UID(msgID),
Parent: parent,
}
switch threadContext {
diff --git a/worker/notmuch/message.go b/worker/notmuch/message.go
index 539d85ae..81a4da54 100644
--- a/worker/notmuch/message.go
+++ b/worker/notmuch/message.go
@@ -21,7 +21,7 @@ import (
)
type Message struct {
- uid uint32
+ uid models.UID
key string
db *notmuch.DB
}
@@ -152,7 +152,7 @@ func (m *Message) ModelFlags() (models.Flags, error) {
return flags, nil
}
-func (m *Message) UID() uint32 {
+func (m *Message) UID() models.UID {
return m.uid
}
diff --git a/worker/notmuch/worker.go b/worker/notmuch/worker.go
index 06c0cde6..8c954a61 100644
--- a/worker/notmuch/worker.go
+++ b/worker/notmuch/worker.go
@@ -457,27 +457,21 @@ func (w *worker) handleFetchMessageHeaders(
return nil
}
-func (w *worker) uidsFromQuery(ctx context.Context, query string) ([]uint32, error) {
+func (w *worker) uidsFromQuery(ctx context.Context, query string) ([]models.UID, error) {
msgIDs, err := w.db.MsgIDsFromQuery(ctx, query)
if err != nil {
return nil, err
}
- var uids []uint32
+ var uids []models.UID
for _, id := range msgIDs {
- uid := w.db.UidFromKey(id)
- uids = append(uids, uid)
-
+ uids = append(uids, models.UID(id))
}
return uids, nil
}
-func (w *worker) msgFromUid(uid uint32) (*Message, error) {
- key, ok := w.db.KeyFromUid(uid)
- if !ok {
- return nil, fmt.Errorf("Invalid uid: %v", uid)
- }
+func (w *worker) msgFromUid(uid models.UID) (*Message, error) {
msg := &Message{
- key: key,
+ key: string(uid),
uid: uid,
db: w.db,
}
@@ -613,7 +607,7 @@ func (w *worker) handleModifyLabels(msg *types.ModifyLabels) error {
for _, uid := range msg.Uids {
m, err := w.msgFromUid(uid)
if err != nil {
- return fmt.Errorf("could not get message from uid %d: %w", uid, err)
+ return fmt.Errorf("could not get message from uid %s: %w", uid, err)
}
err = m.ModifyTags(msg.Add, msg.Remove)
if err != nil {
@@ -699,7 +693,7 @@ func (w *worker) emitDirectoryThreaded(parent types.WorkerMessage) error {
return nil
}
-func (w *worker) emitMessageInfoError(msg types.WorkerMessage, uid uint32, err error) {
+func (w *worker) emitMessageInfoError(msg types.WorkerMessage, uid models.UID, err error) {
w.w.PostMessage(&types.MessageInfo{
Info: &models.MessageInfo{
Envelope: &models.Envelope{},
@@ -743,9 +737,9 @@ func (w *worker) emitLabelList() {
w.w.PostMessage(&types.LabelList{Labels: tags}, nil)
}
-func (w *worker) sort(uids []uint32,
+func (w *worker) sort(uids []models.UID,
criteria []*types.SortCriterion,
-) ([]uint32, error) {
+) ([]models.UID, error) {
if len(criteria) == 0 {
return uids, nil
}
@@ -796,7 +790,7 @@ func (w *worker) handleDeleteMessages(msg *types.DeleteMessages) error {
return errUnsupported
}
- var deleted []uint32
+ var deleted []models.UID
folders, _ := w.store.FolderMap()
curDir := folders[w.currentQueryName]
@@ -874,7 +868,7 @@ func (w *worker) handleMoveMessages(msg *types.MoveMessages) error {
return errUnsupported
}
- var moved []uint32
+ var moved []models.UID
folders, _ := w.store.FolderMap()
diff --git a/worker/types/messages.go b/worker/types/messages.go
index b91adbb7..0d0a187a 100644
--- a/worker/types/messages.go
+++ b/worker/types/messages.go
@@ -146,29 +146,29 @@ type RemoveDirectory struct {
type FetchMessageHeaders struct {
Message
Context context.Context
- Uids []uint32
+ Uids []models.UID
}
type FetchFullMessages struct {
Message
- Uids []uint32
+ Uids []models.UID
}
type FetchMessageBodyPart struct {
Message
- Uid uint32
+ Uid models.UID
Part []int
}
type FetchMessageFlags struct {
Message
Context context.Context
- Uids []uint32
+ Uids []models.UID
}
type DeleteMessages struct {
Message
- Uids []uint32
+ Uids []models.UID
MultiFileStrategy *MultiFileStrategy
}
@@ -177,32 +177,32 @@ type FlagMessages struct {
Message
Enable bool
Flags models.Flags
- Uids []uint32
+ Uids []models.UID
}
type AnsweredMessages struct {
Message
Answered bool
- Uids []uint32
+ Uids []models.UID
}
type ForwardedMessages struct {
Message
Forwarded bool
- Uids []uint32
+ Uids []models.UID
}
type CopyMessages struct {
Message
Destination string
- Uids []uint32
+ Uids []models.UID
MultiFileStrategy *MultiFileStrategy
}
type MoveMessages struct {
Message
Destination string
- Uids []uint32
+ Uids []models.UID
MultiFileStrategy *MultiFileStrategy
}
@@ -244,12 +244,12 @@ type DirectoryInfo struct {
type DirectoryContents struct {
Message
- Uids []uint32
+ Uids []models.UID
}
type SearchResults struct {
Message
- Uids []uint32
+ Uids []models.UID
}
type MessageInfo struct {
@@ -270,24 +270,24 @@ type MessageBodyPart struct {
type MessagesDeleted struct {
Message
- Uids []uint32
+ Uids []models.UID
}
type MessagesCopied struct {
Message
Destination string
- Uids []uint32
+ Uids []models.UID
}
type MessagesMoved struct {
Message
Destination string
- Uids []uint32
+ Uids []models.UID
}
type ModifyLabels struct {
Message
- Uids []uint32
+ Uids []models.UID
Add []string
Remove []string
}
diff --git a/worker/types/thread.go b/worker/types/thread.go
index 42565964..fe6c56bf 100644
--- a/worker/types/thread.go
+++ b/worker/types/thread.go
@@ -6,10 +6,11 @@ import (
"sort"
"git.sr.ht/~rjarry/aerc/lib/log"
+ "git.sr.ht/~rjarry/aerc/models"
)
type Thread struct {
- Uid uint32
+ Uid models.UID
Parent *Thread
PrevSibling *Thread
NextSibling *Thread
@@ -77,11 +78,11 @@ func (t *Thread) Root() *Thread {
}
// Uids returns all associated uids for the given thread and its children
-func (t *Thread) Uids() []uint32 {
+func (t *Thread) Uids() []models.UID {
if t == nil {
return nil
}
- uids := make([]uint32, 0)
+ uids := make([]models.UID, 0)
err := t.Walk(func(node *Thread, _ int, _ error) error {
uids = append(uids, node.Uid)
return nil
@@ -96,20 +97,20 @@ func (t *Thread) String() string {
if t == nil {
return "<nil>"
}
- parent := -1
+ var parent models.UID
if t.Parent != nil {
- parent = int(t.Parent.Uid)
+ parent = t.Parent.Uid
}
- next := -1
+ var next models.UID
if t.NextSibling != nil {
- next = int(t.NextSibling.Uid)
+ next = t.NextSibling.Uid
}
- child := -1
+ var child models.UID
if t.FirstChild != nil {
- child = int(t.FirstChild.Uid)
+ child = t.FirstChild.Uid
}
return fmt.Sprintf(
- "[%d] (parent:%v, next:%v, child:%v)",
+ "[%s] (parent:%s, next:%s, child:%s)",
t.Uid, parent, next, child,
)
}
@@ -141,9 +142,9 @@ type NewThreadWalkFn func(t *Thread, level int, currentErr error) error
// Implement interface to be able to sort threads by newest (max UID)
type ByUID []*Thread
-func getMaxUID(thread *Thread) uint32 {
+func getMaxUID(thread *Thread) models.UID {
// TODO: should we make this part of the Thread type to avoid recomputation?
- var Uid uint32
+ var Uid models.UID
_ = thread.Walk(func(t *Thread, _ int, currentErr error) error {
if t.Deleted || t.Hidden > 0 {
@@ -171,9 +172,9 @@ func (s ByUID) Less(i, j int) bool {
return maxUID_i < maxUID_j
}
-func SortThreadsBy(toSort []*Thread, sortBy []uint32) {
+func SortThreadsBy(toSort []*Thread, sortBy []models.UID) {
// build a map from sortBy
- uidMap := make(map[uint32]int)
+ uidMap := make(map[models.UID]int)
for i, uid := range sortBy {
uidMap[uid] = i
}
diff --git a/worker/types/thread_test.go b/worker/types/thread_test.go
index 669803d8..a6a0f327 100644
--- a/worker/types/thread_test.go
+++ b/worker/types/thread_test.go
@@ -4,16 +4,16 @@ import (
"fmt"
"strings"
"testing"
+
+ "git.sr.ht/~rjarry/aerc/models"
)
func genFakeTree() *Thread {
- tree := &Thread{
- Uid: 0,
- }
+ tree := new(Thread)
var prevChild *Thread
- for i := 1; i < 3; i++ {
+ for i := uint32(1); i < uint32(3); i++ {
child := &Thread{
- Uid: uint32(i * 10),
+ Uid: models.Uint32ToUid(i * 10),
Parent: tree,
PrevSibling: prevChild,
}
@@ -26,9 +26,9 @@ func genFakeTree() *Thread {
}
prevChild = child
var prevSecond *Thread
- for j := 1; j < 3; j++ {
+ for j := uint32(1); j < uint32(3); j++ {
second := &Thread{
- Uid: child.Uid + uint32(j),
+ Uid: models.Uint32ToUid(models.UidToUint32(child.Uid) + j),
Parent: child,
PrevSibling: prevSecond,
}
@@ -41,13 +41,13 @@ func genFakeTree() *Thread {
}
prevSecond = second
var prevThird *Thread
- limit := 3
+ limit := uint32(3)
if j == 2 {
limit = 8
}
- for k := 1; k < limit; k++ {
+ for k := uint32(1); k < limit; k++ {
third := &Thread{
- Uid: second.Uid*10 + uint32(k),
+ Uid: models.Uint32ToUid(models.UidToUint32(second.Uid)*10 + j),
Parent: second,
PrevSibling: prevThird,
}
@@ -107,7 +107,7 @@ func TestNewWalk(t *testing.T) {
func uidSeq(tree *Thread) string {
var seq []string
tree.Walk(func(t *Thread, _ int, _ error) error {
- seq = append(seq, fmt.Sprintf("%d", t.Uid))
+ seq = append(seq, string(t.Uid))
return nil
})
return strings.Join(seq, ".")
@@ -116,25 +116,25 @@ func uidSeq(tree *Thread) string {
func TestThread_AddChild(t *testing.T) {
tests := []struct {
name string
- seq []int
+ seq []models.UID
want string
}{
{
name: "ascending",
- seq: []int{1, 2, 3, 4, 5, 6},
- want: "0.1.2.3.4.5.6",
+ seq: []models.UID{"1", "2", "3", "4", "5", "6"},
+ want: ".1.2.3.4.5.6",
},
{
name: "descending",
- seq: []int{6, 5, 4, 3, 2, 1},
- want: "0.6.5.4.3.2.1",
+ seq: []models.UID{"6", "5", "4", "3", "2", "1"},
+ want: ".6.5.4.3.2.1",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
- tree := &Thread{Uid: 0}
+ tree := new(Thread)
for _, i := range test.seq {
- tree.AddChild(&Thread{Uid: uint32(i)})
+ tree.AddChild(&Thread{Uid: i})
}
if got := uidSeq(tree); got != test.want {
t.Errorf("got: %s, but wanted: %s", got,
@@ -147,30 +147,30 @@ func TestThread_AddChild(t *testing.T) {
func TestThread_OrderedInsert(t *testing.T) {
tests := []struct {
name string
- seq []int
+ seq []models.UID
want string
}{
{
name: "ascending",
- seq: []int{1, 2, 3, 4, 5, 6},
- want: "0.1.2.3.4.5.6",
+ seq: []models.UID{"1", "2", "3", "4", "5", "6"},
+ want: ".1.2.3.4.5.6",
},
{
name: "descending",
- seq: []int{6, 5, 4, 3, 2, 1},
- want: "0.1.2.3.4.5.6",
+ seq: []models.UID{"6", "5", "4", "3", "2", "1"},
+ want: ".1.2.3.4.5.6",
},
{
name: "mixed",
- seq: []int{2, 1, 6, 3, 4, 5},
- want: "0.1.2.3.4.5.6",
+ seq: []models.UID{"2", "1", "6", "3", "4", "5"},
+ want: ".1.2.3.4.5.6",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
- tree := &Thread{Uid: 0}
+ tree := new(Thread)
for _, i := range test.seq {
- tree.OrderedInsert(&Thread{Uid: uint32(i)})
+ tree.OrderedInsert(&Thread{Uid: i})
}
if got := uidSeq(tree); got != test.want {
t.Errorf("got: %s, but wanted: %s", got,
@@ -183,32 +183,32 @@ func TestThread_OrderedInsert(t *testing.T) {
func TestThread_InsertCmd(t *testing.T) {
tests := []struct {
name string
- seq []int
+ seq []models.UID
want string
}{
{
name: "ascending",
- seq: []int{1, 2, 3, 4, 5, 6},
- want: "0.6.4.2.1.3.5",
+ seq: []models.UID{"1", "2", "3", "4", "5", "6"},
+ want: ".6.4.2.1.3.5",
},
{
name: "descending",
- seq: []int{6, 5, 4, 3, 2, 1},
- want: "0.6.4.2.1.3.5",
+ seq: []models.UID{"6", "5", "4", "3", "2", "1"},
+ want: ".6.4.2.1.3.5",
},
{
name: "mixed",
- seq: []int{2, 1, 6, 3, 4, 5},
- want: "0.6.4.2.1.3.5",
+ seq: []models.UID{"2", "1", "6", "3", "4", "5"},
+ want: ".6.4.2.1.3.5",
},
}
- sortMap := map[uint32]int{
- uint32(6): 1,
- uint32(4): 2,
- uint32(2): 3,
- uint32(1): 4,
- uint32(3): 5,
- uint32(5): 6,
+ sortMap := map[models.UID]int{
+ "6": 1,
+ "4": 2,
+ "2": 3,
+ "1": 4,
+ "3": 5,
+ "5": 6,
}
// bigger compares the new child with the next node and returns true if
@@ -219,9 +219,9 @@ func TestThread_InsertCmd(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
- tree := &Thread{Uid: 0}
+ tree := new(Thread)
for _, i := range test.seq {
- tree.InsertCmp(&Thread{Uid: uint32(i)}, bigger)
+ tree.InsertCmp(&Thread{Uid: i}, bigger)
}
if got := uidSeq(tree); got != test.want {
t.Errorf("got: %s, but wanted: %s", got,