summaryrefslogtreecommitdiff
path: root/worker/imap
diff options
context:
space:
mode:
authorReto Brunner <reto@labrat.space>2020-05-16 20:03:42 +0200
committerReto Brunner <reto@labrat.space>2020-05-16 20:03:42 +0200
commitbae678e8f20605b64596c9e976623f2a37247adb (patch)
tree14c90c4e74e2db7f180c94e479f425a5be8907c5 /worker/imap
parentea2646fc039a572491ba8cc8e2879b7bf61c25dd (diff)
downloadaerc-bae678e8f20605b64596c9e976623f2a37247adb.zip
imap: Remove FetchMessageBodyPart.{Encoding,Charset}
Fixes https://todo.sr.ht/~sircmpwn/aerc2/352 exactly as suggested by emersion.
Diffstat (limited to 'worker/imap')
-rw-r--r--worker/imap/fetch.go213
1 files changed, 107 insertions, 106 deletions
diff --git a/worker/imap/fetch.go b/worker/imap/fetch.go
index 9591ced..def0da8 100644
--- a/worker/imap/fetch.go
+++ b/worker/imap/fetch.go
@@ -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
+
+ var partHeaderSection imap.BodySectionName
+ partHeaderSection.Peek = true
+ if len(msg.Part) > 0 {
+ partHeaderSection.Specifier = imap.MIMESpecifier
+ } else {
+ partHeaderSection.Specifier = imap.HeaderSpecifier
+ }
+ 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.FetchFlags,
+ imap.FetchEnvelope,
imap.FetchUid,
- section.FetchItem(),
+ imap.FetchBodyStructure,
+ imap.FetchFlags,
+ partHeaderSection.FetchItem(),
+ partBodySection.FetchItem(),
}
- imapw.handleFetchMessages(msg, []uint32{msg.Uid}, items, section)
+ 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
- }
-
- 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
+ // drain the channel upon error
+ for range messages {
}
- 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
-}