Update vendor/

This commit is contained in:
2018-06-28 01:09:56 +01:00
parent 3e5ab5bb0a
commit 21c6e571d8
108 changed files with 121110 additions and 1144 deletions

View File

@@ -14,59 +14,45 @@ type Authenticate struct {
Writer *imap.Writer
}
func (r *Authenticate) HandleFrom(hdlr imap.RespHandler) (err error) {
w := r.Writer
func (r *Authenticate) writeLine(l string) error {
if _, err := r.Writer.Write([]byte(l + "\r\n")); err != nil {
return err
}
return r.Writer.Flush()
}
// Cancel auth if an error occurs
defer (func() {
if err != nil {
w.Write([]byte("*\r\n"))
w.Flush()
}
})()
func (r *Authenticate) cancel() error {
return r.writeLine("*")
}
for h := range hdlr {
cont, ok := h.Resp.(*imap.ContinuationResp)
if !ok {
h.Reject()
continue
}
h.Accept()
// Empty challenge, send initial response as stated in RFC 2222 section 5.1
if cont.Info == "" && r.InitialResponse != nil {
encoded := base64.StdEncoding.EncodeToString(r.InitialResponse)
if _, err = w.Write([]byte(encoded + "\r\n")); err != nil {
return
}
if err = w.Flush(); err != nil {
return
}
r.InitialResponse = nil
continue
}
var challenge []byte
challenge, err = base64.StdEncoding.DecodeString(cont.Info)
if err != nil {
return
}
var res []byte
res, err = r.Mechanism.Next(challenge)
if err != nil {
return
}
encoded := base64.StdEncoding.EncodeToString(res)
if _, err = w.Write([]byte(encoded + "\r\n")); err != nil {
return
}
if err = w.Flush(); err != nil {
return
}
func (r *Authenticate) Handle(resp imap.Resp) error {
cont, ok := resp.(*imap.ContinuationReq)
if !ok {
return ErrUnhandled
}
return
// Empty challenge, send initial response as stated in RFC 2222 section 5.1
if cont.Info == "" && r.InitialResponse != nil {
encoded := base64.StdEncoding.EncodeToString(r.InitialResponse)
if err := r.writeLine(encoded); err != nil {
return err
}
r.InitialResponse = nil
return nil
}
challenge, err := base64.StdEncoding.DecodeString(cont.Info)
if err != nil {
r.cancel()
return err
}
reply, err := r.Mechanism.Next(challenge)
if err != nil {
r.cancel()
return err
}
encoded := base64.StdEncoding.EncodeToString(reply)
return r.writeLine(encoded)
}

View File

@@ -10,30 +10,11 @@ type Capability struct {
Caps []string
}
func (r *Capability) HandleFrom(hdlr imap.RespHandler) (err error) {
for h := range hdlr {
caps, ok := h.AcceptNamedResp(imap.Capability)
if !ok {
continue
}
r.Caps = make([]string, len(caps))
for i, c := range caps {
r.Caps[i], _ = c.(string)
}
return
}
return
}
func (r *Capability) WriteTo(w *imap.Writer) error {
fields := []interface{}{imap.Capability}
fields := []interface{}{"CAPABILITY"}
for _, cap := range r.Caps {
fields = append(fields, cap)
}
res := &imap.Resp{Fields: fields}
return res.WriteTo(w)
return imap.NewUntaggedResp(fields).WriteTo(w)
}

View File

@@ -4,39 +4,37 @@ import (
"github.com/emersion/go-imap"
)
const expungeName = "EXPUNGE"
// An EXPUNGE response.
// See RFC 3501 section 7.4.1
type Expunge struct {
SeqNums chan uint32
}
func (r *Expunge) HandleFrom(hdlr imap.RespHandler) error {
defer close(r.SeqNums)
for h := range hdlr {
res, ok := h.Resp.(*imap.Resp)
if !ok || len(res.Fields) < 3 {
h.Reject()
continue
}
if name, ok := res.Fields[1].(string); !ok || name != imap.Expunge {
h.Reject()
continue
}
h.Accept()
seqNum, _ := imap.ParseNumber(res.Fields[0])
r.SeqNums <- seqNum
func (r *Expunge) Handle(resp imap.Resp) error {
name, fields, ok := imap.ParseNamedResp(resp)
if !ok || name != expungeName {
return ErrUnhandled
}
if len(fields) == 0 {
return errNotEnoughFields
}
seqNum, err := imap.ParseNumber(fields[0])
if err != nil {
return err
}
r.SeqNums <- seqNum
return nil
}
func (r *Expunge) WriteTo(w *imap.Writer) error {
for seqNum := range r.SeqNums {
res := imap.NewUntaggedResp([]interface{}{seqNum, imap.Expunge})
if err := res.WriteTo(w); err != nil {
resp := imap.NewUntaggedResp([]interface{}{seqNum, expungeName})
if err := resp.WriteTo(w); err != nil {
return err
}
}

View File

@@ -4,49 +4,41 @@ import (
"github.com/emersion/go-imap"
)
const fetchName = "FETCH"
// A FETCH response.
// See RFC 3501 section 7.4.2
type Fetch struct {
Messages chan *imap.Message
}
func (r *Fetch) HandleFrom(hdlr imap.RespHandler) error {
defer close(r.Messages)
for h := range hdlr {
res, ok := h.Resp.(*imap.Resp)
if !ok || len(res.Fields) < 3 {
h.Reject()
continue
}
if name, ok := res.Fields[1].(string); !ok || name != imap.Fetch {
h.Reject()
continue
}
h.Accept()
seqNum, _ := imap.ParseNumber(res.Fields[0])
fields, _ := res.Fields[2].([]interface{})
msg := &imap.Message{
SeqNum: seqNum,
}
if err := msg.Parse(fields); err != nil {
return err
}
r.Messages <- msg
func (r *Fetch) Handle(resp imap.Resp) error {
name, fields, ok := imap.ParseNamedResp(resp)
if !ok || name != fetchName {
return ErrUnhandled
} else if len(fields) < 1 {
return errNotEnoughFields
}
seqNum, err := imap.ParseNumber(fields[0])
if err != nil {
return err
}
msgFields, _ := fields[1].([]interface{})
msg := &imap.Message{SeqNum: seqNum}
if err := msg.Parse(msgFields); err != nil {
return err
}
r.Messages <- msg
return nil
}
func (r *Fetch) WriteTo(w *imap.Writer) error {
for msg := range r.Messages {
res := imap.NewUntaggedResp([]interface{}{msg.SeqNum, imap.Fetch, msg.Format()})
if err := res.WriteTo(w); err != nil {
resp := imap.NewUntaggedResp([]interface{}{msg.SeqNum, fetchName, msg.Format()})
if err := resp.WriteTo(w); err != nil {
return err
}
}

View File

@@ -4,6 +4,11 @@ import (
"github.com/emersion/go-imap"
)
const (
listName = "LIST"
lsubName = "LSUB"
)
// A LIST response.
// If Subscribed is set to true, LSUB will be used instead.
// See RFC 3501 section 7.2.2
@@ -14,43 +19,36 @@ type List struct {
func (r *List) Name() string {
if r.Subscribed {
return imap.Lsub
return lsubName
} else {
return imap.List
return listName
}
}
func (r *List) HandleFrom(hdlr imap.RespHandler) error {
defer close(r.Mailboxes)
name := r.Name()
for h := range hdlr {
fields, ok := h.AcceptNamedResp(name)
if !ok {
continue
}
mbox := &imap.MailboxInfo{}
if err := mbox.Parse(fields); err != nil {
return err
}
r.Mailboxes <- mbox
func (r *List) Handle(resp imap.Resp) error {
name, fields, ok := imap.ParseNamedResp(resp)
if !ok || name != r.Name() {
return ErrUnhandled
}
mbox := &imap.MailboxInfo{}
if err := mbox.Parse(fields); err != nil {
return err
}
r.Mailboxes <- mbox
return nil
}
func (r *List) WriteTo(w *imap.Writer) error {
name := r.Name()
respName := r.Name()
for mbox := range r.Mailboxes {
fields := []interface{}{name}
fields := []interface{}{respName}
fields = append(fields, mbox.Format()...)
res := imap.NewUntaggedResp(fields)
if err := res.WriteTo(w); err != nil {
resp := imap.NewUntaggedResp(fields)
if err := resp.WriteTo(w); err != nil {
return err
}
}

View File

@@ -1,2 +1,28 @@
// IMAP responses defined in RFC 3501.
package responses
import (
"errors"
"github.com/emersion/go-imap"
)
// ErrUnhandled is used when a response hasn't been handled.
var ErrUnhandled = errors.New("imap: unhandled response")
var errNotEnoughFields = errors.New("imap: not enough fields in response")
// Handler handles responses.
type Handler interface {
// Handle processes a response. If the response cannot be processed,
// ErrUnhandledResp must be returned.
Handle(resp imap.Resp) error
}
// HandlerFunc is a function that handles responses.
type HandlerFunc func(resp imap.Resp) error
// Handle implements Handler.
func (f HandlerFunc) Handle(resp imap.Resp) error {
return f(resp)
}

View File

@@ -4,34 +4,38 @@ import (
"github.com/emersion/go-imap"
)
const searchName = "SEARCH"
// A SEARCH response.
// See RFC 3501 section 7.2.5
type Search struct {
Ids []uint32
}
func (r *Search) HandleFrom(hdlr imap.RespHandler) (err error) {
for h := range hdlr {
fields, ok := h.AcceptNamedResp(imap.Search)
if !ok {
continue
}
func (r *Search) Handle(resp imap.Resp) error {
name, fields, ok := imap.ParseNamedResp(resp)
if !ok || name != searchName {
return ErrUnhandled
}
for _, f := range fields {
id, _ := imap.ParseNumber(f)
r.Ids = append(r.Ids, id)
r.Ids = make([]uint32, len(fields))
for i, f := range fields {
if id, err := imap.ParseNumber(f); err != nil {
return err
} else {
r.Ids[i] = id
}
}
return
return nil
}
func (r *Search) WriteTo(w *imap.Writer) (err error) {
fields := []interface{}{imap.Search}
fields := []interface{}{searchName}
for _, id := range r.Ids {
fields = append(fields, id)
}
res := imap.NewUntaggedResp(fields)
return res.WriteTo(w)
resp := imap.NewUntaggedResp(fields)
return resp.WriteTo(w)
}

View File

@@ -11,135 +11,132 @@ type Select struct {
Mailbox *imap.MailboxStatus
}
func (r *Select) HandleFrom(hdlr imap.RespHandler) (err error) {
func (r *Select) Handle(resp imap.Resp) error {
if r.Mailbox == nil {
r.Mailbox = &imap.MailboxStatus{}
r.Mailbox = &imap.MailboxStatus{Items: make(map[imap.StatusItem]interface{})}
}
mbox := r.Mailbox
mbox.Items = make(map[string]interface{})
for h := range hdlr {
switch res := h.Resp.(type) {
case *imap.Resp:
fields, ok := h.AcceptNamedResp(imap.MailboxFlags)
if !ok {
break
}
switch resp := resp.(type) {
case *imap.DataResp:
name, fields, ok := imap.ParseNamedResp(resp)
if !ok || name != "FLAGS" {
return ErrUnhandled
} else if len(fields) < 1 {
return errNotEnoughFields
}
flags, _ := fields[0].([]interface{})
mbox.Flags, _ = imap.ParseStringList(flags)
flags, _ := fields[0].([]interface{})
mbox.Flags, _ = imap.ParseStringList(flags)
case *imap.StatusResp:
if len(resp.Arguments) < 1 {
return ErrUnhandled
}
var item imap.StatusItem
switch resp.Code {
case "UNSEEN":
mbox.UnseenSeqNum, _ = imap.ParseNumber(resp.Arguments[0])
case "PERMANENTFLAGS":
flags, _ := resp.Arguments[0].([]interface{})
mbox.PermanentFlags, _ = imap.ParseStringList(flags)
case "UIDNEXT":
mbox.UidNext, _ = imap.ParseNumber(resp.Arguments[0])
item = imap.StatusUidNext
case "UIDVALIDITY":
mbox.UidValidity, _ = imap.ParseNumber(resp.Arguments[0])
item = imap.StatusUidValidity
default:
return ErrUnhandled
}
if item != "" {
mbox.ItemsLocker.Lock()
mbox.Items[imap.MailboxFlags] = nil
mbox.Items[item] = nil
mbox.ItemsLocker.Unlock()
case *imap.StatusResp:
if len(res.Arguments) < 1 {
h.Accepts <- false
break
}
}
default:
return ErrUnhandled
}
return nil
}
accepted := true
switch res.Code {
case imap.MailboxUnseen:
mbox.Unseen, _ = imap.ParseNumber(res.Arguments[0])
mbox.ItemsLocker.Lock()
mbox.Items[imap.MailboxUnseen] = nil
mbox.ItemsLocker.Unlock()
case imap.MailboxPermanentFlags:
flags, _ := res.Arguments[0].([]interface{})
mbox.PermanentFlags, _ = imap.ParseStringList(flags)
mbox.ItemsLocker.Lock()
mbox.Items[imap.MailboxPermanentFlags] = nil
mbox.ItemsLocker.Unlock()
case imap.MailboxUidNext:
mbox.UidNext, _ = imap.ParseNumber(res.Arguments[0])
mbox.ItemsLocker.Lock()
mbox.Items[imap.MailboxUidNext] = nil
mbox.ItemsLocker.Unlock()
case imap.MailboxUidValidity:
mbox.UidValidity, _ = imap.ParseNumber(res.Arguments[0])
mbox.ItemsLocker.Lock()
mbox.Items[imap.MailboxUidValidity] = nil
mbox.ItemsLocker.Unlock()
default:
accepted = false
}
h.Accepts <- accepted
func (r *Select) WriteTo(w *imap.Writer) error {
mbox := r.Mailbox
if mbox.Flags != nil {
flags := make([]interface{}, len(mbox.Flags))
for i, f := range mbox.Flags {
flags[i] = imap.Atom(f)
}
res := imap.NewUntaggedResp([]interface{}{"FLAGS", flags})
if err := res.WriteTo(w); err != nil {
return err
}
}
return
}
if mbox.PermanentFlags != nil {
flags := make([]interface{}, len(mbox.PermanentFlags))
for i, f := range mbox.PermanentFlags {
flags[i] = imap.Atom(f)
}
statusRes := &imap.StatusResp{
Type: imap.StatusRespOk,
Code: imap.CodePermanentFlags,
Arguments: []interface{}{flags},
Info: "Flags permitted.",
}
if err := statusRes.WriteTo(w); err != nil {
return err
}
}
func (r *Select) WriteTo(w *imap.Writer) (err error) {
status := r.Mailbox
if mbox.UnseenSeqNum > 0 {
statusRes := &imap.StatusResp{
Type: imap.StatusRespOk,
Code: imap.CodeUnseen,
Arguments: []interface{}{mbox.UnseenSeqNum},
Info: fmt.Sprintf("Message %d is first unseen", mbox.UnseenSeqNum),
}
if err := statusRes.WriteTo(w); err != nil {
return err
}
}
for k := range r.Mailbox.Items {
switch k {
case imap.MailboxFlags:
flags := make([]interface{}, len(status.Flags))
for i, f := range status.Flags {
flags[i] = f
case imap.StatusMessages:
res := imap.NewUntaggedResp([]interface{}{mbox.Messages, "EXISTS"})
if err := res.WriteTo(w); err != nil {
return err
}
res := imap.NewUntaggedResp([]interface{}{"FLAGS", flags})
if err = res.WriteTo(w); err != nil {
return
}
case imap.MailboxPermanentFlags:
flags := make([]interface{}, len(status.PermanentFlags))
for i, f := range status.PermanentFlags {
flags[i] = f
case imap.StatusRecent:
res := imap.NewUntaggedResp([]interface{}{mbox.Recent, "RECENT"})
if err := res.WriteTo(w); err != nil {
return err
}
case imap.StatusUidNext:
statusRes := &imap.StatusResp{
Type: imap.StatusOk,
Code: imap.CodePermanentFlags,
Arguments: []interface{}{flags},
Info: "Flags permitted.",
}
if err = statusRes.WriteTo(w); err != nil {
return
}
case imap.MailboxMessages:
res := imap.NewUntaggedResp([]interface{}{status.Messages, "EXISTS"})
if err = res.WriteTo(w); err != nil {
return
}
case imap.MailboxRecent:
res := imap.NewUntaggedResp([]interface{}{status.Recent, "RECENT"})
if err = res.WriteTo(w); err != nil {
return
}
case imap.MailboxUnseen:
statusRes := &imap.StatusResp{
Type: imap.StatusOk,
Code: imap.CodeUnseen,
Arguments: []interface{}{status.Unseen},
Info: fmt.Sprintf("Message %d is first unseen", status.Unseen),
}
if err = statusRes.WriteTo(w); err != nil {
return
}
case imap.MailboxUidNext:
statusRes := &imap.StatusResp{
Type: imap.StatusOk,
Type: imap.StatusRespOk,
Code: imap.CodeUidNext,
Arguments: []interface{}{status.UidNext},
Arguments: []interface{}{mbox.UidNext},
Info: "Predicted next UID",
}
if err = statusRes.WriteTo(w); err != nil {
return
if err := statusRes.WriteTo(w); err != nil {
return err
}
case imap.MailboxUidValidity:
case imap.StatusUidValidity:
statusRes := &imap.StatusResp{
Type: imap.StatusOk,
Type: imap.StatusRespOk,
Code: imap.CodeUidValidity,
Arguments: []interface{}{status.UidValidity},
Arguments: []interface{}{mbox.UidValidity},
Info: "UIDs valid",
}
if err = statusRes.WriteTo(w); err != nil {
return
if err := statusRes.WriteTo(w); err != nil {
return err
}
}
}
return
return nil
}

View File

@@ -7,57 +7,47 @@ import (
"github.com/emersion/go-imap/utf7"
)
const statusName = "STATUS"
// A STATUS response.
// See RFC 3501 section 7.2.4
type Status struct {
Mailbox *imap.MailboxStatus
}
func (r *Status) HandleFrom(hdlr imap.RespHandler) error {
func (r *Status) Handle(resp imap.Resp) error {
if r.Mailbox == nil {
r.Mailbox = &imap.MailboxStatus{}
}
mbox := r.Mailbox
mbox.Items = nil
for h := range hdlr {
fields, ok := h.AcceptNamedResp(imap.Status)
if !ok {
continue
}
if len(fields) < 2 {
return errors.New("STATUS response expects two fields")
}
name, ok := fields[0].(string)
if !ok {
return errors.New("STATUS response expects a string as first argument")
}
mbox.Name, _ = utf7.Decoder.String(name)
mbox.Name = imap.CanonicalMailboxName(mbox.Name)
var items []interface{}
if items, ok = fields[1].([]interface{}); !ok {
return errors.New("STATUS response expects a list as second argument")
}
if err := mbox.Parse(items); err != nil {
return err
}
name, fields, ok := imap.ParseNamedResp(resp)
if !ok || name != statusName {
return ErrUnhandled
} else if len(fields) < 2 {
return errNotEnoughFields
}
return nil
if name, err := imap.ParseString(fields[0]); err != nil {
return err
} else if name, err := utf7.Encoding.NewDecoder().String(name); err != nil {
return err
} else {
mbox.Name = imap.CanonicalMailboxName(name)
}
var items []interface{}
if items, ok = fields[1].([]interface{}); !ok {
return errors.New("STATUS response expects a list as second argument")
}
mbox.Items = nil
return mbox.Parse(items)
}
func (r *Status) WriteTo(w *imap.Writer) error {
mbox := r.Mailbox
fields := []interface{}{imap.Status, mbox.Name, mbox.Format()}
res := imap.NewUntaggedResp(fields)
if err := res.WriteTo(w); err != nil {
return err
}
return nil
name, _ := utf7.Encoding.NewEncoder().String(mbox.Name)
fields := []interface{}{statusName, name, mbox.Format()}
return imap.NewUntaggedResp(fields).WriteTo(w)
}