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(
|
||||
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{
|
||||
Uid: uid,
|
||||
Part: part,
|
||||
Encoding: partbs.Encoding,
|
||||
Charset: charset,
|
||||
Uid: uid,
|
||||
Part: part,
|
||||
}, func(resp types.WorkerMessage) {
|
||||
msg, ok := resp.(*types.MessageBodyPart)
|
||||
if !ok {
|
||||
|
|
|
@ -2,11 +2,7 @@ package imap
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/quotedprintable"
|
||||
"strings"
|
||||
|
||||
"github.com/emersion/go-imap"
|
||||
"github.com/emersion/go-message"
|
||||
|
@ -37,21 +33,90 @@ func (imapw *IMAPWorker) handleFetchMessageHeaders(
|
|||
imap.FetchUid,
|
||||
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(
|
||||
msg *types.FetchMessageBodyPart) {
|
||||
|
||||
imapw.worker.Logger.Printf("Fetching message part")
|
||||
section := &imap.BodySectionName{}
|
||||
section.Path = msg.Part
|
||||
items := []imap.FetchItem{
|
||||
imap.FetchFlags,
|
||||
imap.FetchUid,
|
||||
section.FetchItem(),
|
||||
|
||||
var partHeaderSection imap.BodySectionName
|
||||
partHeaderSection.Peek = true
|
||||
if len(msg.Part) > 0 {
|
||||
partHeaderSection.Specifier = imap.MIMESpecifier
|
||||
} 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(
|
||||
|
@ -65,85 +130,53 @@ func (imapw *IMAPWorker) handleFetchFullMessages(
|
|||
imap.FetchUid,
|
||||
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(
|
||||
msg types.WorkerMessage, uids []uint32, items []imap.FetchItem,
|
||||
section *imap.BodySectionName) {
|
||||
procFunc func(*imap.Message) error) {
|
||||
|
||||
messages := make(chan *imap.Message)
|
||||
done := make(chan error)
|
||||
|
||||
go func() {
|
||||
var reterr error
|
||||
for _msg := range messages {
|
||||
imapw.seqMap[_msg.SeqNum-1] = _msg.Uid
|
||||
switch msg := msg.(type) {
|
||||
case *types.FetchMessageHeaders:
|
||||
reader := _msg.GetBody(section)
|
||||
textprotoHeader, err := textproto.ReadHeader(bufio.NewReader(reader))
|
||||
if err != nil {
|
||||
done <- fmt.Errorf("could not read header: %v", err)
|
||||
return
|
||||
err := procFunc(_msg)
|
||||
if err != nil {
|
||||
if reterr == nil {
|
||||
reterr = 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)
|
||||
case *types.FetchFullMessages:
|
||||
r := _msg.GetBody(section)
|
||||
if r == nil {
|
||||
done <- fmt.Errorf("could not get section %#v", section)
|
||||
return
|
||||
// drain the channel upon error
|
||||
for range messages {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -165,35 +198,3 @@ func (imapw *IMAPWorker) handleFetchMessages(
|
|||
imapw.worker.PostMessage(
|
||||
&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 {
|
||||
Message
|
||||
Uid uint32
|
||||
Part []int
|
||||
Encoding string
|
||||
Charset string
|
||||
Uid uint32
|
||||
Part []int
|
||||
}
|
||||
|
||||
type DeleteMessages struct {
|
||||
|
|
Loading…
Reference in a new issue