Factor IMAP-specific structs out of UI models
Before, we were using several IMAP-specific concepts to represent information being displayed in the UI. Factor these structures out of the IMAP package to make it easier for other backends to provide the required information.
This commit is contained in:
parent
88c379dcba
commit
c610c3cd9d
10 changed files with 211 additions and 108 deletions
|
@ -9,12 +9,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.sr.ht/~sircmpwn/getopt"
|
"git.sr.ht/~sircmpwn/getopt"
|
||||||
"github.com/emersion/go-imap"
|
|
||||||
"github.com/emersion/go-message"
|
"github.com/emersion/go-message"
|
||||||
_ "github.com/emersion/go-message/charset"
|
_ "github.com/emersion/go-message/charset"
|
||||||
"github.com/emersion/go-message/mail"
|
"github.com/emersion/go-message/mail"
|
||||||
|
|
||||||
"git.sr.ht/~sircmpwn/aerc/lib"
|
"git.sr.ht/~sircmpwn/aerc/models"
|
||||||
"git.sr.ht/~sircmpwn/aerc/widgets"
|
"git.sr.ht/~sircmpwn/aerc/widgets"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -67,7 +66,7 @@ func (_ reply) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
var (
|
var (
|
||||||
to []string
|
to []string
|
||||||
cc []string
|
cc []string
|
||||||
toList []*imap.Address
|
toList []*models.Address
|
||||||
)
|
)
|
||||||
if args[0] == "reply" {
|
if args[0] == "reply" {
|
||||||
if len(msg.Envelope.ReplyTo) != 0 {
|
if len(msg.Envelope.ReplyTo) != 0 {
|
||||||
|
@ -76,24 +75,23 @@ func (_ reply) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
toList = msg.Envelope.From
|
toList = msg.Envelope.From
|
||||||
}
|
}
|
||||||
for _, addr := range toList {
|
for _, addr := range toList {
|
||||||
if addr.PersonalName != "" {
|
if addr.Name != "" {
|
||||||
to = append(to, fmt.Sprintf("%s <%s@%s>",
|
to = append(to, fmt.Sprintf("%s <%s@%s>",
|
||||||
addr.PersonalName, addr.MailboxName, addr.HostName))
|
addr.Name, addr.Mailbox, addr.Host))
|
||||||
} else {
|
} else {
|
||||||
to = append(to, fmt.Sprintf("<%s@%s>",
|
to = append(to, fmt.Sprintf("<%s@%s>", addr.Mailbox, addr.Host))
|
||||||
addr.MailboxName, addr.HostName))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if replyAll {
|
if replyAll {
|
||||||
for _, addr := range msg.Envelope.Cc {
|
for _, addr := range msg.Envelope.Cc {
|
||||||
cc = append(cc, lib.FormatAddress(addr))
|
cc = append(cc, addr.Format())
|
||||||
}
|
}
|
||||||
for _, addr := range msg.Envelope.To {
|
for _, addr := range msg.Envelope.To {
|
||||||
address := fmt.Sprintf("%s@%s", addr.MailboxName, addr.HostName)
|
address := fmt.Sprintf("%s@%s", addr.Mailbox, addr.Host)
|
||||||
if address == us.Address {
|
if address == us.Address {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
to = append(to, lib.FormatAddress(addr))
|
to = append(to, addr.Format())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,7 +161,7 @@ func (_ reply) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
go composer.SetContents(pipeout)
|
go composer.SetContents(pipeout)
|
||||||
// TODO: Let user customize the date format used here
|
// TODO: Let user customize the date format used here
|
||||||
io.WriteString(pipein, fmt.Sprintf("Forwarded message from %s on %s:\n\n",
|
io.WriteString(pipein, fmt.Sprintf("Forwarded message from %s on %s:\n\n",
|
||||||
msg.Envelope.From[0].PersonalName,
|
msg.Envelope.From[0].Name,
|
||||||
msg.Envelope.Date.Format("Mon Jan 2, 2006 at 3:04 PM")))
|
msg.Envelope.Date.Format("Mon Jan 2, 2006 at 3:04 PM")))
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
io.WriteString(pipein, fmt.Sprintf("%s\n", scanner.Text()))
|
io.WriteString(pipein, fmt.Sprintf("%s\n", scanner.Text()))
|
||||||
|
@ -176,7 +174,7 @@ func (_ reply) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
if quote {
|
if quote {
|
||||||
var (
|
var (
|
||||||
path []int
|
path []int
|
||||||
part *imap.BodyStructure
|
part *models.BodyStructure
|
||||||
)
|
)
|
||||||
if len(msg.BodyStructure.Parts) != 0 {
|
if len(msg.BodyStructure.Parts) != 0 {
|
||||||
part, path = findPlaintext(msg.BodyStructure, path)
|
part, path = findPlaintext(msg.BodyStructure, path)
|
||||||
|
@ -212,7 +210,7 @@ func (_ reply) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
// TODO: Let user customize the date format used here
|
// TODO: Let user customize the date format used here
|
||||||
io.WriteString(pipein, fmt.Sprintf("On %s %s wrote:\n",
|
io.WriteString(pipein, fmt.Sprintf("On %s %s wrote:\n",
|
||||||
msg.Envelope.Date.Format("Mon Jan 2, 2006 at 3:04 PM"),
|
msg.Envelope.Date.Format("Mon Jan 2, 2006 at 3:04 PM"),
|
||||||
msg.Envelope.From[0].PersonalName))
|
msg.Envelope.From[0].Name))
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
io.WriteString(pipein, fmt.Sprintf("> %s\n", scanner.Text()))
|
io.WriteString(pipein, fmt.Sprintf("> %s\n", scanner.Text()))
|
||||||
}
|
}
|
||||||
|
@ -228,8 +226,8 @@ func (_ reply) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func findPlaintext(bs *imap.BodyStructure,
|
func findPlaintext(bs *models.BodyStructure,
|
||||||
path []int) (*imap.BodyStructure, []int) {
|
path []int) (*models.BodyStructure, []int) {
|
||||||
|
|
||||||
for i, part := range bs.Parts {
|
for i, part := range bs.Parts {
|
||||||
cur := append(path, i+1)
|
cur := append(path, i+1)
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
package lib
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/emersion/go-imap"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
atom *regexp.Regexp = regexp.MustCompile("^[a-z0-9!#$%7'*+-/=?^_`{}|~ ]+$")
|
|
||||||
)
|
|
||||||
|
|
||||||
func FormatAddresses(addrs []*imap.Address) string {
|
|
||||||
val := bytes.Buffer{}
|
|
||||||
for i, addr := range addrs {
|
|
||||||
val.WriteString(FormatAddress(addr))
|
|
||||||
if i != len(addrs)-1 {
|
|
||||||
val.WriteString(", ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return val.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func FormatAddress(addr *imap.Address) string {
|
|
||||||
if addr.PersonalName != "" {
|
|
||||||
if atom.MatchString(addr.PersonalName) {
|
|
||||||
return fmt.Sprintf("%s <%s@%s>",
|
|
||||||
addr.PersonalName, addr.MailboxName, addr.HostName)
|
|
||||||
} else {
|
|
||||||
return fmt.Sprintf("\"%s\" <%s@%s>",
|
|
||||||
strings.ReplaceAll(addr.PersonalName, "\"", "'"),
|
|
||||||
addr.MailboxName, addr.HostName)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return fmt.Sprintf("<%s@%s>", addr.MailboxName, addr.HostName)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,8 +6,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/emersion/go-imap"
|
|
||||||
|
|
||||||
"git.sr.ht/~sircmpwn/aerc/config"
|
"git.sr.ht/~sircmpwn/aerc/config"
|
||||||
"git.sr.ht/~sircmpwn/aerc/models"
|
"git.sr.ht/~sircmpwn/aerc/models"
|
||||||
)
|
)
|
||||||
|
@ -70,10 +68,9 @@ func ParseIndexFormat(conf *config.AercConfig, number int,
|
||||||
}
|
}
|
||||||
addr := msg.Envelope.From[0]
|
addr := msg.Envelope.From[0]
|
||||||
retval = append(retval, 's')
|
retval = append(retval, 's')
|
||||||
args = append(args, fmt.Sprintf("%s@%s", addr.MailboxName,
|
args = append(args, fmt.Sprintf("%s@%s", addr.Mailbox, addr.Host))
|
||||||
addr.HostName))
|
|
||||||
case 'A':
|
case 'A':
|
||||||
var addr *imap.Address
|
var addr *models.Address
|
||||||
if len(msg.Envelope.ReplyTo) == 0 {
|
if len(msg.Envelope.ReplyTo) == 0 {
|
||||||
if len(msg.Envelope.From) == 0 {
|
if len(msg.Envelope.From) == 0 {
|
||||||
return "", nil,
|
return "", nil,
|
||||||
|
@ -85,8 +82,7 @@ func ParseIndexFormat(conf *config.AercConfig, number int,
|
||||||
addr = msg.Envelope.ReplyTo[0]
|
addr = msg.Envelope.ReplyTo[0]
|
||||||
}
|
}
|
||||||
retval = append(retval, 's')
|
retval = append(retval, 's')
|
||||||
args = append(args, fmt.Sprintf("%s@%s", addr.MailboxName,
|
args = append(args, fmt.Sprintf("%s@%s", addr.Mailbox, addr.Host))
|
||||||
addr.HostName))
|
|
||||||
case 'C':
|
case 'C':
|
||||||
retval = append(retval, 'd')
|
retval = append(retval, 'd')
|
||||||
args = append(args, number)
|
args = append(args, number)
|
||||||
|
@ -100,7 +96,7 @@ func ParseIndexFormat(conf *config.AercConfig, number int,
|
||||||
if len(msg.Envelope.From) == 0 {
|
if len(msg.Envelope.From) == 0 {
|
||||||
return "", nil, errors.New("found no address for sender")
|
return "", nil, errors.New("found no address for sender")
|
||||||
}
|
}
|
||||||
addr := FormatAddress(msg.Envelope.From[0])
|
addr := msg.Envelope.From[0].Format()
|
||||||
retval = append(retval, 's')
|
retval = append(retval, 's')
|
||||||
args = append(args, addr)
|
args = append(args, addr)
|
||||||
case 'F':
|
case 'F':
|
||||||
|
@ -111,11 +107,10 @@ func ParseIndexFormat(conf *config.AercConfig, number int,
|
||||||
// TODO: handle case when sender is current user. Then
|
// TODO: handle case when sender is current user. Then
|
||||||
// use recipient's name
|
// use recipient's name
|
||||||
var val string
|
var val string
|
||||||
if addr.PersonalName != "" {
|
if addr.Name != "" {
|
||||||
val = addr.PersonalName
|
val = addr.Name
|
||||||
} else {
|
} else {
|
||||||
val = fmt.Sprintf("%s@%s",
|
val = fmt.Sprintf("%s@%s", addr.Mailbox, addr.Host)
|
||||||
addr.MailboxName, addr.HostName)
|
|
||||||
}
|
}
|
||||||
retval = append(retval, 's')
|
retval = append(retval, 's')
|
||||||
args = append(args, val)
|
args = append(args, val)
|
||||||
|
@ -129,20 +124,19 @@ func ParseIndexFormat(conf *config.AercConfig, number int,
|
||||||
}
|
}
|
||||||
addr := msg.Envelope.From[0]
|
addr := msg.Envelope.From[0]
|
||||||
var val string
|
var val string
|
||||||
if addr.PersonalName != "" {
|
if addr.Name != "" {
|
||||||
val = addr.PersonalName
|
val = addr.Name
|
||||||
} else {
|
} else {
|
||||||
val = fmt.Sprintf("%s@%s",
|
val = fmt.Sprintf("%s@%s", addr.Mailbox, addr.Host)
|
||||||
addr.MailboxName, addr.HostName)
|
|
||||||
}
|
}
|
||||||
retval = append(retval, 's')
|
retval = append(retval, 's')
|
||||||
args = append(args, val)
|
args = append(args, val)
|
||||||
case 'r':
|
case 'r':
|
||||||
addrs := FormatAddresses(msg.Envelope.To)
|
addrs := models.FormatAddresses(msg.Envelope.To)
|
||||||
retval = append(retval, 's')
|
retval = append(retval, 's')
|
||||||
args = append(args, addrs)
|
args = append(args, addrs)
|
||||||
case 'R':
|
case 'R':
|
||||||
addrs := FormatAddresses(msg.Envelope.Cc)
|
addrs := models.FormatAddresses(msg.Envelope.Cc)
|
||||||
retval = append(retval, 's')
|
retval = append(retval, 's')
|
||||||
args = append(args, addrs)
|
args = append(args, addrs)
|
||||||
case 's':
|
case 's':
|
||||||
|
@ -154,16 +148,16 @@ func ParseIndexFormat(conf *config.AercConfig, number int,
|
||||||
}
|
}
|
||||||
addr := msg.Envelope.From[0]
|
addr := msg.Envelope.From[0]
|
||||||
retval = append(retval, 's')
|
retval = append(retval, 's')
|
||||||
args = append(args, addr.MailboxName)
|
args = append(args, addr.Mailbox)
|
||||||
case 'v':
|
case 'v':
|
||||||
if len(msg.Envelope.From) == 0 {
|
if len(msg.Envelope.From) == 0 {
|
||||||
return "", nil, errors.New("found no address for sender")
|
return "", nil, errors.New("found no address for sender")
|
||||||
}
|
}
|
||||||
addr := msg.Envelope.From[0]
|
addr := msg.Envelope.From[0]
|
||||||
// check if message is from current user
|
// check if message is from current user
|
||||||
if addr.PersonalName != "" {
|
if addr.Name != "" {
|
||||||
retval = append(retval, 's')
|
retval = append(retval, 's')
|
||||||
args = append(args, strings.Split(addr.PersonalName, " ")[0])
|
args = append(args, strings.Split(addr.Name, " ")[0])
|
||||||
}
|
}
|
||||||
case 'Z':
|
case 'Z':
|
||||||
// calculate all flags
|
// calculate all flags
|
||||||
|
@ -171,18 +165,18 @@ func ParseIndexFormat(conf *config.AercConfig, number int,
|
||||||
var delFlag = ""
|
var delFlag = ""
|
||||||
var flaggedFlag = ""
|
var flaggedFlag = ""
|
||||||
for _, flag := range msg.Flags {
|
for _, flag := range msg.Flags {
|
||||||
if flag == imap.SeenFlag {
|
if flag == models.SeenFlag {
|
||||||
readFlag = "O" // message is old
|
readFlag = "O" // message is old
|
||||||
} else if flag == imap.RecentFlag {
|
} else if flag == models.RecentFlag {
|
||||||
readFlag = "N" // message is new
|
readFlag = "N" // message is new
|
||||||
} else if flag == imap.AnsweredFlag {
|
} else if flag == models.AnsweredFlag {
|
||||||
readFlag = "r" // message has been replied to
|
readFlag = "r" // message has been replied to
|
||||||
}
|
}
|
||||||
if flag == imap.DeletedFlag {
|
if flag == models.DeletedFlag {
|
||||||
delFlag = "D"
|
delFlag = "D"
|
||||||
// TODO: check if attachments
|
// TODO: check if attachments
|
||||||
}
|
}
|
||||||
if flag == imap.FlaggedFlag {
|
if flag == models.FlaggedFlag {
|
||||||
flaggedFlag = "!"
|
flaggedFlag = "!"
|
||||||
}
|
}
|
||||||
// TODO: check gpg stuff
|
// TODO: check gpg stuff
|
||||||
|
|
|
@ -1,13 +1,37 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/emersion/go-imap"
|
|
||||||
"github.com/emersion/go-message/mail"
|
"github.com/emersion/go-message/mail"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Flag is an abstraction around the different flags which can be present in
|
||||||
|
// different email backends and represents a flag that we use in the UI.
|
||||||
|
type Flag int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SeenFlag marks a message as having been seen previously
|
||||||
|
SeenFlag Flag = iota
|
||||||
|
|
||||||
|
// RecentFlag marks a message as being recent
|
||||||
|
RecentFlag
|
||||||
|
|
||||||
|
// AnsweredFlag marks a message as having been replied to
|
||||||
|
AnsweredFlag
|
||||||
|
|
||||||
|
// DeletedFlag marks a message as having been deleted
|
||||||
|
DeletedFlag
|
||||||
|
|
||||||
|
// FlaggedFlag marks a message with a user flag
|
||||||
|
FlaggedFlag
|
||||||
|
)
|
||||||
|
|
||||||
type Directory struct {
|
type Directory struct {
|
||||||
Name string
|
Name string
|
||||||
Attributes []string
|
Attributes []string
|
||||||
|
@ -30,9 +54,9 @@ type DirectoryInfo struct {
|
||||||
|
|
||||||
// A MessageInfo holds information about the structure of a message
|
// A MessageInfo holds information about the structure of a message
|
||||||
type MessageInfo struct {
|
type MessageInfo struct {
|
||||||
BodyStructure *imap.BodyStructure
|
BodyStructure *BodyStructure
|
||||||
Envelope *imap.Envelope
|
Envelope *Envelope
|
||||||
Flags []string
|
Flags []Flag
|
||||||
InternalDate time.Time
|
InternalDate time.Time
|
||||||
RFC822Headers *mail.Header
|
RFC822Headers *mail.Header
|
||||||
Size uint32
|
Size uint32
|
||||||
|
@ -50,3 +74,59 @@ type FullMessage struct {
|
||||||
Reader io.Reader
|
Reader io.Reader
|
||||||
Uid uint32
|
Uid uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type BodyStructure struct {
|
||||||
|
MIMEType string
|
||||||
|
MIMESubType string
|
||||||
|
Params map[string]string
|
||||||
|
Description string
|
||||||
|
Encoding string
|
||||||
|
Parts []*BodyStructure
|
||||||
|
Disposition string
|
||||||
|
DispositionParams map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Envelope struct {
|
||||||
|
Date time.Time
|
||||||
|
Subject string
|
||||||
|
From []*Address
|
||||||
|
ReplyTo []*Address
|
||||||
|
To []*Address
|
||||||
|
Cc []*Address
|
||||||
|
Bcc []*Address
|
||||||
|
MessageId string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Address struct {
|
||||||
|
Name string
|
||||||
|
Mailbox string
|
||||||
|
Host string
|
||||||
|
}
|
||||||
|
|
||||||
|
var atom *regexp.Regexp = regexp.MustCompile("^[a-z0-9!#$%7'*+-/=?^_`{}|~ ]+$")
|
||||||
|
|
||||||
|
func (a Address) Format() string {
|
||||||
|
if a.Name != "" {
|
||||||
|
if atom.MatchString(a.Name) {
|
||||||
|
return fmt.Sprintf("%s <%s@%s>", a.Name, a.Mailbox, a.Host)
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("\"%s\" <%s@%s>",
|
||||||
|
strings.ReplaceAll(a.Name, "\"", "'"),
|
||||||
|
a.Mailbox, a.Host)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("<%s@%s>", a.Mailbox, a.Host)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FormatAddresses formats a list of addresses, separating each by a comma
|
||||||
|
func FormatAddresses(addrs []*Address) string {
|
||||||
|
val := bytes.Buffer{}
|
||||||
|
for i, addr := range addrs {
|
||||||
|
val.WriteString(addr.Format())
|
||||||
|
if i != len(addrs)-1 {
|
||||||
|
val.WriteString(", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return val.String()
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/emersion/go-imap"
|
|
||||||
"github.com/gdamore/tcell"
|
"github.com/gdamore/tcell"
|
||||||
"github.com/mattn/go-runewidth"
|
"github.com/mattn/go-runewidth"
|
||||||
|
|
||||||
|
@ -86,7 +85,7 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
|
||||||
// unread message
|
// unread message
|
||||||
seen := false
|
seen := false
|
||||||
for _, flag := range msg.Flags {
|
for _, flag := range msg.Flags {
|
||||||
if flag == imap.SeenFlag {
|
if flag == models.SeenFlag {
|
||||||
seen = true
|
seen = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/danwakefield/fnmatch"
|
"github.com/danwakefield/fnmatch"
|
||||||
"github.com/emersion/go-imap"
|
|
||||||
"github.com/emersion/go-message"
|
"github.com/emersion/go-message"
|
||||||
_ "github.com/emersion/go-message/charset"
|
_ "github.com/emersion/go-message/charset"
|
||||||
"github.com/emersion/go-message/mail"
|
"github.com/emersion/go-message/mail"
|
||||||
|
@ -66,12 +65,12 @@ func NewMessageViewer(acct *AccountView, conf *config.AercConfig,
|
||||||
headers.AddChild(
|
headers.AddChild(
|
||||||
&HeaderView{
|
&HeaderView{
|
||||||
Name: "From",
|
Name: "From",
|
||||||
Value: lib.FormatAddresses(msg.Envelope.From),
|
Value: models.FormatAddresses(msg.Envelope.From),
|
||||||
}).At(0, 0)
|
}).At(0, 0)
|
||||||
headers.AddChild(
|
headers.AddChild(
|
||||||
&HeaderView{
|
&HeaderView{
|
||||||
Name: "To",
|
Name: "To",
|
||||||
Value: lib.FormatAddresses(msg.Envelope.To),
|
Value: models.FormatAddresses(msg.Envelope.To),
|
||||||
}).At(0, 1)
|
}).At(0, 1)
|
||||||
headers.AddChild(
|
headers.AddChild(
|
||||||
&HeaderView{
|
&HeaderView{
|
||||||
|
@ -112,7 +111,7 @@ handle_error:
|
||||||
}
|
}
|
||||||
|
|
||||||
func enumerateParts(conf *config.AercConfig, store *lib.MessageStore,
|
func enumerateParts(conf *config.AercConfig, store *lib.MessageStore,
|
||||||
msg *models.MessageInfo, body *imap.BodyStructure,
|
msg *models.MessageInfo, body *models.BodyStructure,
|
||||||
showHeaders bool, index []int) ([]*PartViewer, error) {
|
showHeaders bool, index []int) ([]*PartViewer, error) {
|
||||||
|
|
||||||
var parts []*PartViewer
|
var parts []*PartViewer
|
||||||
|
@ -324,7 +323,7 @@ type PartViewer struct {
|
||||||
msg *models.MessageInfo
|
msg *models.MessageInfo
|
||||||
pager *exec.Cmd
|
pager *exec.Cmd
|
||||||
pagerin io.WriteCloser
|
pagerin io.WriteCloser
|
||||||
part *imap.BodyStructure
|
part *models.BodyStructure
|
||||||
showHeaders bool
|
showHeaders bool
|
||||||
sink io.WriteCloser
|
sink io.WriteCloser
|
||||||
source io.Reader
|
source io.Reader
|
||||||
|
@ -334,7 +333,7 @@ type PartViewer struct {
|
||||||
|
|
||||||
func NewPartViewer(conf *config.AercConfig,
|
func NewPartViewer(conf *config.AercConfig,
|
||||||
store *lib.MessageStore, msg *models.MessageInfo,
|
store *lib.MessageStore, msg *models.MessageInfo,
|
||||||
part *imap.BodyStructure, showHeaders bool,
|
part *models.BodyStructure, showHeaders bool,
|
||||||
index []int) (*PartViewer, error) {
|
index []int) (*PartViewer, error) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -365,11 +364,11 @@ func NewPartViewer(conf *config.AercConfig,
|
||||||
case "subject":
|
case "subject":
|
||||||
header = msg.Envelope.Subject
|
header = msg.Envelope.Subject
|
||||||
case "from":
|
case "from":
|
||||||
header = lib.FormatAddresses(msg.Envelope.From)
|
header = models.FormatAddresses(msg.Envelope.From)
|
||||||
case "to":
|
case "to":
|
||||||
header = lib.FormatAddresses(msg.Envelope.To)
|
header = models.FormatAddresses(msg.Envelope.To)
|
||||||
case "cc":
|
case "cc":
|
||||||
header = lib.FormatAddresses(msg.Envelope.Cc)
|
header = models.FormatAddresses(msg.Envelope.Cc)
|
||||||
}
|
}
|
||||||
if f.Regex.Match([]byte(header)) {
|
if f.Regex.Match([]byte(header)) {
|
||||||
filter = exec.Command("sh", "-c", f.Command)
|
filter = exec.Command("sh", "-c", f.Command)
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package widgets
|
package widgets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emersion/go-imap"
|
|
||||||
|
|
||||||
"git.sr.ht/~sircmpwn/aerc/lib"
|
"git.sr.ht/~sircmpwn/aerc/lib"
|
||||||
"git.sr.ht/~sircmpwn/aerc/lib/ui"
|
"git.sr.ht/~sircmpwn/aerc/lib/ui"
|
||||||
"git.sr.ht/~sircmpwn/aerc/models"
|
"git.sr.ht/~sircmpwn/aerc/models"
|
||||||
|
@ -10,8 +8,8 @@ import (
|
||||||
|
|
||||||
type PartInfo struct {
|
type PartInfo struct {
|
||||||
Index []int
|
Index []int
|
||||||
Msg *types.MessageInfo
|
Msg *models.MessageInfo
|
||||||
Part *imap.BodyStructure
|
Part *models.BodyStructure
|
||||||
Store *lib.MessageStore
|
Store *lib.MessageStore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,9 +82,9 @@ func (imapw *IMAPWorker) handleFetchMessages(
|
||||||
imapw.worker.PostMessage(&types.MessageInfo{
|
imapw.worker.PostMessage(&types.MessageInfo{
|
||||||
Message: types.RespondTo(msg),
|
Message: types.RespondTo(msg),
|
||||||
Info: &models.MessageInfo{
|
Info: &models.MessageInfo{
|
||||||
BodyStructure: _msg.BodyStructure,
|
BodyStructure: translateBodyStructure(_msg.BodyStructure),
|
||||||
Envelope: _msg.Envelope,
|
Envelope: translateEnvelope(_msg.Envelope),
|
||||||
Flags: _msg.Flags,
|
Flags: translateFlags(_msg.Flags),
|
||||||
InternalDate: _msg.InternalDate,
|
InternalDate: _msg.InternalDate,
|
||||||
RFC822Headers: header,
|
RFC822Headers: header,
|
||||||
Uid: _msg.Uid,
|
Uid: _msg.Uid,
|
||||||
|
@ -103,7 +103,7 @@ func (imapw *IMAPWorker) handleFetchMessages(
|
||||||
imapw.worker.PostMessage(&types.MessageInfo{
|
imapw.worker.PostMessage(&types.MessageInfo{
|
||||||
Message: types.RespondTo(msg),
|
Message: types.RespondTo(msg),
|
||||||
Info: &models.MessageInfo{
|
Info: &models.MessageInfo{
|
||||||
Flags: _msg.Flags,
|
Flags: translateFlags(_msg.Flags),
|
||||||
Uid: _msg.Uid,
|
Uid: _msg.Uid,
|
||||||
},
|
},
|
||||||
}, nil)
|
}, nil)
|
||||||
|
@ -120,7 +120,7 @@ func (imapw *IMAPWorker) handleFetchMessages(
|
||||||
imapw.worker.PostMessage(&types.MessageInfo{
|
imapw.worker.PostMessage(&types.MessageInfo{
|
||||||
Message: types.RespondTo(msg),
|
Message: types.RespondTo(msg),
|
||||||
Info: &models.MessageInfo{
|
Info: &models.MessageInfo{
|
||||||
Flags: _msg.Flags,
|
Flags: translateFlags(_msg.Flags),
|
||||||
Uid: _msg.Uid,
|
Uid: _msg.Uid,
|
||||||
},
|
},
|
||||||
}, nil)
|
}, nil)
|
||||||
|
|
|
@ -2,6 +2,8 @@ package imap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emersion/go-imap"
|
"github.com/emersion/go-imap"
|
||||||
|
|
||||||
|
"git.sr.ht/~sircmpwn/aerc/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func toSeqSet(uids []uint32) *imap.SeqSet {
|
func toSeqSet(uids []uint32) *imap.SeqSet {
|
||||||
|
@ -11,3 +13,76 @@ func toSeqSet(uids []uint32) *imap.SeqSet {
|
||||||
}
|
}
|
||||||
return &set
|
return &set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func translateBodyStructure(bs *imap.BodyStructure) *models.BodyStructure {
|
||||||
|
if bs == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var parts []*models.BodyStructure
|
||||||
|
for _, part := range bs.Parts {
|
||||||
|
parts = append(parts, translateBodyStructure(part))
|
||||||
|
}
|
||||||
|
return &models.BodyStructure{
|
||||||
|
MIMEType: bs.MIMEType,
|
||||||
|
MIMESubType: bs.MIMESubType,
|
||||||
|
Params: bs.Params,
|
||||||
|
Description: bs.Description,
|
||||||
|
Encoding: bs.Encoding,
|
||||||
|
Parts: parts,
|
||||||
|
Disposition: bs.Disposition,
|
||||||
|
DispositionParams: bs.DispositionParams,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func translateEnvelope(e *imap.Envelope) *models.Envelope {
|
||||||
|
if e == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &models.Envelope{
|
||||||
|
Date: e.Date,
|
||||||
|
Subject: e.Subject,
|
||||||
|
From: translateAddresses(e.From),
|
||||||
|
ReplyTo: translateAddresses(e.ReplyTo),
|
||||||
|
To: translateAddresses(e.To),
|
||||||
|
Cc: translateAddresses(e.Cc),
|
||||||
|
Bcc: translateAddresses(e.Bcc),
|
||||||
|
MessageId: e.MessageId,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func translateAddress(a *imap.Address) *models.Address {
|
||||||
|
if a == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &models.Address{
|
||||||
|
Name: a.PersonalName,
|
||||||
|
Mailbox: a.MailboxName,
|
||||||
|
Host: a.HostName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func translateAddresses(addrs []*imap.Address) []*models.Address {
|
||||||
|
var converted []*models.Address
|
||||||
|
for _, addr := range addrs {
|
||||||
|
converted = append(converted, translateAddress(addr))
|
||||||
|
}
|
||||||
|
return converted
|
||||||
|
}
|
||||||
|
|
||||||
|
var flagMap = map[string]models.Flag{
|
||||||
|
imap.SeenFlag: models.SeenFlag,
|
||||||
|
imap.RecentFlag: models.RecentFlag,
|
||||||
|
imap.AnsweredFlag: models.AnsweredFlag,
|
||||||
|
imap.DeletedFlag: models.DeletedFlag,
|
||||||
|
imap.FlaggedFlag: models.FlaggedFlag,
|
||||||
|
}
|
||||||
|
|
||||||
|
func translateFlags(imapFlags []string) []models.Flag {
|
||||||
|
var flags []models.Flag
|
||||||
|
for _, imapFlag := range imapFlags {
|
||||||
|
if flag, ok := flagMap[imapFlag]; ok {
|
||||||
|
flags = append(flags, flag)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return flags
|
||||||
|
}
|
||||||
|
|
|
@ -187,9 +187,9 @@ func (w *IMAPWorker) handleImapUpdate(update client.Update) {
|
||||||
}
|
}
|
||||||
w.worker.PostMessage(&types.MessageInfo{
|
w.worker.PostMessage(&types.MessageInfo{
|
||||||
Info: &models.MessageInfo{
|
Info: &models.MessageInfo{
|
||||||
BodyStructure: msg.BodyStructure,
|
BodyStructure: translateBodyStructure(msg.BodyStructure),
|
||||||
Envelope: msg.Envelope,
|
Envelope: translateEnvelope(msg.Envelope),
|
||||||
Flags: msg.Flags,
|
Flags: translateFlags(msg.Flags),
|
||||||
InternalDate: msg.InternalDate,
|
InternalDate: msg.InternalDate,
|
||||||
Uid: msg.Uid,
|
Uid: msg.Uid,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue