mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 09:26:29 +03:00
fix: Treat only "Auto-Submitted: auto-generated" messages as bot-sent (#5213)
"Auto-Submitted: auto-replied" messages mustn't be considered as sent by either bots or non-bots, e.g. MDNs have this header value and it's the same for bots and non-bots.
This commit is contained in:
@@ -757,7 +757,7 @@ impl Message {
|
|||||||
self.param.get_int(Param::GuaranteeE2ee).unwrap_or_default() != 0
|
self.param.get_int(Param::GuaranteeE2ee).unwrap_or_default() != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if message is Auto-Submitted.
|
/// Returns true if message is auto-generated.
|
||||||
pub fn is_bot(&self) -> bool {
|
pub fn is_bot(&self) -> bool {
|
||||||
self.param.get_bool(Param::Bot).unwrap_or_default()
|
self.param.get_bool(Param::Bot).unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -117,8 +117,8 @@ pub(crate) struct MimeMessage {
|
|||||||
/// Hop info for debugging.
|
/// Hop info for debugging.
|
||||||
pub(crate) hop_info: String,
|
pub(crate) hop_info: String,
|
||||||
|
|
||||||
/// Whether the contact sending this should be marked as bot.
|
/// Whether the contact sending this should be marked as bot or non-bot.
|
||||||
pub(crate) is_bot: bool,
|
pub(crate) is_bot: Option<bool>,
|
||||||
|
|
||||||
/// When the message was received, in secs since epoch.
|
/// When the message was received, in secs since epoch.
|
||||||
pub(crate) timestamp_rcvd: i64,
|
pub(crate) timestamp_rcvd: i64,
|
||||||
@@ -394,9 +394,6 @@ impl MimeMessage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Auto-submitted is also set by holiday-notices so we also check `chat-version`
|
|
||||||
let is_bot = headers.contains_key("auto-submitted") && headers.contains_key("chat-version");
|
|
||||||
|
|
||||||
let timestamp_rcvd = smeared_time(context);
|
let timestamp_rcvd = smeared_time(context);
|
||||||
let timestamp_sent = headers
|
let timestamp_sent = headers
|
||||||
.get(HeaderDef::Date.get_headername())
|
.get(HeaderDef::Date.get_headername())
|
||||||
@@ -431,7 +428,7 @@ impl MimeMessage {
|
|||||||
is_mime_modified: false,
|
is_mime_modified: false,
|
||||||
decoded_data: Vec::new(),
|
decoded_data: Vec::new(),
|
||||||
hop_info,
|
hop_info,
|
||||||
is_bot,
|
is_bot: None,
|
||||||
timestamp_rcvd,
|
timestamp_rcvd,
|
||||||
timestamp_sent,
|
timestamp_sent,
|
||||||
};
|
};
|
||||||
@@ -464,6 +461,13 @@ impl MimeMessage {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if parser.mdn_reports.is_empty() {
|
||||||
|
// "Auto-Submitted" is also set by holiday-notices so we also check "chat-version".
|
||||||
|
let is_bot = parser.headers.get("auto-submitted")
|
||||||
|
== Some(&"auto-generated".to_string())
|
||||||
|
&& parser.headers.contains_key("chat-version");
|
||||||
|
parser.is_bot = Some(is_bot);
|
||||||
|
}
|
||||||
parser.maybe_remove_bad_parts();
|
parser.maybe_remove_bad_parts();
|
||||||
parser.maybe_remove_inline_mailinglist_footer();
|
parser.maybe_remove_inline_mailinglist_footer();
|
||||||
parser.heuristically_parse_ndn(context).await;
|
parser.heuristically_parse_ndn(context).await;
|
||||||
@@ -702,7 +706,7 @@ impl MimeMessage {
|
|||||||
self.do_add_single_part(part);
|
self.do_add_single_part(part);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.headers.contains_key("auto-submitted") {
|
if self.is_bot == Some(true) {
|
||||||
for part in &mut self.parts {
|
for part in &mut self.parts {
|
||||||
part.param.set(Param::Bot, "1");
|
part.param.set(Param::Bot, "1");
|
||||||
}
|
}
|
||||||
@@ -2740,6 +2744,7 @@ Chat-Version: 1.0\n\
|
|||||||
Message-ID: <bar@example.org>\n\
|
Message-ID: <bar@example.org>\n\
|
||||||
To: Alice <alice@example.org>\n\
|
To: Alice <alice@example.org>\n\
|
||||||
From: Bob <bob@example.org>\n\
|
From: Bob <bob@example.org>\n\
|
||||||
|
Auto-Submitted: auto-replied\n\
|
||||||
Content-Type: multipart/report; report-type=disposition-notification;\n\t\
|
Content-Type: multipart/report; report-type=disposition-notification;\n\t\
|
||||||
boundary=\"kJBbU58X1xeWNHgBtTbMk80M5qnV4N\"\n\
|
boundary=\"kJBbU58X1xeWNHgBtTbMk80M5qnV4N\"\n\
|
||||||
\n\
|
\n\
|
||||||
@@ -2775,6 +2780,7 @@ Disposition: manual-action/MDN-sent-automatically; displayed\n\
|
|||||||
|
|
||||||
assert_eq!(message.parts.len(), 1);
|
assert_eq!(message.parts.len(), 1);
|
||||||
assert_eq!(message.mdn_reports.len(), 1);
|
assert_eq!(message.mdn_reports.len(), 1);
|
||||||
|
assert_eq!(message.is_bot, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Test parsing multiple MDNs combined in a single message.
|
/// Test parsing multiple MDNs combined in a single message.
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ pub enum Param {
|
|||||||
/// For Messages: the message is a reaction.
|
/// For Messages: the message is a reaction.
|
||||||
Reaction = b'x',
|
Reaction = b'x',
|
||||||
|
|
||||||
/// For Messages: a message with Auto-Submitted header ("bot").
|
/// For Messages: a message with "Auto-Submitted: auto-generated" header ("bot").
|
||||||
Bot = b'b',
|
Bot = b'b',
|
||||||
|
|
||||||
/// For Messages: unset or 0=not forwarded,
|
/// For Messages: unset or 0=not forwarded,
|
||||||
|
|||||||
@@ -539,7 +539,9 @@ pub(crate) async fn receive_imf_inner(
|
|||||||
.handle_reports(context, from_id, &mime_parser.parts)
|
.handle_reports(context, from_id, &mime_parser.parts)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
from_id.mark_bot(context, mime_parser.is_bot).await?;
|
if let Some(is_bot) = mime_parser.is_bot {
|
||||||
|
from_id.mark_bot(context, is_bot).await?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Some(received_msg))
|
Ok(Some(received_msg))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2684,6 +2684,36 @@ async fn test_read_receipts_dont_create_chats() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Test that read receipts don't unmark contacts as bots.
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
|
async fn test_read_receipts_dont_unmark_bots() -> Result<()> {
|
||||||
|
let alice = &TestContext::new_alice().await;
|
||||||
|
let bob = &TestContext::new_bob().await;
|
||||||
|
let ab_contact = alice.add_or_lookup_contact(bob).await;
|
||||||
|
ab_contact.id.mark_bot(alice, true).await?;
|
||||||
|
let alice_chat = alice.create_chat(bob).await;
|
||||||
|
|
||||||
|
// Alice sends and Bob receives a message.
|
||||||
|
bob.recv_msg(&alice.send_text(alice_chat.id, "Message").await)
|
||||||
|
.await;
|
||||||
|
let received_msg = bob.get_last_msg().await;
|
||||||
|
|
||||||
|
// Bob sends a read receipt.
|
||||||
|
let mdn_mimefactory =
|
||||||
|
crate::mimefactory::MimeFactory::from_mdn(bob, &received_msg, vec![]).await?;
|
||||||
|
let rendered_mdn = mdn_mimefactory.render(bob).await?;
|
||||||
|
let mdn_body = rendered_mdn.message;
|
||||||
|
|
||||||
|
// Alice receives the read receipt.
|
||||||
|
receive_imf(alice, mdn_body.as_bytes(), false).await?;
|
||||||
|
let msg = alice.get_last_msg_in(alice_chat.id).await;
|
||||||
|
assert_eq!(msg.state, MessageState::OutMdnRcvd);
|
||||||
|
let ab_contact = alice.add_or_lookup_contact(bob).await;
|
||||||
|
assert!(ab_contact.is_bot());
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
async fn test_gmx_forwarded_msg() -> Result<()> {
|
async fn test_gmx_forwarded_msg() -> Result<()> {
|
||||||
let t = TestContext::new_alice().await;
|
let t = TestContext::new_alice().await;
|
||||||
|
|||||||
Reference in New Issue
Block a user