aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/emersion/go-imap/status.go
blob: 81ffd1b967543172c4cc2dd291d5f6465679c79c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package imap

import (
	"errors"
)

// A status response type.
type StatusRespType string

// Status response types defined in RFC 3501 section 7.1.
const (
	// The OK response indicates an information message from the server.  When
	// tagged, it indicates successful completion of the associated command.
	// The untagged form indicates an information-only message.
	StatusRespOk StatusRespType = "OK"

	// The NO response indicates an operational error message from the
	// server.  When tagged, it indicates unsuccessful completion of the
	// associated command.  The untagged form indicates a warning; the
	// command can still complete successfully.
	StatusRespNo StatusRespType = "NO"

	// The BAD response indicates an error message from the server.  When
	// tagged, it reports a protocol-level error in the client's command;
	// the tag indicates the command that caused the error.  The untagged
	// form indicates a protocol-level error for which the associated
	// command can not be determined; it can also indicate an internal
	// server failure.
	StatusRespBad StatusRespType = "BAD"

	// The PREAUTH response is always untagged, and is one of three
	// possible greetings at connection startup.  It indicates that the
	// connection has already been authenticated by external means; thus
	// no LOGIN command is needed.
	StatusRespPreauth StatusRespType = "PREAUTH"

	// The BYE response is always untagged, and indicates that the server
	// is about to close the connection.
	StatusRespBye StatusRespType = "BYE"
)

type StatusRespCode string

// Status response codes defined in RFC 3501 section 7.1.
const (
	CodeAlert          StatusRespCode = "ALERT"
	CodeBadCharset     StatusRespCode = "BADCHARSET"
	CodeCapability     StatusRespCode = "CAPABILITY"
	CodeParse          StatusRespCode = "PARSE"
	CodePermanentFlags StatusRespCode = "PERMANENTFLAGS"
	CodeReadOnly       StatusRespCode = "READ-ONLY"
	CodeReadWrite      StatusRespCode = "READ-WRITE"
	CodeTryCreate      StatusRespCode = "TRYCREATE"
	CodeUidNext        StatusRespCode = "UIDNEXT"
	CodeUidValidity    StatusRespCode = "UIDVALIDITY"
	CodeUnseen         StatusRespCode = "UNSEEN"
)

// A status response.
// See RFC 3501 section 7.1
type StatusResp struct {
	// The response tag. If empty, it defaults to *.
	Tag string
	// The status type.
	Type StatusRespType
	// The status code.
	// See https://www.iana.org/assignments/imap-response-codes/imap-response-codes.xhtml
	Code StatusRespCode
	// Arguments provided with the status code.
	Arguments []interface{}
	// The status info.
	Info string
}

func (r *StatusResp) resp() {}

// If this status is NO or BAD, returns an error with the status info.
// Otherwise, returns nil.
func (r *StatusResp) Err() error {
	if r == nil {
		// No status response, connection closed before we get one
		return errors.New("imap: connection closed during command execution")
	}

	if r.Type == StatusRespNo || r.Type == StatusRespBad {
		return errors.New(r.Info)
	}
	return nil
}

func (r *StatusResp) WriteTo(w *Writer) error {
	tag := RawString(r.Tag)
	if tag == "" {
		tag = "*"
	}

	if err := w.writeFields([]interface{}{RawString(tag), RawString(r.Type)}); err != nil {
		return err
	}

	if err := w.writeString(string(sp)); err != nil {
		return err
	}

	if r.Code != "" {
		if err := w.writeRespCode(r.Code, r.Arguments); err != nil {
			return err
		}

		if err := w.writeString(string(sp)); err != nil {
			return err
		}
	}

	if err := w.writeString(r.Info); err != nil {
		return err
	}

	return w.writeCrlf()
}

// ErrStatusResp can be returned by a server.Handler to replace the default status
// response. The response tag must be empty.
//
// To suppress default response, Resp should be set to nil.
type ErrStatusResp struct {
	// Response to send instead of default.
	Resp *StatusResp
}

func (err *ErrStatusResp) Error() string {
	if err.Resp == nil {
		return "imap: suppressed response"
	}
	return err.Resp.Info
}