--- /dev/null
+package main
+
+import (
+ "bufio"
+ "bytes"
+ "io"
+ "log"
+ "mime"
+ "net/mail"
+ "net/textproto"
+ "os"
+ "os/exec"
+ "strings"
+)
+
+func main() {
+ log.SetFlags(log.Lshortfile)
+ rawEnc, err := io.ReadAll(bufio.NewReader(os.Stdin))
+ if err != nil {
+ log.Fatal(err)
+ }
+ msgEnc, err := mail.ReadMessage(bytes.NewReader(rawEnc))
+ if err != nil {
+ log.Fatal(err)
+ }
+ {
+ ct := msgEnc.Header.Get("Content-Type")
+ if ct == "" {
+ log.Fatal("no Content-Type")
+ }
+ mt, params, errParse := mime.ParseMediaType(ct)
+ if errParse != nil {
+ log.Fatal(errParse)
+ }
+ if mt != "multipart/encrypted" {
+ log.Fatal("not multipart/encrypted")
+ }
+ if proto := params["protocol"]; proto != "application/pgp-encrypted" {
+ log.Fatal("not application/pgp-encrypted")
+ }
+ }
+ var rawDec []byte
+ {
+ cmd := exec.Command("gpg", "--batch", "--decrypt", "--status-fd", "3")
+ cmd.Stderr = os.Stderr
+ var stdin io.WriteCloser
+ stdin, err = cmd.StdinPipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+ var stdout io.ReadCloser
+ stdout, err = cmd.StdoutPipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+ var statusR, statusW *os.File
+ statusR, statusW, err = os.Pipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+ cmd.ExtraFiles = append(cmd.ExtraFiles, statusW)
+
+ err = cmd.Start()
+ if err != nil {
+ log.Fatal(err)
+ }
+ go func() {
+ _, errStdin := io.Copy(stdin, msgEnc.Body)
+ if err != nil {
+ log.Print(errStdin)
+ }
+ if errStdin = stdin.Close(); err != nil {
+ log.Print(errStdin)
+ }
+ }()
+ var goodDec bool
+ go func() {
+ s := bufio.NewScanner(statusR)
+ var t string
+ for s.Scan() {
+ t = s.Text()
+ if t == "[GNUPG:] DECRYPTION_OKAY" {
+ goodDec = true
+ }
+ log.Print(t)
+ }
+ if s.Err() != nil {
+ log.Print(s.Err())
+ }
+ }()
+ rawDec, err = io.ReadAll(stdout)
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = cmd.Wait()
+ if err != nil {
+ log.Fatal(err)
+ }
+ if !goodDec {
+ log.Fatal("no DECRYPTION_OKAY received")
+ }
+ }
+ msgDec, err := mail.ReadMessage(bytes.NewReader(rawDec))
+ if err != nil {
+ log.Fatal(err)
+ }
+ stdout := bufio.NewWriter(os.Stdout)
+ r := textproto.NewReader(bufio.NewReader(bytes.NewReader(rawEnc)))
+ var t string
+ var hdr string
+ for {
+ t, err = r.ReadContinuedLine()
+ if err != nil {
+ log.Fatal(err)
+ }
+ if t == "" {
+ break
+ }
+ hdr = t[:strings.Index(t, ":")]
+ if msgDec.Header.Get(hdr) != "" {
+ continue
+ }
+ if _, err = stdout.WriteString(t); err != nil {
+ log.Fatal(err)
+ }
+ if _, err = stdout.WriteString("\n"); err != nil {
+ log.Fatal(err)
+ }
+ }
+ if _, err = io.Copy(stdout, bytes.NewReader(rawDec)); err != nil {
+ log.Fatal(err)
+ }
+ if err = stdout.Flush(); err != nil {
+ log.Fatal(err)
+ }
+}