annotate scanner.go @ 12:66b46b3d73be default tip

Handle capabilities sent by the server after negotiating a SASL security layer
author Guido Berhoerster <guido+managesieve@berhoerster.name>
date Tue, 09 Feb 2021 23:01:02 +0100
parents 6369453d47a3
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
1 // Copyright (C) 2020 Guido Berhoerster <guido+managesieve@berhoerster.name>
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
2 //
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
3 // Permission is hereby granted, free of charge, to any person obtaining
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
4 // a copy of this software and associated documentation files (the
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
5 // "Software"), to deal in the Software without restriction, including
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
6 // without limitation the rights to use, copy, modify, merge, publish,
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
7 // distribute, sublicense, and/or sell copies of the Software, and to
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
8 // permit persons to whom the Software is furnished to do so, subject to
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
9 // the following conditions:
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
10 //
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
11 // The above copyright notice and this permission notice shall be included
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
12 // in all copies or substantial portions of the Software.
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
13 //
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
17 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
18 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
19 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
20 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
21
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
22 package managesieve
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
23
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
24 import (
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
25 "bufio"
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
26 "fmt"
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
27 "io"
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
28 "strconv"
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
29 "strings"
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
30 "unicode"
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
31 )
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
32
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
33 const ReadLimit = 1 * 1024 * 1024 // 1 MiB
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
34
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
35 type tokenType int
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
36
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
37 const (
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
38 tokenInvalid tokenType = iota
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
39 tokenCRLF
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
40 tokenLeftParenthesis
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
41 tokenRightParenthesis
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
42 tokenAtom
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
43 tokenQuotedString
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
44 tokenLiteralString
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
45 )
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
46
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
47 type token struct {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
48 typ tokenType
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
49 literal string
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
50 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
51
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
52 func (t token) String() string {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
53 switch t.typ {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
54 case tokenInvalid:
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
55 return "Invalid"
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
56 case tokenLeftParenthesis:
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
57 return "LeftParenthesis: " + t.literal
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
58 case tokenRightParenthesis:
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
59 return "RightParenthesis: " + t.literal
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
60 case tokenAtom:
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
61 return "Atom: " + t.literal
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
62 case tokenCRLF:
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
63 return fmt.Sprintf("CRLF: %q", t.literal)
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
64 case tokenQuotedString:
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
65 return fmt.Sprintf("QuotedString: %q", t.literal)
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
66 case tokenLiteralString:
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
67 return fmt.Sprintf("LiteralString: %q", t.literal)
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
68 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
69 return fmt.Sprintf("unknown token: %q", t.literal)
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
70 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
71
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
72 type scanner struct {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
73 lr *io.LimitedReader // do not read from this, only for access to N
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
74 br *bufio.Reader // wraps LimitReader
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
75 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
76
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
77 func newScanner(r io.Reader) *scanner {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
78 lr := &io.LimitedReader{R: r, N: ReadLimit}
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
79 br := bufio.NewReader(lr)
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
80 return &scanner{lr, br}
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
81 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
82
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
83 func (s *scanner) scanCRLF() (*token, error) {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
84 c, _, err := s.br.ReadRune()
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
85 if err != nil {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
86 if err == io.EOF {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
87 err = io.ErrUnexpectedEOF
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
88 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
89 return nil, err
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
90 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
91 literal := string(c)
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
92 // accept LF without CR
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
93 if c == '\r' {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
94 c, _, err = s.br.ReadRune()
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
95 if err != nil {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
96 if err == io.EOF {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
97 err = io.ErrUnexpectedEOF
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
98 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
99 return nil, err
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
100 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
101 literal += string(c)
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
102 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
103 if c != '\n' {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
104 return nil, ParserError(fmt.Sprintf(`expected '\n', got %q`, c))
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
105 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
106 return &token{typ: tokenCRLF, literal: literal}, nil
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
107 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
108
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
109 func (s *scanner) scanParenthesis() (*token, error) {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
110 c, _, err := s.br.ReadRune()
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
111 if err != nil {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
112 if err == io.EOF {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
113 err = io.ErrUnexpectedEOF
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
114 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
115 return nil, err
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
116 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
117 var typ tokenType
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
118 if c == '(' {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
119 typ = tokenLeftParenthesis
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
120 } else if c == ')' {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
121 typ = tokenRightParenthesis
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
122 } else {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
123 return nil,
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
124 ParserError(fmt.Sprintf("expected parenthesis, got %q",
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
125 c))
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
126 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
127 return &token{typ: typ, literal: string(c)}, nil
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
128 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
129
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
130 func isAtomRune(c rune) bool {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
131 return c == '!' ||
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
132 (c >= 0x23 && c <= 0x27) ||
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
133 (c >= 0x2a && c <= 0x5b) ||
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
134 (c >= 0x5d && c <= 0x7a) ||
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
135 (c >= 0x7c && c <= 0x7e)
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
136 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
137
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
138 func (s *scanner) scanAtom() (*token, error) {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
139 var sb strings.Builder
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
140 var c rune
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
141 for {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
142 c, _, err := s.br.ReadRune()
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
143 if err != nil {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
144 if err == io.EOF {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
145 err = io.ErrUnexpectedEOF
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
146 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
147 return nil, err
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
148 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
149 if isAtomRune(c) {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
150 sb.WriteRune(unicode.ToUpper(c))
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
151 } else {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
152 s.br.UnreadRune()
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
153 break
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
154 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
155 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
156 if sb.Len() == 0 {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
157 return nil, ParserError(fmt.Sprintf("expected atom, got %q", c))
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
158 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
159 return &token{typ: tokenAtom, literal: sb.String()}, nil
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
160 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
161
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
162 func (s *scanner) scanQuotedString() (*token, error) {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
163 c, _, err := s.br.ReadRune()
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
164 if err != nil {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
165 if err == io.EOF {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
166 err = io.ErrUnexpectedEOF
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
167 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
168 return nil, err
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
169 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
170 if c != '"' {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
171 return nil, ParserError(fmt.Sprintf("expected '\"', got %q", c))
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
172 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
173 qs, err := s.br.ReadString('"')
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
174 if err != nil {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
175 if err == io.EOF {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
176 err = io.ErrUnexpectedEOF
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
177 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
178 return nil, err
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
179 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
180 return &token{typ: tokenQuotedString, literal: qs[:len(qs)-1]},
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
181 nil
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
182 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
183
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
184 func (s *scanner) scanLiteralString() (*token, error) {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
185 c, _, err := s.br.ReadRune()
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
186 if err != nil {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
187 if err == io.EOF {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
188 err = io.ErrUnexpectedEOF
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
189 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
190 return nil, err
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
191 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
192 if c != '{' {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
193 return nil, ParserError(fmt.Sprintf("expected '{', got %q", c))
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
194 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
195 nstr, err := s.br.ReadString('}')
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
196 if err != nil {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
197 if err == io.EOF {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
198 err = io.ErrUnexpectedEOF
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
199 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
200 return nil, err
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
201 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
202 n, err := strconv.ParseUint(nstr[:len(nstr)-1], 10, 32)
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
203 if err != nil {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
204 return nil, ParserError("failed to parse literal string length: " + err.Error())
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
205 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
206 if n > uint64(s.lr.N) {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
207 return nil, ParserError(fmt.Sprintf("string too long: %d", n))
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
208 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
209
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
210 if _, err := s.scanCRLF(); err != nil {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
211 return nil, err
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
212 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
213
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
214 b := make([]byte, n)
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
215 _, err = io.ReadFull(s.br, b)
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
216 ls := string(b)
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
217 if err != nil {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
218 if err == io.EOF {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
219 err = io.ErrUnexpectedEOF
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
220 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
221 return nil, err
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
222 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
223
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
224 return &token{typ: tokenLiteralString, literal: ls}, nil
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
225 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
226
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
227 func (s *scanner) skipSpace() error {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
228 for {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
229 b, err := s.br.ReadByte()
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
230 if err != nil {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
231 if err == io.EOF {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
232 err = io.ErrUnexpectedEOF
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
233 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
234 return err
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
235 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
236
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
237 if b != ' ' {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
238 s.br.UnreadByte()
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
239 break
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
240 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
241 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
242
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
243 return nil
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
244 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
245
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
246 func (s *scanner) scan() (*token, error) {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
247 if err := s.skipSpace(); err != nil {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
248 return nil, err
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
249 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
250
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
251 buf, err := s.br.Peek(1)
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
252 if err != nil {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
253 if err == io.EOF {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
254 err = io.ErrUnexpectedEOF
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
255 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
256 return nil, err
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
257 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
258 b := buf[0]
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
259 switch {
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
260 case b == '\r':
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
261 fallthrough
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
262 case b == '\n':
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
263 return s.scanCRLF()
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
264 case b == '"':
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
265 return s.scanQuotedString()
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
266 case b == '{':
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
267 return s.scanLiteralString()
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
268 case b == '(':
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
269 fallthrough
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
270 case b == ')':
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
271 return s.scanParenthesis()
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
272 case isAtomRune(rune(b)):
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
273 return s.scanAtom()
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
274 }
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
275 return nil, ParserError(fmt.Sprintf("invalid character: %q", b))
6369453d47a3 Initial revision
Guido Berhoerster <guido+managesieve@berhoerster.name>
parents:
diff changeset
276 }