aboutsummaryrefslogtreecommitdiff
path: root/vendor/github.com/emersion/go-imap/response.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/emersion/go-imap/response.go')
-rw-r--r--vendor/github.com/emersion/go-imap/response.go181
1 files changed, 181 insertions, 0 deletions
diff --git a/vendor/github.com/emersion/go-imap/response.go b/vendor/github.com/emersion/go-imap/response.go
new file mode 100644
index 0000000..611d03e
--- /dev/null
+++ b/vendor/github.com/emersion/go-imap/response.go
@@ -0,0 +1,181 @@
+package imap
+
+import (
+ "strings"
+)
+
+// Resp is an IMAP response. It is either a *DataResp, a
+// *ContinuationReq or a *StatusResp.
+type Resp interface {
+ resp()
+}
+
+// ReadResp reads a single response from a Reader.
+func ReadResp(r *Reader) (Resp, error) {
+ atom, err := r.ReadAtom()
+ if err != nil {
+ return nil, err
+ }
+ tag, ok := atom.(string)
+ if !ok {
+ return nil, newParseError("response tag is not an atom")
+ }
+
+ if tag == "+" {
+ if err := r.ReadSp(); err != nil {
+ r.UnreadRune()
+ }
+
+ resp := &ContinuationReq{}
+ resp.Info, err = r.ReadInfo()
+ if err != nil {
+ return nil, err
+ }
+
+ return resp, nil
+ }
+
+ if err := r.ReadSp(); err != nil {
+ return nil, err
+ }
+
+ // Can be either data or status
+ // Try to parse a status
+ var fields []interface{}
+ if atom, err := r.ReadAtom(); err == nil {
+ fields = append(fields, atom)
+
+ if err := r.ReadSp(); err == nil {
+ if name, ok := atom.(string); ok {
+ status := StatusRespType(name)
+ switch status {
+ case StatusRespOk, StatusRespNo, StatusRespBad, StatusRespPreauth, StatusRespBye:
+ resp := &StatusResp{
+ Tag: tag,
+ Type: status,
+ }
+
+ char, _, err := r.ReadRune()
+ if err != nil {
+ return nil, err
+ }
+ r.UnreadRune()
+
+ if char == '[' {
+ // Contains code & arguments
+ resp.Code, resp.Arguments, err = r.ReadRespCode()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ resp.Info, err = r.ReadInfo()
+ if err != nil {
+ return nil, err
+ }
+
+ return resp, nil
+ }
+ }
+ } else {
+ r.UnreadRune()
+ }
+ } else {
+ r.UnreadRune()
+ }
+
+ // Not a status so it's data
+ resp := &DataResp{Tag: tag}
+
+ var remaining []interface{}
+ remaining, err = r.ReadLine()
+ if err != nil {
+ return nil, err
+ }
+
+ resp.Fields = append(fields, remaining...)
+ return resp, nil
+}
+
+// DataResp is an IMAP response containing data.
+type DataResp struct {
+ // The response tag. Can be either "" for untagged responses, "+" for continuation
+ // requests or a previous command's tag.
+ Tag string
+ // The parsed response fields.
+ Fields []interface{}
+}
+
+// NewUntaggedResp creates a new untagged response.
+func NewUntaggedResp(fields []interface{}) *DataResp {
+ return &DataResp{
+ Tag: "*",
+ Fields: fields,
+ }
+}
+
+func (r *DataResp) resp() {}
+
+func (r *DataResp) WriteTo(w *Writer) error {
+ tag := RawString(r.Tag)
+ if tag == "" {
+ tag = RawString("*")
+ }
+
+ fields := []interface{}{RawString(tag)}
+ fields = append(fields, r.Fields...)
+ return w.writeLine(fields...)
+}
+
+// ContinuationReq is a continuation request response.
+type ContinuationReq struct {
+ // The info message sent with the continuation request.
+ Info string
+}
+
+func (r *ContinuationReq) resp() {}
+
+func (r *ContinuationReq) WriteTo(w *Writer) error {
+ if err := w.writeString("+"); err != nil {
+ return err
+ }
+
+ if r.Info != "" {
+ if err := w.writeString(string(sp) + r.Info); err != nil {
+ return err
+ }
+ }
+
+ return w.writeCrlf()
+}
+
+// ParseNamedResp attempts to parse a named data response.
+func ParseNamedResp(resp Resp) (name string, fields []interface{}, ok bool) {
+ data, ok := resp.(*DataResp)
+ if !ok || len(data.Fields) == 0 {
+ return
+ }
+
+ // Some responses (namely EXISTS and RECENT) are formatted like so:
+ // [num] [name] [...]
+ // Which is fucking stupid. But we handle that here by checking if the
+ // response name is a number and then rearranging it.
+ if len(data.Fields) > 1 {
+ name, ok := data.Fields[1].(string)
+ if ok {
+ if _, err := ParseNumber(data.Fields[0]); err == nil {
+ fields := []interface{}{data.Fields[0]}
+ fields = append(fields, data.Fields[2:]...)
+ return strings.ToUpper(name), fields, true
+ }
+ }
+ }
+
+ // IMAP commands are formatted like this:
+ // [name] [...]
+ name, ok = data.Fields[0].(string)
+ if !ok {
+ return
+ }
+ return strings.ToUpper(name), data.Fields[1:], true
+}