diff --git a/src/chat.rs b/src/chat.rs index b938fd5a9..88611dceb 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -2784,7 +2784,7 @@ pub(crate) async fn delete_and_reset_all_device_msgs(context: &Context) -> Resul pub(crate) async fn add_info_msg(context: &Context, chat_id: ChatId, text: impl AsRef) { let rfc724_mid = dc_create_outgoing_rfc724_mid(None, "@device"); - if context.sql.execute( + if let Err(e) = context.sql.execute( "INSERT INTO msgs (chat_id,from_id,to_id, timestamp,type,state, txt,rfc724_mid) VALUES (?,?,?, ?,?,?, ?,?);", paramsv![ chat_id, @@ -2796,7 +2796,8 @@ pub(crate) async fn add_info_msg(context: &Context, chat_id: ChatId, text: impl text.as_ref().to_string(), rfc724_mid, ] - ).await.is_err() { + ).await { + error!(context, "Could not add info msg: {}", e); return; } diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 89f582293..4c2608974 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -2441,23 +2441,22 @@ mod tests { assert_eq!(msg.state, MessageState::OutFailed); let msgs = chat::get_chat_msgs(&t.ctx, msg.chat_id, 0, None).await; - let mut found = false; - for id in msgs.iter() { - let m = Message::load_from_db(&t.ctx, *id).await.unwrap(); - if m.from_id == DC_CONTACT_ID_INFO - && m.text - == Some( - t.ctx - .stock_string_repl_str( - StockMessage::FailedSendingTo, - "assidhfaaspocwaeofi@gmail.com", - ) - .await, + println!("Loading {}…", msg.chat_id); + let last_msg = Message::load_from_db(&t.ctx, *msgs.last().unwrap()) + .await + .unwrap(); + + assert_eq!(last_msg.from_id, DC_CONTACT_ID_INFO); + assert_eq!( + last_msg.text, + Some( + t.ctx + .stock_string_repl_str( + StockMessage::FailedSendingTo, + "assidhfaaspocwaeofi@gmail.com", ) - { - found = true; - } - } - assert!(found); + .await, + ) + ); } } diff --git a/src/message.rs b/src/message.rs index ad6679b18..2c1a45747 100644 --- a/src/message.rs +++ b/src/message.rs @@ -14,7 +14,7 @@ use crate::error::{ensure, Error}; use crate::events::Event; use crate::job::{self, Action}; use crate::lot::{Lot, LotState, Meaning}; -use crate::mimeparser::SystemMessage; +use crate::mimeparser::{FailedMsg, SystemMessage}; use crate::param::*; use crate::pgp::*; use crate::stock::StockMessage; @@ -1392,13 +1392,12 @@ pub async fn mdn_from_ext( None } -pub async fn ndn_from_ext( +pub(crate) async fn ndn_from_ext( context: &Context, - from_id: u32, - rfc724_mid: &str, + failed: &FailedMsg, error: Option>, ) { - if from_id <= DC_MSG_ID_LAST_SPECIAL || rfc724_mid.is_empty() { + if failed.rfc724_mid.is_empty() { return; } @@ -1410,17 +1409,15 @@ pub async fn ndn_from_ext( " m.id AS msg_id,", " c.id AS chat_id,", " c.type AS type,", - " m.to_id AS to_id", " FROM msgs m LEFT JOIN chats c ON m.chat_id=c.id", " WHERE rfc724_mid=? AND from_id=1", ), - paramsv![rfc724_mid], + paramsv![failed.rfc724_mid], |row| { Ok(( row.get::<_, MsgId>("msg_id")?, row.get::<_, ChatId>("chat_id")?, row.get::<_, Chattype>("type")?, - row.get::<_, u32>("to_id")?, )) }, ) @@ -1429,25 +1426,29 @@ pub async fn ndn_from_ext( info!(context, "Failed to select NDN {:?}", err); } - if let Ok((msg_id, chat_id, chat_type, contact_id)) = res { + if let Ok((msg_id, chat_id, chat_type)) = res { set_msg_failed(context, msg_id, error).await; - info!(context, "cht {} {} {}", chat_id, chat_type, contact_id); if chat_type == Chattype::Group || chat_type == Chattype::VerifiedGroup { - info!(context, "Adding info msg to chat {}", chat_id); - let contact = Contact::load_from_db(context, contact_id).await.unwrap(); - chat::add_info_msg( - context, - chat_id, - context - .stock_string_repl_str( - StockMessage::FailedSendingTo, - contact.get_display_name(), + if let Some(failed_recipient) = &failed.failed_recipient { + let contact_id = + Contact::lookup_id_by_addr(context, failed_recipient, Origin::Unknown).await; + if let Ok(contact) = Contact::load_from_db(context, contact_id).await { + // Tell the user which of the recipients failed if we know that (because in a group, this might otherwise be unclear) + chat::add_info_msg( + context, + chat_id, + context + .stock_string_repl_str( + StockMessage::FailedSendingTo, + contact.get_display_name(), + ) + .await, ) - .await, - ) - .await; - context.emit_event(Event::ChatModified(chat_id)); + .await; + context.emit_event(Event::ChatModified(chat_id)); + } + } } } } diff --git a/src/mimeparser.rs b/src/mimeparser.rs index ecfdfaea9..0ffea486c 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -54,7 +54,7 @@ pub struct MimeMessage { pub(crate) user_avatar: Option, pub(crate) group_avatar: Option, pub(crate) reports: Vec, - pub(crate) failed_msg: Option, + pub(crate) failed_msg: Option, } #[derive(Debug, PartialEq)] @@ -881,7 +881,7 @@ impl MimeMessage { .iter() .find(|p| p.typ == Viewtype::Text) .map(|p| &p.msg); - message::ndn_from_ext(context, from_id, original_message_id, error).await + message::ndn_from_ext(context, original_message_id, error).await } } @@ -889,7 +889,7 @@ impl MimeMessage { &self, context: &Context, report: &mailparse::ParsedMail<'_>, - ) -> Result> { + ) -> Result> { // parse as mailheaders if let Some(original_msg) = report .subparts @@ -903,7 +903,17 @@ impl MimeMessage { .get_header_value(HeaderDef::MessageId) .and_then(|v| parse_message_id(&v).ok()) { - return Ok(Some(original_message_id)); + let mut to_list = get_recipients(&report_fields); + let to = if to_list.len() == 1 { + Some(to_list.pop().unwrap()) + } else { + None // We do not know which recipient failed + }; + + return Ok(Some(FailedMsg { + rfc724_mid: original_message_id, + failed_recipient: to.map(|s| s.addr), + })); } warn!( @@ -970,6 +980,12 @@ pub(crate) struct Report { additional_message_ids: Vec, } +#[derive(Debug)] +pub(crate) struct FailedMsg { + pub rfc724_mid: String, + pub failed_recipient: Option, +} + pub(crate) fn parse_message_ids(ids: &str) -> Result> { // take care with mailparse::msgidparse() that is pretty untolerant eg. wrt missing `<` or `>` let mut msgids = Vec::new();