mirror of
https://git.sr.ht/~rjarry/aerc
synced 2026-03-01 02:34:26 +01:00
Move the cancellation context from individual message types to the base Message struct. Previously, only a few message types (OpenDirectory, FetchDirectoryContents, FetchDirectoryThreaded, SearchDirectory, FetchMessageHeaders, FetchMessageFlags) had a Context field, requiring special handling in workers. Now all worker messages carry a context through the base Message type, set via PostAction's new first parameter. Workers access it uniformly via the Context() method which returns context.Background() when unset. Add a Close() method to MessageStoreView that cancels pending fetch operations when the message viewer is closed, preventing wasted work on messages the user is no longer viewing. Signed-off-by: Robin Jarry <robin@jarry.cc> Reviewed-by: Simon Martin <simon@nasilyan.com>
145 lines
3.1 KiB
Go
145 lines
3.1 KiB
Go
package compose
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"slices"
|
|
"time"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"git.sr.ht/~rjarry/aerc/app"
|
|
"git.sr.ht/~rjarry/aerc/commands"
|
|
"git.sr.ht/~rjarry/aerc/lib/log"
|
|
"git.sr.ht/~rjarry/aerc/models"
|
|
"git.sr.ht/~rjarry/aerc/worker/types"
|
|
)
|
|
|
|
type Postpone struct {
|
|
Folder string `opt:"-t" complete:"CompleteFolder" desc:"Override the target folder."`
|
|
}
|
|
|
|
func init() {
|
|
commands.Register(Postpone{})
|
|
}
|
|
|
|
func (Postpone) Description() string {
|
|
return "Save the current state of the message to the postpone folder."
|
|
}
|
|
|
|
func (Postpone) Context() commands.CommandContext {
|
|
return commands.COMPOSE_REVIEW
|
|
}
|
|
|
|
func (Postpone) Aliases() []string {
|
|
return []string{"postpone"}
|
|
}
|
|
|
|
func (*Postpone) CompleteFolder(arg string) []string {
|
|
return commands.GetFolders(arg)
|
|
}
|
|
|
|
func (p Postpone) Execute(args []string) error {
|
|
acct := app.SelectedAccount()
|
|
if acct == nil {
|
|
return errors.New("No account selected")
|
|
}
|
|
store := acct.Store()
|
|
if store == nil {
|
|
return errors.New("No message store 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()
|
|
}
|
|
if p.Folder != "" {
|
|
targetFolder = p.Folder
|
|
}
|
|
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 := slices.Contains(dirs, targetFolder)
|
|
|
|
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
|
|
}
|
|
store.Append(
|
|
targetFolder,
|
|
models.SeenFlag|models.DraftFlag,
|
|
time.Now(),
|
|
buf,
|
|
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(context.TODO(), &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
|
|
}
|