Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 40 additions & 3 deletions src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use std::collections::BTreeSet;
use std::collections::HashSet;
use std::collections::VecDeque;
use std::path::{Path, PathBuf};
use std::str;

Expand Down Expand Up @@ -1713,6 +1714,35 @@ pub(crate) async fn delete_msg_locally(context: &Context, msg: &Message) -> Resu
Ok(())
}

pub(crate) async fn get_webxdc_info_messages(
context: &Context,
msg: &Message,
) -> Result<Vec<MsgId>> {
let msg_ids = context
.sql
.query_map(
r#"SELECT id, param
FROM msgs
WHERE chat_id=?1 AND hidden=0 AND mime_in_reply_to = ?2
"#,
(msg.chat_id, &msg.rfc724_mid),
|row| {
let info_msg_id: MsgId = row.get(0)?;
let last_param: Params = row.get::<_, String>(1)?.parse().unwrap_or_default();
Ok((info_msg_id, last_param))
},
|row| {
Ok(row
.filter_map(Result::ok)
.filter(|(_, param)| param.get_cmd() == SystemMessage::WebxdcInfoMessage)
.map(|(msg_id, _)| msg_id)
.collect::<Vec<_>>())
},
)
.await?;
Ok(msg_ids)
}

/// Do final events and jobs after batch deletion using calls to delete_msg_locally().
/// To avoid additional database queries, collecting data is up to the caller.
pub(crate) async fn delete_msgs_locally_done(
Expand Down Expand Up @@ -1751,8 +1781,10 @@ pub async fn delete_msgs_ex(
let mut modified_chat_ids = HashSet::new();
let mut deleted_rfc724_mid = Vec::new();
let mut res = Ok(());
let mut msg_ids_queue = VecDeque::from_iter(msg_ids.iter().copied());
let mut msg_ids = Vec::from(msg_ids);

for &msg_id in msg_ids {
while let Some(msg_id) = msg_ids_queue.pop_front() {
let msg = Message::load_from_db(context, msg_id).await?;
ensure!(
!delete_for_all || msg.from_id == ContactId::SELF,
Expand All @@ -1763,6 +1795,11 @@ pub async fn delete_msgs_ex(
"Cannot request deletion of unencrypted message for others"
);

if msg.viewtype == Viewtype::Webxdc {
let info_msgs = get_webxdc_info_messages(context, &msg).await?;
msg_ids_queue.extend(&info_msgs);
msg_ids.extend(info_msgs);
}
modified_chat_ids.insert(msg.chat_id);
deleted_rfc724_mid.push(msg.rfc724_mid.clone());

Expand Down Expand Up @@ -1808,11 +1845,11 @@ pub async fn delete_msgs_ex(
.await?;
}

for &msg_id in msg_ids {
for &msg_id in &msg_ids {
let msg = Message::load_from_db(context, msg_id).await?;
delete_msg_locally(context, &msg).await?;
}
delete_msgs_locally_done(context, msg_ids, modified_chat_ids).await?;
delete_msgs_locally_done(context, &msg_ids, modified_chat_ids).await?;

// Interrupt Inbox loop to start message deletion, run housekeeping and call send_sync_msg().
context.scheduler.interrupt_inbox().await;
Expand Down
18 changes: 17 additions & 1 deletion src/receive_imf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ use crate::log::LogExt;
use crate::log::{info, warn};
use crate::logged_debug_assert;
use crate::message::{
self, Message, MessageState, MessengerMessage, MsgId, Viewtype, rfc724_mid_exists,
self, Message, MessageState, MessengerMessage, MsgId, Viewtype, get_webxdc_info_messages,
rfc724_mid_exists,
};
use crate::mimeparser::{AvatarAction, MimeMessage, SystemMessage, parse_message_ids};
use crate::param::{Param, Params};
Expand Down Expand Up @@ -2295,12 +2296,18 @@ async fn handle_edit_delete(
let mut modified_chat_ids = HashSet::new();
let mut msg_ids = Vec::new();

let mut deleted_info_msgs = vec![];
let rfc724_mid_vec: Vec<&str> = rfc724_mid_list.split_whitespace().collect();
for rfc724_mid in rfc724_mid_vec {
if let Some((msg_id, _)) =
message::rfc724_mid_exists(context, rfc724_mid).await?
{
if let Some(msg) = Message::load_from_db_optional(context, msg_id).await? {
if msg.viewtype == Viewtype::Webxdc {
let info_msgs = get_webxdc_info_messages(context, &msg).await?;
deleted_info_msgs.extend(&info_msgs);
}

if msg.from_id == from_id {
message::delete_msg_locally(context, &msg).await?;
msg_ids.push(msg.id);
Expand All @@ -2315,6 +2322,15 @@ async fn handle_edit_delete(
warn!(context, "Delete message: {rfc724_mid:?} not found.");
}
}
if !deleted_info_msgs.is_empty() {
message::delete_msgs(context, &deleted_info_msgs).await?;
for msg_id in deleted_info_msgs {
if let Some(msg) = Message::load_from_db_optional(context, msg_id).await? {
message::delete_msg_locally(context, &msg).await?;
msg_ids.push(msg.id);
}
}
}
message::delete_msgs_locally_done(context, &msg_ids, modified_chat_ids).await?;
} else {
warn!(context, "Delete message: Not encrypted.");
Expand Down
16 changes: 15 additions & 1 deletion src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::contact::ContactId;
use crate::context::Context;
use crate::log::LogExt;
use crate::log::{info, warn};
use crate::message::{Message, MsgId, Viewtype};
use crate::message::{Message, MsgId, Viewtype, get_webxdc_info_messages};
use crate::mimeparser::SystemMessage;
use crate::param::Param;
use crate::sync::SyncData::{AddQrToken, AlterChat, DeleteQrToken};
Expand Down Expand Up @@ -306,10 +306,15 @@ impl Context {

async fn sync_message_deletion(&self, msgs: &Vec<String>) -> Result<()> {
let mut modified_chat_ids = HashSet::new();
let mut deleted_info_msgs = vec![];
let mut msg_ids = Vec::new();
for rfc724_mid in msgs {
if let Some((msg_id, _)) = message::rfc724_mid_exists(self, rfc724_mid).await? {
if let Some(msg) = Message::load_from_db_optional(self, msg_id).await? {
if msg.viewtype == Viewtype::Webxdc {
let info_msgs = get_webxdc_info_messages(&self, &msg).await?;
deleted_info_msgs.extend(&info_msgs);
}
message::delete_msg_locally(self, &msg).await?;
msg_ids.push(msg.id);
modified_chat_ids.insert(msg.chat_id);
Expand All @@ -320,6 +325,15 @@ impl Context {
warn!(self, "Sync message delete: {rfc724_mid:?} not found.");
}
}
if !deleted_info_msgs.is_empty() {
message::delete_msgs(&self, &deleted_info_msgs).await?;
for msg_id in deleted_info_msgs {
if let Some(msg) = Message::load_from_db_optional(&self, msg_id).await? {
message::delete_msg_locally(&self, &msg).await?;
msg_ids.push(msg.id);
}
}
}
message::delete_msgs_locally_done(self, &msg_ids, modified_chat_ids).await?;
Ok(())
}
Expand Down
21 changes: 21 additions & 0 deletions src/webxdc/webxdc_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::chatlist::Chatlist;
use crate::config::Config;
use crate::download::DownloadState;
use crate::ephemeral;
use crate::message::delete_msgs;
use crate::receive_imf::{receive_imf, receive_imf_from_inbox};
use crate::test_utils::{E2EE_INFO_MSGS, TestContext, TestContextManager};
use crate::tools::{self, SystemTime};
Expand Down Expand Up @@ -1616,6 +1617,26 @@ async fn test_webxdc_info_msg_no_cleanup_on_interrupted_series() -> Result<()> {
Ok(())
}

#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_webxdc_info_msg_delete() -> Result<()> {
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "c").await?;
let instance = send_webxdc_instance(&t, chat_id).await?;

t.send_webxdc_status_update(instance.id, r#"{"info":"i1", "payload":1}"#)
.await?;
assert_eq!(chat_id.get_msg_cnt(&t).await?, 2);
send_text_msg(&t, chat_id, "msg between info".to_string()).await?;
assert_eq!(chat_id.get_msg_cnt(&t).await?, 3);
t.send_webxdc_status_update(instance.id, r#"{"info":"i2", "payload":2}"#)
.await?;
assert_eq!(chat_id.get_msg_cnt(&t).await?, 4);
delete_msgs(&t, &[instance.id]).await?;
assert_eq!(chat_id.get_msg_cnt(&t).await?, 1);

Ok(())
}

// check that `info.internet_access` is not set for normal, non-integrated webxdc -
// even if they use the deprecated option `request_internet_access` in manifest.toml
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
Expand Down
Loading