diff --git a/notes.md b/notes.md
new file mode 100644
index 0000000..0629c09
--- /dev/null
+++ b/notes.md
@@ -0,0 +1,11 @@
+imap routine
+---
+
+- basic tcp connection is opened
+- if tls is "on", then immediately perform tls handshake with the server
+- if tls is "starttls", check starttls capability
+ - if the server doesn't have starttls capability, die and report to the user
+ - if the server _does_ have starttls, exit the read loop and perform tls handshake over current connection
+- at this point, tls should be figured out, so moving on to auth
+- check if the auth type that the user specified is in the list of auth types (prob support plain and oauth2?)
+
diff --git a/src/config.rs b/src/config.rs
index e75a978..5ecc5a5 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -14,11 +14,30 @@ use tokio::{sync::watch, task::JoinHandle};
use xdg::BaseDirectories;
/// Alias for a MailConfig receiver.
-pub type ConfigWatcher = watch::Receiver>;
+pub type ConfigWatcher = watch::Receiver >;
/// Configuration
#[derive(Default, Serialize, Deserialize, Clone, Debug)]
-pub struct MailConfig {
+pub struct Config {
+ /// Version of the config to use
+ /// (potentially for migration later?)
+ pub version: String,
+
+ /// Mail accounts
+ #[serde(rename = "mail")]
+ pub mail_accounts: Vec,
+}
+
+/// Configuration for a single mail account
+#[derive(Default, Serialize, Deserialize, Clone, Debug)]
+pub struct MailAccountConfig {
+ /// Imap
+ pub imap: ImapConfig,
+}
+
+/// Configuring an IMAP server
+#[derive(Default, Serialize, Deserialize, Clone, Debug)]
+pub struct ImapConfig {
/// Host of the IMAP server (needs to be hostname for TLS)
pub server: String,
@@ -48,7 +67,7 @@ fn start_watcher() -> Result<(RecommendedWatcher, Receiver)> {
Ok((watcher, rx))
}
-async fn read_config(path: impl AsRef) -> Result {
+async fn read_config(path: impl AsRef) -> Result {
let mut file = File::open(path.as_ref())?;
let mut contents = Vec::new();
file.read_to_end(&mut contents)?;
@@ -63,20 +82,29 @@ async fn read_config(path: impl AsRef) -> Result {
/// This exists so all errors are able to be caught in one go.
async fn watcher_loop(
fs_events: Receiver,
- config_tx: watch::Sender>,
+ config_tx: watch::Sender >,
) -> Result<()> {
- // first try opening the config file directly on load
+ // first try opening the config file directly when the program is opened
// (so the config isn't blank until the user touches the config file)
let xdg = BaseDirectories::new()?;
if let Some(config_path) = xdg.find_config_file("panorama/panorama.toml") {
debug!("found config at {:?}", config_path);
let config = read_config(config_path).await?;
+ debug!("read config: {:?}, sending to output", config);
config_tx.send(Some(config))?;
}
+ // start listening for events from the notify::Watcher
for event in fs_events {
debug!("new event: {:?}", event);
- // config_tx.send(Some(config))?;
+ use notify::DebouncedEvent::*;
+ match event {
+ NoticeWrite(path) | Write(path) => {
+ let config = read_config(path).await?;
+ config_tx.send(Some(config))?;
+ }
+ _ => {}
+ }
}
Ok(())
@@ -93,7 +121,7 @@ pub fn spawn_config_watcher() -> Result<(JoinHandle<()>, ConfigWatcher)> {
match watcher_loop(config_rx, config_tx).await {
Ok(_) => {}
Err(err) => {
- debug!("config watcher died: {:?}", err);
+ debug!("config watcher bugged: {:?}", err);
}
}
});
diff --git a/src/mail.rs b/src/mail.rs
index ca80f2d..f717b12 100644
--- a/src/mail.rs
+++ b/src/mail.rs
@@ -25,7 +25,7 @@ use tokio_rustls::{rustls::ClientConfig, webpki::DNSNameRef, TlsConnector};
use tokio_stream::wrappers::WatchStream;
use tokio_util::codec::{Decoder, LinesCodec, LinesCodecError};
-use crate::config::{ConfigWatcher, MailConfig};
+use crate::config::{Config, ConfigWatcher, ImapConfig};
/// Command sent to the mail thread by something else (i.e. UI)
pub enum MailCommand {
@@ -45,7 +45,10 @@ pub async fn run_mail(
let mut config_watcher = WatchStream::new(config_watcher);
loop {
- let config: MailConfig = match config_watcher.next().await {
+ debug!("listening for configs");
+ let a = config_watcher.next().await;
+ debug!("got config {:?}", a);
+ let config: Config = match a {
Some(Some(v)) => v,
_ => break,
};
@@ -57,14 +60,18 @@ pub async fn run_mail(
curr_conn.abort();
}
- let handle = tokio::spawn(open_imap_connection(config));
+ let handle = tokio::spawn(async {
+ for acct in config.mail_accounts.into_iter() {
+ open_imap_connection(acct.imap);
+ }
+ });
curr_conn = Some(handle);
}
Ok(())
}
-async fn open_imap_connection(config: MailConfig) -> Result<()> {
+async fn open_imap_connection(config: ImapConfig) -> Result<()> {
debug!(
"Opening imap connection to {}:{}",
config.server, config.port
@@ -115,7 +122,7 @@ enum LoopExit {
}
async fn listen_loop(
- config: MailConfig,
+ config: ImapConfig,
st: &mut State,
sink: S2,
mut stream: S,
diff --git a/src/main.rs b/src/main.rs
index 7999dd7..40a1a39 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -8,7 +8,7 @@ use std::path::PathBuf;
use anyhow::Result;
use futures::future::TryFutureExt;
use panorama::{
- config::{spawn_config_watcher, MailConfig},
+ config::{spawn_config_watcher, Config},
mail, ui,
};
use structopt::StructOpt;
@@ -38,26 +38,16 @@ async fn main() -> Result<()> {
let xdg = BaseDirectories::new()?;
let (config_thread, config_update) = spawn_config_watcher()?;
- // let config: MailConfig = {
- // let config_path = opt
- // .config_path
- // .clone()
- // .unwrap_or_else(|| "config.toml".into());
- // let mut config_file = File::open(config_path)?;
- // let mut contents = Vec::new();
- // config_file.read_to_end(&mut contents)?;
- // toml::from_slice(&contents)?
- // };
-
// used to notify the runtime that the process should exit
let (exit_tx, mut exit_rx) = mpsc::channel::<()>(1);
// used to send commands to the mail service
let (mail_tx, mail_rx) = mpsc::unbounded_channel();
- let mail_thread = tokio::spawn(mail::run_mail(config_update.clone(), mail_rx).unwrap_or_else(report_err));
+ tokio::spawn(mail::run_mail(config_update.clone(), mail_rx).unwrap_or_else(report_err));
+
let stdout = std::io::stdout();
- let ui_thread = tokio::spawn(ui::run_ui(stdout, exit_tx).unwrap_or_else(report_err));
+ tokio::spawn(ui::run_ui(stdout, exit_tx).unwrap_or_else(report_err));
exit_rx.recv().await;