v0.1.0
This commit is contained in:
parent
1dbb2ab8fc
commit
cf9640069d
11 changed files with 323 additions and 37 deletions
13
.github/FUNDING.yml
vendored
Normal file
13
.github/FUNDING.yml
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# These are supported funding model platforms
|
||||||
|
|
||||||
|
github: stalwartlabs
|
||||||
|
patreon: # Replace with a single Patreon username
|
||||||
|
open_collective: # Replace with a single Open Collective username
|
||||||
|
ko_fi: # Replace with a single Ko-fi username
|
||||||
|
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||||
|
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||||
|
liberapay: # Replace with a single Liberapay username
|
||||||
|
issuehunt: # Replace with a single IssueHunt username
|
||||||
|
otechie: # Replace with a single Otechie username
|
||||||
|
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||||
|
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
22
.github/workflows/rust.yml
vendored
Normal file
22
.github/workflows/rust.yml
vendored
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
name: "CI"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Build
|
||||||
|
run: cargo build --verbose
|
||||||
|
- name: Run tests
|
||||||
|
run: cargo test --verbose
|
|
@ -1,5 +1,13 @@
|
||||||
[package]
|
[package]
|
||||||
name = "smtp-proto"
|
name = "smtp-proto"
|
||||||
|
description = "SMTP protocol parser"
|
||||||
|
authors = [ "Stalwart Labs <hello@stalw.art>"]
|
||||||
|
repository = "https://github.com/stalwartlabs/smtp-proto"
|
||||||
|
homepage = "https://github.com/stalwartlabs/smtp-proto"
|
||||||
|
license = "AGPL-3.0-only"
|
||||||
|
keywords = ["smtp", "lmtp", "protocol", "parser"]
|
||||||
|
categories = ["email", "parser-implementations"]
|
||||||
|
readme = "README.md"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|
37
README.md
37
README.md
|
@ -1,2 +1,37 @@
|
||||||
# smtp-proto
|
# smtp-proto
|
||||||
SMTP Protocol
|
|
||||||
|
[](https://crates.io/crates/smtp-proto)
|
||||||
|
[](https://github.com/stalwartlabs/sieve/actions/workflows/rust.yml)
|
||||||
|
[](https://docs.rs/smtp-proto)
|
||||||
|
[](https://www.gnu.org/licenses/agpl-3.0)
|
||||||
|
|
||||||
|
_smtp-proto_ is a fast SMTP/LMTP parser for Rust that supports all [registered SMTP service extensions](https://www.iana.org/assignments/mail-parameters/mail-parameters.xhtml).
|
||||||
|
The library is part of Stalwart SMTP and LMTP servers. It is not yet documented so if you need help using the library please start a discussion.
|
||||||
|
|
||||||
|
|
||||||
|
## Testing & Fuzzing
|
||||||
|
|
||||||
|
To run the testsuite:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo test
|
||||||
|
```
|
||||||
|
|
||||||
|
To fuzz the library with `cargo-fuzz`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo +nightly fuzz run smtp_proto
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Licensed under the terms of the [GNU Affero General Public License](https://www.gnu.org/licenses/agpl-3.0.en.html) as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
See [LICENSE](LICENSE) for more details.
|
||||||
|
|
||||||
|
You can be released from the requirements of the AGPLv3 license by purchasing
|
||||||
|
a commercial license. Please contact licensing@stalw.art for more details.
|
||||||
|
|
||||||
|
## Copyright
|
||||||
|
|
||||||
|
Copyright (C) 2020-2023, Stalwart Labs Ltd.
|
||||||
|
|
61
src/lib.rs
61
src/lib.rs
|
@ -1,3 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2023, Stalwart Labs Ltd.
|
||||||
|
*
|
||||||
|
* This file is part of the Stalwart SMTP protocol parser.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
* in the LICENSE file at the top-level directory of this distribution.
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* You can be released from the requirements of the AGPLv3 license by
|
||||||
|
* purchasing a commercial license. Please contact licensing@stalw.art
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//! # smtp-proto
|
||||||
|
//!
|
||||||
|
//! [](https://crates.io/crates/smtp-proto)
|
||||||
|
//! [](https://github.com/stalwartlabs/sieve/actions/workflows/rust.yml)
|
||||||
|
//! [](https://docs.rs/smtp-proto)
|
||||||
|
//! [](https://www.gnu.org/licenses/agpl-3.0)
|
||||||
|
//!
|
||||||
|
//! _smtp-proto_ is a fast SMTP/LMTP parser for Rust that supports all [registered SMTP service extensions](https://www.iana.org/assignments/mail-parameters/mail-parameters.xhtml).
|
||||||
|
//! The library is part of Stalwart SMTP and LMTP servers. It is not yet documented so if you need help using the library please start a discussion.
|
||||||
|
//!
|
||||||
|
//!
|
||||||
|
//! ## Testing & Fuzzing
|
||||||
|
//!
|
||||||
|
//! To run the testsuite:
|
||||||
|
//!
|
||||||
|
//! ```bash
|
||||||
|
//! $ cargo test
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! To fuzz the library with `cargo-fuzz`:
|
||||||
|
//!
|
||||||
|
//! ```bash
|
||||||
|
//! $ cargo +nightly fuzz run smtp_proto
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ## License
|
||||||
|
//!
|
||||||
|
//! Licensed under the terms of the [GNU Affero General Public License](https://www.gnu.org/licenses/agpl-3.0.en.html) as published by
|
||||||
|
//! the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
//! See [LICENSE](LICENSE) for more details.
|
||||||
|
//!
|
||||||
|
//! You can be released from the requirements of the AGPLv3 license by purchasing
|
||||||
|
//! a commercial license. Please contact licensing@stalw.art for more details.
|
||||||
|
//!
|
||||||
|
//! ## Copyright
|
||||||
|
//!
|
||||||
|
//! Copyright (C) 2020-2023, Stalwart Labs Ltd.
|
||||||
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
pub mod request;
|
pub mod request;
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2023, Stalwart Labs Ltd.
|
||||||
|
*
|
||||||
|
* This file is part of the Stalwart SMTP protocol parser.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
* in the LICENSE file at the top-level directory of this distribution.
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* You can be released from the requirements of the AGPLv3 license by
|
||||||
|
* purchasing a commercial license. Please contact licensing@stalw.art
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub mod receiver;
|
pub mod receiver;
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2023, Stalwart Labs Ltd.
|
||||||
|
*
|
||||||
|
* This file is part of the Stalwart SMTP protocol parser.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
* in the LICENSE file at the top-level directory of this distribution.
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* You can be released from the requirements of the AGPLv3 license by
|
||||||
|
* purchasing a commercial license. Please contact licensing@stalw.art
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
use std::slice::Iter;
|
use std::slice::Iter;
|
||||||
|
|
||||||
use crate::*;
|
use crate::*;
|
||||||
|
@ -7,6 +30,9 @@ use super::*;
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct RequestParser {}
|
pub struct RequestParser {}
|
||||||
|
|
||||||
|
const MAX_ADDRESS_LEN: usize = 256;
|
||||||
|
const MAX_DOMAIN_LEN: usize = 255;
|
||||||
|
|
||||||
impl Request<String> {
|
impl Request<String> {
|
||||||
pub fn parse(bytes: &mut Iter<'_, u8>) -> Result<Request<String>, Error> {
|
pub fn parse(bytes: &mut Iter<'_, u8>) -> Result<Request<String>, Error> {
|
||||||
let mut parser = Rfc5321Parser::new(bytes);
|
let mut parser = Rfc5321Parser::new(bytes);
|
||||||
|
@ -70,7 +96,7 @@ impl Request<String> {
|
||||||
if parser.stop_char != LF {
|
if parser.stop_char != LF {
|
||||||
let host = parser.text()?;
|
let host = parser.text()?;
|
||||||
parser.seek_lf()?;
|
parser.seek_lf()?;
|
||||||
if !host.is_empty() {
|
if (1..=MAX_DOMAIN_LEN).contains(&host.len()) {
|
||||||
return Ok(Request::Ehlo { host });
|
return Ok(Request::Ehlo { host });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,7 +162,7 @@ impl Request<String> {
|
||||||
if parser.stop_char != LF {
|
if parser.stop_char != LF {
|
||||||
let value = parser.string()?;
|
let value = parser.string()?;
|
||||||
parser.seek_lf()?;
|
parser.seek_lf()?;
|
||||||
if !value.is_empty() {
|
if (1..=MAX_ADDRESS_LEN).contains(&value.len()) {
|
||||||
return Ok(Request::Expn { value });
|
return Ok(Request::Expn { value });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,7 +189,7 @@ impl Request<String> {
|
||||||
if parser.stop_char != LF {
|
if parser.stop_char != LF {
|
||||||
let host = parser.text()?;
|
let host = parser.text()?;
|
||||||
parser.seek_lf()?;
|
parser.seek_lf()?;
|
||||||
if !host.is_empty() {
|
if (1..=MAX_DOMAIN_LEN).contains(&host.len()) {
|
||||||
return Ok(Request::Lhlo { host });
|
return Ok(Request::Lhlo { host });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,7 +205,7 @@ impl Request<String> {
|
||||||
if parser.stop_char != LF {
|
if parser.stop_char != LF {
|
||||||
let value = parser.string()?;
|
let value = parser.string()?;
|
||||||
parser.seek_lf()?;
|
parser.seek_lf()?;
|
||||||
if !value.is_empty() {
|
if (1..=MAX_ADDRESS_LEN).contains(&value.len()) {
|
||||||
return Ok(Request::Vrfy { value });
|
return Ok(Request::Vrfy { value });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -272,7 +298,7 @@ impl Request<String> {
|
||||||
if parser.stop_char != LF {
|
if parser.stop_char != LF {
|
||||||
let host = parser.text()?;
|
let host = parser.text()?;
|
||||||
parser.seek_lf()?;
|
parser.seek_lf()?;
|
||||||
if !host.is_empty() {
|
if (1..=MAX_DOMAIN_LEN).contains(&host.len()) {
|
||||||
return Ok(Request::Helo { host });
|
return Ok(Request::Helo { host });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -423,11 +449,13 @@ impl<'x, 'y> Rfc5321Parser<'x, 'y> {
|
||||||
self.stop_char = ch;
|
self.stop_char = ch;
|
||||||
let value = value.into_string();
|
let value = value.into_string();
|
||||||
let len = value.chars().count();
|
let len = value.chars().count();
|
||||||
return Ok(if len == 0 || len < 255 && at_count == 1 && lp_len > 0 {
|
return Ok(
|
||||||
|
if len == 0 || len <= MAX_ADDRESS_LEN && at_count == 1 && lp_len > 0 {
|
||||||
value.into()
|
value.into()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
b'\r' => (),
|
b'\r' => (),
|
||||||
b':' if !in_quote && matches!(value.first(), Some(b'@')) => {
|
b':' if !in_quote && matches!(value.first(), Some(b'@')) => {
|
||||||
|
@ -442,22 +470,26 @@ impl<'x, 'y> Rfc5321Parser<'x, 'y> {
|
||||||
self.stop_char = b' ';
|
self.stop_char = b' ';
|
||||||
let value = value.into_string();
|
let value = value.into_string();
|
||||||
let len = value.chars().count();
|
let len = value.chars().count();
|
||||||
return Ok(if len == 0 || len < 255 && at_count == 1 && lp_len > 0 {
|
return Ok(
|
||||||
|
if len == 0 || len <= MAX_ADDRESS_LEN && at_count == 1 && lp_len > 0 {
|
||||||
value.into()
|
value.into()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
b'\n' => {
|
b'\n' => {
|
||||||
self.stop_char = b'\n';
|
self.stop_char = b'\n';
|
||||||
let value = value.into_string();
|
let value = value.into_string();
|
||||||
let len = value.chars().count();
|
let len = value.chars().count();
|
||||||
return Ok(if len == 0 || len < 255 && at_count == 1 && lp_len > 0 {
|
return Ok(
|
||||||
|
if len == 0 || len <= MAX_ADDRESS_LEN && at_count == 1 && lp_len > 0 {
|
||||||
value.into()
|
value.into()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
b'\"' if !in_quote || last_ch != b'\\' => {
|
b'\"' if !in_quote || last_ch != b'\\' => {
|
||||||
in_quote = !in_quote;
|
in_quote = !in_quote;
|
||||||
|
@ -937,7 +969,9 @@ impl<'x, 'y> Rfc5321Parser<'x, 'y> {
|
||||||
}
|
}
|
||||||
AUTH_ if self.stop_char == b'=' => {
|
AUTH_ if self.stop_char == b'=' => {
|
||||||
let mailbox = self.xtext()?;
|
let mailbox = self.xtext()?;
|
||||||
if !mailbox.is_empty() && self.stop_char.is_ascii_whitespace() {
|
if (1..=MAX_ADDRESS_LEN).contains(&mailbox.len())
|
||||||
|
&& self.stop_char.is_ascii_whitespace()
|
||||||
|
{
|
||||||
params.auth = mailbox.into();
|
params.auth = mailbox.into();
|
||||||
} else {
|
} else {
|
||||||
self.seek_lf()?;
|
self.seek_lf()?;
|
||||||
|
@ -1039,7 +1073,9 @@ impl<'x, 'y> Rfc5321Parser<'x, 'y> {
|
||||||
return Err(Error::InvalidParameter { param: "ORCPT" });
|
return Err(Error::InvalidParameter { param: "ORCPT" });
|
||||||
}
|
}
|
||||||
let addr = self.xtext()?;
|
let addr = self.xtext()?;
|
||||||
if self.stop_char.is_ascii_whitespace() && (1..=500).contains(&addr.len()) {
|
if self.stop_char.is_ascii_whitespace()
|
||||||
|
&& (1..=MAX_ADDRESS_LEN).contains(&addr.len())
|
||||||
|
{
|
||||||
params.orcpt = addr.into();
|
params.orcpt = addr.into();
|
||||||
} else {
|
} else {
|
||||||
self.seek_lf()?;
|
self.seek_lf()?;
|
||||||
|
@ -2081,12 +2117,11 @@ mod tests {
|
||||||
let (request, parsed_request): (&str, Result<Request<String>, Error>) = item;
|
let (request, parsed_request): (&str, Result<Request<String>, Error>) = item;
|
||||||
|
|
||||||
for extra in ["\n", "\r\n", " \n", " \r\n"] {
|
for extra in ["\n", "\r\n", " \n", " \r\n"] {
|
||||||
let request = format!("{}{}", request, extra);
|
let request = format!("{request}{extra}");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parsed_request,
|
parsed_request,
|
||||||
Request::parse(&mut request.as_bytes().iter()),
|
Request::parse(&mut request.as_bytes().iter()),
|
||||||
"failed for {:?}",
|
"failed for {request:?}"
|
||||||
request
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2023, Stalwart Labs Ltd.
|
||||||
|
*
|
||||||
|
* This file is part of the Stalwart SMTP protocol parser.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
* in the LICENSE file at the top-level directory of this distribution.
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* You can be released from the requirements of the AGPLv3 license by
|
||||||
|
* purchasing a commercial license. Please contact licensing@stalw.art
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
use std::slice::Iter;
|
use std::slice::Iter;
|
||||||
|
|
||||||
use crate::{Error, Request};
|
use crate::{Error, Request};
|
||||||
|
@ -247,7 +270,7 @@ mod tests {
|
||||||
continue 'outer;
|
continue 'outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic!("Failed for {:?}", data);
|
panic!("Failed for {data:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +318,7 @@ mod tests {
|
||||||
Err(Error::NeedsMoreData { .. }) => {
|
Err(Error::NeedsMoreData { .. }) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
err => panic!("Unexpected error {:?}", err),
|
err => panic!("Unexpected error {err:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2023, Stalwart Labs Ltd.
|
||||||
|
*
|
||||||
|
* This file is part of the Stalwart SMTP protocol parser.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
* in the LICENSE file at the top-level directory of this distribution.
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* You can be released from the requirements of the AGPLv3 license by
|
||||||
|
* purchasing a commercial license. Please contact licensing@stalw.art
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
|
@ -39,7 +62,7 @@ impl<T: Display> EhloResponse<T> {
|
||||||
while mechanisms != 0 {
|
while mechanisms != 0 {
|
||||||
let item = 1 << (63 - mechanisms.leading_zeros());
|
let item = 1 << (63 - mechanisms.leading_zeros());
|
||||||
mechanisms ^= item;
|
mechanisms ^= item;
|
||||||
write!(writer, " {}", (item as u64).to_mechanism())?;
|
write!(writer, " {}", item.to_mechanism())?;
|
||||||
}
|
}
|
||||||
writer.write_all(b"\r\n")
|
writer.write_all(b"\r\n")
|
||||||
}
|
}
|
||||||
|
@ -79,7 +102,7 @@ impl<T: Display> EhloResponse<T> {
|
||||||
EXT_MTRK => write!(writer, "MTRK\r\n"),
|
EXT_MTRK => write!(writer, "MTRK\r\n"),
|
||||||
EXT_NO_SOLICITING => {
|
EXT_NO_SOLICITING => {
|
||||||
if let Some(keywords) = &self.no_soliciting {
|
if let Some(keywords) = &self.no_soliciting {
|
||||||
write!(writer, "NO-SOLICITING {}\r\n", keywords)
|
write!(writer, "NO-SOLICITING {keywords}\r\n")
|
||||||
} else {
|
} else {
|
||||||
write!(writer, "NO-SOLICITING\r\n")
|
write!(writer, "NO-SOLICITING\r\n")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2023, Stalwart Labs Ltd.
|
||||||
|
*
|
||||||
|
* This file is part of the Stalwart SMTP protocol parser.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
* in the LICENSE file at the top-level directory of this distribution.
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* You can be released from the requirements of the AGPLv3 license by
|
||||||
|
* purchasing a commercial license. Please contact licensing@stalw.art
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use crate::{EhloResponse, Response};
|
use crate::{EhloResponse, Response};
|
||||||
|
|
|
@ -1,3 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020-2023, Stalwart Labs Ltd.
|
||||||
|
*
|
||||||
|
* This file is part of the Stalwart SMTP protocol parser.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License as
|
||||||
|
* published by the Free Software Foundation, either version 3 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU Affero General Public License for more details.
|
||||||
|
* in the LICENSE file at the top-level directory of this distribution.
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* You can be released from the requirements of the AGPLv3 license by
|
||||||
|
* purchasing a commercial license. Please contact licensing@stalw.art
|
||||||
|
* for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
use std::slice::Iter;
|
use std::slice::Iter;
|
||||||
|
|
||||||
use crate::{request::parser::Rfc5321Parser, *};
|
use crate::{request::parser::Rfc5321Parser, *};
|
||||||
|
@ -480,8 +503,7 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parsed_response,
|
parsed_response,
|
||||||
EhloResponse::parse(&mut response.as_bytes().iter()),
|
EhloResponse::parse(&mut response.as_bytes().iter()),
|
||||||
"failed for {:?}",
|
"failed for {response:?}",
|
||||||
response
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -624,8 +646,7 @@ mod tests {
|
||||||
ResponseReceiver::default()
|
ResponseReceiver::default()
|
||||||
.parse(&mut response.as_bytes().iter())
|
.parse(&mut response.as_bytes().iter())
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
"failed for {:?}",
|
"failed for {response:?}",
|
||||||
response
|
|
||||||
);
|
);
|
||||||
all_responses.extend_from_slice(response.as_bytes());
|
all_responses.extend_from_slice(response.as_bytes());
|
||||||
all_parsed_responses.push(parsed_response);
|
all_parsed_responses.push(parsed_response);
|
||||||
|
@ -643,15 +664,14 @@ mod tests {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
parsed_response.next(),
|
parsed_response.next(),
|
||||||
Some(response),
|
Some(response),
|
||||||
"chunk size {}",
|
"chunk size {chunk_size}",
|
||||||
chunk_size
|
|
||||||
);
|
);
|
||||||
receiver.reset();
|
receiver.reset();
|
||||||
}
|
}
|
||||||
Err(Error::NeedsMoreData { .. }) => {
|
Err(Error::NeedsMoreData { .. }) => {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
err => panic!("Unexpected error {:?} for chunk size {}", err, chunk_size),
|
err => panic!("Unexpected error {err:?} for chunk size {chunk_size}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue