From 3c34096392ca81d7ce498a7b96cd374748e121c7 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sun, 22 Mar 2020 17:21:31 +0100 Subject: [PATCH 01/11] add a failing test that crashes when sending a message to a self-only group with bcc_self enabled --- python/tests/test_account.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/python/tests/test_account.py b/python/tests/test_account.py index 71c8322d3..31835b152 100644 --- a/python/tests/test_account.py +++ b/python/tests/test_account.py @@ -76,6 +76,20 @@ class TestOfflineAccountBasic: with pytest.raises(KeyError): ac1.get_config("123123") + def test_empty_group_bcc_self_enabled(self, acfactory): + ac1 = acfactory.get_configured_offline_account() + ac1.set_config("bcc_self", "1") + chat = ac1.create_group_chat(name="group1") + msg = chat.send_text("msg1") + assert msg in chat.get_messages() + + def test_empty_group_bcc_self_disabled(self, acfactory): + ac1 = acfactory.get_configured_offline_account() + ac1.set_config("bcc_self", "0") + chat = ac1.create_group_chat(name="group1") + msg = chat.send_text("msg1") + assert msg in chat.get_messages() + class TestOfflineContact: def test_contact_attr(self, acfactory): From 17ff1ab3729bdb1d0d9184bdbf0ecbfc21848dcd Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 23 Mar 2020 01:48:27 +0100 Subject: [PATCH 02/11] this corrects the To:-list for group-messages with only SELF as member. before, the list was empty and trying to send to groups that only contain SELF lead to a crash. in theory, this happens for both, bcc_self enabled or not, however, if bcc_self was disabled (default setting), things worked as the whole mimerendering was skipped on a higher level. also, the saved-messages-chat was not affected as this was checked explicitly. this pr changes the mimerendering so that From: is used as To: if there is no recipient-list and the messasge will be sent to SELF only. --- src/mimefactory.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/mimefactory.rs b/src/mimefactory.rs index 2c6a56842..4e957c58c 100644 --- a/src/mimefactory.rs +++ b/src/mimefactory.rs @@ -368,7 +368,7 @@ impl<'a, 'b> MimeFactory<'a, 'b> { self.from_addr.clone(), ); - let mut to = Vec::with_capacity(self.recipients.len()); + let mut to = Vec::new(); for (name, addr) in self.recipients.iter() { if name.is_empty() { to.push(Address::new_mailbox(addr.clone())); @@ -380,6 +380,10 @@ impl<'a, 'b> MimeFactory<'a, 'b> { } } + if to.is_empty() { + to.push(from.clone()); + } + if !self.references.is_empty() { unprotected_headers.push(Header::new("References".into(), self.references.clone())); } From 9c06acff72fde40ee3b1747477b8f4bf923ae323 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 24 Mar 2020 00:58:56 +0100 Subject: [PATCH 03/11] add tests wrt classic email-interaction --- src/dc_receive_imf.rs | 135 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 1 deletion(-) diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index f4ec776f2..7e55acbb4 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -1625,8 +1625,9 @@ fn dc_create_incoming_rfc724_mid( #[cfg(test)] mod tests { use super::*; + use crate::chatlist::Chatlist; use crate::message::Message; - use crate::test_utils::dummy_context; + use crate::test_utils::{dummy_context, TestContext}; #[test] fn test_hex_hash() { @@ -1719,4 +1720,136 @@ mod tests { assert!(is_msgrmsg_rfc724_mid(&t.ctx, &msg.rfc724_mid)); assert!(!is_msgrmsg_rfc724_mid(&t.ctx, "nonexistant@message.id")); } + + fn configured_offline_context() -> TestContext { + let t = dummy_context(); + t.ctx + .set_config(Config::Addr, Some("alice@example.org")) + .unwrap(); + t.ctx + .set_config(Config::ConfiguredAddr, Some("alice@example.org")) + .unwrap(); + t.ctx.set_config(Config::Configured, Some("1")).unwrap(); + t + } + + static MSGRMSG: &[u8] = b"From: Bob \n\ + To: alice@example.org\n\ + Chat-Version: 1.0\n\ + Subject: Chat: hello\n\ + Message-ID: \n\ + Date: Sun, 22 Mar 2020 22:37:55 +0000\n\ + \n\ + hello\n"; + + static ONETOONE_NOREPLY_MAIL: &[u8] = b"From: Bob \n\ + To: alice@example.org\n\ + Subject: Chat: hello\n\ + Message-ID: <2222@example.org>\n\ + Date: Sun, 22 Mar 2020 22:37:56 +0000\n\ + \n\ + hello\n"; + + static GRP_MAIL: &[u8] = b"From: bob@example.org\n\ + To: alice@example.org, claire@example.org\n\ + Subject: group with Alice, Bob and Claire\n\ + Message-ID: <3333@example.org>\n\ + Date: Sun, 22 Mar 2020 22:37:57 +0000\n\ + \n\ + hello\n"; + + #[test] + fn test_adhoc_group_show_chats_only() { + let t = configured_offline_context(); + assert_eq!(t.ctx.get_config_int(Config::ShowEmails), 0); + + let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap(); + assert_eq!(chats.len(), 0); + + dc_receive_imf(&t.ctx, MSGRMSG, "INBOX", 1, false).unwrap(); + let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap(); + assert_eq!(chats.len(), 1); + + dc_receive_imf(&t.ctx, ONETOONE_NOREPLY_MAIL, "INBOX", 1, false).unwrap(); + let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap(); + assert_eq!(chats.len(), 1); + + dc_receive_imf(&t.ctx, GRP_MAIL, "INBOX", 1, false).unwrap(); + let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap(); + assert_eq!(chats.len(), 1); + } + + #[test] + fn test_adhoc_group_show_accepted_contact_unknown() { + let t = configured_offline_context(); + t.ctx.set_config(Config::ShowEmails, Some("1")).unwrap(); + dc_receive_imf(&t.ctx, GRP_MAIL, "INBOX", 1, false).unwrap(); + + // adhoc-group with unknown contacts with show_emails=accepted is ignored for unknown contacts + let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap(); + assert_eq!(chats.len(), 0); + } + + #[test] + fn test_adhoc_group_show_accepted_contact_known() { + let t = configured_offline_context(); + t.ctx.set_config(Config::ShowEmails, Some("1")).unwrap(); + Contact::create(&t.ctx, "Bob", "bob@example.org").unwrap(); + dc_receive_imf(&t.ctx, GRP_MAIL, "INBOX", 1, false).unwrap(); + + // adhoc-group with known contacts with show_emails=accepted is still ignored for known contacts + // (and existent chat is required) + let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap(); + assert_eq!(chats.len(), 0); + } + + #[test] + fn test_adhoc_group_show_accepted_contact_accepted() { + let t = configured_offline_context(); + t.ctx.set_config(Config::ShowEmails, Some("1")).unwrap(); + + // accept Bob by accepting a delta-message from Bob + dc_receive_imf(&t.ctx, MSGRMSG, "INBOX", 1, false).unwrap(); + let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap(); + assert_eq!(chats.len(), 1); + assert!(chats.get_chat_id(0).is_deaddrop()); + let chat_id = chat::create_by_msg_id(&t.ctx, chats.get_msg_id(0).unwrap()).unwrap(); + assert!(!chat_id.is_special()); + let chat = chat::Chat::load_from_db(&t.ctx, chat_id).unwrap(); + assert_eq!(chat.typ, Chattype::Single); + assert_eq!(chat.name, "Bob"); + assert_eq!(chat::get_chat_contacts(&t.ctx, chat_id).len(), 1); + assert_eq!(chat::get_chat_msgs(&t.ctx, chat_id, 0, None).len(), 1); + + // receive a non-delta-message from Bob, shows up because of the show_emails setting + dc_receive_imf(&t.ctx, ONETOONE_NOREPLY_MAIL, "INBOX", 2, false).unwrap(); + assert_eq!(chat::get_chat_msgs(&t.ctx, chat_id, 0, None).len(), 2); + + // let Bob create an adhoc-group by a non-delta-message, shows up because of the show_emails setting + dc_receive_imf(&t.ctx, GRP_MAIL, "INBOX", 3, false).unwrap(); + let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap(); + assert_eq!(chats.len(), 2); + let chat_id = chat::create_by_msg_id(&t.ctx, chats.get_msg_id(0).unwrap()).unwrap(); + let chat = chat::Chat::load_from_db(&t.ctx, chat_id).unwrap(); + assert_eq!(chat.typ, Chattype::Group); + assert_eq!(chat.name, "group with Alice, Bob and Claire"); + assert_eq!(chat::get_chat_contacts(&t.ctx, chat_id).len(), 3); + } + + #[test] + fn test_adhoc_group_show_all() { + let t = configured_offline_context(); + t.ctx.set_config(Config::ShowEmails, Some("2")).unwrap(); + dc_receive_imf(&t.ctx, GRP_MAIL, "INBOX", 1, false).unwrap(); + + // adhoc-group with unknown contacts with show_emails=all will show up in the deaddrop + let chats = Chatlist::try_load(&t.ctx, 0, None, None).unwrap(); + assert_eq!(chats.len(), 1); + assert!(chats.get_chat_id(0).is_deaddrop()); + let chat_id = chat::create_by_msg_id(&t.ctx, chats.get_msg_id(0).unwrap()).unwrap(); + let chat = chat::Chat::load_from_db(&t.ctx, chat_id).unwrap(); + assert_eq!(chat.typ, Chattype::Group); + assert_eq!(chat.name, "group with Alice, Bob and Claire"); + assert_eq!(chat::get_chat_contacts(&t.ctx, chat_id).len(), 3); + } } From 785973c624bfe8a18dd68e8252bc0f2b89fab67d Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 24 Mar 2020 16:31:36 +0100 Subject: [PATCH 04/11] allow ad-hoc-group creation if there is an accepted chat with the contact --- src/dc_receive_imf.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/dc_receive_imf.rs b/src/dc_receive_imf.rs index 7e55acbb4..6d7ffa78b 100644 --- a/src/dc_receive_imf.rs +++ b/src/dc_receive_imf.rs @@ -389,7 +389,11 @@ fn add_parts( let (new_chat_id, new_chat_id_blocked) = create_or_lookup_group( context, &mut mime_parser, - allow_creation, + if test_normal_chat_id.is_unset() { + allow_creation + } else { + true + }, create_blocked, from_id, to_ids, From f28f177c6b8c49c4b215650c375001c0985b8e65 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 24 Mar 2020 19:18:18 +0100 Subject: [PATCH 05/11] use constant for folders_configured cache --- src/constants.rs | 3 +++ src/imap/mod.rs | 12 ++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index 45ebe1375..50345caa1 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -214,6 +214,9 @@ pub const DC_BOB_SUCCESS: i32 = 1; // max. width/height of an avatar pub const AVATAR_SIZE: u32 = 192; +// this value can be increased if the folder configuration is changed and must be redone on next program start +pub const DC_FOLDERS_CONFIGURED_VERSION: i32 = 3; + #[derive( Debug, Display, diff --git a/src/imap/mod.rs b/src/imap/mod.rs index 834120e0e..d073e41cd 100644 --- a/src/imap/mod.rs +++ b/src/imap/mod.rs @@ -1074,9 +1074,7 @@ impl Imap { let folders_configured = context .sql .get_raw_config_int(context, "folders_configured"); - if folders_configured.unwrap_or_default() >= 3 { - // the "3" here we increase if we have future updates to - // to folder configuration + if folders_configured.unwrap_or_default() >= DC_FOLDERS_CONFIGURED_VERSION { return Ok(()); } @@ -1168,9 +1166,11 @@ impl Imap { Some(sentbox_folder.name()), )?; } - context - .sql - .set_raw_config_int(context, "folders_configured", 3)?; + context.sql.set_raw_config_int( + context, + "folders_configured", + DC_FOLDERS_CONFIGURED_VERSION, + )?; } info!(context, "FINISHED configuring IMAP-folders."); Ok(()) From 36e7090466a57ec1ebf4cbfbe08663b5468f7371 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Tue, 24 Mar 2020 19:37:41 +0100 Subject: [PATCH 06/11] force folder-reconfigure on dc_configure() --- src/configure/mod.rs | 2 +- src/imap/mod.rs | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/configure/mod.rs b/src/configure/mod.rs index c5240e551..74ade9595 100644 --- a/src/configure/mod.rs +++ b/src/configure/mod.rs @@ -371,7 +371,7 @@ pub(crate) fn JobConfigureImap(context: &Context) -> job::Status { let create_mvbox = context.get_config_bool(Config::MvboxWatch) || context.get_config_bool(Config::MvboxMove); let imap = &context.inbox_thread.read().unwrap().imap; - if let Err(err) = imap.ensure_configured_folders(context, create_mvbox) { + if let Err(err) = imap.configure_folders(context, create_mvbox) { warn!(context, "configuring folders failed: {:?}", err); false } else { diff --git a/src/imap/mod.rs b/src/imap/mod.rs index d073e41cd..43f2395e5 100644 --- a/src/imap/mod.rs +++ b/src/imap/mod.rs @@ -1078,6 +1078,10 @@ impl Imap { return Ok(()); } + self.configure_folders(context, create_mvbox) + } + + pub fn configure_folders(&self, context: &Context, create_mvbox: bool) -> Result<()> { task::block_on(async move { if !self.is_connected().await { return Err(Error::NoConnection); From e135c969c94f07c65ae3f4ad5fc1c0fc12b1f272 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 25 Mar 2020 13:16:23 +0100 Subject: [PATCH 07/11] figure out and use folder-delimiter provided by LIST command --- src/imap/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/imap/mod.rs b/src/imap/mod.rs index 43f2395e5..b1dfa97ee 100644 --- a/src/imap/mod.rs +++ b/src/imap/mod.rs @@ -1106,7 +1106,15 @@ impl Imap { }); info!(context, "sentbox folder is {:?}", sentbox_folder); - let delimiter = self.config.read().await.imap_delimiter; + let mut delimiter = "."; + if !folders.is_empty() { + if let Some(d) = &folders[0].delimiter() { + if !d.is_empty() { + delimiter = d; + } + } + } + info!(context, "Using \"{}\" as folder-delimiter.", delimiter); let fallback_folder = format!("INBOX{}DeltaChat", delimiter); let mut mvbox_folder = folders From ab8d75b1924000b9c6637aea5cb3e2f4d9ba9e55 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 25 Mar 2020 13:23:29 +0100 Subject: [PATCH 08/11] remove now unused ImapConfig.imap_delimiter --- src/imap/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/imap/mod.rs b/src/imap/mod.rs index b1dfa97ee..548360f3a 100644 --- a/src/imap/mod.rs +++ b/src/imap/mod.rs @@ -188,7 +188,6 @@ struct ImapConfig { /// True if the server has MOVE capability as defined in /// https://tools.ietf.org/html/rfc6851 pub can_move: bool, - pub imap_delimiter: char, } impl Default for ImapConfig { @@ -206,7 +205,6 @@ impl Default for ImapConfig { selected_folder_needs_expunge: false, can_idle: false, can_move: false, - imap_delimiter: '.', } } } From e09a0a548f059df0b5713c70de0690aeeb51090b Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 25 Mar 2020 18:10:02 +0100 Subject: [PATCH 09/11] using first() instead of [0] --- src/imap/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/imap/mod.rs b/src/imap/mod.rs index 548360f3a..7f1eaaf0e 100644 --- a/src/imap/mod.rs +++ b/src/imap/mod.rs @@ -1105,8 +1105,8 @@ impl Imap { info!(context, "sentbox folder is {:?}", sentbox_folder); let mut delimiter = "."; - if !folders.is_empty() { - if let Some(d) = &folders[0].delimiter() { + if let Some(folder) = folders.first() { + if let Some(d) = folder.delimiter() { if !d.is_empty() { delimiter = d; } From edc5754c682a560eefe4786a940e43de879c45de Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 25 Mar 2020 19:29:44 +0100 Subject: [PATCH 10/11] changelog --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 899d017a3..cecfd6723 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,19 @@ # Changelog +## 1.28.0 + +- new flag DC_GCL_FOR_FORWARDING for dc_get_chatlist() + that will sort the "saved messages" chat to the top of the chatlist #1336 +- mark mails as being deleted from server in dc_empty_server() #1333 +- fix interaction with servers that do not allow folder creation on root-level; + use path separator as defined by the email server #1359 +- fix group creation if group was created by non-delta clients #1357 +- fix showing replies from non-delta clients #1353 +- fix member list on rejoining left groups #1343 +- fix crash when using empty groups #1354 +- fix potential crash on special names #1350 + + ## 1.27.0 - handle keys reliably on armv7 #1327 From fd3e6e0ee499f735155d118af9457cf62a8120d6 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 25 Mar 2020 19:30:52 +0100 Subject: [PATCH 11/11] bump version to 1.28 --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- deltachat-ffi/Cargo.toml | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 80c6478ae..1ae331de3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -624,7 +624,7 @@ dependencies = [ [[package]] name = "deltachat" -version = "1.27.0" +version = "1.28.0" dependencies = [ "async-imap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "async-native-tls 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -690,9 +690,9 @@ dependencies = [ [[package]] name = "deltachat_ffi" -version = "1.27.0" +version = "1.28.0" dependencies = [ - "deltachat 1.27.0", + "deltachat 1.28.0", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "human-panic 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 55ac0054a..d54e42468 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat" -version = "1.27.0" +version = "1.28.0" authors = ["Delta Chat Developers (ML) "] edition = "2018" license = "MPL-2.0" diff --git a/deltachat-ffi/Cargo.toml b/deltachat-ffi/Cargo.toml index 2f37da72d..8901dffec 100644 --- a/deltachat-ffi/Cargo.toml +++ b/deltachat-ffi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat_ffi" -version = "1.27.0" +version = "1.28.0" description = "Deltachat FFI" authors = ["Delta Chat Developers (ML) "] edition = "2018"