From 73dc39c6ee0827fc68b93af8dc438b0e1c14e929 Mon Sep 17 00:00:00 2001 From: Robin Jarry Date: Wed, 14 Aug 2024 16:59:11 +0200 Subject: 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 Tested-by: Inwit Tested-by: Tim Culverhouse --- commands/account/clear.go | 2 +- commands/account/export-mbox.go | 19 ++++++++++--------- commands/account/next.go | 2 +- commands/account/search.go | 2 +- commands/msg/archive.go | 10 +++++----- commands/msg/copy.go | 2 +- commands/msg/delete.go | 4 ++-- commands/msg/forward.go | 6 +++--- commands/msg/invite.go | 2 +- commands/msg/mark.go | 5 +++-- commands/msg/move.go | 4 ++-- commands/msg/pipe.go | 3 ++- commands/msg/read.go | 4 ++-- commands/msg/recall.go | 2 +- commands/msg/reply.go | 4 ++-- commands/msg/utils.go | 2 +- commands/util.go | 16 ++++++++-------- 17 files changed, 46 insertions(+), 43 deletions(-) (limited to 'commands') diff --git a/commands/account/clear.go b/commands/account/clear.go index 1c13ddf5..ec033c46 100644 --- a/commands/account/clear.go +++ b/commands/account/clear.go @@ -35,7 +35,7 @@ func (c Clear) Execute(args []string) error { } if c.Selected { - defer store.Select(0) + defer store.Select("") } store.ApplyClear() acct.SetStatus(state.SearchFilterClear()) diff --git a/commands/account/export-mbox.go b/commands/account/export-mbox.go index 6422eae0..619c24a2 100644 --- a/commands/account/export-mbox.go +++ b/commands/account/export-mbox.go @@ -13,6 +13,7 @@ import ( "git.sr.ht/~rjarry/aerc/lib" "git.sr.ht/~rjarry/aerc/lib/log" "git.sr.ht/~rjarry/aerc/lib/xdg" + "git.sr.ht/~rjarry/aerc/models" mboxer "git.sr.ht/~rjarry/aerc/worker/mbox" "git.sr.ht/~rjarry/aerc/worker/types" ) @@ -61,7 +62,7 @@ func (e ExportMbox) Execute(args []string) error { app.PushStatus("Exporting to "+e.Filename, 10*time.Second) // uids of messages to export - var uids []uint32 + var uids []models.UID // check if something is marked - we export that then msgProvider, ok := app.SelectedTabContent().(app.ProvidesMessages) @@ -98,7 +99,7 @@ func (e ExportMbox) Execute(args []string) error { defer file.Close() var mu sync.Mutex - var ctr uint32 + var ctr uint var retries int done := make(chan bool) @@ -159,15 +160,15 @@ func (e ExportMbox) Execute(args []string) error { return nil } -func sortMarkedUids(marked []uint32, store *lib.MessageStore) ([]uint32, error) { - lookup := map[uint32]bool{} +func sortMarkedUids(marked []models.UID, store *lib.MessageStore) ([]models.UID, error) { + lookup := map[models.UID]bool{} for _, uid := range marked { lookup[uid] = true } - uids := []uint32{} + uids := []models.UID{} iter := store.UidsIterator() for iter.Next() { - uid, ok := iter.Value().(uint32) + uid, ok := iter.Value().(models.UID) if !ok { return nil, errors.New("Invalid message UID value") } @@ -179,11 +180,11 @@ func sortMarkedUids(marked []uint32, store *lib.MessageStore) ([]uint32, error) return uids, nil } -func sortAllUids(store *lib.MessageStore) ([]uint32, error) { - uids := []uint32{} +func sortAllUids(store *lib.MessageStore) ([]models.UID, error) { + uids := []models.UID{} iter := store.UidsIterator() for iter.Next() { - uid, ok := iter.Value().(uint32) + uid, ok := iter.Value().(models.UID) if !ok { return nil, errors.New("Invalid message UID value") } diff --git a/commands/account/next.go b/commands/account/next.go index e14b14fb..b54ed0c1 100644 --- a/commands/account/next.go +++ b/commands/account/next.go @@ -85,7 +85,7 @@ func (np NextPrevMsg) Execute(args []string) error { if nextMsg := store.Selected(); nextMsg != nil { reloadViewer(nextMsg) } else { - store.FetchHeaders([]uint32{store.SelectedUid()}, + store.FetchHeaders([]models.UID{store.SelectedUid()}, func(msg types.WorkerMessage) { if m, ok := msg.(*types.MessageInfo); ok { reloadViewer(m.Info) diff --git a/commands/account/search.go b/commands/account/search.go index 5c2eaec7..14aa367b 100644 --- a/commands/account/search.go +++ b/commands/account/search.go @@ -191,7 +191,7 @@ func (s SearchFilter) Execute(args []string) error { store.Sort(store.GetCurrentSortCriteria(), cb) } else { acct.SetStatus(state.Search("Searching...")) - cb := func(uids []uint32) { + cb := func(uids []models.UID) { acct.SetStatus(state.Search(strings.Join(args, " "))) log.Tracef("Search results: %v", uids) store.ApplySearch(uids) diff --git a/commands/msg/archive.go b/commands/msg/archive.go index 8c5f12b9..c262de41 100644 --- a/commands/msg/archive.go +++ b/commands/msg/archive.go @@ -89,7 +89,7 @@ func archive(msgs []*models.MessageInfo, mfs *types.MultiFileStrategy, if err != nil { return err } - var uids []uint32 + var uids []models.UID for _, msg := range msgs { uids = append(uids, msg.Uid) } @@ -98,7 +98,7 @@ func archive(msgs []*models.MessageInfo, mfs *types.MultiFileStrategy, marker.ClearVisualMark() next := findNextNonDeleted(uids, store) - var uidMap map[string][]uint32 + var uidMap map[string][]models.UID switch archiveType { case ARCHIVE_MONTH: uidMap = groupBy(msgs, func(msg *models.MessageInfo) string { @@ -120,7 +120,7 @@ func archive(msgs []*models.MessageInfo, mfs *types.MultiFileStrategy, return dir }) case ARCHIVE_FLAT: - uidMap = make(map[string][]uint32) + uidMap = make(map[string][]models.UID) uidMap[archiveDir] = commands.UidsFromMessageInfos(msgs) } @@ -164,8 +164,8 @@ func archive(msgs []*models.MessageInfo, mfs *types.MultiFileStrategy, func groupBy(msgs []*models.MessageInfo, grouper func(*models.MessageInfo) string, -) map[string][]uint32 { - m := make(map[string][]uint32) +) map[string][]models.UID { + m := make(map[string][]models.UID) for _, msg := range msgs { group := grouper(msg) m[group] = append(m[group], msg.Uid) diff --git a/commands/msg/copy.go b/commands/msg/copy.go index d9c40ee2..52a6ea6c 100644 --- a/commands/msg/copy.go +++ b/commands/msg/copy.go @@ -175,7 +175,7 @@ func (c Copy) Execute(args []string) error { return nil } -func (c Copy) CallBack(msg types.WorkerMessage, uids []uint32, store *lib.MessageStore) { +func (c Copy) CallBack(msg types.WorkerMessage, uids []models.UID, store *lib.MessageStore) { dest := c.Folder if len(c.Account) != 0 { dest = fmt.Sprintf("%s in %s", c.Folder, c.Account) diff --git a/commands/msg/delete.go b/commands/msg/delete.go index 0d269eab..d58b14ad 100644 --- a/commands/msg/delete.go +++ b/commands/msg/delete.go @@ -117,7 +117,7 @@ func (d Delete) Execute(args []string) error { return nil } -func findNextNonDeleted(deleted []uint32, store *lib.MessageStore) *models.MessageInfo { +func findNextNonDeleted(deleted []models.UID, store *lib.MessageStore) *models.MessageInfo { var next, previous *models.MessageInfo stepper := []func(){store.Next, store.Prev} for _, stepFn := range stepper { @@ -146,7 +146,7 @@ func findNextNonDeleted(deleted []uint32, store *lib.MessageStore) *models.Messa return next } -func contains(uids []uint32, uid uint32) bool { +func contains(uids []models.UID, uid models.UID) bool { for _, item := range uids { if item == uid { return true diff --git a/commands/msg/forward.go b/commands/msg/forward.go index 7c491a06..d030636e 100644 --- a/commands/msg/forward.go +++ b/commands/msg/forward.go @@ -131,7 +131,7 @@ func (f forward) Execute(args []string) error { fetchFull = mv.MessageView().FetchFull } else { fetchFull = func(cb func(io.Reader)) { - store.FetchFull([]uint32{msg.Uid}, func(fm *types.FullMessage) { + store.FetchFull([]models.UID{msg.Uid}, func(fm *types.FullMessage) { if fm == nil || (fm != nil && fm.Content == nil) { return } @@ -164,7 +164,7 @@ func (f forward) Execute(args []string) error { composer.AddAttachment(tmpFileName) composer.OnClose(func(c *app.Composer) { if c.Sent() { - store.Forwarded([]uint32{msg.Uid}, true, nil) + store.Forwarded([]models.UID{msg.Uid}, true, nil) } os.RemoveAll(tmpDir) }) @@ -216,7 +216,7 @@ func (f forward) Execute(args []string) error { composer.OnClose(func(c *app.Composer) { if c.Sent() { - store.Forwarded([]uint32{msg.Uid}, true, nil) + store.Forwarded([]models.UID{msg.Uid}, true, nil) } }) diff --git a/commands/msg/invite.go b/commands/msg/invite.go index c62397c5..63ad2d3a 100644 --- a/commands/msg/invite.go +++ b/commands/msg/invite.go @@ -141,7 +141,7 @@ func (i invite) Execute(args []string) error { composer.OnClose(func(c *app.Composer) { if c.Sent() { - store.Answered([]uint32{msg.Uid}, true, nil) + store.Answered([]models.UID{msg.Uid}, true, nil) } }) diff --git a/commands/msg/mark.go b/commands/msg/mark.go index 5717e33d..42110038 100644 --- a/commands/msg/mark.go +++ b/commands/msg/mark.go @@ -4,6 +4,7 @@ import ( "fmt" "git.sr.ht/~rjarry/aerc/commands" + "git.sr.ht/~rjarry/aerc/models" ) type Mark struct { @@ -28,7 +29,7 @@ func (Mark) Aliases() []string { func (m Mark) Execute(args []string) error { h := newHelper() - OnSelectedMessage := func(fn func(uint32)) error { + OnSelectedMessage := func(fn func(models.UID)) error { if fn == nil { return fmt.Errorf("no operation selected") } @@ -58,7 +59,7 @@ func (m Mark) Execute(args []string) error { switch args[0] { case "mark": - var modFunc func(uint32) + var modFunc func(models.UID) if m.Toggle { modFunc = marker.ToggleMark } else { diff --git a/commands/msg/move.go b/commands/msg/move.go index 96e7c3da..1365b060 100644 --- a/commands/msg/move.go +++ b/commands/msg/move.go @@ -119,7 +119,7 @@ func (m Move) Execute(args []string) error { // something is happening app.PushStatus("Moving messages...", 10*time.Second) - var appended []uint32 + var appended []models.UID var timeout bool go func() { defer log.PanicHandler() @@ -187,7 +187,7 @@ func (m Move) Execute(args []string) error { func (m Move) CallBack( msg types.WorkerMessage, acct *app.AccountView, - uids []uint32, + uids []models.UID, next *models.MessageInfo, marker marker.Marker, timeout bool, diff --git a/commands/msg/pipe.go b/commands/msg/pipe.go index 6ba57089..9764de82 100644 --- a/commands/msg/pipe.go +++ b/commands/msg/pipe.go @@ -15,6 +15,7 @@ import ( "git.sr.ht/~rjarry/aerc/commands" cryptoutil "git.sr.ht/~rjarry/aerc/lib/crypto/util" "git.sr.ht/~rjarry/aerc/lib/log" + "git.sr.ht/~rjarry/aerc/models" mboxer "git.sr.ht/~rjarry/aerc/worker/mbox" "git.sr.ht/~rjarry/aerc/worker/types" ) @@ -122,7 +123,7 @@ func (p Pipe) Run(cb func()) error { app.PushStatus("Fetching messages ...", 10*time.Second) if p.Full { - var uids []uint32 + var uids []models.UID var title string h := newHelper() diff --git a/commands/msg/read.go b/commands/msg/read.go index ab84d51c..686c1a9e 100644 --- a/commands/msg/read.go +++ b/commands/msg/read.go @@ -97,8 +97,8 @@ func (f FlagMsg) Execute(args []string) error { } // UIDs of messages to enable or disable the flag for. - var toEnable []uint32 - var toDisable []uint32 + var toEnable []models.UID + var toDisable []models.UID if f.Toggle { // If toggling, split messages into those that need to diff --git a/commands/msg/recall.go b/commands/msg/recall.go index 7c59ac85..15566414 100644 --- a/commands/msg/recall.go +++ b/commands/msg/recall.go @@ -70,7 +70,7 @@ func (r Recall) Execute(args []string) error { } composer.Tab = app.NewTab(composer, subject) composer.OnClose(func(composer *app.Composer) { - uids := []uint32{msgInfo.Uid} + uids := []models.UID{msgInfo.Uid} deleteMessage := func() { store.Delete( diff --git a/commands/msg/reply.go b/commands/msg/reply.go index e55b5d4b..2654514e 100644 --- a/commands/msg/reply.go +++ b/commands/msg/reply.go @@ -195,13 +195,13 @@ func (r reply) Execute(args []string) error { composer.OnClose(func(c *app.Composer) { switch { case c.Sent() && c.Archive() != "" && !noStore: - store.Answered([]uint32{msg.Uid}, true, nil) + store.Answered([]models.UID{msg.Uid}, true, nil) err := archive([]*models.MessageInfo{msg}, nil, c.Archive()) if err != nil { app.PushStatus("Archive failed", 10*time.Second) } case c.Sent() && !noStore: - store.Answered([]uint32{msg.Uid}, true, nil) + store.Answered([]models.UID{msg.Uid}, true, nil) case mv != nil && r.Close: view := account.ViewMessage{Peek: true} //nolint:errcheck // who cares? diff --git a/commands/msg/utils.go b/commands/msg/utils.go index d6dffd50..f6acb10d 100644 --- a/commands/msg/utils.go +++ b/commands/msg/utils.go @@ -29,7 +29,7 @@ func newHelper() *helper { } } -func (h *helper) markedOrSelectedUids() ([]uint32, error) { +func (h *helper) markedOrSelectedUids() ([]models.UID, error) { return commands.MarkedOrSelected(h.msgProvider) } diff --git a/commands/util.go b/commands/util.go index b6a458fd..bb20a204 100644 --- a/commands/util.go +++ b/commands/util.go @@ -148,7 +148,7 @@ func listDir(path string, hidden bool) []string { // MarkedOrSelected returns either all marked messages if any are marked or the // selected message instead -func MarkedOrSelected(pm app.ProvidesMessages) ([]uint32, error) { +func MarkedOrSelected(pm app.ProvidesMessages) ([]models.UID, error) { // marked has priority over the selected message marked, err := pm.MarkedMessages() if err != nil { @@ -162,15 +162,15 @@ func MarkedOrSelected(pm app.ProvidesMessages) ([]uint32, error) { if err != nil { return nil, err } - return expandFoldedThreads(pm, []uint32{msg.Uid}), nil + return expandFoldedThreads(pm, []models.UID{msg.Uid}), nil } -func expandFoldedThreads(pm app.ProvidesMessages, uids []uint32) []uint32 { +func expandFoldedThreads(pm app.ProvidesMessages, uids []models.UID) []models.UID { store := pm.Store() if store == nil { return uids } - expanded := make([]uint32, len(uids)) + expanded := make([]models.UID, len(uids)) copy(expanded, uids) for _, uid := range uids { thread, err := store.Thread(uid) @@ -194,8 +194,8 @@ func expandFoldedThreads(pm app.ProvidesMessages, uids []uint32) []uint32 { } // UidsFromMessageInfos extracts a uid slice from a slice of MessageInfos -func UidsFromMessageInfos(msgs []*models.MessageInfo) []uint32 { - uids := make([]uint32, len(msgs)) +func UidsFromMessageInfos(msgs []*models.MessageInfo) []models.UID { + uids := make([]models.UID, len(msgs)) i := 0 for _, msg := range msgs { uids[i] = msg.Uid @@ -204,9 +204,9 @@ func UidsFromMessageInfos(msgs []*models.MessageInfo) []uint32 { return uids } -func MsgInfoFromUids(store *lib.MessageStore, uids []uint32, statusInfo func(string)) ([]*models.MessageInfo, error) { +func MsgInfoFromUids(store *lib.MessageStore, uids []models.UID, statusInfo func(string)) ([]*models.MessageInfo, error) { infos := make([]*models.MessageInfo, len(uids)) - needHeaders := make([]uint32, 0) + needHeaders := make([]models.UID, 0) for i, uid := range uids { var ok bool infos[i], ok = store.Messages[uid] -- cgit