diff --git a/ui/src/conf/accounts.rs b/ui/src/conf/accounts.rs index c3c2cf0c7..8cd28a04e 100644 --- a/ui/src/conf/accounts.rs +++ b/ui/src/conf/accounts.rs @@ -501,6 +501,19 @@ impl Account { envelope.field_from_to_string(), ) }; + #[cfg(feature = "sqlite3")] + { + if let Err(err) = crate::sqlite3::insert(&envelope, &self.backend) { + melib::log( + format!( + "Failed to insert envelope {} in cache: {}", + envelope.message_id_display(), + err.to_string() + ), + melib::ERROR, + ); + } + } self.collection.insert(*envelope, folder_hash); if self .sent_folder @@ -799,12 +812,17 @@ impl Account { ret } + #[allow(unused_variables)] pub fn search( &self, search_term: &str, sort: (SortField, SortOrder), folder_hash: FolderHash, ) -> Result> { + if self.settings.account().format() == "imap" { + return Err(MeliError::new("No search support for IMAP yet.")); + } + #[cfg(feature = "sqlite3")] { crate::sqlite3::search(search_term, sort) diff --git a/ui/src/sqlite3.rs b/ui/src/sqlite3.rs index fa8b4b301..d545a8e7c 100644 --- a/ui/src/sqlite3.rs +++ b/ui/src/sqlite3.rs @@ -20,7 +20,8 @@ */ use melib::{ - email::EnvelopeHash, + backends::MailBackend, + email::{Envelope, EnvelopeHash}, log, thread::{SortField, SortOrder}, MeliError, Result, StackVec, ERROR, @@ -62,41 +63,19 @@ fn fts5_bareword(w: &str) -> Cow { } } -pub fn open_db(context: &crate::state::Context) -> Result { +pub fn open_db() -> Result { let data_dir = xdg::BaseDirectories::with_prefix("meli").map_err(|e| MeliError::new(e.to_string()))?; - let conn = Connection::open( - data_dir - .place_data_file("index.db") - .map_err(|e| MeliError::new(e.to_string()))?, - ) - .map_err(|e| MeliError::new(e.to_string()))?; - //let conn = Connection::open_in_memory().map_err(|e| MeliError::new(e.to_string()))?; - - /* - * - pub struct Envelope { - date: String, - from: Vec
, - to: Vec
, - cc: Vec
, - bcc: Vec
, - subject: Option>, - message_id: MessageID, - in_reply_to: Option, - references: Option, - other_headers: FnvHashMap, - - timestamp: UnixTimestamp, - thread: ThreadHash, - - hash: EnvelopeHash, - - flags: Flag, - has_attachments: bool, + let db_path = data_dir + .place_data_file("index.db") + .map_err(|e| MeliError::new(e.to_string()))?; + if !db_path.exists() { + log( + format!("Creating index database in {}", db_path.display()), + melib::INFO, + ); } - */ - + let conn = Connection::open(db_path).map_err(|e| MeliError::new(e.to_string()))?; conn.execute_batch( "CREATE TABLE IF NOT EXISTS envelopes ( id INTEGER PRIMARY KEY, @@ -162,15 +141,56 @@ END; ", Ok(conn) } -pub fn insert(context: &mut crate::state::Context) -> Result<()> { - let data_dir = - xdg::BaseDirectories::with_prefix("meli").map_err(|e| MeliError::new(e.to_string()))?; - let conn = Connection::open( - data_dir - .place_data_file("index.db") - .map_err(|e| MeliError::new(e.to_string()))?, - ) - .map_err(|e| MeliError::new(e.to_string()))?; +pub fn insert(envelope: &Envelope, backend: &Arc>>) -> Result<()> { + let conn = open_db()?; + let backend_lck = backend.read().unwrap(); + let op = backend_lck.operation(envelope.hash()); + let body = match envelope.body(op) { + Ok(body) => body.text(), + Err(err) => { + debug!( + "{}", + format!( + "Failed to open envelope {}: {}", + envelope.message_id_display(), + err.to_string() + ) + ); + log( + format!( + "Failed to open envelope {}: {}", + envelope.message_id_display(), + err.to_string() + ), + ERROR, + ); + return Err(err); + } + }; + if let Err(err) = conn.execute( + "INSERT OR REPLACE INTO envelopes (hash, date, _from, _to, cc, bcc, subject, message_id, in_reply_to, _references, flags, has_attachments, body_text, timestamp) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14)", + params![envelope.hash().to_be_bytes().to_vec(), envelope.date_as_str(), envelope.field_from_to_string(), envelope.field_to_to_string(), envelope.field_cc_to_string(), envelope.field_bcc_to_string(), envelope.subject().into_owned().trim_end_matches('\u{0}'), envelope.message_id_display().to_string(), envelope.in_reply_to_display().map(|f| f.to_string()).unwrap_or(String::new()), envelope.field_references_to_string(), i64::from(envelope.flags().bits()), if envelope.has_attachments() { 1 } else { 0 }, body, envelope.date().to_be_bytes().to_vec()], + ) + .map_err(|e| MeliError::new(e.to_string())) { + debug!( + "Failed to insert envelope {}: {}", + envelope.message_id_display(), + err.to_string() + ); + log( + format!( + "Failed to insert envelope {}: {}", + envelope.message_id_display(), + err.to_string() + ), + ERROR, + ); + } + Ok(()) +} +pub fn index(context: &mut crate::state::Context) -> Result<()> { + let conn = open_db()?; let work_context = context.work_controller().get_context(); let mutexes = context .accounts @@ -267,14 +287,7 @@ pub fn search( term: &str, (sort_field, sort_order): (SortField, SortOrder), ) -> Result> { - let data_dir = - xdg::BaseDirectories::with_prefix("meli").map_err(|e| MeliError::new(e.to_string()))?; - let conn = Connection::open( - data_dir - .place_data_file("index.db") - .map_err(|e| MeliError::new(e.to_string()))?, - ) - .map_err(|e| MeliError::new(e.to_string()))?; + let conn = open_db()?; let sort_field = match debug!(sort_field) { SortField::Subject => "subject", @@ -307,15 +320,7 @@ pub fn search( } pub fn from(term: &str) -> Result> { - let data_dir = - xdg::BaseDirectories::with_prefix("meli").map_err(|e| MeliError::new(e.to_string()))?; - let conn = Connection::open_with_flags( - data_dir - .place_data_file("index.db") - .map_err(|e| MeliError::new(e.to_string()))?, - rusqlite::OpenFlags::SQLITE_OPEN_READ_ONLY, - ) - .map_err(|e| MeliError::new(e.to_string()))?; + let conn = open_db()?; let mut stmt = conn .prepare("SELECT hash FROM envelopes WHERE _from LIKE ?;") .map_err(|e| MeliError::new(e.to_string()))?; diff --git a/ui/src/state.rs b/ui/src/state.rs index 974e3884b..b50fad63a 100644 --- a/ui/src/state.rs +++ b/ui/src/state.rs @@ -529,13 +529,6 @@ impl State { /// Convert user commands to actions/method calls. fn parse_command(&mut self, cmd: &str) { - if cmd == "insert" { - return; - } else if cmd.starts_with("_from") { - debug!(crate::sqlite3::from(&cmd["_from".len()..])); - return; - } - let result = parse_command(&cmd.as_bytes()).to_full_result(); if let Ok(v) = result { @@ -571,7 +564,7 @@ impl State { )); } } - AccountAction(_, ReIndex) => match crate::sqlite3::insert(&mut self.context) { + AccountAction(_, ReIndex) => match crate::sqlite3::index(&mut self.context) { Ok(()) => { self.context.replies.push_back(UIEvent::Notification( None,