plugins/base: add message URL and Content-Id helpers

This commit is contained in:
Simon Ser 2020-02-25 10:46:55 +01:00
parent c3e323161a
commit 7af7d73700
No known key found for this signature in database
GPG key ID: 0FDE7BE0E88F5E48

View file

@ -4,6 +4,7 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"fmt" "fmt"
"net/url"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -105,6 +106,14 @@ func ensureMailboxSelected(conn *imapclient.Client, mboxName string) error {
type IMAPMessage struct { type IMAPMessage struct {
*imap.Message *imap.Message
Mailbox string
}
func (msg *IMAPMessage) URL() *url.URL {
return &url.URL{
Path: fmt.Sprintf("/message/%v/%v", url.PathEscape(msg.Mailbox), msg.Uid),
}
} }
func (msg *IMAPMessage) TextPartName() string { func (msg *IMAPMessage) TextPartName() string {
@ -144,6 +153,16 @@ func (msg *IMAPMessage) TextPartName() string {
return strings.Join(l, ".") return strings.Join(l, ".")
} }
func newIMAPPartNode(msg *IMAPMessage, path []int, part *imap.BodyStructure) *IMAPPartNode {
filename, _ := part.Filename()
return &IMAPPartNode{
Path: path,
MIMEType: strings.ToLower(part.MIMEType + "/" + part.MIMESubType),
Filename: filename,
Message: msg,
}
}
func (msg *IMAPMessage) Attachments() []IMAPPartNode { func (msg *IMAPMessage) Attachments() []IMAPPartNode {
if msg.BodyStructure == nil { if msg.BodyStructure == nil {
return nil return nil
@ -155,22 +174,33 @@ func (msg *IMAPMessage) Attachments() []IMAPPartNode {
return true return true
} }
filename, _ := part.Filename() attachments = append(attachments, *newIMAPPartNode(msg, path, part))
attachments = append(attachments, IMAPPartNode{
Path: path,
MIMEType: strings.ToLower(part.MIMEType + "/" + part.MIMESubType),
Filename: filename,
})
return true return true
}) })
return attachments return attachments
} }
func (msg *IMAPMessage) PartByID(id string) *IMAPPartNode {
if msg.BodyStructure == nil || id == "" {
return nil
}
var result *IMAPPartNode
msg.BodyStructure.Walk(func(path []int, part *imap.BodyStructure) bool {
if result == nil && part.Id == "<"+id+">" {
result = newIMAPPartNode(msg, path, part)
}
return result == nil
})
return result
}
type IMAPPartNode struct { type IMAPPartNode struct {
Path []int Path []int
MIMEType string MIMEType string
Filename string Filename string
Children []IMAPPartNode Children []IMAPPartNode
Message *IMAPMessage
} }
func (node IMAPPartNode) PathString() string { func (node IMAPPartNode) PathString() string {
@ -182,6 +212,17 @@ func (node IMAPPartNode) PathString() string {
return strings.Join(l, ".") return strings.Join(l, ".")
} }
func (node IMAPPartNode) URL(raw bool) *url.URL {
u := node.Message.URL()
if raw {
u.Path += "/raw"
}
q := u.Query()
q.Set("part", node.PathString())
u.RawQuery = q.Encode()
return u
}
func (node IMAPPartNode) IsText() bool { func (node IMAPPartNode) IsText() bool {
return strings.HasPrefix(strings.ToLower(node.MIMEType), "text/") return strings.HasPrefix(strings.ToLower(node.MIMEType), "text/")
} }
@ -194,7 +235,7 @@ func (node IMAPPartNode) String() string {
} }
} }
func imapPartTree(bs *imap.BodyStructure, path []int) *IMAPPartNode { func imapPartTree(msg *IMAPMessage, bs *imap.BodyStructure, path []int) *IMAPPartNode {
if !strings.EqualFold(bs.MIMEType, "multipart") && len(path) == 0 { if !strings.EqualFold(bs.MIMEType, "multipart") && len(path) == 0 {
path = []int{1} path = []int{1}
} }
@ -206,6 +247,7 @@ func imapPartTree(bs *imap.BodyStructure, path []int) *IMAPPartNode {
MIMEType: strings.ToLower(bs.MIMEType + "/" + bs.MIMESubType), MIMEType: strings.ToLower(bs.MIMEType + "/" + bs.MIMESubType),
Filename: filename, Filename: filename,
Children: make([]IMAPPartNode, len(bs.Parts)), Children: make([]IMAPPartNode, len(bs.Parts)),
Message: msg,
} }
for i, part := range bs.Parts { for i, part := range bs.Parts {
@ -214,7 +256,7 @@ func imapPartTree(bs *imap.BodyStructure, path []int) *IMAPPartNode {
partPath := append([]int(nil), path...) partPath := append([]int(nil), path...)
partPath = append(partPath, num) partPath = append(partPath, num)
node.Children[i] = *imapPartTree(part, partPath) node.Children[i] = *imapPartTree(msg, part, partPath)
} }
return node return node
@ -225,7 +267,7 @@ func (msg *IMAPMessage) PartTree() *IMAPPartNode {
return nil return nil
} }
return imapPartTree(msg.BodyStructure, nil) return imapPartTree(msg, msg.BodyStructure, nil)
} }
func (msg *IMAPMessage) HasFlag(flag string) bool { func (msg *IMAPMessage) HasFlag(flag string) bool {
@ -265,7 +307,7 @@ func listMessages(conn *imapclient.Client, mboxName string, page, messagesPerPag
msgs := make([]IMAPMessage, 0, to-from) msgs := make([]IMAPMessage, 0, to-from)
for msg := range ch { for msg := range ch {
msgs = append(msgs, IMAPMessage{msg}) msgs = append(msgs, IMAPMessage{msg, mboxName})
} }
if err := <-done; err != nil { if err := <-done; err != nil {
@ -350,7 +392,7 @@ func searchMessages(conn *imapclient.Client, mboxName, query string, page, messa
if !ok { if !ok {
continue continue
} }
msgs[i] = IMAPMessage{msg} msgs[i] = IMAPMessage{msg, mboxName}
} }
if err := <-done; err != nil { if err := <-done; err != nil {
@ -416,7 +458,7 @@ func getMessagePart(conn *imapclient.Client, mboxName string, uid uint32, partPa
return nil, nil, fmt.Errorf("failed to create message reader: %v", err) return nil, nil, fmt.Errorf("failed to create message reader: %v", err)
} }
return &IMAPMessage{msg}, part, nil return &IMAPMessage{msg, mboxName}, part, nil
} }
func markMessageAnswered(conn *imapclient.Client, mboxName string, uid uint32) error { func markMessageAnswered(conn *imapclient.Client, mboxName string, uid uint32) error {