c38ddf8d30
This commit introduces the notmuch backend. The backend is conditionally compiled in if the "notmuch" tag is provided. Most of the message types are implemented, with the notable exceptions of DeleteMessages as well as any copy / move / append type. Reason being, that those aren't normally applicable in a notmuch based workflow. Changes v2 --> v3, based on review comments * Use account config for configuration
123 lines
2.4 KiB
Go
123 lines
2.4 KiB
Go
//+build notmuch
|
|
|
|
package notmuch
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
|
|
"git.sr.ht/~sircmpwn/aerc/models"
|
|
"git.sr.ht/~sircmpwn/aerc/worker/lib"
|
|
"github.com/emersion/go-message"
|
|
_ "github.com/emersion/go-message/charset"
|
|
notmuch "github.com/zenhack/go.notmuch"
|
|
)
|
|
|
|
type Message struct {
|
|
uid uint32
|
|
key string
|
|
msg *notmuch.Message
|
|
}
|
|
|
|
// NewReader reads a message into memory and returns an io.Reader for it.
|
|
func (m Message) NewReader() (io.Reader, error) {
|
|
f, err := os.Open(m.msg.Filename())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
b, err := ioutil.ReadAll(f)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return bytes.NewReader(b), nil
|
|
}
|
|
|
|
// MessageInfo populates a models.MessageInfo struct for the message.
|
|
func (m Message) MessageInfo() (*models.MessageInfo, error) {
|
|
return lib.MessageInfo(m)
|
|
}
|
|
|
|
// NewBodyPartReader creates a new io.Reader for the requested body part(s) of
|
|
// the message.
|
|
func (m Message) NewBodyPartReader(requestedParts []int) (io.Reader, error) {
|
|
f, err := os.Open(m.msg.Filename())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer f.Close()
|
|
msg, err := message.Read(f)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("could not read message: %v", err)
|
|
}
|
|
return lib.FetchEntityPartReader(msg, requestedParts)
|
|
}
|
|
|
|
// MarkRead either adds or removes the maildir.FlagSeen flag from the message.
|
|
func (m Message) MarkRead(seen bool) error {
|
|
haveUnread := false
|
|
for _, t := range m.tags() {
|
|
if t == "unread" {
|
|
haveUnread = true
|
|
break
|
|
}
|
|
}
|
|
if (haveUnread && !seen) || (!haveUnread && seen) {
|
|
// we already have the desired state
|
|
return nil
|
|
}
|
|
|
|
if haveUnread {
|
|
err := m.msg.RemoveTag("unread")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
err := m.msg.AddTag("unread")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// tags returns the notmuch tags of a message
|
|
func (m Message) tags() []string {
|
|
ts := m.msg.Tags()
|
|
var tags []string
|
|
var tag *notmuch.Tag
|
|
for ts.Next(&tag) {
|
|
tags = append(tags, tag.Value)
|
|
}
|
|
return tags
|
|
}
|
|
|
|
func (m Message) ModelFlags() ([]models.Flag, error) {
|
|
var flags []models.Flag
|
|
seen := true
|
|
|
|
for _, tag := range m.tags() {
|
|
switch tag {
|
|
case "replied":
|
|
flags = append(flags, models.AnsweredFlag)
|
|
case "flagged":
|
|
flags = append(flags, models.FlaggedFlag)
|
|
case "unread":
|
|
seen = false
|
|
default:
|
|
continue
|
|
}
|
|
}
|
|
if seen {
|
|
flags = append(flags, models.SeenFlag)
|
|
}
|
|
return flags, nil
|
|
}
|
|
|
|
func (m Message) UID() uint32 {
|
|
return m.uid
|
|
}
|