From 04a6d45802ab3a9cb1f5e3a02d7999ce4618b532 Mon Sep 17 00:00:00 2001 From: Michael Zhang Date: Sat, 7 Aug 2021 20:48:21 -0500 Subject: [PATCH] bytes --- imap/src/proto/mod.rs | 2 ++ imap/src/proto/prelude.rs | 37 +++++++++++++++++++++ imap/src/proto/rfc2234.rs | 68 +++++++++++++++++---------------------- imap/src/proto/rfc3501.rs | 47 +++++++++++++++++++++++++++ 4 files changed, 116 insertions(+), 38 deletions(-) create mode 100644 imap/src/proto/prelude.rs diff --git a/imap/src/proto/mod.rs b/imap/src/proto/mod.rs index 9e8143f..01a147d 100644 --- a/imap/src/proto/mod.rs +++ b/imap/src/proto/mod.rs @@ -1,3 +1,5 @@ #![allow(non_snake_case, dead_code)] +mod prelude; mod rfc2234; +mod rfc3501; diff --git a/imap/src/proto/prelude.rs b/imap/src/proto/prelude.rs new file mode 100644 index 0000000..afeef71 --- /dev/null +++ b/imap/src/proto/prelude.rs @@ -0,0 +1,37 @@ +use std::ops::RangeFrom; + +use nom::{ + error::{ErrorKind, ParseError}, + Err, IResult, InputIter, Needed, Parser, Slice, +}; + +pub fn skip(mut f: F) -> impl FnMut(I) -> IResult +where + F: Parser, +{ + move |i: I| match f.parse(i.clone()) { + Ok(_) => Ok((i, ())), + Err(err) => Err(err), + } +} + +pub fn satisfy(f: F) -> impl Fn(I) -> IResult +where + I: Slice> + InputIter, + F: Fn(T) -> bool, + E: ParseError, + T: Copy, +{ + move |i: I| match i.iter_elements().next().map(|t| (f(t), t)) { + Some((true, ft)) => Ok((i.slice(1..), ft)), + Some((false, _)) => Err(Err::Error(E::from_error_kind(i, ErrorKind::Satisfy))), + None => Err(Err::Incomplete(Needed::Unknown)), + } +} + +pub fn byte>(b: u8) -> impl Fn(I) -> IResult +where + I: Slice> + InputIter, +{ + satisfy(move |c| c == b) +} diff --git a/imap/src/proto/rfc2234.rs b/imap/src/proto/rfc2234.rs index 0114cf7..069fdc3 100644 --- a/imap/src/proto/rfc2234.rs +++ b/imap/src/proto/rfc2234.rs @@ -2,64 +2,56 @@ use nom::{ branch::alt, - character::streaming::{anychar, char, satisfy}, + character::streaming::{anychar}, multi::many0, sequence::pair, - IResult, Parser, + IResult, }; -pub fn skip(mut f: F) -> impl FnMut(I) -> IResult -where - F: Parser, -{ - move |i: I| match f.parse(i.clone()) { - Ok(_) => Ok((i, ())), - Err(err) => Err(err), - } +use super::prelude::{satisfy, skip, byte}; + +pub fn ALPHA(i: &[u8]) -> IResult<&[u8], u8> { + satisfy(|c| (c >= b'a' && c <= b'z') || (c >= b'A' && c <= b'Z'))(i) } -pub fn ALPHA(i: &[u8]) -> IResult<&[u8], char> { - satisfy(|c| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))(i) +pub fn BIT(i: &[u8]) -> IResult<&[u8], u8> { + satisfy(|c| c == b'0' || c == b'1')(i) } -pub fn BIT(i: &[u8]) -> IResult<&[u8], char> { - satisfy(|c| c == '0' || c == '1')(i) +pub fn CHAR(i: &[u8]) -> IResult<&[u8], u8> { + satisfy(|c| c != b'\0')(i) } -pub fn CHAR(i: &[u8]) -> IResult<&[u8], char> { - satisfy(|c| c != '\0')(i) +pub fn CR(i: &[u8]) -> IResult<&[u8], u8> { + byte(b'\x0d')(i) } -pub fn CR(i: &[u8]) -> IResult<&[u8], char> { - char('\x0d')(i) -} - -pub fn CRLF(i: &[u8]) -> IResult<&[u8], (char, char)> { +pub fn CRLF(i: &[u8]) -> IResult<&[u8], (u8, u8)> { pair(CR, LF)(i) } -pub fn CTL(i: &[u8]) -> IResult<&[u8], char> { - satisfy(|c| c <= '\x1f' || c == '\x7f')(i) +pub fn CTL(i: &[u8]) -> IResult<&[u8], u8> { + satisfy(|c| c <= b'\x1f' || c == b'\x7f')(i) } -pub fn DIGIT(i: &[u8]) -> IResult<&[u8], char> { - satisfy(|c| c >= '\x30' && c <= '\x39')(i) +pub fn DIGIT(i: &[u8]) -> IResult<&[u8], u8> { + satisfy(|c| c >= b'\x30' && c <= b'\x39')(i) } -pub fn DQUOTE(i: &[u8]) -> IResult<&[u8], char> { - char('\x22')(i) +pub fn DQUOTE(i: &[u8]) -> IResult<&[u8], u8> { + byte(b'\x22')(i) } -pub fn HEXDIG(i: &[u8]) -> IResult<&[u8], char> { - alt((DIGIT, satisfy(|c| c >= 'A' && c <= 'F')))(i) +pub fn HEXDIG(i: &[u8]) -> IResult<&[u8], u8> { + alt((DIGIT, satisfy(|c| c >= b'A' && c <= b'F')))(i) } -pub fn HTAB(i: &[u8]) -> IResult<&[u8], char> { - char('\x09')(i) +pub fn HTAB(i: &[u8]) -> IResult<&[u8], u8> { + byte(b'\x09')(i) } -pub fn LF(i: &[u8]) -> IResult<&[u8], char> { - char('\x0a')(i) +pub fn LF(i: &[u8]) -> IResult<&[u8], u8> { + byte(b'\x0a')(i) } pub fn LWSP(i: &[u8]) -> IResult<&[u8], ()> { @@ -70,14 +62,14 @@ pub fn OCTET(i: &[u8]) -> IResult<&[u8], char> { anychar(i) } -pub fn SP(i: &[u8]) -> IResult<&[u8], char> { - char('\x20')(i) +pub fn SP(i: &[u8]) -> IResult<&[u8], u8> { + byte(b'\x20')(i) } -pub fn VCHAR(i: &[u8]) -> IResult<&[u8], char> { - satisfy(|c| c >= '\x21' && c <= '\x7e')(i) +pub fn VCHAR(i: &[u8]) -> IResult<&[u8], u8> { + satisfy(|c| c >= b'\x21' && c <= b'\x7e')(i) } -pub fn WSP(i: &[u8]) -> IResult<&[u8], char> { +pub fn WSP(i: &[u8]) -> IResult<&[u8], u8> { alt((SP, HTAB))(i) } diff --git a/imap/src/proto/rfc3501.rs b/imap/src/proto/rfc3501.rs index 632e6fa..76d2af7 100644 --- a/imap/src/proto/rfc3501.rs +++ b/imap/src/proto/rfc3501.rs @@ -1,2 +1,49 @@ //! Grammar from https://datatracker.ietf.org/doc/html/rfc3501#section-9 +use nom::{ + branch::alt, + bytes::streaming::{tag_no_case, take}, + character::streaming::char, + combinator::{map, map_res}, + multi::{many0, many1}, + sequence::delimited, + IResult, +}; + +use super::rfc2234::{DIGIT, DQUOTE}; + +/// literal = "{" number "}" CRLF *CHAR8 +/// ; Number represents the number of CHAR8s +pub fn literal(i: &[u8]) -> IResult<&[u8], Vec> { + let mut length_of = delimited(char('{'), number, char('}')); + let (i, length) = length_of(i)?; + map(take(length), |s: &[u8]| s.to_vec())(i) +} + +pub fn nil(i: &[u8]) -> IResult<&[u8], &[u8]> { + tag_no_case("NIL")(i) +} + +pub fn nstring(i: &[u8]) -> IResult<&[u8], Option>> { + alt((map(string, Some), map(nil, |_| None)))(i) +} + +pub fn number(i: &[u8]) -> IResult<&[u8], u32> { + map_res(map_res(many1(DIGIT), String::from_utf8), |s| s.parse::())(i) +} + +pub fn quoted(i: &[u8]) -> IResult<&[u8], Vec> { + delimited(DQUOTE, many0(QUOTED_CHAR), DQUOTE)(i) +} + +pub fn QUOTED_CHAR(i: &[u8]) -> IResult<&[u8], u8> { + todo!() +} + +pub fn string(i: &[u8]) -> IResult<&[u8], Vec> { + alt((quoted, literal))(i) +} + +pub fn TEXT_CHAR(i: &[u8]) -> IResult<&[u8], u8> { + todo!() +}