fix: MsgBunch not firing after Msg sometimes

Closes https://github.com/chatmail/core/issues/8232.

`receive_imf_inner`, and thus its only caller `fetch_many_msgs`,
seems to be the main function,
apart from `add_device_msg_with_importance` and `handle_call_msg`,
that fires `IncomingMsg` events.
However, `fetch_many_msgs` gets called in two places,
only one of which fires `IncomingMsgBunch`.

Let's fix that by moving `IncomingMsgBunch`
to inside of `fetch_many_msgs`.
This commit is contained in:
WofWca
2026-05-20 12:49:39 +04:00
parent a017663be5
commit c3b4104f0b
2 changed files with 37 additions and 10 deletions

View File

@@ -779,10 +779,6 @@ impl Imap {
info!(context, "{} mails read from \"{}\".", read_cnt, folder); info!(context, "{} mails read from \"{}\".", read_cnt, folder);
if !received_msgs.is_empty() {
context.emit_event(EventType::IncomingMsgBunch);
}
chat::mark_old_messages_as_noticed(context, received_msgs).await?; chat::mark_old_messages_as_noticed(context, received_msgs).await?;
if fetch_res.is_ok() { if fetch_res.is_ok() {
@@ -1269,7 +1265,6 @@ impl Session {
/// ///
/// If the message is incorrect or there is a failure to write a message to the database, /// If the message is incorrect or there is a failure to write a message to the database,
/// it is skipped and the error is logged. /// it is skipped and the error is logged.
#[expect(clippy::arithmetic_side_effects)]
pub(crate) async fn fetch_many_msgs( pub(crate) async fn fetch_many_msgs(
&mut self, &mut self,
context: &Context, context: &Context,
@@ -1277,6 +1272,36 @@ impl Session {
request_uids: Vec<u32>, request_uids: Vec<u32>,
uid_message_ids: &BTreeMap<u32, String>, uid_message_ids: &BTreeMap<u32, String>,
received_msgs_channel: Sender<(u32, Option<ReceivedMsg>)>, received_msgs_channel: Sender<(u32, Option<ReceivedMsg>)>,
) -> Result<()> {
let mut received_at_least_one = false;
let res = self
._fetch_many_msgs(
context,
folder,
request_uids,
uid_message_ids,
async |uid, msg| {
if msg.is_some() {
received_at_least_one = true;
}
received_msgs_channel.send((uid, msg)).await?;
Ok(())
},
)
.await;
if received_at_least_one {
context.emit_event(EventType::IncomingMsgBunch);
}
return res;
}
#[expect(clippy::arithmetic_side_effects)]
async fn _fetch_many_msgs(
&mut self,
context: &Context,
folder: &str,
request_uids: Vec<u32>,
uid_message_ids: &BTreeMap<u32, String>,
mut on_msg_received: impl AsyncFnMut(u32, Option<ReceivedMsg>) -> Result<()>,
) -> Result<()> { ) -> Result<()> {
if request_uids.is_empty() { if request_uids.is_empty() {
return Ok(()); return Ok(());
@@ -1348,7 +1373,7 @@ impl Session {
if is_deleted { if is_deleted {
info!(context, "Not processing deleted msg {}.", request_uid); info!(context, "Not processing deleted msg {}.", request_uid);
received_msgs_channel.send((request_uid, None)).await?; on_msg_received(request_uid, None).await?;
continue; continue;
} }
@@ -1359,7 +1384,7 @@ impl Session {
context, context,
"Not processing message {} without a BODY.", request_uid "Not processing message {} without a BODY.", request_uid
); );
received_msgs_channel.send((request_uid, None)).await?; on_msg_received(request_uid, None).await?;
continue; continue;
}; };
@@ -1392,9 +1417,7 @@ impl Session {
} }
Ok(msg) => msg, Ok(msg) => msg,
}; };
received_msgs_channel on_msg_received(request_uid, received_msg).await?;
.send((request_uid, received_msg))
.await?;
} }
// If we don't process the whole response, IMAP client is left in a broken state where // If we don't process the whole response, IMAP client is left in a broken state where

View File

@@ -462,6 +462,10 @@ async fn get_to_and_past_contact_ids(
/// downloaded again, sets `chat_id=DC_CHAT_ID_TRASH` and returns `Ok(Some(…))`. /// downloaded again, sets `chat_id=DC_CHAT_ID_TRASH` and returns `Ok(Some(…))`.
/// 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)`.
///
/// The caller must emit [`EventType::IncomingMsgBunch`]
/// if this function returned `Ok(Some)`, because that usually (but not always)
/// means that this function emitted [`EventType::IncomingMsg`].
pub(crate) async fn receive_imf_inner( pub(crate) async fn receive_imf_inner(
context: &Context, context: &Context,
rfc724_mid: &str, rfc724_mid: &str,