aerc/commands/msg/pipe.go

146 lines
3 KiB
Go
Raw Normal View History

2019-07-05 18:21:12 +02:00
package msg
import (
"errors"
"fmt"
"io"
2019-07-09 00:19:08 +02:00
"os/exec"
"time"
2019-07-05 18:21:12 +02:00
"git.sr.ht/~sircmpwn/aerc/commands"
"git.sr.ht/~sircmpwn/aerc/widgets"
"git.sr.ht/~sircmpwn/aerc/worker/types"
2019-07-09 00:19:08 +02:00
"git.sr.ht/~sircmpwn/getopt"
"github.com/gdamore/tcell"
2019-07-05 18:21:12 +02:00
)
type Pipe struct{}
func init() {
register(Pipe{})
}
func (Pipe) Aliases() []string {
2019-07-05 18:21:12 +02:00
return []string{"pipe"}
}
func (Pipe) Complete(aerc *widgets.Aerc, args []string) []string {
2019-07-05 18:21:12 +02:00
return nil
}
func (Pipe) Execute(aerc *widgets.Aerc, args []string) error {
2019-07-05 18:21:12 +02:00
var (
2019-07-09 00:19:08 +02:00
background bool
pipeFull bool
pipePart bool
2019-07-05 18:21:12 +02:00
)
// TODO: let user specify part by index or preferred mimetype
2019-07-09 00:19:08 +02:00
opts, optind, err := getopt.Getopts(args, "bmp")
2019-07-05 18:21:12 +02:00
if err != nil {
return err
}
for _, opt := range opts {
switch opt.Option {
2019-07-09 00:19:08 +02:00
case 'b':
background = true
2019-07-05 18:21:12 +02:00
case 'm':
if pipePart {
return errors.New("-m and -p are mutually exclusive")
}
pipeFull = true
case 'p':
if pipeFull {
return errors.New("-m and -p are mutually exclusive")
}
pipePart = true
}
}
cmd := args[optind:]
if len(cmd) == 0 {
return errors.New("Usage: pipe [-mp] <cmd> [args...]")
}
provider := aerc.SelectedTab().(widgets.ProvidesMessage)
if !pipeFull && !pipePart {
if _, ok := provider.(*widgets.MessageViewer); ok {
pipePart = true
} else if _, ok := provider.(*widgets.AccountView); ok {
pipeFull = true
} else {
return errors.New(
"Neither -m nor -p specified and cannot infer default")
}
}
2019-07-09 00:19:08 +02:00
doTerm := func(reader io.Reader, name string) {
term, err := commands.QuickTerm(aerc, cmd, reader)
if err != nil {
aerc.PushError(" " + err.Error())
2019-07-09 00:19:08 +02:00
return
}
aerc.NewTab(term, name)
}
doExec := func(reader io.Reader) {
ecmd := exec.Command(cmd[0], cmd[1:]...)
2019-07-09 00:50:40 +02:00
pipe, err := ecmd.StdinPipe()
if err != nil {
return
}
go func() {
defer pipe.Close()
io.Copy(pipe, reader)
}()
err = ecmd.Run()
2019-07-09 00:19:08 +02:00
if err != nil {
aerc.PushError(" " + err.Error())
2019-07-09 00:19:08 +02:00
} else {
color := tcell.ColorDefault
2019-07-09 00:32:31 +02:00
if ecmd.ProcessState.ExitCode() != 0 {
color = tcell.ColorRed
2019-07-09 00:32:31 +02:00
}
aerc.PushStatus(fmt.Sprintf(
"%s: completed with status %d", cmd[0],
ecmd.ProcessState.ExitCode()), 10*time.Second).
Color(tcell.ColorDefault, color)
2019-07-09 00:19:08 +02:00
}
}
2019-07-05 18:21:12 +02:00
if pipeFull {
store := provider.Store()
if store == nil {
return errors.New("Cannot perform action. Messages still loading")
}
msg, err := provider.SelectedMessage()
if err != nil {
return err
}
store.FetchFull([]uint32{msg.Uid}, func(fm *types.FullMessage) {
2019-07-09 00:19:08 +02:00
if background {
doExec(fm.Content.Reader)
2019-07-09 00:19:08 +02:00
} else {
doTerm(fm.Content.Reader, fmt.Sprintf(
2019-07-09 00:19:08 +02:00
"%s <%s", cmd[0], msg.Envelope.Subject))
2019-07-05 18:21:12 +02:00
}
})
} else if pipePart {
p := provider.SelectedMessagePart()
2020-07-05 14:27:21 +02:00
if p == nil {
return fmt.Errorf("could not fetch message part")
}
store := provider.Store()
store.FetchBodyPart(p.Msg.Uid, p.Index, func(reader io.Reader) {
2019-07-09 00:19:08 +02:00
if background {
doExec(reader)
} else {
name := fmt.Sprintf("%s <%s/[%d]",
cmd[0], p.Msg.Envelope.Subject, p.Index)
doTerm(reader, name)
2019-07-05 18:21:12 +02:00
}
})
}
return nil
}