wip
This commit is contained in:
parent
534833d616
commit
4913b2ac9d
13 changed files with 67 additions and 20 deletions
|
@ -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) {
|
||||||
|
|
|
@ -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::*;
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use nom::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
parser::{core::*, rfc3501::envelope},
|
oldparser::{core::*, rfc3501::envelope},
|
||||||
types::*,
|
types::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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'/'
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()?;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue