11// IMAP4rev1 uses a modified version of UTF-7.
15const utf7chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"
17var utf7encoding = base64.NewEncoding(utf7chars).WithPadding(base64.NoPadding)
20 errUTF7SuperfluousShift = errors.New("utf7: superfluous unshift+shift")
21 errUTF7Base64 = errors.New("utf7: bad base64")
22 errUTF7OddSized = errors.New("utf7: odd-sized data")
23 errUTF7UnneededShift = errors.New("utf7: unneeded shift")
24 errUTF7UnfinishedShift = errors.New("utf7: unfinished shift")
25 errUTF7BadSurrogate = errors.New("utf7: bad utf16 surrogates")
28func utf7decode(s string) (string, error) {
37 if lastunshift == i-1 {
38 return "", errUTF7SuperfluousShift
58 buf, err := utf7encoding.DecodeString(b)
60 return "", fmt.Errorf("%w: %q: %v", errUTF7Base64, b, err)
65 return "", errUTF7OddSized
68 x := make([]rune, len(buf)/2)
71 for i := 0; i < len(buf); i += 2 {
72 x[j] = rune(buf[i])<<8 | rune(buf[i+1])
74 s0 := utf16.IsSurrogate(x[j-1])
75 s1 := utf16.IsSurrogate(x[j])
77 c := utf16.DecodeRune(x[j-1], x[j])
79 return "", fmt.Errorf("%w: decoding %x %x", errUTF7BadSurrogate, x[j-1], x[j])
85 return "", fmt.Errorf("%w: not both surrogate: %x %x", errUTF7BadSurrogate, x[j-1], x[j])
94 if c < 0x20 || c > 0x7e || c == '&' {
98 return "", errUTF7UnneededShift
103 return "", errUTF7UnfinishedShift
108func utf7encode(s string) string {
112 flushcode := func() {
117 for _, c := range code {
118 high, low := utf16.EncodeRune(c)
119 if high == 0xfffd && low == 0xfffd {
120 b.WriteByte(byte(c >> 8))
121 b.WriteByte(byte(c >> 0))
123 b.WriteByte(byte(high >> 8))
124 b.WriteByte(byte(high >> 0))
125 b.WriteByte(byte(low >> 8))
126 b.WriteByte(byte(low >> 0))
129 r += "&" + utf7encoding.EncodeToString(b.Bytes()) + "-"
133 for _, c := range s {
137 } else if c >= ' ' && c < 0x7f {