From 046a2a8eaee3c9d55cb22af60ece2dac7defcc70 Mon Sep 17 00:00:00 2001 From: bjoern Date: Tue, 16 Feb 2021 10:24:44 +0100 Subject: [PATCH] set correct name for mailchimp mailinglists (#2243) * add test for mailchimp mailinglists * pass MimeMessage to create_or_lookup_mailinglist() (as of the other create*() routines) to allow more flexible name processing; document the function * get mailing list name for mailchimp from From:-header * make clippy happy * add comment to '.list-id.mcsv.net' suffix --- CHANGELOG.md | 1 + src/dc_receive_imf.rs | 64 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50c8a1e9b..2e8d5d2e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - new chat type and apis for the new mailing list support, `DC_CHAT_TYPE_MAILINGLIST`, `dc_msg_get_real_chat_id()`, `dc_msg_get_override_sender_name()` #1964 #2181 #2185 #2195 #2211 #2210 #2240 + #2243 - new api `dc_decide_on_contact_request()`, deprecated `dc_create_chat_by_msg_id()` and `dc_marknoticed_contact()` #1964 diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 3cd857de8..3d6232d07 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -529,7 +529,7 @@ async fn add_parts( context, allow_creation, list_id, - &mime_parser.get_subject().unwrap_or_default(), + mime_parser, ) .await; *chat_id = new_chat_id; @@ -542,7 +542,7 @@ async fn add_parts( context, allow_creation, sender, - &mime_parser.get_subject().unwrap_or_default(), + mime_parser, ) .await; *chat_id = new_chat_id; @@ -1491,12 +1491,21 @@ async fn create_or_lookup_group( Ok((chat_id, chat_id_blocked)) } +/// Create or lookup a mailing list chat. +/// +/// `list_id_header` contains the Id that must be used for the mailing list +/// and has the form `Name `, `` or just `Id`. +/// Depending on the mailing list type, `list_id_header` +/// was picked from `ListId:`-header or the `Sender:`-header. +/// +/// `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, - subject: &str, + mime_parser: &MimeMessage, ) -> (ChatId, Blocked) { static LIST_ID: Lazy = Lazy::new(|| Regex::new(r"^(.+)<(.+)>$").unwrap()); let (mut name, listid) = match LIST_ID.captures(list_id_header) { @@ -1515,8 +1524,23 @@ async fn create_or_lookup_mailinglist( return (chat_id, blocked); } + // for mailchimp lists, the name in `ListId` is just a long number. + // a usable name for these lists is in the `From` header + // and we can detect these lists by a unique `ListId`-suffix. + if listid.ends_with(".list-id.mcsv.net") { + if let Some(from) = mime_parser.from.first() { + if let Some(display_name) = &from.display_name { + name = display_name.clone(); + } + } + } + + // if we have an additional name square brackets in the subject, we prefer that + // (as that part is much more visible, we assume, that names is shorter and comes more to the point, + // than the sometimes longer part from ListId) + let subject = mime_parser.get_subject().unwrap_or_default(); static SUBJECT: Lazy = Lazy::new(|| Regex::new(r"^.{0,5}\[(.*.)\]").unwrap()); - if let Some(cap) = SUBJECT.captures(subject) { + if let Some(cap) = SUBJECT.captures(&subject) { name = cap[1].to_string(); } @@ -2955,6 +2979,38 @@ mod tests { assert_eq!(chat::get_chat_msgs(&t, chat.id, 0, None).await.len(), 2); } + #[async_std::test] + async fn test_mailchimp_mailing_list() { + let t = TestContext::new_alice().await; + t.set_config(Config::ShowEmails, Some("2")).await.unwrap(); + + dc_receive_imf( + &t, + b"To: alice \n\ + Subject: =?utf-8?Q?How=20early=20megacities=20emerged=20from=20Cambodia=E2=80=99s=20jungles?=\n\ + From: =?utf-8?Q?Atlas=20Obscura?= \n\ + List-ID: 399fc0402f1b154b67965632emc list <399fc0402f1b154b67965632e.100761.list-id.mcsv.net>\n\ + Message-ID: <555@example.org>\n\ + Date: Sun, 22 Mar 2020 22:37:57 +0000\n\ + \n\ + hello\n", + "INBOX", + 1, + false, + ) + .await + .unwrap(); + let msg = t.get_last_msg().await; + let chat = Chat::load_from_db(&t, msg.chat_id).await.unwrap(); + assert_eq!(chat.typ, Chattype::Mailinglist); + assert_eq!(chat.blocked, Blocked::Deaddrop); + assert_eq!( + chat.grpid, + "399fc0402f1b154b67965632e.100761.list-id.mcsv.net" + ); + assert_eq!(chat.name, "Atlas Obscura"); + } + #[async_std::test] async fn test_dont_show_tokens_in_contacts_list() { check_dont_show_in_contacts_list(