about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--widgets/msgviewer.go146
1 files changed, 80 insertions, 66 deletions
diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go
index a7b9fd6..d6085bf 100644
--- a/widgets/msgviewer.go
+++ b/widgets/msgviewer.go
@@ -562,75 +562,89 @@ func (pv *PartViewer) SetSource(reader io.Reader) {
 }
 
 func (pv *PartViewer) attemptCopy() {
-	if pv.source != nil && pv.pager != nil && pv.pager.Process != nil {
-		if pv.filter != nil {
-			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()
-			}()
+	if pv.source == nil || pv.pager == nil || pv.pager.Process == nil {
+		return
+	}
+	if pv.filter != nil {
+		pv.copyFilterOutToPager() //delayed until we write to the sink
+	}
+	go func() {
+		pv.writeMailHeaders()
+		if pv.part.MIMEType == "text" {
+			// if the content is plain we can strip ansi control chars
+			pv.copySourceToSinkStripAnsi()
+		} else {
+			// if it's binary we have to rely on the filter to be sane
+			io.Copy(pv.sink, pv.source)
 		}
-		go func() {
-			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'})
+		pv.sink.Close()
+	}()
+}
+
+func (pv *PartViewer) writeMailHeaders() {
+	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" {
-				scanner := bufio.NewScanner(pv.source)
-				for scanner.Scan() {
-					text := scanner.Text()
-					text = ansi.ReplaceAllString(text, "")
-					io.WriteString(pv.sink, text+"\n")
-				}
-			} else {
-				io.Copy(pv.sink, pv.source)
-			}
-			pv.sink.Close()
-		}()
+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")
 	}
 }