package compose import ( "bytes" "time" "github.com/pkg/errors" "git.sr.ht/~sircmpwn/getopt" "git.sr.ht/~rjarry/aerc/app" "git.sr.ht/~rjarry/aerc/commands" "git.sr.ht/~rjarry/aerc/log" "git.sr.ht/~rjarry/aerc/models" "git.sr.ht/~rjarry/aerc/worker/types" ) type Postpone struct{} func init() { register(Postpone{}) } func (Postpone) Aliases() []string { return []string{"postpone"} } func (Postpone) Options() string { return "t:" } func (Postpone) CompleteOption(r rune, arg string) []string { var valid []string if r == 't' { valid = commands.GetFolders([]string{arg}) } return commands.CompletionFromList(valid, []string{arg}) } func (Postpone) Complete(args []string) []string { return nil } func (p Postpone) Execute(args []string) error { opts, optind, err := getopt.Getopts(args, p.Options()) if err != nil { return err } acct := app.SelectedAccount() if acct == nil { return errors.New("No account selected") } tab := app.SelectedTab() if tab == nil { return errors.New("No tab selected") } composer, _ := tab.Content.(*app.Composer) config := composer.Config() tabName := tab.Name targetFolder := config.Postpone if composer.RecalledFrom() != "" { targetFolder = composer.RecalledFrom() } for _, opt := range opts { if opt.Option == 't' { targetFolder = opt.Value } } args = args[optind:] if len(args) != 0 { return errors.New("Usage: postpone [-t ]") } if targetFolder == "" { return errors.New("No Postpone location configured") } log.Tracef("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 := acct.Directories().List() alreadyCreated := false for _, dir := range dirs { if dir == targetFolder { 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() { defer log.PanicHandler() errStr := <-errChan if errStr != "" { app.PushError(errStr) return } handleErr := func(err error) { app.PushError(err.Error()) log.Errorf("Postponing failed: %v", err) app.NewTab(composer, tabName) } app.RemoveTab(composer, false) buf := &bytes.Buffer{} err = composer.WriteMessage(header, buf) if err != nil { handleErr(errors.Wrap(err, "WriteMessage")) return } worker.PostAction(&types.AppendMessage{ Destination: targetFolder, Flags: models.SeenFlag, Date: time.Now(), Reader: buf, Length: buf.Len(), }, func(msg types.WorkerMessage) { switch msg := msg.(type) { case *types.Done: app.PushStatus("Message postponed.", 10*time.Second) composer.SetPostponed() composer.Close() case *types.Error: handleErr(msg.Error) } }) }() if !alreadyCreated { // to synchronise the creating of the directory worker.PostAction(&types.CreateDirectory{ Directory: targetFolder, }, func(msg types.WorkerMessage) { switch msg := msg.(type) { case *types.Done: errChan <- "" case *types.Error: errChan <- msg.Error.Error() } }) } else { errChan <- "" } return nil }