mirror of
https://github.com/chatmail/core.git
synced 2026-05-01 20:36:31 +03:00
Don't directly download messages from the Spam folder (#3015)
fix #3007 My approach is: We don't download any messages from the spam folder anymore, and only download them if they were moved out. This means that is-it-spam logic only resides in spam_target_folder(). This has some implications, see the comments.
This commit is contained in:
@@ -193,7 +193,6 @@ pub(crate) async fn dc_receive_imf_inner(
|
||||
&mut mime_parser,
|
||||
imf_raw,
|
||||
incoming,
|
||||
incoming_origin,
|
||||
server_folder,
|
||||
&to_ids,
|
||||
&rfc724_mid,
|
||||
@@ -415,7 +414,6 @@ async fn add_parts(
|
||||
mime_parser: &mut MimeMessage,
|
||||
imf_raw: &[u8],
|
||||
incoming: bool,
|
||||
incoming_origin: Origin,
|
||||
server_folder: &str,
|
||||
to_ids: &[u32],
|
||||
rfc724_mid: &str,
|
||||
@@ -432,7 +430,6 @@ async fn add_parts(
|
||||
) -> Result<ReceivedMsg> {
|
||||
let mut chat_id = None;
|
||||
let mut chat_id_blocked = Blocked::Not;
|
||||
let mut incoming_origin = incoming_origin;
|
||||
|
||||
let parent = get_parent_message(context, mime_parser).await?;
|
||||
|
||||
@@ -676,7 +673,6 @@ async fn add_parts(
|
||||
if chat_id_blocked != Blocked::Not {
|
||||
if chat_id_blocked != create_blocked {
|
||||
chat_id.set_blocked(context, create_blocked).await?;
|
||||
chat_id_blocked = create_blocked;
|
||||
}
|
||||
if create_blocked == Blocked::Request && parent.is_some() {
|
||||
// we do not want any chat to be created implicitly. Because of the origin-scale-up,
|
||||
@@ -687,9 +683,6 @@ async fn add_parts(
|
||||
context,
|
||||
"Message is a reply to a known message, mark sender as known.",
|
||||
);
|
||||
if !incoming_origin.is_known() {
|
||||
incoming_origin = Origin::IncomingReplyTo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -701,15 +694,6 @@ async fn add_parts(
|
||||
} else {
|
||||
MessageState::InFresh
|
||||
};
|
||||
|
||||
let is_spam = (chat_id_blocked == Blocked::Request)
|
||||
&& !incoming_origin.is_known()
|
||||
&& (is_dc_message == MessengerMessage::No)
|
||||
&& context.is_spam_folder(server_folder).await?;
|
||||
if is_spam {
|
||||
chat_id = Some(DC_CHAT_ID_TRASH);
|
||||
info!(context, "Message is probably spam (TRASH)");
|
||||
}
|
||||
} else {
|
||||
// Outgoing
|
||||
|
||||
@@ -2363,12 +2347,10 @@ fn dc_create_incoming_rfc724_mid(mime: &MimeMessage) -> String {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use chat::get_chat_contacts;
|
||||
|
||||
use mailparse::MailHeaderMap;
|
||||
|
||||
use super::*;
|
||||
|
||||
use crate::chat::get_chat_contacts;
|
||||
use crate::chat::{get_chat_msgs, ChatItem, ChatVisibility};
|
||||
use crate::chatlist::Chatlist;
|
||||
use crate::constants::{DC_CONTACT_ID_INFO, DC_GCL_NO_SPECIALS};
|
||||
@@ -2977,7 +2959,7 @@ mod tests {
|
||||
&headers,
|
||||
"some-other-message-id",
|
||||
std::iter::empty(),
|
||||
ShowEmails::Off
|
||||
ShowEmails::Off,
|
||||
)
|
||||
.await
|
||||
.unwrap());
|
||||
@@ -4298,76 +4280,6 @@ YEAAAAAA!.
|
||||
assert_eq!(msg.text.unwrap(), "Reply");
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_dont_show_spam() {
|
||||
async fn is_shown(t: &TestContext, raw: &[u8], server_folder: &str) -> bool {
|
||||
let mail = mailparse::parse_mail(raw).unwrap();
|
||||
dc_receive_imf(t, raw, server_folder, false).await.unwrap();
|
||||
t.get_last_msg().await.rfc724_mid
|
||||
== mail.get_headers().get_first_value("Message-Id").unwrap()
|
||||
}
|
||||
|
||||
let t = TestContext::new_alice().await;
|
||||
t.set_config(Config::ConfiguredSpamFolder, Some("Spam"))
|
||||
.await
|
||||
.unwrap();
|
||||
t.set_config(Config::ShowEmails, Some("2")).await.unwrap();
|
||||
|
||||
assert!(
|
||||
is_shown(
|
||||
&t,
|
||||
b"Message-Id: abcd1@exmaple.com\n\
|
||||
From: bob@example.org\n\
|
||||
Chat-Version: 1.0\n",
|
||||
"Inbox",
|
||||
)
|
||||
.await,
|
||||
);
|
||||
|
||||
assert!(
|
||||
is_shown(
|
||||
&t,
|
||||
b"Message-Id: abcd2@exmaple.com\n\
|
||||
From: bob@example.org\n",
|
||||
"Inbox",
|
||||
)
|
||||
.await,
|
||||
);
|
||||
|
||||
assert!(
|
||||
is_shown(
|
||||
&t,
|
||||
b"Message-Id: abcd3@exmaple.com\n\
|
||||
From: bob@example.org\n\
|
||||
Chat-Version: 1.0\n",
|
||||
"Spam",
|
||||
)
|
||||
.await,
|
||||
);
|
||||
|
||||
assert!(
|
||||
// Note the `!`:
|
||||
!is_shown(
|
||||
&t,
|
||||
b"Message-Id: abcd4@exmaple.com\n\
|
||||
From: bob@example.org\n",
|
||||
"Spam",
|
||||
)
|
||||
.await,
|
||||
);
|
||||
|
||||
Contact::create(&t, "", "bob@example.org").await.unwrap();
|
||||
assert!(
|
||||
is_shown(
|
||||
&t,
|
||||
b"Message-Id: abcd5@exmaple.com\n\
|
||||
From: bob@example.org\n",
|
||||
"Spam",
|
||||
)
|
||||
.await,
|
||||
);
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_dont_show_all_outgoing_msgs_in_self_chat() {
|
||||
// Regression test for <https://github.com/deltachat/deltachat-android/issues/1940>:
|
||||
|
||||
63
src/imap.rs
63
src/imap.rs
@@ -748,6 +748,11 @@ impl Imap {
|
||||
// message, move it to the movebox and then download the second message before
|
||||
// downloading the first one, if downloading from inbox before moving is allowed.
|
||||
if folder == target
|
||||
// Never download messages directly from the spam folder.
|
||||
// If the sender is known, the message will be moved to the Inbox or Mvbox
|
||||
// and then we download the message from there.
|
||||
// Also see `spam_target_folder()`.
|
||||
&& !context.is_spam_folder(folder).await?
|
||||
&& prefetch_should_download(
|
||||
context,
|
||||
&headers,
|
||||
@@ -1598,16 +1603,28 @@ impl Imap {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns target folder for a message found in the Spam folder.
|
||||
async fn spam_target_folder(
|
||||
async fn should_move_out_of_spam(
|
||||
context: &Context,
|
||||
folder: &str,
|
||||
headers: &[mailparse::MailHeader<'_>],
|
||||
) -> Result<Option<Config>> {
|
||||
if let Some(chat) = prefetch_get_chat(context, headers).await? {
|
||||
if chat.blocked != Blocked::Not {
|
||||
) -> Result<bool> {
|
||||
if headers.get_header_value(HeaderDef::ChatVersion).is_some() {
|
||||
// If this is a chat message (i.e. has a ChatVersion header), then this might be
|
||||
// a securejoin message. We can't find out at this point as we didn't prefetch
|
||||
// the SecureJoin header. So, we always move chat messages out of Spam.
|
||||
// Two possibilities to change this would be:
|
||||
// 1. Remove the `&& !context.is_spam_folder(folder).await?` check from
|
||||
// `fetch_new_messages()`, and then let `dc_receive_imf()` check
|
||||
// if it's a spam message and should be hidden.
|
||||
// 2. Or add a flag to the ChatVersion header that this is a securejoin
|
||||
// request, and return `true` here only if the message has this flag.
|
||||
// `dc_receive_imf()` can then check if the securejoin request is valid.
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
if let Some(msg) = get_prefetch_parent_message(context, headers).await? {
|
||||
if msg.chat_blocked != Blocked::Not {
|
||||
// Blocked or contact request message in the spam folder, leave it there.
|
||||
return Ok(None);
|
||||
return Ok(false);
|
||||
}
|
||||
} else {
|
||||
// No chat found.
|
||||
@@ -1615,22 +1632,38 @@ async fn spam_target_folder(
|
||||
from_field_to_contact_id(context, &mimeparser::get_from(headers), true).await?;
|
||||
if blocked_contact {
|
||||
// Contact is blocked, leave the message in spam.
|
||||
return Ok(None);
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
if let Some(chat_id_blocked) = ChatIdBlocked::lookup_by_contact(context, from_id).await? {
|
||||
if chat_id_blocked.blocked != Blocked::Not {
|
||||
return Ok(None);
|
||||
return Ok(false);
|
||||
}
|
||||
} else if from_id != DC_CONTACT_ID_SELF {
|
||||
// No chat with this contact found.
|
||||
return Ok(None);
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// Returns target folder for a message found in the Spam folder.
|
||||
/// If this returns None, the message will not be moved out of the
|
||||
/// Spam folder, and as `fetch_new_messages()` doesn't download
|
||||
/// messages from the Spam folder, the message will be ignored.
|
||||
async fn spam_target_folder(
|
||||
context: &Context,
|
||||
folder: &str,
|
||||
headers: &[mailparse::MailHeader<'_>],
|
||||
) -> Result<Option<Config>> {
|
||||
if !should_move_out_of_spam(context, headers).await? {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
if needs_move_to_mvbox(context, headers).await?
|
||||
// We don't want to move the message to the inbox or sentbox where we wouldn't
|
||||
// fetch it again:
|
||||
// If OnlyFetchMvbox is set, we don't want to move the message to
|
||||
// the inbox or sentbox where we wouldn't fetch it again:
|
||||
|| context.get_config_bool(Config::OnlyFetchMvbox).await?
|
||||
{
|
||||
Ok(Some(Config::ConfiguredMvboxFolder))
|
||||
@@ -2383,7 +2416,7 @@ mod tests {
|
||||
("Spam", true, true, "DeltaChat"),
|
||||
];
|
||||
|
||||
// These are the same as above, but all messages in Spam stay in Spam
|
||||
// These are the same as above, but non-chat messages in Spam stay in Spam
|
||||
const COMBINATIONS_REQUEST: &[(&str, bool, bool, &str)] = &[
|
||||
("INBOX", false, false, "INBOX"),
|
||||
("INBOX", false, true, "INBOX"),
|
||||
@@ -2394,9 +2427,9 @@ mod tests {
|
||||
("Sent", true, false, "Sent"),
|
||||
("Sent", true, true, "DeltaChat"),
|
||||
("Spam", false, false, "Spam"),
|
||||
("Spam", false, true, "Spam"),
|
||||
("Spam", false, true, "INBOX"),
|
||||
("Spam", true, false, "Spam"),
|
||||
("Spam", true, true, "Spam"),
|
||||
("Spam", true, true, "DeltaChat"),
|
||||
];
|
||||
|
||||
#[async_std::test]
|
||||
|
||||
Reference in New Issue
Block a user