From 523e6eaf7a9e05586861b312d4a9952c87c8ca44 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Wed, 24 Feb 2021 06:43:50 -0600 Subject: [PATCH] ouais --- Cargo.toml | 6 +++++- imap/Cargo.toml | 4 ++++ imap/src/client/inner.rs | 6 +++--- imap/src/client/mod.rs | 9 +++++++++ imap/src/command/mod.rs | 20 +++++++++++++++++--- imap/src/parser/mod.rs | 31 +++++++++++++++++++++++++++---- imap/src/parser/rfc3501.pest | 4 ++-- src/mail/mod.rs | 2 +- 8 files changed, 68 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 04918df..1963319 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,6 @@ format-bytes = "0.2.0" futures = "0.3.13" inotify = { version = "0.9.2", features = ["stream"] } log = "0.4.14" -panorama-imap = { path = "imap", version = "0" } parking_lot = "0.11.1" pgp = "0.7.1" pin-project = "1.0.5" @@ -37,5 +36,10 @@ toml = "0.5.8" webpki-roots = "0.21.0" xdg = "2.2.0" +[dependencies.panorama-imap] +path = "imap" +version = "0" +features = ["rfc2177-idle"] + [features] clippy = [] diff --git a/imap/Cargo.toml b/imap/Cargo.toml index a3a5166..03fe539 100644 --- a/imap/Cargo.toml +++ b/imap/Cargo.toml @@ -28,3 +28,7 @@ webpki-roots = "0.21.0" [dev-dependencies] assert_matches = "1.3" + +[features] +default = ["rfc2177-idle"] +rfc2177-idle = [] diff --git a/imap/src/client/inner.rs b/imap/src/client/inner.rs index b4e02f7..e423844 100644 --- a/imap/src/client/inner.rs +++ b/imap/src/client/inner.rs @@ -100,10 +100,10 @@ where } let cmd_str = format!("{}{} {}\r\n", TAG_PREFIX, id, cmd); - debug!("[{}] writing to socket: {:?}", id, cmd_str); + // debug!("[{}] writing to socket: {:?}", id, cmd_str); self.conn.write_all(cmd_str.as_bytes()).await?; self.conn.flush().await?; - debug!("[{}] written.", id); + // debug!("[{}] written.", id); let resp = ExecWaiter(self, id, false).await; // let resp = { @@ -252,7 +252,7 @@ async fn listen( where C: AsyncRead + Unpin, { - debug!("amogus"); + // debug!("amogus"); let mut reader = BufReader::new(conn); let mut greeting = Some(greeting); diff --git a/imap/src/client/mod.rs b/imap/src/client/mod.rs index 10857f5..0a24af8 100644 --- a/imap/src/client/mod.rs +++ b/imap/src/client/mod.rs @@ -166,4 +166,13 @@ impl ClientAuthenticated { debug!("select response: {:?}", resp); Ok(()) } + + /// Runs the SELECT command + #[cfg(feature = "rfc2177-idle")] + pub async fn idle(&mut self) -> Result<()> { + let cmd = Command::Idle; + let resp = self.execute(cmd).await?; + debug!("idle response: {:?}", resp); + Ok(()) + } } diff --git a/imap/src/command/mod.rs b/imap/src/command/mod.rs index 8e5b0e5..cc99bcc 100644 --- a/imap/src/command/mod.rs +++ b/imap/src/command/mod.rs @@ -5,9 +5,20 @@ use std::fmt; pub enum Command { Capability, Starttls, - Login { username: String, password: String }, - Select { mailbox: String }, - List { reference: String, mailbox: String }, + Login { + username: String, + password: String, + }, + Select { + mailbox: String, + }, + List { + reference: String, + mailbox: String, + }, + + #[cfg(feature = "rfc2177-idle")] + Idle, } impl fmt::Display for Command { @@ -19,6 +30,9 @@ impl fmt::Display for Command { Login { username, password } => write!(f, "LOGIN {} {}", username, password), Select { mailbox } => write!(f, "SELECT {}", mailbox), List { reference, mailbox } => write!(f, "LIST {:?} {:?}", reference, mailbox), + + #[cfg(feature = "rfc2177-idle")] + Idle => write!(f, "IDLE"), } } } diff --git a/imap/src/parser/mod.rs b/imap/src/parser/mod.rs index f264004..34c317e 100644 --- a/imap/src/parser/mod.rs +++ b/imap/src/parser/mod.rs @@ -15,13 +15,15 @@ use crate::response::*; #[grammar = "parser/rfc3501.pest"] struct Rfc3501; -pub fn parse_capability(s: impl AsRef) -> Result> { +pub type ParseResult> = Result; + +pub fn parse_capability(s: impl AsRef) -> ParseResult { let mut pairs = Rfc3501::parse(Rule::capability, s.as_ref())?; let pair = pairs.next().unwrap(); Ok(build_capability(pair)) } -pub fn parse_response(s: impl AsRef) -> Result> { +pub fn parse_response(s: impl AsRef) -> ParseResult { let mut pairs = Rfc3501::parse(Rule::response, s.as_ref())?; let pair = pairs.next().unwrap(); Ok(build_response(pair)) @@ -90,10 +92,31 @@ fn build_response(pair: Pair) -> Response { _ => unreachable!("{:#?}", pair), } } + Rule::continue_req => { + let (code, s) = build_resp_text(unwrap1(pair)); + Response::Continue { + code, + information: Some(s), + } + } _ => unreachable!("{:#?}", pair), } } +fn build_resp_text(pair: Pair) -> (Option, String) { + assert!(matches!(pair.as_rule(), Rule::resp_text)); + let mut pairs = pair.into_inner(); + let mut pair = pairs.next().unwrap(); + let mut resp_code = None; + if let Rule::resp_text_code = pair.as_rule() { + resp_code = build_resp_text_code(pair); + pair = pairs.next().unwrap(); + } + assert!(matches!(pair.as_rule(), Rule::text)); + let s = pair.as_str().to_owned(); + (resp_code, s) +} + fn build_msg_att(pair: Pair) -> AttributeValue { if !matches!(pair.as_rule(), Rule::msg_att_dyn_or_stat) { unreachable!("{:#?}", pair); @@ -153,7 +176,7 @@ fn build_resp_cond_state(pair: Pair) -> (Status, Option, Opt let pairs = pair.into_inner(); for pair in pairs { match pair.as_rule() { - Rule::resp_text_code => code = build_resp_code(pair), + Rule::resp_text_code => code = build_resp_text_code(pair), Rule::text => information = Some(pair.as_str().to_owned()), _ => unreachable!("{:#?}", pair), } @@ -162,7 +185,7 @@ fn build_resp_cond_state(pair: Pair) -> (Status, Option, Opt (status, code, information) } -fn build_resp_code(pair: Pair) -> Option { +fn build_resp_text_code(pair: Pair) -> Option { if !matches!(pair.as_rule(), Rule::resp_text_code) { unreachable!("{:#?}", pair); } diff --git a/imap/src/parser/rfc3501.pest b/imap/src/parser/rfc3501.pest index 0f1e8f4..aacd6f6 100644 --- a/imap/src/parser/rfc3501.pest +++ b/imap/src/parser/rfc3501.pest @@ -135,11 +135,11 @@ zone = @{ ("+" | "-") ~ digit{4} } // core rules from https://tools.ietf.org/html/rfc2234#section-6.1 alpha = @{ '\x41'..'\x5a' | '\x61'..'\x7a' } char = @{ '\x01'..'\x7f' } -cr = @{ "\x0d" } +cr = _{ "\x0d" } crlf = _{ cr ~ lf } ctl = @{ '\x00'..'\x1f' | "\x7f" } digit = @{ '\x30'..'\x39' } dquote = @{ "\"" } -lf = @{ "\x0a" } +lf = _{ "\x0a" } sp = _{ " " } diff --git a/src/mail/mod.rs b/src/mail/mod.rs index 8acdc31..e0c8e11 100644 --- a/src/mail/mod.rs +++ b/src/mail/mod.rs @@ -110,7 +110,7 @@ async fn imap_main(acct: MailAccountConfig) -> Result<()> { debug!("listing all emails..."); let folder_tree = authed.list().await?; - tokio::time::sleep(std::time::Duration::from_secs(60)).await; + let idle = authed.idle().await?; debug!("heartbeat"); } }