diff --git a/src/config.rs b/src/config.rs index 6a24f35..e34d3e5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -5,12 +5,21 @@ use std::process::Command; pub struct ImapStoreConfig { pub name: String, pub host: String, + pub port: Option, pub user: String, pub pass: Option, pub pass_command: Option, + pub cert_file: Option, } impl ImapStoreConfig { + pub fn port(&self) -> u16 { + if let Some(port) = self.port { + return port; + } + + 993 + } pub fn password(&self) -> String { if let Some(pass) = &self.pass { return pass.to_string(); @@ -56,9 +65,11 @@ impl Config { enum ConfigLine { ImapStore(String), Host(String), + Port(u16), User(String), Pass(String), PassCommand(String), + CertFile(String), Channel(String), Near(String), @@ -76,9 +87,11 @@ impl TryFrom<&str> for ConfigLine { match key { "IMAPStore" => Ok(ConfigLine::ImapStore(value)), "Host" => Ok(ConfigLine::Host(value)), + "Port" => Ok(ConfigLine::Port(value.parse().unwrap())), "User" => Ok(ConfigLine::User(value)), "Pass" => Ok(ConfigLine::Pass(remove_quotes(value))), "PassCmd" => Ok(ConfigLine::PassCommand(remove_quotes(value))), + "CertificateFile" => Ok(ConfigLine::CertFile(value)), "Channel" => Ok(ConfigLine::Channel(value)), "Near" => Ok(ConfigLine::Near(value)), @@ -136,6 +149,10 @@ pub fn from_file(config_path: &str) -> Config { let store = config.imap_stores.last_mut().unwrap(); store.host = host; } + ConfigLine::Port(port) => { + let store = config.imap_stores.last_mut().unwrap(); + store.port = Some(port); + } ConfigLine::User(user) => { let store = config.imap_stores.last_mut().unwrap(); store.user = user; @@ -148,6 +165,10 @@ pub fn from_file(config_path: &str) -> Config { let store = config.imap_stores.last_mut().unwrap(); store.pass_command = Some(command); } + ConfigLine::CertFile(cert_file) => { + let store = config.imap_stores.last_mut().unwrap(); + store.cert_file = Some(cert_file); + } ConfigLine::Channel(name) => { let mut channel_config = ChannelConfig::default(); diff --git a/src/main.rs b/src/main.rs index b48c77f..fc52d0f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,24 +3,36 @@ mod config; use std::process::Command; use std::thread; +use config::ImapStoreConfig; use imap::{ImapConnection, Session}; -fn connect(host: String, user: String, pass: String) -> Option>> { - let client = imap::ClientBuilder::new(host.clone(), 993) +fn connect(config: &ImapStoreConfig) -> Option>> { + let mut client_builder = imap::ClientBuilder::new(config.host.clone(), config.port()) .mode(imap::ConnectionMode::AutoTls) - .tls_kind(imap::TlsKind::Rust) + .tls_kind(imap::TlsKind::Rust); + + // For now disable skipping tls verification if we have a cert file. I will need to refactor + // this to setup the TPC connection manually to support this. As we have passed in a + // certificate we are assuming its all good. If we really want this to be secure for now we + // need to setup the certificates in the system root store. + if config.cert_file.is_some() { + log::warn!("Skipping tls verification for {}", &config.host); + client_builder = client_builder.danger_skip_tls_verify(true); + } + + let client = client_builder .connect() .expect("Could not connect to the server"); let mut session = client - .login(user, pass) + .login(&config.user, config.password()) .expect("Unable to login please ensure yor credentials are correct"); let capabilities = session.capabilities().expect("Unable to get capabilities"); if !capabilities.has_str("IDLE") { log::info!( "Skipping connection, {} dose not support idle connections", - &host + &config.host ); return None; @@ -55,12 +67,13 @@ fn main() { let channel_name = channel.name.clone(); watchers.push(thread::spawn(move || { - let mut session = connect( - imap_store.host.clone(), - imap_store.user.clone(), - imap_store.password().clone(), - ) - .unwrap(); + let mut session = match connect(&imap_store) { + Some(session) => session, + None => { + log::error!("Unable to connect to channel {}", channel_name); + return; + } + }; log::info!("Watching for messages on channel {}", channel_name); @@ -71,14 +84,9 @@ fn main() { if result.is_err() { log::error!("Error while idling: {:?}", result); - thread::sleep(std::time::Duration::from_secs(10)); - session = connect( - imap_store.host.clone(), - imap_store.user.clone(), - imap_store.password().clone(), - ) - .unwrap(); + thread::sleep(std::time::Duration::from_secs(10)); + session = connect(&imap_store).unwrap(); continue; }