diff options
author | Jordan <me@jordan.im> | 2023-02-04 23:54:03 -0700 |
---|---|---|
committer | Jordan <me@jordan.im> | 2023-02-04 23:54:03 -0700 |
commit | c4159d895ac399ca55326f7b4ff8bfbf8402e654 (patch) | |
tree | 45340ca429c16f683b375695d01e03d65ebf22b0 /vendor/github.com/emersion/go-imap/commands | |
download | pigeon-c4159d895ac399ca55326f7b4ff8bfbf8402e654.tar.gz pigeon-c4159d895ac399ca55326f7b4ff8bfbf8402e654.zip |
initial commit
Diffstat (limited to 'vendor/github.com/emersion/go-imap/commands')
27 files changed, 1098 insertions, 0 deletions
diff --git a/vendor/github.com/emersion/go-imap/commands/append.go b/vendor/github.com/emersion/go-imap/commands/append.go new file mode 100644 index 0000000..d70b584 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/append.go @@ -0,0 +1,93 @@ +package commands + +import ( + "errors" + "time" + + "github.com/emersion/go-imap" + "github.com/emersion/go-imap/utf7" +) + +// Append is an APPEND command, as defined in RFC 3501 section 6.3.11. +type Append struct { + Mailbox string + Flags []string + Date time.Time + Message imap.Literal +} + +func (cmd *Append) Command() *imap.Command { + var args []interface{} + + mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox) + args = append(args, imap.FormatMailboxName(mailbox)) + + if cmd.Flags != nil { + flags := make([]interface{}, len(cmd.Flags)) + for i, flag := range cmd.Flags { + flags[i] = imap.RawString(flag) + } + args = append(args, flags) + } + + if !cmd.Date.IsZero() { + args = append(args, cmd.Date) + } + + args = append(args, cmd.Message) + + return &imap.Command{ + Name: "APPEND", + Arguments: args, + } +} + +func (cmd *Append) Parse(fields []interface{}) (err error) { + if len(fields) < 2 { + return errors.New("No enough arguments") + } + + // Parse mailbox name + if mailbox, err := imap.ParseString(fields[0]); err != nil { + return err + } else if mailbox, err = utf7.Encoding.NewDecoder().String(mailbox); err != nil { + return err + } else { + cmd.Mailbox = imap.CanonicalMailboxName(mailbox) + } + + // Parse message literal + litIndex := len(fields) - 1 + var ok bool + if cmd.Message, ok = fields[litIndex].(imap.Literal); !ok { + return errors.New("Message must be a literal") + } + + // Remaining fields a optional + fields = fields[1:litIndex] + if len(fields) > 0 { + // Parse flags list + if flags, ok := fields[0].([]interface{}); ok { + if cmd.Flags, err = imap.ParseStringList(flags); err != nil { + return err + } + + for i, flag := range cmd.Flags { + cmd.Flags[i] = imap.CanonicalFlag(flag) + } + + fields = fields[1:] + } + + // Parse date + if len(fields) > 0 { + if date, ok := fields[0].(string); !ok { + return errors.New("Date must be a string") + } else if cmd.Date, err = time.Parse(imap.DateTimeLayout, date); err != nil { + return err + } + } + } + + return +} diff --git a/vendor/github.com/emersion/go-imap/commands/authenticate.go b/vendor/github.com/emersion/go-imap/commands/authenticate.go new file mode 100644 index 0000000..b66f21f --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/authenticate.go @@ -0,0 +1,124 @@ +package commands + +import ( + "bufio" + "encoding/base64" + "errors" + "io" + "strings" + + "github.com/emersion/go-imap" + "github.com/emersion/go-sasl" +) + +// AuthenticateConn is a connection that supports IMAP authentication. +type AuthenticateConn interface { + io.Reader + + // WriteResp writes an IMAP response to this connection. + WriteResp(res imap.WriterTo) error +} + +// Authenticate is an AUTHENTICATE command, as defined in RFC 3501 section +// 6.2.2. +type Authenticate struct { + Mechanism string + InitialResponse []byte +} + +func (cmd *Authenticate) Command() *imap.Command { + args := []interface{}{imap.RawString(cmd.Mechanism)} + if cmd.InitialResponse != nil { + var encodedResponse string + if len(cmd.InitialResponse) == 0 { + // Empty initial response should be encoded as "=", not empty + // string. + encodedResponse = "=" + } else { + encodedResponse = base64.StdEncoding.EncodeToString(cmd.InitialResponse) + } + + args = append(args, imap.RawString(encodedResponse)) + } + return &imap.Command{ + Name: "AUTHENTICATE", + Arguments: args, + } +} + +func (cmd *Authenticate) Parse(fields []interface{}) error { + if len(fields) < 1 { + return errors.New("Not enough arguments") + } + + var ok bool + if cmd.Mechanism, ok = fields[0].(string); !ok { + return errors.New("Mechanism must be a string") + } + cmd.Mechanism = strings.ToUpper(cmd.Mechanism) + + if len(fields) != 2 { + return nil + } + + encodedResponse, ok := fields[1].(string) + if !ok { + return errors.New("Initial response must be a string") + } + if encodedResponse == "=" { + cmd.InitialResponse = []byte{} + return nil + } + + var err error + cmd.InitialResponse, err = base64.StdEncoding.DecodeString(encodedResponse) + if err != nil { + return err + } + + return nil +} + +func (cmd *Authenticate) Handle(mechanisms map[string]sasl.Server, conn AuthenticateConn) error { + sasl, ok := mechanisms[cmd.Mechanism] + if !ok { + return errors.New("Unsupported mechanism") + } + + scanner := bufio.NewScanner(conn) + + response := cmd.InitialResponse + for { + challenge, done, err := sasl.Next(response) + if err != nil || done { + return err + } + + encoded := base64.StdEncoding.EncodeToString(challenge) + cont := &imap.ContinuationReq{Info: encoded} + if err := conn.WriteResp(cont); err != nil { + return err + } + + if !scanner.Scan() { + if err := scanner.Err(); err != nil { + return err + } + return errors.New("unexpected EOF") + } + + encoded = scanner.Text() + if encoded != "" { + if encoded == "*" { + return &imap.ErrStatusResp{Resp: &imap.StatusResp{ + Type: imap.StatusRespBad, + Info: "negotiation cancelled", + }} + } + response, err = base64.StdEncoding.DecodeString(encoded) + if err != nil { + return err + } + } + } +} diff --git a/vendor/github.com/emersion/go-imap/commands/capability.go b/vendor/github.com/emersion/go-imap/commands/capability.go new file mode 100644 index 0000000..3359c0a --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/capability.go @@ -0,0 +1,18 @@ +package commands + +import ( + "github.com/emersion/go-imap" +) + +// Capability is a CAPABILITY command, as defined in RFC 3501 section 6.1.1. +type Capability struct{} + +func (c *Capability) Command() *imap.Command { + return &imap.Command{ + Name: "CAPABILITY", + } +} + +func (c *Capability) Parse(fields []interface{}) error { + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/check.go b/vendor/github.com/emersion/go-imap/commands/check.go new file mode 100644 index 0000000..b90df7c --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/check.go @@ -0,0 +1,18 @@ +package commands + +import ( + "github.com/emersion/go-imap" +) + +// Check is a CHECK command, as defined in RFC 3501 section 6.4.1. +type Check struct{} + +func (cmd *Check) Command() *imap.Command { + return &imap.Command{ + Name: "CHECK", + } +} + +func (cmd *Check) Parse(fields []interface{}) error { + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/close.go b/vendor/github.com/emersion/go-imap/commands/close.go new file mode 100644 index 0000000..cc60658 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/close.go @@ -0,0 +1,18 @@ +package commands + +import ( + "github.com/emersion/go-imap" +) + +// Close is a CLOSE command, as defined in RFC 3501 section 6.4.2. +type Close struct{} + +func (cmd *Close) Command() *imap.Command { + return &imap.Command{ + Name: "CLOSE", + } +} + +func (cmd *Close) Parse(fields []interface{}) error { + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/commands.go b/vendor/github.com/emersion/go-imap/commands/commands.go new file mode 100644 index 0000000..a62b248 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/commands.go @@ -0,0 +1,2 @@ +// Package commands implements IMAP commands defined in RFC 3501. +package commands diff --git a/vendor/github.com/emersion/go-imap/commands/copy.go b/vendor/github.com/emersion/go-imap/commands/copy.go new file mode 100644 index 0000000..5258f35 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/copy.go @@ -0,0 +1,47 @@ +package commands + +import ( + "errors" + + "github.com/emersion/go-imap" + "github.com/emersion/go-imap/utf7" +) + +// Copy is a COPY command, as defined in RFC 3501 section 6.4.7. +type Copy struct { + SeqSet *imap.SeqSet + Mailbox string +} + +func (cmd *Copy) Command() *imap.Command { + mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox) + + return &imap.Command{ + Name: "COPY", + Arguments: []interface{}{cmd.SeqSet, imap.FormatMailboxName(mailbox)}, + } +} + +func (cmd *Copy) Parse(fields []interface{}) error { + if len(fields) < 2 { + return errors.New("No enough arguments") + } + + if seqSet, ok := fields[0].(string); !ok { + return errors.New("Invalid sequence set") + } else if seqSet, err := imap.ParseSeqSet(seqSet); err != nil { + return err + } else { + cmd.SeqSet = seqSet + } + + if mailbox, err := imap.ParseString(fields[1]); err != nil { + return err + } else if mailbox, err := utf7.Encoding.NewDecoder().String(mailbox); err != nil { + return err + } else { + cmd.Mailbox = imap.CanonicalMailboxName(mailbox) + } + + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/create.go b/vendor/github.com/emersion/go-imap/commands/create.go new file mode 100644 index 0000000..a1e6fe2 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/create.go @@ -0,0 +1,38 @@ +package commands + +import ( + "errors" + + "github.com/emersion/go-imap" + "github.com/emersion/go-imap/utf7" +) + +// Create is a CREATE command, as defined in RFC 3501 section 6.3.3. +type Create struct { + Mailbox string +} + +func (cmd *Create) Command() *imap.Command { + mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox) + + return &imap.Command{ + Name: "CREATE", + Arguments: []interface{}{mailbox}, + } +} + +func (cmd *Create) Parse(fields []interface{}) error { + if len(fields) < 1 { + return errors.New("No enough arguments") + } + + if mailbox, err := imap.ParseString(fields[0]); err != nil { + return err + } else if mailbox, err := utf7.Encoding.NewDecoder().String(mailbox); err != nil { + return err + } else { + cmd.Mailbox = imap.CanonicalMailboxName(mailbox) + } + + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/delete.go b/vendor/github.com/emersion/go-imap/commands/delete.go new file mode 100644 index 0000000..60f4da8 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/delete.go @@ -0,0 +1,38 @@ +package commands + +import ( + "errors" + + "github.com/emersion/go-imap" + "github.com/emersion/go-imap/utf7" +) + +// Delete is a DELETE command, as defined in RFC 3501 section 6.3.3. +type Delete struct { + Mailbox string +} + +func (cmd *Delete) Command() *imap.Command { + mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox) + + return &imap.Command{ + Name: "DELETE", + Arguments: []interface{}{imap.FormatMailboxName(mailbox)}, + } +} + +func (cmd *Delete) Parse(fields []interface{}) error { + if len(fields) < 1 { + return errors.New("No enough arguments") + } + + if mailbox, err := imap.ParseString(fields[0]); err != nil { + return err + } else if mailbox, err := utf7.Encoding.NewDecoder().String(mailbox); err != nil { + return err + } else { + cmd.Mailbox = imap.CanonicalMailboxName(mailbox) + } + + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/enable.go b/vendor/github.com/emersion/go-imap/commands/enable.go new file mode 100644 index 0000000..980195e --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/enable.go @@ -0,0 +1,23 @@ +package commands + +import ( + "github.com/emersion/go-imap" +) + +// An ENABLE command, defined in RFC 5161 section 3.1. +type Enable struct { + Caps []string +} + +func (cmd *Enable) Command() *imap.Command { + return &imap.Command{ + Name: "ENABLE", + Arguments: imap.FormatStringList(cmd.Caps), + } +} + +func (cmd *Enable) Parse(fields []interface{}) error { + var err error + cmd.Caps, err = imap.ParseStringList(fields) + return err +} diff --git a/vendor/github.com/emersion/go-imap/commands/expunge.go b/vendor/github.com/emersion/go-imap/commands/expunge.go new file mode 100644 index 0000000..af550a4 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/expunge.go @@ -0,0 +1,16 @@ +package commands + +import ( + "github.com/emersion/go-imap" +) + +// Expunge is an EXPUNGE command, as defined in RFC 3501 section 6.4.3. +type Expunge struct{} + +func (cmd *Expunge) Command() *imap.Command { + return &imap.Command{Name: "EXPUNGE"} +} + +func (cmd *Expunge) Parse(fields []interface{}) error { + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/fetch.go b/vendor/github.com/emersion/go-imap/commands/fetch.go new file mode 100644 index 0000000..4eb3ab9 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/fetch.go @@ -0,0 +1,63 @@ +package commands + +import ( + "errors" + "strings" + + "github.com/emersion/go-imap" +) + +// Fetch is a FETCH command, as defined in RFC 3501 section 6.4.5. +type Fetch struct { + SeqSet *imap.SeqSet + Items []imap.FetchItem +} + +func (cmd *Fetch) Command() *imap.Command { + // Handle FETCH macros separately as they should not be serialized within parentheses + if len(cmd.Items) == 1 && (cmd.Items[0] == imap.FetchAll || cmd.Items[0] == imap.FetchFast || cmd.Items[0] == imap.FetchFull) { + return &imap.Command{ + Name: "FETCH", + Arguments: []interface{}{cmd.SeqSet, imap.RawString(cmd.Items[0])}, + } + } else { + items := make([]interface{}, len(cmd.Items)) + for i, item := range cmd.Items { + items[i] = imap.RawString(item) + } + + return &imap.Command{ + Name: "FETCH", + Arguments: []interface{}{cmd.SeqSet, items}, + } + } +} + +func (cmd *Fetch) Parse(fields []interface{}) error { + if len(fields) < 2 { + return errors.New("No enough arguments") + } + + var err error + if seqset, ok := fields[0].(string); !ok { + return errors.New("Sequence set must be an atom") + } else if cmd.SeqSet, err = imap.ParseSeqSet(seqset); err != nil { + return err + } + + switch items := fields[1].(type) { + case string: // A macro or a single item + cmd.Items = imap.FetchItem(strings.ToUpper(items)).Expand() + case []interface{}: // A list of items + cmd.Items = make([]imap.FetchItem, 0, len(items)) + for _, v := range items { + itemStr, _ := v.(string) + item := imap.FetchItem(strings.ToUpper(itemStr)) + cmd.Items = append(cmd.Items, item.Expand()...) + } + default: + return errors.New("Items must be either a string or a list") + } + + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/idle.go b/vendor/github.com/emersion/go-imap/commands/idle.go new file mode 100644 index 0000000..4d9669f --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/idle.go @@ -0,0 +1,17 @@ +package commands + +import ( + "github.com/emersion/go-imap" +) + +// An IDLE command. +// Se RFC 2177 section 3. +type Idle struct{} + +func (cmd *Idle) Command() *imap.Command { + return &imap.Command{Name: "IDLE"} +} + +func (cmd *Idle) Parse(fields []interface{}) error { + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/list.go b/vendor/github.com/emersion/go-imap/commands/list.go new file mode 100644 index 0000000..52686e9 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/list.go @@ -0,0 +1,60 @@ +package commands + +import ( + "errors" + + "github.com/emersion/go-imap" + "github.com/emersion/go-imap/utf7" +) + +// List is a LIST command, as defined in RFC 3501 section 6.3.8. If Subscribed +// is set to true, LSUB will be used instead. +type List struct { + Reference string + Mailbox string + + Subscribed bool +} + +func (cmd *List) Command() *imap.Command { + name := "LIST" + if cmd.Subscribed { + name = "LSUB" + } + + enc := utf7.Encoding.NewEncoder() + ref, _ := enc.String(cmd.Reference) + mailbox, _ := enc.String(cmd.Mailbox) + + return &imap.Command{ + Name: name, + Arguments: []interface{}{ref, mailbox}, + } +} + +func (cmd *List) Parse(fields []interface{}) error { + if len(fields) < 2 { + return errors.New("No enough arguments") + } + + dec := utf7.Encoding.NewDecoder() + + if mailbox, err := imap.ParseString(fields[0]); err != nil { + return err + } else if mailbox, err := dec.String(mailbox); err != nil { + return err + } else { + // TODO: canonical mailbox path + cmd.Reference = imap.CanonicalMailboxName(mailbox) + } + + if mailbox, err := imap.ParseString(fields[1]); err != nil { + return err + } else if mailbox, err := dec.String(mailbox); err != nil { + return err + } else { + cmd.Mailbox = imap.CanonicalMailboxName(mailbox) + } + + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/login.go b/vendor/github.com/emersion/go-imap/commands/login.go new file mode 100644 index 0000000..d0af0b5 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/login.go @@ -0,0 +1,36 @@ +package commands + +import ( + "errors" + + "github.com/emersion/go-imap" +) + +// Login is a LOGIN command, as defined in RFC 3501 section 6.2.2. +type Login struct { + Username string + Password string +} + +func (cmd *Login) Command() *imap.Command { + return &imap.Command{ + Name: "LOGIN", + Arguments: []interface{}{cmd.Username, cmd.Password}, + } +} + +func (cmd *Login) Parse(fields []interface{}) error { + if len(fields) < 2 { + return errors.New("Not enough arguments") + } + + var err error + if cmd.Username, err = imap.ParseString(fields[0]); err != nil { + return err + } + if cmd.Password, err = imap.ParseString(fields[1]); err != nil { + return err + } + + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/logout.go b/vendor/github.com/emersion/go-imap/commands/logout.go new file mode 100644 index 0000000..e826719 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/logout.go @@ -0,0 +1,18 @@ +package commands + +import ( + "github.com/emersion/go-imap" +) + +// Logout is a LOGOUT command, as defined in RFC 3501 section 6.1.3. +type Logout struct{} + +func (c *Logout) Command() *imap.Command { + return &imap.Command{ + Name: "LOGOUT", + } +} + +func (c *Logout) Parse(fields []interface{}) error { + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/move.go b/vendor/github.com/emersion/go-imap/commands/move.go new file mode 100644 index 0000000..613a870 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/move.go @@ -0,0 +1,48 @@ +package commands + +import ( + "errors" + + "github.com/emersion/go-imap" + "github.com/emersion/go-imap/utf7" +) + +// A MOVE command. +// See RFC 6851 section 3.1. +type Move struct { + SeqSet *imap.SeqSet + Mailbox string +} + +func (cmd *Move) Command() *imap.Command { + mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox) + + return &imap.Command{ + Name: "MOVE", + Arguments: []interface{}{cmd.SeqSet, mailbox}, + } +} + +func (cmd *Move) Parse(fields []interface{}) (err error) { + if len(fields) < 2 { + return errors.New("No enough arguments") + } + + seqset, ok := fields[0].(string) + if !ok { + return errors.New("Invalid sequence set") + } + if cmd.SeqSet, err = imap.ParseSeqSet(seqset); err != nil { + return err + } + + mailbox, ok := fields[1].(string) + if !ok { + return errors.New("Mailbox name must be a string") + } + if cmd.Mailbox, err = utf7.Encoding.NewDecoder().String(mailbox); err != nil { + return err + } + + return +} diff --git a/vendor/github.com/emersion/go-imap/commands/noop.go b/vendor/github.com/emersion/go-imap/commands/noop.go new file mode 100644 index 0000000..da6a1c2 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/noop.go @@ -0,0 +1,18 @@ +package commands + +import ( + "github.com/emersion/go-imap" +) + +// Noop is a NOOP command, as defined in RFC 3501 section 6.1.2. +type Noop struct{} + +func (c *Noop) Command() *imap.Command { + return &imap.Command{ + Name: "NOOP", + } +} + +func (c *Noop) Parse(fields []interface{}) error { + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/rename.go b/vendor/github.com/emersion/go-imap/commands/rename.go new file mode 100644 index 0000000..37a5fa7 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/rename.go @@ -0,0 +1,51 @@ +package commands + +import ( + "errors" + + "github.com/emersion/go-imap" + "github.com/emersion/go-imap/utf7" +) + +// Rename is a RENAME command, as defined in RFC 3501 section 6.3.5. +type Rename struct { + Existing string + New string +} + +func (cmd *Rename) Command() *imap.Command { + enc := utf7.Encoding.NewEncoder() + existingName, _ := enc.String(cmd.Existing) + newName, _ := enc.String(cmd.New) + + return &imap.Command{ + Name: "RENAME", + Arguments: []interface{}{imap.FormatMailboxName(existingName), imap.FormatMailboxName(newName)}, + } +} + +func (cmd *Rename) Parse(fields []interface{}) error { + if len(fields) < 2 { + return errors.New("No enough arguments") + } + + dec := utf7.Encoding.NewDecoder() + + if existingName, err := imap.ParseString(fields[0]); err != nil { + return err + } else if existingName, err := dec.String(existingName); err != nil { + return err + } else { + cmd.Existing = imap.CanonicalMailboxName(existingName) + } + + if newName, err := imap.ParseString(fields[1]); err != nil { + return err + } else if newName, err := dec.String(newName); err != nil { + return err + } else { + cmd.New = imap.CanonicalMailboxName(newName) + } + + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/search.go b/vendor/github.com/emersion/go-imap/commands/search.go new file mode 100644 index 0000000..72f026c --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/search.go @@ -0,0 +1,57 @@ +package commands + +import ( + "errors" + "io" + "strings" + + "github.com/emersion/go-imap" +) + +// Search is a SEARCH command, as defined in RFC 3501 section 6.4.4. +type Search struct { + Charset string + Criteria *imap.SearchCriteria +} + +func (cmd *Search) Command() *imap.Command { + var args []interface{} + if cmd.Charset != "" { + args = append(args, imap.RawString("CHARSET"), imap.RawString(cmd.Charset)) + } + args = append(args, cmd.Criteria.Format()...) + + return &imap.Command{ + Name: "SEARCH", + Arguments: args, + } +} + +func (cmd *Search) Parse(fields []interface{}) error { + if len(fields) == 0 { + return errors.New("Missing search criteria") + } + + // Parse charset + if f, ok := fields[0].(string); ok && strings.EqualFold(f, "CHARSET") { + if len(fields) < 2 { + return errors.New("Missing CHARSET value") + } + if cmd.Charset, ok = fields[1].(string); !ok { + return errors.New("Charset must be a string") + } + fields = fields[2:] + } + + var charsetReader func(io.Reader) io.Reader + charset := strings.ToLower(cmd.Charset) + if charset != "utf-8" && charset != "us-ascii" && charset != "" { + charsetReader = func(r io.Reader) io.Reader { + r, _ = imap.CharsetReader(charset, r) + return r + } + } + + cmd.Criteria = new(imap.SearchCriteria) + return cmd.Criteria.ParseWithCharset(fields, charsetReader) +} diff --git a/vendor/github.com/emersion/go-imap/commands/select.go b/vendor/github.com/emersion/go-imap/commands/select.go new file mode 100644 index 0000000..e881eff --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/select.go @@ -0,0 +1,45 @@ +package commands + +import ( + "errors" + + "github.com/emersion/go-imap" + "github.com/emersion/go-imap/utf7" +) + +// Select is a SELECT command, as defined in RFC 3501 section 6.3.1. If ReadOnly +// is set to true, the EXAMINE command will be used instead. +type Select struct { + Mailbox string + ReadOnly bool +} + +func (cmd *Select) Command() *imap.Command { + name := "SELECT" + if cmd.ReadOnly { + name = "EXAMINE" + } + + mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox) + + return &imap.Command{ + Name: name, + Arguments: []interface{}{imap.FormatMailboxName(mailbox)}, + } +} + +func (cmd *Select) Parse(fields []interface{}) error { + if len(fields) < 1 { + return errors.New("No enough arguments") + } + + if mailbox, err := imap.ParseString(fields[0]); err != nil { + return err + } else if mailbox, err := utf7.Encoding.NewDecoder().String(mailbox); err != nil { + return err + } else { + cmd.Mailbox = imap.CanonicalMailboxName(mailbox) + } + + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/starttls.go b/vendor/github.com/emersion/go-imap/commands/starttls.go new file mode 100644 index 0000000..d900e5e --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/starttls.go @@ -0,0 +1,18 @@ +package commands + +import ( + "github.com/emersion/go-imap" +) + +// StartTLS is a STARTTLS command, as defined in RFC 3501 section 6.2.1. +type StartTLS struct{} + +func (cmd *StartTLS) Command() *imap.Command { + return &imap.Command{ + Name: "STARTTLS", + } +} + +func (cmd *StartTLS) Parse(fields []interface{}) error { + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/status.go b/vendor/github.com/emersion/go-imap/commands/status.go new file mode 100644 index 0000000..672dce5 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/status.go @@ -0,0 +1,58 @@ +package commands + +import ( + "errors" + "strings" + + "github.com/emersion/go-imap" + "github.com/emersion/go-imap/utf7" +) + +// Status is a STATUS command, as defined in RFC 3501 section 6.3.10. +type Status struct { + Mailbox string + Items []imap.StatusItem +} + +func (cmd *Status) Command() *imap.Command { + mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox) + + items := make([]interface{}, len(cmd.Items)) + for i, item := range cmd.Items { + items[i] = imap.RawString(item) + } + + return &imap.Command{ + Name: "STATUS", + Arguments: []interface{}{imap.FormatMailboxName(mailbox), items}, + } +} + +func (cmd *Status) Parse(fields []interface{}) error { + if len(fields) < 2 { + return errors.New("No enough arguments") + } + + if mailbox, err := imap.ParseString(fields[0]); err != nil { + return err + } else if mailbox, err := utf7.Encoding.NewDecoder().String(mailbox); err != nil { + return err + } else { + cmd.Mailbox = imap.CanonicalMailboxName(mailbox) + } + + items, ok := fields[1].([]interface{}) + if !ok { + return errors.New("STATUS command parameter is not a list") + } + cmd.Items = make([]imap.StatusItem, len(items)) + for i, f := range items { + if s, ok := f.(string); !ok { + return errors.New("Got a non-string field in a STATUS command parameter") + } else { + cmd.Items[i] = imap.StatusItem(strings.ToUpper(s)) + } + } + + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/store.go b/vendor/github.com/emersion/go-imap/commands/store.go new file mode 100644 index 0000000..aeee3e6 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/store.go @@ -0,0 +1,50 @@ +package commands + +import ( + "errors" + "strings" + + "github.com/emersion/go-imap" +) + +// Store is a STORE command, as defined in RFC 3501 section 6.4.6. +type Store struct { + SeqSet *imap.SeqSet + Item imap.StoreItem + Value interface{} +} + +func (cmd *Store) Command() *imap.Command { + return &imap.Command{ + Name: "STORE", + Arguments: []interface{}{cmd.SeqSet, imap.RawString(cmd.Item), cmd.Value}, + } +} + +func (cmd *Store) Parse(fields []interface{}) error { + if len(fields) < 3 { + return errors.New("No enough arguments") + } + + seqset, ok := fields[0].(string) + if !ok { + return errors.New("Invalid sequence set") + } + var err error + if cmd.SeqSet, err = imap.ParseSeqSet(seqset); err != nil { + return err + } + + if item, ok := fields[1].(string); !ok { + return errors.New("Item name must be a string") + } else { + cmd.Item = imap.StoreItem(strings.ToUpper(item)) + } + + if len(fields[2:]) == 1 { + cmd.Value = fields[2] + } else { + cmd.Value = fields[2:] + } + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/subscribe.go b/vendor/github.com/emersion/go-imap/commands/subscribe.go new file mode 100644 index 0000000..6540969 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/subscribe.go @@ -0,0 +1,63 @@ +package commands + +import ( + "errors" + + "github.com/emersion/go-imap" + "github.com/emersion/go-imap/utf7" +) + +// Subscribe is a SUBSCRIBE command, as defined in RFC 3501 section 6.3.6. +type Subscribe struct { + Mailbox string +} + +func (cmd *Subscribe) Command() *imap.Command { + mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox) + + return &imap.Command{ + Name: "SUBSCRIBE", + Arguments: []interface{}{imap.FormatMailboxName(mailbox)}, + } +} + +func (cmd *Subscribe) Parse(fields []interface{}) error { + if len(fields) < 0 { + return errors.New("No enough arguments") + } + + if mailbox, err := imap.ParseString(fields[0]); err != nil { + return err + } else if cmd.Mailbox, err = utf7.Encoding.NewDecoder().String(mailbox); err != nil { + return err + } + return nil +} + +// An UNSUBSCRIBE command. +// See RFC 3501 section 6.3.7 +type Unsubscribe struct { + Mailbox string +} + +func (cmd *Unsubscribe) Command() *imap.Command { + mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox) + + return &imap.Command{ + Name: "UNSUBSCRIBE", + Arguments: []interface{}{imap.FormatMailboxName(mailbox)}, + } +} + +func (cmd *Unsubscribe) Parse(fields []interface{}) error { + if len(fields) < 0 { + return errors.New("No enogh arguments") + } + + if mailbox, err := imap.ParseString(fields[0]); err != nil { + return err + } else if cmd.Mailbox, err = utf7.Encoding.NewDecoder().String(mailbox); err != nil { + return err + } + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/uid.go b/vendor/github.com/emersion/go-imap/commands/uid.go new file mode 100644 index 0000000..979af14 --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/uid.go @@ -0,0 +1,44 @@ +package commands + +import ( + "errors" + "strings" + + "github.com/emersion/go-imap" +) + +// Uid is a UID command, as defined in RFC 3501 section 6.4.8. It wraps another +// command (e.g. wrapping a Fetch command will result in a UID FETCH). +type Uid struct { + Cmd imap.Commander +} + +func (cmd *Uid) Command() *imap.Command { + inner := cmd.Cmd.Command() + + args := []interface{}{imap.RawString(inner.Name)} + args = append(args, inner.Arguments...) + + return &imap.Command{ + Name: "UID", + Arguments: args, + } +} + +func (cmd *Uid) Parse(fields []interface{}) error { + if len(fields) < 0 { + return errors.New("No command name specified") + } + + name, ok := fields[0].(string) + if !ok { + return errors.New("Command name must be a string") + } + + cmd.Cmd = &imap.Command{ + Name: strings.ToUpper(name), // Command names are case-insensitive + Arguments: fields[1:], + } + + return nil +} diff --git a/vendor/github.com/emersion/go-imap/commands/unselect.go b/vendor/github.com/emersion/go-imap/commands/unselect.go new file mode 100644 index 0000000..da5c63d --- /dev/null +++ b/vendor/github.com/emersion/go-imap/commands/unselect.go @@ -0,0 +1,17 @@ +package commands + +import ( + "github.com/emersion/go-imap" +) + +// An UNSELECT command. +// See RFC 3691 section 2. +type Unselect struct{} + +func (cmd *Unselect) Command() *imap.Command { + return &imap.Command{Name: "UNSELECT"} +} + +func (cmd *Unselect) Parse(fields []interface{}) error { + return nil +} |