1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
|
package responses
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
SeqSet *imap.SeqSet
Uid bool
}
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
}
if r.Uid && msg.Uid == 0 {
// we requested UIDs and got a message without one --> unilateral update --> ignore
return ErrUnhandled
}
var num uint32
if r.Uid {
num = msg.Uid
} else {
num = seqNum
}
// Check whether we obtained a result we requested with our SeqSet
// If the result is not contained in our SeqSet we have to handle an additional special case:
// In case we requested UIDs with a dynamic sequence (i.e. * or n:*) and the maximum UID of the mailbox
// is less then our n, the server will supply us with the max UID (cf. RFC 3501 §6.4.8 and §9 `seq-range`).
// Thus, such a result is correct and has to be returned by us.
if !r.SeqSet.Contains(num) && (!r.Uid || !r.SeqSet.Dynamic()) {
return ErrUnhandled
}
r.Messages <- msg
return nil
}
func (r *Fetch) WriteTo(w *imap.Writer) error {
var err error
for msg := range r.Messages {
resp := imap.NewUntaggedResp([]interface{}{msg.SeqNum, imap.RawString(fetchName), msg.Format()})
if err == nil {
err = resp.WriteTo(w)
}
}
return err
}
|