mox/imapserver/utf7.go

84 lines
1.5 KiB
Go
Raw Normal View History

2023-01-30 16:27:06 +03:00
package imapserver
import (
"encoding/base64"
"errors"
"fmt"
)
const utf7chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"
var utf7encoding = base64.NewEncoding(utf7chars).WithPadding(base64.NoPadding)
var (
errUTF7SuperfluousShift = errors.New("utf7: superfluous unshift+shift")
errUTF7Base64 = errors.New("utf7: bad base64")
errUTF7OddSized = errors.New("utf7: odd-sized data")
errUTF7UnneededShift = errors.New("utf7: unneeded shift")
errUTF7UnfinishedShift = errors.New("utf7: unfinished shift")
)
func utf7decode(s string) (string, error) {
var r string
var shifted bool
var b string
lastunshift := -2
for i, c := range s {
if !shifted {
if c == '&' {
if lastunshift == i-1 {
return "", errUTF7SuperfluousShift
}
shifted = true
} else {
r += string(c)
}
continue
}
if c != '-' {
b += string(c)
continue
}
shifted = false
lastunshift = i
if b == "" {
r += "&"
continue
}
buf, err := utf7encoding.DecodeString(b)
if err != nil {
return "", fmt.Errorf("%w: %q: %v", errUTF7Base64, b, err)
}
b = ""
if len(buf)%2 != 0 {
return "", errUTF7OddSized
}
x := make([]rune, len(buf)/2)
j := 0
for i := 0; i < len(buf); i += 2 {
x[j] = rune(buf[i])<<8 | rune(buf[i+1])
j++
}
need := false
for _, c := range x {
if c < 0x20 || c > 0x7e || c == '&' {
need = true
}
r += string(c)
}
if !need {
return "", errUTF7UnneededShift
}
}
if shifted {
return "", errUTF7UnfinishedShift
}
return r, nil
}