Detailed changes
@@ -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 != "" {
@@ -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}
@@ -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,
"",
}
@@ -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)
@@ -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 {
@@ -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)