msgviewer: simplify attemptCopy

No functional changes, simply extract more complex stuff into
sub functions to help readability.
This commit is contained in:
Reto Brunner 2020-07-28 09:51:36 +02:00
parent bc9d6fc187
commit 01885e2448
1 changed files with 80 additions and 66 deletions

View File

@ -562,75 +562,89 @@ func (pv *PartViewer) SetSource(reader io.Reader) {
} }
func (pv *PartViewer) attemptCopy() { func (pv *PartViewer) attemptCopy() {
if pv.source != nil && pv.pager != nil && pv.pager.Process != nil { if pv.source == nil || pv.pager == nil || pv.pager.Process == nil {
if pv.filter != nil { return
stdout, _ := pv.filter.StdoutPipe() }
stderr, _ := pv.filter.StderrPipe() if pv.filter != nil {
pv.filter.Start() pv.copyFilterOutToPager() //delayed until we write to the sink
ch := make(chan interface{}) }
go func() { go func() {
_, err := io.Copy(pv.pagerin, stdout) pv.writeMailHeaders()
if err != nil { if pv.part.MIMEType == "text" {
pv.err = err // if the content is plain we can strip ansi control chars
pv.Invalidate() pv.copySourceToSinkStripAnsi()
} } else {
stdout.Close() // if it's binary we have to rely on the filter to be sane
ch <- nil io.Copy(pv.sink, pv.source)
}()
go func() {
_, err := io.Copy(pv.pagerin, stderr)
if err != nil {
pv.err = err
pv.Invalidate()
}
stderr.Close()
ch <- nil
}()
go func() {
<-ch
<-ch
pv.filter.Wait()
pv.pagerin.Close()
}()
} }
go func() { pv.sink.Close()
info := pv.msg.MessageInfo() }()
if pv.showHeaders && info.RFC822Headers != nil { }
// header need to bypass the filter, else we run into issues
// with the filter messing with newlines etc.
// hence all writes in this block go directly to the pager
fields := info.RFC822Headers.Fields()
for fields.Next() {
var value string
var err error
if value, err = fields.Text(); err != nil {
// better than nothing, use the non decoded version
value = fields.Value()
}
field := fmt.Sprintf(
"%s: %s\n", fields.Key(), value)
pv.pagerin.Write([]byte(field))
}
// virtual header
if len(info.Labels) != 0 {
labels := fmtHeader(info, "Labels", "")
pv.pagerin.Write([]byte(fmt.Sprintf("Labels: %s\n", labels)))
}
pv.pagerin.Write([]byte{'\n'})
}
if pv.part.MIMEType == "text" { func (pv *PartViewer) writeMailHeaders() {
scanner := bufio.NewScanner(pv.source) info := pv.msg.MessageInfo()
for scanner.Scan() { if pv.showHeaders && info.RFC822Headers != nil {
text := scanner.Text() // header need to bypass the filter, else we run into issues
text = ansi.ReplaceAllString(text, "") // with the filter messing with newlines etc.
io.WriteString(pv.sink, text+"\n") // hence all writes in this block go directly to the pager
} fields := info.RFC822Headers.Fields()
} else { for fields.Next() {
io.Copy(pv.sink, pv.source) var value string
var err error
if value, err = fields.Text(); err != nil {
// better than nothing, use the non decoded version
value = fields.Value()
} }
pv.sink.Close() field := fmt.Sprintf(
}() "%s: %s\n", fields.Key(), value)
pv.pagerin.Write([]byte(field))
}
// virtual header
if len(info.Labels) != 0 {
labels := fmtHeader(info, "Labels", "")
pv.pagerin.Write([]byte(fmt.Sprintf("Labels: %s\n", labels)))
}
pv.pagerin.Write([]byte{'\n'})
}
}
func (pv *PartViewer) copyFilterOutToPager() {
stdout, _ := pv.filter.StdoutPipe()
stderr, _ := pv.filter.StderrPipe()
pv.filter.Start()
ch := make(chan interface{})
go func() {
_, err := io.Copy(pv.pagerin, stdout)
if err != nil {
pv.err = err
pv.Invalidate()
}
stdout.Close()
ch <- nil
}()
go func() {
_, err := io.Copy(pv.pagerin, stderr)
if err != nil {
pv.err = err
pv.Invalidate()
}
stderr.Close()
ch <- nil
}()
go func() {
<-ch
<-ch
pv.filter.Wait()
pv.pagerin.Close()
}()
}
func (pv *PartViewer) copySourceToSinkStripAnsi() {
scanner := bufio.NewScanner(pv.source)
for scanner.Scan() {
text := scanner.Text()
text = ansi.ReplaceAllString(text, "")
io.WriteString(pv.sink, text+"\n")
} }
} }