@@ -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)
}
}
}
@@ -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()
@@ -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
@@ -97,6 +97,10 @@ type ReplyToEmailMsg struct {
Email fetcher.Email
}
+type ForwardEmailMsg struct {
+ Email fetcher.Email
+}
+
type SetComposerCursorToStartMsg struct{}
type GoToFilePickerMsg struct{}