summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/mattermost/rsc/imap/sx.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/mattermost/rsc/imap/sx.go')
-rw-r--r--vendor/github.com/mattermost/rsc/imap/sx.go350
1 files changed, 350 insertions, 0 deletions
diff --git a/vendor/github.com/mattermost/rsc/imap/sx.go b/vendor/github.com/mattermost/rsc/imap/sx.go
new file mode 100644
index 000000000..8b0e361fa
--- /dev/null
+++ b/vendor/github.com/mattermost/rsc/imap/sx.go
@@ -0,0 +1,350 @@
+package imap
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "log"
+ "strings"
+ "time"
+)
+
+type sxKind int
+
+const (
+ sxNone sxKind = iota
+ sxAtom
+ sxString
+ sxNumber
+ sxList
+)
+
+type sx struct {
+ kind sxKind
+ data []byte
+ number int64
+ sx []*sx
+}
+
+func rdsx(b *bufio.Reader) (*sx, error) {
+ x := &sx{kind: sxList}
+ for {
+ xx, err := rdsx1(b)
+ if err != nil {
+ return nil, err
+ }
+ if xx == nil {
+ break
+ }
+ x.sx = append(x.sx, xx)
+ }
+ return x, nil
+}
+
+func rdsx1(b *bufio.Reader) (*sx, error) {
+ c, err := b.ReadByte()
+ if c == ' ' {
+ c, err = b.ReadByte()
+ }
+ if c == '\r' {
+ c, err = b.ReadByte()
+ }
+ if err != nil {
+ return nil, err
+ }
+ if c == '\n' {
+ return nil, nil
+ }
+ if c == ')' { // end of list
+ b.UnreadByte()
+ return nil, nil
+ }
+ if c == '(' { // parenthesized list
+ x, err := rdsx(b)
+ if err != nil {
+ return nil, err
+ }
+ c, err = b.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ if c != ')' {
+ // oops! not good
+ b.UnreadByte()
+ }
+ return x, nil
+ }
+ if c == '{' { // length-prefixed string
+ n := 0
+ for {
+ c, _ = b.ReadByte()
+ if c < '0' || c > '9' {
+ break
+ }
+ n = n*10 + int(c) - '0'
+ }
+ if c != '}' {
+ // oops! not good
+ b.UnreadByte()
+ }
+ c, err = b.ReadByte()
+ if c != '\r' {
+ // oops! not good
+ }
+ c, err = b.ReadByte()
+ if c != '\n' {
+ // oops! not good
+ }
+ data := make([]byte, n)
+ if _, err := io.ReadFull(b, data); err != nil {
+ return nil, err
+ }
+ return &sx{kind: sxString, data: data}, nil
+ }
+ if c == '"' { // quoted string
+ var data []byte
+ for {
+ c, err = b.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ if c == '"' {
+ break
+ }
+ if c == '\\' {
+ c, _ = b.ReadByte()
+ }
+ data = append(data, c)
+ }
+ return &sx{kind: sxString, data: data}, nil
+ }
+ if '0' <= c && c <= '9' { // number
+ n := int64(c) - '0'
+ for {
+ c, err := b.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ if c < '0' || c > '9' {
+ break
+ }
+ n = n*10 + int64(c) - '0'
+ }
+ b.UnreadByte()
+ return &sx{kind: sxNumber, number: n}, nil
+ }
+
+ // atom
+ nbr := 0
+ var data []byte
+ data = append(data, c)
+ for {
+ c, err = b.ReadByte()
+ if err != nil {
+ return nil, err
+ }
+ if c <= ' ' || c == '(' || c == ')' || c == '{' || c == '}' {
+ break
+ }
+ if c == '[' {
+ // allow embedded brackets as in BODY[]
+ if data[0] == '[' {
+ break
+ }
+ nbr++
+ }
+ if c == ']' {
+ if nbr <= 0 {
+ break
+ }
+ nbr--
+ }
+ data = append(data, c)
+ }
+ if c != ' ' {
+ b.UnreadByte()
+ }
+ return &sx{kind: sxAtom, data: data}, nil
+}
+
+func (x *sx) ok() bool {
+ return len(x.sx) >= 2 && x.sx[1].kind == sxAtom && strings.EqualFold(string(x.sx[1].data), "ok")
+}
+
+func (x *sx) String() string {
+ var b bytes.Buffer
+ x.fmt(&b, true)
+ return b.String()
+}
+
+func (x *sx) fmt(b *bytes.Buffer, paren bool) {
+ if x == nil {
+ return
+ }
+ switch x.kind {
+ case sxAtom, sxString:
+ fmt.Fprintf(b, "%q", x.data)
+ case sxNumber:
+ fmt.Fprintf(b, "%d", x.number)
+ case sxList:
+ if paren {
+ b.WriteByte('(')
+ }
+ for i, xx := range x.sx {
+ if i > 0 {
+ b.WriteByte(' ')
+ }
+ xx.fmt(b, paren)
+ }
+ if paren {
+ b.WriteByte(')')
+ }
+ default:
+ b.WriteByte('?')
+ }
+}
+
+var bytesNIL = []byte("NIL")
+
+var fmtKind = []sxKind{
+ 'L': sxList,
+ 'S': sxString,
+ 'N': sxNumber,
+ 'A': sxAtom,
+}
+
+func (x *sx) match(format string) bool {
+ done := false
+ c := format[0]
+ for i := 0; i < len(x.sx); i++ {
+ if !done {
+ if i >= len(format) {
+ log.Printf("sxmatch: too short")
+ return false
+ }
+ if format[i] == '*' {
+ done = true
+ } else {
+ c = format[i]
+ }
+ }
+ xx := x.sx[i]
+ if xx.kind == sxAtom && xx.isNil() {
+ if c == 'L' {
+ xx.kind = sxList
+ xx.data = nil
+ } else if c == 'S' {
+ xx.kind = sxString
+ xx.data = nil
+ }
+ }
+ if xx.kind == sxAtom && c == 'S' {
+ xx.kind = sxString
+ }
+ if xx.kind != fmtKind[c] {
+ log.Printf("sxmatch: %s not %c", xx, c)
+ return false
+ }
+ }
+ if len(format) > len(x.sx) {
+ log.Printf("sxmatch: too long")
+ return false
+ }
+ return true
+}
+
+func (x *sx) isAtom(name string) bool {
+ if x == nil || x.kind != sxAtom {
+ return false
+ }
+ data := x.data
+ n := len(name)
+ if n > 0 && name[n-1] == '[' {
+ i := bytes.IndexByte(data, '[')
+ if i < 0 {
+ return false
+ }
+ data = data[:i]
+ name = name[:n-1]
+ }
+ for i := 0; i < len(name); i++ {
+ if i >= len(data) || lwr(rune(data[i])) != lwr(rune(name[i])) {
+ return false
+ }
+ }
+ return len(name) == len(data)
+}
+
+func (x *sx) isString() bool {
+ if x.isNil() {
+ return true
+ }
+ if x.kind == sxAtom {
+ x.kind = sxString
+ }
+ return x.kind == sxString
+}
+
+func (x *sx) isNumber() bool {
+ return x.kind == sxNumber
+}
+
+func (x *sx) isNil() bool {
+ return x == nil ||
+ x.kind == sxList && len(x.sx) == 0 ||
+ x.kind == sxAtom && bytes.Equal(x.data, bytesNIL)
+}
+
+func (x *sx) isList() bool {
+ return x.isNil() || x.kind == sxList
+}
+
+func (x *sx) parseFlags() Flags {
+ if x.kind != sxList {
+ log.Printf("malformed flags: %s", x)
+ return 0
+ }
+
+ f := Flags(0)
+SX:
+ for _, xx := range x.sx {
+ if xx.kind != sxAtom {
+ continue
+ }
+ for i, name := range flagNames {
+ if xx.isAtom(name) {
+ f |= 1 << uint(i)
+ continue SX
+ }
+ }
+ if Debug {
+ log.Printf("unknown flag: %v", xx)
+ }
+ }
+ return f
+}
+
+func (x *sx) parseDate() time.Time {
+ if x.kind != sxString {
+ log.Printf("malformed date: %s", x)
+ return time.Time{}
+ }
+
+ t, err := time.Parse("02-Jan-2006 15:04:05 -0700", string(x.data))
+ if err != nil {
+ log.Printf("malformed date: %s (%s)", x, err)
+ }
+ return t
+}
+
+func (x *sx) nstring() string {
+ return string(x.nbytes())
+}
+
+func (x *sx) nbytes() []byte {
+ if x.isNil() {
+ return nil
+ }
+ return x.data
+}