75 lines
1.9 KiB
Go
75 lines
1.9 KiB
Go
package enmime
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"io"
|
|
"net/textproto"
|
|
|
|
"github.com/jhillyerd/enmime/internal/coding"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
var defaultHeadersList = []string{
|
|
"From",
|
|
"To",
|
|
"Sender",
|
|
"CC",
|
|
"BCC",
|
|
"Subject",
|
|
"Date",
|
|
}
|
|
|
|
// DecodeHeaders returns a limited selection of mime headers for use by user agents
|
|
// Default header list:
|
|
// "Date", "Subject", "Sender", "From", "To", "CC" and "BCC"
|
|
//
|
|
// Additional headers provided will be formatted canonically:
|
|
// h, err := enmime.DecodeHeaders(b, "content-type", "user-agent")
|
|
func DecodeHeaders(b []byte, addtlHeaders ...string) (textproto.MIMEHeader, error) {
|
|
b = ensureHeaderBoundary(b)
|
|
tr := textproto.NewReader(bufio.NewReader(bytes.NewReader(b)))
|
|
headers, err := tr.ReadMIMEHeader()
|
|
switch errors.Cause(err) {
|
|
case nil, io.EOF:
|
|
// carry on, io.EOF is expected
|
|
default:
|
|
return nil, err
|
|
}
|
|
headerList := defaultHeadersList
|
|
headerList = append(headerList, addtlHeaders...)
|
|
res := map[string][]string{}
|
|
for _, header := range headerList {
|
|
h := textproto.CanonicalMIMEHeaderKey(header)
|
|
res[h] = make([]string, 0, len(headers[h]))
|
|
for _, value := range headers[h] {
|
|
res[h] = append(res[h], coding.RFC2047Decode(value))
|
|
}
|
|
}
|
|
|
|
return res, nil
|
|
}
|
|
|
|
// ensureHeaderBoundary scans through an rfc822 document to ensure the boundary between headers and body exists
|
|
func ensureHeaderBoundary(b []byte) []byte {
|
|
slice := bytes.SplitAfter(b, []byte{'\r', '\n'})
|
|
dest := make([]byte, 0, len(b)+2)
|
|
headers := true
|
|
for _, v := range slice {
|
|
if headers && (bytes.Contains(v, []byte{':'}) || bytes.HasPrefix(v, []byte{' '}) || bytes.HasPrefix(v, []byte{'\t'})) {
|
|
dest = append(dest, v...)
|
|
continue
|
|
}
|
|
if headers {
|
|
headers = false
|
|
if !bytes.Equal(v, []byte{'\r', '\n'}) {
|
|
dest = append(dest, append([]byte{'\r', '\n'}, v...)...)
|
|
continue
|
|
}
|
|
}
|
|
dest = append(dest, v...)
|
|
}
|
|
|
|
return dest
|
|
}
|