From a4a570896a9e4b61cf8e48794df5d1fdeff2f109 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 1 May 2020 15:47:43 +0200 Subject: [PATCH 01/21] add config_defaults array to provider-db --- src/provider/mod.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/provider/mod.rs b/src/provider/mod.rs index 7f7174774..fc414968f 100644 --- a/src/provider/mod.rs +++ b/src/provider/mod.rs @@ -2,6 +2,7 @@ mod data; +use crate::config::Config; use crate::dc_tools::EmailAddress; use crate::provider::data::PROVIDER_DATA; @@ -57,6 +58,12 @@ impl Server { } } +#[derive(Debug)] +pub struct ConfigDefault { + pub key: Config, + pub value: &'static str, +} + #[derive(Debug)] pub struct Provider { pub status: Status, @@ -64,6 +71,7 @@ pub struct Provider { pub after_login_hint: &'static str, pub overview_page: &'static str, pub server: Vec, + pub config_defaults: Option>, } impl Provider { From c1890bb126e70654d7419aa8ca649c4e42072f77 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 1 May 2020 15:48:28 +0200 Subject: [PATCH 02/21] adapt provider/update.py so that it generates config_defaults --- src/provider/update.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/provider/update.py b/src/provider/update.py index f0a19db76..88d464d47 100755 --- a/src/provider/update.py +++ b/src/provider/update.py @@ -9,6 +9,9 @@ out_all = "" out_domains = "" domains_dict = {} +def camel(name): + words = name.split("_") + return "".join(w.capitalize() for i, w in enumerate(words)) def cleanstr(s): s = s.strip() @@ -31,6 +34,18 @@ def file2url(f): return "https://providers.delta.chat/" + f +def process_config_defaults(data): + if not "config_defaults" in data: + return "None" + defaults = "Some(vec![\n" + config_defaults = data.get("config_defaults", "") + for key in config_defaults: + value = str(config_defaults[key]) + defaults += " ConfigDefault { key: Config::" + camel(key) + ", value: \"" + value + "\" },\n" + defaults += " ])" + return defaults + + def process_data(data, file): status = data.get("status", "") if status != "OK" and status != "PREPARATION" and status != "BROKEN": @@ -83,6 +98,8 @@ def process_data(data, file): server += (" Server { protocol: " + protocol + ", socket: " + socket + ", hostname: \"" + hostname + "\", port: " + str(port) + ", username_pattern: " + username_pattern + " },\n") + config_defaults = process_config_defaults(data) + provider = "" before_login_hint = cleanstr(data.get("before_login_hint", "")) after_login_hint = cleanstr(data.get("after_login_hint", "")) @@ -93,6 +110,7 @@ def process_data(data, file): provider += " after_login_hint: \"" + after_login_hint + "\",\n" provider += " overview_page: \"" + file2url(file) + "\",\n" provider += " server: vec![\n" + server + " ],\n" + provider += " config_defaults: " + config_defaults + ",\n" provider += " };\n\n" else: raise TypeError("SMTP and IMAP must be specified together or left out both") From 24bf1dbffb42727acf5aa71f110671acc9daecd3 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 6 May 2020 12:42:39 +0200 Subject: [PATCH 03/21] fixup --- src/provider/update.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/provider/update.py b/src/provider/update.py index 88d464d47..eb0a9e02b 100755 --- a/src/provider/update.py +++ b/src/provider/update.py @@ -121,7 +121,7 @@ def process_data(data, file): # finally, add the provider global out_all, out_domains out_all += " // " + file[file.rindex("/")+1:] + ": " + comment.strip(", ") + "\n" - if status == "OK" and before_login_hint == "" and after_login_hint == "" and server == "": + if status == "OK" and before_login_hint == "" and after_login_hint == "" and server == "" and config_defaults == "None": out_all += " // - skipping provider with status OK and no special things to do\n\n" else: out_all += provider From 8d7d2f7a4451e1d7522a7220095b1823012d2799 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 1 May 2020 15:49:54 +0200 Subject: [PATCH 04/21] run provider/update.py --- src/provider/data.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/provider/data.rs b/src/provider/data.rs index a33c77ca5..ccca6be49 100644 --- a/src/provider/data.rs +++ b/src/provider/data.rs @@ -18,6 +18,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: STARTTLS, hostname: "newyear.aktivix.org", port: 143, username_pattern: EMAIL }, Server { protocol: SMTP, socket: STARTTLS, hostname: "newyear.aktivix.org", port: 25, username_pattern: EMAIL }, ], + config_defaults: None, }; // aol.md: aol.com @@ -28,6 +29,7 @@ lazy_static::lazy_static! { overview_page: "https://providers.delta.chat/aol", server: vec![ ], + config_defaults: None, }; // autistici.org.md: autistici.org @@ -40,6 +42,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: SSL, hostname: "mail.autistici.org", port: 993, username_pattern: EMAIL }, Server { protocol: SMTP, socket: SSL, hostname: "smtp.autistici.org", port: 465, username_pattern: EMAIL }, ], + config_defaults: None, }; // bluewin.ch.md: bluewin.ch @@ -52,6 +55,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: SSL, hostname: "imaps.bluewin.ch", port: 993, username_pattern: EMAIL }, Server { protocol: SMTP, socket: SSL, hostname: "smtpauths.bluewin.ch", port: 465, username_pattern: EMAIL }, ], + config_defaults: None, }; // comcast.md: xfinity.com, comcast.net @@ -73,6 +77,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: SSL, hostname: "imap.example.com", port: 1337, username_pattern: EMAIL }, Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp.example.com", port: 1337, username_pattern: EMAIL }, ], + config_defaults: None, }; // fastmail.md: fastmail.com @@ -83,6 +88,7 @@ lazy_static::lazy_static! { overview_page: "https://providers.delta.chat/fastmail", server: vec![ ], + config_defaults: None, }; // freenet.de.md: freenet.de @@ -95,6 +101,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: SSL, hostname: "mx.freenet.de", port: 993, username_pattern: EMAIL }, Server { protocol: SMTP, socket: STARTTLS, hostname: "mx.freenet.de", port: 587, username_pattern: EMAIL }, ], + config_defaults: None, }; // gmail.md: gmail.com, googlemail.com @@ -107,6 +114,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: SSL, hostname: "imap.gmail.com", port: 993, username_pattern: EMAIL }, Server { protocol: SMTP, socket: SSL, hostname: "smtp.gmail.com", port: 465, username_pattern: EMAIL }, ], + config_defaults: None, }; // gmx.net.md: gmx.net, gmx.de, gmx.at, gmx.ch, gmx.org, gmx.eu, gmx.info, gmx.biz, gmx.com @@ -120,6 +128,7 @@ lazy_static::lazy_static! { Server { protocol: SMTP, socket: SSL, hostname: "mail.gmx.net", port: 465, username_pattern: EMAIL }, Server { protocol: SMTP, socket: STARTTLS, hostname: "mail.gmx.net", port: 587, username_pattern: EMAIL }, ], + config_defaults: None, }; // i.ua.md: i.ua @@ -135,6 +144,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: SSL, hostname: "imap.mail.me.com", port: 993, username_pattern: EMAILLOCALPART }, Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp.mail.me.com", port: 587, username_pattern: EMAIL }, ], + config_defaults: None, }; // kolst.com.md: kolst.com @@ -159,6 +169,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: STARTTLS, hostname: "imap.nauta.cu", port: 143, username_pattern: EMAIL }, Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp.nauta.cu", port: 25, username_pattern: EMAIL }, ], + config_defaults: None, }; // outlook.com.md: hotmail.com, outlook.com, office365.com, outlook.com.tr, live.com @@ -171,6 +182,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: SSL, hostname: "imap-mail.outlook.com", port: 993, username_pattern: EMAIL }, Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp-mail.outlook.com", port: 587, username_pattern: EMAIL }, ], + config_defaults: None, }; // posteo.md: posteo.de @@ -183,6 +195,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: STARTTLS, hostname: "posteo.de", port: 143, username_pattern: EMAIL }, Server { protocol: SMTP, socket: STARTTLS, hostname: "posteo.de", port: 587, username_pattern: EMAIL }, ], + config_defaults: None, }; // protonmail.md: protonmail.com, protonmail.ch @@ -193,6 +206,7 @@ lazy_static::lazy_static! { overview_page: "https://providers.delta.chat/protonmail", server: vec![ ], + config_defaults: None, }; // riseup.net.md: riseup.net @@ -209,6 +223,7 @@ lazy_static::lazy_static! { overview_page: "https://providers.delta.chat/t-online", server: vec![ ], + config_defaults: None, }; // testrun.md: testrun.org @@ -222,6 +237,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: STARTTLS, hostname: "testrun.org", port: 143, username_pattern: EMAIL }, Server { protocol: SMTP, socket: STARTTLS, hostname: "testrun.org", port: 587, username_pattern: EMAIL }, ], + config_defaults: None, }; // tiscali.it.md: tiscali.it @@ -234,6 +250,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: SSL, hostname: "imap.tiscali.it", port: 993, username_pattern: EMAIL }, Server { protocol: SMTP, socket: SSL, hostname: "smtp.tiscali.it", port: 465, username_pattern: EMAIL }, ], + config_defaults: None, }; // ukr.net.md: ukr.net @@ -253,6 +270,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: STARTTLS, hostname: "imap.web.de", port: 143, username_pattern: EMAILLOCALPART }, Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp.web.de", port: 587, username_pattern: EMAILLOCALPART }, ], + config_defaults: None, }; // yahoo.md: yahoo.com, yahoo.de, yahoo.it, yahoo.fr, yahoo.es, yahoo.se, yahoo.co.uk, yahoo.co.nz, yahoo.com.au, yahoo.com.ar, yahoo.com.br, yahoo.com.mx, ymail.com, rocketmail.com, yahoodns.net @@ -265,6 +283,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: SSL, hostname: "imap.mail.yahoo.com", port: 993, username_pattern: EMAIL }, Server { protocol: SMTP, socket: SSL, hostname: "smtp.mail.yahoo.com", port: 465, username_pattern: EMAIL }, ], + config_defaults: None, }; // yandex.ru.md: yandex.ru, yandex.com @@ -275,6 +294,7 @@ lazy_static::lazy_static! { overview_page: "https://providers.delta.chat/yandex-ru", server: vec![ ], + config_defaults: None, }; // ziggo.nl.md: ziggo.nl @@ -287,6 +307,7 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: SSL, hostname: "imap.ziggo.nl", port: 993, username_pattern: EMAIL }, Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp.ziggo.nl", port: 587, username_pattern: EMAIL }, ], + config_defaults: None, }; pub static ref PROVIDER_DATA: HashMap<&'static str, &'static Provider> = [ From 4b744337fe5f5c603ab7aa9a41fa3e8a266670fc Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 1 May 2020 16:37:45 +0200 Subject: [PATCH 05/21] apply user_defaults after the first successful call to dc_configure() --- src/configure/mod.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/configure/mod.rs b/src/configure/mod.rs index ab0e70aeb..49ec6e299 100644 --- a/src/configure/mod.rs +++ b/src/configure/mod.rs @@ -69,6 +69,7 @@ pub(crate) fn JobConfigureImap(context: &Context) -> job::Status { let mut smtp_connected_here = false; let mut param_autoconfig: Option = None; + let was_configured_before = context.is_configured(); context .inbox_thread @@ -441,6 +442,15 @@ pub(crate) fn JobConfigureImap(context: &Context) -> job::Status { } if let Some(provider) = provider::get_provider_info(¶m.addr) { + if !was_configured_before { + if let Some(config_defaults) = &provider.config_defaults { + for def in config_defaults.iter() { + info!(context, "apply config_defaults {}={}", def.key, def.value); + context.set_config(def.key, Some(def.value)); + } + } + } + if !provider.after_login_hint.is_empty() { let mut msg = Message::new(Viewtype::Text); msg.text = Some(provider.after_login_hint.to_string()); From 8bd0a62cb3404cf84c921b444919b23f937e2fc1 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 13 May 2020 22:45:01 +0200 Subject: [PATCH 06/21] changelog --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 80560f305..60080f527 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## 1.33.0 + +- let `dc_set_muted()` also mute one-to-one chats #1470 + +- fix a but that led to load and traffic if the server does not use sent-folder + #1472 + + ## 1.32.0 - fix endless loop when trying to download messages with bad RFC Message-ID, From 7dc58bb3305e58a73db499ec8c7009a05c654e28 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Wed, 13 May 2020 22:46:04 +0200 Subject: [PATCH 07/21] bump version --- 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 4b1e1589d..2430a2cec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -629,7 +629,7 @@ dependencies = [ [[package]] name = "deltachat" -version = "1.32.0" +version = "1.33.0" dependencies = [ "anyhow 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "async-imap 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -695,10 +695,10 @@ dependencies = [ [[package]] name = "deltachat_ffi" -version = "1.32.0" +version = "1.33.0" dependencies = [ "anyhow 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "deltachat 1.32.0", + "deltachat 1.33.0", "human-panic 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index cffcfad77..683fd39ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat" -version = "1.32.0" +version = "1.33.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 ad4bf5df0..46233a86b 100644 --- a/deltachat-ffi/Cargo.toml +++ b/deltachat-ffi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat_ffi" -version = "1.32.0" +version = "1.33.0" description = "Deltachat FFI" authors = ["Delta Chat Developers (ML) "] edition = "2018" From a128e7e7ab0bf1aefff72f21036fecc5b48cfc6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asiel=20D=C3=ADaz=20Ben=C3=ADtez?= Date: Thu, 14 May 2020 03:22:45 -0400 Subject: [PATCH 08/21] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 60080f527..fcb485f98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ - let `dc_set_muted()` also mute one-to-one chats #1470 -- fix a but that led to load and traffic if the server does not use sent-folder +- fix a bug that led to load and traffic if the server does not use sent-folder #1472 From 6658ad8618a820765fe278ffdea1625ece5c0ea3 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 15 May 2020 17:06:15 +0200 Subject: [PATCH 09/21] clarify delete_server_after option --- deltachat-ffi/deltachat.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 53e202fa3..338648311 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -380,7 +380,8 @@ char* dc_get_blobdir (const dc_context_t* context); * Messages are deleted whether they were seen or not, the UI should clearly point that out. * See also dc_estimate_deletion_cnt(). * - `delete_server_after` = 0=do not delete messages from server automatically (default), - * >=1=seconds, after which messages are deleted automatically from the server. + * 1=delete messages directly after receiving from server, mvbox is skipped. + * >1=seconds, after which messages are deleted automatically from the server, mvbox is used as defined. * "Saved messages" are deleted from the server as well as * emails matching the `show_emails` settings above, the UI should clearly point that out. * See also dc_estimate_deletion_cnt(). From 3e2bfc35e3e4ea26c450c6a7771918703788f7eb Mon Sep 17 00:00:00 2001 From: Alexander Krotov Date: Fri, 15 May 2020 03:53:35 +0300 Subject: [PATCH 10/21] Delete hidden expired messages The condition remains from the time when expired messages were hidden instead of being moved into trash chat. As a result, old hidden messages, such as location messages, were not deleted. --- src/chat.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/chat.rs b/src/chat.rs index c9a65538c..5c409dbbe 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1612,8 +1612,7 @@ pub fn delete_device_expired_messages(context: &Context) -> Result WHERE timestamp < ? \ AND chat_id > ? \ AND chat_id != ? \ - AND chat_id != ? \ - AND NOT hidden", + AND chat_id != ?", params![ DC_CHAT_ID_TRASH, threshold_timestamp, From 598dc86ca57f18a74c1c1329248d195a2cb5d247 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Fri, 15 May 2020 12:38:00 +0200 Subject: [PATCH 11/21] make sure we don't garble output during test runs by more carefully switching logging on/off globally --- python/src/deltachat/account.py | 14 +++++- python/src/deltachat/testplugin.py | 74 ++++++++++++++++++++++++++---- 2 files changed, 78 insertions(+), 10 deletions(-) diff --git a/python/src/deltachat/account.py b/python/src/deltachat/account.py index ef2b70c83..d1b4ac519 100644 --- a/python/src/deltachat/account.py +++ b/python/src/deltachat/account.py @@ -30,7 +30,7 @@ class Account(object): """ MissingCredentials = MissingCredentials - def __init__(self, db_path, os_name=None): + def __init__(self, db_path, os_name=None, logging=True): """ initialize account object. :param db_path: a path to the account database. The database @@ -39,6 +39,7 @@ class Account(object): """ # initialize per-account plugin system self._pm = hookspec.PerAccount._make_plugin_manager() + self._logging = logging self.add_account_plugin(self) self._dc_context = ffi.gc( @@ -63,6 +64,14 @@ class Account(object): atexit.register(self.shutdown) hook.dc_account_init(account=self) + def disable_logging(self): + """ disable logging. """ + self._logging = False + + def enable_logging(self): + """ re-enable logging. """ + self._logging = True + @hookspec.account_hookimpl def ac_process_ffi_event(self, ffi_event): for name, kwargs in self._map_ffi_event(ffi_event): @@ -73,7 +82,8 @@ class Account(object): # self.shutdown() def ac_log_line(self, msg): - self._pm.hook.ac_log_line(message=msg) + if self._logging: + self._pm.hook.ac_log_line(message=msg) def _check_config_key(self, name): if name not in self._configkeys: diff --git a/python/src/deltachat/testplugin.py b/python/src/deltachat/testplugin.py index f336ac058..7208e8280 100644 --- a/python/src/deltachat/testplugin.py +++ b/python/src/deltachat/testplugin.py @@ -5,9 +5,13 @@ import subprocess import queue import threading import fnmatch +import time +import weakref +import tempfile + import pytest import requests -import time + from . import Account, const from .tracker import ConfigureTracker from .capi import lib @@ -15,7 +19,7 @@ from .eventlogger import FFIEventLogger, FFIEventTracker from _pytest.monkeypatch import MonkeyPatch from _pytest._code import Source -import tempfile +import deltachat def pytest_addoption(parser): @@ -40,11 +44,55 @@ def pytest_configure(config): if cfg: config.option.liveconfig = cfg + # Make sure we don't get garbled output because threads keep running + # collect all ever created accounts in a weakref-set (so we don't + # keep objects unneccessarily alive) and enable/disable logging + # for each pytest test phase # (setup/call/teardown). + # Additionally make the acfactory use a logging/no-logging default. -def pytest_runtest_setup(item): - if (list(item.iter_markers(name="ignored")) - and not item.config.getoption("ignored")): - pytest.skip("Ignored tests not requested, use --ignored") + class LoggingAspect: + def __init__(self): + self._accounts = weakref.WeakSet() + + @deltachat.global_hookimpl + def dc_account_init(self, account): + self._accounts.add(account) + + def disable_logging(self, item): + for acc in self._accounts: + acc.disable_logging() + acfactory = item.funcargs.get("acfactory") + if acfactory: + acfactory.set_logging_default(False) + + def enable_logging(self, item): + for acc in self._accounts: + acc.enable_logging() + acfactory = item.funcargs.get("acfactory") + if acfactory: + acfactory.set_logging_default(True) + + @pytest.hookimpl(hookwrapper=True) + def pytest_runtest_setup(self, item): + self.enable_logging(item) + yield + self.disable_logging(item) + + @pytest.hookimpl(hookwrapper=True) + def pytest_pyfunc_call(self, pyfuncitem): + self.enable_logging(pyfuncitem) + yield + self.disable_logging(pyfuncitem) + + @pytest.hookimpl(hookwrapper=True) + def pytest_runtest_teardown(self, item): + self.enable_logging(item) + yield + self.disable_logging(item) + + la = LoggingAspect() + config.pluginmanager.register(la) + deltachat.register_global_plugin(la) def pytest_report_header(config, startdir): @@ -164,24 +212,34 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig, data): self.live_count = 0 self.offline_count = 0 self._finalizers = [] + self._accounts = [] self.init_time = time.time() self._generated_keys = ["alice", "bob", "charlie", "dom", "elena", "fiona"] + self.set_logging_default(False) def finalize(self): while self._finalizers: fin = self._finalizers.pop() fin() + while self._accounts: + acc = self._accounts.pop() + acc.shutdown() + acc.disable_logging() + def make_account(self, path, logid, quiet=False): - ac = Account(path) + ac = Account(path, logging=self._logging) ac._evtracker = ac.add_account_plugin(FFIEventTracker(ac)) ac._configtracker = ac.add_account_plugin(ConfigureTracker()) if not quiet: ac.add_account_plugin(FFIEventLogger(ac, logid=logid)) - self._finalizers.append(ac.shutdown) + self._accounts.append(ac) return ac + def set_logging_default(self, logging): + self._logging = bool(logging) + def get_unconfigured_account(self): self.offline_count += 1 tmpdb = tmpdir.join("offlinedb%d" % self.offline_count) From fc6691ce5b2bb34484e73e9cd3329b6de3b61c49 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 15 May 2020 23:05:23 +0200 Subject: [PATCH 12/21] add 'sentmail' to the list of known names for 'sent', acutally used by chello.at --- src/imap/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/imap/mod.rs b/src/imap/mod.rs index 1e19c7844..0e21a550d 100644 --- a/src/imap/mod.rs +++ b/src/imap/mod.rs @@ -1235,7 +1235,7 @@ impl Imap { // CAVE: if possible, take care not to add a name here that is "sent" in one language // but sth. different in others - a hard job. fn get_folder_meaning_by_name(folder_name: &Name) -> FolderMeaning { - let sent_names = vec!["sent", "sent objects", "gesendet"]; + let sent_names = vec!["sent", "sentmail", "sent objects", "gesendet"]; let lower = folder_name.name().to_lowercase(); if sent_names.into_iter().any(|s| s == lower) { From 9e22bf39ccd44d91f2af9c9814922ebedb450255 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 15 May 2020 23:09:55 +0200 Subject: [PATCH 13/21] smoother searching for sentbox search for the sentbox in two passes: - first check the folder attributes - only if that fails, check for some known names this way, the sent-attribute always has precedence over the name; this was not the case before. moreover, this fixes an possibly wrong early exist when the attribute list is completely empty. --- src/imap/mod.rs | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/imap/mod.rs b/src/imap/mod.rs index 0e21a550d..498f1813a 100644 --- a/src/imap/mod.rs +++ b/src/imap/mod.rs @@ -1063,13 +1063,21 @@ impl Imap { } }; - let sentbox_folder = - folders - .iter() - .find(|folder| match get_folder_meaning(folder) { - FolderMeaning::SentObjects => true, - _ => false, - }); + let sentbox_folder = folders + .iter() + .find(|folder| match get_folder_meaning(folder) { + FolderMeaning::SentObjects => true, + _ => false, + }) + .or_else(|| { + info!(context, "can't find sentbox by attributes, checking names"); + folders + .iter() + .find(|folder| match get_folder_meaning_by_name(folder) { + FolderMeaning::SentObjects => true, + _ => false, + }) + }); info!(context, "sentbox folder is {:?}", sentbox_folder); let mut delimiter = "."; @@ -1246,27 +1254,18 @@ fn get_folder_meaning_by_name(folder_name: &Name) -> FolderMeaning { } fn get_folder_meaning(folder_name: &Name) -> FolderMeaning { - if folder_name.attributes().is_empty() { - return FolderMeaning::Unknown; - } - - let mut res = FolderMeaning::Unknown; let special_names = vec!["\\Spam", "\\Trash", "\\Drafts", "\\Junk"]; for attr in folder_name.attributes() { if let NameAttribute::Custom(ref label) = attr { if special_names.iter().any(|s| *s == label) { - res = FolderMeaning::Other; + return FolderMeaning::Other; } else if label == "\\Sent" { - res = FolderMeaning::SentObjects + return FolderMeaning::SentObjects; } } } - - match res { - FolderMeaning::Unknown => get_folder_meaning_by_name(folder_name), - _ => res, - } + return FolderMeaning::Unknown; } fn precheck_imf( From eafb7b979d4a490f4116c8e409f96436165acbeb Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 16 May 2020 00:09:22 +0200 Subject: [PATCH 14/21] make clippy happy --- src/imap/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/imap/mod.rs b/src/imap/mod.rs index 498f1813a..58f6d221b 100644 --- a/src/imap/mod.rs +++ b/src/imap/mod.rs @@ -1265,7 +1265,7 @@ fn get_folder_meaning(folder_name: &Name) -> FolderMeaning { } } } - return FolderMeaning::Unknown; + FolderMeaning::Unknown } fn precheck_imf( From ab253744f8bb8f7683b9afe0d544971471204d9e Mon Sep 17 00:00:00 2001 From: Hocuri Date: Sat, 16 May 2020 15:07:01 +0200 Subject: [PATCH 15/21] Code style --- src/imap/mod.rs | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/imap/mod.rs b/src/imap/mod.rs index 58f6d221b..6286ae4ff 100644 --- a/src/imap/mod.rs +++ b/src/imap/mod.rs @@ -135,7 +135,7 @@ impl async_imap::Authenticator for OAuth2 { } } -#[derive(Debug)] +#[derive(Debug, PartialEq)] enum FolderMeaning { Unknown, SentObjects, @@ -1065,18 +1065,12 @@ impl Imap { let sentbox_folder = folders .iter() - .find(|folder| match get_folder_meaning(folder) { - FolderMeaning::SentObjects => true, - _ => false, - }) + .find(|folder| get_folder_meaning(folder) == FolderMeaning::SentObjects) .or_else(|| { info!(context, "can't find sentbox by attributes, checking names"); - folders - .iter() - .find(|folder| match get_folder_meaning_by_name(folder) { - FolderMeaning::SentObjects => true, - _ => false, - }) + folders.iter().find(|folder| { + get_folder_meaning_by_name(folder) == FolderMeaning::SentObjects + }) }); info!(context, "sentbox folder is {:?}", sentbox_folder); From df3fac4e5ed1d94c10c65b94f0551a12b2817c80 Mon Sep 17 00:00:00 2001 From: Hocuri Date: Sat, 16 May 2020 18:01:00 +0200 Subject: [PATCH 16/21] Make clear that dc_set_chat_mute_duration() and dc_chat_is_muted() belong together. --- deltachat-ffi/deltachat.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 338648311..c88aded79 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -1640,7 +1640,7 @@ int dc_set_chat_profile_image (dc_context_t* context, uint32_t ch /** * Set mute duration of a chat. * - * This value can be checked by the ui upon receiving a new message to decide whether it should trigger an notification. + * The ui can then call dc_chat_is_muted() when receiving a new message to decide whether it should trigger an notification. * * Sends out #DC_EVENT_CHAT_MODIFIED. * @@ -2978,7 +2978,7 @@ int dc_chat_is_sending_locations (const dc_chat_t* chat); /** - * Check whether the chat is currently muted + * Check whether the chat is currently muted (can be changed by dc_set_chat_mute_duration()). * * @memberof dc_chat_t * @param chat The chat object. From a0000b9489ea0e6a965d816437970c07981904b5 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Fri, 15 May 2020 21:53:29 +0200 Subject: [PATCH 17/21] update provider-db --- src/provider/data.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/provider/data.rs b/src/provider/data.rs index ccca6be49..3f5fbb058 100644 --- a/src/provider/data.rs +++ b/src/provider/data.rs @@ -169,7 +169,15 @@ lazy_static::lazy_static! { Server { protocol: IMAP, socket: STARTTLS, hostname: "imap.nauta.cu", port: 143, username_pattern: EMAIL }, Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp.nauta.cu", port: 25, username_pattern: EMAIL }, ], - config_defaults: None, + config_defaults: Some(vec![ + ConfigDefault { key: Config::DeleteServerAfter, value: "1" }, + ConfigDefault { key: Config::BccSelf, value: "0" }, + ConfigDefault { key: Config::SentboxWatch, value: "0" }, + ConfigDefault { key: Config::MvboxWatch, value: "0" }, + ConfigDefault { key: Config::MvboxMove, value: "0" }, + ConfigDefault { key: Config::E2eeEnabled, value: "0" }, + ConfigDefault { key: Config::MediaQuality, value: "1" }, + ]), }; // outlook.com.md: hotmail.com, outlook.com, office365.com, outlook.com.tr, live.com @@ -215,6 +223,9 @@ lazy_static::lazy_static! { // rogers.com.md: rogers.com // - skipping provider with status OK and no special things to do + // systemli.org.md: systemli.org + // - skipping provider with status OK and no special things to do + // t-online.md: t-online.de, magenta.de static ref P_T_ONLINE: Provider = Provider { status: Status::PREPARATION, From b864911e1846f80adef83075730edcdb3be835e1 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 16 May 2020 14:15:15 +0200 Subject: [PATCH 18/21] return current journal_mode in dc_get_info() values are either 'delete' or 'wal'; having this info in debug reports is useful for debugging anyway, if we switch to WAL or not. --- src/context.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/context.rs b/src/context.rs index 7f59241ab..5b1ea6ddf 100644 --- a/src/context.rs +++ b/src/context.rs @@ -240,7 +240,10 @@ impl Context { .sql .get_raw_config_int(self, "dbversion") .unwrap_or_default(); - + let journal_mode = self + .sql + .query_get_value(self, "PRAGMA journal_mode;", rusqlite::NO_PARAMS) + .unwrap_or("unknown".to_string()); let e2ee_enabled = self.get_config_int(Config::E2eeEnabled); let mdns_enabled = self.get_config_int(Config::MdnsEnabled); let bcc_self = self.get_config_int(Config::BccSelf); @@ -285,6 +288,7 @@ impl Context { res.insert("number_of_contacts", contacts.to_string()); res.insert("database_dir", self.get_dbfile().display().to_string()); res.insert("database_version", dbversion.to_string()); + res.insert("journal_mode", journal_mode); res.insert("blobdir", self.get_blobdir().display().to_string()); res.insert("display_name", displayname.unwrap_or_else(|| unset.into())); res.insert( From 3b2192a046808003bce8ed6466a6fe16ccb54031 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 16 May 2020 14:43:00 +0200 Subject: [PATCH 19/21] make clippy happy --- src/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context.rs b/src/context.rs index 5b1ea6ddf..5bf4647d0 100644 --- a/src/context.rs +++ b/src/context.rs @@ -243,7 +243,7 @@ impl Context { let journal_mode = self .sql .query_get_value(self, "PRAGMA journal_mode;", rusqlite::NO_PARAMS) - .unwrap_or("unknown".to_string()); + .unwrap_or_else(|| "unknown".to_string()); let e2ee_enabled = self.get_config_int(Config::E2eeEnabled); let mdns_enabled = self.get_config_int(Config::MdnsEnabled); let bcc_self = self.get_config_int(Config::BccSelf); From 970264704418e842eeae9175da0d379d8cc65941 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Sat, 16 May 2020 15:36:40 +0200 Subject: [PATCH 20/21] enable sqlite's WAL-mode unconditionally --- src/sql.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sql.rs b/src/sql.rs index a09380a8a..40de8200e 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -400,7 +400,7 @@ fn open( } let mgr = r2d2_sqlite::SqliteConnectionManager::file(dbfile.as_ref()) .with_flags(open_flags) - .with_init(|c| c.execute_batch("PRAGMA secure_delete=on;")); + .with_init(|c| c.execute_batch("PRAGMA journal_mode=WAL; PRAGMA secure_delete=on;")); let pool = r2d2::Pool::builder() .min_idle(Some(2)) .max_size(10) From 6483b8c1386695c9f6d61525a7492c4f13ce2dd8 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 18 May 2020 17:49:44 +0200 Subject: [PATCH 21/21] change to WAL only on one handle. journal_mode is persisted, it is sufficient to change it only for one handle. with_init() is called for a bunch of handles directly on pool-creation, so changing to WAL here easily results in busy-errors. --- src/sql.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sql.rs b/src/sql.rs index 40de8200e..c5927aa04 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -398,9 +398,13 @@ fn open( open_flags.insert(OpenFlags::SQLITE_OPEN_READ_WRITE); open_flags.insert(OpenFlags::SQLITE_OPEN_CREATE); } + + // this actually creates min_idle database handles just now. + // therefore, with_init() must not try to modify the database as otherwise + // we easily get busy-errors (eg. table-creation, journal_mode etc. should be done on only one handle) let mgr = r2d2_sqlite::SqliteConnectionManager::file(dbfile.as_ref()) .with_flags(open_flags) - .with_init(|c| c.execute_batch("PRAGMA journal_mode=WAL; PRAGMA secure_delete=on;")); + .with_init(|c| c.execute_batch("PRAGMA secure_delete=on;")); let pool = r2d2::Pool::builder() .min_idle(Some(2)) .max_size(10) @@ -413,6 +417,13 @@ fn open( } if !readonly { + // journal_mode is persisted, it is sufficient to change it only for one handle. + // (nb: execute() always returns errors for this PRAGMA call, just discard it. + // but even if execute() would handle errors more gracefully, we should continue on errors - + // systems might not be able to handle WAL, in which case the standard-journal is used. + // that may be not optimal, but better than not working at all :) + sql.execute("PRAGMA journal_mode=WAL;", NO_PARAMS).ok(); + let mut exists_before_update = false; let mut dbversion_before_update = 0; /* Init tables to dbversion=0 */