aerc/commands/msg/forward.go
Reto Brunner c574a838fa Remove hard coded bodystruct path everywhere
Aerc usually used the path []int{1} if it didn't know what the proper path is.
However this only works for multipart messages and breaks if it isn't one.

This patch removes all the hard coding and extracts the necessary helpers to lib.
2020-07-27 09:19:27 +02:00

154 lines
3.3 KiB
Go

package msg
import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path"
"strings"
"git.sr.ht/~sircmpwn/aerc/lib"
"git.sr.ht/~sircmpwn/aerc/models"
"git.sr.ht/~sircmpwn/aerc/widgets"
"git.sr.ht/~sircmpwn/aerc/worker/types"
"git.sr.ht/~sircmpwn/getopt"
)
type forward struct{}
func init() {
register(forward{})
}
func (forward) Aliases() []string {
return []string{"forward"}
}
func (forward) Complete(aerc *widgets.Aerc, args []string) []string {
return nil
}
func (forward) Execute(aerc *widgets.Aerc, args []string) error {
opts, optind, err := getopt.Getopts(args, "AT:")
if err != nil {
return err
}
attach := false
template := ""
for _, opt := range opts {
switch opt.Option {
case 'A':
attach = true
case 'T':
template = opt.Value
}
}
to := ""
if len(args) != 1 {
to = strings.Join(args[optind:], ", ")
}
widget := aerc.SelectedTab().(widgets.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")
}
msg, err := widget.SelectedMessage()
if err != nil {
return err
}
acct.Logger().Println("Forwarding email " + msg.Envelope.MessageId)
subject := "Fwd: " + msg.Envelope.Subject
defaults := map[string]string{
"To": to,
"Subject": subject,
}
original := models.OriginalMail{}
addTab := func() (*widgets.Composer, error) {
if template != "" {
original.From = models.FormatAddresses(msg.Envelope.From)
original.Date = msg.Envelope.Date
}
composer, err := widgets.NewComposer(aerc, acct, aerc.Config(), acct.AccountConfig(),
acct.Worker(), template, defaults, original)
if err != nil {
aerc.PushError("Error: " + err.Error())
return nil, err
}
tab := aerc.NewTab(composer, subject)
if to == "" {
composer.FocusRecipient()
} else {
composer.FocusTerminal()
}
composer.OnHeaderChange("Subject", func(subject string) {
if subject == "" {
tab.Name = "New email"
} else {
tab.Name = subject
}
tab.Content.Invalidate()
})
return composer, nil
}
if attach {
tmpDir, err := ioutil.TempDir("", "aerc-tmp-attachment")
if err != nil {
return err
}
tmpFileName := path.Join(tmpDir,
strings.ReplaceAll(fmt.Sprintf("%s.eml", msg.Envelope.Subject), "/", "-"))
store.FetchFull([]uint32{msg.Uid}, func(fm *types.FullMessage) {
tmpFile, err := os.Create(tmpFileName)
if err != nil {
println(err)
// TODO: Do something with the error
addTab()
return
}
defer tmpFile.Close()
io.Copy(tmpFile, fm.Content.Reader)
composer, err := addTab()
if err != nil {
return
}
composer.AddAttachment(tmpFileName)
composer.OnClose(func(composer *widgets.Composer) {
os.RemoveAll(tmpDir)
})
})
} else {
if template == "" {
template = aerc.Config().Templates.Forwards
}
// TODO: add attachments!
part := lib.FindPlaintext(msg.BodyStructure, nil)
if part == nil {
part = lib.FindFirstNonMultipart(msg.BodyStructure, nil)
// if it's still nil here, we don't have a multipart msg, that's fine
}
store.FetchBodyPart(msg.Uid, part, func(reader io.Reader) {
buf := new(bytes.Buffer)
buf.ReadFrom(reader)
original.Text = buf.String()
addTab()
})
}
return nil
}