Initial commit

This commit is contained in:
2018-03-05 12:19:04 +00:00
commit 811b90224f
114 changed files with 16465 additions and 0 deletions

95
vendor/github.com/emersion/go-imap/commands/append.go generated vendored Normal file
View File

@@ -0,0 +1,95 @@
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.Encoder.String(cmd.Mailbox)
args = append(args, mailbox)
if cmd.Flags != nil {
flags := make([]interface{}, len(cmd.Flags))
for i, flag := range cmd.Flags {
flags[i] = flag
}
args = append(args, flags)
}
if !cmd.Date.IsZero() {
args = append(args, cmd.Date)
}
args = append(args, cmd.Message)
return &imap.Command{
Name: imap.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, ok := fields[0].(string); !ok {
return errors.New("Mailbox name must be a string")
} else if mailbox, err = utf7.Decoder.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 {
date, ok := fields[0].(string)
if !ok {
return errors.New("Date must be a string")
}
if cmd.Date, err = time.Parse(imap.DateTimeLayout, date); err != nil {
return err
}
}
}
return
}

View File

@@ -0,0 +1,83 @@
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
}
func (cmd *Authenticate) Command() *imap.Command {
return &imap.Command{
Name: imap.Authenticate,
Arguments: []interface{}{cmd.Mechanism},
}
}
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)
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)
var response []byte
for {
challenge, done, err := sasl.Next(response)
if err != nil || done {
return err
}
encoded := base64.StdEncoding.EncodeToString(challenge)
cont := &imap.ContinuationResp{Info: encoded}
if err := conn.WriteResp(cont); err != nil {
return err
}
scanner.Scan()
if err := scanner.Err(); err != nil {
return err
}
encoded = scanner.Text()
if encoded != "" {
response, err = base64.StdEncoding.DecodeString(encoded)
if err != nil {
return err
}
}
}
}

View File

@@ -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: imap.Capability,
}
}
func (c *Capability) Parse(fields []interface{}) error {
return nil
}

18
vendor/github.com/emersion/go-imap/commands/check.go generated vendored Normal file
View File

@@ -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: imap.Check,
}
}
func (cmd *Check) Parse(fields []interface{}) error {
return nil
}

18
vendor/github.com/emersion/go-imap/commands/close.go generated vendored Normal file
View File

@@ -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: imap.Close,
}
}
func (cmd *Close) Parse(fields []interface{}) error {
return nil
}

View File

@@ -0,0 +1,2 @@
// Package commands implements IMAP commands defined in RFC 3501.
package commands

47
vendor/github.com/emersion/go-imap/commands/copy.go generated vendored Normal file
View File

@@ -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.Encoder.String(cmd.Mailbox)
return &imap.Command{
Name: imap.Copy,
Arguments: []interface{}{cmd.SeqSet, 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.NewSeqSet(seqSet); err != nil {
return err
} else {
cmd.SeqSet = seqSet
}
if mailbox, ok := fields[1].(string); !ok {
return errors.New("Mailbox name must be a string")
} else if mailbox, err := utf7.Decoder.String(mailbox); err != nil {
return err
} else {
cmd.Mailbox = imap.CanonicalMailboxName(mailbox)
}
return nil
}

38
vendor/github.com/emersion/go-imap/commands/create.go generated vendored Normal file
View File

@@ -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.Encoder.String(cmd.Mailbox)
return &imap.Command{
Name: imap.Create,
Arguments: []interface{}{mailbox},
}
}
func (cmd *Create) Parse(fields []interface{}) error {
if len(fields) < 1 {
return errors.New("No enough arguments")
}
if mailbox, ok := fields[0].(string); !ok {
return errors.New("Mailbox name must be a string")
} else if mailbox, err := utf7.Decoder.String(mailbox); err != nil {
return err
} else {
cmd.Mailbox = imap.CanonicalMailboxName(mailbox)
}
return nil
}

38
vendor/github.com/emersion/go-imap/commands/delete.go generated vendored Normal file
View File

@@ -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.Encoder.String(cmd.Mailbox)
return &imap.Command{
Name: imap.Delete,
Arguments: []interface{}{mailbox},
}
}
func (cmd *Delete) Parse(fields []interface{}) error {
if len(fields) < 1 {
return errors.New("No enough arguments")
}
if mailbox, ok := fields[0].(string); !ok {
return errors.New("Mailbox name must be a string")
} else if mailbox, err := utf7.Decoder.String(mailbox); err != nil {
return err
} else {
cmd.Mailbox = imap.CanonicalMailboxName(mailbox)
}
return nil
}

16
vendor/github.com/emersion/go-imap/commands/expunge.go generated vendored Normal file
View File

