aerc/commands/compose/postpone.go
Koni Marti 4bd4f4664a postpone: re-open review mode on error
re-opens the review UI when the postpone operation fails. Before, the
composer would close, even on error, and we would lose the email draft.
Now, the user can decide on how to proceed when postponing fails.

References: https://lists.sr.ht/~rjarry/aerc-devel/patches/28824
Signed-off-by: Koni Marti <koni.marti@gmail.com>
2022-02-06 17:06:20 +01:00

125 lines
2.7 KiB
Go

package compose
import (
"io"
"io/ioutil"
"time"
"github.com/miolini/datacounter"
"github.com/pkg/errors"
"git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/widgets"
"git.sr.ht/~rjarry/aerc/worker/types"
)
type Postpone struct{}
func init() {
register(Postpone{})
}
func (Postpone) Aliases() []string {
return []string{"postpone"}
}
func (Postpone) Complete(aerc *widgets.Aerc, args []string) []string {
return nil
}
func (Postpone) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 1 {
return errors.New("Usage: postpone")
}
composer, _ := aerc.SelectedTab().(*widgets.Composer)
config := composer.Config()
tabName := aerc.TabNames()[aerc.SelectedTabIndex()]
if config.Postpone == "" {
return errors.New("No Postpone location configured")
}
aerc.Logger().Println("Postponing mail")
header, err := composer.PrepareHeader()
if err != nil {
return errors.Wrap(err, "PrepareHeader")
}
header.SetContentType("text/plain", map[string]string{"charset": "UTF-8"})
header.Set("Content-Transfer-Encoding", "quoted-printable")
worker := composer.Worker()
dirs := aerc.SelectedAccount().Directories().List()
alreadyCreated := false
for _, dir := range dirs {
if dir == config.Postpone {
alreadyCreated = true
break
}
}
errChan := make(chan string)
// run this as a goroutine so we can make other progress. The message
// will be saved once the directory is created.
go func() {
errStr := <-errChan
if errStr != "" {
aerc.PushError(errStr)
return
}
handleErr := func(err error) {
aerc.PushError(err.Error())
aerc.Logger().Println("Postponing failed:", err)
aerc.NewTab(composer, tabName)
}
aerc.RemoveTab(composer)
ctr := datacounter.NewWriterCounter(ioutil.Discard)
err = composer.WriteMessage(header, ctr)
if err != nil {
handleErr(errors.Wrap(err, "WriteMessage"))
return
}
nbytes := int(ctr.Count())
r, w := io.Pipe()
worker.PostAction(&types.AppendMessage{
Destination: config.Postpone,
Flags: []models.Flag{models.SeenFlag},
Date: time.Now(),
Reader: r,
Length: int(nbytes),
}, func(msg types.WorkerMessage) {
switch msg := msg.(type) {
case *types.Done:
aerc.PushStatus("Message postponed.", 10*time.Second)
r.Close()
composer.Close()
case *types.Error:
r.Close()
handleErr(msg.Error)
}
})
composer.WriteMessage(header, w)
w.Close()
}()
if !alreadyCreated {
// to synchronise the creating of the directory
worker.PostAction(&types.CreateDirectory{
Directory: config.Postpone,
}, func(msg types.WorkerMessage) {
switch msg := msg.(type) {
case *types.Done:
errChan <- ""
case *types.Error:
errChan <- msg.Error.Error()
}
})
} else {
errChan <- ""
}
return nil
}