gte/pkg/mstore/email.go

214 lines
3.9 KiB
Go
Raw Normal View History

2021-01-26 07:16:53 +01:00
package mstore
import (
2021-01-27 10:07:31 +01:00
"fmt"
2021-01-29 12:29:23 +01:00
"io"
2021-01-29 17:22:07 +01:00
"io/ioutil"
2021-01-29 12:29:23 +01:00
"strings"
2021-01-27 15:01:42 +01:00
"time"
2021-01-27 10:07:31 +01:00
"github.com/emersion/go-imap"
2021-01-26 07:16:53 +01:00
"github.com/emersion/go-imap/client"
2021-01-29 17:22:07 +01:00
"github.com/emersion/go-message/mail"
2021-01-26 07:16:53 +01:00
)
2021-01-29 12:29:23 +01:00
type Body struct {
reader io.Reader
length int
}
func NewBody(msg string) *Body {
return &Body{
reader: strings.NewReader(msg),
length: len([]byte(msg)),
}
}
func (b *Body) Read(p []byte) (int, error) {
return b.reader.Read(p)
}
func (b *Body) Len() int {
return b.length
}
2021-01-29 17:22:07 +01:00
type ImapConfiguration struct {
ImapUrl string
ImapUsername string
ImapPassword string
2021-01-26 07:16:53 +01:00
}
2021-01-29 17:22:07 +01:00
func (esc *ImapConfiguration) Valid() bool {
if esc.ImapUrl == "" {
2021-01-27 10:07:31 +01:00
return false
}
2021-01-29 17:22:07 +01:00
if esc.ImapUsername == "" || esc.ImapPassword == "" {
2021-01-27 10:07:31 +01:00
return false
}
return true
}
2021-01-29 17:22:07 +01:00
type Imap struct {
2021-01-28 09:40:08 +01:00
imap *client.Client
mboxStatus *imap.MailboxStatus
2021-01-27 12:58:43 +01:00
}
2021-01-29 17:22:07 +01:00
func ImapConnect(conf *ImapConfiguration) (*Imap, error) {
imap, err := client.DialTLS(conf.ImapUrl, nil)
2021-01-27 10:07:31 +01:00
if err != nil {
2021-01-29 17:22:07 +01:00
return &Imap{}, err
2021-01-27 10:07:31 +01:00
}
2021-01-29 17:22:07 +01:00
if err := imap.Login(conf.ImapUsername, conf.ImapPassword); err != nil {
return &Imap{}, err
2021-01-27 10:07:31 +01:00
}
2021-01-29 17:22:07 +01:00
return &Imap{
2021-01-27 12:58:43 +01:00
imap: imap,
2021-01-27 10:07:31 +01:00
}, nil
}
2021-01-29 17:22:07 +01:00
func (es *Imap) Disconnect() {
2021-01-27 12:58:43 +01:00
es.imap.Logout()
2021-01-27 10:07:31 +01:00
}
2021-01-29 17:22:07 +01:00
func (es *Imap) Folders() ([]string, error) {
2021-01-27 10:07:31 +01:00
boxes, done := make(chan *imap.MailboxInfo), make(chan error)
go func() {
2021-01-27 12:58:43 +01:00
done <- es.imap.List("", "*", boxes)
2021-01-27 10:07:31 +01:00
}()
2021-01-28 09:40:08 +01:00
folders := []string{}
2021-01-27 10:07:31 +01:00
for b := range boxes {
2021-01-28 09:40:08 +01:00
folders = append(folders, b.Name)
2021-01-27 10:07:31 +01:00
}
if err := <-done; err != nil {
2021-01-28 09:40:08 +01:00
return []string{}, err
2021-01-27 10:07:31 +01:00
}
2021-01-26 07:16:53 +01:00
2021-01-27 10:07:31 +01:00
return folders, nil
2021-01-26 07:16:53 +01:00
}
2021-01-27 12:58:43 +01:00
2021-01-29 17:22:07 +01:00
func (es *Imap) selectFolder(folder string) error {
2021-01-28 09:40:08 +01:00
status, err := es.imap.Select(folder, false)
2021-01-27 12:58:43 +01:00
if err != nil {
2021-01-28 09:40:08 +01:00
return err
2021-01-27 12:58:43 +01:00
}
2021-01-28 09:40:08 +01:00
es.mboxStatus = status
return nil
}
2021-01-29 17:22:07 +01:00
func (es *Imap) Messages(folder string) ([]*Message, error) {
2021-01-29 12:29:23 +01:00
if err := es.selectFolder(folder); err != nil {
return []*Message{}, err
2021-01-28 09:40:08 +01:00
}
2021-01-27 12:58:43 +01:00
2021-01-28 14:43:00 +01:00
if es.mboxStatus.Messages == 0 {
return []*Message{}, nil
}
2021-01-27 12:58:43 +01:00
seqset := new(imap.SeqSet)
2021-01-28 09:40:08 +01:00
seqset.AddRange(uint32(1), es.mboxStatus.Messages)
2021-01-27 12:58:43 +01:00
2021-01-29 17:22:07 +01:00
// Get the whole message body
section := &imap.BodySectionName{}
items := []imap.FetchItem{imap.FetchUid, section.FetchItem()}
2021-01-27 12:58:43 +01:00
imsg, done := make(chan *imap.Message), make(chan error)
go func() {
2021-01-29 17:22:07 +01:00
done <- es.imap.Fetch(seqset, items, imsg)
2021-01-27 12:58:43 +01:00
}()
messages := []*Message{}
for m := range imsg {
2021-01-29 17:22:07 +01:00
r := m.GetBody(section)
if r == nil {
return []*Message{}, fmt.Errorf("server didn't returned message body")
}
// Create a new mail reader
mr, err := mail.CreateReader(r)
if err != nil {
return []*Message{}, err
}
// Print some info about the message
header := mr.Header
subject, err := header.Subject()
if err != nil {
return []*Message{}, err
}
// Process each message's part
body := []byte(``)
for {
p, err := mr.NextPart()
if err == io.EOF {
break
} else if err != nil {
return []*Message{}, err
}
switch p.Header.(type) {
case *mail.InlineHeader:
// This is the message's text (can be plain-text or HTML)
body, _ = ioutil.ReadAll(p.Body)
}
}
2021-01-27 12:58:43 +01:00
messages = append(messages, &Message{
2021-01-28 14:43:00 +01:00
Uid: m.Uid,
2021-01-29 12:29:23 +01:00
Folder: folder,
2021-01-29 17:22:07 +01:00
Subject: subject,
Body: string(body),
2021-01-27 12:58:43 +01:00
})
}
if err := <-done; err != nil {
return []*Message{}, err
}
return messages, nil
}
2021-01-27 15:01:42 +01:00
2021-01-29 17:22:07 +01:00
func (es *Imap) Add(folder, subject, body string) error {
2021-01-29 12:29:23 +01:00
msgStr := fmt.Sprintf(`From: todo <process@erikwinter.nl>
Subject: %s
%s`, subject, body)
msg := NewBody(msgStr)
return es.imap.Append(folder, nil, time.Time{}, imap.Literal(msg))
2021-01-27 15:01:42 +01:00
}
2021-01-28 09:40:08 +01:00
2021-01-29 17:22:07 +01:00
func (es *Imap) Remove(msg *Message) error {
2021-01-29 12:29:23 +01:00
if !msg.Valid() {
return ErrInvalidMessage
2021-01-28 14:43:00 +01:00
}
2021-01-29 12:29:23 +01:00
if err := es.selectFolder(msg.Folder); err != nil {
return err
2021-01-28 09:40:08 +01:00
}
// set deleted flag
seqset := new(imap.SeqSet)
2021-01-29 12:29:23 +01:00
seqset.AddRange(msg.Uid, msg.Uid)
2021-01-28 09:40:08 +01:00
storeItem := imap.FormatFlagsOp(imap.SetFlags, true)
err := es.imap.UidStore(seqset, storeItem, imap.FormatStringList([]string{imap.DeletedFlag}), nil)
if err != nil {
return err
}
// expunge box
if err := es.imap.Expunge(nil); err != nil {
return err
}
return nil
}