1package imap
2
3import (
4	"errors"
5)
6
7// A status response type.
8type StatusRespType string
9
10// Status response types defined in RFC 3501 section 7.1.
11const (
12	// The OK response indicates an information message from the server.  When
13	// tagged, it indicates successful completion of the associated command.
14	// The untagged form indicates an information-only message.
15	StatusRespOk StatusRespType = "OK"
16
17	// The NO response indicates an operational error message from the
18	// server.  When tagged, it indicates unsuccessful completion of the
19	// associated command.  The untagged form indicates a warning; the
20	// command can still complete successfully.
21	StatusRespNo StatusRespType = "NO"
22
23	// The BAD response indicates an error message from the server.  When
24	// tagged, it reports a protocol-level error in the client's command;
25	// the tag indicates the command that caused the error.  The untagged
26	// form indicates a protocol-level error for which the associated
27	// command can not be determined; it can also indicate an internal
28	// server failure.
29	StatusRespBad StatusRespType = "BAD"
30
31	// The PREAUTH response is always untagged, and is one of three
32	// possible greetings at connection startup.  It indicates that the
33	// connection has already been authenticated by external means; thus
34	// no LOGIN command is needed.
35	StatusRespPreauth StatusRespType = "PREAUTH"
36
37	// The BYE response is always untagged, and indicates that the server
38	// is about to close the connection.
39	StatusRespBye StatusRespType = "BYE"
40)
41
42type StatusRespCode string
43
44// Status response codes defined in RFC 3501 section 7.1.
45const (
46	CodeAlert          StatusRespCode = "ALERT"
47	CodeBadCharset     StatusRespCode = "BADCHARSET"
48	CodeCapability     StatusRespCode = "CAPABILITY"
49	CodeParse          StatusRespCode = "PARSE"
50	CodePermanentFlags StatusRespCode = "PERMANENTFLAGS"
51	CodeReadOnly       StatusRespCode = "READ-ONLY"
52	CodeReadWrite      StatusRespCode = "READ-WRITE"
53	CodeTryCreate      StatusRespCode = "TRYCREATE"
54	CodeUidNext        StatusRespCode = "UIDNEXT"
55	CodeUidValidity    StatusRespCode = "UIDVALIDITY"
56	CodeUnseen         StatusRespCode = "UNSEEN"
57)
58
59// A status response.
60// See RFC 3501 section 7.1
61type StatusResp struct {
62	// The response tag. If empty, it defaults to *.
63	Tag string
64	// The status type.
65	Type StatusRespType
66	// The status code.
67	// See https://www.iana.org/assignments/imap-response-codes/imap-response-codes.xhtml
68	Code StatusRespCode
69	// Arguments provided with the status code.
70	Arguments []interface{}
71	// The status info.
72	Info string
73}
74
75func (r *StatusResp) resp() {}
76
77// If this status is NO or BAD, returns an error with the status info.
78// Otherwise, returns nil.
79func (r *StatusResp) Err() error {
80	if r == nil {
81		// No status response, connection closed before we get one
82		return errors.New("imap: connection closed during command execution")
83	}
84
85	if r.Type == StatusRespNo || r.Type == StatusRespBad {
86		return errors.New(r.Info)
87	}
88	return nil
89}
90
91func (r *StatusResp) WriteTo(w *Writer) error {
92	tag := RawString(r.Tag)
93	if tag == "" {
94		tag = "*"
95	}
96
97	if err := w.writeFields([]interface{}{RawString(tag), RawString(r.Type)}); err != nil {
98		return err
99	}
100
101	if err := w.writeString(string(sp)); err != nil {
102		return err
103	}
104
105	if r.Code != "" {
106		if err := w.writeRespCode(r.Code, r.Arguments); err != nil {
107			return err
108		}
109
110		if err := w.writeString(string(sp)); err != nil {
111			return err
112		}
113	}
114
115	if err := w.writeString(r.Info); err != nil {
116		return err
117	}
118
119	return w.writeCrlf()
120}
121