diff options
Diffstat (limited to 'vendor/github.com/mattermost/rsc/imap/mail.go')
-rw-r--r-- | vendor/github.com/mattermost/rsc/imap/mail.go | 468 |
1 files changed, 0 insertions, 468 deletions
diff --git a/vendor/github.com/mattermost/rsc/imap/mail.go b/vendor/github.com/mattermost/rsc/imap/mail.go deleted file mode 100644 index 365540f82..000000000 --- a/vendor/github.com/mattermost/rsc/imap/mail.go +++ /dev/null @@ -1,468 +0,0 @@ -package imap - -import ( - "bytes" - "fmt" - "log" - "regexp" - "sort" - "strings" - "time" -) - -type Flags uint32 - -const ( - FlagJunk Flags = 1 << iota - FlagNonJunk - FlagReplied - FlagFlagged - FlagDeleted - FlagDraft - FlagRecent - FlagSeen - FlagNoInferiors - FlagNoSelect - FlagMarked - FlagUnMarked - FlagHasChildren - FlagHasNoChildren - FlagInbox // Gmail extension - FlagAllMail // Gmail extension - FlagDrafts // Gmail extension - FlagSent // Gmail extension - FlagSpam // Gmail extension - FlagStarred // Gmail extension - FlagTrash // Gmail extension - FlagImportant // Gmail extension -) - -var flagNames = []string{ - "Junk", - "NonJunk", - "\\Answered", - "\\Flagged", - "\\Deleted", - "\\Draft", - "\\Recent", - "\\Seen", - "\\NoInferiors", - "\\NoSelect", - "\\Marked", - "\\UnMarked", - "\\HasChildren", - "\\HasNoChildren", - "\\Inbox", - "\\AllMail", - "\\Drafts", - "\\Sent", - "\\Spam", - "\\Starred", - "\\Trash", - "\\Important", -} - -// A Box represents an IMAP mailbox. -type Box struct { - Name string // name of mailbox - Elem string // last element in name - Client *Client - - parent *Box // parent in hierarchy - child []*Box // child boxes - dead bool // box no longer exists - inbox bool // box is inbox - flags Flags // allowed flags - permFlags Flags // client-modifiable permanent flags - readOnly bool // box is read-only - - exists int // number of messages in box (according to server) - maxSeen int // maximum message number seen (for polling) - unseen int // number of first unseen message - validity uint32 // UID validity base number - load bool // if false, don't track full set of messages - firstNum int // 0 means box not loaded - msgByNum []*Msg - msgByUID map[uint64]*Msg -} - -func (c *Client) Boxes() []*Box { - c.data.lock() - defer c.data.unlock() - - box := make([]*Box, len(c.allBox)) - copy(box, c.allBox) - return box -} - -func (c *Client) Box(name string) *Box { - c.data.lock() - defer c.data.unlock() - - return c.boxByName[name] -} - -func (c *Client) Inbox() *Box { - c.data.lock() - defer c.data.unlock() - - return c.inbox -} - -func (c *Client) newBox(name, sep string, inbox bool) *Box { - c.data.mustBeLocked() - if b := c.boxByName[name]; b != nil { - return b - } - - b := &Box{ - Name: name, - Elem: name, - Client: c, - inbox: inbox, - } - if !inbox { - b.parent = c.rootBox - } - if !inbox && sep != "" && name != c.root { - if i := strings.LastIndex(name, sep); i >= 0 { - b.Elem = name[i+len(sep):] - b.parent = c.newBox(name[:i], sep, false) - } - } - c.allBox = append(c.allBox, b) - c.boxByName[name] = b - if b.parent != nil { - b.parent.child = append(b.parent.child, b) - } - return b -} - -// A Msg represents an IMAP message. -type Msg struct { - Box *Box // box containing message - Date time.Time // date - Flags Flags // message flags - Bytes int64 // size in bytes - Lines int64 // number of lines - Hdr *MsgHdr // MIME header - Root MsgPart // top-level message part - GmailID uint64 // Gmail message id - GmailThread uint64 // Gmail thread id - UID uint64 // unique id for this message - - deleted bool - dead bool - num int // message number in box (changes) -} - -// TODO: Return os.Error too - -type byUID []*Msg - -func (x byUID) Len() int { return len(x) } -func (x byUID) Swap(i, j int) { x[i], x[j] = x[j], x[i] } -func (x byUID) Less(i, j int) bool { return x[i].UID < x[j].UID } - -func (b *Box) Msgs() []*Msg { - b.Client.data.lock() - defer b.Client.data.unlock() - - msgs := make([]*Msg, len(b.msgByUID)) - n := 0 - for _, m := range b.msgByUID { - msgs[n] = m - n++ - } - sort.Sort(byUID(msgs)) - return msgs -} - -func (b *Box) newMsg(uid uint64, id int) *Msg { - b.Client.data.mustBeLocked() - if m := b.msgByUID[uid]; m != nil { - return m - } - if b.msgByUID == nil { - b.msgByUID = map[uint64]*Msg{} - } - m := &Msg{ - UID: uid, - Box: b, - num: id, - } - m.Root.Msg = m - if b.load { - if b.firstNum == 0 { - b.firstNum = id - } - if id < b.firstNum { - log.Printf("warning: unexpected id %d < %d", id, b.firstNum) - byNum := make([]*Msg, len(b.msgByNum)+b.firstNum-id) - copy(byNum[b.firstNum-id:], b.msgByNum) - b.msgByNum = byNum - b.firstNum = id - } - if id-b.firstNum < len(b.msgByNum) { - b.msgByNum[id-b.firstNum] = m - } else { - if id-b.firstNum > len(b.msgByNum) { - log.Printf("warning: unexpected id %d > %d", id, b.firstNum+len(b.msgByNum)) - byNum := make([]*Msg, id-b.firstNum) - copy(byNum, b.msgByNum) - b.msgByNum = byNum - } - b.msgByNum = append(b.msgByNum, m) - } - } - b.msgByUID[uid] = m - return m -} - -func (b *Box) Delete(msgs []*Msg) error { - for _, m := range msgs { - if m.Box != b { - return fmt.Errorf("messages not from this box") - } - } - b.Client.io.lock() - defer b.Client.io.unlock() - err := b.Client.deleteList(msgs) - if err == nil { - b.Client.data.lock() - defer b.Client.data.unlock() - for _, m := range msgs { - if m.Flags&FlagDeleted != 0 { - delete(b.msgByUID, m.UID) - } - } - } - return err -} - -func (b *Box) Copy(msgs []*Msg) error { - if len(msgs) == 0 { - return nil - } - src := msgs[0].Box - for _, m := range msgs { - if m.Box != src { - return fmt.Errorf("messages span boxes: %q and %q", src.Name, m.Box.Name) - } - } - b.Client.io.lock() - defer b.Client.io.unlock() - return b.Client.copyList(b, src, msgs) -} - -func (b *Box) Mute(msgs []*Msg) error { - if len(msgs) == 0 { - return nil - } - for _, m := range msgs { - if m.Box != b { - return fmt.Errorf("messages not from this box") - } - } - b.Client.io.lock() - defer b.Client.io.unlock() - return b.Client.muteList(b, msgs) -} - -func (b *Box) Check() error { - b.Client.io.lock() - defer b.Client.io.unlock() - - return b.Client.check(b) -} - -func (m *Msg) Deleted() bool { - // Racy but okay. Can add a lock later if it matters. - return m.Flags&FlagDeleted != 0 -} - -// A Hdr represents a message header. -type MsgHdr struct { - Date string - Subject string - From []Addr - Sender []Addr - ReplyTo []Addr - To []Addr - CC []Addr - BCC []Addr - InReplyTo string - MessageID string - Digest string -} - -// An Addr represents a single, named email address. -// If Name is empty, only the email address is known. -// If Email is empty, the Addr represents an unspecified (but named) group. -type Addr struct { - Name string - Email string -} - -func (a Addr) String() string { - if a.Email == "" { - return a.Name - } - if a.Name == "" { - return a.Email - } - return a.Name + " <" + a.Email + ">" -} - -// A MsgPart represents a single part of a MIME-encoded message. -type MsgPart struct { - Msg *Msg // containing message - Type string - ContentID string - Desc string - Encoding string - Bytes int64 - Lines int64 - Charset string - Name string - Hdr *MsgHdr - ID string - Child []*MsgPart - - raw []byte // raw message - rawHeader []byte // raw RFC-2822 header, for message/rfc822 - rawBody []byte // raw RFC-2822 body, for message/rfc822 - mimeHeader []byte // mime header, for attachments -} - -func (p *MsgPart) newPart() *MsgPart { - p.Msg.Box.Client.data.mustBeLocked() - dot := "." - if p.ID == "" { // no dot at root - dot = "" - } - pp := &MsgPart{ - Msg: p.Msg, - ID: fmt.Sprint(p.ID, dot, 1+len(p.Child)), - } - p.Child = append(p.Child, pp) - return pp -} - -func (p *MsgPart) Text() []byte { - c := p.Msg.Box.Client - var raw []byte - c.data.lock() - if p == &p.Msg.Root { - raw = p.rawBody - c.data.unlock() - if raw == nil { - c.io.lock() - if raw = p.rawBody; raw == nil { - c.fetch(p, "TEXT") - raw = p.rawBody - } - c.io.unlock() - } - } else { - raw = p.raw - c.data.unlock() - if raw == nil { - c.io.lock() - if raw = p.raw; raw == nil { - c.fetch(p, "") - raw = p.raw - } - c.io.unlock() - } - } - return decodeText(raw, p.Encoding, p.Charset, false) -} - -func (p *MsgPart) Raw() []byte { - c := p.Msg.Box.Client - var raw []byte - c.data.lock() - raw = p.rawBody - c.data.unlock() - if raw == nil { - c.io.lock() - if raw = p.rawBody; raw == nil { - c.fetch(p, "") - raw = p.rawBody - } - c.io.unlock() - } - return raw -} - -var sigDash = []byte("\n--\n") -var quote = []byte("\n> ") -var nl = []byte("\n") - -var onwrote = regexp.MustCompile(`\A\s*On .* wrote:\s*\z`) - -func (p *MsgPart) ShortText() []byte { - t := p.Text() - - return shortText(t) -} - -func shortText(t []byte) []byte { - if t == nil { - return nil - } - - // Cut signature. - i := bytes.LastIndex(t, sigDash) - j := bytes.LastIndex(t, quote) - if i > j && bytes.Count(t[i+1:], nl) <= 10 { - t = t[:i+1] - } - - // Cut trailing quoted text. - for { - rest, last := lastLine(t) - trim := bytes.TrimSpace(last) - if len(rest) < len(t) && (len(trim) == 0 || trim[0] == '>') { - t = rest - continue - } - break - } - - // Cut 'On foo.*wrote:' line. - rest, last := lastLine(t) - if onwrote.Match(last) { - t = rest - } - - // Cut trailing blank lines. - for { - rest, last := lastLine(t) - trim := bytes.TrimSpace(last) - if len(rest) < len(t) && len(trim) == 0 { - t = rest - continue - } - break - } - - // Cut signature again. - i = bytes.LastIndex(t, sigDash) - j = bytes.LastIndex(t, quote) - if i > j && bytes.Count(t[i+1:], nl) <= 10 { - t = t[:i+1] - } - - return t -} - -func lastLine(t []byte) (rest, last []byte) { - n := len(t) - if n > 0 && t[n-1] == '\n' { - n-- - } - j := bytes.LastIndex(t[:n], nl) - return t[:j+1], t[j+1:] -} |