From 611c25799d994db44bdad4490b7c285380dc51d2 Mon Sep 17 00:00:00 2001 From: William Poussier Date: Wed, 13 Sep 2017 14:44:39 +0200 Subject: [PATCH] executors/imap: proper support for Content-Transfer-Encoding header. (#84) --- executors/imap/decode.go | 97 ++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/executors/imap/decode.go b/executors/imap/decode.go index 5c7408e2..efef8421 100644 --- a/executors/imap/decode.go +++ b/executors/imap/decode.go @@ -3,6 +3,7 @@ package imap import ( "bytes" "crypto/md5" + "encoding/base64" "fmt" "io" "io/ioutil" @@ -34,61 +35,71 @@ func hash(in string) string { func extract(rsp imap.Response, l venom.Logger) (*Mail, error) { tm := &Mail{} - var params map[string]string header := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822.HEADER"]) tm.UID = imap.AsNumber((rsp.MessageInfo().Attrs["UID"])) body := imap.AsBytes(rsp.MessageInfo().Attrs["RFC822.TEXT"]) - if mmsg, _ := mail.ReadMessage(bytes.NewReader(header)); mmsg != nil { - var errds error - tm.Subject, errds = decodeHeader(mmsg, "Subject") - if errds != nil { - log.Warnf("Cannot decode subject: %s", errds) - return nil, nil - } - var errdf error - tm.From, errdf = decodeHeader(mmsg, "From") - if errdf != nil { - log.Warnf("Cannot decode from: %s", errdf) - return nil, nil - } - var errpm error - _, params, errpm = mime.ParseMediaType(mmsg.Header.Get("Content-Type")) - if errpm != nil { - return nil, fmt.Errorf("Error while read Content-Type:%s", errpm) - } + mmsg, err := mail.ReadMessage(bytes.NewReader(header)) + if err != nil { + return nil, err + } + tm.Subject, err = decodeHeader(mmsg, "Subject") + if err != nil { + log.Warnf("Cannot decode subject: %s", err) + return nil, nil + } + tm.From, err = decodeHeader(mmsg, "From") + if err != nil { + log.Warnf("Cannot decode from: %s", err) + return nil, nil } - r := quotedprintable.NewReader(bytes.NewReader(body)) - bodya, errra := ioutil.ReadAll(r) - if errra == nil { - tm.Body = string(bodya) - return tm, nil - } else if len(params) > 0 { - r := bytes.NewReader(body) - mr := multipart.NewReader(r, params["boundary"]) - for { - p, err := mr.NextPart() - if err == io.EOF { - continue - } - if err != nil { - l.Debugf("Error while read Part:%s", err) + encoding := mmsg.Header.Get("Content-Transfer-Encoding") + var r io.Reader = bytes.NewReader(body) + switch encoding { + case "7bit", "8bit", "binary": + // noop, reader already initialized. + case "quoted-printable": + r = quotedprintable.NewReader(r) + case "base64": + r = base64.NewDecoder(base64.StdEncoding, r) + } + l.Debugf("Mail Content-Transfer-Encoding is %s ", encoding) + + contentType, params, err := mime.ParseMediaType(mmsg.Header.Get("Content-Type")) + if err != nil { + return nil, fmt.Errorf("Error while reading Content-Type:%s", err) + } + if contentType == "multipart/mixed" || contentType == "multipart/alternative" { + if boundary, ok := params["boundary"]; ok { + mr := multipart.NewReader(r, boundary) + for { + p, errm := mr.NextPart() + if errm == io.EOF { + continue + } + if errm != nil { + l.Debugf("Error while read Part:%s", err) + break + } + slurp, errm := ioutil.ReadAll(p) + if errm != nil { + l.Debugf("Error while ReadAll Part:%s", err) + continue + } + tm.Body = string(slurp) break } - slurp, err := ioutil.ReadAll(p) - if err != nil { - l.Debugf("Error while ReadAll Part:%s", err) - continue - } - tm.Body = string(slurp) - break + } + } else { + body, err = ioutil.ReadAll(r) + if err != nil { + return nil, err } } - if tm.Body == "" { - tm.Body = string(bodya) + tm.Body = string(body) } return tm, nil }