9// Capability is a known string for with the ENABLED and CAPABILITY command.
13 CapIMAP4rev1 Capability = "IMAP4rev1"
14 CapIMAP4rev2 Capability = "IMAP4rev2"
15 CapLoginDisabled Capability = "LOGINDISABLED"
16 CapStarttls Capability = "STARTTLS"
17 CapAuthPlain Capability = "AUTH=PLAIN"
18 CapLiteralPlus Capability = "LITERAL+"
19 CapLiteralMinus Capability = "LITERAL-"
20 CapIdle Capability = "IDLE"
21 CapNamespace Capability = "NAMESPACE"
22 CapBinary Capability = "BINARY"
23 CapUnselect Capability = "UNSELECT"
24 CapUidplus Capability = "UIDPLUS"
25 CapEsearch Capability = "ESEARCH"
26 CapEnable Capability = "ENABLE"
27 CapSave Capability = "SAVE"
28 CapListExtended Capability = "LIST-EXTENDED"
29 CapSpecialUse Capability = "SPECIAL-USE"
30 CapMove Capability = "MOVE"
31 CapUTF8Only Capability = "UTF8=ONLY"
32 CapUTF8Accept Capability = "UTF8=ACCEPT"
36// Status is the tagged final result of a command.
40 BAD Status = "BAD" // Syntax error.
41 NO Status = "NO" // Command failed.
42 OK Status = "OK" // Command succeeded.
45// Result is the final response for a command, indicating success or failure.
51// CodeArg represents a response code with arguments, i.e. the data between [] in the response line.
52type CodeArg interface {
56// CodeOther is a valid but unrecognized response code.
57type CodeOther struct {
62func (c CodeOther) CodeString() string {
63 return c.Code + " " + strings.Join(c.Args, " ")
66// CodeWords is a code with space-separated string parameters. E.g. CAPABILITY.
67type CodeWords struct {
72func (c CodeWords) CodeString() string {
74 for _, w := range c.Args {
80// CodeList is a code with a list with space-separated strings as parameters. E.g. BADCHARSET, PERMANENTFLAGS.
83 Args []string // If nil, no list was present. List can also be empty.
86func (c CodeList) CodeString() string {
91 return s + "(" + strings.Join(c.Args, " ") + ")"
94// CodeUint is a code with a uint32 parameter, e.g. UIDNEXT and UIDVALIDITY.
100func (c CodeUint) CodeString() string {
101 return fmt.Sprintf("%s %d", c.Code, c.Num)
104// "APPENDUID" response code.
105type CodeAppendUID struct {
110func (c CodeAppendUID) CodeString() string {
111 return fmt.Sprintf("APPENDUID %d %d", c.UIDValidity, c.UID)
114// "COPYUID" response code.
115type CodeCopyUID struct {
116 DestUIDValidity uint32
121func (c CodeCopyUID) CodeString() string {
122 str := func(l []NumRange) string {
124 for i, e := range l {
128 s += fmt.Sprintf("%d", e.First)
130 s += fmt.Sprintf(":%d", *e.Last)
135 return fmt.Sprintf("COPYUID %d %s %s", c.DestUIDValidity, str(c.From), str(c.To))
139type CodeModified NumSet
141func (c CodeModified) CodeString() string {
142 return fmt.Sprintf("MODIFIED %s", NumSet(c).String())
146type CodeHighestModSeq int64
148func (c CodeHighestModSeq) CodeString() string {
149 return fmt.Sprintf("HIGHESTMODSEQ %d", c)
152// RespText represents a response line minus the leading tag.
153type RespText struct {
154 Code string // The first word between [] after the status.
155 CodeArg CodeArg // Set if code has a parameter.
156 More string // Any remaining text.
160func astring(s string) string {
164 for _, c := range s {
165 if c <= ' ' || c >= 0x7f || c == '(' || c == ')' || c == '{' || c == '%' || c == '*' || c == '"' || c == '\\' {
172// imap "string", i.e. double-quoted string or syncliteral.
173func stringx(s string) string {
175 for _, c := range s {
176 if c == '\x00' || c == '\r' || c == '\n' {
177 return syncliteral(s)
179 if c == '\\' || c == '"' {
188// sync literal, i.e. {<num>}\r\n<num bytes>.
189func syncliteral(s string) string {
190 return fmt.Sprintf("{%d}\r\n", len(s)) + s
193// Untagged is a parsed untagged response. See types starting with Untagged.
194// todo: make an interface that the untagged responses implement?
197type UntaggedBye RespText
198type UntaggedPreauth RespText
199type UntaggedExpunge uint32
200type UntaggedExists uint32
201type UntaggedRecent uint32
202type UntaggedCapability []string
203type UntaggedEnabled []string
204type UntaggedResult Result
205type UntaggedFlags []string
206type UntaggedList struct {
209 Separator byte // 0 for NIL
211 Extended []MboxListExtendedItem
212 OldName string // If present, taken out of Extended.
214type UntaggedFetch struct {
218type UntaggedSearch []uint32
221type UntaggedSearchModSeq struct {
225type UntaggedStatus struct {
229type UntaggedNamespace struct {
230 Personal, Other, Shared []NamespaceDescr
232type UntaggedLsub struct {
239// Fields are optional and zero if absent.
240type UntaggedEsearch struct {
249 Exts []EsearchDataExt
252// UntaggedVanished is used in QRESYNC to send UIDs that have been removed.
253type UntaggedVanished struct {
260type UntaggedID map[string]string
262// Extended data in an ESEARCH response.
263type EsearchDataExt struct {
268type NamespaceDescr struct {
271 Separator byte // If 0 then separator was absent.
272 Exts []NamespaceExtension
275type NamespaceExtension struct {
281// FetchAttr represents a FETCH response attribute.
282type FetchAttr interface {
283 Attr() string // Name of attribute.
287 SearchResult bool // True if "$", in which case Ranges is irrelevant.
291func (ns NumSet) IsZero() bool {
292 return !ns.SearchResult && ns.Ranges == nil
295func (ns NumSet) String() string {
300 for i, x := range ns.Ranges {
309func ParseNumSet(s string) (ns NumSet, rerr error) {
310 c := Conn{r: bufio.NewReader(strings.NewReader(s))}
311 defer c.recover(&rerr)
312 ns = c.xsequenceSet()
316// NumRange is a single number or range.
317type NumRange struct {
318 First uint32 // 0 for "*".
319 Last *uint32 // Nil if absent, 0 for "*".
322func (nr NumRange) String() string {
327 r += fmt.Sprintf("%d", nr.First)
337 r += fmt.Sprintf("%d", v)
342type TaggedExtComp struct {
344 Comps []TaggedExtComp // Used for both space-separated and ().
347type TaggedExtVal struct {
351 Comp *TaggedExtComp // If SimpleNumber and SimpleSeqSet is nil, this is a Comp. But Comp is optional and can also be nil. Not great.
354type MboxListExtendedItem struct {
360// "FLAGS" fetch response.
361type FetchFlags []string
363func (f FetchFlags) Attr() string { return "FLAGS" }
365// "ENVELOPE" fetch response.
366type FetchEnvelope Envelope
368func (f FetchEnvelope) Attr() string { return "ENVELOPE" }
370// Envelope holds the basic email message fields.
371type Envelope struct {
374 From, Sender, ReplyTo, To, CC, BCC []Address
375 InReplyTo, MessageID string
378// Address is an address field in an email message, e.g. To.
380 Name, Adl, Mailbox, Host string
383// "INTERNALDATE" fetch response.
384type FetchInternalDate string // todo: parsed time
385func (f FetchInternalDate) Attr() string { return "INTERNALDATE" }
387// "RFC822.SIZE" fetch response.
388type FetchRFC822Size int64
390func (f FetchRFC822Size) Attr() string { return "RFC822.SIZE" }
392// "RFC822" fetch response.
393type FetchRFC822 string
395func (f FetchRFC822) Attr() string { return "RFC822" }
397// "RFC822.HEADER" fetch response.
398type FetchRFC822Header string
400func (f FetchRFC822Header) Attr() string { return "RFC822.HEADER" }
402// "RFC82.TEXT" fetch response.
403type FetchRFC822Text string
405func (f FetchRFC822Text) Attr() string { return "RFC822.TEXT" }
407// "BODYSTRUCTURE" fetch response.
408type FetchBodystructure struct {
411 Body any // BodyType*
414func (f FetchBodystructure) Attr() string { return f.RespAttr }
416// "BODY" fetch response.
417type FetchBody struct {
425func (f FetchBody) Attr() string { return f.RespAttr }
427// BodyFields is part of a FETCH BODY[] response.
428type BodyFields struct {
430 ContentID, ContentDescr, CTE string
434// BodyTypeMpart represents the body structure a multipart message, with subparts and the multipart media subtype. Used in a FETCH response.
435type BodyTypeMpart struct {
437 Bodies []any // BodyTypeBasic, BodyTypeMsg, BodyTypeText
441// BodyTypeBasic represents basic information about a part, used in a FETCH response.
442type BodyTypeBasic struct {
444 MediaType, MediaSubtype string
445 BodyFields BodyFields
448// BodyTypeMsg represents an email message as a body structure, used in a FETCH response.
449type BodyTypeMsg struct {
451 MediaType, MediaSubtype string
452 BodyFields BodyFields
454 Bodystructure any // One of the BodyType*
458// BodyTypeText represents a text part as a body structure, used in a FETCH response.
459type BodyTypeText struct {
461 MediaType, MediaSubtype string
462 BodyFields BodyFields
466// "BINARY" fetch response.
467type FetchBinary struct {
469 Parts []uint32 // Can be nil.
473func (f FetchBinary) Attr() string { return f.RespAttr }
475// "BINARY.SIZE" fetch response.
476type FetchBinarySize struct {
482func (f FetchBinarySize) Attr() string { return f.RespAttr }
484// "UID" fetch response.
487func (f FetchUID) Attr() string { return "UID" }
489// "MODSEQ" fetch response.
490type FetchModSeq int64
492func (f FetchModSeq) Attr() string { return "MODSEQ" }