@@ -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: imap.Expunge}
}
func (cmd *Expunge) Parse(fields []interface{}) error {
return nil
}

70
vendor/github.com/emersion/go-imap/commands/fetch.go generated vendored Normal file
View File

@@ -0,0 +1,70 @@
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 []string
}
func (cmd *Fetch) Command() *imap.Command {
items := make([]interface{}, len(cmd.Items))
for i, item := range cmd.Items {
if section, err := imap.NewBodySectionName(item); err == nil {
items[i] = section
} else {
items[i] = item
}
}
return &imap.Command{
Name: imap.Fetch,
Arguments: []interface{}{cmd.SeqSet, items},
}
}
func (cmd *Fetch) Parse(fields []interface{}) error {
if len(fields) < 2 {
return errors.New("No enough arguments")
}
seqset, ok := fields[0].(string)
if !ok {
return errors.New("Sequence set must be a string")
}
var err error
if cmd.SeqSet, err = imap.NewSeqSet(seqset); err != nil {
return err
}
switch items := fields[1].(type) {
case string: // A macro or a single item
switch strings.ToUpper(items) {
case "ALL":
cmd.Items = []string{"FLAGS", "INTERNALDATE", "RFC822.SIZE", "ENVELOPE"}
case "FAST":
cmd.Items = []string{"FLAGS", "INTERNALDATE", "RFC822.SIZE"}
case "FULL":
cmd.Items = []string{"FLAGS", "INTERNALDATE", "RFC822.SIZE", "ENVELOPE", "BODY"}
default:
cmd.Items = []string{strings.ToUpper(items)}
}
case []interface{}: // A list of items
cmd.Items = make([]string, len(items))
for i, v := range items {
item, _ := v.(string)
cmd.Items[i] = strings.ToUpper(item)
}
default:
return errors.New("Items must be either a string or a list")
}
return nil
}

57
vendor/github.com/emersion/go-imap/commands/list.go generated vendored Normal file
View File

@@ -0,0 +1,57 @@
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 := imap.List
if cmd.Subscribed {
name = imap.Lsub
}
ref, _ := utf7.Encoder.String(cmd.Reference)
mailbox, _ := utf7.Encoder.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")
}
if mailbox, ok := fields[0].(string); !ok {
return errors.New("Reference name must be a string")
} else if mailbox, err := utf7.Decoder.String(mailbox); err != nil {
return err
} else {
// TODO: canonical mailbox path
cmd.Reference = imap.CanonicalMailboxName(mailbox)
}
if mailbox, ok := fields[1].(string); !ok {
return errors.New("Mailbox name must be a string")
} else if mailbox, err := utf7.Decoder.String(mailbox); err != nil {
return err
} else {
cmd.Mailbox = imap.CanonicalMailboxName(mailbox)
}
return nil
}

36
vendor/github.com/emersion/go-imap/commands/login.go generated vendored Normal file
View File

@@ -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: imap.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 ok bool
if cmd.Username, ok = fields[0].(string); !ok {
return errors.New("Username is not a string")
}
if cmd.Password, ok = fields[1].(string); !ok {
return errors.New("Password is not a string")
}
return nil
}

18
vendor/github.com/emersion/go-imap/commands/logout.go generated vendored Normal file
View File

@@ -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: imap.Logout,
}
}
func (c *Logout) Parse(fields []interface{}) error {
return nil
}

18
vendor/github.com/emersion/go-imap/commands/noop.go generated vendored Normal file
View File

@@ -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: imap.Noop,
}
}
func (c *Noop) Parse(fields []interface{}) error {
return nil
}

48
vendor/github.com/emersion/go-imap/commands/rename.go generated vendored Normal file
View File

@@ -0,0 +1,48 @@
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 {
existingName, _ := utf7.Encoder.String(cmd.Existing)
newName, _ := utf7.Encoder.String(cmd.New)
return &imap.Command{
Name: imap.Rename,
Arguments: []interface{}{existingName, newName},
}
}
func (cmd *Rename) Parse(fields []interface{}) error {
if len(fields) < 2 {
return errors.New("No enough arguments")
}
if existingName, ok := fields[0].(string); !ok {
return errors.New("Mailbox name must be a string")
} else if existingName, err := utf7.Decoder.String(existingName); err != nil {
return err
} else {
cmd.Existing = imap.CanonicalMailboxName(existingName)
}
if newName, ok := fields[1].(string); !ok {
return errors.New("Mailbox name must be a string")
} else if newName, err := utf7.Decoder.String(newName); err != nil {
return err
} else {
cmd.New = imap.CanonicalMailboxName(newName)
}
return nil
}

57
vendor/github.com/emersion/go-imap/commands/search.go generated vendored Normal file
View File

