From 5db86a9a413cf4d4ae2de5ec5e025f291093926c Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Sun, 21 Feb 2021 08:59:27 -0600 Subject: [PATCH] switch to owned responses instead of references --- imap/src/client/inner.rs | 23 +++---- imap/src/response/mod.rs | 130 +++++++++++++++++++++++++++++++++--- imap/src/response/parser.rs | 0 imap/src/types.rs | 2 +- src/mail/mod.rs | 5 ++ 5 files changed, 136 insertions(+), 24 deletions(-) delete mode 100644 imap/src/response/parser.rs diff --git a/imap/src/client/inner.rs b/imap/src/client/inner.rs index 30649e6..430e233 100644 --- a/imap/src/client/inner.rs +++ b/imap/src/client/inner.rs @@ -19,12 +19,11 @@ use tokio_rustls::{ }; use crate::command::Command; -use crate::types::Response; +use crate::response::Response; use super::ClientConfig; -pub type BoxedFunc = Box; -pub type ResultMap = Arc, Option)>>>; +pub type ResultMap = Arc, Option)>>>; pub type GreetingState = Arc)>>; pub const TAG_PREFIX: &str = "panorama"; @@ -85,7 +84,7 @@ where } /// Sends a command to the server and returns a handle to retrieve the result - pub async fn execute(&mut self, cmd: Command) -> Result { + pub async fn execute(&mut self, cmd: Command) -> Result { debug!("executing command {:?}", cmd); let id = self.id; self.id += 1; @@ -116,13 +115,10 @@ where .execute(cmd) .await .context("error executing CAPABILITY command")?; - let (_, resp) = Response::from_bytes(result.as_bytes()) - .map_err(|err| anyhow!("")) - .context("error parsing response from CAPABILITY")?; - debug!("cap resp: {:?}", resp); - if let Response::Capabilities(caps) = resp { - debug!("capabilities: {:?}", caps); - } + debug!("cap resp: {:?}", result); + // if let Response::Capabilities(caps) = resp { + // debug!("capabilities: {:?}", caps); + // } Ok(()) } @@ -217,6 +213,9 @@ where match future::select(fut, fut2).await { Either::Left((_, _)) => { debug!("got a new line"); + let (_, resp) = crate::parser::parse_response(next_line.as_bytes()).unwrap(); + let resp = Response::from(resp); + debug!("parsed as: {:?}", resp); let next_line = next_line.trim_end_matches('\n').trim_end_matches('\r'); let mut parts = next_line.split(" "); @@ -241,7 +240,7 @@ where let mut results = results.write(); if let Some((c, w)) = results.get_mut(&id) { // *c = Some(rest.to_string()); - *c = Some(next_line.to_owned()); + *c = Some(resp); if let Some(waker) = w.take() { waker.wake(); } diff --git a/imap/src/response/mod.rs b/imap/src/response/mod.rs index 375d6e7..b609bc8 100644 --- a/imap/src/response/mod.rs +++ b/imap/src/response/mod.rs @@ -1,33 +1,141 @@ -use std::str::FromStr; +use std::ops::RangeInclusive; +use crate::types::{ + AttributeValue as AttributeValue_, Capability as Capability_, MailboxDatum as MailboxDatum_, + RequestId, Response as Response_, ResponseCode as ResponseCode_, State, Status, +}; + +#[derive(Clone, Debug)] pub enum Response { Capabilities(Vec), + Continue { + code: Option, + information: Option, + }, Done { tag: RequestId, status: Status, code: Option, information: Option, }, + Data { + status: Status, + code: Option, + information: Option, + }, + Expunge(u32), + Vanished { + earlier: bool, + uids: Vec>, + }, + Fetch(u32, Vec), + MailboxData(MailboxDatum), } -impl FromStr for Response { - type Err = anyhow::Error; - fn from_str(s: &str) -> Result { - todo!() +impl<'a> From> for Response { + fn from(b: Response_) -> Self { + use Response_::*; + match b { + Capabilities(caps) => { + Response::Capabilities(caps.into_iter().map(Capability::from).collect()) + } + Continue { code, information } => Response::Continue { + code: code.map(ResponseCode::from), + information: information.map(str::to_owned), + }, + Done { + tag, + status, + code, + information, + } => Response::Done { + tag, + status, + code: code.map(ResponseCode::from), + information: information.map(str::to_owned), + }, + Data { + status, + code, + information, + } => Response::Data { + status, + code: code.map(ResponseCode::from), + information: information.map(str::to_owned), + }, + Expunge(n) => Response::Expunge(n), + Vanished {earlier, uids} => Response::Vanished{earlier, uids}, + _ => todo!("nyi: {:?}", b), + } } } +#[derive(Clone, Debug)] pub enum Capability { Imap4rev1, Auth(String), Atom(String), } -pub struct RequestId(pub String); - -pub enum Status { - Ok, - No, +impl<'a> From> for Capability { + fn from(b: Capability_) -> Self { + use Capability_::*; + match b { + Imap4rev1 => Capability::Imap4rev1, + Auth(s) => Capability::Auth(s.to_owned()), + Atom(s) => Capability::Atom(s.to_owned()), + } + } } -pub enum ResponseCode {} +#[derive(Clone, Debug)] +pub enum ResponseCode { + Alert, + BadCharset(Option>), + Capabilities(Vec), + HighestModSeq(u64), // RFC 4551, section 3.1.1 + Parse, + PermanentFlags(Vec), + ReadOnly, + ReadWrite, + TryCreate, + UidNext(u32), + UidValidity(u32), + Unseen(u32), + AppendUid(u32, Vec), + CopyUid(u32, Vec, Vec), + UidNotSticky, +} + +impl<'a> From> for ResponseCode { + fn from(b: ResponseCode_) -> Self { + use ResponseCode_::*; + match b { + Alert => ResponseCode::Alert, + BadCharset(s) => { + ResponseCode::BadCharset(s.map(|v| v.into_iter().map(str::to_owned).collect())) + } + Capabilities(v) => { + ResponseCode::Capabilities(v.into_iter().map(Capability::from).collect()) + } + HighestModSeq(n) => ResponseCode::HighestModSeq(n), + Parse => ResponseCode::Parse, + _ => todo!("nyi: {:?}", b), + } + } +} + +#[derive(Clone, Debug)] +pub enum UidSetMember { + UidRange(RangeInclusive), + Uid(u32), +} + +#[derive(Clone, Debug)] +pub enum AttributeValue { +} + +#[derive(Clone, Debug)] +pub enum MailboxDatum { + +} diff --git a/imap/src/response/parser.rs b/imap/src/response/parser.rs deleted file mode 100644 index e69de29..0000000 diff --git a/imap/src/types.rs b/imap/src/types.rs index b83f55a..63fe5a7 100644 --- a/imap/src/types.rs +++ b/imap/src/types.rs @@ -44,7 +44,7 @@ impl<'a> Response<'a> { } } -#[derive(Debug, Eq, PartialEq)] +#[derive(Clone, Debug, Eq, PartialEq)] pub enum Status { Ok, No, diff --git a/src/mail/mod.rs b/src/mail/mod.rs index 7a33c09..e97c013 100644 --- a/src/mail/mod.rs +++ b/src/mail/mod.rs @@ -89,5 +89,10 @@ async fn imap_main(acct: MailAccountConfig) -> Result<()> { // debug!("sending CAPABILITY"); // let result = unauth.capabilities().await?; + + loop { + tokio::time::sleep(std::time::Duration::from_secs(10)).await; + debug!("heartbeat"); + } } }