diff --git a/src/chat.rs b/src/chat.rs index bd59a7177..5946cb9d2 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -3249,7 +3249,7 @@ pub async fn create_broadcast_list(context: &Context) -> Result { create_broadcast_list_ex(context, Sync, grpid, chat_name).await } -async fn create_broadcast_list_ex( +pub(crate) async fn create_broadcast_list_ex( context: &Context, sync: sync::Sync, grpid: String, @@ -6514,6 +6514,47 @@ mod tests { Ok(()) } + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_broadcast_multidev() -> Result<()> { + let alices = [ + TestContext::new_alice().await, + TestContext::new_alice().await, + ]; + let bob = TestContext::new_bob().await; + let a1b_contact_id = alices[1].add_or_lookup_contact(&bob).await.id; + + let a0_broadcast_id = create_broadcast_list(&alices[0]).await?; + let a0_broadcast_chat = Chat::load_from_db(&alices[0], a0_broadcast_id).await?; + set_chat_name(&alices[0], a0_broadcast_id, "Broadcast list 42").await?; + let sent_msg = alices[0].send_text(a0_broadcast_id, "hi").await; + let msg = alices[1].recv_msg(&sent_msg).await; + let a1_broadcast_id = get_chat_id_by_grpid(&alices[1], &a0_broadcast_chat.grpid) + .await? + .unwrap() + .0; + assert_eq!(msg.chat_id, a1_broadcast_id); + let a1_broadcast_chat = Chat::load_from_db(&alices[1], a1_broadcast_id).await?; + assert_eq!(a1_broadcast_chat.get_type(), Chattype::Broadcast); + assert_eq!(a1_broadcast_chat.get_name(), "Broadcast list 42"); + assert!(get_chat_contacts(&alices[1], a1_broadcast_id) + .await? + .is_empty()); + + add_contact_to_chat(&alices[1], a1_broadcast_id, a1b_contact_id).await?; + set_chat_name(&alices[1], a1_broadcast_id, "Broadcast list 43").await?; + let sent_msg = alices[1].send_text(a1_broadcast_id, "hi").await; + let msg = alices[0].recv_msg(&sent_msg).await; + assert_eq!(msg.chat_id, a0_broadcast_id); + let a0_broadcast_chat = Chat::load_from_db(&alices[0], a0_broadcast_id).await?; + assert_eq!(a0_broadcast_chat.get_type(), Chattype::Broadcast); + assert_eq!(a0_broadcast_chat.get_name(), "Broadcast list 42"); + assert!(get_chat_contacts(&alices[0], a0_broadcast_id) + .await? + .is_empty()); + + Ok(()) + } + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_create_for_contact_with_blocked() -> Result<()> { let t = TestContext::new().await; @@ -6947,9 +6988,8 @@ mod tests { let msg = bob.recv_msg(&sent_msg).await; let chat = Chat::load_from_db(&bob, msg.chat_id).await?; assert_eq!(chat.get_type(), Chattype::Mailinglist); - // TODO: It doesn't work now for some reason, `msg.chat_id == DC_CHAT_ID_TRASH`. - // let msg = alices[0].recv_msg(&sent_msg).await; - // assert_eq!(msg.chat_id, a0_broadcast_id); + let msg = alices[0].recv_msg(&sent_msg).await; + assert_eq!(msg.chat_id, a0_broadcast_id); remove_contact_from_chat(&alices[0], a0_broadcast_id, ab_contact_ids[0]).await?; sync(&alices).await?; assert!(get_chat_contacts(&alices[1], a1_broadcast_id) diff --git a/src/receive_imf.rs b/src/receive_imf.rs index f009024a5..d53d08bad 100644 --- a/src/receive_imf.rs +++ b/src/receive_imf.rs @@ -930,6 +930,22 @@ async fn add_parts( } } } + + if chat_id.is_none() { + // Check if the message belongs to a broadcast list. + if let Some(mailinglist_header) = mime_parser.get_mailinglist_header() { + let listid = mailinglist_header_listid(mailinglist_header)?; + chat_id = Some( + if let Some((id, ..)) = chat::get_chat_id_by_grpid(context, &listid).await? { + id + } else { + let name = + compute_mailinglist_name(mailinglist_header, &listid, mime_parser); + chat::create_broadcast_list_ex(context, Nosync, listid, name).await? + }, + ); + } + } } if fetching_existing_messages && mime_parser.decrypting_failed { @@ -1966,6 +1982,17 @@ async fn apply_group_changes( static LIST_ID_REGEX: Lazy = Lazy::new(|| Regex::new(r"^(.+)<(.+)>$").unwrap()); +fn mailinglist_header_listid(list_id_header: &str) -> Result { + Ok(match LIST_ID_REGEX.captures(list_id_header) { + Some(cap) => cap.get(2).context("no match??")?.as_str().trim(), + None => list_id_header + .trim() + .trim_start_matches('<') + .trim_end_matches('>'), + } + .to_string()) +} + /// Create or lookup a mailing list chat. /// /// `list_id_header` contains the Id that must be used for the mailing list @@ -1975,21 +2002,13 @@ static LIST_ID_REGEX: Lazy = Lazy::new(|| Regex::new(r"^(.+)<(.+)>$").unw /// /// `mime_parser` is the corresponding message /// and is used to figure out the mailing list name from different header fields. -#[allow(clippy::indexing_slicing)] async fn create_or_lookup_mailinglist( context: &Context, allow_creation: bool, list_id_header: &str, mime_parser: &MimeMessage, ) -> Result> { - let listid = match LIST_ID_REGEX.captures(list_id_header) { - Some(cap) => cap[2].trim().to_string(), - None => list_id_header - .trim() - .trim_start_matches('<') - .trim_end_matches('>') - .to_string(), - }; + let listid = mailinglist_header_listid(list_id_header)?; if let Some((chat_id, _, blocked)) = chat::get_chat_id_by_grpid(context, &listid).await? { return Ok(Some((chat_id, blocked)));