wow testing

This commit is contained in:
Michael Zhang 2021-08-09 17:56:17 -05:00
parent 0405b478eb
commit 60e0bb3bbb
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
12 changed files with 90 additions and 39 deletions

View file

@ -1,2 +1,5 @@
fmt:
cargo +nightly fmt --all
doc:
cargo doc --workspace --no-deps

View file

@ -1,7 +1,7 @@
//! Configurable cert verifier for rustls, can disable hostname verification,
//! etc.
//!
//! Based closely on https://github.com/rustls/rustls/blob/v/0.19.0/rustls/src/verify.rs#L253
//! Based closely on <https://github.com/rustls/rustls/blob/v/0.19.0/rustls/src/verify.rs#L253>
use tokio_rustls::{
rustls::{

View file

@ -1,9 +1,9 @@
use std::io::{self, Write};
use format_bytes::DisplayBytes;
use panorama_proto_common::{quote_string as q, Bytes};
use panorama_proto_common::{quote_string, Bytes};
use super::rfc3501::is_quoted_specials as isq;
use super::rfc3501::is_quoted_specials;
#[derive(Clone, Debug)]
pub enum Command {
@ -52,6 +52,7 @@ pub enum Command {
impl DisplayBytes for Command {
fn display_bytes(&self, w: &mut dyn Write) -> io::Result<()> {
let quote = quote_string(b'\x22', b'\\', is_quoted_specials);
match self {
// command-any
Command::Capability => write_bytes!(w, b"CAPABILITY"),
@ -63,8 +64,8 @@ impl DisplayBytes for Command {
write_bytes!(
w,
b"LOGIN {} {}",
q(&login.userid, isq),
q(&login.password, isq)
quote(&login.userid),
quote(&login.password)
)
}
Command::Starttls => write_bytes!(w, b"STARTTLS"),
@ -74,11 +75,11 @@ impl DisplayBytes for Command {
write_bytes!(
w,
b"LIST {} {}",
q(&list.reference, isq),
q(&list.mailbox, isq)
quote(&list.reference),
quote(&list.mailbox)
)
}
Command::Select(select) => write_bytes!(w, b"SELECT {}", q(&select.mailbox, isq)),
Command::Select(select) => write_bytes!(w, b"SELECT {}", quote(&select.mailbox)),
#[cfg(feature = "rfc2177")]
Command::Idle => write_bytes!(w, b"IDLE"),

View file

@ -159,7 +159,7 @@ pub struct MailboxList {
pub mailbox: Mailbox,
}
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq)]
pub enum MailboxListFlag {
NoInferiors,
NoSelect,

View file

@ -19,6 +19,13 @@ use super::response::{
};
use super::rfc2234::{is_char, is_cr, is_ctl, is_digit, is_dquote, is_lf, is_sp, CRLF, DQUOTE, SP};
#[macro_export]
macro_rules! opt_nil {
($t:expr) => {
alt((map($t, Some), map(crate::proto::rfc3501::nil, |_| None)))
};
}
rule!(pub address : Address => map(paren!(tuple((
terminated(addr_name, SP),
terminated(addr_adl, SP),

View file

@ -1,5 +1,6 @@
use panorama_proto_common::Bytes;
use super::response::*;
use super::rfc3501::*;
#[test]
@ -15,7 +16,20 @@ fn test_literal() {
#[test]
fn test_list() {
let _ = response(Bytes::from(
b"* LIST (\\HasChildren \\UnMarked \\Trash) \".\" Trash\r\n",
assert!(matches!(
response(Bytes::from(
b"* LIST (\\HasChildren \\UnMarked \\Trash) \".\" Trash\r\n",
))
.unwrap()
.1,
Response::MailboxData(MailboxData::List(MailboxList {
flags,
delimiter: Some(b'.'),
mailbox: Mailbox::Name(mailbox),
}) ) if flags.len() == 3 &&
flags.contains(&MailboxListFlag::Extension(Atom::from(b"HasChildren"))) &&
flags.contains(&MailboxListFlag::Extension(Atom::from(b"UnMarked"))) &&
flags.contains(&MailboxListFlag::Extension(Atom::from(b"Trash"))) &&
&*mailbox == &b"Trash"[..]
));
}

View file

@ -7,12 +7,25 @@ use nom::{
CompareResult, Err, IResult, InputLength, Needed,
};
/// Glue code between nom and Bytes so they work together
/// Glue code between nom and Bytes so they work together.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Bytes(bytes::Bytes);
impl Bytes {
/// Length of the internal `Bytes`.
///
/// # Example
///
/// ```
/// # use panorama_proto_common::Bytes;
/// // the &, [..] is needed since &[u8; N] doesn't coerce automatically to &[u8]
/// let b = Bytes::from(&b"hello"[..]);
/// assert_eq!(b.len(), 5);
/// ```
pub fn len(&self) -> usize { self.0.len() }
/// Consumes the wrapper, returning the original `Bytes`.
pub fn inner(self) -> bytes::Bytes { self.0 }
}
impl DisplayBytes for Bytes {
@ -224,10 +237,6 @@ array_impls! {
50 51 52 53 54 55 56 57 58 59
}
impl Bytes {
pub fn inner(self) -> bytes::Bytes { self.0 }
}
impl Deref for Bytes {
type Target = [u8];
fn deref(&self) -> &Self::Target { &*self.0 }

View file

@ -1,15 +1,30 @@
pub fn quote_string(input: impl AsRef<[u8]>, should_escape: impl Fn(u8) -> bool) -> Vec<u8> {
let input = input.as_ref();
let mut ret = Vec::with_capacity(input.len() + 2);
/// Adds quotes around a byte-string according to a quote function.
///
/// # Example
///
/// ```
/// # use panorama_proto_common::quote_string;
/// let quote = quote_string(b'\x22', b'\\', |c| c == b'\x22' || c == b'\x27');
/// assert_eq!(quote(b"hello \"' world"), b"\"hello \\\"\\' world\"");
/// ```
pub fn quote_string<B, F>(quote: u8, escape: u8, should_escape: F) -> impl Fn(B) -> Vec<u8>
where
B: AsRef<[u8]>,
F: Fn(u8) -> bool,
{
move |input: B| {
let input = input.as_ref();
let mut ret = Vec::with_capacity(input.len() + 2);
ret.push(b'\x22');
for c in input {
if should_escape(*c) {
ret.push(b'\\');
ret.push(quote);
for c in input {
if should_escape(*c) {
ret.push(escape);
}
ret.push(*c);
}
ret.push(*c);
}
ret.push(b'\x22');
ret.push(quote);
ret
ret
}
}

View file

@ -5,6 +5,6 @@ mod bytes;
mod formatter;
mod parsers;
pub use crate::bytes::Bytes;
pub use crate::bytes::{Bytes, ShitCompare, ShitNeededForParsing};
pub use crate::formatter::quote_string;
pub use crate::parsers::{byte, never, parse_u32, satisfy, skip, tagi, take, take_while1, VResult};

View file

@ -6,7 +6,7 @@ use nom::{
use super::bytes::{ShitCompare, ShitNeededForParsing};
/// A specific form of `nom::IResult` that uses `nom::error::VerboseError`.
/// A specific form of `IResult` that uses `VerboseError`.
pub type VResult<I, O> = IResult<I, O, VerboseError<I>>;
/// `sep_list!(t, d)` represents `t *(d t)` and automatically collapses it into
@ -20,7 +20,10 @@ pub type VResult<I, O> = IResult<I, O, VerboseError<I>>;
macro_rules! sep_list {
($t:expr) => {
map(
pair($t, many0(preceded(crate::proto::rfc2234::SP, $t))),
pair(
$t,
many0(preceded(panorama_proto_common::byte(b'\x20'), $t)),
),
|(hd, mut tl)| {
tl.insert(0, hd);
tl
@ -35,7 +38,10 @@ macro_rules! sep_list {
};
(? $t:expr) => {
map(
opt(pair($t, many0(preceded(crate::proto::rfc2234::SP, $t)))),
opt(pair(
$t,
many0(preceded(panorama_proto_common::byte(b'\x20'), $t)),
)),
|opt| {
opt.map(|(hd, mut tl)| {
tl.insert(0, hd);
@ -56,13 +62,7 @@ macro_rules! sep_list {
};
}
#[macro_export]
macro_rules! opt_nil {
($t:expr) => {
alt((map($t, Some), map(crate::proto::rfc3501::nil, |_| None)))
};
}
/// Helper macro for wrapping a parser in parentheses.
#[macro_export]
macro_rules! paren {
($t:expr) => {

1
smtp/src/client/mod.rs Normal file
View file

@ -0,0 +1 @@

View file

@ -1 +1,2 @@
mod client;
pub mod proto;