fuckkk i have to take my parser apart now

This commit is contained in:
Michael Zhang 2021-03-06 20:04:58 -06:00
parent 4c989e0991
commit da7df7dfb3
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
7 changed files with 107 additions and 24 deletions

View file

@ -1,5 +1,4 @@
use anyhow::Result;
use futures::stream::StreamExt;
use crate::command::Command;
use crate::response::{Response, ResponseDone, Status};

View file

@ -223,6 +223,7 @@ where
}
len = read_fut => {
trace!("read line {:?}", next_line);
// res should not be None here
let resp = parse_response(next_line)?;

View file

@ -39,17 +39,13 @@ mod inner;
use std::sync::Arc;
use anyhow::Result;
use futures::{
future::{self, Either, FutureExt},
stream::StreamExt,
};
use tokio::net::TcpStream;
use tokio_rustls::{
client::TlsStream, rustls::ClientConfig as RustlsConfig, webpki::DNSNameRef, TlsConnector,
};
use tokio_stream::wrappers::UnboundedReceiverStream;
use crate::command::Command;
use crate::command::{Command, FetchItems, SearchCriteria};
use crate::response::{MailboxData, Response, ResponseData, ResponseDone};
pub use self::inner::{Client, ResponseStream};
@ -176,12 +172,11 @@ impl ClientAuthenticated {
let cmd = Command::Select {
mailbox: mailbox.as_ref().to_owned(),
};
let mut stream = self.execute(cmd).await?;
// let (resp, mut st) = self.execute(cmd).await?;
debug!("execute called returned...");
debug!("ST: {:?}", stream.next().await);
// let resp = resp.await?;
// debug!("select response: {:?}", resp);
let stream = self.execute(cmd).await?;
let (done, data) = stream.wait().await?;
for resp in data {
debug!("execute called returned: {:?}", resp);
}
// nuke the capabilities cache
self.nuke_capabilities();
@ -189,6 +184,37 @@ impl ClientAuthenticated {
Ok(())
}
/// Runs the SEARCH command
pub async fn uid_search(&mut self) -> Result<Vec<u32>> {
let cmd = Command::UidSearch {
criteria: SearchCriteria::All,
};
let stream = self.execute(cmd).await?;
let (_, data) = stream.wait().await?;
for resp in data {
if let Response::MailboxData(MailboxData::Search(uids)) = resp {
return Ok(uids);
}
}
bail!("could not find the SEARCH response")
}
/// Runs the UID FETCH command
pub async fn uid_fetch(&mut self, uids: &[u32]) -> Result<()> {
let cmd = Command::UidFetch {
uids: uids.to_vec(),
items: FetchItems::All,
};
debug!("uid fetch: {}", cmd);
let stream = self.execute(cmd).await?;
let (done, data) = stream.wait().await?;
debug!("done: {:?} {:?}", done, data);
for resp in data {
debug!("uid fetch: {:?}", resp);
}
todo!()
}
/// Runs the IDLE command
#[cfg(feature = "rfc2177-idle")]
pub async fn idle(&mut self) -> Result<ResponseStream> {

View file

@ -16,6 +16,17 @@ pub enum Command {
reference: String,
mailbox: String,
},
Search {
criteria: SearchCriteria,
},
UidSearch {
criteria: SearchCriteria,
},
UidFetch {
// TODO: do sequence-set
uids: Vec<u32>,
items: FetchItems,
},
#[cfg(feature = "rfc2177-idle")]
Idle,
@ -25,14 +36,8 @@ impl fmt::Debug for Command {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Command::*;
match self {
Capability => write!(f, "CAPABILITY"),
Starttls => write!(f, "STARTTLS"),
Login { .. } => write!(f, "LOGIN"),
Select { mailbox } => write!(f, "SELECT {}", mailbox),
List { reference, mailbox } => write!(f, "LIST {:?} {:?}", reference, mailbox),
#[cfg(feature = "rfc2177-idle")]
Idle => write!(f, "IDLE"),
_ => <Self as fmt::Display>::fmt(self, f),
}
}
}
@ -45,10 +50,53 @@ impl fmt::Display for Command {
Starttls => write!(f, "STARTTLS"),
Login { username, password } => write!(f, "LOGIN {:?} {:?}", username, password),
Select { mailbox } => write!(f, "SELECT {}", mailbox),
Search { criteria } => write!(f, "SEARCH {}", criteria),
UidSearch { criteria } => write!(f, "UID SEARCH {}", criteria),
List { reference, mailbox } => write!(f, "LIST {:?} {:?}", reference, mailbox),
UidFetch { uids, items } => write!(
f,
"UID FETCH {} {}",
uids.iter()
.map(|s| s.to_string())
.collect::<Vec<_>>()
.join(","),
items
),
#[cfg(feature = "rfc2177-idle")]
Idle => write!(f, "IDLE"),
}
}
}
#[derive(Clone, Debug)]
pub enum SearchCriteria {
All,
}
impl fmt::Display for SearchCriteria {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use SearchCriteria::*;
match self {
All => write!(f, "ALL"),
}
}
}
#[derive(Clone, Debug)]
pub enum FetchItems {
All,
Fast,
Full,
}
impl fmt::Display for FetchItems {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use FetchItems::*;
match self {
All => write!(f, "ALL"),
Fast => write!(f, "FAST"),
Full => write!(f, "FULL"),
}
}
}

