-
Notifications
You must be signed in to change notification settings - Fork 16
/
commands.go
104 lines (84 loc) · 3.27 KB
/
commands.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
package conn
import (
"fmt"
"regexp"
"github.com/jordwest/imap-server/mailstore"
)
type command struct {
match *regexp.Regexp
handler func(commandArgs, *Conn)
}
type commandArgs []string
func (a commandArgs) FullCommand() string {
return a[0]
}
func (a commandArgs) ID() string {
return a[1]
}
func (a commandArgs) Arg(i int) string {
return a[i+2]
}
func (a commandArgs) DebugPrint(prompt string) {
fmt.Printf("%s\n", prompt)
fmt.Printf("\tFull Command: %s\n", a.FullCommand())
fmt.Printf("\t.ID(): %s\n", a.ID())
for index, arg := range a {
if index < 2 {
continue
}
fmt.Printf("\t.Arg(%d): \"%s\"\n", index-2, arg)
}
}
var commands []command
// Register all supported client command handlers
// with the server. This function is run on server startup and
// panics if a command regex is invalid.
func init() {
commands = make([]command, 0)
// A sequence set consists only of digits, colons, stars and commas.
// eg: 5,9,10:15,256:*,566
sequenceSet := "[\\d\\:\\*\\,]+"
registerCommand("(?i:CAPABILITY)", cmdCapability)
registerCommand("(?i:LOGIN) \"([A-z0-9]+)\" \"([A-z0-9]+)\"", cmdLogin)
registerCommand("(?i:AUTHENTICATE PLAIN)", cmdAuthPlain)
registerCommand("(?i:LIST) \"?([A-z0-9]+)?\"? \"?([A-z0-9*]+)?\"?", cmdList)
registerCommand("(?i:LSUB)", cmdLSub)
registerCommand("(?i:LOGOUT)", cmdLogout)
registerCommand("(?i:NOOP)", cmdNoop)
registerCommand("(?i:CLOSE)", cmdClose)
registerCommand("(?i:EXPUNGE)", cmdExpunge)
registerCommand("(?i:SELECT) \"?([A-z0-9]+)?\"?", cmdSelect)
registerCommand("(?i:EXAMINE) \"?([A-z0-9]+)\"?", cmdExamine)
registerCommand("(?i:STATUS) \"?([A-z0-9/]+)\"? \\(([A-z\\s]+)\\)", cmdStatus)
registerCommand("((?i)UID )?(?i:FETCH) ("+sequenceSet+") \\(([A-z0-9\\s\\(\\)\\[\\]\\.-]+)\\)", cmdFetch)
// APPEND "INBOX" (\Seen) {310}
// APPEND "INBOX" (\Seen) "21-Jun-2015 01:00:25 +0900" {310}
// APPEND "INBOX" {310}
registerCommand("(?i:APPEND) \"?([A-z0-9/]+)\"?(?: \\(([\\\\A-z\\s]+)\\))?(?: \"([A-Za-z0-9\\-\\:\\+ ]+)\")? {([0-9]+)}", cmdAppend)
// STORE 2:4 +FLAGS (\Deleted) Mark messages as deleted
// STORE 2:4 -FLAGS (\Seen) Mark messages as unseen
// STORE 2:4 FLAGS (\Seen \Deleted) Replace flags
registerCommand("((?i)UID )?(?i:STORE) ("+sequenceSet+") ([\\+\\-])?(?i:FLAGS(\\.SILENT)?) \\(?([\\\\A-z0-9\\s]+)\\)?", cmdStoreFlags)
registerCommand("((?i)UID )?(?i:COPY) ("+sequenceSet+") \"?([A-z0-9]+)?\"?", cmdCopy)
registerCommand("", cmdNA)
}
func registerCommand(matchExpr string, handleFunc func(commandArgs, *Conn)) error {
// Add command identifier to beginning of command
matchExpr = "([A-z0-9\\.]+) " + matchExpr
newRE := regexp.MustCompile(matchExpr)
c := command{match: newRE, handler: handleFunc}
commands = append(commands, c)
return nil
}
// Write out the info for a mailbox (used in both SELECT and EXAMINE)
func writeMailboxInfo(c *Conn, m mailstore.Mailbox) {
fmt.Fprintf(c, "* %d EXISTS\r\n", m.Messages())
fmt.Fprintf(c, "* %d RECENT\r\n", m.Recent())
fmt.Fprintf(c, "* OK [UNSEEN %d]\r\n", m.Unseen())
fmt.Fprintf(c, "* OK [UIDNEXT %d]\r\n", m.NextUID())
fmt.Fprintf(c, "* OK [UIDVALIDITY %d]\r\n", 250)
fmt.Fprintf(c, "* FLAGS (\\Answered \\Flagged \\Deleted \\Seen \\Draft)\r\n")
}
func cmdNA(args commandArgs, c *Conn) {
c.writeResponse(args.ID(), "BAD Not implemented")
}