diff --git a/src/inbox.rs b/src/inbox.rs index b064fad..4acbf73 100644 --- a/src/inbox.rs +++ b/src/inbox.rs @@ -170,6 +170,29 @@ pub(crate) fn fetch_body( extract_plain_text(&raw) } +/// Delete an email by sequence number (flag as \Deleted + expunge). +pub(crate) fn delete_email( + session: &mut Option, + seq: u32, + config: &Config, +) -> Result<(), String> { + let s = ensure_session(session, config)?; + let range = seq.to_string(); + match s { + ImapSession::Plain(s) => { + s.select("INBOX").map_err(|e| e.to_string())?; + s.store(&range, "+FLAGS (\\Deleted)").map_err(|e| e.to_string())?; + s.expunge().map_err(|e| e.to_string())?; + } + ImapSession::Tls(s) => { + s.select("INBOX").map_err(|e| e.to_string())?; + s.store(&range, "+FLAGS (\\Deleted)").map_err(|e| e.to_string())?; + s.expunge().map_err(|e| e.to_string())?; + } + } + Ok(()) +} + fn extract_raw_body(fetches: &[imap::types::Fetch]) -> Option> { fetches.first().and_then(|f| { f.body().map(|b| b.to_vec()) diff --git a/src/lib.rs b/src/lib.rs index 1fc1eb0..e80ff29 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,7 @@ enum WorkerCmd { Refresh, FetchMore { oldest_seq: u32 }, FetchBody { seq: u32 }, + Delete { seq: u32 }, Quit, } @@ -41,6 +42,7 @@ enum WorkerResult { Refreshed(Result), FetchedMore(Result<(Vec, u32), String>), Body { seq: u32, result: Result }, + Deleted(Result<(), String>), } fn worker_loop( @@ -64,6 +66,10 @@ fn worker_loop( let result = inbox::fetch_body(&mut session, seq, &config); let _ = result_tx.send(WorkerResult::Body { seq, result }); } + WorkerCmd::Delete { seq } => { + let result = inbox::delete_email(&mut session, seq, &config); + let _ = result_tx.send(WorkerResult::Deleted(result)); + } WorkerCmd::Quit => break, } } @@ -155,6 +161,11 @@ pub fn main(config: &Config, terminal: &mut Terminal>) } } } + WorkerResult::Deleted(result) => { + if let Err(e) = result { + error = Some(format!("Delete failed: {}", e)); + } + } } } @@ -248,7 +259,7 @@ pub fn main(config: &Config, terminal: &mut Terminal>) .scroll((preview_scroll, 0)); frame.render_widget(preview, layout[1]); - let status = Paragraph::new(" 'q' quit | 'r' refresh | ↑/↓ navigate | Tab switch pane") + let status = Paragraph::new(" 'q' quit | 'r' refresh | 'd' delete | ↑/↓ navigate | Tab switch pane") .style(Style::default().fg(Color::DarkGray)); frame.render_widget(status, layout[2]); })?; @@ -317,6 +328,33 @@ pub fn main(config: &Config, terminal: &mut Terminal>) preview_scroll = preview_scroll.saturating_sub(1); } } + KeyCode::Char('d') if focus == Focus::Inbox => { + if let Some(idx) = list_state.selected() { + if idx < emails.len() { + let seq = emails[idx].seq; + // Remove from UI immediately + emails.remove(idx); + if emails.is_empty() { + list_state.select(None); + preview_seq = None; + preview_body.clear(); + } else { + let new_idx = idx.min(emails.len().saturating_sub(1)); + list_state.select(Some(new_idx)); + let new_seq = emails[new_idx].seq; + if preview_seq != Some(new_seq) { + preview_seq = Some(new_seq); + preview_body.clear(); + preview_scroll = 0; + body_loading = true; + let _ = cmd_tx.send(WorkerCmd::FetchBody { seq: new_seq }); + } + } + // Delete on server in background + let _ = cmd_tx.send(WorkerCmd::Delete { seq }); + } + } + } _ => {} } }