imap: Remove FetchMessageBodyPart.{Encoding,Charset}
Fixes https://todo.sr.ht/~sircmpwn/aerc2/352 exactly as suggested by emersion.
This commit is contained in:
parent
ea2646fc03
commit
bae678e8f2
3 changed files with 113 additions and 125 deletions
|
@ -138,21 +138,10 @@ func (store *MessageStore) FetchFull(uids []uint32, cb func(*types.FullMessage))
|
||||||
|
|
||||||
func (store *MessageStore) FetchBodyPart(
|
func (store *MessageStore) FetchBodyPart(
|
||||||
uid uint32, parent *models.BodyStructure, part []int, cb func(io.Reader)) {
|
uid uint32, parent *models.BodyStructure, part []int, cb func(io.Reader)) {
|
||||||
partbs, err := parent.PartAtIndex(part)
|
|
||||||
if err != nil {
|
|
||||||
store.worker.Logger.Printf("FetchBodyPart: %v\n", err)
|
|
||||||
}
|
|
||||||
var charset string
|
|
||||||
var ok bool
|
|
||||||
if charset, ok = partbs.Params["charset"]; !ok {
|
|
||||||
charset = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
store.worker.PostAction(&types.FetchMessageBodyPart{
|
store.worker.PostAction(&types.FetchMessageBodyPart{
|
||||||
Uid: uid,
|
Uid: uid,
|
||||||
Part: part,
|
Part: part,
|
||||||
Encoding: partbs.Encoding,
|
|
||||||
Charset: charset,
|
|
||||||
}, func(resp types.WorkerMessage) {
|
}, func(resp types.WorkerMessage) {
|
||||||
msg, ok := resp.(*types.MessageBodyPart)
|
msg, ok := resp.(*types.MessageBodyPart)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
@ -2,11 +2,7 @@ package imap
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"encoding/base64"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
"mime/quotedprintable"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/emersion/go-imap"
|
"github.com/emersion/go-imap"
|
||||||
"github.com/emersion/go-message"
|
"github.com/emersion/go-message"
|
||||||
|
@ -37,21 +33,90 @@ func (imapw *IMAPWorker) handleFetchMessageHeaders(
|
||||||
imap.FetchUid,
|
imap.FetchUid,
|
||||||
section.FetchItem(),
|
section.FetchItem(),
|
||||||
}
|
}
|
||||||
imapw.handleFetchMessages(msg, msg.Uids, items, section)
|
imapw.handleFetchMessages(msg, msg.Uids, items,
|
||||||
|
func(_msg *imap.Message) error {
|
||||||
|
reader := _msg.GetBody(section)
|
||||||
|
textprotoHeader, err := textproto.ReadHeader(bufio.NewReader(reader))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not read header: %v", err)
|
||||||
|
}
|
||||||
|
header := &mail.Header{message.Header{textprotoHeader}}
|
||||||
|
imapw.worker.PostMessage(&types.MessageInfo{
|
||||||
|
Message: types.RespondTo(msg),
|
||||||
|
Info: &models.MessageInfo{
|
||||||
|
BodyStructure: translateBodyStructure(_msg.BodyStructure),
|
||||||
|
Envelope: translateEnvelope(_msg.Envelope),
|
||||||
|
Flags: translateImapFlags(_msg.Flags),
|
||||||
|
InternalDate: _msg.InternalDate,
|
||||||
|
RFC822Headers: header,
|
||||||
|
Uid: _msg.Uid,
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imapw *IMAPWorker) handleFetchMessageBodyPart(
|
func (imapw *IMAPWorker) handleFetchMessageBodyPart(
|
||||||
msg *types.FetchMessageBodyPart) {
|
msg *types.FetchMessageBodyPart) {
|
||||||
|
|
||||||
imapw.worker.Logger.Printf("Fetching message part")
|
imapw.worker.Logger.Printf("Fetching message part")
|
||||||
section := &imap.BodySectionName{}
|
|
||||||
section.Path = msg.Part
|
var partHeaderSection imap.BodySectionName
|
||||||
items := []imap.FetchItem{
|
partHeaderSection.Peek = true
|
||||||
imap.FetchFlags,
|
if len(msg.Part) > 0 {
|
||||||
imap.FetchUid,
|
partHeaderSection.Specifier = imap.MIMESpecifier
|
||||||
section.FetchItem(),
|
} else {
|
||||||
|
partHeaderSection.Specifier = imap.HeaderSpecifier
|
||||||
}
|
}
|
||||||
imapw.handleFetchMessages(msg, []uint32{msg.Uid}, items, section)
|
partHeaderSection.Path = msg.Part
|
||||||
|
|
||||||
|
var partBodySection imap.BodySectionName
|
||||||
|
if len(msg.Part) > 0 {
|
||||||
|
partBodySection.Specifier = imap.EntireSpecifier
|
||||||
|
} else {
|
||||||
|
partBodySection.Specifier = imap.TextSpecifier
|
||||||
|
}
|
||||||
|
partBodySection.Path = msg.Part
|
||||||
|
|
||||||
|
items := []imap.FetchItem{
|
||||||
|
imap.FetchEnvelope,
|
||||||
|
imap.FetchUid,
|
||||||
|
imap.FetchBodyStructure,
|
||||||
|
imap.FetchFlags,
|
||||||
|
partHeaderSection.FetchItem(),
|
||||||
|
partBodySection.FetchItem(),
|
||||||
|
}
|
||||||
|
imapw.handleFetchMessages(msg, []uint32{msg.Uid}, items,
|
||||||
|
func(_msg *imap.Message) error {
|
||||||
|
headerReader := bufio.NewReader(_msg.GetBody(&partHeaderSection))
|
||||||
|
h, err := textproto.ReadHeader(headerReader)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read part header: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
part, err := message.New(message.Header{h},
|
||||||
|
_msg.GetBody(&partBodySection))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create message reader: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
imapw.worker.PostMessage(&types.MessageBodyPart{
|
||||||
|
Message: types.RespondTo(msg),
|
||||||
|
Part: &models.MessageBodyPart{
|
||||||
|
Reader: part.Body,
|
||||||
|
Uid: _msg.Uid,
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
// Update flags (to mark message as read)
|
||||||
|
imapw.worker.PostMessage(&types.MessageInfo{
|
||||||
|
Message: types.RespondTo(msg),
|
||||||
|
Info: &models.MessageInfo{
|
||||||
|
Flags: translateImapFlags(_msg.Flags),
|
||||||
|
Uid: _msg.Uid,
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imapw *IMAPWorker) handleFetchFullMessages(
|
func (imapw *IMAPWorker) handleFetchFullMessages(
|
||||||
|
@ -65,85 +130,53 @@ func (imapw *IMAPWorker) handleFetchFullMessages(
|
||||||
imap.FetchUid,
|
imap.FetchUid,
|
||||||
section.FetchItem(),
|
section.FetchItem(),
|
||||||
}
|
}
|
||||||
imapw.handleFetchMessages(msg, msg.Uids, items, section)
|
imapw.handleFetchMessages(msg, msg.Uids, items,
|
||||||
|
func(_msg *imap.Message) error {
|
||||||
|
r := _msg.GetBody(section)
|
||||||
|
if r == nil {
|
||||||
|
return fmt.Errorf("could not get section %#v", section)
|
||||||
|
}
|
||||||
|
imapw.worker.PostMessage(&types.FullMessage{
|
||||||
|
Message: types.RespondTo(msg),
|
||||||
|
Content: &models.FullMessage{
|
||||||
|
Reader: bufio.NewReader(r),
|
||||||
|
Uid: _msg.Uid,
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
// Update flags (to mark message as read)
|
||||||
|
imapw.worker.PostMessage(&types.MessageInfo{
|
||||||
|
Message: types.RespondTo(msg),
|
||||||
|
Info: &models.MessageInfo{
|
||||||
|
Flags: translateImapFlags(_msg.Flags),
|
||||||
|
Uid: _msg.Uid,
|
||||||
|
},
|
||||||
|
}, nil)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (imapw *IMAPWorker) handleFetchMessages(
|
func (imapw *IMAPWorker) handleFetchMessages(
|
||||||
msg types.WorkerMessage, uids []uint32, items []imap.FetchItem,
|
msg types.WorkerMessage, uids []uint32, items []imap.FetchItem,
|
||||||
section *imap.BodySectionName) {
|
procFunc func(*imap.Message) error) {
|
||||||
|
|
||||||
messages := make(chan *imap.Message)
|
messages := make(chan *imap.Message)
|
||||||
done := make(chan error)
|
done := make(chan error)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
|
var reterr error
|
||||||
for _msg := range messages {
|
for _msg := range messages {
|
||||||
imapw.seqMap[_msg.SeqNum-1] = _msg.Uid
|
imapw.seqMap[_msg.SeqNum-1] = _msg.Uid
|
||||||
switch msg := msg.(type) {
|
err := procFunc(_msg)
|
||||||
case *types.FetchMessageHeaders:
|
if err != nil {
|
||||||
reader := _msg.GetBody(section)
|
if reterr == nil {
|
||||||
textprotoHeader, err := textproto.ReadHeader(bufio.NewReader(reader))
|
reterr = err
|
||||||
if err != nil {
|
|
||||||
done <- fmt.Errorf("could not read header: %v", err)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
header := &mail.Header{message.Header{textprotoHeader}}
|
// drain the channel upon error
|
||||||
imapw.worker.PostMessage(&types.MessageInfo{
|
for range messages {
|
||||||
Message: types.RespondTo(msg),
|
|
||||||
Info: &models.MessageInfo{
|
|
||||||
BodyStructure: translateBodyStructure(_msg.BodyStructure),
|
|
||||||
Envelope: translateEnvelope(_msg.Envelope),
|
|
||||||
Flags: translateImapFlags(_msg.Flags),
|
|
||||||
InternalDate: _msg.InternalDate,
|
|
||||||
RFC822Headers: header,
|
|
||||||
Uid: _msg.Uid,
|
|
||||||
},
|
|
||||||
}, nil)
|
|
||||||
case *types.FetchFullMessages:
|
|
||||||
r := _msg.GetBody(section)
|
|
||||||
if r == nil {
|
|
||||||
done <- fmt.Errorf("could not get section %#v", section)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
imapw.worker.PostMessage(&types.FullMessage{
|
|
||||||
Message: types.RespondTo(msg),
|
|
||||||
Content: &models.FullMessage{
|
|
||||||
Reader: bufio.NewReader(r),
|
|
||||||
Uid: _msg.Uid,
|
|
||||||
},
|
|
||||||
}, nil)
|
|
||||||
// Update flags (to mark message as read)
|
|
||||||
imapw.worker.PostMessage(&types.MessageInfo{
|
|
||||||
Message: types.RespondTo(msg),
|
|
||||||
Info: &models.MessageInfo{
|
|
||||||
Flags: translateImapFlags(_msg.Flags),
|
|
||||||
Uid: _msg.Uid,
|
|
||||||
},
|
|
||||||
}, nil)
|
|
||||||
case *types.FetchMessageBodyPart:
|
|
||||||
reader, err := getDecodedPart(msg, _msg, section)
|
|
||||||
if err != nil {
|
|
||||||
done <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
imapw.worker.PostMessage(&types.MessageBodyPart{
|
|
||||||
Message: types.RespondTo(msg),
|
|
||||||
Part: &models.MessageBodyPart{
|
|
||||||
Reader: reader,
|
|
||||||
Uid: _msg.Uid,
|
|
||||||
},
|
|
||||||
}, nil)
|
|
||||||
// Update flags (to mark message as read)
|
|
||||||
imapw.worker.PostMessage(&types.MessageInfo{
|
|
||||||
Message: types.RespondTo(msg),
|
|
||||||
Info: &models.MessageInfo{
|
|
||||||
Flags: translateImapFlags(_msg.Flags),
|
|
||||||
Uid: _msg.Uid,
|
|
||||||
},
|
|
||||||
}, nil)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done <- nil
|
done <- reterr
|
||||||
}()
|
}()
|
||||||
|
|
||||||
emitErr := func(err error) {
|
emitErr := func(err error) {
|
||||||
|
@ -165,35 +198,3 @@ func (imapw *IMAPWorker) handleFetchMessages(
|
||||||
imapw.worker.PostMessage(
|
imapw.worker.PostMessage(
|
||||||
&types.Done{types.RespondTo(msg)}, nil)
|
&types.Done{types.RespondTo(msg)}, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getDecodedPart(task *types.FetchMessageBodyPart, msg *imap.Message,
|
|
||||||
section *imap.BodySectionName) (io.Reader, error) {
|
|
||||||
var r io.Reader
|
|
||||||
var err error
|
|
||||||
|
|
||||||
r = msg.GetBody(section)
|
|
||||||
|
|
||||||
if r == nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
r = encodingReader(task.Encoding, r)
|
|
||||||
if task.Charset != "" {
|
|
||||||
r, err = message.CharsetReader(task.Charset, r)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return r, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func encodingReader(encoding string, r io.Reader) io.Reader {
|
|
||||||
reader := r
|
|
||||||
// email parts are encoded as 7bit (plaintext), quoted-printable, or base64
|
|
||||||
if strings.EqualFold(encoding, "base64") {
|
|
||||||
reader = base64.NewDecoder(base64.StdEncoding, r)
|
|
||||||
} else if strings.EqualFold(encoding, "quoted-printable") {
|
|
||||||
reader = quotedprintable.NewReader(r)
|
|
||||||
}
|
|
||||||
return reader
|
|
||||||
}
|
|
||||||
|
|
|
@ -104,10 +104,8 @@ type FetchFullMessages struct {
|
||||||
|
|
||||||
type FetchMessageBodyPart struct {
|
type FetchMessageBodyPart struct {
|
||||||
Message
|
Message
|
||||||
Uid uint32
|
Uid uint32
|
||||||
Part []int
|
Part []int
|
||||||
Encoding string
|
|
||||||
Charset string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeleteMessages struct {
|
type DeleteMessages struct {
|
||||||
|
|
Loading…
Reference in a new issue