mirror of
https://github.com/chatmail/core.git
synced 2026-04-26 01:46:34 +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
|
||||
}
|
||||
|
||||
/// Returns true if message is Auto-Submitted.
|
||||
/// Returns true if message is auto-generated.
|
||||
pub fn is_bot(&self) -> bool {
|
||||
self.param.get_bool(Param::Bot).unwrap_or_default()
|
||||
}
|
||||
|
||||
@@ -117,8 +117,8 @@ pub(crate) struct MimeMessage {
|
||||
/// Hop info for debugging.
|
||||
pub(crate) hop_info: String,
|
||||
|
||||
/// Whether the contact sending this should be marked as bot.
|
||||
pub(crate) is_bot: bool,
|
||||
/// Whether the contact sending this should be marked as bot or non-bot.
|
||||
pub(crate) is_bot: Option<bool>,
|
||||
|
||||
/// When the message was received, in secs since epoch.
|
||||
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_sent = headers
|
||||
.get(HeaderDef::Date.get_headername())
|
||||
@@ -431,7 +428,7 @@ impl MimeMessage {
|
||||
is_mime_modified: false,
|
||||
decoded_data: Vec::new(),
|
||||
hop_info,
|
||||
is_bot,
|
||||
is_bot: None,
|
||||
timestamp_rcvd,
|
||||
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_inline_mailinglist_footer();
|
||||
parser.heuristically_parse_ndn(context).await;
|
||||
@@ -702,7 +706,7 @@ impl MimeMessage {
|
||||
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 {
|
||||
part.param.set(Param::Bot, "1");
|
||||
}
|
||||
@@ -2740,6 +2744,7 @@ Chat-Version: 1.0\n\
|
||||
Message-ID: <bar@example.org>\n\
|
||||
To: Alice <alice@example.org>\n\
|
||||
From: Bob <bob@example.org>\n\
|
||||
Auto-Submitted: auto-replied\n\
|
||||
Content-Type: multipart/report; report-type=disposition-notification;\n\t\
|
||||
boundary=\"kJBbU58X1xeWNHgBtTbMk80M5qnV4N\"\n\
|
||||
\n\
|
||||
@@ -2775,6 +2780,7 @@ Disposition: manual-action/MDN-sent-automatically; displayed\n\
|
||||
|
||||
assert_eq!(message.parts.len(), 1);
|
||||
assert_eq!(message.mdn_reports.len(), 1);
|
||||
assert_eq!(message.is_bot, None);
|
||||
}
|
||||
|
||||
/// Test parsing multiple MDNs combined in a single message.
|
||||
|
||||
@@ -65,7 +65,7 @@ pub enum Param {
|
||||
/// For Messages: the message is a reaction.
|
||||
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',
|
||||
|
||||
/// 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)
|
||||
.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))
|
||||
}
|
||||
|
||||
@@ -2684,6 +2684,36 @@ async fn test_read_receipts_dont_create_chats() -> Result<()> {
|
||||
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)]
|
||||
async fn test_gmx_forwarded_msg() -> Result<()> {
|
||||
let t = TestContext::new_alice().await;
|
||||
|
||||
Reference in New Issue
Block a user