mirror of
https://github.com/chatmail/core.git
synced 2026-05-07 17:06:35 +03:00
Implement get_headerdef method for MailHeader slices
This commit is contained in:
@@ -8,6 +8,7 @@ use std::{fmt, str};
|
|||||||
|
|
||||||
use crate::contact::*;
|
use crate::contact::*;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
|
use crate::headerdef::{HeaderDef, HeaderDefMap};
|
||||||
use crate::key::{DcKey, SignedPublicKey};
|
use crate::key::{DcKey, SignedPublicKey};
|
||||||
|
|
||||||
/// Possible values for encryption preference
|
/// Possible values for encryption preference
|
||||||
@@ -74,9 +75,7 @@ impl Aheader {
|
|||||||
wanted_from: &str,
|
wanted_from: &str,
|
||||||
headers: &[mailparse::MailHeader<'_>],
|
headers: &[mailparse::MailHeader<'_>],
|
||||||
) -> Option<Self> {
|
) -> Option<Self> {
|
||||||
use mailparse::MailHeaderMap;
|
if let Ok(Some(value)) = headers.get_headerdef(HeaderDef::Autocrypt) {
|
||||||
|
|
||||||
if let Ok(Some(value)) = headers.get_first_value("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) {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use mailparse::{MailHeaderMap, ParsedMail};
|
use mailparse::ParsedMail;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
|
|
||||||
use crate::aheader::*;
|
use crate::aheader::*;
|
||||||
@@ -11,6 +11,7 @@ use crate::config::Config;
|
|||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::dc_tools::EmailAddress;
|
use crate::dc_tools::EmailAddress;
|
||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
use crate::headerdef::{HeaderDef, HeaderDefMap};
|
||||||
use crate::key::{self, Key, KeyPairUse, SignedPublicKey};
|
use crate::key::{self, Key, KeyPairUse, SignedPublicKey};
|
||||||
use crate::keyring::*;
|
use crate::keyring::*;
|
||||||
use crate::peerstate::*;
|
use crate::peerstate::*;
|
||||||
@@ -124,7 +125,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_first_value("From")?
|
.get_headerdef(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,4 +1,5 @@
|
|||||||
use crate::strum::AsStaticRef;
|
use crate::strum::AsStaticRef;
|
||||||
|
use mailparse::{MailHeader, MailHeaderMap, MailParseError};
|
||||||
|
|
||||||
#[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")]
|
||||||
@@ -34,6 +35,7 @@ pub enum HeaderDef {
|
|||||||
ChatContent,
|
ChatContent,
|
||||||
ChatDuration,
|
ChatDuration,
|
||||||
ChatDispositionNotificationTo,
|
ChatDispositionNotificationTo,
|
||||||
|
Autocrypt,
|
||||||
AutocryptSetupMessage,
|
AutocryptSetupMessage,
|
||||||
SecureJoin,
|
SecureJoin,
|
||||||
SecureJoinGroup,
|
SecureJoinGroup,
|
||||||
@@ -50,6 +52,16 @@ impl HeaderDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait HeaderDefMap {
|
||||||
|
fn get_headerdef(&self, headerdef: HeaderDef) -> Result<Option<String>, MailParseError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HeaderDefMap for [MailHeader<'_>] {
|
||||||
|
fn get_headerdef(&self, headerdef: HeaderDef) -> Result<Option<String>, MailParseError> {
|
||||||
|
self.get_first_value(headerdef.get_headername())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -61,4 +73,22 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(HeaderDef::_TestHeader.get_headername(), "test-header");
|
assert_eq!(HeaderDef::_TestHeader.get_headername(), "test-header");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
/// Test that headers are parsed case-insensitively
|
||||||
|
fn headerdef_case() {
|
||||||
|
let (headers, _) =
|
||||||
|
mailparse::parse_headers(b"fRoM: Bob\naUtoCryPt-SeTup-MessAge: v99").unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
headers
|
||||||
|
.get_headerdef(HeaderDef::AutocryptSetupMessage)
|
||||||
|
.unwrap(),
|
||||||
|
Some("v99".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
headers.get_headerdef(HeaderDef::From_).unwrap(),
|
||||||
|
Some("Bob".to_string())
|
||||||
|
);
|
||||||
|
assert_eq!(headers.get_headerdef(HeaderDef::Autocrypt).unwrap(), None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ use async_imap::{
|
|||||||
use async_std::sync::{Mutex, RwLock};
|
use async_std::sync::{Mutex, RwLock};
|
||||||
use async_std::task;
|
use async_std::task;
|
||||||
|
|
||||||
use mailparse::MailHeaderMap;
|
|
||||||
|
|
||||||
use crate::config::*;
|
use crate::config::*;
|
||||||
use crate::constants::*;
|
use crate::constants::*;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
@@ -23,7 +21,7 @@ use crate::dc_receive_imf::{
|
|||||||
dc_receive_imf, from_field_to_contact_id, is_msgrmsg_rfc724_mid_in_list,
|
dc_receive_imf, from_field_to_contact_id, is_msgrmsg_rfc724_mid_in_list,
|
||||||
};
|
};
|
||||||
use crate::events::Event;
|
use crate::events::Event;
|
||||||
use crate::headerdef::HeaderDef;
|
use crate::headerdef::{HeaderDef, HeaderDefMap};
|
||||||
use crate::imap_client::*;
|
use crate::imap_client::*;
|
||||||
use crate::job::{job_add, Action};
|
use crate::job::{job_add, Action};
|
||||||
use crate::login_param::{CertificateChecks, LoginParam};
|
use crate::login_param::{CertificateChecks, LoginParam};
|
||||||
@@ -1304,31 +1302,24 @@ 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_first_value(&HeaderDef::MessageId.get_headername())? {
|
if let Some(message_id) = headers.get_headerdef(HeaderDef::MessageId)? {
|
||||||
Ok(parse_message_id(&message_id)?)
|
Ok(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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks if fetch result contains a header
|
|
||||||
fn prefetch_has_header(headers: &[mailparse::MailHeader], headerdef: HeaderDef) -> Result<bool> {
|
|
||||||
Ok(headers
|
|
||||||
.get_first_value(&headerdef.get_headername())?
|
|
||||||
.is_some())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn prefetch_is_reply_to_chat_message(
|
fn prefetch_is_reply_to_chat_message(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
headers: &[mailparse::MailHeader],
|
headers: &[mailparse::MailHeader],
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
if let Some(value) = headers.get_first_value(&HeaderDef::InReplyTo.get_headername())? {
|
if let Some(value) = headers.get_headerdef(HeaderDef::InReplyTo)? {
|
||||||
if is_msgrmsg_rfc724_mid_in_list(context, &value) {
|
if is_msgrmsg_rfc724_mid_in_list(context, &value) {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(value) = headers.get_first_value(&HeaderDef::References.get_headername())? {
|
if let Some(value) = headers.get_headerdef(HeaderDef::References)? {
|
||||||
if is_msgrmsg_rfc724_mid_in_list(context, &value) {
|
if is_msgrmsg_rfc724_mid_in_list(context, &value) {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
@@ -1342,16 +1333,15 @@ fn prefetch_should_download(
|
|||||||
headers: &[mailparse::MailHeader],
|
headers: &[mailparse::MailHeader],
|
||||||
show_emails: ShowEmails,
|
show_emails: ShowEmails,
|
||||||
) -> Result<bool> {
|
) -> Result<bool> {
|
||||||
let is_chat_message = prefetch_has_header(&headers, HeaderDef::ChatVersion)?;
|
let is_chat_message = headers.get_headerdef(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 =
|
let is_autocrypt_setup_message = headers
|
||||||
prefetch_has_header(&headers, HeaderDef::AutocryptSetupMessage)?;
|
.get_headerdef(HeaderDef::AutocryptSetupMessage)?
|
||||||
|
.is_some();
|
||||||
|
|
||||||
let from_field = headers
|
let from_field = headers.get_headerdef(HeaderDef::From_)?.unwrap_or_default();
|
||||||
.get_first_value(&HeaderDef::From_.get_headername())?
|
|
||||||
.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)?;
|
||||||
let accepted_contact = origin.is_known();
|
let accepted_contact = origin.is_known();
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ use crate::dehtml::dehtml;
|
|||||||
use crate::e2ee;
|
use crate::e2ee;
|
||||||
use crate::error::Result;
|
use crate::error::Result;
|
||||||
use crate::events::Event;
|
use crate::events::Event;
|
||||||
use crate::headerdef::HeaderDef;
|
use crate::headerdef::{HeaderDef, HeaderDefMap};
|
||||||
use crate::job::{job_add, Action};
|
use crate::job::{job_add, Action};
|
||||||
use crate::location;
|
use crate::location;
|
||||||
use crate::message;
|
use crate::message;
|
||||||
@@ -96,7 +96,7 @@ impl MimeMessage {
|
|||||||
|
|
||||||
let message_time = mail
|
let message_time = mail
|
||||||
.headers
|
.headers
|
||||||
.get_first_value("Date")?
|
.get_headerdef(HeaderDef::Date)?
|
||||||
.and_then(|v| mailparse::dateparse(&v).ok())
|
.and_then(|v| mailparse::dateparse(&v).ok())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
@@ -781,16 +781,19 @@ impl MimeMessage {
|
|||||||
let (report_fields, _) = mailparse::parse_headers(&report_body)?;
|
let (report_fields, _) = mailparse::parse_headers(&report_body)?;
|
||||||
|
|
||||||
// must be present
|
// must be present
|
||||||
let disp = HeaderDef::Disposition.get_headername();
|
if let Some(_disposition) = report_fields
|
||||||
if let Some(_disposition) = report_fields.get_first_value(&disp).ok().flatten() {
|
.get_headerdef(HeaderDef::Disposition)
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
{
|
||||||
if let Some(original_message_id) = report_fields
|
if let Some(original_message_id) = report_fields
|
||||||
.get_first_value(&HeaderDef::OriginalMessageId.get_headername())
|
.get_headerdef(HeaderDef::OriginalMessageId)
|
||||||
.ok()
|
.ok()
|
||||||
.flatten()
|
.flatten()
|
||||||
.and_then(|v| parse_message_id(&v))
|
.and_then(|v| parse_message_id(&v))
|
||||||
{
|
{
|
||||||
let additional_message_ids = report_fields
|
let additional_message_ids = report_fields
|
||||||
.get_first_value(&HeaderDef::AdditionalMessageIds.get_headername())
|
.get_headerdef(HeaderDef::AdditionalMessageIds)
|
||||||
.ok()
|
.ok()
|
||||||
.flatten()
|
.flatten()
|
||||||
.map_or_else(Vec::new, |v| {
|
.map_or_else(Vec::new, |v| {
|
||||||
@@ -806,7 +809,7 @@ impl MimeMessage {
|
|||||||
warn!(
|
warn!(
|
||||||
context,
|
context,
|
||||||
"ignoring unknown disposition-notification, Message-Id: {:?}",
|
"ignoring unknown disposition-notification, Message-Id: {:?}",
|
||||||
report_fields.get_first_value("Message-ID").ok()
|
report_fields.get_headerdef(HeaderDef::MessageId).ok()
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(None)
|
Ok(None)
|
||||||
|
|||||||
Reference in New Issue
Block a user