mirror of
https://github.com/chatmail/core.git
synced 2026-05-05 14:26:30 +03:00
Update mailparse to 0.12
This commit is contained in:
committed by
holger krekel
parent
958802a233
commit
d78ea882c8
6
Cargo.lock
generated
6
Cargo.lock
generated
@@ -651,7 +651,7 @@ dependencies = [
|
|||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lettre_email 0.9.2 (git+https://github.com/deltachat/lettre)",
|
"lettre_email 0.9.2 (git+https://github.com/deltachat/lettre)",
|
||||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mailparse 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mailparse 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -1473,7 +1473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mailparse"
|
name = "mailparse"
|
||||||
version = "0.10.4"
|
version = "0.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -3299,7 +3299,7 @@ dependencies = [
|
|||||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||||
"checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
|
"checksum lru-cache 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
|
||||||
"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
|
"checksum lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d947cbb889ed21c2a84be6ffbaebf5b4e0f4340638cba0444907e38b56be084"
|
||||||
"checksum mailparse 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6c03df7fe4bab038aaa2f313baae7600de0afd606f8244860801c46f53babdd8"
|
"checksum mailparse 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7181507a68fef921f011b0c0f143efca20871da5ab3963bdc064537278469cd2"
|
||||||
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||||
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
||||||
"checksum md-5 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a18af3dcaf2b0219366cdb4e2af65a6101457b415c3d1a5c71dd9c2b7c77b9c8"
|
"checksum md-5 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a18af3dcaf2b0219366cdb4e2af65a6101457b415c3d1a5c71dd9c2b7c77b9c8"
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ bitflags = "1.1.0"
|
|||||||
debug_stub_derive = "0.3.0"
|
debug_stub_derive = "0.3.0"
|
||||||
sanitize-filename = "0.2.1"
|
sanitize-filename = "0.2.1"
|
||||||
stop-token = { version = "0.1.1", features = ["unstable"] }
|
stop-token = { version = "0.1.1", features = ["unstable"] }
|
||||||
mailparse = "0.10.2"
|
mailparse = "0.12.0"
|
||||||
encoded-words = { git = "https://github.com/async-email/encoded-words", branch="master" }
|
encoded-words = { git = "https://github.com/async-email/encoded-words", branch="master" }
|
||||||
native-tls = "0.2.3"
|
native-tls = "0.2.3"
|
||||||
image = { version = "0.22.4", default-features=false, features = ["gif_codec", "jpeg", "ico", "png_codec", "pnm", "webp", "bmp"] }
|
image = { version = "0.22.4", default-features=false, features = ["gif_codec", "jpeg", "ico", "png_codec", "pnm", "webp", "bmp"] }
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ impl Aheader {
|
|||||||
wanted_from: &str,
|
wanted_from: &str,
|
||||||
headers: &[mailparse::MailHeader<'_>],
|
headers: &[mailparse::MailHeader<'_>],
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
if let Ok(Some(value)) = headers.get_header_value(HeaderDef::Autocrypt) {
|
if let Some(value) = headers.get_header_value(HeaderDef::Autocrypt) {
|
||||||
match Self::from_str(&value) {
|
match Self::from_str(&value) {
|
||||||
Ok(header) => {
|
Ok(header) => {
|
||||||
if addr_cmp(&header.addr, wanted_from) {
|
if addr_cmp(&header.addr, wanted_from) {
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ pub fn try_decrypt(
|
|||||||
) -> Result<(Option<Vec<u8>>, HashSet<String>)> {
|
) -> Result<(Option<Vec<u8>>, HashSet<String>)> {
|
||||||
let from = mail
|
let from = mail
|
||||||
.headers
|
.headers
|
||||||
.get_header_value(HeaderDef::From_)?
|
.get_header_value(HeaderDef::From_)
|
||||||
.and_then(|from_addr| mailparse::addrparse(&from_addr).ok())
|
.and_then(|from_addr| mailparse::addrparse(&from_addr).ok())
|
||||||
.and_then(|from| from.extract_single_info())
|
.and_then(|from| from.extract_single_info())
|
||||||
.map(|from| from.addr)
|
.map(|from| from.addr)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::strum::AsStaticRef;
|
use crate::strum::AsStaticRef;
|
||||||
use mailparse::{MailHeader, MailHeaderMap, MailParseError};
|
use mailparse::{MailHeader, MailHeaderMap};
|
||||||
|
|
||||||
#[derive(Debug, Display, Clone, PartialEq, Eq, EnumVariantNames, AsStaticStr)]
|
#[derive(Debug, Display, Clone, PartialEq, Eq, EnumVariantNames, AsStaticStr)]
|
||||||
#[strum(serialize_all = "kebab_case")]
|
#[strum(serialize_all = "kebab_case")]
|
||||||
@@ -52,11 +52,11 @@ impl HeaderDef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait HeaderDefMap {
|
pub trait HeaderDefMap {
|
||||||
fn get_header_value(&self, headerdef: HeaderDef) -> Result<Option<String>, MailParseError>;
|
fn get_header_value(&self, headerdef: HeaderDef) -> Option<String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeaderDefMap for [MailHeader<'_>] {
|
impl HeaderDefMap for [MailHeader<'_>] {
|
||||||
fn get_header_value(&self, headerdef: HeaderDef) -> Result<Option<String>, MailParseError> {
|
fn get_header_value(&self, headerdef: HeaderDef) -> Option<String> {
|
||||||
self.get_first_value(headerdef.get_headername())
|
self.get_first_value(headerdef.get_headername())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,18 +79,13 @@ mod tests {
|
|||||||
let (headers, _) =
|
let (headers, _) =
|
||||||
mailparse::parse_headers(b"fRoM: Bob\naUtoCryPt-SeTup-MessAge: v99").unwrap();
|
mailparse::parse_headers(b"fRoM: Bob\naUtoCryPt-SeTup-MessAge: v99").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
headers
|
headers.get_header_value(HeaderDef::AutocryptSetupMessage),
|
||||||
.get_header_value(HeaderDef::AutocryptSetupMessage)
|
|
||||||
.unwrap(),
|
|
||||||
Some("v99".to_string())
|
Some("v99".to_string())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
headers.get_header_value(HeaderDef::From_).unwrap(),
|
headers.get_header_value(HeaderDef::From_),
|
||||||
Some("Bob".to_string())
|
Some("Bob".to_string())
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(headers.get_header_value(HeaderDef::Autocrypt), None);
|
||||||
headers.get_header_value(HeaderDef::Autocrypt).unwrap(),
|
|
||||||
None
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1338,30 +1338,27 @@ fn get_fetch_headers(prefetch_msg: &Fetch) -> Result<Vec<mailparse::MailHeader>>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn prefetch_get_message_id(headers: &[mailparse::MailHeader]) -> Result<String> {
|
fn prefetch_get_message_id(headers: &[mailparse::MailHeader]) -> Result<String> {
|
||||||
if let Some(message_id) = headers.get_header_value(HeaderDef::MessageId)? {
|
if let Some(message_id) = headers.get_header_value(HeaderDef::MessageId) {
|
||||||
Ok(crate::mimeparser::parse_message_id(&message_id)?)
|
Ok(crate::mimeparser::parse_message_id(&message_id)?)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Other("prefetch: No message ID found".to_string()))
|
Err(Error::Other("prefetch: No message ID found".to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prefetch_is_reply_to_chat_message(
|
fn prefetch_is_reply_to_chat_message(context: &Context, headers: &[mailparse::MailHeader]) -> bool {
|
||||||
context: &Context,
|
if let Some(value) = headers.get_header_value(HeaderDef::InReplyTo) {
|
||||||
headers: &[mailparse::MailHeader],
|
|
||||||
) -> Result<bool> {
|
|
||||||
if let Some(value) = headers.get_header_value(HeaderDef::InReplyTo)? {
|
|
||||||
if is_msgrmsg_rfc724_mid_in_list(context, &value) {
|
if is_msgrmsg_rfc724_mid_in_list(context, &value) {
|
||||||
return Ok(true);
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(value) = headers.get_header_value(HeaderDef::References)? {
|
if let Some(value) = headers.get_header_value(HeaderDef::References) {
|
||||||
if is_msgrmsg_rfc724_mid_in_list(context, &value) {
|
if is_msgrmsg_rfc724_mid_in_list(context, &value) {
|
||||||
return Ok(true);
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(false)
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prefetch_should_download(
|
fn prefetch_should_download(
|
||||||
@@ -1369,16 +1366,16 @@ fn prefetch_should_download(
|
|||||||
headers: &[mailparse::MailHeader],
|
headers: &[mailparse::MailHeader],
|
||||||
show_emails: ShowEmails,
|
show_emails: ShowEmails,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let is_chat_message = headers.get_header_value(HeaderDef::ChatVersion)?.is_some();
|
let is_chat_message = headers.get_header_value(HeaderDef::ChatVersion).is_some();
|
||||||
let is_reply_to_chat_message = prefetch_is_reply_to_chat_message(context, &headers)?;
|
let is_reply_to_chat_message = prefetch_is_reply_to_chat_message(context, &headers);
|
||||||
|
|
||||||
// Autocrypt Setup Message should be shown even if it is from non-chat client.
|
// Autocrypt Setup Message should be shown even if it is from non-chat client.
|
||||||
let is_autocrypt_setup_message = headers
|
let is_autocrypt_setup_message = headers
|
||||||
.get_header_value(HeaderDef::AutocryptSetupMessage)?
|
.get_header_value(HeaderDef::AutocryptSetupMessage)
|
||||||
.is_some();
|
.is_some();
|
||||||
|
|
||||||
let from_field = headers
|
let from_field = headers
|
||||||
.get_header_value(HeaderDef::From_)?
|
.get_header_value(HeaderDef::From_)
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
let (_contact_id, blocked_contact, origin) = from_field_to_contact_id(context, &from_field)?;
|
let (_contact_id, blocked_contact, origin) = from_field_to_contact_id(context, &from_field)?;
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ impl MimeMessage {
|
|||||||
|
|
||||||
let message_time = mail
|
let message_time = mail
|
||||||
.headers
|
.headers
|
||||||
.get_header_value(HeaderDef::Date)?
|
.get_header_value(HeaderDef::Date)
|
||||||
.and_then(|v| mailparse::dateparse(&v).ok())
|
.and_then(|v| mailparse::dateparse(&v).ok())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
@@ -111,8 +111,7 @@ impl MimeMessage {
|
|||||||
|
|
||||||
// Handle any gossip headers if the mail was encrypted. See section
|
// Handle any gossip headers if the mail was encrypted. See section
|
||||||
// "3.6 Key Gossip" of https://autocrypt.org/autocrypt-spec-1.1.0.pdf
|
// "3.6 Key Gossip" of https://autocrypt.org/autocrypt-spec-1.1.0.pdf
|
||||||
let gossip_headers =
|
let gossip_headers = decrypted_mail.headers.get_all_values("Autocrypt-Gossip");
|
||||||
decrypted_mail.headers.get_all_values("Autocrypt-Gossip")?;
|
|
||||||
gossipped_addr =
|
gossipped_addr =
|
||||||
update_gossip_peerstates(context, message_time, &mail, gossip_headers)?;
|
update_gossip_peerstates(context, message_time, &mail, gossip_headers)?;
|
||||||
|
|
||||||
@@ -746,16 +745,13 @@ impl MimeMessage {
|
|||||||
|
|
||||||
fn merge_headers(headers: &mut HashMap<String, String>, fields: &[mailparse::MailHeader<'_>]) {
|
fn merge_headers(headers: &mut HashMap<String, String>, fields: &[mailparse::MailHeader<'_>]) {
|
||||||
for field in fields {
|
for field in fields {
|
||||||
if let Ok(key) = field.get_key() {
|
// lowercasing all headers is technically not correct, but makes things work better
|
||||||
// lowercasing all headers is technically not correct, but makes things work better
|
let key = field.get_key().to_lowercase();
|
||||||
let key = key.to_lowercase();
|
if !headers.contains_key(&key) || // key already exists, only overwrite known types (protected headers)
|
||||||
if !headers.contains_key(&key) || // key already exists, only overwrite known types (protected headers)
|
|
||||||
is_known(&key) || key.starts_with("chat-")
|
is_known(&key) || key.starts_with("chat-")
|
||||||
{
|
{
|
||||||
if let Ok(value) = field.get_value() {
|
let value = field.get_value();
|
||||||
headers.insert(key, value);
|
headers.insert(key.to_string(), value);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -770,21 +766,13 @@ impl MimeMessage {
|
|||||||
let (report_fields, _) = mailparse::parse_headers(&report_body)?;
|
let (report_fields, _) = mailparse::parse_headers(&report_body)?;
|
||||||
|
|
||||||
// must be present
|
// must be present
|
||||||
if let Some(_disposition) = report_fields
|
if let Some(_disposition) = report_fields.get_header_value(HeaderDef::Disposition) {
|
||||||
.get_header_value(HeaderDef::Disposition)
|
|
||||||
.ok()
|
|
||||||
.flatten()
|
|
||||||
{
|
|
||||||
if let Some(original_message_id) = report_fields
|
if let Some(original_message_id) = report_fields
|
||||||
.get_header_value(HeaderDef::OriginalMessageId)
|
.get_header_value(HeaderDef::OriginalMessageId)
|
||||||
.ok()
|
|
||||||
.flatten()
|
|
||||||
.and_then(|v| parse_message_id(&v).ok())
|
.and_then(|v| parse_message_id(&v).ok())
|
||||||
{
|
{
|
||||||
let additional_message_ids = report_fields
|
let additional_message_ids = report_fields
|
||||||
.get_header_value(HeaderDef::AdditionalMessageIds)
|
.get_header_value(HeaderDef::AdditionalMessageIds)
|
||||||
.ok()
|
|
||||||
.flatten()
|
|
||||||
.map_or_else(Vec::new, |v| {
|
.map_or_else(Vec::new, |v| {
|
||||||
v.split(' ')
|
v.split(' ')
|
||||||
.filter_map(|s| parse_message_id(s).ok())
|
.filter_map(|s| parse_message_id(s).ok())
|
||||||
@@ -800,7 +788,7 @@ impl MimeMessage {
|
|||||||
warn!(
|
warn!(
|
||||||
context,
|
context,
|
||||||
"ignoring unknown disposition-notification, Message-Id: {:?}",
|
"ignoring unknown disposition-notification, Message-Id: {:?}",
|
||||||
report_fields.get_header_value(HeaderDef::MessageId).ok()
|
report_fields.get_header_value(HeaderDef::MessageId)
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
@@ -860,14 +848,9 @@ fn update_gossip_peerstates(
|
|||||||
|
|
||||||
if let Ok(ref header) = gossip_header {
|
if let Ok(ref header) = gossip_header {
|
||||||
if recipients.is_none() {
|
if recipients.is_none() {
|
||||||
recipients = Some(get_recipients(mail.headers.iter().filter_map(|v| {
|
recipients = Some(get_recipients(
|
||||||
let key = v.get_key();
|
mail.headers.iter().map(|v| (v.get_key(), v.get_value())),
|
||||||
let value = v.get_value();
|
));
|
||||||
if key.is_err() || value.is_err() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some((v.get_key().unwrap(), v.get_value().unwrap()))
|
|
||||||
})));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if recipients
|
if recipients
|
||||||
@@ -915,13 +898,8 @@ pub(crate) fn parse_message_id(value: &str) -> crate::error::Result<String> {
|
|||||||
let ids = mailparse::msgidparse(value)
|
let ids = mailparse::msgidparse(value)
|
||||||
.map_err(|err| format_err!("failed to parse message id {:?}", err))?;
|
.map_err(|err| format_err!("failed to parse message id {:?}", err))?;
|
||||||
|
|
||||||
if ids.len() == 1 {
|
if let Some(id) = ids.first() {
|
||||||
let id = &ids[0];
|
Ok(id.to_string())
|
||||||
if id.starts_with('<') && id.ends_with('>') {
|
|
||||||
Ok(id.chars().skip(1).take(id.len() - 2).collect())
|
|
||||||
} else {
|
|
||||||
bail!("message-ID {} is not enclosed in < and >", value);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
bail!("could not parse message_id: {}", value);
|
bail!("could not parse message_id: {}", value);
|
||||||
}
|
}
|
||||||
@@ -987,15 +965,12 @@ fn get_mime_type(mail: &mailparse::ParsedMail<'_>) -> Result<(Mime, Viewtype)> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_attachment_disposition(mail: &mailparse::ParsedMail<'_>) -> bool {
|
fn is_attachment_disposition(mail: &mailparse::ParsedMail<'_>) -> bool {
|
||||||
if let Ok(ct) = mail.get_content_disposition() {
|
let ct = mail.get_content_disposition();
|
||||||
return ct.disposition == DispositionType::Attachment
|
ct.disposition == DispositionType::Attachment
|
||||||
&& ct
|
&& ct
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.any(|(key, _value)| key.starts_with("filename"));
|
.any(|(key, _value)| key.starts_with("filename"))
|
||||||
}
|
|
||||||
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to get attachment filename.
|
/// Tries to get attachment filename.
|
||||||
@@ -1010,7 +985,7 @@ fn get_attachment_filename(mail: &mailparse::ParsedMail) -> Result<Option<String
|
|||||||
// or `Content-Disposition: ... filename*0*=... filename*1*=... filename*2*=...`
|
// or `Content-Disposition: ... filename*0*=... filename*1*=... filename*2*=...`
|
||||||
// or `Content-Disposition: ... filename=...`
|
// or `Content-Disposition: ... filename=...`
|
||||||
|
|
||||||
let ct = mail.get_content_disposition()?;
|
let ct = mail.get_content_disposition();
|
||||||
|
|
||||||
let desired_filename: Option<String> = ct
|
let desired_filename: Option<String> = ct
|
||||||
.params
|
.params
|
||||||
|
|||||||
Reference in New Issue
Block a user