diff options
Diffstat (limited to 'worker')
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, |