mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 09:26:29 +03:00
fix: add device message instead of partial message when receive_imf fails
This commit is contained in:
@@ -338,44 +338,27 @@ def test_receive_imf_failure(acfactory) -> None:
|
|||||||
|
|
||||||
bob.set_config("fail_on_receiving_full_msg", "1")
|
bob.set_config("fail_on_receiving_full_msg", "1")
|
||||||
alice_chat_bob.send_text("Hello!")
|
alice_chat_bob.send_text("Hello!")
|
||||||
event = bob.wait_for_incoming_msg_event()
|
event = bob.wait_for_event(EventType.MSGS_CHANGED)
|
||||||
chat_id = event.chat_id
|
assert event.chat_id == bob.get_device_chat().id
|
||||||
msg_id = event.msg_id
|
msg_id = event.msg_id
|
||||||
message = bob.get_message_by_id(msg_id)
|
message = bob.get_message_by_id(msg_id)
|
||||||
snapshot = message.get_snapshot()
|
snapshot = message.get_snapshot()
|
||||||
assert snapshot.chat_id == chat_id
|
assert (
|
||||||
assert snapshot.download_state == DownloadState.AVAILABLE
|
snapshot.text == "❌ Failed to receive a message:"
|
||||||
assert snapshot.error is not None
|
" Condition failed: `!context.get_config_bool(Config::FailOnReceivingFullMsg).await?`."
|
||||||
assert snapshot.show_padlock
|
" Please report this bug to delta@merlinux.eu or https://support.delta.chat/."
|
||||||
snapshot.chat.accept()
|
)
|
||||||
|
|
||||||
# The failed message doesn't break the IMAP loop.
|
# The failed message doesn't break the IMAP loop.
|
||||||
bob.set_config("fail_on_receiving_full_msg", "0")
|
bob.set_config("fail_on_receiving_full_msg", "0")
|
||||||
alice_chat_bob.send_text("Hello again!")
|
alice_chat_bob.send_text("Hello again!")
|
||||||
event = bob.wait_for_incoming_msg_event()
|
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
|
msg_id = event.msg_id
|
||||||
message = bob.get_message_by_id(msg_id)
|
message = bob.get_message_by_id(msg_id)
|
||||||
snapshot = message.get_snapshot()
|
snapshot = message.get_snapshot()
|
||||||
assert snapshot.chat_id == chat_id
|
assert snapshot.text == "Hello again!"
|
||||||
assert snapshot.download_state == DownloadState.DONE
|
assert snapshot.download_state == DownloadState.DONE
|
||||||
assert snapshot.error is None
|
assert snapshot.error is None
|
||||||
assert snapshot.text == "Hello!"
|
|
||||||
|
|
||||||
|
|
||||||
def test_selfavatar_sync(acfactory, data, log) -> None:
|
def test_selfavatar_sync(acfactory, data, log) -> None:
|
||||||
|
|||||||
@@ -221,21 +221,14 @@ impl MimeMessage {
|
|||||||
/// To create the placeholder, only the outermost header can be used,
|
/// To create the placeholder, only the outermost header can be used,
|
||||||
/// the mime-structure itself is not available.
|
/// the mime-structure itself is not available.
|
||||||
///
|
///
|
||||||
/// The placeholder part currently contains a text with size and availability of the message;
|
/// 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.
|
|
||||||
pub(crate) async fn create_stub_from_partial_download(
|
pub(crate) async fn create_stub_from_partial_download(
|
||||||
&mut self,
|
&mut self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
org_bytes: u32,
|
org_bytes: u32,
|
||||||
error: Option<String>,
|
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let prefix = match error {
|
|
||||||
None => "",
|
|
||||||
Some(_) => "[❗] ",
|
|
||||||
};
|
|
||||||
let mut text = format!(
|
let mut text = format!(
|
||||||
"{prefix}[{}]",
|
"[{}]",
|
||||||
stock_str::partial_download_msg_body(context, org_bytes).await
|
stock_str::partial_download_msg_body(context, org_bytes).await
|
||||||
);
|
);
|
||||||
if let Some(delete_server_after) = context.get_config_delete_server_after().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 {
|
self.do_add_single_part(Part {
|
||||||
typ: Viewtype::Text,
|
typ: Viewtype::Text,
|
||||||
msg: text,
|
msg: text,
|
||||||
error,
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
36
src/imap.rs
36
src/imap.rs
@@ -24,7 +24,7 @@ use ratelimit::Ratelimit;
|
|||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::calls::{create_fallback_ice_servers, create_ice_servers_from_metadata};
|
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::chatlist_events;
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::constants::{self, Blocked, Chattype, ShowEmails};
|
use crate::constants::{self, Blocked, Chattype, ShowEmails};
|
||||||
@@ -1468,29 +1468,19 @@ impl Session {
|
|||||||
context,
|
context,
|
||||||
"Passing message UID {} to receive_imf().", request_uid
|
"Passing message UID {} to receive_imf().", request_uid
|
||||||
);
|
);
|
||||||
let res = receive_imf_inner(
|
let res = receive_imf_inner(context, rfc724_mid, body, is_seen, partial).await;
|
||||||
context,
|
let received_msg = match res {
|
||||||
rfc724_mid,
|
Err(err) => {
|
||||||
body,
|
warn!(context, "receive_imf error: {err:#}.");
|
||||||
is_seen,
|
|
||||||
partial.map(|msg_size| (msg_size, None)),
|
let text = format!(
|
||||||
)
|
"❌ Failed to receive a message: {err:#}. Please report this bug to delta@merlinux.eu or https://support.delta.chat/."
|
||||||
.await;
|
);
|
||||||
let received_msg = if let Err(err) = res {
|
let mut msg = Message::new_text(text);
|
||||||
warn!(context, "receive_imf error: {:#}.", err);
|
add_device_msg(context, None, Some(&mut msg)).await?;
|
||||||
if partial.is_some() {
|
None
|
||||||
return Err(err);
|
|
||||||
}
|
}
|
||||||
receive_imf_inner(
|
Ok(msg) => msg,
|
||||||
context,
|
|
||||||
rfc724_mid,
|
|
||||||
body,
|
|
||||||
is_seen,
|
|
||||||
Some((body.len().try_into()?, Some(format!("{err:#}")))),
|
|
||||||
)
|
|
||||||
.await?
|
|
||||||
} else {
|
|
||||||
res?
|
|
||||||
};
|
};
|
||||||
received_msgs_channel
|
received_msgs_channel
|
||||||
.send((request_uid, received_msg))
|
.send((request_uid, received_msg))
|
||||||
|
|||||||
@@ -240,12 +240,11 @@ const MIME_AC_SETUP_FILE: &str = "application/autocrypt-setup";
|
|||||||
impl MimeMessage {
|
impl MimeMessage {
|
||||||
/// Parse a mime message.
|
/// Parse a mime message.
|
||||||
///
|
///
|
||||||
/// If `partial` is set, it contains the full message size in bytes and an optional error text
|
/// If `partial` is set, it contains the full message size in bytes.
|
||||||
/// for the partially downloaded message, and `body` contains the HEADER only.
|
|
||||||
pub(crate) async fn from_bytes(
|
pub(crate) async fn from_bytes(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
body: &[u8],
|
body: &[u8],
|
||||||
partial: Option<(u32, Option<String>)>,
|
partial: Option<u32>,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let mail = mailparse::parse_mail(body)?;
|
let mail = mailparse::parse_mail(body)?;
|
||||||
|
|
||||||
@@ -619,9 +618,9 @@ impl MimeMessage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match partial {
|
match partial {
|
||||||
Some((org_bytes, err)) => {
|
Some(org_bytes) => {
|
||||||
parser
|
parser
|
||||||
.create_stub_from_partial_download(context, org_bytes, err)
|
.create_stub_from_partial_download(context, org_bytes)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
None => match mail {
|
None => match mail {
|
||||||
|
|||||||
@@ -186,14 +186,7 @@ pub(crate) async fn receive_imf_from_inbox(
|
|||||||
seen: bool,
|
seen: bool,
|
||||||
is_partial_download: Option<u32>,
|
is_partial_download: Option<u32>,
|
||||||
) -> Result<Option<ReceivedMsg>> {
|
) -> Result<Option<ReceivedMsg>> {
|
||||||
receive_imf_inner(
|
receive_imf_inner(context, rfc724_mid, imf_raw, seen, is_partial_download).await
|
||||||
context,
|
|
||||||
rfc724_mid,
|
|
||||||
imf_raw,
|
|
||||||
seen,
|
|
||||||
is_partial_download.map(|msg_size| (msg_size, None)),
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts a tombstone into `msgs` table
|
/// 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,
|
/// If the message is so wrong that we didn't even create a database entry,
|
||||||
/// returns `Ok(None)`.
|
/// returns `Ok(None)`.
|
||||||
///
|
///
|
||||||
/// If `partial` is set, it contains the full message size in bytes and an optional error text for
|
/// If `is_partial_download` is set, it contains the full message size in bytes.
|
||||||
/// the partially downloaded message.
|
|
||||||
pub(crate) async fn receive_imf_inner(
|
pub(crate) async fn receive_imf_inner(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
rfc724_mid: &str,
|
rfc724_mid: &str,
|
||||||
imf_raw: &[u8],
|
imf_raw: &[u8],
|
||||||
seen: bool,
|
seen: bool,
|
||||||
partial: Option<(u32, Option<String>)>,
|
is_partial_download: Option<u32>,
|
||||||
) -> Result<Option<ReceivedMsg>> {
|
) -> Result<Option<ReceivedMsg>> {
|
||||||
if std::env::var(crate::DCC_MIME_DEBUG).is_ok() {
|
if std::env::var(crate::DCC_MIME_DEBUG).is_ok() {
|
||||||
info!(
|
info!(
|
||||||
@@ -506,7 +498,7 @@ pub(crate) async fn receive_imf_inner(
|
|||||||
String::from_utf8_lossy(imf_raw),
|
String::from_utf8_lossy(imf_raw),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if partial.is_none() {
|
if is_partial_download.is_none() {
|
||||||
ensure!(
|
ensure!(
|
||||||
!context
|
!context
|
||||||
.get_config_bool(Config::FailOnReceivingFullMsg)
|
.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, is_partial_download).await
|
||||||
let mut mime_parser = match MimeMessage::from_bytes(context, imf_raw, partial).await {
|
{
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(context, "receive_imf: can't parse MIME: {err:#}.");
|
warn!(context, "receive_imf: can't parse MIME: {err:#}.");
|
||||||
if rfc724_mid.starts_with(GENERATED_PREFIX) {
|
if rfc724_mid.starts_with(GENERATED_PREFIX) {
|
||||||
|
|||||||
Reference in New Issue
Block a user