Browse Source

Update vendor/

master
Nick Thomas 1 year ago
parent
commit
21c6e571d8
Signed by: lupine <me@ur.gs> GPG Key ID: 1F1A7ECCCFE0B92F
100 changed files with 38918 additions and 1119 deletions
  1. +27
    -5
      Gopkg.lock
  2. +4
    -0
      Gopkg.toml
  3. +2
    -1
      vendor/github.com/emersion/go-imap/.travis.yml
  4. +1
    -2
      vendor/github.com/emersion/go-imap/README.md
  5. +2
    -0
      vendor/github.com/emersion/go-imap/backend/backendutil/backendutil.go
  6. +68
    -0
      vendor/github.com/emersion/go-imap/backend/backendutil/body.go
  7. +60
    -0
      vendor/github.com/emersion/go-imap/backend/backendutil/bodystructure.go
  8. +50
    -0
      vendor/github.com/emersion/go-imap/backend/backendutil/envelope.go
  9. +40
    -0
      vendor/github.com/emersion/go-imap/backend/backendutil/flags.go
  10. +225
    -0
      vendor/github.com/emersion/go-imap/backend/backendutil/search.go
  11. +6
    -6
      vendor/github.com/emersion/go-imap/backend/mailbox.go
  12. +39
    -56
      vendor/github.com/emersion/go-imap/backend/updates.go
  13. +0
    -32
      vendor/github.com/emersion/go-imap/command.go
  14. +8
    -10
      vendor/github.com/emersion/go-imap/commands/append.go
  15. +2
    -2
      vendor/github.com/emersion/go-imap/commands/authenticate.go
  16. +1
    -1
      vendor/github.com/emersion/go-imap/commands/capability.go
  17. +1
    -1
      vendor/github.com/emersion/go-imap/commands/check.go
  18. +1
    -1
      vendor/github.com/emersion/go-imap/commands/close.go
  19. +6
    -6
      vendor/github.com/emersion/go-imap/commands/copy.go
  20. +5
    -5
      vendor/github.com/emersion/go-imap/commands/create.go
  21. +5
    -5
      vendor/github.com/emersion/go-imap/commands/delete.go
  22. +1
    -1
      vendor/github.com/emersion/go-imap/commands/expunge.go
  23. +13
    -24
      vendor/github.com/emersion/go-imap/commands/fetch.go
  24. +13
    -10
      vendor/github.com/emersion/go-imap/commands/list.go
  25. +6
    -6
      vendor/github.com/emersion/go-imap/commands/login.go
  26. +1
    -1
      vendor/github.com/emersion/go-imap/commands/logout.go
  27. +1
    -1
      vendor/github.com/emersion/go-imap/commands/noop.go
  28. +12
    -9
      vendor/github.com/emersion/go-imap/commands/rename.go
  29. +1
    -1
      vendor/github.com/emersion/go-imap/commands/search.go
  30. +6
    -6
      vendor/github.com/emersion/go-imap/commands/select.go
  31. +1
    -1
      vendor/github.com/emersion/go-imap/commands/starttls.go
  32. +18
    -15
      vendor/github.com/emersion/go-imap/commands/status.go
  33. +11
    -9
      vendor/github.com/emersion/go-imap/commands/store.go
  34. +15
    -23
      vendor/github.com/emersion/go-imap/commands/subscribe.go
  35. +1
    -1
      vendor/github.com/emersion/go-imap/commands/uid.go
  36. +1
    -4
      vendor/github.com/emersion/go-imap/conn.go
  37. +0
    -121
      vendor/github.com/emersion/go-imap/handle.go
  38. +80
    -2
      vendor/github.com/emersion/go-imap/imap.go
  39. +44
    -40
      vendor/github.com/emersion/go-imap/mailbox.go
  40. +165
    -132
      vendor/github.com/emersion/go-imap/message.go
  41. +41
    -10
      vendor/github.com/emersion/go-imap/read.go
  42. +117
    -92
      vendor/github.com/emersion/go-imap/response.go
  43. +33
    -47
      vendor/github.com/emersion/go-imap/responses/authenticate.go
  44. +2
    -21
      vendor/github.com/emersion/go-imap/responses/capability.go
  45. +16
    -18
      vendor/github.com/emersion/go-imap/responses/expunge.go
  46. +20
    -28
      vendor/github.com/emersion/go-imap/responses/fetch.go
  47. +20
    -22
      vendor/github.com/emersion/go-imap/responses/list.go
  48. +26
    -0
      vendor/github.com/emersion/go-imap/responses/responses.go
  49. +17
    -13
      vendor/github.com/emersion/go-imap/responses/search.go
  50. +98
    -101
      vendor/github.com/emersion/go-imap/responses/select.go
  51. +26
    -36
      vendor/github.com/emersion/go-imap/responses/status.go
  52. +4
    -5
      vendor/github.com/emersion/go-imap/search.go
  53. +2
    -3
      vendor/github.com/emersion/go-imap/seqset.go
  54. +2
    -2
      vendor/github.com/emersion/go-imap/server/cmd_any.go
  55. +11
    -9
      vendor/github.com/emersion/go-imap/server/cmd_auth.go
  56. +2
    -2
      vendor/github.com/emersion/go-imap/server/cmd_noauth.go
  57. +9
    -19
      vendor/github.com/emersion/go-imap/server/cmd_selected.go
  58. +43
    -32
      vendor/github.com/emersion/go-imap/server/conn.go
  59. +51
    -65
      vendor/github.com/emersion/go-imap/server/server.go
  60. +23
    -23
      vendor/github.com/emersion/go-imap/status.go
  61. +10
    -14
      vendor/github.com/emersion/go-imap/utf7/decoder.go
  62. +2
    -7
      vendor/github.com/emersion/go-imap/utf7/encoder.go
  63. +20
    -1
      vendor/github.com/emersion/go-imap/utf7/utf7.go
  64. +12
    -7
      vendor/github.com/emersion/go-imap/write.go
  65. +24
    -0
      vendor/github.com/emersion/go-message/.gitignore
  66. +5
    -0
      vendor/github.com/emersion/go-message/.travis.yml
  67. +21
    -0
      vendor/github.com/emersion/go-message/LICENSE
  68. +22
    -0
      vendor/github.com/emersion/go-message/README.md
  69. +57
    -0
      vendor/github.com/emersion/go-message/charset/charset.go
  70. +22
    -0
      vendor/github.com/emersion/go-message/charset/header.go
  71. +47
    -0
      vendor/github.com/emersion/go-message/encoding.go
  72. +132
    -0
      vendor/github.com/emersion/go-message/entity.go
  73. +154
    -0
      vendor/github.com/emersion/go-message/header.go
  74. +37
    -0
      vendor/github.com/emersion/go-message/mail/address.go
  75. +38
    -0
      vendor/github.com/emersion/go-message/mail/attachment.go
  76. +57
    -0
      vendor/github.com/emersion/go-message/mail/header.go
  77. +9
    -0
      vendor/github.com/emersion/go-message/mail/mail.go
  78. +130
    -0
      vendor/github.com/emersion/go-message/mail/reader.go
  79. +18
    -0
      vendor/github.com/emersion/go-message/mail/text.go
  80. +73
    -0
      vendor/github.com/emersion/go-message/mail/writer.go
  81. +5
    -0
      vendor/github.com/emersion/go-message/message.go
  82. +110
    -0
      vendor/github.com/emersion/go-message/multipart.go
  83. +116
    -0
      vendor/github.com/emersion/go-message/writer.go
  84. +24
    -0
      vendor/github.com/emersion/go-textwrapper/.gitignore
  85. +1
    -0
      vendor/github.com/emersion/go-textwrapper/.travis.yml
  86. +21
    -0
      vendor/github.com/emersion/go-textwrapper/LICENSE
  87. +27
    -0
      vendor/github.com/emersion/go-textwrapper/README.md
  88. +61
    -0
      vendor/github.com/emersion/go-textwrapper/wrapper.go
  89. +5
    -1
      vendor/golang.org/x/sys/unix/fcntl.go
  90. +5
    -1
      vendor/golang.org/x/sys/unix/syscall_solaris.go
  91. +249
    -0
      vendor/golang.org/x/text/encoding/charmap/charmap.go
  92. +556
    -0
      vendor/golang.org/x/text/encoding/charmap/maketables.go
  93. +7410
    -0
      vendor/golang.org/x/text/encoding/charmap/tables.go
  94. +75
    -0
      vendor/golang.org/x/text/encoding/internal/internal.go
  95. +12
    -0
      vendor/golang.org/x/text/encoding/japanese/all.go
  96. +225
    -0
      vendor/golang.org/x/text/encoding/japanese/eucjp.go
  97. +299
    -0
      vendor/golang.org/x/text/encoding/japanese/iso2022jp.go
  98. +161
    -0
      vendor/golang.org/x/text/encoding/japanese/maketables.go
  99. +189
    -0
      vendor/golang.org/x/text/encoding/japanese/shiftjis.go
  100. +26971
    -0
      vendor/golang.org/x/text/encoding/japanese/tables.go

