Add forwarding as attachment feature

This allows a single message to be forward as attachment with the
:forward -a command
This commit is contained in:
Jelle Besseling 2019-08-18 11:33:15 +02:00 committed by Drew DeVault
parent 36c6030e81
commit 1f5293931a
3 changed files with 73 additions and 5 deletions

View file

@ -4,10 +4,16 @@ import (
"bufio" "bufio"
"errors" "errors"
"fmt" "fmt"
"git.sr.ht/~sircmpwn/aerc/lib"
"git.sr.ht/~sircmpwn/aerc/models"
"git.sr.ht/~sircmpwn/aerc/widgets" "git.sr.ht/~sircmpwn/aerc/widgets"
"git.sr.ht/~sircmpwn/getopt"
"github.com/emersion/go-message" "github.com/emersion/go-message"
"github.com/emersion/go-message/mail" "github.com/emersion/go-message/mail"
"io" "io"
"io/ioutil"
"os"
"path"
"strings" "strings"
) )
@ -26,9 +32,21 @@ func (_ forward) Complete(aerc *widgets.Aerc, args []string) []string {
} }
func (_ forward) Execute(aerc *widgets.Aerc, args []string) error { func (_ forward) Execute(aerc *widgets.Aerc, args []string) error {
opts, optind, err := getopt.Getopts(args, "A")
if err != nil {
return err
}
attach := false
for _, opt := range opts {
switch opt.Option {
case 'A':
attach = true
}
}
to := "" to := ""
if len(args) != 1 { if len(args) != 1 {
to = strings.Join(args[1:], ", ") to = strings.Join(args[optind:], ", ")
} }
widget := aerc.SelectedTab().(widgets.ProvidesMessage) widget := aerc.SelectedTab().(widgets.ProvidesMessage)
@ -48,7 +66,7 @@ func (_ forward) Execute(aerc *widgets.Aerc, args []string) error {
subject := "Fwd: " + msg.Envelope.Subject subject := "Fwd: " + msg.Envelope.Subject
defaults := map[string]string{ defaults := map[string]string{
"To": to, "To": to,
"Subject": subject, "Subject": subject,
} }
composer := widgets.NewComposer(aerc.Config(), acct.AccountConfig(), composer := widgets.NewComposer(aerc.Config(), acct.AccountConfig(),
@ -56,7 +74,7 @@ func (_ forward) Execute(aerc *widgets.Aerc, args []string) error {
addTab := func() { addTab := func() {
tab := aerc.NewTab(composer, subject) tab := aerc.NewTab(composer, subject)
if len(args) == 1 { if to == "" {
composer.FocusRecipient() composer.FocusRecipient()
} else { } else {
composer.FocusTerminal() composer.FocusTerminal()
@ -71,6 +89,46 @@ func (_ forward) Execute(aerc *widgets.Aerc, args []string) error {
}) })
} }
if attach {
forwardAttach(store, composer, msg, addTab)
} else {
forwardBodyPart(store, composer, msg, addTab)
}
return nil
}
func forwardAttach(store *lib.MessageStore, composer *widgets.Composer,
msg *models.MessageInfo, addTab func()) {
store.FetchFull([]uint32{msg.Uid}, func(reader io.Reader) {
tmpDir, err := ioutil.TempDir("", "aerc-tmp-attachment")
if err != nil {
// TODO: Do something with the error
addTab()
return
}
tmpFileName := path.Join(tmpDir,
strings.ReplaceAll(fmt.Sprintf("%s.eml", msg.Envelope.Subject), "/", "-"))
tmpFile, err := os.Create(tmpFileName)
if err != nil {
println(err)
// TODO: Do something with the error
addTab()
return
}
defer tmpFile.Close()
io.Copy(tmpFile, reader)
composer.AddAttachment(tmpFileName)
composer.OnClose(func(composer *widgets.Composer) {
os.RemoveAll(tmpDir)
})
addTab()
})
}
func forwardBodyPart(store *lib.MessageStore, composer *widgets.Composer,
msg *models.MessageInfo, addTab func()) {
// TODO: something more intelligent than fetching the 1st part // TODO: something more intelligent than fetching the 1st part
// TODO: add attachments! // TODO: add attachments!
store.FetchBodyPart(msg.Uid, []int{1}, func(reader io.Reader) { store.FetchBodyPart(msg.Uid, []int{1}, func(reader io.Reader) {
@ -108,5 +166,4 @@ func (_ forward) Execute(aerc *widgets.Aerc, args []string) error {
pipeout.Close() pipeout.Close()
addTab() addTab()
}) })
return nil
} }

View file

@ -90,9 +90,11 @@ message list, the message in the message viewer, etc).
*delete* *delete*
Deletes the selected message. Deletes the selected message.
*forward* [address...] *forward* [-A] [address...]
Opens the composer to forward the selected message to another recipient. Opens the composer to forward the selected message to another recipient.
*-A*: Forward the message as an RFC 8022 attachment.
*move* <target> *move* <target>
Moves the selected message to the target folder. Moves the selected message to the target folder.

View file

@ -42,6 +42,8 @@ type Composer struct {
layout HeaderLayout layout HeaderLayout
focusable []ui.DrawableInteractive focusable []ui.DrawableInteractive
focused int focused int
onClose []func(ti *Composer)
} }
func NewComposer(conf *config.AercConfig, func NewComposer(conf *config.AercConfig,
@ -169,6 +171,10 @@ func (c *Composer) OnHeaderChange(header string, fn func(subject string)) {
} }
} }
func (c *Composer) OnClose(fn func(composer *Composer)) {
c.onClose = append(c.onClose, fn)
}
func (c *Composer) Draw(ctx *ui.Context) { func (c *Composer) Draw(ctx *ui.Context) {
c.grid.Draw(ctx) c.grid.Draw(ctx)
} }
@ -184,6 +190,9 @@ func (c *Composer) OnInvalidate(fn func(d ui.Drawable)) {
} }
func (c *Composer) Close() { func (c *Composer) Close() {
for _, onClose := range c.onClose {
onClose(c)
}
if c.email != nil { if c.email != nil {
path := c.email.Name() path := c.email.Name()
c.email.Close() c.email.Close()