This commit is contained in:
Michael Zhang 2021-02-22 14:36:08 -06:00
parent 534833d616
commit 4913b2ac9d
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
13 changed files with 67 additions and 20 deletions

View file

@ -1,4 +1,4 @@
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
use std::task::{Context, Poll, Waker}; use std::task::{Context, Poll, Waker};
@ -20,11 +20,11 @@ use tokio_rustls::{
use crate::command::Command; use crate::command::Command;
use crate::response::{Capability, Response, ResponseCode}; use crate::response::{Capability, Response, ResponseCode};
use crate::types::Status; use crate::types::{Capability as Capability_, Status};
use super::ClientConfig; use super::ClientConfig;
pub type CapsLock = Arc<RwLock<Option<Vec<Capability>>>>; pub type CapsLock = Arc<RwLock<Option<HashSet<Capability>>>>;
pub type ResultMap = Arc<RwLock<HashMap<usize, (Option<Response>, Option<Waker>)>>>; pub type ResultMap = Arc<RwLock<HashMap<usize, (Option<Response>, Option<Waker>)>>>;
pub type GreetingState = Arc<RwLock<(bool, Option<Waker>)>>; pub type GreetingState = Arc<RwLock<(bool, Option<Waker>)>>;
pub const TAG_PREFIX: &str = "panorama"; pub const TAG_PREFIX: &str = "panorama";
@ -130,6 +130,10 @@ where
/// Attempts to upgrade this connection using STARTTLS /// Attempts to upgrade this connection using STARTTLS
pub async fn upgrade(mut self) -> Result<Client<TlsStream<C>>> { pub async fn upgrade(mut self) -> Result<Client<TlsStream<C>>> {
// TODO: make sure STARTTLS is in the capability list // TODO: make sure STARTTLS is in the capability list
if !self.has_capability("STARTTLS").await? {
bail!("server doesn't support this capability");
}
// first, send the STARTTLS command // first, send the STARTTLS command
let resp = self.execute(Command::Starttls).await?; let resp = self.execute(Command::Starttls).await?;
debug!("server response to starttls: {:?}", resp); debug!("server response to starttls: {:?}", resp);
@ -154,6 +158,34 @@ where
Ok(Client::new(stream, self.config)) Ok(Client::new(stream, self.config))
} }
/// Check if this client has a particular capability
pub async fn has_capability(&self, cap: impl AsRef<str>) -> Result<bool> {
let cap = cap.as_ref().to_owned();
debug!("checking for the capability: {:?}", cap);
let cap_bytes = cap.as_bytes();
debug!("cap_bytes {:?}", cap_bytes);
let (_, cap) = match crate::oldparser::rfc3501::capability(cap_bytes) {
Ok(v) => v,
Err(err) => {
error!("ERROR PARSING {:?} {} {:?}", cap, err, err);
use std::error::Error;
let bt = err.backtrace().unwrap();
error!("{}", bt);
std::process::exit(1);
}
};
let cap = Capability::from(cap);
let caps = &*self.caps.read();
// TODO: refresh caps
let caps = caps.as_ref().unwrap();
let result = caps.contains(&cap);
debug!("cap result: {:?}", result);
Ok(result)
}
} }
pub struct GreetingWaiter(GreetingState); pub struct GreetingWaiter(GreetingState);
@ -226,7 +258,7 @@ where
} }
debug!("got a new line {:?}", next_line); debug!("got a new line {:?}", next_line);
let (_, resp) = match crate::parser::parse_response(next_line.as_bytes()) { let (_, resp) = match crate::oldparser::parse_response(next_line.as_bytes()) {
Ok(v) => v, Ok(v) => v,
Err(err) => { Err(err) => {
debug!("shiet: {:?}", err); debug!("shiet: {:?}", err);
@ -246,6 +278,7 @@ where
let resp = Response::from(resp); let resp = Response::from(resp);
debug!("resp: {:?}", resp); debug!("resp: {:?}", resp);
match &resp { match &resp {
// capabilities list
Response::Capabilities(new_caps) Response::Capabilities(new_caps)
| Response::Data { | Response::Data {
status: Status::Ok, status: Status::Ok,
@ -253,10 +286,18 @@ where
.. ..
} => { } => {
let caps = &mut *caps.write(); let caps = &mut *caps.write();
*caps = Some(new_caps.clone()); *caps = Some(new_caps.iter().cloned().collect());
debug!("new caps: {:?}", caps); debug!("new caps: {:?}", caps);
} }
// bye
Response::Data {
status: Status::Bye,
..
} => {
bail!("disconnected");
}
Response::Done { tag, .. } => { Response::Done { tag, .. } => {
let tag_str = &tag.0; let tag_str = &tag.0;
if tag_str.starts_with(TAG_PREFIX) { if tag_str.starts_with(TAG_PREFIX) {

View file

@ -1,3 +1,5 @@
#![feature(backtrace)]
#[macro_use] #[macro_use]
extern crate anyhow; extern crate anyhow;
#[macro_use] #[macro_use]
@ -10,9 +12,9 @@ extern crate log;
pub mod builders; pub mod builders;
pub mod client; pub mod client;
pub mod command; pub mod command;
pub mod parser; pub mod oldparser;
pub mod response; pub mod response;
pub mod types; pub mod types;
pub use crate::parser::ParseResult; pub use crate::oldparser::ParseResult;
pub use crate::types::*; pub use crate::types::*;

View file

@ -8,7 +8,7 @@ use nom::{
IResult, IResult,
}; };
use crate::{parser::core::*, types::*}; use crate::{oldparser::core::*, types::*};
pub fn section_part(i: &[u8]) -> IResult<&[u8], Vec<u32>> { pub fn section_part(i: &[u8]) -> IResult<&[u8], Vec<u32>> {
let (i, (part, mut rest)) = tuple((number, many0(preceded(char('.'), number))))(i)?; let (i, (part, mut rest)) = tuple((number, many0(preceded(char('.'), number))))(i)?;

View file

@ -9,7 +9,7 @@ use nom::{
}; };
use crate::{ use crate::{
parser::{core::*, rfc3501::envelope}, oldparser::{core::*, rfc3501::envelope},
types::*, types::*,
}; };

View file

@ -17,7 +17,7 @@ use nom::{
}; };
use crate::{ use crate::{
parser::{ oldparser::{
core::*, rfc3501::body::*, rfc3501::body_structure::*, rfc4315, rfc4551, rfc5161, rfc5464, core::*, rfc3501::body::*, rfc3501::body_structure::*, rfc4315, rfc4551, rfc5161, rfc5464,
rfc7162, rfc7162,
}, },
@ -181,7 +181,7 @@ fn resp_text_code(i: &[u8]) -> IResult<&[u8], ResponseCode> {
)(i) )(i)
} }
fn capability(i: &[u8]) -> IResult<&[u8], Capability> { pub fn capability(i: &[u8]) -> IResult<&[u8], Capability> {
alt(( alt((
map(tag_no_case(b"IMAP4rev1"), |_| Capability::Imap4rev1), map(tag_no_case(b"IMAP4rev1"), |_| Capability::Imap4rev1),
map(preceded(tag_no_case(b"AUTH="), atom), Capability::Auth), map(preceded(tag_no_case(b"AUTH="), atom), Capability::Auth),

View file

@ -13,7 +13,7 @@ use nom::{
IResult, IResult,
}; };
use crate::parser::core::number; use crate::oldparser::core::number;
use crate::types::*; use crate::types::*;
/// Extends resp-text-code as follows: /// Extends resp-text-code as follows:

View file

@ -8,7 +8,7 @@
use nom::{bytes::streaming::tag_no_case, sequence::tuple, IResult}; use nom::{bytes::streaming::tag_no_case, sequence::tuple, IResult};
use crate::{ use crate::{
parser::core::{number_64, paren_delimited}, oldparser::core::{number_64, paren_delimited},
types::*, types::*,
}; };

View file

@ -13,7 +13,7 @@ use nom::{
IResult, IResult,
}; };
use crate::parser::core::atom; use crate::oldparser::core::atom;
use crate::types::*; use crate::types::*;
// The ENABLED response lists capabilities that were enabled in response // The ENABLED response lists capabilities that were enabled in response
@ -23,7 +23,7 @@ pub(crate) fn resp_enabled(i: &[u8]) -> IResult<&[u8], Response> {
map(enabled_data, Response::Capabilities)(i) map(enabled_data, Response::Capabilities)(i)
} }
fn enabled_data(i: &[u8]) -> IResult<&[u8], Vec<Capability>> { pub fn enabled_data(i: &[u8]) -> IResult<&[u8], Vec<Capability>> {
let (i, (_, capabilities)) = tuple(( let (i, (_, capabilities)) = tuple((
tag_no_case("ENABLED"), tag_no_case("ENABLED"),
many0(preceded(char(' '), capability)), many0(preceded(char(' '), capability)),
@ -31,6 +31,6 @@ fn enabled_data(i: &[u8]) -> IResult<&[u8], Vec<Capability>> {
Ok((i, capabilities)) Ok((i, capabilities))
} }
fn capability(i: &[u8]) -> IResult<&[u8], Capability> { pub fn capability(i: &[u8]) -> IResult<&[u8], Capability> {
map(atom, Capability::Atom)(i) map(atom, Capability::Atom)(i)
} }

View file

@ -13,7 +13,7 @@ use nom::{
IResult, IResult,
}; };
use crate::{parser::core::*, types::*}; use crate::{oldparser::core::*, types::*};
fn is_entry_component_char(c: u8) -> bool { fn is_entry_component_char(c: u8) -> bool {
c < 0x80 && c > 0x19 && c != b'*' && c != b'%' && c != b'/' c < 0x80 && c > 0x19 && c != b'*' && c != b'%' && c != b'/'

View file

@ -10,7 +10,7 @@ use nom::{
IResult, IResult,
}; };
use crate::parser::core::sequence_set; use crate::oldparser::core::sequence_set;
use crate::types::*; use crate::types::*;
// The VANISHED response reports that the specified UIDs have been // The VANISHED response reports that the specified UIDs have been

View file

@ -70,7 +70,7 @@ impl<'a> From<Response_<'a>> for Response {
} }
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub enum Capability { pub enum Capability {
Imap4rev1, Imap4rev1,
Auth(String), Auth(String),

View file

@ -40,7 +40,7 @@ pub enum Response<'a> {
impl<'a> Response<'a> { impl<'a> Response<'a> {
pub fn from_bytes(buf: &'a [u8]) -> crate::ParseResult { pub fn from_bytes(buf: &'a [u8]) -> crate::ParseResult {
crate::parser::parse_response(buf) crate::oldparser::parse_response(buf)
} }
} }

View file

@ -28,6 +28,10 @@ pub struct Rect(u16, u16, u16, u16);
/// UI entrypoint. /// UI entrypoint.
pub async fn run_ui(mut w: impl Write + Debug, exit: ExitSender) -> Result<()> { pub async fn run_ui(mut w: impl Write + Debug, exit: ExitSender) -> Result<()> {
loop {
tokio::time::sleep(Duration::from_secs(4000)).await;
}
execute!(w, cursor::Hide, terminal::EnterAlternateScreen)?; execute!(w, cursor::Hide, terminal::EnterAlternateScreen)?;
terminal::enable_raw_mode()?; terminal::enable_raw_mode()?;