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) 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, ")") }