mirror of
https://github.com/chatmail/core.git
synced 2026-05-03 21:36:29 +03:00
feat: Sync user actions for ad-hoc groups across devices (#5065)
Ad-hoc groups don't have grpid-s that can be used to identify them across devices and thus wasn't synced until now. The same problem already exists for assigning messages to ad-hoc groups and this assignment is done by `get_parent_message()` and `lookup_chat_by_reply()`. Let's reuse this logic for the synchronisation, it works well enough and this way we have less surprises than if we try to implement grpids for ad-hoc groups. I.e. add an `Msgids` variant to `chat::SyncId` analogous to the "References" header in messages and put two following Message-IDs to a sync message: - The latest message A having `DownloadState::Done` and the state to be one of `InFresh, InNoticed, InSeen, OutDelivered, OutMdnRcvd`. - The message that A references in `In-Reply-To`. This way the logic is almost the same to what we have in `Chat::prepare_msg_raw()` (the difference is that we don't use the oldest Message-ID) and it's easier to reuse the existing code. NOTE: If a chat has only an OutPending message f.e., the synchronisation wouldn't work, but trying to work in such a corner case has no significant value and isn't worth complicating the code.
This commit is contained in:
@@ -1544,27 +1544,10 @@ async fn lookup_chat_by_reply(
|
||||
let Some(parent) = parent else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let parent_chat = Chat::load_from_db(context, parent.chat_id).await?;
|
||||
|
||||
if parent.download_state != DownloadState::Done
|
||||
// TODO (2023-09-12): Added for backward compatibility with versions that did not have
|
||||
// `DownloadState::Undecipherable`. Remove eventually with the comment in
|
||||
// `MimeMessage::from_bytes()`.
|
||||
|| parent
|
||||
.error
|
||||
.as_ref()
|
||||
.filter(|e| e.starts_with("Decrypting failed:"))
|
||||
.is_some()
|
||||
{
|
||||
// If the parent msg is not fully downloaded or undecipherable, it may have been
|
||||
// assigned to the wrong chat (they often get assigned to the 1:1 chat with the sender).
|
||||
let Some(parent_chat_id) = ChatId::lookup_by_message(parent) else {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
if parent_chat.id == DC_CHAT_ID_TRASH {
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
let parent_chat = Chat::load_from_db(context, parent_chat_id).await?;
|
||||
|
||||
// If this was a private message just to self, it was probably a private reply.
|
||||
// It should not go into the group then, but into the private chat.
|
||||
@@ -2558,20 +2541,7 @@ async fn get_previous_message(
|
||||
///
|
||||
/// Only messages that are not in the trash chat are considered.
|
||||
async fn get_rfc724_mid_in_list(context: &Context, mid_list: &str) -> Result<Option<Message>> {
|
||||
if mid_list.is_empty() {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
for id in parse_message_ids(mid_list).iter().rev() {
|
||||
if let Some(msg_id) = rfc724_mid_exists(context, id).await? {
|
||||
let msg = Message::load_from_db(context, msg_id).await?;
|
||||
if msg.chat_id != DC_CHAT_ID_TRASH {
|
||||
return Ok(Some(msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
message::get_latest_by_rfc724_mids(context, &parse_message_ids(mid_list)).await
|
||||
}
|
||||
|
||||
/// Returns the last message referenced from References: header found in the database.
|
||||
|
||||
Reference in New Issue
Block a user