diff --git a/Cargo.lock b/Cargo.lock index fd2540a..57703ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,9 +32,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.38" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" +checksum = "81cddc5f91628367664cc7c69714ff08deee8a3efc54623011c772544d7b2767" [[package]] name = "archery" @@ -1481,9 +1481,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.89" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "538c092e5586f4cdd7dd8078c4a79220e3e168880218124dcbce860f0ea938c6" +checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae" [[package]] name = "libgit2-sys" @@ -1860,6 +1860,16 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "panorama-maildir" +version = "0.1.0" +dependencies = [ + "anyhow", + "futures 0.3.13", + "tempfile", + "tokio 1.3.0", +] + [[package]] name = "panorama-smtp" version = "0.1.0" @@ -2486,9 +2496,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7" +checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27" [[package]] name = "sized-chunks" @@ -2939,9 +2949,9 @@ checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" [[package]] name = "vec-arena" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eafc1b9b2dfc6f5529177b62cf806484db55b32dc7c9658a118e11bbeb33061d" +checksum = "34b2f665b594b07095e3ac3f718e13c2197143416fae4c5706cffb7b1af8d7f1" [[package]] name = "vec_map" diff --git a/Cargo.toml b/Cargo.toml index 1742caa..9782297 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,10 +9,14 @@ readme = "README.md" license = "GPL-3.0-or-later" [workspace] -members = ["imap", "smtp"] +members = [ + "imap", + "smtp", + "maildir", +] [dependencies] -anyhow = "1.0.38" +anyhow = "1.0.39" async-trait = "0.1.48" cfg-if = "1.0.0" chrono = "0.4.19" diff --git a/maildir/Cargo.toml b/maildir/Cargo.toml new file mode 100644 index 0000000..650af4c --- /dev/null +++ b/maildir/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "panorama-maildir" +version = "0.1.0" +authors = ["Michael Zhang "] +edition = "2018" + +[dependencies] +anyhow = "1.0.39" +futures = "0.3.13" +tempfile = "3.2.0" +tokio = { version = "1.3.0", features = ["full"] } diff --git a/maildir/src/lib.rs b/maildir/src/lib.rs new file mode 100644 index 0000000..d9440e7 --- /dev/null +++ b/maildir/src/lib.rs @@ -0,0 +1,50 @@ +use std::path::{Path, PathBuf}; + +use tokio::fs::{File, self}; +use anyhow::Result; +use tempfile::NamedTempFile; + +pub struct Maildir { + path: PathBuf, +} + +impl Maildir { + // TODO: should this double as create (aka create tmp cur new if they don't exist)? + pub async fn open(path: impl AsRef) -> Result { + Ok(Maildir { + path: path.as_ref().to_path_buf(), + }) + } + + /// Stores a new message into the `new` directory + // TODO: maybe have a streaming option? + pub async fn store(&self) -> Result<()> { + let unique_name = "hellosu"; + let tmp_file = self.tmp_dir().join(unique_name); + { + let mut file = File::create(&tmp_file).await?; + } + + let new_file = self.new_dir().join(unique_name); + fs::rename(tmp_file, new_file).await?; + Ok(()) + } + + /// Returns the path to the `tmp` subdirectory + #[inline] + pub fn tmp_dir(&self) -> PathBuf { + self.path.join("tmp") + } + + /// Returns the path to the `new` subdirectory + #[inline] + pub fn new_dir(&self) -> PathBuf { + self.path.join("new") + } + + /// Returns the path to the `cur` subdirectory + #[inline] + pub fn cur_dir(&self) -> PathBuf { + self.path.join("cur") + } +} diff --git a/src/ui/colon_prompt.rs b/src/ui/colon_prompt.rs index 4bedb1f..592e4e5 100644 --- a/src/ui/colon_prompt.rs +++ b/src/ui/colon_prompt.rs @@ -10,11 +10,11 @@ pub struct ColonPrompt { } impl ColonPrompt { - pub fn init(term: TermType) -> Self { - let s = term.size().unwrap(); - term.set_cursor(1, s.height - 1); - term.show_cursor(); - ColonPrompt::default() + pub fn init(term: TermType) -> Result { + let s = term.size()?; + term.set_cursor(1, s.height - 1)?; + term.show_cursor()?; + Ok(ColonPrompt::default()) } } diff --git a/src/ui/input.rs b/src/ui/input.rs index a0d70fc..63c3f06 100644 --- a/src/ui/input.rs +++ b/src/ui/input.rs @@ -41,7 +41,7 @@ impl HandlesInput for BaseInputHandler { KeyCode::Char('j') => self.1.store(1, Ordering::Relaxed), KeyCode::Char('k') => self.1.store(-1, Ordering::Relaxed), KeyCode::Char(':') => { - let colon_prompt = Box::new(ColonPrompt::init(term)); + let colon_prompt = Box::new(ColonPrompt::init(term)?); return Ok(InputResult::Push(colon_prompt)); } _ => {} diff --git a/src/ui/mod.rs b/src/ui/mod.rs index 9f90f76..1b0131b 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -286,16 +286,14 @@ pub async fn run_ui( // handle states in the state stack // although this is written in a for loop, every case except one should break let mut should_pop = false; - for input_state in input_states.iter_mut().rev() { + if let Some(input_state) = input_states.last_mut() { match input_state.handle_key(&mut term, evt)? { - InputResult::Ok => break, + InputResult::Ok => {}, InputResult::Push(state) => { input_states.push(state); - break; } InputResult::Pop => { should_pop = true; - break; } } }