+ 27
- 5
Gopkg.lock View File

@@ -27,17 +27,28 @@
version = "v1.1.0"

[[projects]]
branch = "v1"
name = "github.com/emersion/go-imap"
packages = [
".",
"backend",
"backend/backendutil",
"commands",
"responses",
"server",
"utf7"
]
revision = "840b16b212bff35b595e708937c6d60861cfab49"
version = "v0.9"
revision = "e402a386e2001febf508c43e85d1a1383dca9e3c"

[[projects]]
name = "github.com/emersion/go-message"
packages = [
".",
"charset",
"mail"
]
revision = "f7e2be8074d097a816a1f5bd9d502adc46275d4a"
version = "v0.9.1"

[[projects]]
branch = "master"
@@ -53,6 +64,12 @@

[[projects]]
branch = "master"
name = "github.com/emersion/go-textwrapper"
packages = ["."]
revision = "d0e65e56babe3f687ff94c1d764ca0e6aa7723ee"

[[projects]]
branch = "master"
name = "github.com/luksen/maildir"
packages = ["."]
revision = "1859503b54bd306fc302bbeac2c10b5a0d5260c9"
@@ -85,7 +102,7 @@
branch = "master"
name = "golang.org/x/net"
packages = ["context"]
revision = "afe8f62b1d6bbd81f31868121a50b06d8188e1f9"
revision = "e514e69ffb8bc3c76a71ae40de0118d794855992"

[[projects]]
branch = "master"
@@ -97,13 +114,18 @@
branch = "master"
name = "golang.org/x/sys"
packages = ["unix"]
revision = "a200a19cb90b19de298170992778b1fda7217bd6"
revision = "7138fd3d9dc8335c567ca206f4333fb75eb05d56"

