Skip to content

Commit

Permalink
mv mime.QEncoding.Encode logic to mail
Browse files Browse the repository at this point in the history
it is named qEncode
  • Loading branch information
miraclesu committed Jan 26, 2016
1 parent f26d360 commit bf870eb
Showing 1 changed file with 74 additions and 2 deletions.
76 changes: 74 additions & 2 deletions utils/mail.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ import (
"path/filepath"
"strconv"
"strings"
"sync"
)

const (
maxLineLength = 76

upperhex = "0123456789ABCDEF"
)

// Email is the type used for email messages
Expand Down Expand Up @@ -238,8 +241,7 @@ func (e *Email) Send() error {
e.From = e.Username
}
// use mail's RFC 2047 to encode any string
sub := mail.Address{Name: e.Subject, Address: ""}
e.Subject = strings.TrimRight(sub.String(), " <@>")
e.Subject = qEncode("utf-8", e.Subject)

raw, err := e.Bytes()
if err != nil {
Expand Down Expand Up @@ -347,3 +349,73 @@ func base64Wrap(w io.Writer, b []byte) {
w.Write(out)
}
}

// Encode returns the encoded-word form of s. If s is ASCII without special
// characters, it is returned unchanged. The provided charset is the IANA
// charset name of s. It is case insensitive.
// RFC 2047 encoded-word
func qEncode(charset, s string) string {
if !needsEncoding(s) {
return s
}
return encodeWord(charset, s)
}

func needsEncoding(s string) bool {
for _, b := range s {
if (b < ' ' || b > '~') && b != '\t' {
return true
}
}
return false
}

// encodeWord encodes a string into an encoded-word.
func encodeWord(charset, s string) string {
buf := getBuffer()

buf.WriteString("=?")
buf.WriteString(charset)
buf.WriteByte('?')
buf.WriteByte('q')
buf.WriteByte('?')

enc := make([]byte, 3)
for i := 0; i < len(s); i++ {
b := s[i]
switch {
case b == ' ':
buf.WriteByte('_')
case b <= '~' && b >= '!' && b != '=' && b != '?' && b != '_':
buf.WriteByte(b)
default:
enc[0] = '='
enc[1] = upperhex[b>>4]
enc[2] = upperhex[b&0x0f]
buf.Write(enc)
}
}
buf.WriteString("?=")

es := buf.String()
putBuffer(buf)
return es
}

var bufPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}

func getBuffer() *bytes.Buffer {
return bufPool.Get().(*bytes.Buffer)
}

func putBuffer(buf *bytes.Buffer) {
if buf.Len() > 1024 {
return
}
buf.Reset()
bufPool.Put(buf)
}

0 comments on commit bf870eb

Please sign in to comment.