78 lines
1.7 KiB
Go
78 lines
1.7 KiB
Go
package imap
|
|||
|
|
|
||
|
|
import "strings"
|
||
|
|
|
||
|
|
// tokenize splits an IMAP command line into space-separated tokens, treating
|
||
|
|
// "quoted strings" and (parenthesized lists) as single tokens (lists keep
|
||
|
|
// their outer parens so command handlers can recognize and further split
|
||
|
|
// them). Literal syntax ({n}\r\n<bytes>) is not handled here — see session.go's
|
||
|
|
// readCommand, which handles literals as a pre-pass before tokenizing since
|
||
|
|
// they require reading raw bytes off the connection, not just string scanning.
|
||
|
|
func tokenize(line string) []string {
|
||
|
|
var tokens []string
|
||
|
|
i, n := 0, len(line)
|
||
|
|
|
||
|
|
for i < n {
|
||
|
|
for i < n && (line[i] == ' ' || line[i] == '\t') {
|
||
|
|
i++
|
||
|
|
}
|
||
|
|
if i >= n {
|
||
|
|
break
|
||
|
|
}
|
||
|
|
|
||
|
|
switch line[i] {
|
||
|
|
case '"':
|
||
|
|
j := i + 1
|
||
|
|
var sb strings.Builder
|
||
|
|
for j < n && line[j] != '"' {
|
||
|
|
if line[j] == '\\' && j+1 < n {
|
||
|
|
j++
|
||
|
|
}
|
||
|
|
sb.WriteByte(line[j])
|
||
|
|
j++
|
||
|
|
}
|
||
|
|
tokens = append(tokens, sb.String())
|
||
|
|
i = j + 1
|
||
|
|
|
||
|
|
case '(':
|
||
|
|
depth := 1
|
||
|
|
j := i + 1
|
||
|
|
for j < n && depth > 0 {
|
||
|
|
switch line[j] {
|
||
|
|
case '(':
|
||
|
|
depth++
|
||
|
|
case ')':
|
||
|
|
depth--
|
||
|
|
}
|
||
|
|
j++
|
||
|
|
}
|
||
|
|
tokens = append(tokens, line[i:j])
|
||
|
|
i = j
|
||
|
|
|
||
|
|
default:
|
||
|
|
j := i
|
||
|
|
for j < n && line[j] != ' ' && line[j] != '\t' {
|
||
|
|
j++
|
||
|
|
}
|
||
|
|
tokens = append(tokens, line[i:j])
|
||
|
|
i = j
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return tokens
|
||
|
|
}
|
||
|
|
|
||
|
|
// splitList takes a token like "(FLAGS UID)" and returns its inner
|
||
|
|
// space-separated items — used by FETCH/STORE argument parsing.
|
||
|
|
func splitList(token string) []string {
|
||
|
|
inner := strings.TrimPrefix(token, "(")
|
||
|
|
inner = strings.TrimSuffix(inner, ")")
|
||
|
|
if inner == "" {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
return tokenize(inner)
|
||
|
|
}
|
||
|
|
|
||
|
|
func isList(token string) bool {
|
||
|
|
return strings.HasPrefix(token, "(") && strings.HasSuffix(token, ")")
|
||
|
|
}
|