From e0ca51ef795730c4463ccfdb8465ecfe43b0e3f5 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Mon, 22 Feb 2021 15:33:30 -0600 Subject: [PATCH] capability parser --- Cargo.lock | 189 ++++++++++++------ imap/Cargo.toml | 6 +- imap/src/lib.rs | 3 + .../{parser => oldparser}/bodystructure.rs | 0 imap/src/{parser => oldparser}/core.rs | 0 imap/src/oldparser/mod.rs | 25 +++ .../src/{parser => oldparser}/rfc3501/body.rs | 0 .../rfc3501/body_structure.rs | 0 imap/src/{parser => oldparser}/rfc3501/mod.rs | 0 imap/src/{parser => oldparser}/rfc4315.rs | 0 imap/src/{parser => oldparser}/rfc4551.rs | 0 imap/src/{parser => oldparser}/rfc5161.rs | 0 imap/src/{parser => oldparser}/rfc5464.rs | 0 imap/src/{parser => oldparser}/rfc7162.rs | 0 imap/src/{parser => oldparser}/tests.rs | 0 imap/src/parser/mod.rs | 67 +++++-- imap/src/parser/rfc3501.pest | 17 ++ 17 files changed, 224 insertions(+), 83 deletions(-) rename imap/src/{parser => oldparser}/bodystructure.rs (100%) rename imap/src/{parser => oldparser}/core.rs (100%) create mode 100644 imap/src/oldparser/mod.rs rename imap/src/{parser => oldparser}/rfc3501/body.rs (100%) rename imap/src/{parser => oldparser}/rfc3501/body_structure.rs (100%) rename imap/src/{parser => oldparser}/rfc3501/mod.rs (100%) rename imap/src/{parser => oldparser}/rfc4315.rs (100%) rename imap/src/{parser => oldparser}/rfc4551.rs (100%) rename imap/src/{parser => oldparser}/rfc5161.rs (100%) rename imap/src/{parser => oldparser}/rfc5464.rs (100%) rename imap/src/{parser => oldparser}/rfc7162.rs (100%) rename imap/src/{parser => oldparser}/tests.rs (100%) create mode 100644 imap/src/parser/rfc3501.pest diff --git a/Cargo.lock b/Cargo.lock index f104a08..97b405b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,15 +77,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] -name = "bitvec" -version = "0.19.4" +name = "block-buffer" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ba35e9565969edb811639dbebfe34edc0368e472c5018474c8eb2543397f81" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" dependencies = [ - "funty", - "radium", - "tap", - "wyz", + "block-padding", + "byte-tools", + "byteorder", + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools", ] [[package]] @@ -100,6 +109,12 @@ version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + [[package]] name = "byteorder" version = "1.4.2" @@ -264,6 +279,21 @@ dependencies = [ "syn", ] +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + [[package]] name = "fast_chemail" version = "0.9.6" @@ -326,12 +356,6 @@ dependencies = [ "syn", ] -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - [[package]] name = "futures" version = "0.3.12" @@ -427,6 +451,15 @@ dependencies = [ "slab", ] +[[package]] +name = "generic-array" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" +dependencies = [ + "typenum", +] + [[package]] name = "getrandom" version = "0.2.2" @@ -536,7 +569,7 @@ dependencies = [ "hostname", "log", "native-tls", - "nom 4.2.3", + "nom", "serde", "serde_derive", "serde_json", @@ -566,6 +599,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "memchr" version = "2.3.4" @@ -623,18 +662,6 @@ dependencies = [ "version_check 0.1.5", ] -[[package]] -name = "nom" -version = "6.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" -dependencies = [ - "bitvec", - "funty", - "memchr", - "version_check 0.9.2", -] - [[package]] name = "ntapi" version = "0.3.6" @@ -679,6 +706,12 @@ version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + [[package]] name = "openssl" version = "0.10.32" @@ -712,15 +745,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "owning_ref" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" -dependencies = [ - "stable_deref_trait", -] - [[package]] name = "panorama" version = "0.0.1" @@ -760,9 +784,9 @@ dependencies = [ "derive_builder", "futures", "log", - "nom 6.1.2", - "owning_ref", "parking_lot", + "pest", + "pest_derive", "tokio", "tokio-rustls", "webpki-roots", @@ -793,6 +817,49 @@ dependencies = [ "winapi", ] +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +dependencies = [ + "maplit", + "pest", + "sha-1", +] + [[package]] name = "pin-project" version = "1.0.5" @@ -891,12 +958,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - [[package]] name = "rand" version = "0.8.3" @@ -1093,6 +1154,18 @@ dependencies = [ "serde", ] +[[package]] +name = "sha-1" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" +dependencies = [ + "block-buffer", + "digest", + "fake-simd", + "opaque-debug", +] + [[package]] name = "signal-hook" version = "0.1.17" @@ -1142,12 +1215,6 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "strsim" version = "0.8.0" @@ -1195,12 +1262,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "tempfile" version = "3.2.0" @@ -1314,6 +1375,18 @@ dependencies = [ "serde", ] +[[package]] +name = "typenum" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" + +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + [[package]] name = "unicode-segmentation" version = "1.7.1" @@ -1482,12 +1555,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "xdg" version = "2.2.0" diff --git a/imap/Cargo.toml b/imap/Cargo.toml index 401de54..caad1dc 100644 --- a/imap/Cargo.toml +++ b/imap/Cargo.toml @@ -16,9 +16,11 @@ anyhow = "1.0.38" derive_builder = "0.9.0" futures = "0.3.12" log = "0.4.14" -nom = { version = "6.1.2", default-features = false, features = ["std"] } -owning_ref = "0.4.1" +# nom = { version = "6.1.2", default-features = false, features = ["std"] } +# owning_ref = "0.4.1" parking_lot = "0.11.1" +pest = "2.1.3" +pest_derive = "2.1.0" tokio = { version = "1.1.1", features = ["full"] } tokio-rustls = "0.22.0" webpki-roots = "0.21.0" diff --git a/imap/src/lib.rs b/imap/src/lib.rs index 4846616..475b4d8 100644 --- a/imap/src/lib.rs +++ b/imap/src/lib.rs @@ -6,9 +6,12 @@ extern crate derive_builder; extern crate futures; #[macro_use] extern crate log; +#[macro_use] +extern crate pest_derive; pub mod client; pub mod command; +pub mod parser; pub mod response; // pub mod builders; diff --git a/imap/src/parser/bodystructure.rs b/imap/src/oldparser/bodystructure.rs similarity index 100% rename from imap/src/parser/bodystructure.rs rename to imap/src/oldparser/bodystructure.rs diff --git a/imap/src/parser/core.rs b/imap/src/oldparser/core.rs similarity index 100% rename from imap/src/parser/core.rs rename to imap/src/oldparser/core.rs diff --git a/imap/src/oldparser/mod.rs b/imap/src/oldparser/mod.rs new file mode 100644 index 0000000..a37fd91 --- /dev/null +++ b/imap/src/oldparser/mod.rs @@ -0,0 +1,25 @@ +use crate::types::Response; +use nom::{branch::alt, IResult}; + +pub mod core; + +pub mod bodystructure; +pub mod rfc3501; +pub mod rfc4315; +pub mod rfc4551; +pub mod rfc5161; +pub mod rfc5464; +pub mod rfc7162; + +#[cfg(test)] +mod tests; + +pub fn parse_response(msg: &[u8]) -> ParseResult { + alt(( + rfc3501::continue_req, + rfc3501::response_data, + rfc3501::response_tagged, + ))(msg) +} + +pub type ParseResult<'a> = IResult<&'a [u8], Response<'a>>; diff --git a/imap/src/parser/rfc3501/body.rs b/imap/src/oldparser/rfc3501/body.rs similarity index 100% rename from imap/src/parser/rfc3501/body.rs rename to imap/src/oldparser/rfc3501/body.rs diff --git a/imap/src/parser/rfc3501/body_structure.rs b/imap/src/oldparser/rfc3501/body_structure.rs similarity index 100% rename from imap/src/parser/rfc3501/body_structure.rs rename to imap/src/oldparser/rfc3501/body_structure.rs diff --git a/imap/src/parser/rfc3501/mod.rs b/imap/src/oldparser/rfc3501/mod.rs similarity index 100% rename from imap/src/parser/rfc3501/mod.rs rename to imap/src/oldparser/rfc3501/mod.rs diff --git a/imap/src/parser/rfc4315.rs b/imap/src/oldparser/rfc4315.rs similarity index 100% rename from imap/src/parser/rfc4315.rs rename to imap/src/oldparser/rfc4315.rs diff --git a/imap/src/parser/rfc4551.rs b/imap/src/oldparser/rfc4551.rs similarity index 100% rename from imap/src/parser/rfc4551.rs rename to imap/src/oldparser/rfc4551.rs diff --git a/imap/src/parser/rfc5161.rs b/imap/src/oldparser/rfc5161.rs similarity index 100% rename from imap/src/parser/rfc5161.rs rename to imap/src/oldparser/rfc5161.rs diff --git a/imap/src/parser/rfc5464.rs b/imap/src/oldparser/rfc5464.rs similarity index 100% rename from imap/src/parser/rfc5464.rs rename to imap/src/oldparser/rfc5464.rs diff --git a/imap/src/parser/rfc7162.rs b/imap/src/oldparser/rfc7162.rs similarity index 100% rename from imap/src/parser/rfc7162.rs rename to imap/src/oldparser/rfc7162.rs diff --git a/imap/src/parser/tests.rs b/imap/src/oldparser/tests.rs similarity index 100% rename from imap/src/parser/tests.rs rename to imap/src/oldparser/tests.rs diff --git a/imap/src/parser/mod.rs b/imap/src/parser/mod.rs index a37fd91..4c7c222 100644 --- a/imap/src/parser/mod.rs +++ b/imap/src/parser/mod.rs @@ -1,25 +1,52 @@ -use crate::types::Response; -use nom::{branch::alt, IResult}; +use pest::{error::Error, Parser}; -pub mod core; +use crate::response::*; -pub mod bodystructure; -pub mod rfc3501; -pub mod rfc4315; -pub mod rfc4551; -pub mod rfc5161; -pub mod rfc5464; -pub mod rfc7162; +#[derive(Parser)] +#[grammar = "parser/rfc3501.pest"] +struct Rfc3501; -#[cfg(test)] -mod tests; - -pub fn parse_response(msg: &[u8]) -> ParseResult { - alt(( - rfc3501::continue_req, - rfc3501::response_data, - rfc3501::response_tagged, - ))(msg) +pub fn parse_capability(s: &str) -> Result> { + let mut pairs = Rfc3501::parse(Rule::capability, s)?; + let pair = pairs.next().unwrap(); + let cap = match pair.as_rule() { + Rule::capability => { + let mut inner = pair.into_inner(); + let pair = inner.next().unwrap(); + match pair.as_rule() { + Rule::auth_type => Capability::Auth(pair.as_str().to_owned()), + Rule::atom => match pair.as_str() { + "IMAP4rev1" => Capability::Imap4rev1, + s => Capability::Atom(s.to_owned()), + }, + _ => unreachable!("{:?}", pair), + } + } + _ => unreachable!("{:?}", pair), + }; + Ok(cap) } -pub type ParseResult<'a> = IResult<&'a [u8], Response<'a>>; +#[cfg(test)] +#[rustfmt::skip] +mod tests { + use super::*; + use crate::response::*; + use pest::Parser; + + #[test] + fn test_capability() { + assert_eq!(parse_capability("IMAP4rev1"), Ok(Capability::Imap4rev1)); + assert_eq!(parse_capability("LOGINDISABLED"), Ok(Capability::Atom("LOGINDISABLED".to_owned()))); + assert_eq!(parse_capability("AUTH=PLAIN"), Ok(Capability::Auth("PLAIN".to_owned()))); + + assert!(parse_capability("(OSU)").is_err()); + assert!(parse_capability("\x01HELLO").is_err()); + } + + #[test] + fn test_nil() { + assert!(Rfc3501::parse(Rule::nil, "NIL").is_ok()); + assert!(Rfc3501::parse(Rule::nil, "anything else").is_err()); + } +} diff --git a/imap/src/parser/rfc3501.pest b/imap/src/parser/rfc3501.pest new file mode 100644 index 0000000..2fecd78 --- /dev/null +++ b/imap/src/parser/rfc3501.pest @@ -0,0 +1,17 @@ +// formal syntax from https://tools.ietf.org/html/rfc3501#section-9 +atom = @{ atom_char{1,} } +atom_char = @{ !atom_specials ~ char } +atom_specials = @{ "(" | ")" | "{" | sp | ctl | list_wildcards | quoted_specials | resp_specials } +auth_type = { atom } +capability = ${ "AUTH=" ~ auth_type | atom } +list_wildcards = @{ "%" | "*" } +quoted_specials = @{ dquote | "\\" } +resp_specials = @{ "]" } +nil = { "NIL" } + +// core rules from https://tools.ietf.org/html/rfc2234#section-6.1 +char = @{ '\x01'..'\x7f' } +ctl = @{ '\x00'..'\x1f' | "\x7f" } +dquote = @{ "\"" } +sp = @{ " " } +