summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattermost/rsc/imap/decode.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mattermost/rsc/imap/decode.go')
-rw-r--r--vendor/github.com/mattermost/rsc/imap/decode.go227
1 files changed, 227 insertions, 0 deletions
diff --git a/vendor/github.com/mattermost/rsc/imap/decode.go b/vendor/github.com/mattermost/rsc/imap/decode.go
new file mode 100644
index 000000000..ebeb1d7d7
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/decode.go
@@ -0,0 +1,227 @@
+package imap
+
+import (
+ "bytes"
+ "encoding/base64"
+ "strings"
+ "unicode"
+)
+
+func decode2047chunk(s string) (conv []byte, rest string, ok bool) {
+ // s is =?...
+ // and should be =?charset?e?text?=
+ j := strings.Index(s[2:], "?")
+ if j < 0 {
+ return
+ }
+ j += 2
+ if j+2 >= len(s) || s[j+2] != '?' {
+ return
+ }
+ k := strings.Index(s[j+3:], "?=")
+ if k < 0 {
+ return
+ }
+ k += j + 3
+
+ charset, enc, text, rest := s[2:j], s[j+1], s[j+3:k], s[k+2:]
+ var encoding string
+ switch enc {
+ default:
+ return
+ case 'q', 'Q':
+ encoding = "quoted-printable"
+ case 'b', 'B':
+ encoding = "base64"
+ }
+
+ dat := decodeText([]byte(text), encoding, charset, true)
+ if dat == nil {
+ return
+ }
+ return dat, rest, true
+}
+
+func decodeQP(dat []byte, underscore bool) []byte {
+ out := make([]byte, len(dat))
+ w := 0
+ for i := 0; i < len(dat); i++ {
+ c := dat[i]
+ if underscore && c == '_' {
+ out[w] = ' '
+ w++
+ continue
+ }
+ if c == '\r' {
+ continue
+ }
+ if c == '=' {
+ if i+1 < len(dat) && dat[i+1] == '\n' {
+ i++
+ continue
+ }
+ if i+2 < len(dat) && dat[i+1] == '\r' && dat[i+2] == '\n' {
+ i += 2
+ continue
+ }
+ if i+2 < len(dat) {
+ v := unhex(dat[i+1])<<4 | unhex(dat[i+2])
+ if v >= 0 {
+ out[w] = byte(v)
+ w++
+ i += 2
+ continue
+ }
+ }
+ }
+ out[w] = c
+ w++
+ }
+ return out[:w]
+}
+
+func nocrnl(dat []byte) []byte {
+ w := 0
+ for _, c := range dat {
+ if c != '\r' && c != '\n' {
+ dat[w] = c
+ w++
+ }
+ }
+ return dat[:w]
+}
+
+func decode64(dat []byte) []byte {
+ out := make([]byte, len(dat))
+ copy(out, dat)
+ out = nocrnl(out)
+ n, err := base64.StdEncoding.Decode(out, out)
+ if err != nil {
+ return nil
+ }
+ return out[:n]
+}
+
+func decodeText(dat []byte, encoding, charset string, underscore bool) []byte {
+ odat := dat
+ switch strlwr(encoding) {
+ case "quoted-printable":
+ dat = decodeQP(dat, underscore)
+ case "base64":
+ dat = decode64(dat)
+ }
+ if dat == nil {
+ return nil
+ }
+ if bytes.IndexByte(dat, '\r') >= 0 {
+ if &odat[0] == &dat[0] {
+ dat = append([]byte(nil), dat...)
+ }
+ dat = nocr(dat)
+ }
+
+ charset = strlwr(charset)
+ if charset == "utf-8" || charset == "us-ascii" {
+ return dat
+ }
+ if charset == "iso-8859-1" {
+ // Avoid allocation for iso-8859-1 that is really just ascii.
+ for _, c := range dat {
+ if c >= 0x80 {
+ goto NeedConv
+ }
+ }
+ return dat
+ NeedConv:
+ }
+
+ // TODO: big5, iso-2022-jp
+
+ tab := convtab[charset]
+ if tab == nil {
+ return dat
+ }
+ var b bytes.Buffer
+ for _, c := range dat {
+ if tab[c] < 0 {
+ b.WriteRune(unicode.ReplacementChar)
+ } else {
+ b.WriteRune(tab[c])
+ }
+ }
+ return b.Bytes()
+}
+
+var convtab = map[string]*[256]rune{
+ "iso-8859-1": &tab_iso8859_1,
+ "iso-8859-2": &tab_iso8859_2,
+ "iso-8859-3": &tab_iso8859_3,
+ "iso-8859-4": &tab_iso8859_4,
+ "iso-8859-5": &tab_iso8859_5,
+ "iso-8859-6": &tab_iso8859_6,
+ "iso-8859-7": &tab_iso8859_7,
+ "iso-8859-8": &tab_iso8859_8,
+ "iso-8859-9": &tab_iso8859_9,
+ "iso-8859-10": &tab_iso8859_10,
+ "iso-8859-15": &tab_iso8859_15,
+ "koi8-r": &tab_koi8,
+ "windows-1250": &tab_cp1250,
+ "windows-1251": &tab_cp1251,
+ "windows-1252": &tab_cp1252,
+ "windows-1253": &tab_cp1253,
+ "windows-1254": &tab_cp1254,
+ "windows-1255": &tab_cp1255,
+ "windows-1256": &tab_cp1256,
+ "windows-1257": &tab_cp1257,
+ "windows-1258": &tab_cp1258,
+}
+
+func unrfc2047(s string) string {
+ if !strings.Contains(s, "=?") {
+ return s
+ }
+ var buf bytes.Buffer
+ for {
+ // =?charset?e?text?=
+ i := strings.Index(s, "=?")
+ if i < 0 {
+ break
+ }
+ conv, rest, ok := decode2047chunk(s[i:])
+ if !ok {
+ buf.WriteString(s[:i+2])
+ s = s[i+2:]
+ continue
+ }
+ buf.WriteString(s[:i])
+ buf.Write(conv)
+ s = rest
+ }
+ buf.WriteString(s)
+ return buf.String()
+}
+
+func lwr(c rune) rune {
+ if 'A' <= c && c <= 'Z' {
+ return c + 'a' - 'A'
+ }
+ return c
+}
+
+func strlwr(s string) string {
+ return strings.Map(lwr, s)
+}
+
+func unhex(c byte) int {
+ switch {
+ case '0' <= c && c <= '9':
+ return int(c) - '0'
+ case 'a' <= c && c <= 'f':
+ return int(c) - 'a' + 10
+ case 'A' <= c && c <= 'F':
+ return int(c) - 'A' + 10
+ }
+ return -1
+}
+
+// TODO: Will need modified UTF-7 eventually.