mirror of
https://git.sr.ht/~rjarry/aerc
synced 2026-03-02 18:23:33 +01:00
Parse multipart messages on a best-efforts basis. Allow the user to see as much of the message as possible, but log the errors. If a charset or encoding error is encountered for a message part of a multipart message, the error is logged and ignored. In those cases, we still get a valid message body but the content is just not decoded or converted. No error will be propagated. If a multipart message cannot be parsed, ParseEntityStructure will return a multipart error. This error indicates that the message is malformed and there is nothing more we can do. The caller is then advised to use a single text/plain body structure using CreateTextPlainPart() to provide the entire message content to the user. Fixes: https://todo.sr.ht/~rjarry/aerc/288 Signed-off-by: Koni Marti <koni.marti@gmail.com> Acked-by: Robin Jarry <robin@jarry.cc>
85 lines
1.8 KiB
Go
85 lines
1.8 KiB
Go
package lib
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
|
|
"github.com/ProtonMail/go-crypto/openpgp"
|
|
_ "github.com/emersion/go-message/charset"
|
|
|
|
"git.sr.ht/~rjarry/aerc/lib/crypto"
|
|
"git.sr.ht/~rjarry/aerc/lib/log"
|
|
"git.sr.ht/~rjarry/aerc/lib/rfc822"
|
|
"git.sr.ht/~rjarry/aerc/models"
|
|
)
|
|
|
|
// EmlMessage implements the RawMessage interface
|
|
type EmlMessage []byte
|
|
|
|
func (fm *EmlMessage) NewReader() (io.ReadCloser, error) {
|
|
return io.NopCloser(bytes.NewReader(*fm)), nil
|
|
}
|
|
|
|
func (fm *EmlMessage) UID() models.UID {
|
|
return ""
|
|
}
|
|
|
|
func (fm *EmlMessage) Labels() ([]string, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (fm *EmlMessage) ModelFlags() (models.Flags, error) {
|
|
return models.SeenFlag, nil
|
|
}
|
|
|
|
// NewEmlMessageView provides a MessageView for a full message that is not
|
|
// stored in a message store
|
|
func NewEmlMessageView(full []byte, pgp crypto.Provider,
|
|
decryptKeys openpgp.PromptFunction, cb func(MessageView, error),
|
|
) {
|
|
eml := EmlMessage(full)
|
|
messageInfo, err := rfc822.MessageInfo(&eml)
|
|
if err != nil {
|
|
cb(nil, err)
|
|
return
|
|
}
|
|
msv := &MessageStoreView{
|
|
messageInfo: messageInfo,
|
|
messageStore: nil,
|
|
message: full,
|
|
details: nil,
|
|
bodyStructure: nil,
|
|
setSeen: false,
|
|
}
|
|
|
|
if usePGP(messageInfo.BodyStructure) {
|
|
reader := rfc822.NewCRLFReader(bytes.NewReader(full))
|
|
md, err := pgp.Decrypt(reader, decryptKeys)
|
|
if err != nil {
|
|
cb(nil, err)
|
|
return
|
|
}
|
|
msv.details = md
|
|
msv.message, err = io.ReadAll(md.Body)
|
|
if err != nil {
|
|
cb(nil, err)
|
|
return
|
|
}
|
|
}
|
|
entity, err := rfc822.ReadMessage(bytes.NewBuffer(msv.message))
|
|
if err != nil {
|
|
cb(nil, err)
|
|
return
|
|
}
|
|
bs, err := rfc822.ParseEntityStructure(entity)
|
|
if rfc822.IsMultipartError(err) {
|
|
log.Warnf("EmlView: %v", err)
|
|
bs = rfc822.CreateTextPlainBody()
|
|
} else if err != nil {
|
|
cb(nil, err)
|
|
return
|
|
}
|
|
msv.bodyStructure = bs
|
|
cb(msv, nil)
|
|
}
|