1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
package msg
import (
"errors"
"fmt"
"io"
"os/exec"
"time"
"git.sr.ht/~sircmpwn/aerc/commands"
"git.sr.ht/~sircmpwn/aerc/widgets"
"git.sr.ht/~sircmpwn/aerc/worker/types"
"git.sr.ht/~sircmpwn/getopt"
"github.com/gdamore/tcell"
)
type Pipe struct{}
func init() {
register(Pipe{})
}
func (Pipe) Aliases() []string {
return []string{"pipe"}
}
func (Pipe) Complete(aerc *widgets.Aerc, args []string) []string {
return nil
}
func (Pipe) Execute(aerc *widgets.Aerc, args []string) error {
var (
background bool
pipeFull bool
pipePart bool
)
// TODO: let user specify part by index or preferred mimetype
opts, optind, err := getopt.Getopts(args, "bmp")
if err != nil {
return err
}
for _, opt := range opts {
switch opt.Option {
case 'b':
background = true
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")
}
}
doTerm := func(reader io.Reader, name string) {
term, err := commands.QuickTerm(aerc, cmd, reader)
if err != nil {
aerc.PushError(" " + err.Error())
return
}
aerc.NewTab(term, name)
}
doExec := func(reader io.Reader) {
ecmd := exec.Command(cmd[0], cmd[1:]...)
pipe, err := ecmd.StdinPipe()
if err != nil {
return
}
go func() {
defer pipe.Close()
io.Copy(pipe, reader)
}()
err = ecmd.Run()
if err != nil {
aerc.PushError(" " + err.Error())
} else {
color := tcell.ColorDefault
if ecmd.ProcessState.ExitCode() != 0 {
color = tcell.ColorRed
}
aerc.PushStatus(fmt.Sprintf(
"%s: completed with status %d", cmd[0],
ecmd.ProcessState.ExitCode()), 10*time.Second).
Color(tcell.ColorDefault, color)
}
}
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) {
if background {
doExec(fm.Content.Reader)
} else {
doTerm(fm.Content.Reader, fmt.Sprintf(
"%s <%s", cmd[0], msg.Envelope.Subject))
}
})
} else if pipePart {
p := provider.SelectedMessagePart()
store := provider.Store()
store.FetchBodyPart(p.Msg.Uid, p.Index, func(reader io.Reader) {
if background {
doExec(reader)
} else {
name := fmt.Sprintf("%s <%s/[%d]",
cmd[0], p.Msg.Envelope.Subject, p.Index)
doTerm(reader, name)
}
})
}
return nil
}
|