From 27818bd93a3638e4e77171f7b4bcde610933878e Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Mon, 22 Feb 2021 18:21:12 -0600 Subject: [PATCH] ouais --- README.md | 1 + imap/src/parser/mod.rs | 67 +++++++++++++++++++++++------------- imap/src/parser/rfc3501.pest | 6 ++-- 3 files changed, 48 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 5684d47..c8f1b68 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ Goals: Stretch goals: - Unified "feed" that any app can submit to. - Submit notifications to gotify-shaped notification servers. +- JMAP implementation. - RSS aggregator. - IRC client?? diff --git a/imap/src/parser/mod.rs b/imap/src/parser/mod.rs index f79de63..59a13c8 100644 --- a/imap/src/parser/mod.rs +++ b/imap/src/parser/mod.rs @@ -1,3 +1,6 @@ +use std::fmt::Debug; +use std::str::FromStr; + use pest::{ error::Error, iterators::{Pair, Pairs}, @@ -99,10 +102,10 @@ fn build_resp_cond_state(pair: Pair) -> (Status, Option, Opt println!("pairs: {:#?}", pairs); let pair = pairs.next().unwrap(); - let mut pairs = pair.into_inner(); + let pairs = pair.into_inner(); for pair in pairs { match pair.as_rule() { - Rule::resp_text_code => code = Some(build_resp_code(pair)), + Rule::resp_text_code => code = build_resp_code(pair), Rule::text => information = Some(pair.as_str().to_owned()), _ => unreachable!("{:#?}", pair), } @@ -111,22 +114,19 @@ fn build_resp_cond_state(pair: Pair) -> (Status, Option, Opt (status, code, information) } -fn build_resp_code(pair: Pair) -> ResponseCode { +fn build_resp_code(pair: Pair) -> Option { if !matches!(pair.as_rule(), Rule::resp_text_code) { unreachable!("{:#?}", pair); } let mut pairs = pair.into_inner(); - let pair = pairs.next().unwrap(); - match pair.as_rule() { - Rule::resp_text_code_unseen => { - let mut pairs = pair.into_inner(); - let pair = pairs.next().unwrap(); - let number = pair.as_str().parse::().unwrap(); - ResponseCode::Unseen(number) - } + let pair = pairs.next()?; + Some(match pair.as_rule() { + Rule::resp_text_code_readwrite => ResponseCode::ReadWrite, + Rule::resp_text_code_uidvalidity => ResponseCode::UidValidity(build_number(pair)), + Rule::resp_text_code_unseen => ResponseCode::Unseen(build_number(pair)), _ => unreachable!("{:#?}", pair), - } + }) } fn build_status(pair: Pair) -> Status { @@ -173,28 +173,28 @@ fn build_mailbox_data(pair: Pair) -> MailboxData { let mut pairs = pair.into_inner(); let pair = pairs.next().unwrap(); match pair.as_rule() { - Rule::mailbox_data_exists => { - let mut pairs = pair.into_inner(); - let pair = pairs.next().unwrap(); - let number = pair.as_str().parse::().unwrap(); - MailboxData::Exists(number) - } + Rule::mailbox_data_exists => MailboxData::Exists(build_number(pair)), Rule::mailbox_data_flags => { let mut pairs = pair.into_inner(); let pair = pairs.next().unwrap(); let flags = build_flag_list(pair); MailboxData::Flags(flags) } - Rule::mailbox_data_recent => { - let mut pairs = pair.into_inner(); - let pair = pairs.next().unwrap(); - let number = pair.as_str().parse::().unwrap(); - MailboxData::Recent(number) - } + Rule::mailbox_data_recent => MailboxData::Recent(build_number(pair)), _ => unreachable!("{:#?}", pair), } } +fn build_number(pair: Pair) -> T +where + T: FromStr, + T::Err: Debug, +{ + let mut pairs = pair.into_inner(); + let pair = pairs.next().unwrap(); + pair.as_str().parse::().unwrap() +} + #[cfg(test)] mod tests { use super::*; @@ -273,5 +273,24 @@ mod tests { information: Some("Message 17 is the first unseen message".to_owned()), }) ); + + assert_eq!( + parse_response("* OK [UIDVALIDITY 3857529045] UIDs valid\r\n"), + Ok(Response::Data { + status: Status::Ok, + code: Some(ResponseCode::UidValidity(3857529045)), + information: Some("UIDs valid".to_owned()), + }) + ); + + assert_eq!( + parse_response("a002 OK [READ-WRITE] SELECT completed\r\n"), + Ok(Response::Done { + tag: "a002".to_owned(), + status: Status::Ok, + code: Some(ResponseCode::ReadWrite), + information: Some("SELECT completed".to_owned()), + }) + ); } } diff --git a/imap/src/parser/rfc3501.pest b/imap/src/parser/rfc3501.pest index 8fb67b9..d72904f 100644 --- a/imap/src/parser/rfc3501.pest +++ b/imap/src/parser/rfc3501.pest @@ -92,9 +92,11 @@ resp_cond_state = { resp_status ~ sp ~ resp_text } resp_specials = @{ "]" } resp_status = { (^"OK" | ^"NO" | ^"BAD") } resp_text = { ("[" ~ resp_text_code ~ "]" ~ sp)? ~ text } -resp_text_code = { ^"ALERT" | (^"BADCHARSET" ~ (sp ~ "(" ~ astring ~ (sp ~ astring)* ~ ")")?) | capability_data | ^"PARSE" | (^"PERMANENTFLAGS" ~ sp ~ "(" ~ (flag_perm ~ (sp ~ flag_perm)*)? ~ ")") | ^"READ-ONLY" | ^"READ-WRITE" | ^"TRYCREATE" | (^"UIDNEXT" ~ sp ~ nz_number) | (^"UIDVALIDITY" ~ sp ~ nz_number) | resp_text_code_unseen | (atom ~ (sp ~ resp_text_code_atom)?) } -resp_text_code_unseen = { ^"UNSEEN" ~ sp ~ nz_number } +resp_text_code = { ^"ALERT" | (^"BADCHARSET" ~ (sp ~ "(" ~ astring ~ (sp ~ astring)* ~ ")")?) | capability_data | ^"PARSE" | (^"PERMANENTFLAGS" ~ sp ~ "(" ~ (flag_perm ~ (sp ~ flag_perm)*)? ~ ")") | ^"READ-ONLY" | resp_text_code_readwrite | ^"TRYCREATE" | (^"UIDNEXT" ~ sp ~ nz_number) | resp_text_code_uidvalidity | resp_text_code_unseen | (atom ~ (sp ~ resp_text_code_atom)?) } resp_text_code_atom = @{ (!"]" ~ text_char){1,} } +resp_text_code_readwrite = { ^"READ-WRITE" } +resp_text_code_uidvalidity = { ^"UIDVALIDITY" ~ sp ~ nz_number } +resp_text_code_unseen = { ^"UNSEEN" ~ sp ~ nz_number } response = { continue_req | response_data | response_done } response_data = { "*" ~ sp ~ (resp_cond_state | resp_cond_bye | mailbox_data | message_data | capability_data) ~ crlf } response_done = { response_tagged | response_fatal }