forked from alienscience/imapsrv
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.go
117 lines (95 loc) · 2.43 KB
/
parser.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package imapsrv
import (
"bufio"
"fmt"
"strings"
)
// An IMAP parser
type parser struct {
lexer *lexer
}
// An Error from the IMAP parser or lexer
type parseError string
// Parse errors satisfy the error interface
func (e parseError) Error() string {
return string(e)
}
// Create an imap parser
func createParser(in *bufio.Reader) *parser {
lexer := createLexer(in)
return &parser{lexer: lexer}
}
// Parse the next command
func (p *parser) next() command {
// Expect a tag followed by a command
tagToken := p.match(stringTokenType)
commandToken := p.match(stringTokenType)
// Parse the command based on its lowercase value
rawCommand := commandToken.value
lcCommand := strings.ToLower(rawCommand)
tag := tagToken.value
switch lcCommand {
case "noop":
return p.noop(tag)
case "capability":
return p.capability(tag)
case "login":
return p.login(tag)
case "logout":
return p.logout(tag)
case "select":
return p.selectC(tag)
default:
return p.unknown(tag, rawCommand)
}
}
// Create a NOOP command
func (p *parser) noop(tag string) command {
p.match(eolTokenType)
return &noop{tag: tag}
}
// Create a capability command
func (p *parser) capability(tag string) command {
p.match(eolTokenType)
return &capability{tag: tag}
}
// Create a login command
func (p *parser) login(tag string) command {
// Get the command arguments
userId := p.match(stringTokenType).value
password := p.match(stringTokenType).value
p.match(eolTokenType)
// Create the command
return &login{tag: tag, userId: userId, password: password}
}
// Create a logout command
func (p *parser) logout(tag string) command {
p.match(eolTokenType)
return &logout{tag: tag}
}
// Create a select command
func (p *parser) selectC(tag string) command {
// Get the mailbox name
mailbox := p.match(stringTokenType).value
p.match(eolTokenType)
return &selectMailbox{tag: tag, mailbox: mailbox}
}
// Create a placeholder for an unknown command
func (p *parser) unknown(tag string, cmd string) command {
for tok := p.lexer.next(); tok.tokType != eolTokenType; tok = p.lexer.next() {
}
return &unknown{tag: tag, cmd: cmd}
}
// Match the given token
func (p *parser) match(expected tokenType) *token {
// Get the next token from the lexer
tok := p.lexer.next()
// Is this the expected token?
if tok.tokType != expected {
msg := fmt.Sprintf("Parser expected token type %v but got %v",
expected, tok.tokType)
err := parseError(msg)
panic(err)
}
return tok
}