diff --git a/fetcher/fetcher.go b/fetcher/fetcher.go index 753bc2b2d4ec5841b0b40660191b52b6d7212a00..8ec150d3f5422c7e114c2f76e00c0903141e8150 100644 --- a/fetcher/fetcher.go +++ b/fetcher/fetcher.go @@ -341,8 +341,8 @@ func FetchEmailBodyFromMailbox(account *config.Account, mailbox string, uid uint return "", nil, fmt.Errorf("no message or body structure found with UID %d", uid) } - var plainPartID string - var htmlPartID string + var plainPartID, plainPartEncoding string + var htmlPartID, htmlPartEncoding string var attachments []Attachment var checkPart func(part *imap.BodyStructure, partID string) checkPart = func(part *imap.BodyStructure, partID string) { @@ -353,10 +353,12 @@ func FetchEmailBodyFromMailbox(account *config.Account, mailbox string, uid uint case "html": if htmlPartID == "" { htmlPartID = partID + htmlPartEncoding = part.Encoding } case "plain": if plainPartID == "" { plainPartID = partID + plainPartEncoding = part.Encoding } } } @@ -444,10 +446,13 @@ func FetchEmailBodyFromMailbox(account *config.Account, mailbox string, uid uint var body string textPartID := "" + textPartEncoding := "" if htmlPartID != "" { textPartID = htmlPartID + textPartEncoding = htmlPartEncoding } else if plainPartID != "" { textPartID = plainPartID + textPartEncoding = plainPartEncoding } if os.Getenv("DEBUG_KITTY_IMAGES") != "" { msg := fmt.Sprintf("[kitty-img] body selection html=%s plain=%s chosen=%s\n", htmlPartID, plainPartID, textPartID) @@ -481,38 +486,12 @@ func FetchEmailBodyFromMailbox(account *config.Account, mailbox string, uid uint if partMsg != nil { literal := partMsg.GetBody(section) if literal != nil { - // The new decoding logic starts here buf, _ := ioutil.ReadAll(literal) - mr, err := mail.CreateReader(bytes.NewReader(buf)) - if err != nil { - body = string(buf) + // Use the encoding from BodyStructure to decode + if decoded, err := decodeAttachmentData(buf, textPartEncoding); err == nil { + body = string(decoded) } else { - p, err := mr.NextPart() - if err != nil { - body = string(buf) - } else { - encoding := p.Header.Get("Content-Transfer-Encoding") - bodyBytes, _ := ioutil.ReadAll(p.Body) - - switch strings.ToLower(encoding) { - case "base64": - decoded, err := base64.StdEncoding.DecodeString(string(bodyBytes)) - if err == nil { - body = string(decoded) - } else { - body = string(bodyBytes) - } - case "quoted-printable": - decoded, err := ioutil.ReadAll(quotedprintable.NewReader(strings.NewReader(string(bodyBytes)))) - if err == nil { - body = string(decoded) - } else { - body = string(bodyBytes) - } - default: - body = string(bodyBytes) - } - } + body = string(buf) } } } diff --git a/main.go b/main.go index 5e9039073a4692c13a41650a22c369323cb86144..568e794bab6886e6a6ef8732ceeb7560840c39de 100644 --- a/main.go +++ b/main.go @@ -599,6 +599,37 @@ func (m *mainModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.current, _ = m.current.Update(tea.WindowSizeMsg{Width: m.width, Height: m.height}) return m, m.current.Init() + case tui.ForwardEmailMsg: + subject := msg.Email.Subject + if !strings.HasPrefix(strings.ToLower(subject), "fwd:") { + subject = "Fwd: " + subject + } + + forwardHeader := fmt.Sprintf("\n\n---------- Forwarded message ----------\nFrom: %s\nDate: %s\nSubject: %s\nTo: %s\n\n", + msg.Email.From, + msg.Email.Date.Format("Mon, Jan 2, 2006 at 3:04 PM"), + msg.Email.Subject, + msg.Email.To, + ) + + body := forwardHeader + msg.Email.Body + + var composer *tui.Composer + if m.config != nil && len(m.config.Accounts) > 0 { + // Use the account that received the email + accountID := msg.Email.AccountID + if accountID == "" { + accountID = m.config.GetFirstAccount().ID + } + composer = tui.NewComposerWithAccounts(m.config.Accounts, accountID, "", subject, body) + } else { + composer = tui.NewComposer("", "", subject, body) + } + + m.current = composer + m.current, _ = m.current.Update(tea.WindowSizeMsg{Width: m.width, Height: m.height}) + return m, m.current.Init() + case tui.GoToFilePickerMsg: m.previousModel = m.current wd, _ := os.Getwd() diff --git a/tui/email_view.go b/tui/email_view.go index 7ce722a3595049a224da267d9cc57f1677de5b9d..5da1c3a2100a5136abf79284a290f89865ba1bf5 100644 --- a/tui/email_view.go +++ b/tui/email_view.go @@ -122,6 +122,10 @@ func (m *EmailView) Update(msg tea.Msg) (tea.Model, tea.Cmd) { // Clear Kitty graphics before opening composer clearKittyGraphics() return m, func() tea.Msg { return ReplyToEmailMsg{Email: m.email} } + case "f": + // Clear Kitty graphics before opening composer + clearKittyGraphics() + return m, func() tea.Msg { return ForwardEmailMsg{Email: m.email} } case "d": accountID := m.accountID uid := m.email.UID @@ -184,7 +188,7 @@ func (m *EmailView) View() string { if m.focusOnAttachments { help = helpStyle.Render("↑/↓: navigate • enter: download • esc/tab: back to email body") } else { - help = helpStyle.Render("\uf112 r: reply • \uea81 d: delete • \uea98 a: archive • \uf435 tab: focus attachments • \ueb06 esc: back to inbox") + help = helpStyle.Render("\uf112 r: reply • \uf064 f: forward • \uea81 d: delete • \uea98 a: archive • \uf435 tab: focus attachments • \ueb06 esc: back to inbox") } var attachmentView string diff --git a/tui/messages.go b/tui/messages.go index 7c48f546e4808e3b7f00b3690fd7a69e3462c789..f7f504377465e56a44a366c0a66ef882e7efaae4 100644 --- a/tui/messages.go +++ b/tui/messages.go @@ -97,6 +97,10 @@ type ReplyToEmailMsg struct { Email fetcher.Email } +type ForwardEmailMsg struct { + Email fetcher.Email +} + type SetComposerCursorToStartMsg struct{} type GoToFilePickerMsg struct{}