diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 3d796a211..d21e3f0ac 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -220,13 +220,8 @@ impl MimeMessage { let mail = mailparse::parse_mail(body)?; let timestamp_rcvd = smeared_time(context); - let timestamp_sent = mail - .headers - .get_header_value(HeaderDef::Date) - .and_then(|v| mailparse::dateparse(&v).ok()) - .map_or(timestamp_rcvd, |value| { - min(value, timestamp_rcvd + constants::TIMESTAMP_SENT_TOLERANCE) - }); + let mut timestamp_sent = + Self::get_timestamp_sent(&mail.headers, timestamp_rcvd, timestamp_rcvd); let mut hop_info = parse_receive_headers(&mail.get_headers()); let mut headers = Default::default(); @@ -254,6 +249,8 @@ impl MimeMessage { // We don't remove "subject" from `headers` because currently just signed // messages are shown as unencrypted anyway. + timestamp_sent = + Self::get_timestamp_sent(&mail.headers, timestamp_sent, timestamp_rcvd); MimeMessage::merge_headers( context, &mut headers, @@ -349,6 +346,8 @@ impl MimeMessage { content }); if let (Ok(mail), true) = (mail, encrypted) { + timestamp_sent = + Self::get_timestamp_sent(&mail.headers, timestamp_sent, timestamp_rcvd); if !signatures.is_empty() { // Handle any gossip headers if the mail was encrypted. See section // "3.6 Key Gossip" of @@ -525,6 +524,18 @@ impl MimeMessage { Ok(parser) } + fn get_timestamp_sent( + hdrs: &[mailparse::MailHeader<'_>], + default: i64, + timestamp_rcvd: i64, + ) -> i64 { + hdrs.get_header_value(HeaderDef::Date) + .and_then(|v| mailparse::dateparse(&v).ok()) + .map_or(default, |value| { + min(value, timestamp_rcvd + constants::TIMESTAMP_SENT_TOLERANCE) + }) + } + /// Parses system messages. fn parse_system_message_headers(&mut self, context: &Context) { if self.get_header(HeaderDef::AutocryptSetupMessage).is_some() && !self.incoming { diff --git a/src/receive_imf/tests.rs b/src/receive_imf/tests.rs index d749bf4c9..91c2ffb79 100644 --- a/src/receive_imf/tests.rs +++ b/src/receive_imf/tests.rs @@ -15,7 +15,7 @@ use crate::download::MIN_DOWNLOAD_LIMIT; use crate::imap::prefetch_should_download; use crate::imex::{imex, ImexMode}; use crate::test_utils::{get_chat_msg, mark_as_verified, TestContext, TestContextManager}; -use crate::tools::SystemTime; +use crate::tools::{time, SystemTime}; #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_outgoing() -> Result<()> { @@ -3326,6 +3326,22 @@ async fn test_bot_recv_existing_msg() -> Result<()> { Ok(()) } +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_wrong_date_in_imf_section() { + let mut tcm = TestContextManager::new(); + let alice = &tcm.alice().await; + let bob = &tcm.bob().await; + let alice_chat_id = tcm.send_recv_accept(bob, alice, "hi").await.chat_id; + let time_before_sending = time(); + let mut sent_msg = alice.send_text(alice_chat_id, "hi").await; + sent_msg.payload = sent_msg.payload.replace( + "Date:", + "Date: Tue, 29 Feb 1972 22:37:57 +0000\nX-Microsoft-Original-Date:", + ); + let msg = bob.recv_msg(&sent_msg).await; + assert!(msg.timestamp_sent >= time_before_sending); +} + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_no_private_reply_to_blocked_account() -> Result<()> { let mut tcm = TestContextManager::new();