mirror of
https://github.com/mailscope/kumomta.git
synced 2026-10-29 01:36:14 +00:00
message: replace mailparser dep with mailparsing
Use our own parser
This commit is contained in:
Generated
+1
-1
@@ -2875,8 +2875,8 @@ dependencies = [
|
||||
"kumo-log-types",
|
||||
"lazy_static",
|
||||
"lruttl",
|
||||
"mail-parser",
|
||||
"mailparse",
|
||||
"mailparsing",
|
||||
"mlua",
|
||||
"prometheus",
|
||||
"rand",
|
||||
|
||||
@@ -12,4 +12,6 @@ pub enum MailParsingError {
|
||||
InvalidContentTransferEncoding(String),
|
||||
#[error("parsing body: {0}")]
|
||||
BodyParse(String),
|
||||
#[error("Data is not ASCII or UTF-8")]
|
||||
NotAscii,
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ use crate::rfc5322_parser::Parser;
|
||||
use crate::{
|
||||
AddressList, MailParsingError, Mailbox, MailboxList, MimeParameters, Result, SharedString,
|
||||
};
|
||||
use std::convert::TryInto;
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
|
||||
@@ -188,10 +189,12 @@ impl<'a> Header<'a> {
|
||||
Parser::parse_unstructured_header(self.get_raw_value())
|
||||
}
|
||||
|
||||
pub fn parse_headers<S: Into<SharedString<'a>>>(
|
||||
pub fn parse_headers<S: TryInto<SharedString<'a>>>(
|
||||
header_block: S,
|
||||
) -> Result<HeaderParseResult<'a>> {
|
||||
let header_block = header_block.into();
|
||||
let header_block = header_block
|
||||
.try_into()
|
||||
.map_err(|_| MailParsingError::NotAscii)?;
|
||||
let mut headers = vec![];
|
||||
let mut idx = 0;
|
||||
let mut overall_conformance = HeaderConformance::default();
|
||||
|
||||
@@ -10,7 +10,7 @@ pub use error::MailParsingError;
|
||||
pub type Result<T> = std::result::Result<T, MailParsingError>;
|
||||
|
||||
pub use header::{Header, HeaderConformance, HeaderParseResult};
|
||||
pub use headermap::HeaderMap;
|
||||
pub use headermap::*;
|
||||
pub use mimepart::MimePart;
|
||||
pub use rfc5322_parser::*;
|
||||
pub use strings::SharedString;
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::header::{HeaderConformance, HeaderParseResult};
|
||||
use crate::headermap::HeaderMap;
|
||||
use crate::{Header, MailParsingError, MimeParameters, Result, SharedString};
|
||||
use charset::Charset;
|
||||
use std::convert::TryInto;
|
||||
use std::str::FromStr;
|
||||
|
||||
/// Define our own because data_encoding::BASE64_MIME, despite its name,
|
||||
@@ -80,8 +81,8 @@ impl Rfc2045Info {
|
||||
|
||||
impl<'a> MimePart<'a> {
|
||||
/// Parse some data into a tree of MimeParts
|
||||
pub fn parse<S: Into<SharedString<'a>>>(bytes: S) -> Result<Self> {
|
||||
let bytes = bytes.into();
|
||||
pub fn parse<S: TryInto<SharedString<'a>>>(bytes: S) -> Result<Self> {
|
||||
let bytes = bytes.try_into().map_err(|_| MailParsingError::NotAscii)?;
|
||||
Self::parse_impl(bytes, true)
|
||||
}
|
||||
|
||||
|
||||
@@ -1225,10 +1225,10 @@ pub enum Address {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct AddressList(Vec<Address>);
|
||||
pub struct AddressList(pub Vec<Address>);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct MailboxList(Vec<Mailbox>);
|
||||
pub struct MailboxList(pub Vec<Mailbox>);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Mailbox {
|
||||
|
||||
@@ -120,3 +120,11 @@ impl<'a> From<&'a str> for SharedString<'a> {
|
||||
Self::Borrowed(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a [u8]> for SharedString<'a> {
|
||||
type Error = std::str::Utf8Error;
|
||||
fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
|
||||
let s = std::str::from_utf8(s)?;
|
||||
Ok(Self::Borrowed(s))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ kumo-log-types = {path="../kumo-log-types"}
|
||||
lazy_static = "1.4"
|
||||
lruttl = {path="../lruttl"}
|
||||
mailparse = "0.14"
|
||||
mail-parser = "0.8"
|
||||
mailparsing = {path="../mailparsing"}
|
||||
mlua = {workspace=true, features=["vendored", "lua54", "async", "send", "serialize"]}
|
||||
prometheus = "0.13"
|
||||
rand = "0.8"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use config::any_err;
|
||||
use mail_parser::{Addr, Group, HeaderValue};
|
||||
use mailparsing::{Address, AddressList, EncodeHeaderValue, Mailbox};
|
||||
use mlua::{MetaMethod, UserData, UserDataFields, UserDataMethods};
|
||||
use rfc5321::{ForwardPath, ReversePath};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -146,6 +146,13 @@ impl HeaderAddressList {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<AddressList> for HeaderAddressList {
|
||||
fn from(input: AddressList) -> HeaderAddressList {
|
||||
let addresses: Vec<HeaderAddressEntry> = input.0.iter().map(Into::into).collect();
|
||||
HeaderAddressList(addresses)
|
||||
}
|
||||
}
|
||||
|
||||
impl UserData for HeaderAddressList {
|
||||
fn add_fields<'lua, F: UserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("user", |_, this| {
|
||||
@@ -183,18 +190,22 @@ pub enum HeaderAddressEntry {
|
||||
Group(AddressGroup),
|
||||
}
|
||||
|
||||
impl From<Addr<'_>> for HeaderAddressEntry {
|
||||
fn from(addr: Addr) -> Self {
|
||||
Self::Address(addr.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Group<'_>> for HeaderAddressEntry {
|
||||
fn from(group: Group) -> Self {
|
||||
Self::Group(AddressGroup {
|
||||
name: group.name.map(|s| s.to_string()),
|
||||
addresses: group.addresses.into_iter().map(|a| a.into()).collect(),
|
||||
})
|
||||
impl From<&Address> for HeaderAddressEntry {
|
||||
fn from(addr: &Address) -> HeaderAddressEntry {
|
||||
match addr {
|
||||
Address::Mailbox(mbox) => HeaderAddressEntry::Address(mbox.into()),
|
||||
Address::Group { name, entries } => {
|
||||
let addresses = entries.0.iter().map(Into::into).collect();
|
||||
HeaderAddressEntry::Group(AddressGroup {
|
||||
name: if name.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(name.to_string())
|
||||
},
|
||||
addresses,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,6 +215,15 @@ pub struct HeaderAddress {
|
||||
pub address: Option<String>,
|
||||
}
|
||||
|
||||
impl From<&Mailbox> for HeaderAddress {
|
||||
fn from(mbox: &Mailbox) -> HeaderAddress {
|
||||
Self {
|
||||
name: mbox.name.clone(),
|
||||
address: Some(mbox.address.encode_value().to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HeaderAddress {
|
||||
fn user(&self) -> anyhow::Result<&str> {
|
||||
let (user, _domain) = self.crack_address().map_err(any_err)?;
|
||||
@@ -251,59 +271,8 @@ impl UserData for HeaderAddress {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Addr<'_>> for HeaderAddress {
|
||||
fn from(addr: Addr) -> Self {
|
||||
Self {
|
||||
name: addr.name.map(|s| s.to_string()),
|
||||
address: addr.address.map(|s| s.to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AddressGroup {
|
||||
pub name: Option<String>,
|
||||
pub addresses: Vec<HeaderAddress>,
|
||||
}
|
||||
|
||||
impl HeaderAddressList {
|
||||
pub fn parse_header_value(data: &[u8]) -> Option<Self> {
|
||||
// The parser needs a newline in the data otherwise it
|
||||
// won't recognize the value
|
||||
let mut fixed = data.to_vec();
|
||||
fixed.push(b'\n');
|
||||
let res = mail_parser::parsers::MessageStream::new(&fixed).parse_address();
|
||||
|
||||
let mut results = vec![];
|
||||
|
||||
match res {
|
||||
HeaderValue::Address(addr) => {
|
||||
results.push(addr.into());
|
||||
}
|
||||
HeaderValue::AddressList(list) => {
|
||||
for addr in list {
|
||||
results.push(addr.into());
|
||||
}
|
||||
}
|
||||
HeaderValue::Group(group) => {
|
||||
results.push(group.into());
|
||||
}
|
||||
HeaderValue::GroupList(list) => {
|
||||
for group in list {
|
||||
results.push(group.into());
|
||||
}
|
||||
}
|
||||
HeaderValue::Text(_)
|
||||
| HeaderValue::TextList(_)
|
||||
| HeaderValue::DateTime(_)
|
||||
| HeaderValue::ContentType(_)
|
||||
| HeaderValue::Empty => {}
|
||||
}
|
||||
|
||||
if results.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(Self(results))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ use futures::FutureExt;
|
||||
use kumo_log_types::rfc3464::Report;
|
||||
use kumo_log_types::rfc5965::ARFReport;
|
||||
use mailparse::{MailHeader, MailHeaderMap};
|
||||
use mailparsing::HeaderParseResult;
|
||||
use mlua::{LuaSerdeExt, UserData, UserDataMethods};
|
||||
use prometheus::IntGauge;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -593,10 +594,15 @@ impl Message {
|
||||
header_name: &str,
|
||||
) -> anyhow::Result<Option<HeaderAddressList>> {
|
||||
let data = self.get_data();
|
||||
let (headers, _body_offset) = mailparse::parse_headers(&data)?;
|
||||
let HeaderParseResult { headers, .. } =
|
||||
mailparsing::Header::parse_headers(data.as_ref().as_ref())?;
|
||||
|
||||
match headers.get_first_header(header_name) {
|
||||
Some(hdr) => Ok(HeaderAddressList::parse_header_value(hdr.get_value_raw())),
|
||||
match headers.get_first(header_name) {
|
||||
Some(hdr) => {
|
||||
let list = hdr.as_address_list()?;
|
||||
let result: HeaderAddressList = list.into();
|
||||
Ok(Some(result))
|
||||
}
|
||||
None => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user