diff --git a/python/tests/test_1_online.py b/python/tests/test_1_online.py index c8526e68d..a1d8ac2ad 100644 --- a/python/tests/test_1_online.py +++ b/python/tests/test_1_online.py @@ -846,6 +846,7 @@ def test_dont_show_emails(acfactory, lp): ac1.direct_imap.create_folder("Sent") ac1.direct_imap.create_folder("Spam") ac1.direct_imap.create_folder("Junk") + ac1.set_config("sentbox_watch", "1") acfactory.bring_accounts_online() ac1.stop_io() @@ -955,7 +956,10 @@ def test_dont_show_emails(acfactory, lp): msg = ac1._evtracker.wait_next_messages_changed() - # Wait until each folder was scanned, this is necessary for this test to test what it should test: + # Wait until each folder was scanned, this is necessary for this test to test what it should + # test. Need to wait two times because of "sentbox_watch" set (the same event is emitted for + # Sentbox currently). + ac1._evtracker.wait_idle_inbox_ready() ac1._evtracker.wait_idle_inbox_ready() assert msg.text == "subj – message in Sent" diff --git a/src/events/payload.rs b/src/events/payload.rs index fb0d972a3..06f429d1a 100644 --- a/src/events/payload.rs +++ b/src/events/payload.rs @@ -35,7 +35,7 @@ pub enum EventType { /// Emitted when an IMAP message has been moved ImapMessageMoved(String), - /// Emitted before going into IDLE on the Inbox folder. + /// Emitted before going into IDLE on any folder. ImapInboxIdle, /// Emitted when an new file in the $BLOBDIR was created diff --git a/src/imap.rs b/src/imap.rs index ea6d90736..cd1333ddc 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -665,18 +665,15 @@ 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_cfg()`. - && folder_meaning != FolderMeaning::Spam && prefetch_should_download( context, + folder_meaning, &headers, &message_id, fetch_response.flags(), ) - .await.context("prefetch_should_download")? + .await + .context("prefetch_should_download")? { match download_limit { Some(download_limit) => uids_fetch.push(( @@ -2244,10 +2241,34 @@ async fn prefetch_get_chat( /// Determines whether the message should be downloaded based on prefetched headers. pub(crate) async fn prefetch_should_download( context: &Context, + folder_meaning: FolderMeaning, headers: &[mailparse::MailHeader<'_>], message_id: &str, mut flags: impl Iterator>, ) -> Result { + // 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_cfg()`. + if folder_meaning == FolderMeaning::Spam { + return Ok(false); + } + + // Download outgoing messages only from Inbox and Mvbox (and Sent -- until + // `Config::SentboxWatch` is dropped) to ensure they are sorted correctly with incoming + // messages. This way we actually do server-side sorting. Otherwise it's possible that outgoing + // replies from other devices appear before incoming messages. Users should CC/BCC/To themselves + // to see sent messages in Delta Chat. + if matches!( + folder_meaning, + FolderMeaning::Inbox | FolderMeaning::Mvbox | FolderMeaning::Sent + ) { + } else if let Some(from) = mimeparser::get_from(headers) { + if context.is_self_addr(&from.addr).await? { + return Ok(false); + } + } + if message::rfc724_mid_exists(context, message_id) .await? .is_some() diff --git a/src/imap/scan_folders.rs b/src/imap/scan_folders.rs index 860c27568..11fbfcffd 100644 --- a/src/imap/scan_folders.rs +++ b/src/imap/scan_folders.rs @@ -71,10 +71,14 @@ impl Imap { _ => folder_meaning, }; + // Scan folders for incoming messages. As for outgoing ones, users should CC/BCC/To + // themselves so that Delta Chat sees such messages in Inbox. + // // Don't scan folders that are watched anyway if !watched_folders.contains(&folder.name().to_string()) && folder_meaning != FolderMeaning::Drafts && folder_meaning != FolderMeaning::Trash + && folder_meaning != FolderMeaning::Sent { self.fetch_move_delete(context, session, folder.name(), folder_meaning) .await diff --git a/src/receive_imf/receive_imf_tests.rs b/src/receive_imf/receive_imf_tests.rs index 618a807e7..dd0b7881f 100644 --- a/src/receive_imf/receive_imf_tests.rs +++ b/src/receive_imf/receive_imf_tests.rs @@ -12,7 +12,7 @@ use crate::chatlist::Chatlist; use crate::constants::DC_GCL_FOR_FORWARDING; use crate::contact; use crate::download::MIN_DOWNLOAD_LIMIT; -use crate::imap::prefetch_should_download; +use crate::imap::{FolderMeaning, prefetch_should_download}; use crate::imex::{ImexMode, imex}; use crate::securejoin::get_securejoin_qr; use crate::test_utils::{ @@ -672,9 +672,15 @@ async fn test_parse_ndn( // Check that the ndn would be downloaded: let headers = mailparse::parse_mail(raw_ndn).unwrap().headers; assert!( - prefetch_should_download(&t, &headers, "some-other-message-id", std::iter::empty(),) - .await - .unwrap() + prefetch_should_download( + &t, + FolderMeaning::Inbox, + &headers, + "some-other-message-id", + std::iter::empty(), + ) + .await + .unwrap() ); receive_imf(&t, raw_ndn, false).await.unwrap(); diff --git a/src/scheduler.rs b/src/scheduler.rs index 621a799eb..cbfa9c6cb 100644 --- a/src/scheduler.rs +++ b/src/scheduler.rs @@ -661,6 +661,7 @@ async fn fetch_idle( connection.connectivity.set_idle(ctx); + // Maybe we'll remove watching other folders soon, so use this event for all folders for now. ctx.emit_event(EventType::ImapInboxIdle); if !session.can_idle() {