@@ -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, "CHARSET", cmd.Charset)
}
args = append(args, cmd.Criteria.Format()...)
return &imap.Command{
Name: imap.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)
}

45
vendor/github.com/emersion/go-imap/commands/select.go generated vendored Normal file
View File

@@ -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 := imap.Select
if cmd.ReadOnly {
name = imap.Examine
}
mailbox, _ := utf7.Encoder.String(cmd.Mailbox)
return &imap.Command{
Name: name,
Arguments: []interface{}{mailbox},
}
}
func (cmd *Select) Parse(fields []interface{}) error {
if len(fields) < 1 {
return errors.New("No enough arguments")
}
if mailbox, ok := fields[0].(string); !ok {
return errors.New("Mailbox name must be a string")
} else if mailbox, err := utf7.Decoder.String(mailbox); err != nil {
return err
} else {
cmd.Mailbox = imap.CanonicalMailboxName(mailbox)
}
return nil
}

View File

@@ -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: imap.StartTLS,
}
}
func (cmd *StartTLS) Parse(fields []interface{}) error {
return nil
}

55
vendor/github.com/emersion/go-imap/commands/status.go generated vendored Normal file
View File

@@ -0,0 +1,55 @@
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 []string
}
func (cmd *Status) Command() *imap.Command {
mailbox, _ := utf7.Encoder.String(cmd.Mailbox)
items := make([]interface{}, len(cmd.Items))
for i, f := range cmd.Items {
items[i] = f
}
return &imap.Command{
Name: imap.Status,
Arguments: []interface{}{mailbox, items},
}
}
func (cmd *Status) Parse(fields []interface{}) error {
if len(fields) < 2 {
return errors.New("No enough arguments")
}
if mailbox, ok := fields[0].(string); !ok {
return errors.New("Mailbox name must be a string")
} else if mailbox, err := utf7.Decoder.String(mailbox); err != nil {
return err
} else {
cmd.Mailbox = imap.CanonicalMailboxName(mailbox)
}
if items, ok := fields[1].([]interface{}); !ok {
return errors.New("Items must be a list")
} else {
cmd.Items = make([]string, len(items))
for i, v := range items {
item, _ := v.(string)
cmd.Items[i] = strings.ToUpper(item)
}
}
return nil
}

45
vendor/github.com/emersion/go-imap/commands/store.go generated vendored Normal file
View File

@@ -0,0 +1,45 @@
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 string
Value interface{}
}
func (cmd *Store) Command() *imap.Command {
return &imap.Command{
Name: imap.Store,
Arguments: []interface{}{cmd.SeqSet, cmd.Item, cmd.Value},
}
}
func (cmd *Store) Parse(fields []interface{}) (err error) {
if len(fields) < 3 {
return errors.New("No enough arguments")
}
seqset, ok := fields[0].(string)
if !ok {
return errors.New("Invalid sequence set")
}
if cmd.SeqSet, err = imap.NewSeqSet(seqset); err != nil {
return err
}
if cmd.Item, ok = fields[1].(string); !ok {
return errors.New("Item name must be a string")
}
cmd.Item = strings.ToUpper(cmd.Item)
cmd.Value = fields[2]
return
}

View File

@@ -0,0 +1,71 @@
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.Encoder.String(cmd.Mailbox)
return &imap.Command{
Name: imap.Subscribe,
Arguments: []interface{}{mailbox},
}
}
func (cmd *Subscribe) Parse(fields []interface{}) (err error) {
if len(fields) < 0 {
return errors.New("No enogh arguments")
}
mailbox, ok := fields[0].(string)
if !ok {
return errors.New("Mailbox name must be a string")
}
if cmd.Mailbox, err = utf7.Decoder.String(mailbox); err != nil {
return err
}
return
}
// An UNSUBSCRIBE command.
// See RFC 3501 section 6.3.7
type Unsubscribe struct {
Mailbox string
}
func (cmd *Unsubscribe) Command() *imap.Command {
mailbox, _ := utf7.Encoder.String(cmd.Mailbox)
return &imap.Command{
Name: imap.Unsubscribe,
Arguments: []interface{}{mailbox},
}
}
func (cmd *Unsubscribe) Parse(fields []interface{}) (err error) {
if len(fields) < 0 {
return errors.New("No enogh arguments")
}
mailbox, ok := fields[0].(string)
if !ok {
return errors.New("Mailbox name must be a string")
}
if cmd.Mailbox, err = utf7.Decoder.String(mailbox); err != nil {
return err
}
return
}

44
vendor/github.com/emersion/go-imap/commands/uid.go generated vendored Normal file
View File

@@ -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{}{inner.Name}
args = append(args, inner.Arguments...)
return &imap.Command{
Name: imap.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
}