diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 85a74704b..416d858bf 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -4165,7 +4165,8 @@ void dc_msg_latefiling_mediasize (dc_msg_t* msg, int width, int hei * * @memberof dc_msg_t * @param msg The message object to set the reply to. - * @param quote The quote to set for msg. + * @param quote The quote to set for the message object given as `msg`. + * NULL removes an previously set quote. */ void dc_msg_set_quote (dc_msg_t* msg, const dc_msg_t* quote); diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index aa629bbbf..1d674514a 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -3372,17 +3372,21 @@ pub unsafe extern "C" fn dc_msg_set_quote(msg: *mut dc_msg_t, quote: *const dc_m return; } let ffi_msg = &mut *msg; - let ffi_quote = &*quote; - - if ffi_msg.context != ffi_quote.context { - eprintln!("ignoring attempt to quote message from a different context"); - return; - } + let quote_msg = if quote.is_null() { + None + } else { + let ffi_quote = &*quote; + if ffi_msg.context != ffi_quote.context { + eprintln!("ignoring attempt to quote message from a different context"); + return; + } + Some(&ffi_quote.message) + }; block_on(async move { ffi_msg .message - .set_quote(&*ffi_msg.context, &ffi_quote.message) + .set_quote(&*ffi_msg.context, quote_msg) .await .log_err(&*ffi_msg.context, "failed to set quote") .ok(); diff --git a/src/chat.rs b/src/chat.rs index b4c7835b2..81ea5adef 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -3441,6 +3441,58 @@ mod tests { Ok(()) } + #[async_std::test] + async fn test_change_quotes_on_reused_message_object() -> Result<()> { + let t = TestContext::new_alice().await; + let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "chat").await?; + let quote1 = + Message::load_from_db(&t, send_text_msg(&t, chat_id, "quote1".to_string()).await?) + .await?; + let quote2 = + Message::load_from_db(&t, send_text_msg(&t, chat_id, "quote2".to_string()).await?) + .await?; + + // save a draft + let mut draft = Message::new(Viewtype::Text); + draft.set_text(Some("draft text".to_string())); + chat_id.set_draft(&t, Some(&mut draft)).await?; + + let test = Message::load_from_db(&t, draft.id).await?; + assert_eq!(test.text, Some("draft text".to_string())); + assert!(test.quoted_text().is_none()); + assert!(test.quoted_message(&t).await?.is_none()); + + // add quote to same message object + draft.set_quote(&t, Some("e1)).await?; + chat_id.set_draft(&t, Some(&mut draft)).await?; + + let test = Message::load_from_db(&t, draft.id).await?; + assert_eq!(test.text, Some("draft text".to_string())); + assert_eq!(test.quoted_text(), Some("quote1".to_string())); + assert_eq!(test.quoted_message(&t).await?.unwrap().id, quote1.id); + + // change quote on same message object + draft.set_text(Some("another draft text".to_string())); + draft.set_quote(&t, Some("e2)).await?; + chat_id.set_draft(&t, Some(&mut draft)).await?; + + let test = Message::load_from_db(&t, draft.id).await?; + assert_eq!(test.text, Some("another draft text".to_string())); + assert_eq!(test.quoted_text(), Some("quote2".to_string())); + assert_eq!(test.quoted_message(&t).await?.unwrap().id, quote2.id); + + // remove quote on same message object + draft.set_quote(&t, None).await?; + chat_id.set_draft(&t, Some(&mut draft)).await?; + + let test = Message::load_from_db(&t, draft.id).await?; + assert_eq!(test.text, Some("another draft text".to_string())); + assert!(test.quoted_text().is_none()); + assert!(test.quoted_message(&t).await?.is_none()); + + Ok(()) + } + #[async_std::test] async fn test_add_contact_to_chat_ex_add_self() { // Adding self to a contact should succeed, even though it's pointless. @@ -4746,7 +4798,7 @@ mod tests { // Bob quotes received message and sends a reply to Alice. let mut reply = Message::new(Viewtype::Text); reply.set_text(Some("Reply".to_owned())); - reply.set_quote(&bob, &received_msg).await?; + reply.set_quote(&bob, Some(&received_msg)).await?; let sent_reply = bob.send_msg(bob_chat.id, &mut reply).await; alice.recv_msg(&sent_reply).await; let received_reply = alice.get_last_msg().await; diff --git a/src/message.rs b/src/message.rs index 6514ba444..6815b0756 100644 --- a/src/message.rs +++ b/src/message.rs @@ -756,36 +756,41 @@ impl Message { /// /// The message itself is not required to exist in the database, /// it may even be deleted from the database by the time the message is prepared. - pub async fn set_quote(&mut self, context: &Context, quote: &Message) -> Result<()> { - ensure!( - !quote.rfc724_mid.is_empty(), - "Message without Message-Id cannot be quoted" - ); - self.in_reply_to = Some(quote.rfc724_mid.clone()); + pub async fn set_quote(&mut self, context: &Context, quote: Option<&Message>) -> Result<()> { + if let Some(quote) = quote { + ensure!( + !quote.rfc724_mid.is_empty(), + "Message without Message-Id cannot be quoted" + ); + self.in_reply_to = Some(quote.rfc724_mid.clone()); - if quote - .param - .get_bool(Param::GuaranteeE2ee) - .unwrap_or_default() - { - self.param.set(Param::GuaranteeE2ee, "1"); + if quote + .param + .get_bool(Param::GuaranteeE2ee) + .unwrap_or_default() + { + self.param.set(Param::GuaranteeE2ee, "1"); + } + + let text = quote.get_text().unwrap_or_default(); + self.param.set( + Param::Quote, + if text.is_empty() { + // Use summary, similar to "Image" to avoid sending empty quote. + quote + .get_summary(context, None) + .await? + .truncated_text(500) + .to_string() + } else { + text + }, + ); + } else { + self.in_reply_to = None; + self.param.remove(Param::Quote); } - let text = quote.get_text().unwrap_or_default(); - self.param.set( - Param::Quote, - if text.is_empty() { - // Use summary, similar to "Image" to avoid sending empty quote. - quote - .get_summary(context, None) - .await? - .truncated_text(500) - .to_string() - } else { - text - }, - ); - Ok(()) } @@ -1850,7 +1855,9 @@ mod tests { assert!(!msg.rfc724_mid.is_empty()); let mut msg2 = Message::new(Viewtype::Text); - msg2.set_quote(ctx, &msg).await.expect("can't set quote"); + msg2.set_quote(ctx, Some(&msg)) + .await + .expect("can't set quote"); assert!(msg2.quoted_text() == msg.get_text()); let quoted_msg = msg2 diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 3e1bca144..fcc6531ed 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -1688,7 +1688,7 @@ mod tests { let mut new_msg = Message::new(Viewtype::Text); new_msg.set_text(Some("Hi".to_string())); if let Some(q) = quote { - new_msg.set_quote(t, q).await?; + new_msg.set_quote(t, Some(q)).await?; } let sent = t.send_msg(group_id, &mut new_msg).await; get_subject(t, sent).await @@ -1857,7 +1857,7 @@ mod tests { } if reply { - new_msg.set_quote(&t, &incoming_msg).await.unwrap(); + new_msg.set_quote(&t, Some(&incoming_msg)).await.unwrap(); } let mf = MimeFactory::from_msg(&t, &new_msg, false).await.unwrap();