diff --git a/src/config.rs b/src/config.rs index e34d3e5..1e31f10 100644 --- a/src/config.rs +++ b/src/config.rs @@ -40,17 +40,24 @@ impl ImapStoreConfig { } } -#[derive(Debug, Default)] +#[derive(Debug, Default, Clone)] pub struct ChannelConfig { pub name: String, pub near: String, pub far: String, } +#[derive(Debug, Default, Clone)] +pub struct GroupConfig { + pub name: String, + pub channels: Vec<(String, String)>, +} + #[derive(Debug, Default)] pub struct Config { pub channels: Vec, pub imap_stores: Vec, + pub groups: Vec, } impl Config { @@ -60,6 +67,20 @@ impl Config { .find(|store| format!(":{}:", store.name) == name) .map(|store| store.clone()) } + + pub fn find_channel(&self, name: &str) -> Option { + self.channels + .iter() + .find(|channel| channel.name == name) + .map(|channel| channel.clone()) + } + + pub fn find_group(&self, name: &str) -> Option { + self.groups + .iter() + .find(|group| group.name == name) + .map(|group| group.clone()) + } } enum ConfigLine { @@ -75,6 +96,9 @@ enum ConfigLine { Near(String), Far(String), + Group(String), + Channels(String), + End, } @@ -97,6 +121,9 @@ impl TryFrom<&str> for ConfigLine { "Near" => Ok(ConfigLine::Near(value)), "Far" => Ok(ConfigLine::Far(value)), + "Group" => Ok(ConfigLine::Group(value)), + "Channels" => Ok(ConfigLine::Channels(value)), + _ => { if value == "" { return Ok(ConfigLine::End); @@ -143,7 +170,7 @@ pub fn from_file(config_path: &str) -> Config { ConfigLine::ImapStore(name) => { let mut imap_store_config = ImapStoreConfig::default(); imap_store_config.name = name; - config.imap_stores.push(imap_store_config) + config.imap_stores.push(imap_store_config); } ConfigLine::Host(host) => { let store = config.imap_stores.last_mut().unwrap(); @@ -184,6 +211,27 @@ pub fn from_file(config_path: &str) -> Config { channel.near = near; } + ConfigLine::Group(name) => { + let mut group = GroupConfig::default(); + group.name = name; + + config.groups.push(group); + } + ConfigLine::Channels(channels) => { + let group = config.groups.last_mut().unwrap(); + group.channels = channels + .split(',') + .map(|channel| { + let mut iter = channel.trim().split(':'); + + ( + iter.next().unwrap_or("").to_string(), + iter.next().unwrap_or("").to_string(), + ) + }) + .collect(); + } + ConfigLine::End => {} } } diff --git a/src/main.rs b/src/main.rs index fc52d0f..4a80cbe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ use std::thread; use config::ImapStoreConfig; use imap::{ImapConnection, Session}; -fn connect(config: &ImapStoreConfig) -> Option>> { +fn connect(config: &ImapStoreConfig, mailbox: &String) -> Option>> { let mut client_builder = imap::ClientBuilder::new(config.host.clone(), config.port()) .mode(imap::ConnectionMode::AutoTls) .tls_kind(imap::TlsKind::Rust); @@ -38,7 +38,7 @@ fn connect(config: &ImapStoreConfig) -> Option>> return None; } - session.select("INBOX").expect("Unable to select folder"); + session.select(mailbox).expect("Unable to select folder"); Some(session) } @@ -56,18 +56,32 @@ fn main() { }; let config = config::from_file(&format!("{home}/.mbsyncrc")); + let mbwatch_group = match config.find_group("mbwatch") { + Some(group) => group, + None => panic!("Unable to find mbwatch group in your mbsync config"), + }; let mut watchers = Vec::new(); - for channel in &config.channels { + for (channel_name, mailbox) in &mbwatch_group.channels { + let channel = match config.find_channel(channel_name) { + Some(channel) => channel, + None => panic!("Unable to find channel {}", channel_name), + }; + + if mailbox.is_empty() { + panic!("No mailbox defined for channel {}", channel_name); + } + let imap_store = match config.find_imap_store(&channel.far) { Some(store) => store, None => panic!("Unable to find store {}", &channel.far), }; let channel_name = channel.name.clone(); + let mailbox = mailbox.clone(); watchers.push(thread::spawn(move || { - let mut session = match connect(&imap_store) { + let mut session = match connect(&imap_store, &mailbox) { Some(session) => session, None => { log::error!("Unable to connect to channel {}", channel_name); @@ -75,7 +89,11 @@ fn main() { } }; - log::info!("Watching for messages on channel {}", channel_name); + log::info!( + "Watching for messages on channel {} in mailbox {}", + channel_name, + mailbox + ); loop { let result = session @@ -86,15 +104,19 @@ fn main() { log::error!("Error while idling: {:?}", result); thread::sleep(std::time::Duration::from_secs(10)); - session = connect(&imap_store).unwrap(); + session = connect(&imap_store, &mailbox).unwrap(); continue; } - log::info!("Syncing changes for {}", channel_name); + log::info!( + "Syncing changes for {} in mailbox {}", + channel_name, + mailbox + ); Command::new("mbsync") - .args(["--all", &format!("{}:INBOX", channel_name)]) + .args(["--all", &format!("{}:{}", channel_name, mailbox)]) .output() .expect("Unable to sync mail"); }