init: pristine aerc 0.20.0 source
This commit is contained in:
@@ -0,0 +1,177 @@
|
||||
package msg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
_ "github.com/emersion/go-message/charset"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"git.sr.ht/~rjarry/aerc/app"
|
||||
"git.sr.ht/~rjarry/aerc/commands"
|
||||
"git.sr.ht/~rjarry/aerc/config"
|
||||
"git.sr.ht/~rjarry/aerc/lib"
|
||||
"git.sr.ht/~rjarry/aerc/lib/log"
|
||||
"git.sr.ht/~rjarry/aerc/models"
|
||||
"git.sr.ht/~rjarry/aerc/worker/types"
|
||||
)
|
||||
|
||||
type Recall struct {
|
||||
Force bool `opt:"-f" desc:"Force recall if not in postpone directory."`
|
||||
Edit bool `opt:"-e" desc:"Force [compose].edit-headers = true."`
|
||||
NoEdit bool `opt:"-E" desc:"Force [compose].edit-headers = false."`
|
||||
SkipEditor bool `opt:"-s" desc:"Skip the editor and go directly to the review screen."`
|
||||
}
|
||||
|
||||
func init() {
|
||||
commands.Register(Recall{})
|
||||
}
|
||||
|
||||
func (Recall) Description() string {
|
||||
return "Open a postponed message for re-editing."
|
||||
}
|
||||
|
||||
func (Recall) Context() commands.CommandContext {
|
||||
return commands.MESSAGE_LIST | commands.MESSAGE_VIEWER
|
||||
}
|
||||
|
||||
func (Recall) Aliases() []string {
|
||||
return []string{"recall"}
|
||||
}
|
||||
|
||||
func (r Recall) Execute(args []string) error {
|
||||
editHeaders := (config.Compose.EditHeaders || r.Edit) && !r.NoEdit
|
||||
|
||||
widget := app.SelectedTabContent().(app.ProvidesMessage)
|
||||
acct := widget.SelectedAccount()
|
||||
if acct == nil {
|
||||
return errors.New("No account selected")
|
||||
}
|
||||
store := widget.Store()
|
||||
if store == nil {
|
||||
return errors.New("Cannot perform action. Messages still loading")
|
||||
}
|
||||
|
||||
msgInfo, err := widget.SelectedMessage()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Recall failed")
|
||||
}
|
||||
|
||||
if acct.SelectedDirectory() != acct.AccountConfig().Postpone &&
|
||||
!msgInfo.Flags.Has(models.DraftFlag) && !r.Force {
|
||||
return errors.New("Use -f to recall non-draft messages from outside the " +
|
||||
acct.AccountConfig().Postpone + " directory.")
|
||||
}
|
||||
|
||||
log.Debugf("Recalling message <%s>", msgInfo.Envelope.MessageId)
|
||||
|
||||
addTab := func(composer *app.Composer) {
|
||||
subject := msgInfo.Envelope.Subject
|
||||
if subject == "" {
|
||||
subject = "Recalled email"
|
||||
}
|
||||
composer.Tab = app.NewTab(composer, subject)
|
||||
composer.OnClose(func(composer *app.Composer) {
|
||||
uids := []models.UID{msgInfo.Uid}
|
||||
|
||||
deleteMessage := func() {
|
||||
store.Delete(
|
||||
uids,
|
||||
nil,
|
||||
func(msg types.WorkerMessage) {
|
||||
switch msg := msg.(type) {
|
||||
case *types.Done:
|
||||
app.PushStatus("Recalled message deleted", 10*time.Second)
|
||||
case *types.Error:
|
||||
app.PushError(msg.Error.Error())
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if composer.Sent() || composer.Postponed() {
|
||||
deleteMessage()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
lib.NewMessageStoreView(msgInfo, acct.UiConfig().AutoMarkRead,
|
||||
store, app.CryptoProvider(), app.DecryptKeys,
|
||||
func(msg lib.MessageView, err error) {
|
||||
if err != nil {
|
||||
app.PushError(err.Error())
|
||||
return
|
||||
}
|
||||
var path []int
|
||||
if len(msg.BodyStructure().Parts) != 0 {
|
||||
path = lib.FindPlaintext(msg.BodyStructure(), path)
|
||||
}
|
||||
|
||||
msg.FetchBodyPart(path, func(reader io.Reader) {
|
||||
composer, err := app.NewComposer(acct,
|
||||
acct.AccountConfig(), acct.Worker(), editHeaders,
|
||||
"", msgInfo.RFC822Headers, nil, reader)
|
||||
if err != nil {
|
||||
app.PushError(err.Error())
|
||||
return
|
||||
}
|
||||
if md := msg.MessageDetails(); md != nil {
|
||||
if md.IsEncrypted {
|
||||
composer.SetEncrypt(md.IsEncrypted)
|
||||
}
|
||||
if md.IsSigned {
|
||||
err = composer.SetSign(md.IsSigned)
|
||||
if err != nil {
|
||||
log.Warnf("failed to set signed state: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add attachments if present
|
||||
var mu sync.Mutex
|
||||
parts := lib.FindAllNonMultipart(msg.BodyStructure(), nil, nil)
|
||||
for _, p := range parts {
|
||||
if lib.EqualParts(p, path) {
|
||||
continue
|
||||
}
|
||||
bs, err := msg.BodyStructure().PartAtIndex(p)
|
||||
if err != nil {
|
||||
log.Warnf("cannot get PartAtIndex %v: %v", p, err)
|
||||
continue
|
||||
}
|
||||
msg.FetchBodyPart(p, func(reader io.Reader) {
|
||||
mime := bs.FullMIMEType()
|
||||
params := lib.SetUtf8Charset(bs.Params)
|
||||
name, ok := params["name"]
|
||||
if !ok {
|
||||
name = fmt.Sprintf("%s_%s_%d", bs.MIMEType, bs.MIMESubType, rand.Uint64())
|
||||
}
|
||||
mu.Lock()
|
||||
err := composer.AddPartAttachment(name, mime, params, reader)
|
||||
mu.Unlock()
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
app.PushError(err.Error())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if r.Force {
|
||||
composer.SetRecalledFrom(acct.SelectedDirectory())
|
||||
}
|
||||
|
||||
if r.SkipEditor {
|
||||
composer.Terminal().Close()
|
||||
} else {
|
||||
// focus the terminal since the header fields are likely already done
|
||||
composer.FocusTerminal()
|
||||
}
|
||||
addTab(composer)
|
||||
})
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user