//! We use a stubbornly stupid algorithm where we just //! recursively drill down into the appropriate folder //! until we find `emlx` files and return those. use rayon::prelude::*; use walkdir::WalkDir; use super::super::shared::filesystem::emails_in; use ps_core::eyre::{eyre, Result}; use ps_core::tracing; use ps_core::{Config, Message, MessageSender}; use super::mail::Mail; use std::path::PathBuf; pub fn read_emails(config: &Config, sender: MessageSender) -> Result> { // on macOS, we might need permission for the `Library` folder... match std::fs::read_dir(&config.emails_folder_path) { Ok(_) => (), Err(e) => match e.kind() { #[cfg(target_os = "macos")] std::io::ErrorKind::PermissionDenied => { tracing::info!("Could not read folder: {}", e); if let Err(e) = sender.send(Message::MissingPermissions) { tracing::error!("Error sending: {}", e); } // We should return early now, otherwise the code below will send a different // error return Ok(Vec::new()); } _ => { if let Err(e) = sender.send(Message::Error(eyre!("Error: {:?}", &e))) { tracing::error!("Error sending: {}", e); } } }, } // As `walkdir` does not support `par_iter` (see https://www.reddit.com/r/rust/comments/6eif7r/walkdir_users_we_need_you/) // - -we first collect all folders, // then all sub-folders in those ending in mboxending in .mbox and then iterate over them in paralell let folders: Vec = WalkDir::new(&config.emails_folder_path) .into_iter() .filter_map(|e| match e { Ok(n) if n.path().is_dir() && n.path() .to_str() .map(|e| e.contains(".mbox")) .unwrap_or(false) => { tracing::trace!("Found folder {}", n.path().display()); Some(n.path().to_path_buf()) } Err(e) => { tracing::info!("Could not read folder: {}", e); if let Err(e) = sender.send(Message::Error(eyre!("Could not read folder: {:?}", e))) { tracing::error!("Error sending error {}", e); } None } _ => None, }) .collect(); sender.send(Message::ReadTotal(folders.len()))?; let mails: Vec = folders .into_par_iter() .filter_map( |path| match emails_in(path.clone(), sender.clone(), Mail::new) { Ok(n) => Some(n), Err(e) => { tracing::error!("{} {:?}", path.display(), &e); if let Err(e) = sender.send(Message::Error(eyre!( "Could read mails in {}: {:?}", path.display(), e ))) { tracing::error!("Error sending error {}", e); } None } }, ) .flatten() .collect(); Ok(mails) }