aboutsummaryrefslogtreecommitdiffstats
path: root/lib/templates/data.go
diff options
context:
space:
mode:
authorRobin Jarry <robin@jarry.cc>2022-12-20 18:37:16 +0100
committerRobin Jarry <robin@jarry.cc>2023-01-04 22:57:31 +0100
commitd758441fe0c4da6bc3486d0643436ad7ac290a56 (patch)
tree8d8fe289a4612c2dd5b8043028cf5a813502b0f6 /lib/templates/data.go
parentae675b491d2b55a06588e8ab4ce8205aaae796c8 (diff)
downloadaerc-d758441fe0c4da6bc3486d0643436ad7ac290a56.tar.gz
templates: add more fields and functions
Add functions and fields in preparation for more than only message templates. The idea is to reuse the same symbols for the message list format and other parts of the UI. Update the man page accordingly. Signed-off-by: Robin Jarry <robin@jarry.cc> Acked-by: Tim Culverhouse <tim@timculverhouse.com>
Diffstat (limited to 'lib/templates/data.go')
-rw-r--r--lib/templates/data.go321
1 files changed, 304 insertions, 17 deletions
diff --git a/lib/templates/data.go b/lib/templates/data.go
index 8637aa7f..dab698d5 100644
--- a/lib/templates/data.go
+++ b/lib/templates/data.go
@@ -1,59 +1,289 @@
package templates
import (
+ "fmt"
+ "strings"
"time"
"git.sr.ht/~rjarry/aerc/models"
+ sortthread "github.com/emersion/go-imap-sortthread"
"github.com/emersion/go-message/mail"
)
type TemplateData struct {
- msg *mail.Header
- // Only available when replying with a quote
+ // only available when composing/replying/forwarding
+ headers *mail.Header
+ // only available when replying with a quote
parent *models.OriginalMail
+ // only available for the message list
+ info *models.MessageInfo
+ marked bool
+ msgNum int
+
+ // account config
+ myAddresses map[string]bool
+ account string
+ folder string // selected folder name
+
+ // ui config
+ timeFmt string
+ thisDayTimeFmt string
+ thisWeekTimeFmt string
+ thisYearTimeFmt string
+ iconAttachment string
}
func NewTemplateData(
- msg *mail.Header, parent *models.OriginalMail,
+ from *mail.Address,
+ aliases []*mail.Address,
+ account string,
+ folder string,
+ timeFmt string,
+ thisDayTimeFmt string,
+ thisWeekTimeFmt string,
+ thisYearTimeFmt string,
+ iconAttachment string,
) *TemplateData {
+ myAddresses := map[string]bool{from.Address: true}
+ for _, addr := range aliases {
+ myAddresses[addr.Address] = true
+ }
return &TemplateData{
- msg: msg,
- parent: parent,
+ myAddresses: myAddresses,
+ account: account,
+ folder: folder,
+ timeFmt: timeFmt,
+ thisDayTimeFmt: thisDayTimeFmt,
+ thisWeekTimeFmt: thisWeekTimeFmt,
+ thisYearTimeFmt: thisYearTimeFmt,
+ iconAttachment: iconAttachment,
}
}
+// only used for compose/reply/forward
+func (d *TemplateData) SetHeaders(h *mail.Header, o *models.OriginalMail) {
+ d.headers = h
+ d.parent = o
+}
+
+// only used for message list templates
+func (d *TemplateData) SetInfo(info *models.MessageInfo, num int, marked bool) {
+ d.info = info
+ d.msgNum = num
+ d.marked = marked
+}
+
+func (d *TemplateData) Account() string {
+ return d.account
+}
+
+func (d *TemplateData) Folder() string {
+ return d.folder
+}
+
func (d *TemplateData) To() []*mail.Address {
- to, _ := d.msg.AddressList("to")
+ var to []*mail.Address
+ switch {
+ case d.info != nil && d.info.Envelope != nil:
+ to = d.info.Envelope.To
+ case d.headers != nil:
+ to, _ = d.headers.AddressList("to")
+ }
return to
}
func (d *TemplateData) Cc() []*mail.Address {
- to, _ := d.msg.AddressList("cc")
- return to
+ var cc []*mail.Address
+ switch {
+ case d.info != nil && d.info.Envelope != nil:
+ cc = d.info.Envelope.Cc
+ case d.headers != nil:
+ cc, _ = d.headers.AddressList("cc")
+ }
+ return cc
}
func (d *TemplateData) Bcc() []*mail.Address {
- to, _ := d.msg.AddressList("bcc")
- return to
+ var bcc []*mail.Address
+ switch {
+ case d.info != nil && d.info.Envelope != nil:
+ bcc = d.info.Envelope.Bcc
+ case d.headers != nil:
+ bcc, _ = d.headers.AddressList("bcc")
+ }
+ return bcc
}
func (d *TemplateData) From() []*mail.Address {
- to, _ := d.msg.AddressList("from")
- return to
+ var from []*mail.Address
+ switch {
+ case d.info != nil && d.info.Envelope != nil:
+ from = d.info.Envelope.From
+ case d.headers != nil:
+ from, _ = d.headers.AddressList("from")
+ }
+ return from
+}
+
+func (d *TemplateData) Peer() []*mail.Address {
+ var from, to []*mail.Address
+ switch {
+ case d.info != nil && d.info.Envelope != nil:
+ from = d.info.Envelope.From
+ to = d.info.Envelope.To
+ case d.headers != nil:
+ from, _ = d.headers.AddressList("from")
+ to, _ = d.headers.AddressList("to")
+ }
+ for _, addr := range from {
+ if d.myAddresses[addr.Address] {
+ return to
+ }
+ }
+ return from
+}
+
+func (d *TemplateData) ReplyTo() []*mail.Address {
+ var replyTo []*mail.Address
+ switch {
+ case d.info != nil && d.info.Envelope != nil:
+ replyTo = d.info.Envelope.ReplyTo
+ case d.headers != nil:
+ replyTo, _ = d.headers.AddressList("reply-to")
+ }
+ return replyTo
}
func (d *TemplateData) Date() time.Time {
- return time.Now()
+ var date time.Time
+ switch {
+ case d.info != nil && d.info.Envelope != nil:
+ date = d.info.Envelope.Date
+ case d.info != nil:
+ date = d.info.InternalDate
+ default:
+ date = time.Now()
+ }
+ return date
}
-func (d *TemplateData) Subject() string {
- subject, err := d.msg.Text("subject")
+func (d *TemplateData) DateAutoFormat(date time.Time) string {
+ if date.IsZero() {
+ return ""
+ }
+ year := date.Year()
+ day := date.YearDay()
+ now := time.Now()
+ thisYear := now.Year()
+ thisDay := now.YearDay()
+ fmt := d.timeFmt
+ if year == thisYear {
+ switch {
+ case day == thisDay && d.thisDayTimeFmt != "":
+ fmt = d.thisDayTimeFmt
+ case day > thisDay-7 && d.thisWeekTimeFmt != "":
+ fmt = d.thisDayTimeFmt
+ case d.thisYearTimeFmt != "":
+ fmt = d.thisYearTimeFmt
+ }
+ }
+ return date.Format(fmt)
+}
+
+func (d *TemplateData) Header(name string) string {
+ var h *mail.Header
+ switch {
+ case d.headers != nil:
+ h = d.headers
+ case d.info != nil && d.info.RFC822Headers != nil:
+ h = d.info.RFC822Headers
+ default:
+ return ""
+ }
+ text, err := h.Text(name)
if err != nil {
- subject = d.msg.Get("subject")
+ text = h.Get(name)
+ }
+ return text
+}
+
+func (d *TemplateData) Subject() string {
+ var subject string
+ switch {
+ case d.info != nil && d.info.Envelope != nil:
+ subject = d.info.Envelope.Subject
+ case d.headers != nil:
+ subject = d.Header("subject")
}
return subject
}
+func (d *TemplateData) SubjectBase() string {
+ base, _ := sortthread.GetBaseSubject(d.Subject())
+ return base
+}
+
+func (d *TemplateData) Number() string {
+ return fmt.Sprintf("%d", d.msgNum)
+}
+
+func (d *TemplateData) Labels() []string {
+ if d.info == nil {
+ return nil
+ }
+ return d.info.Labels
+}
+
+func (d *TemplateData) Flags() []string {
+ var flags []string
+ if d.info == nil {
+ return flags
+ }
+
+ switch {
+ case d.info.Flags.Has(models.SeenFlag | models.AnsweredFlag):
+ flags = append(flags, "r") // message has been replied to
+ case d.info.Flags.Has(models.SeenFlag):
+ break
+ case d.info.Flags.Has(models.RecentFlag):
+ flags = append(flags, "N") // message is new
+ default:
+ flags = append(flags, "O") // message is old
+ }
+ if d.info.Flags.Has(models.DeletedFlag) {
+ flags = append(flags, "D")
+ }
+ if d.info.BodyStructure != nil {
+ for _, bS := range d.info.BodyStructure.Parts {
+ if strings.ToLower(bS.Disposition) == "attachment" {
+ flags = append(flags, d.iconAttachment)
+ break
+ }
+ }
+ }
+ if d.info.Flags.Has(models.FlaggedFlag) {
+ flags = append(flags, "!")
+ }
+ if d.marked {
+ flags = append(flags, "*")
+ }
+ return flags
+}
+
+func (d *TemplateData) MessageId() string {
+ if d.info == nil || d.info.Envelope == nil {
+ return ""
+ }
+ return d.info.Envelope.MessageId
+}
+
+func (d *TemplateData) Size() uint32 {
+ if d.info == nil || d.info.Envelope == nil {
+ return 0
+ }
+ return d.info.Size
+}
+
func (d *TemplateData) OriginalText() string {
if d.parent == nil {
return ""
@@ -83,6 +313,17 @@ func (d *TemplateData) OriginalMIMEType() string {
return d.parent.MIMEType
}
+func (d *TemplateData) OriginalHeader(name string) string {
+ if d.parent == nil || d.parent.RFC822Headers == nil {
+ return ""
+ }
+ text, err := d.parent.RFC822Headers.Text(name)
+ if err != nil {
+ text = d.parent.RFC822Headers.Get(name)
+ }
+ return text
+}
+
// DummyData provides dummy data to test template validity
func DummyData() *TemplateData {
from := &mail.Address{
@@ -108,5 +349,51 @@ func DummyData() *TemplateData {
MIMEType: "text/plain",
RFC822Headers: oh,
}
- return NewTemplateData(h, &original)
+ data := NewTemplateData(
+ to,
+ nil,
+ "account",
+ "folder",
+ "2006 Jan 02, 15:04 GMT-0700",
+ "15:04",
+ "Monday 15:04",
+ "Jan 02",
+ "a",
+ )
+ data.SetHeaders(h, &original)
+
+ info := &models.MessageInfo{
+ BodyStructure: &models.BodyStructure{
+ MIMEType: "text",
+ MIMESubType: "plain",
+ Params: make(map[string]string),
+ Description: "",
+ Encoding: "",
+ Parts: []*models.BodyStructure{},
+ Disposition: "",
+ DispositionParams: make(map[string]string),
+ },
+ Envelope: &models.Envelope{
+ Date: time.Date(1981, 6, 23, 16, 52, 0, 0, time.UTC),
+ Subject: "[PATCH aerc 2/3] foo: baz bar buz",
+ From: []*mail.Address{from},
+ ReplyTo: []*mail.Address{},
+ To: []*mail.Address{to},
+ Cc: []*mail.Address{},
+ Bcc: []*mail.Address{},
+ MessageId: "",
+ InReplyTo: "",
+ },
+ Flags: models.FlaggedFlag,
+ Labels: []string{"inbox", "patch"},
+ InternalDate: time.Now(),
+ RFC822Headers: nil,
+ Refs: []string{},
+ Size: 65512,
+ Uid: 12345,
+ Error: nil,
+ }
+ data.SetInfo(info, 42, true)
+
+ return data
}