mirror of
https://github.com/chatmail/core.git
synced 2026-07-03 13:05:14 +03:00
Compare commits
28 Commits
1.33.0
...
stress_tes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bbf828518a | ||
|
|
adc1d52b2d | ||
|
|
f7b1c91ef8 | ||
|
|
f9fe5795f5 | ||
|
|
9702647044 | ||
|
|
3b2192a046 | ||
|
|
b864911e18 | ||
|
|
9e0506cb48 | ||
|
|
a0000b9489 | ||
|
|
df3fac4e5e | ||
|
|
8a36f55439 | ||
|
|
ab253744f8 | ||
|
|
fff1eaba45 | ||
|
|
eafb7b979d | ||
|
|
9e22bf39cc | ||
|
|
fc6691ce5b | ||
|
|
598dc86ca5 | ||
|
|
3e2bfc35e3 | ||
|
|
6658ad8618 | ||
|
|
759ccdbee2 | ||
|
|
635060a02d | ||
|
|
a128e7e7ab | ||
|
|
3cb69b8035 | ||
|
|
4b744337fe | ||
|
|
8d7d2f7a44 | ||
|
|
24bf1dbffb | ||
|
|
c1890bb126 | ||
|
|
a4a570896a |
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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().
|
||||
@@ -1639,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.
|
||||
*
|
||||
@@ -2977,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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,35 @@ 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())
|
||||
ac.addr = ac.get_self_contact().addr
|
||||
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)
|
||||
@@ -262,6 +321,13 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig, data):
|
||||
ac2._configtracker.wait_finish()
|
||||
return ac1, ac2
|
||||
|
||||
def get_many_online_accounts(self, num, move=True, quiet=True):
|
||||
accounts = [self.get_online_configuring_account(move=move, quiet=quiet)
|
||||
for i in range(num)]
|
||||
for acc in accounts:
|
||||
acc._configtracker.wait_finish()
|
||||
return accounts
|
||||
|
||||
def clone_online_account(self, account, pre_generated_key=True):
|
||||
self.live_count += 1
|
||||
tmpdb = tmpdir.join("livedb%d" % self.live_count)
|
||||
|
||||
105
python/tests/stress_test_db.py
Normal file
105
python/tests/stress_test_db.py
Normal file
@@ -0,0 +1,105 @@
|
||||
import time
|
||||
import os
|
||||
from queue import Queue
|
||||
|
||||
import deltachat
|
||||
|
||||
|
||||
def test_db_busy_error(acfactory, tmpdir):
|
||||
starttime = time.time()
|
||||
|
||||
def log(string):
|
||||
print("%3.2f %s" % (time.time() - starttime, string))
|
||||
|
||||
# make a number of accounts
|
||||
accounts = acfactory.get_many_online_accounts(5, quiet=False)
|
||||
log("created %s accounts" % len(accounts))
|
||||
|
||||
# put a bigfile into each account
|
||||
for acc in accounts:
|
||||
acc.bigfile = os.path.join(acc.get_blobdir(), "bigfile")
|
||||
with open(acc.bigfile, "wb") as f:
|
||||
f.write(b"01234567890"*1000_000)
|
||||
log("created %s bigfiles" % len(accounts))
|
||||
|
||||
contact_addrs = [acc.get_self_contact().addr for acc in accounts]
|
||||
chat = accounts[0].create_group_chat("stress-group")
|
||||
for addr in contact_addrs[1:]:
|
||||
chat.add_contact(chat.account.create_contact(addr))
|
||||
|
||||
# setup auto-responder bots which report back failures/actions
|
||||
report_queue = Queue()
|
||||
|
||||
def report_func(replier, report_type, *report_args):
|
||||
report_queue.put((replier, report_type, report_args))
|
||||
|
||||
# each replier receives all events and sends report events to receive_queue
|
||||
repliers = []
|
||||
for acc in accounts:
|
||||
replier = AutoReplier(acc, num_send=1000, num_bigfiles=0, report_func=report_func)
|
||||
acc.add_account_plugin(replier)
|
||||
repliers.append(replier)
|
||||
|
||||
# kick off message sending
|
||||
# after which repliers will reply to each other
|
||||
chat.send_text("hello")
|
||||
|
||||
alive_count = len(accounts)
|
||||
while alive_count > 0:
|
||||
replier, report_type, report_args = report_queue.get(10)
|
||||
addr = replier.account.get_self_contact().addr
|
||||
assert addr
|
||||
if report_type == ReportType.exit:
|
||||
alive_count -= 1
|
||||
log("{} EXIT -- remaining: {}".format(addr, alive_count))
|
||||
replier.account.shutdown(wait=True)
|
||||
elif report_type == ReportType.message_sent:
|
||||
log("{} sent message: {}".format(addr, report_args[0].text))
|
||||
elif report_type == ReportType.message_incoming:
|
||||
log("{} incoming message: {}".format(addr, report_args[0].text))
|
||||
elif report_type == ReportType.ffi_error:
|
||||
log("{} ERROR: {}".format(addr, report_args[0]))
|
||||
replier.account.shutdown(wait=True)
|
||||
alive_count -= 1
|
||||
|
||||
|
||||
class ReportType:
|
||||
exit = "exit"
|
||||
message_sent = "message-sent"
|
||||
ffi_error = "ffi-error"
|
||||
message_incoming = "message-incoming"
|
||||
|
||||
|
||||
class AutoReplier:
|
||||
def __init__(self, account, report_func, num_send, num_bigfiles):
|
||||
self.account = account
|
||||
self.report_func = report_func
|
||||
self.num_send = num_send
|
||||
self.num_bigfiles = num_bigfiles
|
||||
self.current_sent = 0
|
||||
|
||||
@deltachat.account_hookimpl
|
||||
def ac_incoming_message(self, message):
|
||||
if self.current_sent >= self.num_send:
|
||||
return
|
||||
message.accept_sender_contact()
|
||||
message.mark_seen()
|
||||
self.report_func(self, ReportType.message_incoming, message)
|
||||
|
||||
self.current_sent += 1
|
||||
# we are still alive, let's send a reply
|
||||
if self.num_bigfiles and self.current_sent % self.num_bigfiles == 0:
|
||||
message.chat.send_text("send big file as reply to: {}".format(message.text))
|
||||
msg = message.chat.send_file(self.account.bigfile)
|
||||
else:
|
||||
msg = message.chat.send_text("got message id {}, small text reply".format(message.id))
|
||||
assert msg.text
|
||||
self.report_func(self, ReportType.message_sent, msg)
|
||||
if self.current_sent >= self.num_send:
|
||||
self.report_func(self, ReportType.exit)
|
||||
return
|
||||
|
||||
@deltachat.account_hookimpl
|
||||
def ac_process_ffi_event(self, ffi_event):
|
||||
if ffi_event.name == "DC_EVENT_ERROR":
|
||||
self.report_func(self, ReportType.ffi_error, ffi_event)
|
||||
@@ -1612,8 +1612,7 @@ pub fn delete_device_expired_messages(context: &Context) -> Result<bool, Error>
|
||||
WHERE timestamp < ? \
|
||||
AND chat_id > ? \
|
||||
AND chat_id != ? \
|
||||
AND chat_id != ? \
|
||||
AND NOT hidden",
|
||||
AND chat_id != ?",
|
||||
params![
|
||||
DC_CHAT_ID_TRASH,
|
||||
threshold_timestamp,
|
||||
|
||||
@@ -69,6 +69,7 @@ pub(crate) fn JobConfigureImap(context: &Context) -> job::Status {
|
||||
let mut smtp_connected_here = false;
|
||||
|
||||
let mut param_autoconfig: Option<LoginParam> = 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());
|
||||
|
||||
@@ -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_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);
|
||||
@@ -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(
|
||||
|
||||
@@ -135,7 +135,7 @@ impl async_imap::Authenticator for OAuth2 {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum FolderMeaning {
|
||||
Unknown,
|
||||
SentObjects,
|
||||
@@ -1063,13 +1063,15 @@ 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| get_folder_meaning(folder) == FolderMeaning::SentObjects)
|
||||
.or_else(|| {
|
||||
info!(context, "can't find sentbox by attributes, checking names");
|
||||
folders.iter().find(|folder| {
|
||||
get_folder_meaning_by_name(folder) == FolderMeaning::SentObjects
|
||||
})
|
||||
});
|
||||
info!(context, "sentbox folder is {:?}", sentbox_folder);
|
||||
|
||||
let mut delimiter = ".";
|
||||
@@ -1235,7 +1237,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) {
|
||||
@@ -1246,27 +1248,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,
|
||||
}
|
||||
FolderMeaning::Unknown
|
||||
}
|
||||
|
||||
fn precheck_imf(
|
||||
|
||||
@@ -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,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: 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
|
||||
@@ -171,6 +190,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 +203,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 +214,7 @@ lazy_static::lazy_static! {
|
||||
overview_page: "https://providers.delta.chat/protonmail",
|
||||
server: vec![
|
||||
],
|
||||
config_defaults: None,
|
||||
};
|
||||
|
||||
// riseup.net.md: riseup.net
|
||||
@@ -201,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,
|
||||
@@ -209,6 +234,7 @@ lazy_static::lazy_static! {
|
||||
overview_page: "https://providers.delta.chat/t-online",
|
||||
server: vec![
|
||||
],
|
||||
config_defaults: None,
|
||||
};
|
||||
|
||||
// testrun.md: testrun.org
|
||||
@@ -222,6 +248,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 +261,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 +281,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 +294,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 +305,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 +318,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> = [
|
||||
|
||||
@@ -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<Server>,
|
||||
pub config_defaults: Option<Vec<ConfigDefault>>,
|
||||
}
|
||||
|
||||
impl Provider {
|
||||
|
||||
@@ -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")
|
||||
@@ -103,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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user