wow testing
This commit is contained in:
parent
0405b478eb
commit
60e0bb3bbb
12 changed files with 90 additions and 39 deletions
3
Justfile
3
Justfile
|
@ -1,2 +1,5 @@
|
|||
fmt:
|
||||
cargo +nightly fmt --all
|
||||
|
||||
doc:
|
||||
cargo doc --workspace --no-deps
|
||||
|
|
|
@ -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::{
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -159,7 +159,7 @@ pub struct MailboxList {
|
|||
pub mailbox: Mailbox,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum MailboxListFlag {
|
||||
NoInferiors,
|
||||
NoSelect,
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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"[..]
|
||||
));
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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
1
smtp/src/client/mod.rs
Normal file
|
@ -0,0 +1 @@
|
|||
|
|
@ -1 +1,2 @@
|
|||
mod client;
|
||||
pub mod proto;
|
||||
|
|
Loading…
Reference in a new issue