diff --git a/src/chat.rs b/src/chat.rs index 4da1e5ecd..7539b5bc5 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -3685,7 +3685,8 @@ pub async fn create_group_chat( /// Returns the created chat's id. pub async fn create_broadcast(context: &Context, chat_name: String) -> Result { 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( @@ -3693,6 +3694,7 @@ pub(crate) async fn create_broadcast_ex( sync: sync::Sync, grpid: String, chat_name: String, + secret: String, ) -> Result { let row_id = { let chat_name = &chat_name; @@ -3712,7 +3714,7 @@ pub(crate) async fn create_broadcast_ex( } let mut param = Params::new(); // 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( "INSERT INTO chats \ (type, name, grpid, param, created_timestamp) \ @@ -3725,6 +3727,13 @@ pub(crate) async fn create_broadcast_ex( 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()?) }; context.sql.transaction(trans_fn).await? @@ -3736,7 +3745,7 @@ pub(crate) async fn create_broadcast_ex( if sync.into() { 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(); } @@ -4952,7 +4961,10 @@ pub(crate) enum SyncAction { SetVisibility(ChatVisibility), SetMuted(MuteDuration), /// Create broadcast channel with the given name. - CreateBroadcast(String), + CreateBroadcast { + chat_name: String, + secret: String, + }, Rename(String), /// Set chat contacts by their addresses. SetContacts(Vec), @@ -5015,8 +5027,15 @@ impl Context { .id } SyncId::Grpid(grpid) => { - if let SyncAction::CreateBroadcast(name) = action { - create_broadcast_ex(self, Nosync, grpid.clone(), name.clone()).await?; + if let SyncAction::CreateBroadcast { chat_name, secret } = action { + create_broadcast_ex( + self, + Nosync, + grpid.clone(), + chat_name.clone(), + secret.to_string(), + ) + .await?; return Ok(()); } get_chat_id_by_grpid(self, grpid) @@ -5039,7 +5058,7 @@ impl Context { SyncAction::Accept => chat_id.accept_ex(self, Nosync).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::CreateBroadcast(_) => { + SyncAction::CreateBroadcast { .. } => { Err(anyhow!("sync_alter_chat({id:?}, {action:?}): Bad request.")) } SyncAction::Rename(to) => rename_ex(self, Nosync, chat_id, to).await, diff --git a/src/chat/chat_tests.rs b/src/chat/chat_tests.rs index 9c6b646f8..214a2da28 100644 --- a/src/chat/chat_tests.rs +++ b/src/chat/chat_tests.rs @@ -3827,12 +3827,25 @@ async fn test_sync_name() -> Result<()> { let a0_broadcast_id = create_broadcast(alice0, "Channel".to_string()).await?; sync(alice0, alice1).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?; - 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) .await? .unwrap() .0; + assert_eq!(rcvd.chat_id, a1_broadcast_id); + 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_name(), "Broadcast channel 42"); diff --git a/src/param.rs b/src/param.rs index b9da5d97a..1e1302bfb 100644 --- a/src/param.rs +++ b/src/param.rs @@ -174,7 +174,7 @@ pub enum Param { /// and for messages adding members to such a chat. /// The symmetric key shared among all chat participants, /// 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 /// the List-Id of the mailing list (which is also used as the group id of the chat). diff --git a/src/receive_imf.rs b/src/receive_imf.rs index e0f643e52..33fa7f5cb 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -1540,10 +1540,25 @@ async fn do_chat_assignment( if let Some((id, ..)) = chat::get_chat_id_by_grpid(context, &listid).await? { id - } else { + } else if let Some(secret) = + mime_parser.get_header(HeaderDef::ChatBroadcastSecret) + { let name = 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, from_id: ContactId, ) -> Result { + // TODO code duplication with apply_in_broadcast_changes() 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) { // The sender of the message left the broadcast channel 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(