From 2cd6446d1399c4fd8b8046678773fdddcf08a068 Mon Sep 17 00:00:00 2001 From: Shautvast Date: Tue, 17 Feb 2026 20:03:20 +0100 Subject: [PATCH] keep existing session --- src/lib.rs | 127 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 76 insertions(+), 51 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2a02fcf..216e198 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ use std::io::{Error, Stdout}; use std::net::TcpStream; use std::time::{Duration, Instant}; -use crossterm::{event}; +use crossterm::event; use crossterm::event::{Event, KeyCode}; use ratatui::backend::CrosstermBackend; use ratatui::layout::{Constraint, Direction, Layout}; @@ -14,20 +14,86 @@ pub mod config; const POLL_INTERVAL: Duration = Duration::from_secs(30); -pub(crate) struct Email { +struct Email { subject: String, from: String, date: String, } -pub fn main(config: &Config, mut terminal: &mut Terminal>) -> Result<(), Error>{ - let mut inbox = fetch_inbox(config); +type ImapSession = imap::Session; + +fn connect(config: &Config) -> Result { + let imap_cfg = &config.imap; + let stream = + TcpStream::connect((&*imap_cfg.host, imap_cfg.port)).map_err(|e| e.to_string())?; + let client = imap::Client::new(stream); + let session = client + .login(&imap_cfg.username, &imap_cfg.password) + .map_err(|(e, _)| e.to_string())?; + Ok(session) +} + +fn fetch_inbox(session: &mut ImapSession) -> Result, String> { + session.select("INBOX").map_err(|e| e.to_string())?; + + let messages = session + .fetch("1:*", "BODY.PEEK[HEADER.FIELDS (SUBJECT FROM DATE)]") + .map_err(|e| e.to_string())?; + + let mut emails = Vec::new(); + for message in messages.iter() { + if let Some(body) = message.header() { + let header = String::from_utf8_lossy(body); + let mut subject = String::new(); + let mut from = String::new(); + let mut date = String::new(); + + for line in header.lines() { + if let Some(val) = line.strip_prefix("Subject: ") { + subject = val.to_string(); + } else if let Some(val) = line.strip_prefix("From: ") { + from = val.to_string(); + } else if let Some(val) = line.strip_prefix("Date: ") { + date = val.to_string(); + } + } + + emails.push(Email { subject, from, date }); + } + } + + Ok(emails) +} + +/// Refresh inbox using NOOP + fetch. Reconnects on error. +fn refresh_inbox( + session: &mut Option, + config: &Config, +) -> Result, String> { + // If we have a session, try NOOP to keep alive / detect changes + if let Some(s) = session.as_mut() { + if s.noop().is_ok() { + return fetch_inbox(s); + } + } + + // Session is dead or missing — reconnect + *session = None; + let mut new_session = connect(config)?; + let result = fetch_inbox(&mut new_session); + *session = Some(new_session); + result +} + +pub fn main(config: &Config, terminal: &mut Terminal>) -> Result<(), Error> { + let mut session = connect(config).ok(); + let mut inbox = refresh_inbox(&mut session, config); let mut last_fetch = Instant::now(); // --- Main loop --- loop { if last_fetch.elapsed() >= POLL_INTERVAL { - inbox = fetch_inbox(&config); + inbox = refresh_inbox(&mut session, config); last_fetch = Instant::now(); } @@ -83,7 +149,7 @@ pub fn main(config: &Config, mut terminal: &mut Terminal break, KeyCode::Char('r') => { - inbox = fetch_inbox(&config); + inbox = refresh_inbox(&mut session, config); last_fetch = Instant::now(); } _ => {} @@ -92,51 +158,10 @@ pub fn main(config: &Config, mut terminal: &mut Terminal Result, String> { - let imap_cfg = &config.imap; - let stream = - TcpStream::connect((&*imap_cfg.host, imap_cfg.port)).map_err(|e| e.to_string())?; - let client = imap::Client::new(stream); - let mut session = client - .login(&imap_cfg.username, &imap_cfg.password) - .map_err(|(e, _)| e.to_string())?; - - session.select("INBOX").map_err(|e| e.to_string())?; - - let mut emails = Vec::new(); - - let messages = session - .fetch("1:*", "BODY.PEEK[HEADER.FIELDS (SUBJECT FROM DATE)]") - .map_err(|e| e.to_string())?; - - for message in messages.iter() { - if let Some(body) = message.header() { - let header = String::from_utf8_lossy(body); - let mut subject = String::new(); - let mut from = String::new(); - let mut date = String::new(); - - for line in header.lines() { - if let Some(val) = line.strip_prefix("Subject: ") { - subject = val.to_string(); - } else if let Some(val) = line.strip_prefix("From: ") { - from = val.to_string(); - } else if let Some(val) = line.strip_prefix("Date: ") { - date = val.to_string(); - } - } - - emails.push(Email { - subject, - from, - date, - }); - } + // Clean up the session + if let Some(mut s) = session.take() { + let _ = s.logout(); } - let _ = session.logout(); - Ok(emails) + Ok(()) }