mirror of
https://github.com/chatmail/core.git
synced 2026-05-19 06:46:32 +03:00
mimeparser: construct MimeMessage at the end of from_bytes()
This reduces the scope of code dealing with mutable structures.
This commit is contained in:
@@ -95,42 +95,25 @@ impl<'a> MimeMessage<'a> {
|
|||||||
pub fn from_bytes(context: &'a Context, body: &[u8]) -> Result<Self> {
|
pub fn from_bytes(context: &'a Context, body: &[u8]) -> Result<Self> {
|
||||||
let mail = mailparse::parse_mail(body)?;
|
let mail = mailparse::parse_mail(body)?;
|
||||||
|
|
||||||
let mut parser = MimeMessage {
|
|
||||||
parts: Vec::new(),
|
|
||||||
header: Default::default(),
|
|
||||||
decrypting_failed: false,
|
|
||||||
|
|
||||||
// only non-empty if it was a valid autocrypt message
|
|
||||||
signatures: Default::default(),
|
|
||||||
gossipped_addr: Default::default(),
|
|
||||||
is_forwarded: false,
|
|
||||||
context,
|
|
||||||
reports: Vec::new(),
|
|
||||||
is_system_message: SystemMessage::Unknown,
|
|
||||||
location_kml: None,
|
|
||||||
message_kml: None,
|
|
||||||
user_avatar: AvatarAction::None,
|
|
||||||
group_avatar: AvatarAction::None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let message_time = mail
|
let message_time = mail
|
||||||
.headers
|
.headers
|
||||||
.get_first_value("Date")?
|
.get_first_value("Date")?
|
||||||
.and_then(|v| mailparse::dateparse(&v).ok())
|
.and_then(|v| mailparse::dateparse(&v).ok())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let mut headers = Default::default();
|
||||||
|
|
||||||
// init known headers with what mailparse provided us
|
// init known headers with what mailparse provided us
|
||||||
parser.merge_headers(&mail.headers);
|
MimeMessage::merge_headers(&mut headers, &mail.headers);
|
||||||
|
|
||||||
// Memory location for a possible decrypted message.
|
// Memory location for a possible decrypted message.
|
||||||
let mail_raw;
|
let mail_raw;
|
||||||
|
let mut gossipped_addr = Default::default();
|
||||||
|
|
||||||
let mail = match e2ee::try_decrypt(parser.context, &mail, message_time) {
|
let (mail, signatures) = match e2ee::try_decrypt(context, &mail, message_time) {
|
||||||
Ok((raw, signatures)) => {
|
Ok((raw, signatures)) => {
|
||||||
// Valid autocrypt message, encrypted
|
|
||||||
parser.signatures = signatures;
|
|
||||||
|
|
||||||
if let Some(raw) = raw {
|
if let Some(raw) = raw {
|
||||||
|
// Valid autocrypt message, encrypted
|
||||||
mail_raw = raw;
|
mail_raw = raw;
|
||||||
let decrypted_mail = mailparse::parse_mail(&mail_raw)?;
|
let decrypted_mail = mailparse::parse_mail(&mail_raw)?;
|
||||||
if std::env::var(crate::DCC_MIME_DEBUG).is_ok() {
|
if std::env::var(crate::DCC_MIME_DEBUG).is_ok() {
|
||||||
@@ -142,17 +125,17 @@ impl<'a> MimeMessage<'a> {
|
|||||||
// "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")?;
|
||||||
parser.gossipped_addr =
|
gossipped_addr =
|
||||||
update_gossip_peerstates(context, message_time, &mail, gossip_headers)?;
|
update_gossip_peerstates(context, message_time, &mail, gossip_headers)?;
|
||||||
|
|
||||||
// let known protected headers from the decrypted
|
// let known protected headers from the decrypted
|
||||||
// part override the unencrypted top-level
|
// part override the unencrypted top-level
|
||||||
parser.merge_headers(&decrypted_mail.headers);
|
MimeMessage::merge_headers(&mut headers, &decrypted_mail.headers);
|
||||||
|
|
||||||
decrypted_mail
|
(decrypted_mail, signatures)
|
||||||
} else {
|
} else {
|
||||||
// Message was not encrypted
|
// Message was not encrypted
|
||||||
mail
|
(mail, signatures)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -163,13 +146,29 @@ impl<'a> MimeMessage<'a> {
|
|||||||
// if we just return here, the header is missing
|
// if we just return here, the header is missing
|
||||||
// and the caller cannot display the message
|
// and the caller cannot display the message
|
||||||
// and try to assign the message to a chat
|
// and try to assign the message to a chat
|
||||||
warn!(parser.context, "decryption failed: {}", err);
|
warn!(context, "decryption failed: {}", err);
|
||||||
mail
|
(mail, Default::default())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
parser.parse_mime_recursive(&mail)?;
|
let mut parser = MimeMessage {
|
||||||
|
parts: Vec::new(),
|
||||||
|
header: headers,
|
||||||
|
decrypting_failed: false,
|
||||||
|
|
||||||
|
// only non-empty if it was a valid autocrypt message
|
||||||
|
signatures,
|
||||||
|
gossipped_addr,
|
||||||
|
is_forwarded: false,
|
||||||
|
context,
|
||||||
|
reports: Vec::new(),
|
||||||
|
is_system_message: SystemMessage::Unknown,
|
||||||
|
location_kml: None,
|
||||||
|
message_kml: None,
|
||||||
|
user_avatar: AvatarAction::None,
|
||||||
|
group_avatar: AvatarAction::None,
|
||||||
|
};
|
||||||
|
parser.parse_mime_recursive(&mail)?;
|
||||||
parser.parse_headers()?;
|
parser.parse_headers()?;
|
||||||
|
|
||||||
Ok(parser)
|
Ok(parser)
|
||||||
@@ -744,16 +743,16 @@ impl<'a> MimeMessage<'a> {
|
|||||||
.and_then(|msgid| parse_message_id(msgid))
|
.and_then(|msgid| parse_message_id(msgid))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn merge_headers(&mut self, 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() {
|
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 = key.to_lowercase();
|
let key = key.to_lowercase();
|
||||||
if !self.header.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() {
|
if let Ok(value) = field.get_value() {
|
||||||
self.header.insert(key, value);
|
headers.insert(key, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user