aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobin Jarry <robin@jarry.cc>2023-01-25 00:34:59 +0100
committerRobin Jarry <robin@jarry.cc>2023-01-26 00:21:14 +0100
commit63f0e0cbc9a5f072d8915717c89d7ab4f4ff94af (patch)
treeb1940dd2d2a07960786b35f51a7278b326a44179
parent402a634937573b86694b372cf76ce375df51f79d (diff)
downloadaerc-63f0e0cbc9a5f072d8915717c89d7ab4f4ff94af.tar.gz
viewer: allow piping full headers in a filter
Allow defining a .headers special filter command that will be used only to process email headers (when [viewer].show-headers=true). Signed-off-by: Robin Jarry <robin@jarry.cc> Tested-by: Kt Programs <ktprograms@gmail.com>
-rw-r--r--config/aerc.conf6
-rw-r--r--config/filters.go3
-rw-r--r--doc/aerc-config.5.scd11
-rw-r--r--widgets/msgviewer.go54
4 files changed, 65 insertions, 9 deletions
diff --git a/config/aerc.conf b/config/aerc.conf
index 1ce4810e..b09a7ab7 100644
--- a/config/aerc.conf
+++ b/config/aerc.conf
@@ -437,6 +437,12 @@ message/rfc822=colorize
#subject,~Git(hub|lab)=lolcat -f
#from,thatguywhodoesnothardwraphismessages=wrap -w 100 | colorize
+# This special filter is only used to post-process email headers when
+# [viewer].show-headers=true
+# By default, headers are piped directly into the pager.
+#
+#.headers=colorize
+
[openers]
#
# Openers allow you to specify the command to use for the :open action on a
diff --git a/config/filters.go b/config/filters.go
index 0b7a1cb2..113a6de6 100644
--- a/config/filters.go
+++ b/config/filters.go
@@ -13,6 +13,7 @@ type FilterType int
const (
FILTER_MIMETYPE FilterType = iota
FILTER_HEADER
+ FILTER_HEADERS
)
type FilterConfig struct {
@@ -57,6 +58,8 @@ func parseFilters(file *ini.File) error {
if err != nil {
return err
}
+ case filter.Filter == ".headers":
+ filter.Type = FILTER_HEADERS
default:
filter.Type = FILTER_MIMETYPE
}
diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd
index cc0a5f80..22c3a40a 100644
--- a/doc/aerc-config.5.scd
+++ b/doc/aerc-config.5.scd
@@ -644,6 +644,10 @@ The following variables are defined in the filter command environment:
Note that said email body is converted into UTF-8 before being passed to
filters.
+If *show-headers* is enabled, only the currently viewed part body is piped into
+the filter command. A special _.headers_ filter command can be defined to post
+process the full headers.
+
## EXAMPLES
_text/plain_
@@ -708,6 +712,13 @@ _text/\*_
text/\*=bat -fP --file-name="$AERC_FILENAME" --style=plain
```
+_.headers_
+ Colorize email headers when *show-headers* is _true_.
+
+ ```
+ .headers=colorize
+ ```
+
_message/delivery-status_
When not being able to deliver the provider might send such emails:
diff --git a/widgets/msgviewer.go b/widgets/msgviewer.go
index d33e61cc..d2fc0d80 100644
--- a/widgets/msgviewer.go
+++ b/widgets/msgviewer.go
@@ -689,9 +689,45 @@ func (pv *PartViewer) attemptCopy() {
func (pv *PartViewer) writeMailHeaders() {
info := pv.msg.MessageInfo()
if config.Viewer.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
+ var file io.WriteCloser
+
+ for _, f := range config.Filters {
+ if f.Type != config.FILTER_HEADERS {
+ continue
+ }
+ log.Debugf("<%s> piping headers in filter: %s",
+ info.Envelope.MessageId, f.Command)
+ filter := exec.Command("sh", "-c", f.Command)
+ if pv.filter != nil {
+ // inherit from filter env
+ filter.Env = pv.filter.Env
+ }
+
+ stdin, err := filter.StdinPipe()
+ if err == nil {
+ filter.Stdout = pv.pagerin
+ filter.Stderr = pv.pagerin
+ err := filter.Start()
+ if err == nil {
+ //nolint:errcheck // who cares?
+ defer filter.Wait()
+ file = stdin
+ } else {
+ log.Errorf(
+ "failed to start header filter: %v",
+ err)
+ }
+ } else {
+ log.Errorf("failed to create pipe: %v", err)
+ }
+ break
+ }
+ if file == nil {
+ file = pv.pagerin
+ } else {
+ defer file.Close()
+ }
+
fields := info.RFC822Headers.Fields()
for fields.Next() {
var value string
@@ -702,22 +738,22 @@ func (pv *PartViewer) writeMailHeaders() {
}
field := fmt.Sprintf(
"%s: %s\n", fields.Key(), value)
- _, err = pv.pagerin.Write([]byte(field))
+ _, err = file.Write([]byte(field))
if err != nil {
- log.Errorf("failed to write to stdin of pager: %v", err)
+ log.Errorf("failed to write headers: %v", err)
}
}
// virtual header
if len(info.Labels) != 0 {
labels := fmtHeader(info, "Labels", "", "", "", "")
- _, err := pv.pagerin.Write([]byte(fmt.Sprintf("Labels: %s\n", labels)))
+ _, err := file.Write([]byte(fmt.Sprintf("Labels: %s\n", labels)))
if err != nil {
- log.Errorf("failed to write to stdin of pager: %v", err)
+ log.Errorf("failed to write to labels: %v", err)
}
}
- _, err := pv.pagerin.Write([]byte{'\n'})
+ _, err := file.Write([]byte{'\n'})
if err != nil {
- log.Errorf("failed to write to stdin of pager: %v", err)
+ log.Errorf("failed to write empty line: %v", err)
}
}
}