diff --git a/config/config.go b/config/config.go index 0d5e10633a2ec0e32b06730ac3db6a14c3dcb32c..b20393a78129513e333c8d2d5ad735a9f874fe3e 100644 --- a/config/config.go +++ b/config/config.go @@ -35,12 +35,11 @@ type Account struct { SMIMESignByDefault bool `json:"smime_sign_by_default,omitempty"` // Whether to enable S/MIME signing by default // PGP settings - PGPPublicKey string `json:"pgp_public_key,omitempty"` // Path to public key (.asc or .gpg) - PGPPrivateKey string `json:"pgp_private_key,omitempty"` // Path to private key (.asc or .gpg) - PGPKeySource string `json:"pgp_key_source,omitempty"` // "file" (default) or "yubikey" for hardware key - PGPPIN string `json:"-"` // YubiKey PIN (stored in keyring, not JSON) - PGPSignByDefault bool `json:"pgp_sign_by_default,omitempty"` // Auto-sign outgoing emails - PGPEncryptByDefault bool `json:"pgp_encrypt_by_default,omitempty"` // Auto-encrypt when recipient keys available + PGPPublicKey string `json:"pgp_public_key,omitempty"` // Path to public key (.asc or .gpg) + PGPPrivateKey string `json:"pgp_private_key,omitempty"` // Path to private key (.asc or .gpg) + PGPKeySource string `json:"pgp_key_source,omitempty"` // "file" (default) or "yubikey" for hardware key + PGPPIN string `json:"-"` // YubiKey PIN (stored in keyring, not JSON) + PGPSignByDefault bool `json:"pgp_sign_by_default,omitempty"` // Auto-sign outgoing emails // OAuth2 settings AuthMethod string `json:"auth_method,omitempty"` // "password" (default) or "oauth2" @@ -210,30 +209,29 @@ func LoadConfig() (*Config, error) { var needsMigration bool type rawAccount struct { - ID string `json:"id"` - Name string `json:"name"` - Email string `json:"email"` - Password string `json:"password,omitempty"` - ServiceProvider string `json:"service_provider"` - FetchEmail string `json:"fetch_email,omitempty"` - IMAPServer string `json:"imap_server,omitempty"` - IMAPPort int `json:"imap_port,omitempty"` - SMTPServer string `json:"smtp_server,omitempty"` - SMTPPort int `json:"smtp_port,omitempty"` - Insecure bool `json:"insecure,omitempty"` - SMIMECert string `json:"smime_cert,omitempty"` - SMIMEKey string `json:"smime_key,omitempty"` - SMIMESignByDefault bool `json:"smime_sign_by_default,omitempty"` - PGPPublicKey string `json:"pgp_public_key,omitempty"` - PGPPrivateKey string `json:"pgp_private_key,omitempty"` - PGPKeySource string `json:"pgp_key_source,omitempty"` - PGPSignByDefault bool `json:"pgp_sign_by_default,omitempty"` - PGPEncryptByDefault bool `json:"pgp_encrypt_by_default,omitempty"` - AuthMethod string `json:"auth_method,omitempty"` - Protocol string `json:"protocol,omitempty"` - JMAPEndpoint string `json:"jmap_endpoint,omitempty"` - POP3Server string `json:"pop3_server,omitempty"` - POP3Port int `json:"pop3_port,omitempty"` + ID string `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + Password string `json:"password,omitempty"` + ServiceProvider string `json:"service_provider"` + FetchEmail string `json:"fetch_email,omitempty"` + IMAPServer string `json:"imap_server,omitempty"` + IMAPPort int `json:"imap_port,omitempty"` + SMTPServer string `json:"smtp_server,omitempty"` + SMTPPort int `json:"smtp_port,omitempty"` + Insecure bool `json:"insecure,omitempty"` + SMIMECert string `json:"smime_cert,omitempty"` + SMIMEKey string `json:"smime_key,omitempty"` + SMIMESignByDefault bool `json:"smime_sign_by_default,omitempty"` + PGPPublicKey string `json:"pgp_public_key,omitempty"` + PGPPrivateKey string `json:"pgp_private_key,omitempty"` + PGPKeySource string `json:"pgp_key_source,omitempty"` + PGPSignByDefault bool `json:"pgp_sign_by_default,omitempty"` + AuthMethod string `json:"auth_method,omitempty"` + Protocol string `json:"protocol,omitempty"` + JMAPEndpoint string `json:"jmap_endpoint,omitempty"` + POP3Server string `json:"pop3_server,omitempty"` + POP3Port int `json:"pop3_port,omitempty"` } type diskConfig struct { Accounts []rawAccount `json:"accounts"` @@ -276,29 +274,28 @@ func LoadConfig() (*Config, error) { config.MailingLists = raw.MailingLists for _, rawAcc := range raw.Accounts { acc := Account{ - ID: rawAcc.ID, - Name: rawAcc.Name, - Email: rawAcc.Email, - ServiceProvider: rawAcc.ServiceProvider, - FetchEmail: rawAcc.FetchEmail, - IMAPServer: rawAcc.IMAPServer, - IMAPPort: rawAcc.IMAPPort, - SMTPServer: rawAcc.SMTPServer, - SMTPPort: rawAcc.SMTPPort, - Insecure: rawAcc.Insecure, - SMIMECert: rawAcc.SMIMECert, - SMIMEKey: rawAcc.SMIMEKey, - SMIMESignByDefault: rawAcc.SMIMESignByDefault, - PGPPublicKey: rawAcc.PGPPublicKey, - PGPPrivateKey: rawAcc.PGPPrivateKey, - PGPKeySource: rawAcc.PGPKeySource, - PGPSignByDefault: rawAcc.PGPSignByDefault, - PGPEncryptByDefault: rawAcc.PGPEncryptByDefault, - AuthMethod: rawAcc.AuthMethod, - Protocol: rawAcc.Protocol, - JMAPEndpoint: rawAcc.JMAPEndpoint, - POP3Server: rawAcc.POP3Server, - POP3Port: rawAcc.POP3Port, + ID: rawAcc.ID, + Name: rawAcc.Name, + Email: rawAcc.Email, + ServiceProvider: rawAcc.ServiceProvider, + FetchEmail: rawAcc.FetchEmail, + IMAPServer: rawAcc.IMAPServer, + IMAPPort: rawAcc.IMAPPort, + SMTPServer: rawAcc.SMTPServer, + SMTPPort: rawAcc.SMTPPort, + Insecure: rawAcc.Insecure, + SMIMECert: rawAcc.SMIMECert, + SMIMEKey: rawAcc.SMIMEKey, + SMIMESignByDefault: rawAcc.SMIMESignByDefault, + PGPPublicKey: rawAcc.PGPPublicKey, + PGPPrivateKey: rawAcc.PGPPrivateKey, + PGPKeySource: rawAcc.PGPKeySource, + PGPSignByDefault: rawAcc.PGPSignByDefault, + AuthMethod: rawAcc.AuthMethod, + Protocol: rawAcc.Protocol, + JMAPEndpoint: rawAcc.JMAPEndpoint, + POP3Server: rawAcc.POP3Server, + POP3Port: rawAcc.POP3Port, } if rawAcc.Password != "" { diff --git a/main.go b/main.go index 050debd6a36110bf04b6cf9985e5f4ba95185272..f7e3453e8938a2d61592a0944e97ddceeef280ad 100644 --- a/main.go +++ b/main.go @@ -1662,7 +1662,7 @@ func sendEmail(account *config.Account, msg tui.SendEmailMsg) tea.Cmd { attachments[filename] = fileData } - err := sender.SendEmail(account, recipients, cc, bcc, msg.Subject, body, string(htmlBody), images, attachments, msg.InReplyTo, msg.References, msg.SignSMIME, msg.EncryptSMIME, msg.SignPGP, msg.EncryptPGP) + err := sender.SendEmail(account, recipients, cc, bcc, msg.Subject, body, string(htmlBody), images, attachments, msg.InReplyTo, msg.References, msg.SignSMIME, msg.EncryptSMIME, msg.SignPGP, false) if err != nil { log.Printf("Failed to send email: %v", err) return tui.EmailResultMsg{Err: err} diff --git a/tui/composer.go b/tui/composer.go index 82444a0f91283736adf88d784bc71398170ef09b..f9edf9163c784932050408b38fe28dde3a60f56a 100644 --- a/tui/composer.go +++ b/tui/composer.go @@ -43,7 +43,6 @@ const ( focusSignature focusAttachment focusEncryptSMIME - focusEncryptPGP focusSend ) @@ -58,7 +57,6 @@ type Composer struct { signatureInput textarea.Model attachmentPaths []string encryptSMIME bool - encryptPGP bool width int height int confirmingExit bool @@ -404,11 +402,7 @@ func (m *Composer) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.encryptSMIME = !m.encryptSMIME } return m, nil - case focusEncryptPGP: - if msg.String() == "enter" || msg.String() == " " { - m.encryptPGP = !m.encryptPGP - } - return m, nil + case focusSend: if msg.String() == "enter" { acc := m.getSelectedAccount() @@ -432,7 +426,6 @@ func (m *Composer) Update(msg tea.Msg) (tea.Model, tea.Cmd) { SignSMIME: acc != nil && acc.SMIMESignByDefault, EncryptSMIME: m.encryptSMIME, SignPGP: acc != nil && acc.PGPSignByDefault, - EncryptPGP: m.encryptPGP, } } } @@ -538,15 +531,6 @@ func (m *Composer) View() tea.View { encField = focusedStyle.Render(fmt.Sprintf("> Encrypt Email (S/MIME): %s", encToggle)) } - pgpEncToggle := "[ ]" - if m.encryptPGP { - pgpEncToggle = "[x]" - } - pgpEncField := blurredStyle.Render(fmt.Sprintf(" Encrypt Email (PGP): %s", pgpEncToggle)) - if m.focusIndex == focusEncryptPGP { - pgpEncField = focusedStyle.Render(fmt.Sprintf("> Encrypt Email (PGP): %s", pgpEncToggle)) - } - // Build To field with suggestions toFieldView := m.toInput.View() if m.showSuggestions && len(m.suggestions) > 0 { @@ -593,8 +577,6 @@ func (m *Composer) View() tea.View { tip = "Enter: add file • backspace/d: remove last attachment" case focusEncryptSMIME: tip = "Press Space or Enter to toggle S/MIME encryption on or off." - case focusEncryptPGP: - tip = "Press Space or Enter to toggle PGP encryption on or off." case focusSend: tip = "Press Enter to send the email." } @@ -611,7 +593,6 @@ func (m *Composer) View() tea.View { m.signatureInput.View(), attachmentStyle.Render(attachmentField), smimeToggleStyle.Render(encField), - smimeToggleStyle.Render(pgpEncField), button, "", } diff --git a/tui/composer_test.go b/tui/composer_test.go index 5229c72bd30d7cc079129e06579e914e50fb9de6..9ec3d8d1391135f4d28330c9bf8e71d890afbe8b 100644 --- a/tui/composer_test.go +++ b/tui/composer_test.go @@ -71,18 +71,11 @@ func TestComposerUpdate(t *testing.T) { t.Errorf("After seven Tabs, focusIndex should be %d (focusEncryptSMIME), got %d", focusEncryptSMIME, composer.focusIndex) } - // Simulate pressing Tab again to move to the 'EncryptPGP' toggle. - model, _ = composer.Update(tea.KeyPressMsg{Code: tea.KeyTab}) - composer = model.(*Composer) - if composer.focusIndex != focusEncryptPGP { - t.Errorf("After eight Tabs, focusIndex should be %d (focusEncryptPGP), got %d", focusEncryptPGP, composer.focusIndex) - } - // Simulate pressing Tab again to move to the 'Send' button. model, _ = composer.Update(tea.KeyPressMsg{Code: tea.KeyTab}) composer = model.(*Composer) if composer.focusIndex != focusSend { - t.Errorf("After nine Tabs, focusIndex should be %d (focusSend), got %d", focusSend, composer.focusIndex) + t.Errorf("After eight Tabs, focusIndex should be %d (focusSend), got %d", focusSend, composer.focusIndex) } // Simulate one more Tab to wrap around. @@ -90,7 +83,7 @@ func TestComposerUpdate(t *testing.T) { model, _ = composer.Update(tea.KeyPressMsg{Code: tea.KeyTab}) composer = model.(*Composer) if composer.focusIndex != focusTo { - t.Errorf("After ten Tabs, focusIndex should wrap to %d (focusTo) since single account skips From, got %d", focusTo, composer.focusIndex) + t.Errorf("After nine Tabs, focusIndex should wrap to %d (focusTo) since single account skips From, got %d", focusTo, composer.focusIndex) } }) @@ -218,9 +211,7 @@ func TestComposerUpdate(t *testing.T) { multiComposer = model.(*Composer) model, _ = multiComposer.Update(tea.KeyPressMsg{Code: tea.KeyTab}) // Attachment -> EncryptSMIME multiComposer = model.(*Composer) - model, _ = multiComposer.Update(tea.KeyPressMsg{Code: tea.KeyTab}) // EncryptSMIME -> EncryptPGP - multiComposer = model.(*Composer) - model, _ = multiComposer.Update(tea.KeyPressMsg{Code: tea.KeyTab}) // EncryptPGP -> Send + model, _ = multiComposer.Update(tea.KeyPressMsg{Code: tea.KeyTab}) // EncryptSMIME -> Send multiComposer = model.(*Composer) model, _ = multiComposer.Update(tea.KeyPressMsg{Code: tea.KeyTab}) // Send -> From (wrap) multiComposer = model.(*Composer) diff --git a/tui/messages.go b/tui/messages.go index c24103858bfcf74166489833c1df01a188d6d464..ad7311cf414edb77e5ffab8250537d65dec351cd 100644 --- a/tui/messages.go +++ b/tui/messages.go @@ -36,7 +36,6 @@ type SendEmailMsg struct { SignSMIME bool // Whether to sign the email using S/MIME EncryptSMIME bool // Whether to encrypt the email using S/MIME SignPGP bool // Whether to sign the email using PGP - EncryptPGP bool // Whether to encrypt the email using PGP } type Credentials struct { diff --git a/tui/settings.go b/tui/settings.go index c063855e45241016442d94f0f2878b3e87539e0e..dc30f94da9d38d2e9b9cee1a059dcc365fb22ddf 100644 --- a/tui/settings.go +++ b/tui/settings.go @@ -312,10 +312,9 @@ func (m *Settings) updateAccounts(msg tea.KeyPressMsg) (tea.Model, tea.Cmd) { // 5: PGP Key Source toggle (file/yubikey) // 6: PGP PIN input (only shown if yubikey) // 7: PGP Sign By Default toggle -// 8: PGP Encrypt By Default toggle -// 9: Save button -// 10: Cancel button -const cryptoConfigMaxFocus = 10 +// 8: Save button +// 9: Cancel button +const cryptoConfigMaxFocus = 9 func (m *Settings) updateSMIMEConfig(msg tea.KeyPressMsg) (*Settings, tea.Cmd) { var cmds []tea.Cmd @@ -410,12 +409,7 @@ func (m *Settings) updateSMIMEConfig(msg tea.KeyPressMsg) (*Settings, tea.Cmd) { m.cfg.Accounts[m.editingAccountIdx].PGPSignByDefault = !m.cfg.Accounts[m.editingAccountIdx].PGPSignByDefault } return m, nil - case 8: // PGP encrypt toggle - if msg.String() == "enter" || msg.String() == " " { - m.cfg.Accounts[m.editingAccountIdx].PGPEncryptByDefault = !m.cfg.Accounts[m.editingAccountIdx].PGPEncryptByDefault - } - return m, nil - case 9: // Save + case 8: // Save if msg.String() == "enter" { m.cfg.Accounts[m.editingAccountIdx].SMIMECert = m.smimeCertInput.Value() m.cfg.Accounts[m.editingAccountIdx].SMIMEKey = m.smimeKeyInput.Value() @@ -427,7 +421,7 @@ func (m *Settings) updateSMIMEConfig(msg tea.KeyPressMsg) (*Settings, tea.Cmd) { m.state = SettingsAccounts return m, nil } - case 10: // Cancel + case 9: // Cancel if msg.String() == "enter" { m.state = SettingsAccounts return m, nil @@ -806,27 +800,17 @@ func (m *Settings) viewSMIMEConfig() string { b.WriteString(settingsBlurredStyle.Render(fmt.Sprintf(" Sign By Default: %s\n\n", pgpSignStatus))) } - pgpEncryptStatus := "OFF" - if account.PGPEncryptByDefault { - pgpEncryptStatus = "ON" - } - if m.focusIndex == 8 { - b.WriteString(settingsFocusedStyle.Render(fmt.Sprintf("> Encrypt By Default: %s\n\n", pgpEncryptStatus))) - } else { - b.WriteString(settingsBlurredStyle.Render(fmt.Sprintf(" Encrypt By Default: %s\n\n", pgpEncryptStatus))) - } - // --- Buttons --- saveBtn := "[ Save ]" cancelBtn := "[ Cancel ]" - if m.focusIndex == 9 { + if m.focusIndex == 8 { saveBtn = settingsFocusedStyle.Render(saveBtn) } else { saveBtn = settingsBlurredStyle.Render(saveBtn) } - if m.focusIndex == 10 { + if m.focusIndex == 9 { cancelBtn = settingsFocusedStyle.Render(cancelBtn) } else { cancelBtn = settingsBlurredStyle.Render(cancelBtn)