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 {
227 Attrs map[StatusAttr]int64 // Upper case status attributes.
231type StatusAttr string
234 StatusMessages StatusAttr = "MESSAGES"
235 StatusUIDNext StatusAttr = "UIDNEXT"
236 StatusUIDValidity StatusAttr = "UIDVALIDITY"
237 StatusUnseen StatusAttr = "UNSEEN"
238 StatusDeleted StatusAttr = "DELETED"
239 StatusSize StatusAttr = "SIZE"
240 StatusRecent StatusAttr = "RECENT"
241 StatusAppendLimit StatusAttr = "APPENDLIMIT"
242 StatusHighestModSeq StatusAttr = "HIGHESTMODSEQ"
243 StatusDeletedStorage StatusAttr = "DELETED-STORAGE"
246type UntaggedNamespace struct {
247 Personal, Other, Shared []NamespaceDescr
249type UntaggedLsub struct {
256// Fields are optional and zero if absent.
257type UntaggedEsearch struct {
266 Exts []EsearchDataExt
269// UntaggedVanished is used in QRESYNC to send UIDs that have been removed.
270type UntaggedVanished struct {
275// UntaggedQuotaroot lists the roots for which quota can be present.
276type UntaggedQuotaroot []string
278// UntaggedQuota holds the quota for a quota root.
279type UntaggedQuota struct {
282 // Always has at least one. Any QUOTA=RES-* capability not mentioned has no limit
283 // or this quota root.
284 Resources []QuotaResource
289// QuotaResourceName is the name of a resource type. More can be defined in the
290// future and encountered in the wild. Always in upper case.
291type QuotaResourceName string
294 QuotaResourceStorage = "STORAGE"
295 QuotaResourceMesssage = "MESSAGE"
296 QuotaResourceMailbox = "MAILBOX"
297 QuotaResourceAnnotationStorage = "ANNOTATION-STORAGE"
300type QuotaResource struct {
301 Name QuotaResourceName
302 Usage int64 // Currently in use. Count or disk size in 1024 byte blocks.
303 Limit int64 // Maximum allowed usage.
308type UntaggedID map[string]string
310// Extended data in an ESEARCH response.
311type EsearchDataExt struct {
316type NamespaceDescr struct {
319 Separator byte // If 0 then separator was absent.
320 Exts []NamespaceExtension
323type NamespaceExtension struct {
329// FetchAttr represents a FETCH response attribute.
330type FetchAttr interface {
331 Attr() string // Name of attribute.
335 SearchResult bool // True if "$", in which case Ranges is irrelevant.
339func (ns NumSet) IsZero() bool {
340 return !ns.SearchResult && ns.Ranges == nil
343func (ns NumSet) String() string {
348 for i, x := range ns.Ranges {
357func ParseNumSet(s string) (ns NumSet, rerr error) {
358 c := Conn{r: bufio.NewReader(strings.NewReader(s))}
359 defer c.recover(&rerr)
360 ns = c.xsequenceSet()
364// NumRange is a single number or range.
365type NumRange struct {
366 First uint32 // 0 for "*".
367 Last *uint32 // Nil if absent, 0 for "*".
370func (nr NumRange) String() string {
375 r += fmt.Sprintf("%d", nr.First)
385 r += fmt.Sprintf("%d", v)
390type TaggedExtComp struct {
392 Comps []TaggedExtComp // Used for both space-separated and ().
395type TaggedExtVal struct {
399 Comp *TaggedExtComp // If SimpleNumber and SimpleSeqSet is nil, this is a Comp. But Comp is optional and can also be nil. Not great.
402type MboxListExtendedItem struct {
408// "FLAGS" fetch response.
409type FetchFlags []string
411func (f FetchFlags) Attr() string { return "FLAGS" }
413// "ENVELOPE" fetch response.
414type FetchEnvelope Envelope
416func (f FetchEnvelope) Attr() string { return "ENVELOPE" }
418// Envelope holds the basic email message fields.
419type Envelope struct {
422 From, Sender, ReplyTo, To, CC, BCC []Address
423 InReplyTo, MessageID string
426// Address is an address field in an email message, e.g. To.
428 Name, Adl, Mailbox, Host string
431// "INTERNALDATE" fetch response.
432type FetchInternalDate string // todo: parsed time
433func (f FetchInternalDate) Attr() string { return "INTERNALDATE" }
435// "RFC822.SIZE" fetch response.
436type FetchRFC822Size int64
438func (f FetchRFC822Size) Attr() string { return "RFC822.SIZE" }
440// "RFC822" fetch response.
441type FetchRFC822 string
443func (f FetchRFC822) Attr() string { return "RFC822" }
445// "RFC822.HEADER" fetch response.
446type FetchRFC822Header string
448func (f FetchRFC822Header) Attr() string { return "RFC822.HEADER" }
450// "RFC82.TEXT" fetch response.
451type FetchRFC822Text string
453func (f FetchRFC822Text) Attr() string { return "RFC822.TEXT" }
455// "BODYSTRUCTURE" fetch response.
456type FetchBodystructure struct {
459 Body any // BodyType*
462func (f FetchBodystructure) Attr() string { return f.RespAttr }
464// "BODY" fetch response.
465type FetchBody struct {
473func (f FetchBody) Attr() string { return f.RespAttr }
475// BodyFields is part of a FETCH BODY[] response.
476type BodyFields struct {
478 ContentID, ContentDescr, CTE string
482// BodyTypeMpart represents the body structure a multipart message, with
483// subparts and the multipart media subtype. Used in a FETCH response.
484type BodyTypeMpart struct {
486 Bodies []any // BodyTypeBasic, BodyTypeMsg, BodyTypeText
488 Ext *BodyExtensionMpart
491// BodyTypeBasic represents basic information about a part, used in a FETCH
493type BodyTypeBasic struct {
495 MediaType, MediaSubtype string
496 BodyFields BodyFields
497 Ext *BodyExtension1Part
500// BodyTypeMsg represents an email message as a body structure, used in a FETCH
502type BodyTypeMsg struct {
504 MediaType, MediaSubtype string
505 BodyFields BodyFields
507 Bodystructure any // One of the BodyType*
509 Ext *BodyExtension1Part
512// BodyTypeText represents a text part as a body structure, used in a FETCH
514type BodyTypeText struct {
516 MediaType, MediaSubtype string
517 BodyFields BodyFields
519 Ext *BodyExtension1Part
522// BodyExtension1Part has the extensible form fields of a BODYSTRUCTURE for
524type BodyExtensionMpart struct {
528 DispositionParams [][2]string
534// BodyExtension1Part has the extensible form fields of a BODYSTRUCTURE for
536type BodyExtension1Part struct {
540 DispositionParams [][2]string
546// BodyExtension has the additional extension fields for future expansion of
548type BodyExtension struct {
554// "BINARY" fetch response.
555type FetchBinary struct {
557 Parts []uint32 // Can be nil.
561func (f FetchBinary) Attr() string { return f.RespAttr }
563// "BINARY.SIZE" fetch response.
564type FetchBinarySize struct {
570func (f FetchBinarySize) Attr() string { return f.RespAttr }
572// "UID" fetch response.
575func (f FetchUID) Attr() string { return "UID" }
577// "MODSEQ" fetch response.
578type FetchModSeq int64
580func (f FetchModSeq) Attr() string { return "MODSEQ" }