diff --git a/src/imap.rs b/src/imap.rs index 896ee1c85..ca0d525e4 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -1282,6 +1282,7 @@ impl Session { return Ok(()); } let is_chatmail = self.is_chatmail(); + let transport_id = self.transport_id(); for (request_uids, set) in build_sequence_sets(&request_uids)? { info!(context, "Starting UID FETCH of message set \"{}\".", set); @@ -1381,17 +1382,7 @@ impl Session { ); let res = receive_imf_inner(context, rfc724_mid, body, is_seen).await; - // If the message is not needed anymore on the server, mark it for deletion: - if !context.get_config_bool(Config::BccSelf).await? && is_chatmail { - context - .sql - .execute( - "UPDATE imap SET target='' WHERE rfc724_mid=?", - (rfc724_mid,), - ) - .await?; - context.scheduler.interrupt_inbox().await; - } + maybe_mark_for_deletion(is_chatmail, transport_id, rfc724_mid, context).await?; // If there was an error receiving the message, show a device message: let received_msg = match res { @@ -1664,6 +1655,26 @@ impl Session { } } +async fn maybe_mark_for_deletion( + is_chatmail: bool, + transport_id: u32, + rfc724_mid: &String, + context: &Context, +) -> Result<()> { + if !context.get_config_bool(Config::BccSelf).await? && is_chatmail { + context + .sql + .execute( + "UPDATE imap SET target='' WHERE rfc724_mid=? AND transport_id=?", + (rfc724_mid, transport_id), + ) + .await?; + context.scheduler.interrupt_inbox().await; + } + + Ok(()) +} + fn format_setmetadata(folder: &str, device_token: &str) -> String { let device_token_len = device_token.len(); format!( @@ -1972,6 +1983,15 @@ pub(crate) fn create_message_id() -> String { } /// Determines whether the message should be downloaded based on prefetched headers. +// We want to call maybe_delete() iff it's not a post-message OR the post-message was already downloaded. +// I.e. if it's a post-message that is Available, Failure, or InProgress, then we do not want to delete it. +// WRT InProgress, we do want to delete it later on _all_ relays later, after we downloaded it. +// So, maybe when choosing what to delete, we should not filter by transport. +// I'm not sure about checking is_chatmail - maybe it's fine to just remove a message from all transports +// if it also arrived via a chatmail transport, +// because generally the only reason why this happens is because the chatpartner has DC with multi-relay. +// +// I.e., we want to delete everything for which prefetch_should_download() returns false, EXCEPT for the case where a post-message's download failed or is in progress. pub(crate) async fn prefetch_should_download( context: &Context, headers: &[mailparse::MailHeader<'_>], diff --git a/src/message.rs b/src/message.rs index b2be0169d..90ec049b7 100644 --- a/src/message.rs +++ b/src/message.rs @@ -2220,6 +2220,36 @@ pub(crate) async fn rfc724_mid_download_tried(context: &Context, rfc724_mid: &st Ok(res) } +/// Returns `true` iff there is a message +/// with the given `rfc724_mid` +/// and a download state other than `DownloadState::Available`, +/// i.e. it was already tried to download the message or it's sent locally. +pub(crate) async fn rfc724_mid_was_downloaded(context: &Context, rfc724_mid: &str) -> Result { + let rfc724_mid = rfc724_mid.trim_start_matches('<').trim_end_matches('>'); + if rfc724_mid.is_empty() { + warn!( + context, + "Empty rfc724_mid passed to rfc724_mid_download_tried" + ); + return Ok(false); + } + + let res = context + .sql + .exists( + "SELECT COUNT(*) FROM msgs + WHERE rfc724_mid=? AND download_state=? OR download_state=?", + ( + rfc724_mid, + DownloadState::Done, + DownloadState::Undecipherable, + ), + ) + .await?; + + Ok(res) +} + /// Given a list of Message-IDs, returns the most relevant message found in the database. /// /// Relevance here is `(download_state == Done, index)`, where `index` is an index of Message-ID in