View file

@ -152,6 +152,7 @@ fn build_msg_att_static(pair: Pair<Rule>) -> AttributeValue {
index: None,
data: None,
},
Rule::msg_att_static_uid => AttributeValue::Uid(build_number(unwrap1(unwrap1(pair)))),
_ => unreachable!("{:#?}", pair),
}
}
@ -313,6 +314,10 @@ fn build_mailbox_data(pair: Pair<Rule>) -> MailboxData {
name,
}
}
Rule::mailbox_data_search => {
let uids = pair.into_inner().map(build_number).collect();
MailboxData::Search(uids)
}
_ => unreachable!("{:#?}", pair),
}
}

View file

@ -64,11 +64,12 @@ header_fld_name = { astring }
header_list = { "(" ~ header_fld_name ~ (sp ~ header_fld_name)* ~ ")" }
list_wildcards = @{ "%" | "*" }
mailbox = { ^"INBOX" | astring }
mailbox_data = { mailbox_data_flags | mailbox_data_list | (^"LSUB" ~ sp ~ mailbox_list) | (^"SEARCH" ~ (sp ~ nz_number)*) | (^"STATUS" ~ sp ~ mailbox ~ sp ~ ^"(" ~ status_att_list? ~ ^")") | mailbox_data_exists | mailbox_data_recent }
mailbox_data = { mailbox_data_flags | mailbox_data_list | (^"LSUB" ~ sp ~ mailbox_list) | mailbox_data_search | (^"STATUS" ~ sp ~ mailbox ~ sp ~ ^"(" ~ status_att_list? ~ ^")") | mailbox_data_exists | mailbox_data_recent }
mailbox_data_exists = { number ~ sp ~ ^"EXISTS" }
mailbox_data_flags = { ^"FLAGS" ~ sp ~ flag_list }
mailbox_data_list = { ^"LIST" ~ sp ~ mailbox_list }
mailbox_data_recent = { number ~ sp ~ ^"RECENT" }
mailbox_data_search = { ^"SEARCH" ~ (sp ~ nz_number)* }
mailbox_list = { mailbox_list_flags ~ sp ~ mailbox_list_string ~ sp ~ mailbox }
mailbox_list_flags = { "(" ~ mbx_list_flags* ~ ")" }
mailbox_list_string = { dquote ~ quoted_char ~ dquote | nil }
@ -85,11 +86,12 @@ message_data_fetch = { ^"FETCH" ~ sp ~ msg_att }
msg_att = { "(" ~ msg_att_dyn_or_stat ~ (sp ~ msg_att_dyn_or_stat)* ~ ")" }
msg_att_dyn_or_stat = { msg_att_dynamic | msg_att_static }
msg_att_dynamic = { ^"FLAGS" ~ sp ~ "(" ~ (flag_fetch ~ (sp ~ flag_fetch)*)? ~ ")" }
msg_att_static = { msg_att_static_envelope | msg_att_static_internaldate | (^"RFC822" ~ (^".HEADER" | ^".TEXT") ~ sp ~ nstring) | msg_att_static_rfc822_size | msg_att_static_body | (^"BODY" ~ section ~ ("<" ~ number ~ ">")? ~ sp ~ nstring) | (^"UID" ~ sp ~ uniqueid) }
msg_att_static = { msg_att_static_envelope | msg_att_static_internaldate | (^"RFC822" ~ (^".HEADER" | ^".TEXT") ~ sp ~ nstring) | msg_att_static_rfc822_size | msg_att_static_body | (^"BODY" ~ section ~ ("<" ~ number ~ ">")? ~ sp ~ nstring) | msg_att_static_uid }
msg_att_static_body = { ^"BODY" ~ ^"STRUCTURE"? ~ sp ~ body }
msg_att_static_envelope = { ^"ENVELOPE" ~ sp ~ envelope }
msg_att_static_internaldate = { ^"INTERNALDATE" ~ sp ~ date_time }
msg_att_static_rfc822_size = { ^"RFC822.SIZE" ~ sp ~ number }
msg_att_static_uid = { ^"UID" ~ sp ~ uniqueid }
nil = { ^"NIL" }
nstring = { string | nil }
number = @{ digit{1,} }

View file

@ -135,16 +135,18 @@ async fn imap_main(acct: MailAccountConfig, mail2ui_tx: UnboundedSender<MailEven
authed.select("INBOX").await?;
loop {
debug!("listing all mailboxes...");
let folder_list = authed.list().await?;
debug!("mailbox list: {:?}", folder_list);
let _ = mail2ui_tx.send(MailEvent::FolderList(folder_list));
let message_list = authed.uid_search().await?;
authed.uid_fetch(&message_list).await?;
let mut idle_stream = authed.idle().await?;
loop {
idle_stream.next().await;
debug!("got an event");
let evt = idle_stream.next().await;
debug!("got an event: {:?}", evt);
if false {
break;