diff --git a/deltachat-jsonrpc/src/api.rs b/deltachat-jsonrpc/src/api.rs index 1603f341a..8f3b27fa4 100644 --- a/deltachat-jsonrpc/src/api.rs +++ b/deltachat-jsonrpc/src/api.rs @@ -21,9 +21,9 @@ use deltachat::context::get_info; use deltachat::ephemeral::Timer; use deltachat::imex; use deltachat::location; -use deltachat::message::get_msg_read_receipts; use deltachat::message::{ - self, delete_msgs_ex, markseen_msgs, Message, MessageState, MsgId, Viewtype, + self, delete_msgs_ex, get_existing_msg_ids, get_msg_read_receipts, markseen_msgs, Message, + MessageState, MsgId, Viewtype, }; use deltachat::peer_channels::{ leave_webxdc_realtime, send_webxdc_realtime_advertisement, send_webxdc_realtime_data, @@ -1295,6 +1295,19 @@ impl CommandApi { .collect()) } + /// Checks if the messages with given IDs exist. + /// + /// Returns IDs of existing messages. + async fn get_existing_msg_ids(&self, account_id: u32, msg_ids: Vec) -> Result> { + let context = self.get_context(account_id).await?; + let msg_ids: Vec = msg_ids.into_iter().map(MsgId::new).collect(); + let existing_msg_ids = get_existing_msg_ids(&context, &msg_ids).await?; + Ok(existing_msg_ids + .into_iter() + .map(|msg_id| msg_id.to_u32()) + .collect()) + } + async fn get_message_list_items( &self, account_id: u32, diff --git a/src/message.rs b/src/message.rs index 2f7252a37..aedfded94 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1868,6 +1868,33 @@ pub async fn markseen_msgs(context: &Context, msg_ids: Vec) -> Result<()> Ok(()) } +/// Checks if the messages with given IDs exist. +/// +/// Returns IDs of existing messages. +pub async fn get_existing_msg_ids(context: &Context, ids: &[MsgId]) -> Result> { + let query_only = true; + let res = context + .sql + .transaction_ex(query_only, |transaction| { + let mut res: Vec = Vec::new(); + for id in ids { + if transaction.query_one( + "SELECT COUNT(*) > 0 FROM msgs WHERE id=? AND chat_id!=3", + (id,), + |row| { + let exists: bool = row.get(0)?; + Ok(exists) + }, + )? { + res.push(*id); + } + } + Ok(res) + }) + .await?; + Ok(res) +} + pub(crate) async fn update_msg_state( context: &Context, msg_id: MsgId, diff --git a/src/message/message_tests.rs b/src/message/message_tests.rs index 66f2c6f09..be3ed01d9 100644 --- a/src/message/message_tests.rs +++ b/src/message/message_tests.rs @@ -764,3 +764,27 @@ async fn test_load_unknown_viewtype() -> Result<()> { assert_eq!(bob_msg.get_viewtype(), Viewtype::Unknown); Ok(()) } + +#[tokio::test(flavor = "multi_thread", worker_threads = 2)] +async fn test_get_existing_msg_ids() -> Result<()> { + let mut tcm = TestContextManager::new(); + let alice = &tcm.alice().await; + let bob = &tcm.bob().await; + + let msg1_id = tcm.send_recv(alice, bob, "Hello 1!").await.id; + let msg2_id = tcm.send_recv(alice, bob, "Hello 2!").await.id; + let msg3_id = tcm.send_recv(alice, bob, "Hello 3!").await.id; + let msg4_id = tcm.send_recv(alice, bob, "Hello 4!").await.id; + + assert_eq!( + get_existing_msg_ids(bob, &[msg1_id, msg2_id, msg3_id, msg4_id]).await?, + vec![msg1_id, msg2_id, msg3_id, msg4_id] + ); + delete_msgs(bob, &[msg1_id, msg3_id]).await?; + assert_eq!( + get_existing_msg_ids(bob, &[msg1_id, msg2_id, msg3_id, msg4_id]).await?, + vec![msg2_id, msg4_id] + ); + + Ok(()) +}