[[projects]]
name = "golang.org/x/text"
packages = [
"encoding",
"encoding/charmap",
"encoding/internal",
"encoding/internal/identifier",
"encoding/japanese",
"encoding/simplifiedchinese",
"encoding/traditionalchinese",
"internal/gen",
"transform",
"unicode/cldr"
@@ -120,6 +142,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "3c83cbb5b80f3005d42707c0c6e4f1b301a0429c8b83a837816d41ddeb9dd3ef"
inputs-digest = "08b3e1cf0695997a6bb64a34c8f6d941f605f7354a813e70606352318c6cfb5f"
solver-name = "gps-cdcl"
solver-version = 1

+ 4
- 0
Gopkg.toml View File

@@ -24,6 +24,10 @@
# go-tests = true
# unused-packages = true

[[constraint]]
name = "github.com/emersion/go-imap"
branch = "v1"

[prune]
go-tests = true
unused-packages = true

+ 2
- 1
vendor/github.com/emersion/go-imap/.travis.yml View File

@@ -1,5 +1,6 @@
language: go
sudo: false
go:
- 1.8
- 1.9
script: bash <(curl -sL https://gist.github.com/emersion/49d4dda535497002639626bd9e16480c/raw/codecov-go.sh)
after_script: bash <(curl -s https://codecov.io/bash)

+ 1
- 2
vendor/github.com/emersion/go-imap/README.md View File

@@ -6,7 +6,6 @@
[![Go Report
Card](https://goreportcard.com/badge/github.com/emersion/go-imap)](https://goreportcard.com/report/github.com/emersion/go-imap)
[![Unstable](https://img.shields.io/badge/stability-unstable-yellow.svg)](https://github.com/emersion/stability-badges#unstable)
[![Gitter chat](https://badges.gitter.im/goimap/Lobby.svg)](https://gitter.im/goimap/Lobby)

An [IMAP4rev1](https://tools.ietf.org/html/rfc3501) library written in Go. It
can be used to build a client and/or a server.
@@ -96,7 +95,7 @@ func main() {
messages := make(chan *imap.Message, 10)
done = make(chan error, 1)
go func() {
done <- c.Fetch(seqset, []string{imap.EnvelopeMsgAttr}, messages)
done <- c.Fetch(seqset, []imap.FetchItem{imap.FetchEnvelope}, messages)
}()

log.Println("Last 4 messages:")


+ 2
- 0
vendor/github.com/emersion/go-imap/backend/backendutil/backendutil.go View File

@@ -0,0 +1,2 @@
// Package backendutil provides utility functions to implement IMAP backends.
package backendutil

+ 68
- 0
vendor/github.com/emersion/go-imap/backend/backendutil/body.go View File

@@ -0,0 +1,68 @@
package backendutil

import (
"bytes"
"errors"
"io"

"github.com/emersion/go-imap"
"github.com/emersion/go-message"
)

var errNoSuchPart = errors.New("backendutil: no such message body part")

// FetchBodySection extracts a body section from a message.
func FetchBodySection(e *message.Entity, section *imap.BodySectionName) (imap.Literal, error) {
// First, find the requested part using the provided path
for i := len(section.Path) - 1; i >= 0; i-- {
n := section.Path[i]

mr := e.MultipartReader()
if mr == nil {
return nil, errNoSuchPart
}

for j := 1; j <= n; j++ {
p, err := mr.NextPart()
if err == io.EOF {
return nil, errNoSuchPart
} else if err != nil {
return nil, err
}

if j == n {
e = p
break
}
}
}

// Then, write the requested data to a buffer
b := new(bytes.Buffer)

// Write the header
mw, err := message.CreateWriter(b, e.Header)
if err != nil {
return nil, err
}
defer mw.Close()

// If the header hasn't been requested, discard it
if section.Specifier == imap.TextSpecifier {
b.Reset()
}

// Write the body, if requested
switch section.Specifier {
case imap.EntireSpecifier, imap.TextSpecifier:
if _, err := io.Copy(mw, e.Body); err != nil {
return nil, err
}
}

var l imap.Literal = b
if section.Partial != nil {
l = bytes.NewReader(section.ExtractPartial(b.Bytes()))
}
return l, nil
}

+ 60
- 0
vendor/github.com/emersion/go-imap/backend/backendutil/bodystructure.go View File

@@ -0,0 +1,60 @@
package backendutil

import (
"io"
"strings"

"github.com/emersion/go-imap"
"github.com/emersion/go-message"
)

// FetchBodyStructure computes a message's body structure from its content.
func FetchBodyStructure(e *message.Entity, extended bool) (*imap.BodyStructure, error) {
bs := new(imap.BodyStructure)

mediaType, mediaParams, _ := e.Header.ContentType()
typeParts := strings.SplitN(mediaType, "/", 2)
bs.MIMEType = typeParts[0]
if len(typeParts) == 2 {
bs.MIMESubType = typeParts[1]
}
bs.Params = mediaParams

bs.Id = e.Header.Get("Content-Id")
bs.Description = e.Header.Get("Content-Description")
bs.Encoding = e.Header.Get("Content-Encoding")
// TODO: bs.Size

if mr := e.MultipartReader(); mr != nil {
var parts []*imap.BodyStructure
for {
p, err := mr.NextPart()
if err == io.EOF {
break
} else if err != nil {
return nil, err
}

pbs, err := FetchBodyStructure(p, extended)
if err != nil {
return nil, err
}
parts = append(parts, pbs)
}
bs.Parts = parts
}

// TODO: bs.Envelope, bs.BodyStructure
// TODO: bs.Lines

if extended {
bs.Extended = true

bs.Disposition, bs.DispositionParams, _ = e.Header.ContentDisposition()

// TODO: bs.Language, bs.Location
// TODO: bs.MD5
}

return bs, nil
}

+ 50
- 0
vendor/github.com/emersion/go-imap/backend/backendutil/envelope.go View File

@@ -0,0 +1,50 @@
package backendutil

import (
"strings"

"github.com/emersion/go-imap"
"github.com/emersion/go-message"
"github.com/emersion/go-message/mail"
)

func headerAddressList(h mail.Header, key string) ([]*imap.Address, error) {
addrs, err := h.AddressList(key)

list := make([]*imap.Address, len(addrs))
for i, a := range addrs {
parts := strings.SplitN(a.Address, "@", 2)
mailbox := parts[0]
var hostname string
if len(parts) == 2 {
hostname = parts[1]
}

list[i] = &imap.Address{
PersonalName: a.Name,
MailboxName: mailbox,
HostName: hostname,
}
}

return list, err
}

// FetchEnvelope returns a message's envelope from its header.
func FetchEnvelope(h message.Header) (*imap.Envelope, error) {
mh := mail.Header{h}

env := new(imap.Envelope)
env.Date, _ = mh.Date()
env.Subject, _ = mh.Subject()
env.From, _ = headerAddressList(mh, "From")
env.Sender, _ = headerAddressList(mh, "Sender")
env.ReplyTo, _ = headerAddressList(mh, "Reply-To")
env.To, _ = headerAddressList(mh, "To")
env.Cc, _ = headerAddressList(mh, "Cc")
env.Bcc, _ = headerAddressList(mh, "Bcc")
env.InReplyTo = mh.Get("In-Reply-To")
env.MessageId = mh.Get("Message-Id")

return env, nil
}

+ 40
- 0
vendor/github.com/emersion/go-imap/backend/backendutil/flags.go View File

@@ -0,0 +1,40 @@
package backendutil

import (
"github.com/emersion/go-imap"
)

// UpdateFlags executes a flag operation on the flag set current.
func UpdateFlags(current []string, op imap.FlagsOp, flags []string) []string {
switch op {
case imap.SetFlags:
// TODO: keep \Recent if it is present
return flags
case imap.AddFlags:
// Check for duplicates
for _, flag := range current {
for i, addFlag := range flags {
if addFlag == flag {
flags = append(flags[:i], flags[i+1:]...)
break
}
}
}
return append(current, flags...)
case imap.RemoveFlags:
// Iterate through flags from the last one to the first one, to be able to
// delete some of them.
for i := len(current) - 1; i >= 0; i-- {
flag := current[i]

for _, removeFlag := range flags {
if removeFlag == flag {
current = append(current[:i], current[i+1:]...)
break
}
}
}
return current
}
return current
}

+ 225
- 0
vendor/github.com/emersion/go-imap/backend/backendutil/search.go View File

@@ -0,0 +1,225 @@
package backendutil

import (
"bytes"
"fmt"
"io"
"strings"
"time"

"github.com/emersion/go-imap"
"github.com/emersion/go-message"
"github.com/emersion/go-message/mail"
)

func matchString(s, substr string) bool {
return strings.Contains(strings.ToLower(s), strings.ToLower(substr))
}

func bufferBody(e *message.Entity) (*bytes.Buffer, error) {
b := new(bytes.Buffer)
if _, err := io.Copy(b, e.Body); err != nil {
return nil, err
}
e.Body = b
return b, nil
}

func matchBody(e *message.Entity, substr string) (bool, error) {
if s, ok := e.Body.(fmt.Stringer); ok {
return matchString(s.String(), substr), nil
}

b, err := bufferBody(e)
if err != nil {
return false, err
}
return matchString(b.String(), substr), nil
}

type lengther interface {
Len() int
}

func bodyLen(e *message.Entity) (int, error) {
if l, ok := e.Body.(lengther); ok {
return l.Len(), nil
}

b, err := bufferBody(e)
if err != nil {
return 0, err
}
return b.Len(), nil
}

// Match returns true if a message matches the provided criteria. Sequence
// number, UID, flag and internal date contrainsts are not checked.
func Match(e *message.Entity, c *imap.SearchCriteria) (bool, error) {
// TODO: support encoded header fields for Bcc, Cc, From, To
// TODO: add header size for Larger and Smaller

h := mail.Header{e.Header}

if !c.SentBefore.IsZero() || !c.SentSince.IsZero() {
t, err := h.Date()
if err != nil {
return false, err
}
t = t.Round(24 * time.Hour)

if !c.SentBefore.IsZero() && !t.Before(c.SentBefore) {
return false, nil
}
if !c.SentSince.IsZero() && !t.After(c.SentSince) {
return false, nil
}
}

for key, wantValues := range c.Header {
values, ok := e.Header[key]
for _, wantValue := range wantValues {
if wantValue == "" && !ok {
return false, nil
}
if wantValue != "" {
ok := false
for _, v := range values {
if matchString(v, wantValue) {
ok = true
break
}
}
if !ok {
return false, nil
}
}
}
}
for _, body := range c.Body {
if ok, err := matchBody(e, body); err != nil || !ok {
return false, err
}
}
for _, text := range c.Text {
// TODO: also match header fields
if ok, err := matchBody(e, text); err != nil || !ok {
return false, err
}
}

if c.Larger > 0 || c.Smaller > 0 {
n, err := bodyLen(e)
if err != nil {
return false, err
}

if c.Larger > 0 && uint32(n) < c.Larger {
return false, nil
}
if c.Smaller > 0 && uint32(n) > c.Smaller {
return false, nil
}
}

for _, not := range c.Not {
ok, err := Match(e, not)
if err != nil || ok {
return false, err
}
}
for _, or := range c.Or {
ok1, err := Match(e, or[0])
if err != nil {
return ok1, err
}

ok2, err := Match(e, or[1])
if err != nil || (!ok1 && !ok2) {
return false, err
}
}

return true, nil
}

func matchFlags(flags map[string]bool, c *imap.SearchCriteria) bool {
for _, f := range c.WithFlags {
if !flags[f] {
return false
}
}
for _, f := range c.WithoutFlags {
if flags[f] {
return false
}
}

for _, not := range c.Not {
if matchFlags(flags, not) {
return false
}
}
for _, or := range c.Or {
if !matchFlags(flags, or[0]) && !matchFlags(flags, or[1]) {
return false
}
}
return true
}

// MatchFlags returns true if a flag list matches the provided criteria.
func MatchFlags(flags []string, c *imap.SearchCriteria) bool {
flagsMap := make(map[string]bool)
for _, f := range flags {
flagsMap[f] = true
}

return matchFlags(flagsMap, c)
}

// MatchSeqNumAndUid returns true if a sequence number and a UID matches the
// provided criteria.
func MatchSeqNumAndUid(seqNum uint32, uid uint32, c *imap.SearchCriteria) bool {
if c.SeqNum != nil && !c.SeqNum.Contains(seqNum) {
return false
}
if c.Uid != nil && !c.Uid.Contains(uid) {
return false
}

for _, not := range c.Not {
if MatchSeqNumAndUid(seqNum, uid, not) {
return false
}
}
for _, or := range c.Or {
if !MatchSeqNumAndUid(seqNum, uid, or[0]) && !MatchSeqNumAndUid(seqNum, uid, or[1]) {
return false
}
}
return true
}

// MatchDate returns true if a date matches the provided criteria.
func MatchDate(date time.Time, c *imap.SearchCriteria) bool {
date = date.Round(24 * time.Hour)
if !c.Since.IsZero() && !date.After(c.Since) {
return false
}
if !c.Before.IsZero() && !date.Before(c.Before) {
return false
}

for _, not := range c.Not {
if MatchDate(date, not) {
return false
}
}
for _, or := range c.Or {
if !MatchDate(date, or[0]) && !MatchDate(date, or[1]) {
return false
}
}
return true
}

+ 6
- 6
vendor/github.com/emersion/go-imap/backend/mailbox.go View File

@@ -15,11 +15,11 @@ type Mailbox interface {
// Info returns this mailbox info.
Info() (*imap.MailboxInfo, error)

// Status returns this mailbox status. The fields Name, Flags and
// PermanentFlags in the returned MailboxStatus must be always populated. This
// function does not affect the state of any messages in the mailbox. See RFC
// 3501 section 6.3.10 for a list of items that can be requested.
Status(items []string) (*imap.MailboxStatus, error)
// Status returns this mailbox status. The fields Name, Flags, PermanentFlags
// and UnseenSeqNum in the returned MailboxStatus must be always populated.
// This function does not affect the state of any messages in the mailbox. See
// RFC 3501 section 6.3.10 for a list of items that can be requested.
Status(items []imap.StatusItem) (*imap.MailboxStatus, error)

// SetSubscribed adds or removes the mailbox to the server's set of "active"
// or "subscribed" mailboxes.
@@ -38,7 +38,7 @@ type Mailbox interface {
// 3501 section 6.4.5 for a list of items that can be requested.
//
// Messages must be sent to ch. When the function returns, ch must be closed.
ListMessages(uid bool, seqset *imap.SeqSet, items []string, ch chan<- *imap.Message) error
ListMessages(uid bool, seqset *imap.SeqSet, items []imap.FetchItem, ch chan<- *imap.Message) error

// SearchMessages searches messages. The returned list must contain UIDs if
// uid is set to true, or sequence numbers otherwise.


+ 39
- 56
vendor/github.com/emersion/go-imap/backend/updates.go View File

@@ -6,35 +6,47 @@ import (

// Update contains user and mailbox information about an unilateral backend
// update.
type Update struct {
type Update interface {
// The user targeted by this update. If empty, all connected users will
// be notified.
Username string
Username() string
// The mailbox targeted by this update. If empty, the update targets all
// mailboxes.
Mailbox string
Mailbox() string
// Done returns a channel that is closed when the update has been broadcast to
// all clients.
Done() chan struct{}
}

// A channel that will be closed once the update has been processed.
// NewUpdate creates a new update.
func NewUpdate(username, mailbox string) Update {
return &update{
username: username,
mailbox: mailbox,
}
}

type update struct {
username string
mailbox string
done chan struct{}
}

// Done returns a channel that is closed when the update has been broadcast to
// all clients.
func (u *Update) Done() <-chan struct{} {
func (u *update) Username() string {
return u.username
}

func (u *update) Mailbox() string {
return u.mailbox
}

func (u *update) Done() chan struct{} {
if u.done == nil {
u.done = make(chan struct{})
}
return u.done
}

// DoneUpdate marks an update as done.
// TODO: remove this function
func DoneUpdate(u *Update) {
if u.done != nil {
close(u.done)
}
}

// StatusUpdate is a status update. See RFC 3501 section 7.1 for a list of
// status responses.
type StatusUpdate struct {
@@ -60,50 +72,21 @@ type ExpungeUpdate struct {
SeqNum uint32
}

// Updater is a Backend that implements Updater is able to send unilateral
// backend updates. Backends not implementing this interface don't correctly
// send unilateral updates, for instance if a user logs in from two connections
// and deletes a message from one of them, the over is not aware that such a
// mesage has been deleted. More importantly, backends implementing Updater can
// notify the user for external updates such as new message notifications.
type Updater interface {
// BackendUpdater is a Backend that implements Updater is able to send
// unilateral backend updates. Backends not implementing this interface don't
// correctly send unilateral updates, for instance if a user logs in from two
// connections and deletes a message from one of them, the over is not aware
// that such a mesage has been deleted. More importantly, backends implementing
// Updater can notify the user for external updates such as new message
// notifications.
type BackendUpdater interface {
// Updates returns a set of channels where updates are sent to.
Updates() <-chan interface{}
Updates() <-chan Update
}

// UpdaterMailbox is a Mailbox that implements UpdaterMailbox is able to poll
// updates for new messages or message status updates during a period of
// inactivity.
type UpdaterMailbox interface {
// MailboxPoller is a Mailbox that is able to poll updates for new messages or
// message status updates during a period of inactivity.
type MailboxPoller interface {
// Poll requests mailbox updates.
Poll() error
}

// WaitUpdates returns a channel that's closed when all provided updates have
// been dispatched to all clients. It panics if one of the provided value is
// not an update.
func WaitUpdates(updates ...interface{}) <-chan struct{} {
done := make(chan struct{})

var chs []<-chan struct{}
for _, u := range updates {
uu, ok := u.(interface {
Done() <-chan struct{}
})
if !ok {
panic("imap: cannot wait for update: provided value is not a valid update")
}

chs = append(chs, uu.Done())
}

go func() {
// Wait for all updates to be sent
for _, ch := range chs {
<-ch
}
close(done)
}()

return done
}

+ 0
- 32
vendor/github.com/emersion/go-imap/command.go View File

@@ -5,38 +5,6 @@ import (
"strings"
)

// IMAP4rev1 commands.
const (
Capability string = "CAPABILITY"
Noop = "NOOP"
Logout = "LOGOUT"
StartTLS = "STARTTLS"

Authenticate = "AUTHENTICATE"
Login = "LOGIN"

Select = "SELECT"
Examine = "EXAMINE"
Create = "CREATE"
Delete = "DELETE"
Rename = "RENAME"
Subscribe = "SUBSCRIBE"
Unsubscribe = "UNSUBSCRIBE"
List = "LIST"
Lsub = "LSUB"
Status = "STATUS"
Append = "APPEND"

Check = "CHECK"
Close = "CLOSE"
Expunge = "EXPUNGE"
Search = "SEARCH"
Fetch = "FETCH"
Store = "STORE"
Copy = "COPY"
Uid = "UID"
)

// A value that can be converted to a command.
type Commander interface {
Command() *Command


+ 8
- 10
vendor/github.com/emersion/go-imap/commands/append.go View File

@@ -19,13 +19,13 @@ type Append struct {
func (cmd *Append) Command() *imap.Command {
var args []interface{}

mailbox, _ := utf7.Encoder.String(cmd.Mailbox)
mailbox, _ := utf7.Encoding.NewEncoder().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
flags[i] = imap.Atom(flag)
}
args = append(args, flags)
}
@@ -37,7 +37,7 @@ func (cmd *Append) Command() *imap.Command {
args = append(args, cmd.Message)

return &imap.Command{
Name: imap.Append,
Name: "APPEND",
Arguments: args,
}
}
@@ -48,9 +48,9 @@ func (cmd *Append) Parse(fields []interface{}) (err error) {
}

// 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 {
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)
@@ -81,11 +81,9 @@ func (cmd *Append) Parse(fields []interface{}) (err error) {

// Parse date
if len(fields) > 0 {
date, ok := fields[0].(string)
if !ok {
if date, ok := fields[0].(string); !ok {
return errors.New("Date must be a string")
}
if cmd.Date, err = time.Parse(imap.DateTimeLayout, date); err != nil {
} else if cmd.Date, err = time.Parse(imap.DateTimeLayout, date); err != nil {
return err
}
}


+ 2
- 2
vendor/github.com/emersion/go-imap/commands/authenticate.go View File

@@ -27,7 +27,7 @@ type Authenticate struct {

func (cmd *Authenticate) Command() *imap.Command {
return &imap.Command{
Name: imap.Authenticate,
Name: "AUTHENTICATE",
Arguments: []interface{}{cmd.Mechanism},
}
}
@@ -62,7 +62,7 @@ func (cmd *Authenticate) Handle(mechanisms map[string]sasl.Server, conn Authenti
}

encoded := base64.StdEncoding.EncodeToString(challenge)
cont := &imap.ContinuationResp{Info: encoded}
cont := &imap.ContinuationReq{Info: encoded}
if err := conn.WriteResp(cont); err != nil {
return err
}


+ 1
- 1
vendor/github.com/emersion/go-imap/commands/capability.go View File

@@ -9,7 +9,7 @@ type Capability struct{}

func (c *Capability) Command() *imap.Command {
return &imap.Command{
Name: imap.Capability,
Name: "CAPABILITY",
}
}



+ 1
- 1
vendor/github.com/emersion/go-imap/commands/check.go View File

@@ -9,7 +9,7 @@ type Check struct{}

func (cmd *Check) Command() *imap.Command {
return &imap.Command{
Name: imap.Check,
Name: "CHECK",
}
}



+ 1
- 1
vendor/github.com/emersion/go-imap/commands/close.go View File

@@ -9,7 +9,7 @@ type Close struct{}

func (cmd *Close) Command() *imap.Command {
return &imap.Command{
Name: imap.Close,
Name: "CLOSE",
}
}



+ 6
- 6
vendor/github.com/emersion/go-imap/commands/copy.go View File

@@ -14,10 +14,10 @@ type Copy struct {
}

func (cmd *Copy) Command() *imap.Command {
mailbox, _ := utf7.Encoder.String(cmd.Mailbox)
mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox)

return &imap.Command{
Name: imap.Copy,
Name: "COPY",
Arguments: []interface{}{cmd.SeqSet, mailbox},
}
}
@@ -29,15 +29,15 @@ func (cmd *Copy) Parse(fields []interface{}) error {

if seqSet, ok := fields[0].(string); !ok {
return errors.New("Invalid sequence set")
} else if seqSet, err := imap.NewSeqSet(seqSet); err != nil {
} else if seqSet, err := imap.ParseSeqSet(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 {
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)


+ 5
- 5
vendor/github.com/emersion/go-imap/commands/create.go View File

@@ -13,10 +13,10 @@ type Create struct {
}

func (cmd *Create) Command() *imap.Command {
mailbox, _ := utf7.Encoder.String(cmd.Mailbox)
mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox)

return &imap.Command{
Name: imap.Create,
Name: "CREATE",
Arguments: []interface{}{mailbox},
}
}
@@ -26,9 +26,9 @@ func (cmd *Create) Parse(fields []interface{}) error {
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 {
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)


+ 5
- 5
vendor/github.com/emersion/go-imap/commands/delete.go View File

@@ -13,10 +13,10 @@ type Delete struct {
}

func (cmd *Delete) Command() *imap.Command {
mailbox, _ := utf7.Encoder.String(cmd.Mailbox)
mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox)

return &imap.Command{
Name: imap.Delete,
Name: "DELETE",
Arguments: []interface{}{mailbox},
}
}
@@ -26,9 +26,9 @@ func (cmd *Delete) Parse(fields []interface{}) error {
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 {
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)


+ 1
- 1
vendor/github.com/emersion/go-imap/commands/expunge.go View File

@@ -8,7 +8,7 @@ import (
type Expunge struct{}

func (cmd *Expunge) Command() *imap.Command {
return &imap.Command{Name: imap.Expunge}
return &imap.Command{Name: "EXPUNGE"}
}

func (cmd *Expunge) Parse(fields []interface{}) error {


+ 13
- 24
vendor/github.com/emersion/go-imap/commands/fetch.go View File

@@ -10,21 +10,21 @@ import (
// Fetch is a FETCH command, as defined in RFC 3501 section 6.4.5.
type Fetch struct {
SeqSet *imap.SeqSet
Items []string
Items []imap.FetchItem
}

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 {
if section, err := imap.ParseBodySectionName(item); err == nil {
items[i] = section
} else {
items[i] = item
items[i] = string(item)
}
}

return &imap.Command{
Name: imap.Fetch,
Name: "FETCH",
Arguments: []interface{}{cmd.SeqSet, items},
}
}
@@ -34,33 +34,22 @@ func (cmd *Fetch) Parse(fields []interface{}) error {
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 {
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
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)}
}
cmd.Items = imap.FetchItem(strings.ToUpper(items)).Expand()
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)
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")


+ 13
- 10
vendor/github.com/emersion/go-imap/commands/list.go View File

@@ -17,13 +17,14 @@ type List struct {
}

func (cmd *List) Command() *imap.Command {
name := imap.List
name := "LIST"
if cmd.Subscribed {
name = imap.Lsub
name = "LSUB"
}

ref, _ := utf7.Encoder.String(cmd.Reference)
mailbox, _ := utf7.Encoder.String(cmd.Mailbox)
enc := utf7.Encoding.NewEncoder()
ref, _ := enc.String(cmd.Reference)
mailbox, _ := enc.String(cmd.Mailbox)

return &imap.Command{
Name: name,
@@ -36,18 +37,20 @@ func (cmd *List) Parse(fields []interface{}) error {
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 {
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, ok := fields[1].(string); !ok {
return errors.New("Mailbox name must be a string")
} else if mailbox, err := utf7.Decoder.String(mailbox); err != nil {
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)


+ 6
- 6
vendor/github.com/emersion/go-imap/commands/login.go View File

@@ -14,7 +14,7 @@ type Login struct {

func (cmd *Login) Command() *imap.Command {
return &imap.Command{
Name: imap.Login,
Name: "LOGIN",
Arguments: []interface{}{cmd.Username, cmd.Password},
}
}
@@ -24,12 +24,12 @@ func (cmd *Login) Parse(fields []interface{}) error {
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")
var err error
if cmd.Username, err = imap.ParseString(fields[0]); err != nil {
return err
}
if cmd.Password, ok = fields[1].(string); !ok {
return errors.New("Password is not a string")
if cmd.Password, err = imap.ParseString(fields[1]); err != nil {
return err
}

return nil


+ 1
- 1
vendor/github.com/emersion/go-imap/commands/logout.go View File

@@ -9,7 +9,7 @@ type Logout struct{}

func (c *Logout) Command() *imap.Command {
return &imap.Command{
Name: imap.Logout,
Name: "LOGOUT",
}
}



+ 1
- 1
vendor/github.com/emersion/go-imap/commands/noop.go View File

@@ -9,7 +9,7 @@ type Noop struct{}

func (c *Noop) Command() *imap.Command {
return &imap.Command{
Name: imap.Noop,
Name: "NOOP",
}
}



+ 12
- 9
vendor/github.com/emersion/go-imap/commands/rename.go View File

@@ -14,11 +14,12 @@ type Rename struct {
}

func (cmd *Rename) Command() *imap.Command {
existingName, _ := utf7.Encoder.String(cmd.Existing)
newName, _ := utf7.Encoder.String(cmd.New)
enc := utf7.Encoding.NewEncoder()
existingName, _ := enc.String(cmd.Existing)
newName, _ := enc.String(cmd.New)

return &imap.Command{
Name: imap.Rename,
Name: "RENAME",
Arguments: []interface{}{existingName, newName},
}
}
@@ -28,17 +29,19 @@ func (cmd *Rename) Parse(fields []interface{}) error {
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 {
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, ok := fields[1].(string); !ok {
return errors.New("Mailbox name must be a string")
} else if newName, err := utf7.Decoder.String(newName); err != nil {
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)


+ 1
- 1
vendor/github.com/emersion/go-imap/commands/search.go View File

@@ -22,7 +22,7 @@ func (cmd *Search) Command() *imap.Command {
args = append(args, cmd.Criteria.Format()...)

return &imap.Command{
Name: imap.Search,
Name: "SEARCH",
Arguments: args,
}
}


+ 6
- 6
vendor/github.com/emersion/go-imap/commands/select.go View File

@@ -15,12 +15,12 @@ type Select struct {
}

func (cmd *Select) Command() *imap.Command {
name := imap.Select
name := "SELECT"
if cmd.ReadOnly {
name = imap.Examine
name = "EXAMINE"
}

mailbox, _ := utf7.Encoder.String(cmd.Mailbox)
mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox)

return &imap.Command{
Name: name,
@@ -33,9 +33,9 @@ func (cmd *Select) Parse(fields []interface{}) error {
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 {
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)


+ 1
- 1
vendor/github.com/emersion/go-imap/commands/starttls.go View File

@@ -9,7 +9,7 @@ type StartTLS struct{}

func (cmd *StartTLS) Command() *imap.Command {
return &imap.Command{
Name: imap.StartTLS,
Name: "STARTTLS",
}
}



+ 18
- 15
vendor/github.com/emersion/go-imap/commands/status.go View File

@@ -11,19 +11,19 @@ import (
// Status is a STATUS command, as defined in RFC 3501 section 6.3.10.
type Status struct {
Mailbox string
Items []string
Items []imap.StatusItem
}

func (cmd *Status) Command() *imap.Command {
mailbox, _ := utf7.Encoder.String(cmd.Mailbox)
mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox)

items := make([]interface{}, len(cmd.Items))
for i, f := range cmd.Items {
items[i] = f
for i, item := range cmd.Items {
items[i] = string(item)
}

return &imap.Command{
Name: imap.Status,
Name: "STATUS",
Arguments: []interface{}{mailbox, items},
}
}
@@ -33,21 +33,24 @@ func (cmd *Status) Parse(fields []interface{}) error {
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 {
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)
}

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)
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))
}
}



+ 11
- 9
vendor/github.com/emersion/go-imap/commands/store.go View File

@@ -10,18 +10,18 @@ import (
// Store is a STORE command, as defined in RFC 3501 section 6.4.6.
type Store struct {
SeqSet *imap.SeqSet
Item string
Item imap.StoreItem
Value interface{}
}

func (cmd *Store) Command() *imap.Command {
return &imap.Command{
Name: imap.Store,
Arguments: []interface{}{cmd.SeqSet, cmd.Item, cmd.Value},
Name: "STORE",
Arguments: []interface{}{cmd.SeqSet, string(cmd.Item), cmd.Value},
}
}

func (cmd *Store) Parse(fields []interface{}) (err error) {
func (cmd *Store) Parse(fields []interface{}) error {
if len(fields) < 3 {
return errors.New("No enough arguments")
}
@@ -30,16 +30,18 @@ func (cmd *Store) Parse(fields []interface{}) (err error) {
if !ok {
return errors.New("Invalid sequence set")
}
if cmd.SeqSet, err = imap.NewSeqSet(seqset); err != nil {
var err error
if cmd.SeqSet, err = imap.ParseSeqSet(seqset); err != nil {
return err
}

if cmd.Item, ok = fields[1].(string); !ok {
if item, ok := fields[1].(string); !ok {
return errors.New("Item name must be a string")
} else {
cmd.Item = imap.StoreItem(strings.ToUpper(item))
}
cmd.Item = strings.ToUpper(cmd.Item)

// TODO: could be fields[2:] according to RFC 3501 page 91 "store-att-flags"
cmd.Value = fields[2]

return
return nil
}

+ 15
- 23
vendor/github.com/emersion/go-imap/commands/subscribe.go View File

@@ -13,29 +13,25 @@ type Subscribe struct {
}

func (cmd *Subscribe) Command() *imap.Command {
mailbox, _ := utf7.Encoder.String(cmd.Mailbox)
mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox)

return &imap.Command{
Name: imap.Subscribe,
Name: "SUBSCRIBE",
Arguments: []interface{}{mailbox},
}
}

func (cmd *Subscribe) Parse(fields []interface{}) (err error) {
func (cmd *Subscribe) Parse(fields []interface{}) 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")
return errors.New("No enough arguments")
}

if cmd.Mailbox, err = utf7.Decoder.String(mailbox); err != nil {
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
return nil
}

// An UNSUBSCRIBE command.
@@ -45,27 +41,23 @@ type Unsubscribe struct {
}

func (cmd *Unsubscribe) Command() *imap.Command {
mailbox, _ := utf7.Encoder.String(cmd.Mailbox)
mailbox, _ := utf7.Encoding.NewEncoder().String(cmd.Mailbox)

return &imap.Command{
Name: imap.Unsubscribe,
Name: "UNSUBSCRIBE",
Arguments: []interface{}{mailbox},
}
}

func (cmd *Unsubscribe) Parse(fields []interface{}) (err error) {
func (cmd *Unsubscribe) Parse(fields []interface{}) 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 {
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
return nil
}

+ 1
- 1
vendor/github.com/emersion/go-imap/commands/uid.go View File

@@ -20,7 +20,7 @@ func (cmd *Uid) Command() *imap.Command {
args = append(args, inner.Arguments...)

return &imap.Command{
Name: imap.Uid,
Name: "UID",
Arguments: args,
}
}


+ 1
- 4
vendor/github.com/emersion/go-imap/conn.go View File

@@ -154,10 +154,7 @@ func (c *Conn) Write(b []byte) (n int, err error) {

// Flush writes any buffered data to the underlying connection.
func (c *Conn) Flush() error {
if err := c.Writer.Flush(); err != nil {
return err
}
return nil
return c.Writer.Flush()
}

// Upgrade a connection, e.g. wrap an unencrypted connection with an encrypted


+ 0
- 121
vendor/github.com/emersion/go-imap/handle.go View File

@@ -1,121 +0,0 @@
package imap

import (
"sync"
)

// A response that can be either accepted or rejected by a handler.
type RespHandle struct {
Resp interface{}
Accepts chan bool
}

// Accept this response. This means that the handler will process it.
func (h *RespHandle) Accept() {
h.Accepts <- true
}

// Reject this response. The handler cannot process it.
func (h *RespHandle) Reject() {
h.Accepts <- false
}

// Accept this response if it has the specified name. If not, reject it.
func (h *RespHandle) AcceptNamedResp(name string) (fields []interface{}, accepted bool) {
res, ok := h.Resp.(*Resp)
if !ok || len(res.Fields) == 0 {
h.Reject()
return
}

n, ok := res.Fields[0].(string)
if !ok || n != name {
h.Reject()
return
}

h.Accept()

fields = res.Fields[1:]
accepted = true
return
}

// Delivers responses to handlers.
type RespHandler chan *RespHandle

// Handles responses from a handler.
type RespHandlerFrom interface {
HandleFrom(hdlr RespHandler) error
}

// A RespHandlerFrom that forwards responses to multiple RespHandler.
type MultiRespHandler struct {
handlers []RespHandler
locker sync.Locker
}

func NewMultiRespHandler() *MultiRespHandler {
return &MultiRespHandler{
locker: &sync.Mutex{},
}
}

func (mh *MultiRespHandler) HandleFrom(ch RespHandler) error {
for rh := range ch {
mh.locker.Lock()

accepted := false
for i := len(mh.handlers) - 1; i >= 0; i-- {
hdlr := mh.handlers[i]

rh := &RespHandle{
Resp: rh.Resp,
Accepts: make(chan bool),
}

hdlr <- rh
if accepted = <-rh.Accepts; accepted {
break
}
}

mh.locker.Unlock()

if accepted {
rh.Accept()
} else {
rh.Reject()
}
}

mh.locker.Lock()
for _, hdlr := range mh.handlers {
close(hdlr)
}
mh.handlers = nil
mh.locker.Unlock()

return nil
}

func (mh *MultiRespHandler) Add(hdlr RespHandler) {
if hdlr == nil {
return
}

mh.locker.Lock()
mh.handlers = append(mh.handlers, hdlr)
mh.locker.Unlock()
}

func (mh *MultiRespHandler) Del(hdlr RespHandler) {
mh.locker.Lock()
for i, h := range mh.handlers {
if h == hdlr {
close(hdlr)
mh.handlers = append(mh.handlers[:i], mh.handlers[i+1:]...)
}
}
mh.locker.Unlock()
}

+ 80
- 2
vendor/github.com/emersion/go-imap/imap.go View File

@@ -2,9 +2,60 @@
package imap

import (
"errors"
"io"
"strings"
)

// A StatusItem is a mailbox status data item that can be retrieved with a
// STATUS command. See RFC 3501 section 6.3.10.
type StatusItem string

const (
StatusMessages StatusItem = "MESSAGES"
StatusRecent = "RECENT"
StatusUidNext = "UIDNEXT"
StatusUidValidity = "UIDVALIDITY"
StatusUnseen = "UNSEEN"
)

// A FetchItem is a message data item that can be fetched.
type FetchItem string

// List of items that can be fetched.
const (
// Macros
FetchAll FetchItem = "ALL"
FetchFast = "FAST"
FetchFull = "FULL"

// Items
FetchBody = "BODY"
FetchBodyStructure = "BODYSTRUCTURE"
FetchEnvelope = "ENVELOPE"
FetchFlags = "FLAGS"
FetchInternalDate = "INTERNALDATE"
FetchRFC822 = "RFC822"
FetchRFC822Header = "RFC822.HEADER"
FetchRFC822Size = "RFC822.SIZE"
FetchRFC822Text = "RFC822.TEXT"
FetchUid = "UID"
)

// Expand expands the item if it's a macro.
func (item FetchItem) Expand() []FetchItem {
switch item {
case FetchAll:
return []FetchItem{FetchFlags, FetchInternalDate, FetchRFC822Size, FetchEnvelope}
case FetchFast:
return []FetchItem{FetchFlags, FetchInternalDate, FetchRFC822Size}
case FetchFull:
return []FetchItem{FetchFlags, FetchInternalDate, FetchRFC822Size, FetchEnvelope, FetchBody}
default:
return []FetchItem{item}
}
}

// FlagsOp is an operation that will be applied on message flags.
type FlagsOp string

@@ -17,9 +68,36 @@ const (
RemoveFlags = "-FLAGS"
)

// SilentOp can be appended to a FlagsOp to prevent the operation from
// silentOp can be appended to a FlagsOp to prevent the operation from
// triggering unilateral message updates.
const SilentOp = ".SILENT"
const silentOp = ".SILENT"

// A StoreItem is a message data item that can be updated.
type StoreItem string

// FormatFlagsOp returns the StoreItem that executes the flags operation op.
func FormatFlagsOp(op FlagsOp, silent bool) StoreItem {
s := string(op)
if silent {
s += silentOp
}
return StoreItem(s)
}

// ParseFlagsOp parses a flags operation from StoreItem.
func ParseFlagsOp(item StoreItem) (op FlagsOp, silent bool, err error) {
itemStr := string(item)
silent = strings.HasSuffix(itemStr, silentOp)
if silent {
itemStr = strings.TrimSuffix(itemStr, silentOp)
}
op = FlagsOp(itemStr)

if op != SetFlags && op != AddFlags && op != RemoveFlags {
err = errors.New("Unsupported STORE operation")
}
return
}

// CharsetReader, if non-nil, defines a function to generate charset-conversion
// readers, converting from the provided charset into UTF-8. Charsets are always


+ 44
- 40
vendor/github.com/emersion/go-imap/mailbox.go View File

@@ -2,6 +2,7 @@ package imap

import (
"errors"
"fmt"
"strings"
"sync"

@@ -53,22 +54,36 @@ func (info *MailboxInfo) Parse(fields []interface{}) error {
return errors.New("Mailbox info needs at least 3 fields")
}

info.Attributes, _ = ParseStringList(fields[0])
var err error
if info.Attributes, err = ParseStringList(fields[0]); err != nil {
return err
}

info.Delimiter, _ = fields[1].(string)
var ok bool
if info.Delimiter, ok = fields[1].(string); !ok {
return errors.New("Mailbox delimiter must be a string")
}

name, _ := fields[2].(string)
info.Name, _ = utf7.Decoder.String(name)
info.Name = CanonicalMailboxName(info.Name)
if name, err := ParseString(fields[2]); err != nil {
return err
} else if name, err := utf7.Encoding.NewDecoder().String(name); err != nil {
return err
} else {
info.Name = CanonicalMailboxName(name)
}

return nil
}

// Format mailbox info to fields.
func (info *MailboxInfo) Format() []interface{} {
name, _ := utf7.Encoder.String(info.Name)
name, _ := utf7.Encoding.NewEncoder().String(info.Name)
attrs := make([]interface{}, len(info.Attributes))
for i, attr := range info.Attributes {
attrs[i] = Atom(attr)
}
// Thunderbird doesn't understand delimiters if not quoted
return []interface{}{FormatStringList(info.Attributes), Quoted(info.Delimiter), name}
return []interface{}{attrs, Quoted(info.Delimiter), name}
}

// TODO: optimize this
@@ -125,19 +140,6 @@ func (info *MailboxInfo) Match(reference, pattern string) bool {
return info.match(name, pattern)
}

// Mailbox status items.
const (
MailboxFlags = "FLAGS"
MailboxPermanentFlags = "PERMANENTFLAGS"

// Defined in RFC 3501 section 6.3.10.
MailboxMessages = "MESSAGES"
MailboxRecent = "RECENT"
MailboxUnseen = "UNSEEN"
MailboxUidNext = "UIDNEXT"
MailboxUidValidity = "UIDVALIDITY"
)

// A mailbox status.
type MailboxStatus struct {
// The mailbox name.
@@ -147,7 +149,7 @@ type MailboxStatus struct {
// The mailbox items that are currently filled in. This map's values
// should not be used directly, they must only be used by libraries
// implementing extensions of the IMAP protocol.
Items map[string]interface{}
Items map[StatusItem]interface{}

// The Items map may be accessed in different goroutines. Protect
// concurrent writes.
@@ -157,6 +159,8 @@ type MailboxStatus struct {
Flags []string
// The mailbox permanent flags.
PermanentFlags []string
// The sequence number of the first unseen message in the mailbox.
UnseenSeqNum uint32

// The number of messages in this mailbox.
Messages uint32
@@ -172,10 +176,10 @@ type MailboxStatus struct {
}

// Create a new mailbox status that will contain the specified items.
func NewMailboxStatus(name string, items []string) *MailboxStatus {
func NewMailboxStatus(name string, items []StatusItem) *MailboxStatus {
status := &MailboxStatus{
Name: name,
Items: make(map[string]interface{}),
Items: make(map[StatusItem]interface{}),
}

for _, k := range items {
@@ -186,30 +190,30 @@ func NewMailboxStatus(name string, items []string) *MailboxStatus {
}

func (status *MailboxStatus) Parse(fields []interface{}) error {
status.Items = make(map[string]interface{})
status.Items = make(map[StatusItem]interface{})

var k string
var k StatusItem
for i, f := range fields {
if i%2 == 0 {
var ok bool
if k, ok = f.(string); !ok {
return errors.New("Key is not a string")
if kstr, ok := f.(string); !ok {
return fmt.Errorf("cannot parse mailbox status: key is not a string, but a %T", f)
} else {
k = StatusItem(strings.ToUpper(kstr))
}
k = strings.ToUpper(k)
} else {
status.Items[k] = nil

var err error
switch k {
case MailboxMessages:
case StatusMessages:
status.Messages, err = ParseNumber(f)
case MailboxRecent:
case StatusRecent:
status.Recent, err = ParseNumber(f)
case MailboxUnseen:
case StatusUnseen:
status.Unseen, err = ParseNumber(f)
case MailboxUidNext:
case StatusUidNext:
status.UidNext, err = ParseNumber(f)
case MailboxUidValidity:
case StatusUidValidity:
status.UidValidity, err = ParseNumber(f)
default:
status.Items[k] = f
@@ -228,19 +232,19 @@ func (status *MailboxStatus) Format() []interface{} {
var fields []interface{}
for k, v := range status.Items {
switch k {
case MailboxMessages:
case StatusMessages:
v = status.Messages
case MailboxRecent:
case StatusRecent:
v = status.Recent
case MailboxUnseen:
case StatusUnseen:
v = status.Unseen
case MailboxUidNext:
case StatusUidNext:
v = status.UidNext
case MailboxUidValidity:
case StatusUidValidity:
v = status.UidValidity
}

fields = append(fields, k, v)
fields = append(fields, string(k), v)
}
return fields
}

+ 165
- 132
vendor/github.com/emersion/go-imap/message.go View File

@@ -30,30 +30,13 @@ var flags = []string{
RecentFlag,
}

// Message attributes that can be fetched, defined in RFC 3501 section 6.4.5.
// Attributes that fetches the message contents are defined with
// BodySectionName.
const (
// Non-extensible form of BODYSTRUCTURE.
BodyMsgAttr = "BODY"
// MIME body structure of the message.
BodyStructureMsgAttr = "BODYSTRUCTURE"
// The envelope structure of the message.
EnvelopeMsgAttr = "ENVELOPE"
// The flags that are set for the message.
FlagsMsgAttr = "FLAGS"
// The internal date of the message.
InternalDateMsgAttr = "INTERNALDATE"
// The RFC 822 size of the message.
SizeMsgAttr = "RFC822.SIZE"
// The unique identifier for the message.
UidMsgAttr = "UID"
)
// A PartSpecifier specifies which parts of the MIME entity should be returned.
type PartSpecifier string

// Part specifiers described in RFC 3501 page 55.
const (
// Refers to the entire part, including headers.
EntireSpecifier = ""
EntireSpecifier PartSpecifier = ""
// Refers to the header of the part. Must include the final CRLF delimiting
// the header and the body.
HeaderSpecifier = "HEADER"
@@ -61,7 +44,7 @@ const (
TextSpecifier = "TEXT"
// Refers to the MIME Internet Message Body header. Must include the final
// CRLF delimiting the header and the body.
MimeSpecifier = "MIME"
MIMESpecifier = "MIME"
)

// Returns the canonical form of a flag. Flags are case-insensitive.
@@ -83,9 +66,9 @@ func ParseParamList(fields []interface{}) (map[string]string, error) {

var k string
for i, f := range fields {
p, ok := f.(string)
if !ok {
return nil, errors.New("Parameter list contains a non-string")
p, err := ParseString(f)
if err != nil {
return nil, errors.New("Parameter list contains a non-string: " + err.Error())
}

if i%2 == 0 {
@@ -158,7 +141,7 @@ type Message struct {
// The mailbox items that are currently filled in. This map's values
// should not be used directly, they must only be used by libraries
// implementing extensions of the IMAP protocol.
Items map[string]interface{}
Items map[FetchItem]interface{}
<