diff options
author | Jason Cox <me@jasoncarloscox.com> | 2024-02-23 11:40:17 -0500 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2024-04-02 22:22:28 +0200 |
commit | 1ce82f50d0981a9ee047e75d94c7ab496070bd4a (patch) | |
tree | 72d835ad5da26eea6d5a6acbdd916640b75f1a4e /commands | |
parent | 54a72f83035bdf710368846e55a5b003ccab66cd (diff) | |
download | aerc-1ce82f50d0981a9ee047e75d94c7ab496070bd4a.tar.gz |
notmuch: add strategies for multi-file messages
A single notmuch message can represent multiple files. As a result,
file-based operations like move, copy, and delete can be ambiguous. Add
a new account config option, multi-file-strategy, to tell aerc how to
handle these ambiguous cases. Also add options to relevant commands to
set the multi-file strategy on a per-invocation basis.
If no multi-file strategy is set, refuse to take file-based actions on
multi-file messages. This default behavior is mostly the same as aerc's
previous behavior, but a bit stricter in some cases which previously
tried to be smart about multi-file operations (e.g., move and delete).
Applying multi-file strategies to cross-account copy and move operations
is not implemented. These operations will proceed as they have in the
past -- aerc will copy/move a single file. However, for cross-account
move operations, aerc will refuse to delete multiple files to prevent
data loss as not all of the files are added to the destination account.
See the changes to aerc-notmuch(5) for details on the currently
supported multi-file strategies.
Changelog-added: Tell aerc how to handle file-based operations
on multi-file notmuch messages with the account config option
`multi-file-strategy` and the `-m` flag to `:archive`, `:copy`,
`:delete`, and `:move`.
Signed-off-by: Jason Cox <me@jasoncarloscox.com>
Tested-by: Maarten Aertsen <maarten@nlnetlabs.nl>
Acked-by: Robin Jarry <robin@jarry.cc>
Diffstat (limited to 'commands')
-rw-r--r-- | commands/msg/archive.go | 26 | ||||
-rw-r--r-- | commands/msg/copy.go | 29 | ||||
-rw-r--r-- | commands/msg/delete.go | 23 | ||||
-rw-r--r-- | commands/msg/move.go | 32 | ||||
-rw-r--r-- | commands/msg/recall.go | 1 | ||||
-rw-r--r-- | commands/msg/reply.go | 2 |
6 files changed, 92 insertions, 21 deletions
diff --git a/commands/msg/archive.go b/commands/msg/archive.go index 0714a805..8c5f12b9 100644 --- a/commands/msg/archive.go +++ b/commands/msg/archive.go @@ -22,7 +22,19 @@ const ( var ARCHIVE_TYPES = []string{ARCHIVE_FLAT, ARCHIVE_YEAR, ARCHIVE_MONTH} type Archive struct { - Type string `opt:"type" action:"ParseArchiveType" metavar:"flat|year|month" complete:"CompleteType"` + MultiFileStrategy *types.MultiFileStrategy `opt:"-m" action:"ParseMFS" complete:"CompleteMFS"` + Type string `opt:"type" action:"ParseArchiveType" metavar:"flat|year|month" complete:"CompleteType"` +} + +func (a *Archive) ParseMFS(arg string) error { + if arg != "" { + mfs, ok := types.StrToStrategy[arg] + if !ok { + return fmt.Errorf("invalid multi-file strategy %s", arg) + } + a.MultiFileStrategy = &mfs + } + return nil } func (a *Archive) ParseArchiveType(arg string) error { @@ -47,6 +59,10 @@ func (Archive) Aliases() []string { return []string{"archive"} } +func (Archive) CompleteMFS(arg string) []string { + return commands.FilterList(types.StrategyStrs(), arg, nil) +} + func (*Archive) CompleteType(arg string) []string { return commands.FilterList(ARCHIVE_TYPES, arg, nil) } @@ -57,11 +73,13 @@ func (a Archive) Execute(args []string) error { if err != nil { return err } - err = archive(msgs, a.Type) + err = archive(msgs, a.MultiFileStrategy, a.Type) return err } -func archive(msgs []*models.MessageInfo, archiveType string) error { +func archive(msgs []*models.MessageInfo, mfs *types.MultiFileStrategy, + archiveType string, +) error { h := newHelper() acct, err := h.account() if err != nil { @@ -111,7 +129,7 @@ func archive(msgs []*models.MessageInfo, archiveType string) error { success := true for dir, uids := range uidMap { - store.Move(uids, dir, true, func( + store.Move(uids, dir, true, mfs, func( msg types.WorkerMessage, ) { switch msg := msg.(type) { diff --git a/commands/msg/copy.go b/commands/msg/copy.go index af44216f..9ea81055 100644 --- a/commands/msg/copy.go +++ b/commands/msg/copy.go @@ -14,9 +14,10 @@ import ( ) type Copy struct { - CreateFolders bool `opt:"-p"` - Account string `opt:"-a" complete:"CompleteAccount"` - Folder string `opt:"folder" complete:"CompleteFolder"` + CreateFolders bool `opt:"-p"` + Account string `opt:"-a" complete:"CompleteAccount"` + MultiFileStrategy *types.MultiFileStrategy `opt:"-m" action:"ParseMFS" complete:"CompleteMFS"` + Folder string `opt:"folder" complete:"CompleteFolder"` } func init() { @@ -31,6 +32,17 @@ func (Copy) Aliases() []string { return []string{"cp", "copy"} } +func (c *Copy) ParseMFS(arg string) error { + if arg != "" { + mfs, ok := types.StrToStrategy[arg] + if !ok { + return fmt.Errorf("invalid multi-file strategy %s", arg) + } + c.MultiFileStrategy = &mfs + } + return nil +} + func (*Copy) CompleteAccount(arg string) []string { return commands.FilterList(app.AccountNames(), arg, commands.QuoteSpace) } @@ -48,6 +60,10 @@ func (c *Copy) CompleteFolder(arg string) []string { return commands.FilterList(acct.Directories().List(), arg, nil) } +func (Copy) CompleteMFS(arg string) []string { + return commands.FilterList(types.StrategyStrs(), arg, nil) +} + func (c Copy) Execute(args []string) error { h := newHelper() uids, err := h.markedOrSelectedUids() @@ -60,9 +76,10 @@ func (c Copy) Execute(args []string) error { } if len(c.Account) == 0 { - store.Copy(uids, c.Folder, c.CreateFolders, func(msg types.WorkerMessage) { - c.CallBack(msg, uids, store) - }) + store.Copy(uids, c.Folder, c.CreateFolders, c.MultiFileStrategy, + func(msg types.WorkerMessage) { + c.CallBack(msg, uids, store) + }) return nil } diff --git a/commands/msg/delete.go b/commands/msg/delete.go index 0abde31c..0d269eab 100644 --- a/commands/msg/delete.go +++ b/commands/msg/delete.go @@ -13,7 +13,9 @@ import ( "git.sr.ht/~rjarry/aerc/worker/types" ) -type Delete struct{} +type Delete struct { + MultiFileStrategy *types.MultiFileStrategy `opt:"-m" action:"ParseMFS" complete:"CompleteMFS"` +} func init() { commands.Register(Delete{}) @@ -27,7 +29,22 @@ func (Delete) Aliases() []string { return []string{"delete", "delete-message"} } -func (Delete) Execute(args []string) error { +func (d *Delete) ParseMFS(arg string) error { + if arg != "" { + mfs, ok := types.StrToStrategy[arg] + if !ok { + return fmt.Errorf("invalid multi-file strategy %s", arg) + } + d.MultiFileStrategy = &mfs + } + return nil +} + +func (Delete) CompleteMFS(arg string) []string { + return commands.FilterList(types.StrategyStrs(), arg, nil) +} + +func (d Delete) Execute(args []string) error { h := newHelper() store, err := h.store() if err != nil { @@ -46,7 +63,7 @@ func (Delete) Execute(args []string) error { marker.ClearVisualMark() // caution, can be nil next := findNextNonDeleted(uids, store) - store.Delete(uids, func(msg types.WorkerMessage) { + store.Delete(uids, d.MultiFileStrategy, func(msg types.WorkerMessage) { switch msg := msg.(type) { case *types.Done: var s string diff --git a/commands/msg/move.go b/commands/msg/move.go index d2623268..c073765f 100644 --- a/commands/msg/move.go +++ b/commands/msg/move.go @@ -17,9 +17,10 @@ import ( ) type Move struct { - CreateFolders bool `opt:"-p"` - Account string `opt:"-a" complete:"CompleteAccount"` - Folder string `opt:"folder" complete:"CompleteFolder"` + CreateFolders bool `opt:"-p"` + Account string `opt:"-a" complete:"CompleteAccount"` + MultiFileStrategy *types.MultiFileStrategy `opt:"-m" action:"ParseMFS" complete:"CompleteMFS"` + Folder string `opt:"folder" complete:"CompleteFolder"` } func init() { @@ -34,6 +35,17 @@ func (Move) Aliases() []string { return []string{"mv", "move"} } +func (m *Move) ParseMFS(arg string) error { + if arg != "" { + mfs, ok := types.StrToStrategy[arg] + if !ok { + return fmt.Errorf("invalid multi-file strategy %s", arg) + } + m.MultiFileStrategy = &mfs + } + return nil +} + func (*Move) CompleteAccount(arg string) []string { return commands.FilterList(app.AccountNames(), arg, commands.QuoteSpace) } @@ -51,6 +63,10 @@ func (m *Move) CompleteFolder(arg string) []string { return commands.FilterList(acct.Directories().List(), arg, nil) } +func (Move) CompleteMFS(arg string) []string { + return commands.FilterList(types.StrategyStrs(), arg, nil) +} + func (m Move) Execute(args []string) error { h := newHelper() acct, err := h.account() @@ -71,9 +87,10 @@ func (m Move) Execute(args []string) error { marker.ClearVisualMark() if len(m.Account) == 0 { - store.Move(uids, m.Folder, m.CreateFolders, func(msg types.WorkerMessage) { - m.CallBack(msg, acct, uids, next, marker, false) - }) + store.Move(uids, m.Folder, m.CreateFolders, m.MultiFileStrategy, + func(msg types.WorkerMessage) { + m.CallBack(msg, acct, uids, next, marker, false) + }) return nil } @@ -158,7 +175,8 @@ func (m Move) Execute(args []string) error { } } if len(appended) > 0 { - store.Delete(appended, func(msg types.WorkerMessage) { + mfs := types.Refuse + store.Delete(appended, &mfs, func(msg types.WorkerMessage) { m.CallBack(msg, acct, appended, next, marker, timeout) }) } diff --git a/commands/msg/recall.go b/commands/msg/recall.go index 280c41b8..7c59ac85 100644 --- a/commands/msg/recall.go +++ b/commands/msg/recall.go @@ -75,6 +75,7 @@ func (r Recall) Execute(args []string) error { deleteMessage := func() { store.Delete( uids, + nil, func(msg types.WorkerMessage) { switch msg := msg.(type) { case *types.Done: diff --git a/commands/msg/reply.go b/commands/msg/reply.go index 02cf42ce..79a0c598 100644 --- a/commands/msg/reply.go +++ b/commands/msg/reply.go @@ -184,7 +184,7 @@ func (r reply) Execute(args []string) error { switch { case c.Sent() && c.Archive() != "" && !noStore: store.Answered([]uint32{msg.Uid}, true, nil) - err := archive([]*models.MessageInfo{msg}, c.Archive()) + err := archive([]*models.MessageInfo{msg}, nil, c.Archive()) if err != nil { app.PushStatus("Archive failed", 10*time.Second) } |