From 3b98a4d0746605fce9e8ea761ad7afde72db05da Mon Sep 17 00:00:00 2001 From: drew Date: Sun, 7 Dec 2025 23:01:01 +0400 Subject: [PATCH] fix!: decode attatchments --- fetcher/fetcher.go | 32 +++++++++++++++++++++++++++++--- main.go | 21 +++++++++++++++++++-- tui/messages.go | 1 + 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/fetcher/fetcher.go b/fetcher/fetcher.go index 20929102a58ef827be2084adf26292f190ed6490..0ba07906b4382937aabd05db66f65d59842a8989 100644 --- a/fetcher/fetcher.go +++ b/fetcher/fetcher.go @@ -24,6 +24,7 @@ type Attachment struct { Filename string PartID string // Keep PartID to fetch on demand Data []byte + Encoding string // Store encoding for proper decoding } type Email struct { @@ -250,7 +251,11 @@ func FetchEmailBody(account *config.Account, uid uint32) (string, []Attachment, // Add as attachment if it has a disposition or a filename (and not just plain text) if filename != "" && (part.Disposition == "attachment" || part.Disposition == "inline" || part.MIMEType != "text") { - attachments = append(attachments, Attachment{Filename: filename, PartID: partID}) + attachments = append(attachments, Attachment{ + Filename: filename, + PartID: partID, + Encoding: part.Encoding, // Store encoding for proper decoding + }) } } @@ -345,7 +350,7 @@ func FetchEmailBody(account *config.Account, uid uint32) (string, []Attachment, return body, attachments, nil } -func FetchAttachment(account *config.Account, uid uint32, partID string) ([]byte, error) { +func FetchAttachment(account *config.Account, uid uint32, partID string, encoding string) ([]byte, error) { c, err := connect(account) if err != nil { return nil, err @@ -385,7 +390,28 @@ func FetchAttachment(account *config.Account, uid uint32, partID string) ([]byte return nil, fmt.Errorf("could not get attachment body") } - return ioutil.ReadAll(literal) + rawBytes, err := ioutil.ReadAll(literal) + if err != nil { + return nil, err + } + + switch strings.ToLower(encoding) { + case "base64": + decoder := base64.NewDecoder(base64.StdEncoding, bytes.NewReader(rawBytes)) + decoded, err := ioutil.ReadAll(decoder) + if err == nil { + return decoded, nil + } + return rawBytes, nil + case "quoted-printable": + decoded, err := ioutil.ReadAll(quotedprintable.NewReader(bytes.NewReader(rawBytes))) + if err == nil { + return decoded, nil + } + return rawBytes, nil + default: + return rawBytes, nil + } } func moveEmail(account *config.Account, uid uint32, destMailbox string) error { diff --git a/main.go b/main.go index 2aec244889062c0e591a44773faa6e3db55fc646..b93f820a405b87ced54368734deeb5224793e101 100644 --- a/main.go +++ b/main.go @@ -551,7 +551,23 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, nil } - return m, tea.Batch(m.current.Init(), downloadAttachmentCmd(account, email.UID, msg)) + // Find the correct attachment to get encoding + var encoding string + for _, att := range email.Attachments { + if att.PartID == msg.PartID { + encoding = att.Encoding + break + } + } + newMsg := tui.DownloadAttachmentMsg{ + Index: msg.Index, + Filename: msg.Filename, + PartID: msg.PartID, + Data: msg.Data, + AccountID: msg.AccountID, + Encoding: encoding, + } + return m, tea.Batch(m.current.Init(), downloadAttachmentCmd(account, email.UID, newMsg)) case tui.AttachmentDownloadedMsg: var statusMsg string @@ -861,7 +877,8 @@ func archiveEmailCmd(account *config.Account, uid uint32, accountID string) tea. func downloadAttachmentCmd(account *config.Account, uid uint32, msg tui.DownloadAttachmentMsg) tea.Cmd { return func() tea.Msg { - data, err := fetcher.FetchAttachment(account, uid, msg.PartID) + // Download and decode the attachment using encoding provided in msg.Encoding. + data, err := fetcher.FetchAttachment(account, uid, msg.PartID, msg.Encoding) if err != nil { return tui.AttachmentDownloadedMsg{Err: err} } diff --git a/tui/messages.go b/tui/messages.go index a659a572a38e00e3d72af5ab89fe7cd351655be6..e2a7cacd9748ede4f602935c974bbdb328263494 100644 --- a/tui/messages.go +++ b/tui/messages.go @@ -109,6 +109,7 @@ type DownloadAttachmentMsg struct { PartID string Data []byte AccountID string + Encoding string } type AttachmentDownloadedMsg struct {