Fix multidevice

This commit is contained in:
Hocuri
2025-07-12 13:45:35 +02:00
parent 70ab41d7c2
commit eadbf41383
4 changed files with 82 additions and 12 deletions

View File

@@ -3685,7 +3685,8 @@ pub async fn create_group_chat(
/// Returns the created chat's id. /// Returns the created chat's id.
pub async fn create_broadcast(context: &Context, chat_name: String) -> Result<ChatId> { pub async fn create_broadcast(context: &Context, chat_name: String) -> Result<ChatId> {
let grpid = create_id(); let grpid = create_id();
create_broadcast_ex(context, Sync, grpid, chat_name).await let secret = create_broadcast_shared_secret();
create_broadcast_ex(context, Sync, grpid, chat_name, secret).await
} }
pub(crate) async fn create_broadcast_ex( pub(crate) async fn create_broadcast_ex(
@@ -3693,6 +3694,7 @@ pub(crate) async fn create_broadcast_ex(
sync: sync::Sync, sync: sync::Sync,
grpid: String, grpid: String,
chat_name: String, chat_name: String,
secret: String,
) -> Result<ChatId> { ) -> Result<ChatId> {
let row_id = { let row_id = {
let chat_name = &chat_name; let chat_name = &chat_name;
@@ -3712,7 +3714,7 @@ pub(crate) async fn create_broadcast_ex(
} }
let mut param = Params::new(); let mut param = Params::new();
// param.set(Param::Unpromoted, 1); // TODO broadcasts will just never be unpromoted for now // param.set(Param::Unpromoted, 1); // TODO broadcasts will just never be unpromoted for now
param.set(Param::SymmetricKey, create_broadcast_shared_secret()); param.set(Param::SymmetricKey, &secret);
t.execute( t.execute(
"INSERT INTO chats \ "INSERT INTO chats \
(type, name, grpid, param, created_timestamp) \ (type, name, grpid, param, created_timestamp) \
@@ -3725,6 +3727,13 @@ pub(crate) async fn create_broadcast_ex(
create_smeared_timestamp(context), create_smeared_timestamp(context),
), ),
)?; )?;
let chat_id = t.last_insert_rowid();
// TODO code duplication of `INSERT INTO broadcasts_shared_secrets`
t.execute(
"INSERT INTO broadcasts_shared_secrets (chat_id, secret) VALUES (?, ?)
ON CONFLICT(chat_id) DO UPDATE SET secret=excluded.chat_id",
(chat_id, &secret),
)?;
Ok(t.last_insert_rowid().try_into()?) Ok(t.last_insert_rowid().try_into()?)
}; };
context.sql.transaction(trans_fn).await? context.sql.transaction(trans_fn).await?
@@ -3736,7 +3745,7 @@ pub(crate) async fn create_broadcast_ex(
if sync.into() { if sync.into() {
let id = SyncId::Grpid(grpid); let id = SyncId::Grpid(grpid);
let action = SyncAction::CreateBroadcast(chat_name); let action = SyncAction::CreateBroadcast { chat_name, secret };
self::sync(context, id, action).await.log_err(context).ok(); self::sync(context, id, action).await.log_err(context).ok();
} }
@@ -4952,7 +4961,10 @@ pub(crate) enum SyncAction {
SetVisibility(ChatVisibility), SetVisibility(ChatVisibility),
SetMuted(MuteDuration), SetMuted(MuteDuration),
/// Create broadcast channel with the given name. /// Create broadcast channel with the given name.
CreateBroadcast(String), CreateBroadcast {
chat_name: String,
secret: String,
},
Rename(String), Rename(String),
/// Set chat contacts by their addresses. /// Set chat contacts by their addresses.
SetContacts(Vec<String>), SetContacts(Vec<String>),
@@ -5015,8 +5027,15 @@ impl Context {
.id .id
} }
SyncId::Grpid(grpid) => { SyncId::Grpid(grpid) => {
if let SyncAction::CreateBroadcast(name) = action { if let SyncAction::CreateBroadcast { chat_name, secret } = action {
create_broadcast_ex(self, Nosync, grpid.clone(), name.clone()).await?; create_broadcast_ex(
self,
Nosync,
grpid.clone(),
chat_name.clone(),
secret.to_string(),
)
.await?;
return Ok(()); return Ok(());
} }
get_chat_id_by_grpid(self, grpid) get_chat_id_by_grpid(self, grpid)
@@ -5039,7 +5058,7 @@ impl Context {
SyncAction::Accept => chat_id.accept_ex(self, Nosync).await, SyncAction::Accept => chat_id.accept_ex(self, Nosync).await,
SyncAction::SetVisibility(v) => chat_id.set_visibility_ex(self, Nosync, *v).await, SyncAction::SetVisibility(v) => chat_id.set_visibility_ex(self, Nosync, *v).await,
SyncAction::SetMuted(duration) => set_muted_ex(self, Nosync, chat_id, *duration).await, SyncAction::SetMuted(duration) => set_muted_ex(self, Nosync, chat_id, *duration).await,
SyncAction::CreateBroadcast(_) => { SyncAction::CreateBroadcast { .. } => {
Err(anyhow!("sync_alter_chat({id:?}, {action:?}): Bad request.")) Err(anyhow!("sync_alter_chat({id:?}, {action:?}): Bad request."))
} }
SyncAction::Rename(to) => rename_ex(self, Nosync, chat_id, to).await, SyncAction::Rename(to) => rename_ex(self, Nosync, chat_id, to).await,

View File

@@ -3827,12 +3827,25 @@ async fn test_sync_name() -> Result<()> {
let a0_broadcast_id = create_broadcast(alice0, "Channel".to_string()).await?; let a0_broadcast_id = create_broadcast(alice0, "Channel".to_string()).await?;
sync(alice0, alice1).await; sync(alice0, alice1).await;
let a0_broadcast_chat = Chat::load_from_db(alice0, a0_broadcast_id).await?; let a0_broadcast_chat = Chat::load_from_db(alice0, a0_broadcast_id).await?;
set_chat_name(alice0, a0_broadcast_id, "Broadcast channel 42").await?; set_chat_name(alice0, a0_broadcast_id, "Broadcast channel 42").await?;
sync(alice0, alice1).await; //sync(alice0, alice1).await; // crash
let sent = alice0.pop_sent_msg().await;
let rcvd = alice1.recv_msg(&sent).await;
assert_eq!(rcvd.from_id, ContactId::SELF);
assert_eq!(rcvd.to_id, ContactId::SELF);
assert_eq!(
rcvd.text,
"You changed group name from \"Channel\" to \"Broadcast channel 42\"."
);
assert_eq!(rcvd.param.get_cmd(), SystemMessage::GroupNameChanged);
let a1_broadcast_id = get_chat_id_by_grpid(alice1, &a0_broadcast_chat.grpid) let a1_broadcast_id = get_chat_id_by_grpid(alice1, &a0_broadcast_chat.grpid)
.await? .await?
.unwrap() .unwrap()
.0; .0;
assert_eq!(rcvd.chat_id, a1_broadcast_id);
let a1_broadcast_chat = Chat::load_from_db(alice1, a1_broadcast_id).await?; let a1_broadcast_chat = Chat::load_from_db(alice1, a1_broadcast_id).await?;
assert_eq!(a1_broadcast_chat.get_type(), Chattype::OutBroadcast); assert_eq!(a1_broadcast_chat.get_type(), Chattype::OutBroadcast);
assert_eq!(a1_broadcast_chat.get_name(), "Broadcast channel 42"); assert_eq!(a1_broadcast_chat.get_name(), "Broadcast channel 42");

View File

@@ -174,7 +174,7 @@ pub enum Param {
/// and for messages adding members to such a chat. /// and for messages adding members to such a chat.
/// The symmetric key shared among all chat participants, /// The symmetric key shared among all chat participants,
/// used to encrypt and decrypt messages. /// used to encrypt and decrypt messages.
SymmetricKey = b'z', SymmetricKey = b'z', // TODO remove this again
/// For Contacts: If this is the List-Post address of a mailing list, contains /// For Contacts: If this is the List-Post address of a mailing list, contains
/// the List-Id of the mailing list (which is also used as the group id of the chat). /// the List-Id of the mailing list (which is also used as the group id of the chat).

View File

@@ -1540,10 +1540,25 @@ async fn do_chat_assignment(
if let Some((id, ..)) = chat::get_chat_id_by_grpid(context, &listid).await? if let Some((id, ..)) = chat::get_chat_id_by_grpid(context, &listid).await?
{ {
id id
} else { } else if let Some(secret) =
mime_parser.get_header(HeaderDef::ChatBroadcastSecret)
{
let name = let name =
compute_mailinglist_name(mailinglist_header, &listid, mime_parser); compute_mailinglist_name(mailinglist_header, &listid, mime_parser);
chat::create_broadcast_ex(context, Nosync, listid, name).await? chat::create_broadcast_ex(
context,
Nosync,
listid,
name,
secret.to_string(),
)
.await?
} else {
warn!(
context,
"Unknown shared secret for outgoing broadcast (TRASH)"
);
DC_CHAT_ID_TRASH
}, },
); );
} }
@@ -3450,8 +3465,22 @@ async fn apply_out_broadcast_changes(
chat: &mut Chat, chat: &mut Chat,
from_id: ContactId, from_id: ContactId,
) -> Result<GroupChangesInfo> { ) -> Result<GroupChangesInfo> {
// TODO code duplication with apply_in_broadcast_changes()
ensure!(chat.typ == Chattype::OutBroadcast); ensure!(chat.typ == Chattype::OutBroadcast);
let mut send_event_chat_modified = false;
let mut better_msg = None;
apply_chat_name_and_avatar_changes(
context,
mime_parser,
from_id,
chat,
&mut send_event_chat_modified,
&mut better_msg,
)
.await?;
if let Some(_removed_addr) = mime_parser.get_header(HeaderDef::ChatGroupMemberRemoved) { if let Some(_removed_addr) = mime_parser.get_header(HeaderDef::ChatGroupMemberRemoved) {
// The sender of the message left the broadcast channel // The sender of the message left the broadcast channel
remove_from_chat_contacts_table(context, chat.id, from_id).await?; remove_from_chat_contacts_table(context, chat.id, from_id).await?;
@@ -3464,7 +3493,16 @@ async fn apply_out_broadcast_changes(
}); });
} }
Ok(GroupChangesInfo::default()) if send_event_chat_modified {
context.emit_event(EventType::ChatModified(chat.id));
chatlist_events::emit_chatlist_item_changed(context, chat.id);
}
Ok(GroupChangesInfo {
better_msg,
added_removed_id: None,
silent: false,
extra_msgs: vec![],
})
} }
async fn apply_in_broadcast_changes( async fn apply_in_broadcast_changes(