From 1f5293931adf591fcbeaa9a272d717240da9213a Mon Sep 17 00:00:00 2001 From: Jelle Besseling Date: Sun, 18 Aug 2019 11:33:15 +0200 Subject: Add forwarding as attachment feature This allows a single message to be forward as attachment with the :forward -a command --- commands/msg/forward.go | 65 ++++++++++++++++++++++++++++++++++++++++++++++--- doc/aerc.1.scd | 4 ++- widgets/compose.go | 9 +++++++ 3 files changed, 73 insertions(+), 5 deletions(-) diff --git a/commands/msg/forward.go b/commands/msg/forward.go index ca29096..7f23a0a 100644 --- a/commands/msg/forward.go +++ b/commands/msg/forward.go @@ -4,10 +4,16 @@ import ( "bufio" "errors" "fmt" + "git.sr.ht/~sircmpwn/aerc/lib" + "git.sr.ht/~sircmpwn/aerc/models" "git.sr.ht/~sircmpwn/aerc/widgets" + "git.sr.ht/~sircmpwn/getopt" "github.com/emersion/go-message" "github.com/emersion/go-message/mail" "io" + "io/ioutil" + "os" + "path" "strings" ) @@ -26,9 +32,21 @@ func (_ forward) Complete(aerc *widgets.Aerc, args []string) []string { } 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 := "" if len(args) != 1 { - to = strings.Join(args[1:], ", ") + to = strings.Join(args[optind:], ", ") } widget := aerc.SelectedTab().(widgets.ProvidesMessage) @@ -48,7 +66,7 @@ func (_ forward) Execute(aerc *widgets.Aerc, args []string) error { subject := "Fwd: " + msg.Envelope.Subject defaults := map[string]string{ - "To": to, + "To": to, "Subject": subject, } composer := widgets.NewComposer(aerc.Config(), acct.AccountConfig(), @@ -56,7 +74,7 @@ func (_ forward) Execute(aerc *widgets.Aerc, args []string) error { addTab := func() { tab := aerc.NewTab(composer, subject) - if len(args) == 1 { + if to == "" { composer.FocusRecipient() } else { 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: add attachments! 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() addTab() }) - return nil } diff --git a/doc/aerc.1.scd b/doc/aerc.1.scd index e172f89..4aa777c 100644 --- a/doc/aerc.1.scd +++ b/doc/aerc.1.scd @@ -90,9 +90,11 @@ message list, the message in the message viewer, etc). *delete* Deletes the selected message. -*forward* [address...] +*forward* [-A] [address...] Opens the composer to forward the selected message to another recipient. + *-A*: Forward the message as an RFC 8022 attachment. + *move* Moves the selected message to the target folder. diff --git a/widgets/compose.go b/widgets/compose.go index b4ae078..a49a947 100644 --- a/widgets/compose.go +++ b/widgets/compose.go @@ -42,6 +42,8 @@ type Composer struct { layout HeaderLayout focusable []ui.DrawableInteractive focused int + + onClose []func(ti *Composer) } 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) { c.grid.Draw(ctx) } @@ -184,6 +190,9 @@ func (c *Composer) OnInvalidate(fn func(d ui.Drawable)) { } func (c *Composer) Close() { + for _, onClose := range c.onClose { + onClose(c) + } if c.email != nil { path := c.email.Name() c.email.Close() -- cgit 1.4.1-2-gfad0