#[macro_use] extern crate serde; #[macro_use] extern crate log; #[macro_use] extern crate futures; mod config; mod mail; use anyhow::Result; use clap::Clap; use futures::future::{ select, Either::{Left, Right}, FutureExt, }; use tokio::sync::oneshot; use crate::config::{Config, MailAccountConfig, TlsMethod}; type ExitListener = oneshot::Receiver<()>; /// The panorama daemon runs in the background and communicates with other panorama components over Unix sockets. #[derive(Debug, Clap)] struct Options { // /// Config file path (defaults to XDG) // #[clap(long = "config", short = 'c')] // config_file: Option, /// Verbose mode (-v, -vv, -vvv, etc) #[clap(short = 'v', long = "verbose", parse(from_occurrences))] verbose: usize, } #[tokio::main] async fn main() -> Result<()> { let opt = Options::parse(); stderrlog::new() .module(module_path!()) .verbosity(opt.verbose) .init() .unwrap(); let (_, mut config_watcher) = config::spawn_config_watcher_system()?; loop { let (exit_tx, exit_rx) = oneshot::channel(); let new_config = config_watcher.borrow().clone(); tokio::spawn(run_with_config(new_config, exit_rx)); // wait till the config has changed, then tell the current thread to stop config_watcher.changed().await?; let _ = exit_tx.send(()); } } async fn run_with_config(config: Config, exit: ExitListener) -> Result<()> { debug!("new config"); let mut notify_mail_threads = Vec::new(); for (account_name, account) in config.mail_accounts { let (exit_tx, exit_rx) = oneshot::channel(); tokio::spawn(run_single_mail_account(account_name, account, exit_rx)); notify_mail_threads.push(exit_tx); } exit.await?; for exit_tx in notify_mail_threads { let _ = exit_tx.send(()); } Ok(()) } async fn run_single_mail_account( account_name: String, account: MailAccountConfig, exit: ExitListener, ) -> Result<()> { debug!("connecting to account {}", account_name); let imap_cookie = ImapClient::open( &account.imap.server, account.imap.port, matches!(account.imap.tls, TlsMethod::On), ); pin_mut!(imap_cookie); pin_mut!(exit); let (imap, exit) = match select(imap_cookie, exit).await { Left(res) => res, Right(_) => return Ok(()), }; debug!("connected to {}", account.imap.server); let imap = imap?; let mut exit = exit.fuse(); loop { select! { _ = exit => break, } } debug!("disconnecting from account {}", account_name); Ok(()) }