From c725e660f08b8192bbb9b0c8457335c4403a81db Mon Sep 17 00:00:00 2001 From: link2xt Date: Tue, 4 Nov 2025 23:32:45 +0000 Subject: [PATCH] fix: add device message instead of partial message when receive_imf fails --- deltachat-rpc-client/tests/test_something.py | 33 +++++------------- src/download.rs | 12 ++----- src/imap.rs | 36 +++++++------------- src/mimeparser.rs | 9 +++-- src/receive_imf.rs | 20 ++++------- 5 files changed, 33 insertions(+), 77 deletions(-) diff --git a/deltachat-rpc-client/tests/test_something.py b/deltachat-rpc-client/tests/test_something.py index 5bbc32c21b..03626260c8 100644 --- a/deltachat-rpc-client/tests/test_something.py +++ b/deltachat-rpc-client/tests/test_something.py @@ -338,44 +338,27 @@ def test_receive_imf_failure(acfactory) -> None: bob.set_config("fail_on_receiving_full_msg", "1") alice_chat_bob.send_text("Hello!") - event = bob.wait_for_incoming_msg_event() - chat_id = event.chat_id + event = bob.wait_for_event(EventType.MSGS_CHANGED) + assert event.chat_id == bob.get_device_chat().id msg_id = event.msg_id message = bob.get_message_by_id(msg_id) snapshot = message.get_snapshot() - assert snapshot.chat_id == chat_id - assert snapshot.download_state == DownloadState.AVAILABLE - assert snapshot.error is not None - assert snapshot.show_padlock - snapshot.chat.accept() + assert ( + snapshot.text == "❌ Failed to receive a message:" + " Condition failed: `!context.get_config_bool(Config::FailOnReceivingFullMsg).await?`." + " Please report this bug to delta@merlinux.eu or https://support.delta.chat/." + ) # The failed message doesn't break the IMAP loop. bob.set_config("fail_on_receiving_full_msg", "0") alice_chat_bob.send_text("Hello again!") event = bob.wait_for_incoming_msg_event() - assert event.chat_id == chat_id - msg_id = event.msg_id - message1 = bob.get_message_by_id(msg_id) - snapshot = message1.get_snapshot() - assert snapshot.chat_id == chat_id - assert snapshot.download_state == DownloadState.DONE - assert snapshot.error is None - - # The failed message can be re-downloaded later. - bob._rpc.download_full_message(bob.id, message.id) - event = bob.wait_for_event(EventType.MSGS_CHANGED) - message = bob.get_message_by_id(event.msg_id) - snapshot = message.get_snapshot() - assert snapshot.download_state == DownloadState.IN_PROGRESS - event = bob.wait_for_event(EventType.MSGS_CHANGED) - assert event.chat_id == chat_id msg_id = event.msg_id message = bob.get_message_by_id(msg_id) snapshot = message.get_snapshot() - assert snapshot.chat_id == chat_id + assert snapshot.text == "Hello again!" assert snapshot.download_state == DownloadState.DONE assert snapshot.error is None - assert snapshot.text == "Hello!" def test_selfavatar_sync(acfactory, data, log) -> None: diff --git a/src/download.rs b/src/download.rs index 44e8520218..ec279c4a71 100644 --- a/src/download.rs +++ b/src/download.rs @@ -221,21 +221,14 @@ impl MimeMessage { /// To create the placeholder, only the outermost header can be used, /// the mime-structure itself is not available. /// - /// The placeholder part currently contains a text with size and availability of the message; - /// `error` is set as the part error; - /// in the future, we may do more advanced things as previews here. + /// The placeholder part currently contains a text with size and availability of the message. pub(crate) async fn create_stub_from_partial_download( &mut self, context: &Context, org_bytes: u32, - error: Option, ) -> Result<()> { - let prefix = match error { - None => "", - Some(_) => "[❗] ", - }; let mut text = format!( - "{prefix}[{}]", + "[{}]", stock_str::partial_download_msg_body(context, org_bytes).await ); if let Some(delete_server_after) = context.get_config_delete_server_after().await? { @@ -252,7 +245,6 @@ impl MimeMessage { self.do_add_single_part(Part { typ: Viewtype::Text, msg: text, - error, ..Default::default() }); diff --git a/src/imap.rs b/src/imap.rs index 1555ac0af9..7826558afb 100644 --- a/src/imap.rs +++ b/src/imap.rs @@ -24,7 +24,7 @@ use ratelimit::Ratelimit; use url::Url; use crate::calls::{create_fallback_ice_servers, create_ice_servers_from_metadata}; -use crate::chat::{self, ChatId, ChatIdBlocked}; +use crate::chat::{self, ChatId, ChatIdBlocked, add_device_msg}; use crate::chatlist_events; use crate::config::Config; use crate::constants::{self, Blocked, Chattype, ShowEmails}; @@ -1468,29 +1468,19 @@ impl Session { context, "Passing message UID {} to receive_imf().", request_uid ); - let res = receive_imf_inner( - context, - rfc724_mid, - body, - is_seen, - partial.map(|msg_size| (msg_size, None)), - ) - .await; - let received_msg = if let Err(err) = res { - warn!(context, "receive_imf error: {:#}.", err); - if partial.is_some() { - return Err(err); + let res = receive_imf_inner(context, rfc724_mid, body, is_seen, partial).await; + let received_msg = match res { + Err(err) => { + warn!(context, "receive_imf error: {err:#}."); + + let text = format!( + "❌ Failed to receive a message: {err:#}. Please report this bug to delta@merlinux.eu or https://support.delta.chat/." + ); + let mut msg = Message::new_text(text); + add_device_msg(context, None, Some(&mut msg)).await?; + None } - receive_imf_inner( - context, - rfc724_mid, - body, - is_seen, - Some((body.len().try_into()?, Some(format!("{err:#}")))), - ) - .await? - } else { - res? + Ok(msg) => msg, }; received_msgs_channel .send((request_uid, received_msg)) diff --git a/src/mimeparser.rs b/src/mimeparser.rs index 2e66b1e344..eeb884ecbc 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -240,12 +240,11 @@ const MIME_AC_SETUP_FILE: &str = "application/autocrypt-setup"; impl MimeMessage { /// Parse a mime message. /// - /// If `partial` is set, it contains the full message size in bytes and an optional error text - /// for the partially downloaded message, and `body` contains the HEADER only. + /// If `partial` is set, it contains the full message size in bytes. pub(crate) async fn from_bytes( context: &Context, body: &[u8], - partial: Option<(u32, Option)>, + partial: Option, ) -> Result { let mail = mailparse::parse_mail(body)?; @@ -619,9 +618,9 @@ impl MimeMessage { }; match partial { - Some((org_bytes, err)) => { + Some(org_bytes) => { parser - .create_stub_from_partial_download(context, org_bytes, err) + .create_stub_from_partial_download(context, org_bytes) .await?; } None => match mail { diff --git a/src/receive_imf.rs b/src/receive_imf.rs index 549f2bc8c3..c0f8dfc102 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -186,14 +186,7 @@ pub(crate) async fn receive_imf_from_inbox( seen: bool, is_partial_download: Option, ) -> Result> { - receive_imf_inner( - context, - rfc724_mid, - imf_raw, - seen, - is_partial_download.map(|msg_size| (msg_size, None)), - ) - .await + receive_imf_inner(context, rfc724_mid, imf_raw, seen, is_partial_download).await } /// Inserts a tombstone into `msgs` table @@ -490,14 +483,13 @@ async fn get_to_and_past_contact_ids( /// If the message is so wrong that we didn't even create a database entry, /// returns `Ok(None)`. /// -/// If `partial` is set, it contains the full message size in bytes and an optional error text for -/// the partially downloaded message. +/// If `is_partial_download` is set, it contains the full message size in bytes. pub(crate) async fn receive_imf_inner( context: &Context, rfc724_mid: &str, imf_raw: &[u8], seen: bool, - partial: Option<(u32, Option)>, + is_partial_download: Option, ) -> Result> { if std::env::var(crate::DCC_MIME_DEBUG).is_ok() { info!( @@ -506,7 +498,7 @@ pub(crate) async fn receive_imf_inner( String::from_utf8_lossy(imf_raw), ); } - if partial.is_none() { + if is_partial_download.is_none() { ensure!( !context .get_config_bool(Config::FailOnReceivingFullMsg) @@ -514,8 +506,8 @@ pub(crate) async fn receive_imf_inner( ); } - let is_partial_download = partial.as_ref().map(|(msg_size, _err)| *msg_size); - let mut mime_parser = match MimeMessage::from_bytes(context, imf_raw, partial).await { + let mut mime_parser = match MimeMessage::from_bytes(context, imf_raw, is_partial_download).await + { Err(err) => { warn!(context, "receive_imf: can't parse MIME: {err:#}."); if rfc724_mid.starts_with(GENERATED_PREFIX) {