Koni Marti: 1 recover: recover emails from tempdir after a crash 1 files changed, 110 insertions(+), 0 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~rjarry/aerc-devel/patches/28824/mbox | git am -3Learn more about email & git
implements a recover command that searches the local temp dir for aerc emails. If a file is found and selected, a new composer tab will open with the file contents as the message body. No header data is stored in the temp file and thus this information cannot be recovered.
That is a pity. It makes me want to challenge the design choice that was made to not allow editing the headers in the text editor. I wonder if that could be a possible new global setting for aerc: [compose] edit-headers = true Most text editors allow defining macros to ease email headers management. I believe {,neo}mutt works that way.kt programs <ktprograms@gmail.com>Even if the editor doesn't have macros, it would still be a massive improvement from the current header editors, which can't cut and paste, which I needed to use in composing _this_ very email in order to move some of the addresses to the Cc field.Enabling this would of course break mirroring the Subject header to the composer tab title. I don't think it is a bad compromise but it may be a deal breaker for some users.kt programs <ktprograms@gmail.com>Perhaps, if replying to an email, the tab title could be populated with the Re: stuff, and if composing a new email, just make it "Composing..." Then make it clear that the Subject header needs to be on the first line, so that when the file is written to (maybe even if the editor isn't quit), the first line can be parsed and the tab title updated. However, this might be a bit weird to integrate with the message review screen as it stands currently, because you wouldn't be able to review anything about the message, unless the message review screen has a [v]iew option to show the message text including its headers.However, it would mean that all headers are saved into the temp file and thus completely "recoverable". What do you think?
Recover will not remove the temporary file unless the force flag (-f) is explicitly used. This recovery method only works when the editor buffer is saved to disk and the Close() function of the composer has not been called yet. Sending, postponing or quitting will call the Close() function which removes the temporary file completely. After Close() is called, no recovery is possible anymore. Signed-off-by: Koni Marti <koni.marti@gmail.com> --- If there are no recoverable files for testing, you can compose a new message and save the file buffer. Run 'killall aerc' to simulate a crash and at the next start, you should be able to recover the message.
I gave it a quick test. It works as advertised :)
As a reminder, we should perform a code review of the send and postpone commands to make sure they do not close the composer unless the message has been properly saved or sent.
It looks like these two commands do close the composer on error. Another patch would be welcome to avoid discarding the temp file on error.I guess there are two ways to deal with this: 1) have a CloseOnError() (instead of Close()) function that does not remove the file, or 2) shows the composer again in a new tab for the user to decide what to do? I gravitate towards 2). What are your thoughts?To git.sr.ht:~rjarry/aerc fc07495ee889..cdec23323c64 cdec23323c64 -> master Thanks!
commands/account/recover.go | 110 ++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 commands/account/recover.go diff --git a/commands/account/recover.go b/commands/account/recover.go new file mode 100644 index 0000000..a167d50 --- /dev/null +++ b/commands/account/recover.go @@ -0,0 +1,110 @@ +package account + +import ( + "bytes" + "errors" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "git.sr.ht/~rjarry/aerc/models" + "git.sr.ht/~rjarry/aerc/widgets" + "git.sr.ht/~sircmpwn/getopt" +) + +type Recover struct{} + +func init() { + register(Recover{}) +} + +func (Recover) Aliases() []string { + return []string{"recover"} +} + +func (Recover) Complete(aerc *widgets.Aerc, args []string) []string { + // file name of temp file is hard-coded in the NewComposer() function + files, err := filepath.Glob( + filepath.Join(os.TempDir(), "aerc-compose-*.eml"), + ) + if err != nil { + return []string{} + } + arg := strings.Join(args, " ") + if arg != "" { + for i, file := range files { + files[i] = strings.Join([]string{arg, file}, " ") + } + } + return files +} + +func (Recover) Execute(aerc *widgets.Aerc, args []string) error { + if len(Recover{}.Complete(aerc, args)) == 0 { + return errors.New("No messages to recover.") + } + + force := false + + opts, optind, err := getopt.Getopts(args, "f") + if err != nil { + return err + } + for _, opt := range opts { + switch opt.Option { + case 'f': + force = true + } + } + + if len(args) <= optind { + return errors.New("Usage: recover [-f] <file>") + } + + acct := aerc.SelectedAccount() + if acct == nil { + return errors.New("No account selected") + } + + readData := func() ([]byte, error) { + recoverFile, err := os.Open(args[optind]) + if err != nil { + return nil, err + } + defer recoverFile.Close() + data, err := ioutil.ReadAll(recoverFile) + if err != nil { + return nil, err + } + return data, nil + } + data, err := readData() + if err != nil { + return err + } + + composer, err := widgets.NewComposer(aerc, acct, + aerc.Config(), acct.AccountConfig(), acct.Worker(), + "", nil, models.OriginalMail{}) + if err != nil { + return err + } + + tab := aerc.NewTab(composer, "Recovered") + composer.OnHeaderChange("Subject", func(subject string) { + tab.Name = subject + tab.Content.Invalidate() + }) + go composer.AppendContents(bytes.NewReader(data)) + + // remove file if force flag is set + if force { + err = os.Remove(args[optind]) + if err != nil { + return err + } + } + + return nil +} -- 2.34.1
builds.sr.ht <builds@sr.ht>aerc/patches: SUCCESS in 4m4s [recover: recover emails from tempdir after a crash][0] from [Koni Marti][1] [0]: https://lists.sr.ht/~rjarry/aerc-devel/patches/28824 [1]: mailto:koni.marti@gmail.com ✓ #683142 SUCCESS aerc/patches/alpine-edge.yml https://builds.sr.ht/~rjarry/job/683142 ✓ #683145 SUCCESS aerc/patches/openbsd.yml https://builds.sr.ht/~rjarry/job/683145 ✓ #683144 SUCCESS aerc/patches/fedora-latest.yml https://builds.sr.ht/~rjarry/job/683144 ✓ #683143 SUCCESS aerc/patches/debian-stable.yml https://builds.sr.ht/~rjarry/job/683143
Koni Marti, Jan 28, 2022 at 22:50: