add vendoring
This commit is contained in:
135
vendor/github.com/jhillyerd/enmime/internal/coding/headerext.go
generated
vendored
Normal file
135
vendor/github.com/jhillyerd/enmime/internal/coding/headerext.go
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
package coding
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// NewExtMimeDecoder creates new MIME word decoder which allows decoding of additional charsets.
|
||||
func NewExtMimeDecoder() *mime.WordDecoder {
|
||||
return &mime.WordDecoder{
|
||||
CharsetReader: NewCharsetReader,
|
||||
}
|
||||
}
|
||||
|
||||
// DecodeExtHeader decodes a single line (per RFC 2047, aka Message Header Extensions) using Golang's
|
||||
// mime.WordDecoder.
|
||||
func DecodeExtHeader(input string) string {
|
||||
if !strings.Contains(input, "=?") {
|
||||
// Don't scan if there is nothing to do here
|
||||
return input
|
||||
}
|
||||
|
||||
header, err := NewExtMimeDecoder().DecodeHeader(input)
|
||||
if err != nil {
|
||||
return input
|
||||
}
|
||||
|
||||
return header
|
||||
}
|
||||
|
||||
// RFC2047Decode returns a decoded string if the input uses RFC2047 encoding, otherwise it will
|
||||
// return the input.
|
||||
//
|
||||
// RFC2047 Example: `=?UTF-8?B?bmFtZT0iw7DCn8KUwoo=?=`
|
||||
func RFC2047Decode(s string) string {
|
||||
// Convert CR/LF to spaces.
|
||||
s = strings.Map(func(r rune) rune {
|
||||
if r == '\n' || r == '\r' {
|
||||
return ' '
|
||||
}
|
||||
return r
|
||||
}, s)
|
||||
|
||||
var err error
|
||||
decoded := false
|
||||
for {
|
||||
s, err = rfc2047Recurse(s)
|
||||
switch err {
|
||||
case nil:
|
||||
decoded = true
|
||||
continue
|
||||
|
||||
default:
|
||||
if decoded {
|
||||
keyValuePair := strings.SplitAfter(s, "=")
|
||||
if len(keyValuePair) < 2 {
|
||||
return s
|
||||
}
|
||||
|
||||
// Add quotes as needed.
|
||||
if !strings.HasPrefix(keyValuePair[1], "\"") {
|
||||
keyValuePair[1] = fmt.Sprintf("\"%s", keyValuePair[1])
|
||||
}
|
||||
if !strings.HasSuffix(keyValuePair[1], "\"") {
|
||||
keyValuePair[1] = fmt.Sprintf("%s\"", keyValuePair[1])
|
||||
}
|
||||
|
||||
return strings.Join(keyValuePair, "")
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// rfc2047Recurse is called for if the value contains content encoded in RFC2047 format and decodes
|
||||
// it.
|
||||
func rfc2047Recurse(s string) (string, error) {
|
||||
us := strings.ToUpper(s)
|
||||
if !strings.Contains(us, "?Q?") && !strings.Contains(us, "?B?") {
|
||||
return s, io.EOF
|
||||
}
|
||||
|
||||
var val string
|
||||
if val = DecodeExtHeader(s); val == s {
|
||||
if val = DecodeExtHeader(fixRFC2047String(val)); val == s {
|
||||
return val, io.EOF
|
||||
}
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// fixRFC2047String removes the following characters from charset and encoding segments of an
|
||||
// RFC2047 string: '\n', '\r' and ' '
|
||||
func fixRFC2047String(s string) string {
|
||||
inString := false
|
||||
isWithinTerminatingEqualSigns := false
|
||||
questionMarkCount := 0
|
||||
sb := &strings.Builder{}
|
||||
for _, v := range s {
|
||||
switch v {
|
||||
case '=':
|
||||
if questionMarkCount == 3 {
|
||||
inString = false
|
||||
} else {
|
||||
isWithinTerminatingEqualSigns = true
|
||||
}
|
||||
sb.WriteRune(v)
|
||||
|
||||
case '?':
|
||||
if isWithinTerminatingEqualSigns {
|
||||
inString = true
|
||||
} else {
|
||||
questionMarkCount++
|
||||
}
|
||||
isWithinTerminatingEqualSigns = false
|
||||
sb.WriteRune(v)
|
||||
|
||||
case '\n', '\r', ' ':
|
||||
if !inString {
|
||||
sb.WriteRune(v)
|
||||
}
|
||||
isWithinTerminatingEqualSigns = false
|
||||
|
||||
default:
|
||||
isWithinTerminatingEqualSigns = false
|
||||
sb.WriteRune(v)
|
||||
}
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
Reference in New Issue
Block a user