From a5cf99244a3cc95483614093f9549359ea91c9c1 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Mon, 20 Jul 2026 18:50:34 +0200 Subject: [PATCH 1/4] api!: remove provider-db handling and provider lookup APIs BREAKING CHANGE: provider lookup APIs were removed from CFFI and JSON-RPC. also removes offline provider database code and generated provider data, provider-specific fields in configure/transport paths, and REPL providerinfo. --- .github/workflows/ci.yml | 14 - deltachat-ffi/deltachat.h | 148 -- deltachat-ffi/src/lib.rs | 93 - deltachat-jsonrpc/src/api.rs | 17 - .../src/api/types/login_param.rs | 4 +- deltachat-jsonrpc/src/api/types/mod.rs | 2 +- .../src/api/types/provider_info.rs | 25 - deltachat-jsonrpc/typescript/test/online.ts | 16 - deltachat-repl/src/cmdline.rs | 21 +- deltachat-repl/src/main.rs | 3 +- python/src/deltachat/provider.py | 46 - scripts/create-provider-data-rs.py | 242 -- scripts/update-provider-database.sh | 22 - src/config.rs | 3 - src/configure.rs | 104 +- src/configure/server_params.rs | 7 +- src/context.rs | 8 +- src/login_param.rs | 4 +- src/provider.rs | 200 +- src/provider/data.rs | 2309 ----------------- src/qr/dclogin_scheme.rs | 2 +- src/sql/migrations.rs | 16 +- src/transport.rs | 191 +- src/transport/transport_tests.rs | 180 +- 24 files changed, 38 insertions(+), 3639 deletions(-) delete mode 100644 deltachat-jsonrpc/src/api/types/provider_info.rs delete mode 100644 python/src/deltachat/provider.py delete mode 100755 scripts/create-provider-data-rs.py delete mode 100755 scripts/update-provider-database.sh delete mode 100644 src/provider/data.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ef01f35e28..09076d402c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,20 +68,6 @@ jobs: command: check command-arguments: "-Dwarnings" - provider_database: - name: Check provider database - runs-on: ubuntu-latest - timeout-minutes: 60 - steps: - - uses: actions/checkout@v7 - with: - show-progress: false - persist-credentials: false - - name: Install rustfmt - run: rustup component add --toolchain stable-x86_64-unknown-linux-gnu rustfmt - - name: Check provider database - run: scripts/update-provider-database.sh - docs: name: Rust doc comments runs-on: ubuntu-latest diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index ed96d50193..537bc043be 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -19,7 +19,6 @@ typedef struct _dc_chat dc_chat_t; typedef struct _dc_msg dc_msg_t; typedef struct _dc_contact dc_contact_t; typedef struct _dc_lot dc_lot_t; -typedef struct _dc_provider dc_provider_t; typedef struct _dc_event dc_event_t; typedef struct _dc_event_emitter dc_event_emitter_t; typedef struct _dc_event_channel dc_event_channel_t; @@ -5200,98 +5199,6 @@ int dc_contact_is_key_contact (dc_contact_t* contact); uint32_t dc_contact_get_verifier_id (dc_contact_t* contact); -/** - * @class dc_provider_t - * - * Opaque object containing information about one single e-mail provider. - */ - - -/** - * Create a provider struct for the given e-mail address by local lookup. - * - * Lookup is done from the local database by extracting the domain from the e-mail address. - * Therefore the provider for custom domains cannot be identified. - * - * @memberof dc_provider_t - * @param context The context object. - * @param email The user's e-mail address to extract the provider info form. - * @return A dc_provider_t struct which can be used with the dc_provider_get_* - * accessor functions. If no provider info is found, NULL will be - * returned. - */ -dc_provider_t* dc_provider_new_from_email (const dc_context_t* context, const char* email); - - -/** - * Create a provider struct for the given e-mail address by local lookup. - * - * DNS lookup is not used anymore and this function is deprecated. - * - * @memberof dc_provider_t - * @param context The context object. - * @param email The user's e-mail address to extract the provider info form. - * @return A dc_provider_t struct which can be used with the dc_provider_get_* - * accessor functions. If no provider info is found, NULL will be - * returned. - * @deprecated 2025-10-17 use dc_provider_new_from_email() instead. - */ -dc_provider_t* dc_provider_new_from_email_with_dns (const dc_context_t* context, const char* email); - - -/** - * URL of the overview page. - * - * This URL allows linking to the providers page on providers.delta.chat. - * - * @memberof dc_provider_t - * @param provider The dc_provider_t struct. - * @return A string with a fully-qualified URL, - * if there is no such URL, an empty string is returned, NULL is never returned. - * The returned value must be released using dc_str_unref(). - */ -char* dc_provider_get_overview_page (const dc_provider_t* provider); - - -/** - * Get hints to be shown to the user on the login screen. - * Depending on the @ref DC_PROVIDER_STATUS returned by dc_provider_get_status(), - * the UI may want to highlight the hint. - * - * Moreover, the UI should display a "More information" link - * that forwards to the URL returned by dc_provider_get_overview_page(). - * - * @memberof dc_provider_t - * @param provider The dc_provider_t struct. - * @return A string with the hint to show to the user, may contain multiple lines, - * if there is no such hint, an empty string is returned, NULL is never returned. - * The returned value must be released using dc_str_unref(). - */ -char* dc_provider_get_before_login_hint (const dc_provider_t* provider); - - -/** - * Whether DC works with this provider. - * - * Can be one of #DC_PROVIDER_STATUS_OK, - * #DC_PROVIDER_STATUS_PREPARATION or #DC_PROVIDER_STATUS_BROKEN. - * - * @memberof dc_provider_t - * @param provider The dc_provider_t struct. - * @return The status as a constant number. - */ -int dc_provider_get_status (const dc_provider_t* provider); - - -/** - * Free the provider info struct. - * - * @memberof dc_provider_t - * @param provider The dc_provider_t struct. - */ -void dc_provider_unref (dc_provider_t* provider); - - /** * @class dc_lot_t * @@ -6612,61 +6519,6 @@ void dc_event_unref(dc_event_t* event); #define DC_MEDIA_QUALITY_WORSE 1 -/** - * @defgroup DC_PROVIDER_STATUS DC_PROVIDER_STATUS - * - * These constants are used as return values for dc_provider_get_status(). - * - * @addtogroup DC_PROVIDER_STATUS - * @{ - */ - -/** - * Provider works out-of-the-box. - * This provider status is returned for provider where the login - * works by just entering the name or the e-mail address. - * - * - There is no need for the user to do any special things - * (enable IMAP or so) in the provider's web interface or at other places. - * - There is no need for the user to enter advanced settings; - * server, port etc. are known by the core. - * - * The status is returned by dc_provider_get_status(). - */ -#define DC_PROVIDER_STATUS_OK 1 - -/** - * Provider works, but there are preparations needed. - * - * - The user has to do some special things as "Enable IMAP in the web interface", - * what exactly, is described in the string returned by dc_provider_get_before_login_hints() - * and, typically more detailed, in the page linked by dc_provider_get_overview_page(). - * - There is no need for the user to enter advanced settings; - * server, port etc. should be known by the core. - * - * The status is returned by dc_provider_get_status(). - */ -#define DC_PROVIDER_STATUS_PREPARATION 2 - -/** - * Provider is not working. - * This provider status is returned for providers - * that are known to not work with Delta Chat. - * The UI should block logging in with this provider. - * - * More information about that is typically provided - * in the string returned by dc_provider_get_before_login_hints() - * and in the page linked by dc_provider_get_overview_page(). - * - * The status is returned by dc_provider_get_status(). - */ -#define DC_PROVIDER_STATUS_BROKEN 3 - -/** - * @} - */ - - /** * @defgroup DC_CHAT_VISIBILITY DC_CHAT_VISIBILITY * diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index d3ff6f42eb..da4f45ecef 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -4523,99 +4523,6 @@ fn convert_and_prune_message_ids(msg_ids: *const u32, msg_cnt: libc::c_int) -> V msg_ids } -// dc_provider_t - -pub type dc_provider_t = provider::Provider; - -#[no_mangle] -pub unsafe extern "C" fn dc_provider_new_from_email( - context: *const dc_context_t, - addr: *const libc::c_char, -) -> *const dc_provider_t { - if context.is_null() || addr.is_null() { - eprintln!("ignoring careless call to dc_provider_new_from_email()"); - return ptr::null(); - } - let addr = to_string_lossy(addr); - - let ctx = &*context; - - match provider::get_provider_info_by_addr(addr.as_str()) - .log_err(ctx) - .unwrap_or_default() - { - Some(provider) => provider, - None => ptr::null_mut(), - } -} - -#[no_mangle] -pub unsafe extern "C" fn dc_provider_new_from_email_with_dns( - context: *const dc_context_t, - addr: *const libc::c_char, -) -> *const dc_provider_t { - if context.is_null() || addr.is_null() { - eprintln!("ignoring careless call to dc_provider_new_from_email_with_dns()"); - return ptr::null(); - } - let addr = to_string_lossy(addr); - - let ctx = &*context; - - match provider::get_provider_info_by_addr(addr.as_str()) - .log_err(ctx) - .unwrap_or_default() - { - Some(provider) => provider, - None => ptr::null_mut(), - } -} - -#[no_mangle] -pub unsafe extern "C" fn dc_provider_get_overview_page( - provider: *const dc_provider_t, -) -> *mut libc::c_char { - if provider.is_null() { - eprintln!("ignoring careless call to dc_provider_get_overview_page()"); - return "".strdup(); - } - let provider = &*provider; - provider.overview_page.strdup() -} - -#[no_mangle] -pub unsafe extern "C" fn dc_provider_get_before_login_hint( - provider: *const dc_provider_t, -) -> *mut libc::c_char { - if provider.is_null() { - eprintln!("ignoring careless call to dc_provider_get_before_login_hint()"); - return "".strdup(); - } - let provider = &*provider; - provider.before_login_hint.strdup() -} - -#[no_mangle] -pub unsafe extern "C" fn dc_provider_get_status(provider: *const dc_provider_t) -> libc::c_int { - if provider.is_null() { - eprintln!("ignoring careless call to dc_provider_get_status()"); - return 0; - } - let provider = &*provider; - provider.status as libc::c_int -} - -#[no_mangle] -#[allow(clippy::needless_return)] -pub unsafe extern "C" fn dc_provider_unref(provider: *mut dc_provider_t) { - if provider.is_null() { - eprintln!("ignoring careless call to dc_provider_unref()"); - return; - } - // currently, there is nothing to free, the provider info is a static object. - // this may change once we start localizing string. -} - // -- Accounts /// Reader-writer lock wrapper for accounts manager to guarantee thread safety when using diff --git a/deltachat-jsonrpc/src/api.rs b/deltachat-jsonrpc/src/api.rs index 788a220f70..66a0bcbd42 100644 --- a/deltachat-jsonrpc/src/api.rs +++ b/deltachat-jsonrpc/src/api.rs @@ -29,7 +29,6 @@ use deltachat::message::{ use deltachat::peer_channels::{ leave_webxdc_realtime, send_webxdc_realtime_advertisement, send_webxdc_realtime_data, }; -use deltachat::provider::get_provider_info; use deltachat::qr::{self, Qr}; use deltachat::qr_code_generator::{create_qr_svg, generate_backup_qr, get_securejoin_qr_svg}; use deltachat::reaction::{get_msg_reactions, send_reaction}; @@ -55,7 +54,6 @@ use types::events::Event; use types::http::HttpResponse; use types::message::{MessageData, MessageObject, MessageReadReceipt}; use types::notify_state::JsonrpcNotifyState; -use types::provider_info::ProviderInfo; use types::reactions::JsonrpcReactions; use types::webxdc::WebxdcMessageInfo; @@ -345,21 +343,6 @@ impl CommandApi { Ok(dbfile + total_size) } - /// Returns provider for the given domain. - /// - /// This function looks up domain in offline database. - /// - /// For compatibility, email address can be passed to this function - /// instead of the domain. - async fn get_provider_info( - &self, - _account_id: u32, - email: String, - ) -> Result> { - let provider_info = get_provider_info(email.split('@').next_back().unwrap_or("")); - Ok(ProviderInfo::from_dc_type(provider_info)) - } - /// Checks if the context is already configured. async fn is_configured(&self, account_id: u32) -> Result { let ctx = self.get_context(account_id).await?; diff --git a/deltachat-jsonrpc/src/api/types/login_param.rs b/deltachat-jsonrpc/src/api/types/login_param.rs index 0d650a357b..de3f54b98b 100644 --- a/deltachat-jsonrpc/src/api/types/login_param.rs +++ b/deltachat-jsonrpc/src/api/types/login_param.rs @@ -168,9 +168,7 @@ impl From for dc::Socket { #[derive(Serialize, Deserialize, TypeDef, schemars::JsonSchema, Default, PartialEq)] #[serde(rename_all = "camelCase")] pub enum EnteredCertificateChecks { - /// `Automatic` means that provider database setting should be taken. - /// If there is no provider database setting for certificate checks, - /// check certificates strictly. + /// `Automatic` means strict certificate checks. #[default] Automatic, diff --git a/deltachat-jsonrpc/src/api/types/mod.rs b/deltachat-jsonrpc/src/api/types/mod.rs index c71a995c8f..50397312b4 100644 --- a/deltachat-jsonrpc/src/api/types/mod.rs +++ b/deltachat-jsonrpc/src/api/types/mod.rs @@ -9,7 +9,7 @@ pub mod location; pub mod login_param; pub mod message; pub mod notify_state; -pub mod provider_info; + pub mod qr; pub mod reactions; pub mod webxdc; diff --git a/deltachat-jsonrpc/src/api/types/provider_info.rs b/deltachat-jsonrpc/src/api/types/provider_info.rs deleted file mode 100644 index 9142ffa603..0000000000 --- a/deltachat-jsonrpc/src/api/types/provider_info.rs +++ /dev/null @@ -1,25 +0,0 @@ -use deltachat::provider::Provider; -use num_traits::cast::ToPrimitive; -use serde::Serialize; -use typescript_type_def::TypeDef; - -#[derive(Serialize, TypeDef, schemars::JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct ProviderInfo { - /// Unique ID, corresponding to provider database filename. - pub id: String, - pub before_login_hint: String, - pub overview_page: String, - pub status: u32, // in reality this is an enum, but for simplicity and because it gets converted into a number anyway, we use an u32 here. -} - -impl ProviderInfo { - pub fn from_dc_type(provider: Option<&Provider>) -> Option { - provider.map(|p| ProviderInfo { - id: p.id.to_owned(), - before_login_hint: p.before_login_hint.to_owned(), - overview_page: p.overview_page.to_owned(), - status: p.status.to_u32().unwrap(), - }) - } -} diff --git a/deltachat-jsonrpc/typescript/test/online.ts b/deltachat-jsonrpc/typescript/test/online.ts index 60bd1ddf53..97f97fb515 100644 --- a/deltachat-jsonrpc/typescript/test/online.ts +++ b/deltachat-jsonrpc/typescript/test/online.ts @@ -149,22 +149,6 @@ describe("online tests", function () { expect(message2.showPadlock).equal(true); }); - it("get provider info for example.com", async () => { - const acc = await dc.rpc.addAccount(); - const info = await dc.rpc.getProviderInfo(acc, "example.com"); - expect(info).to.be.not.null; - expect(info?.overviewPage).to.equal( - "https://providers.delta.chat/example-com", - ); - expect(info?.status).to.equal(3); - }); - - it("get provider info - domain and email should give same result", async () => { - const acc = await dc.rpc.addAccount(); - const info_domain = await dc.rpc.getProviderInfo(acc, "example.com"); - const info_email = await dc.rpc.getProviderInfo(acc, "hi@example.com"); - expect(info_email).to.deep.equal(info_domain); - }); }); async function waitForEvent( diff --git a/deltachat-repl/src/cmdline.rs b/deltachat-repl/src/cmdline.rs index a8e07e4f69..3c58e65849 100644 --- a/deltachat-repl/src/cmdline.rs +++ b/deltachat-repl/src/cmdline.rs @@ -24,7 +24,7 @@ use deltachat::reaction::send_reaction; use deltachat::receive_imf::*; use deltachat::sql; use deltachat::tools::*; -use deltachat::{config, provider}; +use deltachat::config; use tokio::fs; /// Reset database tables. @@ -395,7 +395,6 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu joinqr \n\ setqr \n\ createqrsvg \n\ - providerinfo \n\ fileinfo \n\ estimatedeletion \n\ clear -- clear screen\n\ @@ -1204,24 +1203,6 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu fs::write(&file, svg).await?; println!("{file:#?} written."); } - "providerinfo" => { - ensure!(!arg1.is_empty(), "Argument missing."); - match provider::get_provider_info(arg1) { - Some(info) => { - println!("Information for provider belonging to {arg1}:"); - println!("status: {}", info.status as u32); - println!("before_login_hint: {}", info.before_login_hint); - println!("after_login_hint: {}", info.after_login_hint); - println!("overview_page: {}", info.overview_page); - for server in info.server.iter() { - println!("server: {}:{}", server.hostname, server.port,); - } - } - None => { - println!("No information for provider belonging to {arg1} found."); - } - } - } "fileinfo" => { ensure!(!arg1.is_empty(), "Argument missing."); diff --git a/deltachat-repl/src/main.rs b/deltachat-repl/src/main.rs index b082a79556..0b2b7e242c 100644 --- a/deltachat-repl/src/main.rs +++ b/deltachat-repl/src/main.rs @@ -237,7 +237,7 @@ const CONTACT_COMMANDS: [&str; 9] = [ "import-vcard", "make-vcard", ]; -const MISC_COMMANDS: [&str; 14] = [ +const MISC_COMMANDS: [&str; 13] = [ "getqr", "getqrsvg", "getbadqr", @@ -245,7 +245,6 @@ const MISC_COMMANDS: [&str; 14] = [ "joinqr", "setqr", "createqrsvg", - "providerinfo", "fileinfo", "estimatedeletion", "clear", diff --git a/python/src/deltachat/provider.py b/python/src/deltachat/provider.py deleted file mode 100644 index 29313a0fb6..0000000000 --- a/python/src/deltachat/provider.py +++ /dev/null @@ -1,46 +0,0 @@ -"""Provider info class.""" - -from .capi import ffi, lib -from .cutil import as_dc_charpointer, from_dc_charpointer - - -class ProviderNotFoundError(Exception): - """The provider information was not found.""" - - -class Provider: - """ - Provider information. - - :param domain: The email to get the provider info for. - """ - - def __init__(self, account, addr) -> None: - provider = ffi.gc( - lib.dc_provider_new_from_email(account._dc_context, as_dc_charpointer(addr)), - lib.dc_provider_unref, - ) - if provider == ffi.NULL: - raise ProviderNotFoundError("Provider not found") - self._provider = provider - - @property - def overview_page(self) -> str: - """URL to the overview page of the provider on providers.delta.chat.""" - return from_dc_charpointer(lib.dc_provider_get_overview_page(self._provider)) - - @property - def get_before_login_hints(self) -> str: - """Should be shown to the user on login.""" - return from_dc_charpointer(lib.dc_provider_get_before_login_hint(self._provider)) - - @property - def status(self) -> int: - """The status of the provider information. - - This is one of the - :attr:`deltachat.const.DC_PROVIDER_STATUS_OK`, - :attr:`deltachat.const.DC_PROVIDER_STATUS_PREPARATION` or - :attr:`deltachat.const.DC_PROVIDER_STATUS_BROKEN` constants. - """ - return lib.dc_provider_get_status(self._provider) diff --git a/scripts/create-provider-data-rs.py b/scripts/create-provider-data-rs.py deleted file mode 100755 index e6ee793b29..0000000000 --- a/scripts/create-provider-data-rs.py +++ /dev/null @@ -1,242 +0,0 @@ -#!/usr/bin/env python3 -# if the yaml import fails, run "pip install pyyaml" - -import sys -import yaml -import datetime -from pathlib import Path - -out_all = "" -out_domains = "" -out_ids = "" -domains_set = set() - - -def camel(name): - words = name.split("_") - return "".join(w.capitalize() for i, w in enumerate(words)) - - -def cleanstr(s): - s = s.strip() - s = s.replace("\n", " ") - s = s.replace("\\", "\\\\") - s = s.replace('"', '\\"') - return s - - -def file2id(f): - return f.stem - - -def file2varname(f): - f = file2id(f) - f = f.replace(".", "_") - f = f.replace("-", "_") - return "P_" + f.upper() - - -def file2url(f): - f = file2id(f) - f = f.replace(".", "-") - return "https://providers.delta.chat/" + f - - -def process_opt(data): - if not "opt" in data: - return "ProviderOptions::new()" - opt = "ProviderOptions {\n" - opt_data = data.get("opt", "") - for key in opt_data: - value = str(opt_data[key]) - if key == "max_smtp_rcpt_to": - value = "Some(" + value + ")" - if value in {"True", "False"}: - value = value.lower() - opt += " " + key + ": " + value + ",\n" - opt += " ..ProviderOptions::new()\n" - opt += " }" - return opt - - -def process_config_defaults(data): - if not "config_defaults" in data: - return "None" - defaults = "Some(&[\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": - raise TypeError("bad status") - - comment = "" - domains = "" - if not "domains" in data: - raise TypeError("no domains found") - for domain in data["domains"]: - domain = cleanstr(domain) - if domain == "" or domain.lower() != domain: - raise TypeError("bad domain: " + domain) - - global domains_set - if domain in domains_set: - raise TypeError("domain used twice: " + domain) - domains_set.add(domain) - - domains += ' ("' + domain + '", &' + file2varname(file) + "),\n" - comment += domain + ", " - - ids = "" - ids += ' ("' + file2id(file) + '", &' + file2varname(file) + "),\n" - - server = "" - has_imap = False - has_smtp = False - if "server" in data: - for s in data["server"]: - hostname = cleanstr(s.get("hostname", "")) - port = int(s.get("port", "")) - if hostname == "" or hostname.lower() != hostname or port <= 0: - raise TypeError("bad hostname or port") - - protocol = s.get("type", "").upper() - if protocol == "IMAP": - has_imap = True - elif protocol == "SMTP": - has_smtp = True - else: - raise TypeError("bad protocol") - - socket = s.get("socket", "").upper() - if socket != "STARTTLS" and socket != "SSL" and socket != "PLAIN": - raise TypeError("bad socket") - - username_pattern = s.get("username_pattern", "EMAIL").upper() - if username_pattern != "EMAIL" and username_pattern != "EMAILLOCALPART": - raise TypeError("bad username pattern") - - server += ( - " Server { protocol: " - + protocol.capitalize() - + ", socket: " - + socket.capitalize() - + ', hostname: "' - + hostname - + '", port: ' - + str(port) - + ", username_pattern: " - + username_pattern.capitalize() - + " },\n" - ) - - opt = process_opt(data) - config_defaults = process_config_defaults(data) - - provider = "" - before_login_hint = cleanstr(data.get("before_login_hint", "") or "") - after_login_hint = cleanstr(data.get("after_login_hint", "")) - if (not has_imap and not has_smtp) or (has_imap and has_smtp): - provider += ( - "static " - + file2varname(file) - + ": Provider = Provider {\n" - ) - provider += ' id: "' + file2id(file) + '",\n' - provider += " status: Status::" + status.capitalize() + ",\n" - provider += ' before_login_hint: "' + before_login_hint + '",\n' - provider += ' after_login_hint: "' + after_login_hint + '",\n' - provider += ' overview_page: "' + file2url(file) + '",\n' - provider += " server: &[\n" + server + " ],\n" - provider += " opt: " + opt + ",\n" - provider += " config_defaults: " + config_defaults + ",\n" - provider += "};\n\n" - else: - raise TypeError("SMTP and IMAP must be specified together or left out both") - - if status != "OK" and before_login_hint == "": - raise TypeError( - "status PREPARATION or BROKEN requires before_login_hint: " + file - ) - - # finally, add the provider - global out_all, out_domains, out_ids - out_all += "// " + file.name + ": " + comment.strip(", ") + "\n" - - # also add provider with no special things to do - - # eg. we can skip the mx-lookup in this case - out_all += provider - out_domains += domains - out_ids += ids - - -def process_file(file): - print("processing file: {}".format(file), file=sys.stderr) - with open(file) as f: - # load_all() loads "---"-separated yamls - - # by coincidence, this is also the frontmatter separator :) - data = next(yaml.load_all(f, Loader=yaml.SafeLoader)) - process_data(data, file) - - -def process_dir(dir): - print("processing directory: {}".format(dir), file=sys.stderr) - files = sorted(f for f in dir.iterdir() if f.suffix == ".md") - for f in files: - process_file(f) - - -if __name__ == "__main__": - if len(sys.argv) < 2: - raise SystemExit("usage: update.py DIR_WITH_MD_FILES > data.rs") - - out_all = ( - "// file generated by src/provider/update.py\n\n" - "use crate::provider::Protocol::*;\n" - "use crate::provider::Socket::*;\n" - "use crate::provider::UsernamePattern::*;\n" - "use crate::provider::{\n" - " Config, ConfigDefault, Provider, ProviderOptions, Server, Status,\n" - "};\n" - "use std::collections::HashMap;\n\n" - "use std::sync::LazyLock;\n\n" - ) - - process_dir(Path(sys.argv[1])) - - out_all += "pub(crate) static PROVIDER_DATA: [(&str, &Provider); " + str(len(domains_set)) + "] = [\n"; - out_all += out_domains - out_all += "];\n\n" - - out_all += "pub(crate) static PROVIDER_IDS: LazyLock> = LazyLock::new(|| HashMap::from([\n" - out_all += out_ids - out_all += "]));\n\n" - - if len(sys.argv) < 3: - now = datetime.datetime.utcnow() - else: - now = datetime.datetime.fromisoformat(sys.argv[2]) - out_all += ( - "pub static _PROVIDER_UPDATED: LazyLock = " - "LazyLock::new(|| chrono::NaiveDate::from_ymd_opt(" - + str(now.year) - + ", " - + str(now.month) - + ", " - + str(now.day) - + ").unwrap());\n" - ) - - print(out_all) diff --git a/scripts/update-provider-database.sh b/scripts/update-provider-database.sh deleted file mode 100755 index dfde951aa3..0000000000 --- a/scripts/update-provider-database.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env bash -# Updates provider database. -# Returns 1 if the database is changed, 0 otherwise. -set -euo pipefail - -export TZ=UTC - -# Provider database revision. -REV=2cba4b72f4c6e6417b83ba549aff7781be5f166c - -CORE_ROOT="$PWD" -TMP="$(mktemp -d)" -git clone --filter=blob:none https://github.com/chatmail/provider-db.git "$TMP" -cd "$TMP" -git checkout "$REV" -DATE=$(git show -s --format=%cs) -"$CORE_ROOT"/scripts/create-provider-data-rs.py "$TMP/_providers" "$DATE" >"$CORE_ROOT/src/provider/data.rs" -rustfmt --edition 2024 "$CORE_ROOT/src/provider/data.rs" -rm -fr "$TMP" - -cd "$CORE_ROOT" -test -z "$(git status --porcelain src/provider/data.rs)" diff --git a/src/config.rs b/src/config.rs index 8c822545f6..8c84a9de8c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -294,9 +294,6 @@ pub enum Config { /// Unix timestamp of the last successful configuration. ConfiguredTimestamp, - /// ID of the configured provider from the provider database. - ConfiguredProvider, - /// Deprecated(2026-04). /// Use [`Context::is_configured()`] instead. /// diff --git a/src/configure.rs b/src/configure.rs index 5c36a32dce..e92a31616d 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -1,11 +1,9 @@ //! # Email accounts autoconfiguration process. //! -//! The module provides automatic lookup of configuration -//! for email providers based on the built-in [provider database], -//! [Mozilla Thunderbird Autoconfiguration protocol] +//! The module provides automatic lookup of configuration for email providers +//! using [Mozilla Thunderbird Autoconfiguration protocol] //! and [Outlook's Autodiscover]. //! -//! [provider database]: crate::provider //! [Mozilla Thunderbird Autoconfiguration protocol]: auto_mozilla //! [Outlook's Autodiscover]: auto_outlook @@ -30,19 +28,16 @@ use crate::imap::Imap; use crate::log::warn; pub use crate::login_param::EnteredLoginParam; use crate::login_param::{EnteredCertificateChecks, TransportListEntry}; -use crate::message::Message; use crate::net::proxy::ProxyConfig; -use crate::provider::{Protocol, Provider, Socket, UsernamePattern}; +use crate::provider::{Protocol, Socket}; use crate::qr::{login_param_from_account_qr, login_param_from_login_qr}; use crate::smtp::Smtp; -use crate::sync::Sync::*; use crate::tools::time; use crate::transport::{ ConfiguredCertificateChecks, ConfiguredLoginParam, ConfiguredServerLoginParam, ConnectionCandidate, send_sync_transports, }; use crate::{EventType, stock_str}; -use crate::{chat, provider}; /// Maximum number of relays. /// @@ -339,7 +334,7 @@ impl Context { self.try_make_space_for_new_relay().await?; } - let provider = match configure(self, param).await { + match configure(self, param).await { Err(error) => { // Log entered and actual params let configured_param = get_configured_param(self, param).await; @@ -353,11 +348,10 @@ impl Context { ); return Err(error); } - Ok(provider) => provider, + Ok(()) => (), }; self.set_config_internal(Config::NotifyAboutWrongPw, Some("1")) .await?; - on_configure_completed(self, provider).await?; Ok(()) } @@ -398,42 +392,7 @@ impl Context { } } -async fn on_configure_completed( - context: &Context, - provider: Option<&'static Provider>, -) -> Result<()> { - if let Some(provider) = provider { - if let Some(config_defaults) = provider.config_defaults { - for def in config_defaults { - if !context.config_exists(def.key).await? { - info!(context, "apply config_defaults {}={}", def.key, def.value); - context - .set_config_ex(Nosync, def.key, Some(def.value)) - .await?; - } else { - info!( - context, - "skip already set config_defaults {}={}", def.key, def.value - ); - } - } - } - - if !provider.after_login_hint.is_empty() { - let mut msg = Message::new_text(provider.after_login_hint.to_string()); - if chat::add_device_msg(context, Some("core-provider-info"), Some(&mut msg)) - .await - .is_err() - { - warn!(context, "cannot add after_login_hint as core-provider-info"); - } - } - } - - Ok(()) -} - -/// Retrieves data from autoconfig and provider database +/// Retrieves data from autoconfig /// to transform user-entered login parameters into complete configuration. async fn get_configured_param( ctx: &Context, @@ -457,7 +416,6 @@ async fn get_configured_param( progress!(ctx, 200); - let provider; let param_autoconfig; if param.imap.server.is_empty() && param.imap.port == 0 @@ -468,49 +426,9 @@ async fn get_configured_param( && param.smtp.security == Socket::Automatic && param.smtp.user.is_empty() { - // no advanced parameters entered by the user: query provider-database or do Autoconfig - info!( - ctx, - "checking internal provider-info for offline autoconfig" - ); - - provider = provider::get_provider_info(¶m_domain); - if let Some(provider) = provider { - if provider.server.is_empty() { - info!(ctx, "Offline autoconfig found, but no servers defined."); - param_autoconfig = None; - } else { - info!(ctx, "Offline autoconfig found."); - let servers = provider - .server - .iter() - .map(|s| ServerParams { - protocol: s.protocol, - socket: s.socket, - hostname: s.hostname.to_string(), - port: s.port, - username: match s.username_pattern { - UsernamePattern::Email => param.addr.to_string(), - UsernamePattern::Emaillocalpart => { - if let Some(at) = param.addr.find('@') { - param.addr.split_at(at).0.to_string() - } else { - param.addr.to_string() - } - } - }, - }) - .collect(); - - param_autoconfig = Some(servers) - } - } else { - // Try receiving autoconfig - info!(ctx, "No offline autoconfig found."); - param_autoconfig = get_autoconfig(ctx, param, ¶m_domain).await; - } + // no advanced parameters entered by the user: do Autoconfig + param_autoconfig = get_autoconfig(ctx, param, ¶m_domain).await; } else { - provider = None; param_autoconfig = None; } @@ -591,7 +509,6 @@ async fn get_configured_param( .collect(), smtp_user: param.smtp.user.clone(), smtp_password, - provider, certificate_checks: match param.certificate_checks { EnteredCertificateChecks::Automatic => ConfiguredCertificateChecks::Automatic, EnteredCertificateChecks::Strict => ConfiguredCertificateChecks::Strict, @@ -604,7 +521,7 @@ async fn get_configured_param( Ok(configured_login_param) } -async fn configure(ctx: &Context, param: &EnteredLoginParam) -> Result> { +async fn configure(ctx: &Context, param: &EnteredLoginParam) -> Result<()> { progress!(ctx, 1); let configured_param = get_configured_param(ctx, param).await?; @@ -674,7 +591,6 @@ async fn configure(ctx: &Context, param: &EnteredLoginParam) -> Result Result Result { - let Some((transport_id, param)) = ConfiguredLoginParam::load(self).await? else { + let Some((transport_id, _param)) = ConfiguredLoginParam::load(self).await? else { bail!("Not configured"); }; let metadata_limit = self @@ -586,11 +586,7 @@ impl Context { if let Some(limit) = metadata_limit { return Ok(limit); } - let val = param - .provider - .and_then(|provider| provider.opt.max_smtp_rcpt_to) - .map_or(constants::DEFAULT_MAX_SMTP_RCPT_TO, u32::from); - Ok(val) + Ok(constants::DEFAULT_MAX_SMTP_RCPT_TO) } /// Does a single round of fetching from IMAP and returns. diff --git a/src/login_param.rs b/src/login_param.rs index f6f0b12233..9f6738c07a 100644 --- a/src/login_param.rs +++ b/src/login_param.rs @@ -37,9 +37,7 @@ use crate::tools::ToOption; #[repr(u32)] #[strum(serialize_all = "snake_case")] pub enum EnteredCertificateChecks { - /// `Automatic` means that provider database setting should be taken. - /// If there is no provider database setting for certificate checks, - /// check certificates strictly. + /// `Automatic` means strict certificate checks. #[default] Automatic = 0, diff --git a/src/provider.rs b/src/provider.rs index 3e4aef3295..b12d827ecb 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -1,29 +1,7 @@ -//! [Provider database](https://providers.delta.chat/) module. +//! Provider types. -pub(crate) mod data; - -use anyhow::Result; -use deltachat_contact_tools::EmailAddress; use serde::{Deserialize, Serialize}; -use crate::config::Config; -use crate::provider::data::{PROVIDER_DATA, PROVIDER_IDS}; - -/// Provider status according to manual testing. -#[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)] -#[repr(u8)] -pub enum Status { - /// Provider is known to be working with Delta Chat. - Ok = 1, - - /// Provider works with Delta Chat, but requires some preparation, - /// such as changing the settings in the web interface. - Preparation = 2, - - /// Provider is known not to work with Delta Chat. - Broken = 3, -} - /// Server protocol. #[derive(Debug, Display, PartialEq, Eq, Copy, Clone, FromPrimitive, ToPrimitive)] #[repr(u8)] @@ -75,179 +53,3 @@ pub enum UsernamePattern { /// Part of address before `@` is used as username. Emaillocalpart = 2, } - -/// Email server endpoint. -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Server { - /// Server protocol, e.g. SMTP or IMAP. - pub protocol: Protocol, - - /// Port security, e.g. TLS or STARTTLS. - pub socket: Socket, - - /// Server host. - pub hostname: &'static str, - - /// Server port. - pub port: u16, - - /// Pattern used to construct login usernames from email addresses. - pub username_pattern: UsernamePattern, -} - -/// Pair of key and value for default configuration. -#[derive(Debug, PartialEq, Eq)] -pub struct ConfigDefault { - /// Configuration variable name. - pub key: Config, - - /// Configuration variable value. - pub value: &'static str, -} - -/// Provider database entry. -#[derive(Debug, PartialEq, Eq)] -pub struct Provider { - /// Unique ID, corresponding to provider database filename. - pub id: &'static str, - - /// Provider status according to manual testing. - pub status: Status, - - /// Hint to be shown to the user on the login screen. - pub before_login_hint: &'static str, - - /// Hint to be added to the device chat after provider configuration. - pub after_login_hint: &'static str, - - /// URL of the page with provider overview. - pub overview_page: &'static str, - - /// List of provider servers. - pub server: &'static [Server], - - /// Default configuration values to set when provider is configured. - pub config_defaults: Option<&'static [ConfigDefault]>, - - /// Options with good defaults. - pub opt: ProviderOptions, -} - -/// Provider options with good defaults. -#[derive(Debug, PartialEq, Eq)] -#[non_exhaustive] -pub struct ProviderOptions { - /// True if provider is known to use use proper, - /// not self-signed certificates. - pub strict_tls: bool, - - /// Maximum number of recipients the provider allows to send a single email to. - pub max_smtp_rcpt_to: Option, -} - -impl ProviderOptions { - const fn new() -> Self { - Self { - strict_tls: true, - max_smtp_rcpt_to: None, - } - } -} - -/// Returns provider for the given an e-mail address. -/// -/// Returns an error if provided address is not valid. -pub fn get_provider_info_by_addr(addr: &str) -> Result> { - let addr = EmailAddress::new(addr)?; - - Ok(get_provider_info(&addr.domain)) -} - -/// Finds a provider in offline database based on domain. -pub fn get_provider_info(domain: &str) -> Option<&'static Provider> { - let domain = domain.to_lowercase(); - for (pattern, provider) in PROVIDER_DATA { - if let Some(suffix) = pattern.strip_prefix('*') { - // Wildcard domain pattern. - // - // For example, `suffix` is ".hermes.radio" for "*.hermes.radio" pattern. - if domain.ends_with(suffix) { - return Some(provider); - } - } else if pattern == domain { - return Some(provider); - } - } - - None -} - -/// Returns a provider with the given ID from the database. -pub fn get_provider_by_id(id: &str) -> Option<&'static Provider> { - if let Some(provider) = PROVIDER_IDS.get(id) { - Some(provider) - } else { - None - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_get_provider_by_domain_unexistant() { - let provider = get_provider_info("unexistant.org"); - assert!(provider.is_none()); - } - - #[test] - fn test_get_provider_by_domain_mixed_case() { - let provider = get_provider_info("nAUta.Cu").unwrap(); - assert!(provider.status == Status::Ok); - } - - #[test] - fn test_get_provider_info() { - let addr = "nauta.cu"; - let provider = get_provider_info(addr).unwrap(); - assert!(provider.status == Status::Ok); - let server = &provider.server[0]; - assert_eq!(server.protocol, Protocol::Imap); - assert_eq!(server.socket, Socket::Starttls); - assert_eq!(server.hostname, "imap.nauta.cu"); - assert_eq!(server.port, 143); - assert_eq!(server.username_pattern, UsernamePattern::Email); - let server = &provider.server[1]; - assert_eq!(server.protocol, Protocol::Smtp); - assert_eq!(server.socket, Socket::Starttls); - assert_eq!(server.hostname, "smtp.nauta.cu"); - assert_eq!(server.port, 25); - assert_eq!(server.username_pattern, UsernamePattern::Email); - - let provider = get_provider_info("gmail.com").unwrap(); - assert!(provider.status == Status::Preparation); - assert!(!provider.before_login_hint.is_empty()); - assert!(!provider.overview_page.is_empty()); - - let provider = get_provider_info("googlemail.com").unwrap(); - assert!(provider.status == Status::Preparation); - - assert!(get_provider_info("").is_none()); - assert!(get_provider_info("google.com").unwrap().id == "gmail"); - assert!(get_provider_info("example@google.com").is_none()); - } - - #[test] - fn test_get_provider_by_id() { - let provider = get_provider_by_id("gmail").unwrap(); - assert!(provider.id == "gmail"); - } - - #[tokio::test(flavor = "multi_thread", worker_threads = 2)] - async fn test_get_provider_info_by_addr() -> Result<()> { - assert!(get_provider_info_by_addr("google.com").is_err()); - assert!(get_provider_info_by_addr("example@google.com")?.unwrap().id == "gmail"); - Ok(()) - } -} diff --git a/src/provider/data.rs b/src/provider/data.rs deleted file mode 100644 index a4126ee3b7..0000000000 --- a/src/provider/data.rs +++ /dev/null @@ -1,2309 +0,0 @@ -// file generated by src/provider/update.py - -use crate::provider::Protocol::*; -use crate::provider::Socket::*; -use crate::provider::UsernamePattern::*; -use crate::provider::{Config, ConfigDefault, Provider, ProviderOptions, Server, Status}; -use std::collections::HashMap; - -use std::sync::LazyLock; - -// 163.md: 163.com -static P_163: Provider = Provider { - id: "163", - status: Status::Preparation, - before_login_hint: "Enable \"POP3/SMTP/IMAP\" on the website, add a third-party auth code and use that as the login password", - after_login_hint: "", - overview_page: "https://providers.delta.chat/163", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.163.com", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.163.com", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// aktivix.org.md: aktivix.org -static P_AKTIVIX_ORG: Provider = Provider { - id: "aktivix.org", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/aktivix-org", - server: &[ - Server { - protocol: Imap, - socket: Starttls, - hostname: "newyear.aktivix.org", - port: 143, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Starttls, - hostname: "newyear.aktivix.org", - port: 587, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// aliyun.md: aliyun.com -static P_ALIYUN: Provider = Provider { - id: "aliyun", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/aliyun", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.aliyun.com", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.aliyun.com", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// aol.md: aol.com -static P_AOL: Provider = Provider { - id: "aol", - status: Status::Preparation, - before_login_hint: "To log in to AOL, you need to set up an app password in the AOL web interface.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/aol", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.aol.com", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.aol.com", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// arcor.de.md: arcor.de -static P_ARCOR_DE: Provider = Provider { - id: "arcor.de", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/arcor-de", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.arcor.de", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "mail.arcor.de", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// autistici.org.md: autistici.org -static P_AUTISTICI_ORG: Provider = Provider { - id: "autistici.org", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/autistici-org", - server: &[ - 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, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// blindzeln.org.md: delta.blinzeln.de, delta.blindzeln.org -static P_BLINDZELN_ORG: Provider = Provider { - id: "blindzeln.org", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/blindzeln-org", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "webbox222.server-home.org", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "webbox222.server-home.org", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// bluewin.ch.md: bluewin.ch -static P_BLUEWIN_CH: Provider = Provider { - id: "bluewin.ch", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/bluewin-ch", - server: &[ - 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, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// chello.at.md: chello.at -static P_CHELLO_AT: Provider = Provider { - id: "chello.at", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/chello-at", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "mail.mymagenta.at", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "mail.mymagenta.at", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// comcast.md: xfinity.com, comcast.net -static P_COMCAST: Provider = Provider { - id: "comcast", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/comcast", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// dismail.de.md: dismail.de -static P_DISMAIL_DE: Provider = Provider { - id: "dismail.de", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/dismail-de", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// disroot.md: disroot.org -static P_DISROOT: Provider = Provider { - id: "disroot", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/disroot", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "disroot.org", - port: 993, - username_pattern: Emaillocalpart, - }, - Server { - protocol: Smtp, - socket: Starttls, - hostname: "disroot.org", - port: 587, - username_pattern: Emaillocalpart, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// e.email.md: e.email -static P_E_EMAIL: Provider = Provider { - id: "e.email", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/e-email", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "mail.ecloud.global", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Starttls, - hostname: "mail.ecloud.global", - port: 587, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// espiv.net.md: espiv.net -static P_ESPIV_NET: Provider = Provider { - id: "espiv.net", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/espiv-net", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// example.com.md: example.com, example.org, example.net -static P_EXAMPLE_COM: Provider = Provider { - id: "example.com", - status: Status::Broken, - before_login_hint: "Hush this provider doesn't exist!", - after_login_hint: "This provider doesn't really exist, so you can't use it :/ If you need an email provider, take a look at providers.delta.chat!", - overview_page: "https://providers.delta.chat/example-com", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.example.com", - port: 1337, - username_pattern: Emaillocalpart, - }, - Server { - protocol: Smtp, - socket: Starttls, - hostname: "smtp.example.com", - port: 1337, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// fastmail.md: 123mail.org, 150mail.com, 150ml.com, 16mail.com, 2-mail.com, 4email.net, 50mail.com, airpost.net, allmail.net, bestmail.us, cluemail.com, elitemail.org, emailcorner.net, emailengine.net, emailengine.org, emailgroups.net, emailplus.org, emailuser.net, eml.cc, f-m.fm, fast-email.com, fast-mail.org, fastem.com, fastemail.us, fastemailer.com, fastest.cc, fastimap.com, fastmail.cn, fastmail.co.uk, fastmail.com, fastmail.com.au, fastmail.de, fastmail.es, fastmail.fm, fastmail.fr, fastmail.im, fastmail.in, fastmail.jp, fastmail.mx, fastmail.net, fastmail.nl, fastmail.org, fastmail.se, fastmail.to, fastmail.tw, fastmail.uk, fastmail.us, fastmailbox.net, fastmessaging.com, fea.st, fmail.co.uk, fmailbox.com, fmgirl.com, fmguy.com, ftml.net, h-mail.us, hailmail.net, imap-mail.com, imap.cc, imapmail.org, inoutbox.com, internet-e-mail.com, internet-mail.org, internetemails.net, internetmailing.net, jetemail.net, justemail.net, letterboxes.org, mail-central.com, mail-page.com, mailandftp.com, mailas.com, mailbolt.com, mailc.net, mailcan.com, mailforce.net, mailftp.com, mailhaven.com, mailingaddress.org, mailite.com, mailmight.com, mailnew.com, mailsent.net, mailservice.ms, mailup.net, mailworks.org, ml1.net, mm.st, myfastmail.com, mymacmail.com, nospammail.net, ownmail.net, petml.com, postinbox.com, postpro.net, proinbox.com, promessage.com, realemail.net, reallyfast.biz, reallyfast.info, rushpost.com, sent.as, sent.at, sent.com, speedpost.net, speedymail.org, ssl-mail.com, swift-mail.com, the-fastest.net, the-quickest.com, theinternetemail.com, veryfast.biz, veryspeedy.net, warpmail.net, xsmail.com, yepmail.net, your-mail.com -static P_FASTMAIL: Provider = Provider { - id: "fastmail", - status: Status::Preparation, - before_login_hint: "You must create an app-specific password before you can log in.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/fastmail", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.fastmail.com", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.fastmail.com", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// firemail.de.md: firemail.at, firemail.de -static P_FIREMAIL_DE: Provider = Provider { - id: "firemail.de", - status: Status::Preparation, - before_login_hint: "Firemail erlaubt nur bei bezahlten Accounts den vollen Zugriff auf das E-Mail-Protokoll. Wenn Sie nicht für Firemail bezahlen, verwenden Sie bitte einen anderen E-Mail-Anbieter.", - after_login_hint: "Leider schränkt Firemail die maximale Gruppengröße ein. Je nach Bezahlmodell sind nur 5 bis 30 Gruppenmitglieder erlaubt.", - overview_page: "https://providers.delta.chat/firemail-de", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// freenet.de.md: freenet.de -static P_FREENET_DE: Provider = Provider { - id: "freenet.de", - status: Status::Preparation, - before_login_hint: "Um deine freenet.de E-Mail-Adresse zu benutzen, musst du erst auf der freenet.de-Webseite \"POP3/IMAP/SMTP\" aktivieren.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/freenet-de", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "mx.freenet.de", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Imap, - socket: Starttls, - hostname: "mx.freenet.de", - port: 143, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "mx.freenet.de", - port: 465, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Starttls, - hostname: "mx.freenet.de", - port: 587, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// gmail.md: gmail.com, googlemail.com, google.com -static P_GMAIL: Provider = Provider { - id: "gmail", - status: Status::Preparation, - before_login_hint: "For Gmail accounts, you need to have \"2-Step Verification\" enabled and create an app-password. Gmail limits how many messages you can send per day.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/gmail", - server: &[ - 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, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// gmx.net.md: gmx.net, gmx.de, gmx.at, gmx.ch, gmx.org, gmx.eu, gmx.info, gmx.biz, gmx.com -static P_GMX_NET: Provider = Provider { - id: "gmx.net", - status: Status::Preparation, - before_login_hint: "You must allow IMAP access to your account before you can login.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/gmx-net", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.gmx.net", - port: 993, - username_pattern: Email, - }, - 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, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// hermes.radio.md: *.hermes.radio, *.aco-connexion.org -static P_HERMES_RADIO: Provider = Provider { - id: "hermes.radio", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/hermes-radio", - server: &[], - opt: ProviderOptions { - strict_tls: false, - ..ProviderOptions::new() - }, - config_defaults: Some(&[ConfigDefault { - key: Config::MdnsEnabled, - value: "0", - }]), -}; - -// hey.com.md: hey.com -static P_HEY_COM: Provider = Provider { - id: "hey.com", - status: Status::Broken, - before_login_hint: "hey.com does not offer the standard IMAP e-mail protocol, so you cannot log in to hey.com.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/hey-com", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// i.ua.md: i.ua -static P_I_UA: Provider = Provider { - id: "i.ua", - status: Status::Broken, - before_login_hint: "Протокол IMAP не предоставляется и не планируется.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/i-ua", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// i3.net.md: i3.net -static P_I3_NET: Provider = Provider { - id: "i3.net", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/i3-net", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// icloud.md: icloud.com, me.com, mac.com -static P_ICLOUD: Provider = Provider { - id: "icloud", - status: Status::Preparation, - before_login_hint: "You must create an app-specific password before login.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/icloud", - server: &[ - 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, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// infomaniak.com.md: ik.me -static P_INFOMANIAK_COM: Provider = Provider { - id: "infomaniak.com", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/infomaniak-com", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "mail.infomaniak.com", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "mail.infomaniak.com", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions { - max_smtp_rcpt_to: Some(10), - ..ProviderOptions::new() - }, - config_defaults: None, -}; - -// kolst.com.md: kolst.com -static P_KOLST_COM: Provider = Provider { - id: "kolst.com", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/kolst-com", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// kontent.com.md: kontent.com -static P_KONTENT_COM: Provider = Provider { - id: "kontent.com", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/kontent-com", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// mail.com.md: email.com, groupmail.com, post.com, homemail.com, housemail.com, writeme.com, mail.com, mail-me.com, workmail.com, accountant.com, activist.com, adexec.com, allergist.com, alumni.com, alumnidirector.com, archaeologist.com, auctioneer.net, bartender.net, brew-master.com, chef.net, chemist.com, collector.org, columnist.com, comic.com, consultant.com, contractor.net, counsellor.com, deliveryman.com, diplomats.com, dr.com, engineer.com, financier.com, fireman.net, gardener.com, geologist.com, graphic-designer.com, graduate.org, hairdresser.net, instructor.net, insurer.com, journalist.com, legislator.com, lobbyist.com, minister.com, musician.org, optician.com, orthodontist.net, pediatrician.com, photographer.net, physicist.net, politician.com, presidency.com, priest.com, programmer.net, publicist.com, radiologist.net, realtyagent.com, registerednurses.com, repairman.com, representative.com, salesperson.net, secretary.net, socialworker.net, sociologist.com, songwriter.net, teachers.org, techie.com, technologist.com, therapist.net, umpire.com, worker.com, artlover.com, bikerider.com, birdlover.com, blader.com, kittymail.com, lovecat.com, marchmail.com, boardermail.com, catlover.com, clubmember.org, nonpartisan.com, petlover.com, doglover.com, greenmail.net, hackermail.com, theplate.com, bsdmail.com, computer4u.com, coolsite.net, cyberdude.com, cybergal.com, cyberservices.com, cyber-wizard.com, linuxmail.org, null.net, solution4u.com, tech-center.com, webname.com, acdcfan.com, angelic.com, discofan.com, elvisfan.com, hiphopfan.com, kissfans.com, madonnafan.com, metalfan.com, ninfan.com, ravemail.com, reggaefan.com, snakebite.com, bellair.net, californiamail.com, dallasmail.com, nycmail.com, pacific-ocean.com, pacificwest.com, sanfranmail.com, usa.com, africamail.com, asia-mail.com, australiamail.com, berlin.com, brazilmail.com, chinamail.com, dublin.com, dutchmail.com, englandmail.com, europe.com, arcticmail.com, europemail.com, germanymail.com, irelandmail.com, israelmail.com, italymail.com, koreamail.com, mexicomail.com, moscowmail.com, munich.com, asia.com, polandmail.com, safrica.com, samerica.com, scotlandmail.com, spainmail.com, swedenmail.com, swissmail.com, torontomail.com, aircraftmail.com, cash4u.com, disposable.com, execs.com, fastservice.com, instruction.com, job4u.com, net-shopping.com, planetmail.com, planetmail.net, qualityservice.com, rescueteam.com, surgical.net, atheist.com, disciples.com, muslim.com, protestant.com, reborn.com, reincarnate.com, religious.com, saintly.com, brew-meister.com, cutey.com, dbzmail.com, doramail.com, galaxyhit.com, hilarious.com, humanoid.net, hot-shot.com, inorbit.com, iname.com, innocent.com, keromail.com, myself.com, rocketship.com, toothfairy.com, toke.com, tvstar.com, uymail.com, 2trom.com -static P_MAIL_COM: Provider = Provider { - id: "mail.com", - status: Status::Preparation, - before_login_hint: "To log in, you first need to activate POP3/IMAP in your mail.com settings. Note that this is a mail.com Premium feature only.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/mail-com", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// mail.de.md: mail.de -static P_MAIL_DE: Provider = Provider { - id: "mail.de", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/mail-de", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.mail.de", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.mail.de", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// mail.ru.md: mail.ru, inbox.ru, internet.ru, bk.ru, list.ru -static P_MAIL_RU: Provider = Provider { - id: "mail.ru", - status: Status::Preparation, - before_login_hint: "Вам необходимо сгенерировать \"пароль для внешнего приложения\" в веб-интерфейсе mail.ru, чтобы mail.ru работал с chatmail.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/mail-ru", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.mail.ru", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.mail.ru", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// mail2tor.md: mail2tor.com -static P_MAIL2TOR: Provider = Provider { - id: "mail2tor", - status: Status::Preparation, - before_login_hint: "Tor is needed to connect to the email servers.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/mail2tor", - server: &[ - Server { - protocol: Imap, - socket: Plain, - hostname: "g77kjrad6bafzzyldqvffq6kxlsgphcygptxhnn4xlnktfgaqshilmyd.onion", - port: 143, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Plain, - hostname: "xc7tgk2c5onxni2wsy76jslfsitxjbbptejnqhw6gy2ft7khpevhc7ad.onion", - port: 25, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// mailbox.org.md: mailbox.org, secure.mailbox.org -static P_MAILBOX_ORG: Provider = Provider { - id: "mailbox.org", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/mailbox-org", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.mailbox.org", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.mailbox.org", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// mailo.com.md: mailo.com -static P_MAILO_COM: Provider = Provider { - id: "mailo.com", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/mailo-com", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.mailo.com", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.mailo.com", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// migadu.md: migadu.com -static P_MIGADU: Provider = Provider { - id: "migadu", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/migadu", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.migadu.com", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.migadu.com", - port: 465, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Starttls, - hostname: "smtp.migadu.com", - port: 587, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// nauta.cu.md: nauta.cu -static P_NAUTA_CU: Provider = Provider { - id: "nauta.cu", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/nauta-cu", - server: &[ - 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, - }, - ], - opt: ProviderOptions { - max_smtp_rcpt_to: Some(20), - strict_tls: false, - ..ProviderOptions::new() - }, - config_defaults: Some(&[ConfigDefault { - key: Config::MediaQuality, - value: "1", - }]), -}; - -// naver.md: naver.com -static P_NAVER: Provider = Provider { - id: "naver", - status: Status::Preparation, - before_login_hint: "Manually enabling IMAP/SMTP is required.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/naver", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.naver.com", - port: 993, - username_pattern: Emaillocalpart, - }, - Server { - protocol: Smtp, - socket: Starttls, - hostname: "smtp.naver.com", - port: 587, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// nine.testrun.org.md: nine.testrun.org -static P_NINE_TESTRUN_ORG: Provider = Provider { - id: "nine.testrun.org", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/nine-testrun-org", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "nine.testrun.org", - port: 443, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "nine.testrun.org", - port: 443, - username_pattern: Email, - }, - Server { - protocol: Imap, - socket: Ssl, - hostname: "nine.testrun.org", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "nine.testrun.org", - port: 465, - username_pattern: Email, - }, - Server { - protocol: Imap, - socket: Starttls, - hostname: "nine.testrun.org", - port: 143, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Starttls, - hostname: "nine.testrun.org", - port: 587, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// nubo.coop.md: nubo.coop -static P_NUBO_COOP: Provider = Provider { - id: "nubo.coop", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/nubo-coop", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "mail.nubo.coop", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "mail.nubo.coop", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// outlook.com.md: hotmail.com, outlook.com, office365.com, outlook.com.tr, live.com, outlook.de -static P_OUTLOOK_COM: Provider = Provider { - id: "outlook.com", - status: Status::Broken, - before_login_hint: "Unfortunately, Outlook does not allow using passwords anymore, per-app-passwords are currently not working.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/outlook-com", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "outlook.office365.com", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Starttls, - hostname: "smtp.office365.com", - port: 587, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// ouvaton.coop.md: ouvaton.org -static P_OUVATON_COOP: Provider = Provider { - id: "ouvaton.coop", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/ouvaton-coop", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.ouvaton.coop", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.ouvaton.coop", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// posteo.md: posteo.de, posteo.af, posteo.at, posteo.be, posteo.ca, posteo.ch, posteo.cl, posteo.co, posteo.co.uk, posteo.com, posteo.com.br, posteo.cr, posteo.cz, posteo.dk, posteo.ee, posteo.es, posteo.eu, posteo.fi, posteo.gl, posteo.gr, posteo.hn, posteo.hr, posteo.hu, posteo.ie, posteo.in, posteo.is, posteo.it, posteo.jp, posteo.la, posteo.li, posteo.lt, posteo.lu, posteo.me, posteo.mx, posteo.my, posteo.net, posteo.nl, posteo.no, posteo.nz, posteo.org, posteo.pe, posteo.pl, posteo.pm, posteo.pt, posteo.ro, posteo.ru, posteo.se, posteo.sg, posteo.si, posteo.tn, posteo.uk, posteo.us -static P_POSTEO: Provider = Provider { - id: "posteo", - status: Status::Preparation, - before_login_hint: "You must create an app-specific password before you can log in.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/posteo", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "posteo.de", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Imap, - socket: Starttls, - hostname: "posteo.de", - port: 143, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "posteo.de", - port: 465, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Starttls, - hostname: "posteo.de", - port: 587, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// protonmail.md: protonmail.com, protonmail.ch, pm.me -static P_PROTONMAIL: Provider = Provider { - id: "protonmail", - status: Status::Broken, - before_login_hint: "Protonmail does not offer the standard IMAP e-mail protocol, so you cannot log in with to Protonmail.", - after_login_hint: "To use Protonmail, the IMAP bridge must be running in the background. If you have connectivity issues, double check whether it works as expected.", - overview_page: "https://providers.delta.chat/protonmail", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// purelymail.com.md: purelymail.com, cheapermail.com, placeq.com, rethinkmail.com, worldofmail.com -static P_PURELYMAIL_COM: Provider = Provider { - id: "purelymail.com", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/purelymail-com", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.purelymail.com", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.purelymail.com", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// qq.md: qq.com, foxmail.com -static P_QQ: Provider = Provider { - id: "qq", - status: Status::Preparation, - before_login_hint: "Manually enabling IMAP/SMTP and creating an app-specific password are required.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/qq", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.qq.com", - port: 993, - username_pattern: Emaillocalpart, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.qq.com", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// rambler.ru.md: rambler.ru, autorambler.ru, myrambler.ru, rambler.ua, lenta.ru, ro.ru, r0.ru -static P_RAMBLER_RU: Provider = Provider { - id: "rambler.ru", - status: Status::Preparation, - before_login_hint: "Чтобы войти в Рамблер/почта, необходимо предварительно включить доступ с помощью почтовых клиентов на сайте mail.rambler.ru", - after_login_hint: "", - overview_page: "https://providers.delta.chat/rambler-ru", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.rambler.ru", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.rambler.ru", - port: 465, - username_pattern: Email, - }, - Server { - protocol: Imap, - socket: Starttls, - hostname: "imap.rambler.ru", - port: 143, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// riseup.net.md: riseup.net -static P_RISEUP_NET: Provider = Provider { - id: "riseup.net", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/riseup-net", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "mail.riseup.net", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "mail.riseup.net", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// rogers.com.md: rogers.com -static P_ROGERS_COM: Provider = Provider { - id: "rogers.com", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/rogers-com", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// sonic.md: sonic.net -static P_SONIC: Provider = Provider { - id: "sonic", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/sonic", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// stinpriza.net.md: stinpriza.net, stinpriza.eu, el-hoyo.net -static P_STINPRIZA_NET: Provider = Provider { - id: "stinpriza.net", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/stinpriza-net", - server: &[ - Server { - protocol: Imap, - socket: Starttls, - hostname: "stinpriza.net", - port: 143, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Starttls, - hostname: "stinpriza.net", - port: 587, - username_pattern: Email, - }, - ], - opt: ProviderOptions { - strict_tls: true, - ..ProviderOptions::new() - }, - config_defaults: None, -}; - -// systemausfall.org.md: systemausfall.org, solidaris.me -static P_SYSTEMAUSFALL_ORG: Provider = Provider { - id: "systemausfall.org", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/systemausfall-org", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "mail.systemausfall.org", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "mail.systemausfall.org", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// systemli.org.md: systemli.org -static P_SYSTEMLI_ORG: Provider = Provider { - id: "systemli.org", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/systemli-org", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "mail.systemli.org", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "mail.systemli.org", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// t-online.md: t-online.de, magenta.de -static P_T_ONLINE: Provider = Provider { - id: "t-online", - status: Status::Preparation, - before_login_hint: "To use a T-Online email address, you need to create an app password in the web interface.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/t-online", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "secureimap.t-online.de", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "securesmtp.t-online.de", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// tiscali.it.md: tiscali.it -static P_TISCALI_IT: Provider = Provider { - id: "tiscali.it", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/tiscali-it", - server: &[ - 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, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// tutanota.md: tutanota.com, tutanota.de, tutamail.com, tuta.io, keemail.me -static P_TUTANOTA: Provider = Provider { - id: "tutanota", - status: Status::Broken, - before_login_hint: "Tutanota does not offer the standard IMAP e-mail protocol, so you cannot log in to Tutanota.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/tutanota", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// ukr.net.md: ukr.net -static P_UKR_NET: Provider = Provider { - id: "ukr.net", - status: Status::Preparation, - before_login_hint: "You must allow IMAP access to your account before you can login.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/ukr-net", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.ukr.net", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.ukr.net", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// undernet.uy.md: undernet.uy -static P_UNDERNET_UY: Provider = Provider { - id: "undernet.uy", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/undernet-uy", - server: &[ - Server { - protocol: Imap, - socket: Starttls, - hostname: "undernet.uy", - port: 143, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Starttls, - hostname: "undernet.uy", - port: 587, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// vfemail.md: vfemail.net -static P_VFEMAIL: Provider = Provider { - id: "vfemail", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/vfemail", - server: &[], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// vivaldi.md: vivaldi.net -static P_VIVALDI: Provider = Provider { - id: "vivaldi", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/vivaldi", - server: &[ - Server { - protocol: Imap, - socket: Starttls, - hostname: "imap.vivaldi.net", - port: 143, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Starttls, - hostname: "smtp.vivaldi.net", - port: 587, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// vk.com.md: vk.com -static P_VK_COM: Provider = Provider { - id: "vk.com", - status: Status::Preparation, - before_login_hint: "Вам необходимо сгенерировать \"пароль для внешнего приложения\" в веб-интерфейсе mail.ru https://account.mail.ru/user/2-step-auth/passwords/ чтобы vk.com работал с chatmail.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/vk-com", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.mail.ru", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.mail.ru", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// vodafone.de.md: vodafone.de, vodafonemail.de -static P_VODAFONE_DE: Provider = Provider { - id: "vodafone.de", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/vodafone-de", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.vodafonemail.de", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Starttls, - hostname: "smtp.vodafonemail.de", - port: 587, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// web.de.md: web.de, email.de, flirt.ms, hallo.ms, kuss.ms, love.ms, magic.ms, singles.ms, cool.ms, kanzler.ms, okay.ms, party.ms, pop.ms, stars.ms, techno.ms, clever.ms, deutschland.ms, genial.ms, ich.ms, online.ms, smart.ms, wichtig.ms, action.ms, fussball.ms, joker.ms, planet.ms, power.ms -static P_WEB_DE: Provider = Provider { - id: "web.de", - status: Status::Preparation, - before_login_hint: "You must allow IMAP access to your account before you can login.", - after_login_hint: "Note: if you have your web.de spam settings too strict, you won't receive contact requests from new people. If you want to receive contact requests, you should disable the \"3-Wege-Spamschutz\" in the web.de settings. Read how: https://hilfe.web.de/email/spam-und-viren/spamschutz-einstellungen.html", - overview_page: "https://providers.delta.chat/web-de", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.web.de", - port: 993, - username_pattern: Emaillocalpart, - }, - 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, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// wkpb.de.md: wkpb.de -static P_WKPB_DE: Provider = Provider { - id: "wkpb.de", - status: Status::Preparation, - before_login_hint: "Dies sind die gleichen Anmeldedaten wie bei Moodle und Abitur-Online.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/wkpb-de", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "pimap.schulon.org", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "psmtp.schulon.org", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - 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, myyahoo.com, ymail.com, rocketmail.com, yahoodns.net -static P_YAHOO: Provider = Provider { - id: "yahoo", - status: Status::Preparation, - before_login_hint: "To use your Yahoo email address you have to create an app password in the Yahoo account security screen.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/yahoo", - server: &[ - 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, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// yandex.ru.md: yandex.com, yandex.by, yandex.kz, yandex.ru, yandex.ua, ya.ru, narod.ru -static P_YANDEX_RU: Provider = Provider { - id: "yandex.ru", - status: Status::Preparation, - before_login_hint: "For Yandex accounts, you have to set IMAP protocol option turned on.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/yandex-ru", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.yandex.com", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.yandex.com", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// yggmail.md: yggmail -static P_YGGMAIL: Provider = Provider { - id: "yggmail", - status: Status::Preparation, - before_login_hint: "An Yggmail companion app needs to be installed on your device to access the Yggmail network.", - after_login_hint: "Make sure, the Yggmail companion app runs whenever you want to use this account. Note, that you usually cannot write from @yggmail addresses to normal e-mail-addresses (as @gmx.net). However, you can create another account in the normal e-mail-network for this purpose.", - overview_page: "https://providers.delta.chat/yggmail", - server: &[ - Server { - protocol: Imap, - socket: Plain, - hostname: "localhost", - port: 1143, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Plain, - hostname: "localhost", - port: 1025, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// ziggo.nl.md: ziggo.nl -static P_ZIGGO_NL: Provider = Provider { - id: "ziggo.nl", - status: Status::Ok, - before_login_hint: "", - after_login_hint: "", - overview_page: "https://providers.delta.chat/ziggo-nl", - server: &[ - 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, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -// zoho.md: zohomail.eu, zohomail.com, zoho.com -static P_ZOHO: Provider = Provider { - id: "zoho", - status: Status::Preparation, - before_login_hint: "To use Zoho Mail, you have to turn on IMAP in the Zoho Mail backend.", - after_login_hint: "", - overview_page: "https://providers.delta.chat/zoho", - server: &[ - Server { - protocol: Imap, - socket: Ssl, - hostname: "imap.zoho.eu", - port: 993, - username_pattern: Email, - }, - Server { - protocol: Smtp, - socket: Ssl, - hostname: "smtp.zoho.eu", - port: 465, - username_pattern: Email, - }, - ], - opt: ProviderOptions::new(), - config_defaults: None, -}; - -pub(crate) static PROVIDER_DATA: [(&str, &Provider); 521] = [ - ("163.com", &P_163), - ("aktivix.org", &P_AKTIVIX_ORG), - ("aliyun.com", &P_ALIYUN), - ("aol.com", &P_AOL), - ("arcor.de", &P_ARCOR_DE), - ("autistici.org", &P_AUTISTICI_ORG), - ("delta.blinzeln.de", &P_BLINDZELN_ORG), - ("delta.blindzeln.org", &P_BLINDZELN_ORG), - ("bluewin.ch", &P_BLUEWIN_CH), - ("chello.at", &P_CHELLO_AT), - ("xfinity.com", &P_COMCAST), - ("comcast.net", &P_COMCAST), - ("dismail.de", &P_DISMAIL_DE), - ("disroot.org", &P_DISROOT), - ("e.email", &P_E_EMAIL), - ("espiv.net", &P_ESPIV_NET), - ("example.com", &P_EXAMPLE_COM), - ("example.org", &P_EXAMPLE_COM), - ("example.net", &P_EXAMPLE_COM), - ("123mail.org", &P_FASTMAIL), - ("150mail.com", &P_FASTMAIL), - ("150ml.com", &P_FASTMAIL), - ("16mail.com", &P_FASTMAIL), - ("2-mail.com", &P_FASTMAIL), - ("4email.net", &P_FASTMAIL), - ("50mail.com", &P_FASTMAIL), - ("airpost.net", &P_FASTMAIL), - ("allmail.net", &P_FASTMAIL), - ("bestmail.us", &P_FASTMAIL), - ("cluemail.com", &P_FASTMAIL), - ("elitemail.org", &P_FASTMAIL), - ("emailcorner.net", &P_FASTMAIL), - ("emailengine.net", &P_FASTMAIL), - ("emailengine.org", &P_FASTMAIL), - ("emailgroups.net", &P_FASTMAIL), - ("emailplus.org", &P_FASTMAIL), - ("emailuser.net", &P_FASTMAIL), - ("eml.cc", &P_FASTMAIL), - ("f-m.fm", &P_FASTMAIL), - ("fast-email.com", &P_FASTMAIL), - ("fast-mail.org", &P_FASTMAIL), - ("fastem.com", &P_FASTMAIL), - ("fastemail.us", &P_FASTMAIL), - ("fastemailer.com", &P_FASTMAIL), - ("fastest.cc", &P_FASTMAIL), - ("fastimap.com", &P_FASTMAIL), - ("fastmail.cn", &P_FASTMAIL), - ("fastmail.co.uk", &P_FASTMAIL), - ("fastmail.com", &P_FASTMAIL), - ("fastmail.com.au", &P_FASTMAIL), - ("fastmail.de", &P_FASTMAIL), - ("fastmail.es", &P_FASTMAIL), - ("fastmail.fm", &P_FASTMAIL), - ("fastmail.fr", &P_FASTMAIL), - ("fastmail.im", &P_FASTMAIL), - ("fastmail.in", &P_FASTMAIL), - ("fastmail.jp", &P_FASTMAIL), - ("fastmail.mx", &P_FASTMAIL), - ("fastmail.net", &P_FASTMAIL), - ("fastmail.nl", &P_FASTMAIL), - ("fastmail.org", &P_FASTMAIL), - ("fastmail.se", &P_FASTMAIL), - ("fastmail.to", &P_FASTMAIL), - ("fastmail.tw", &P_FASTMAIL), - ("fastmail.uk", &P_FASTMAIL), - ("fastmail.us", &P_FASTMAIL), - ("fastmailbox.net", &P_FASTMAIL), - ("fastmessaging.com", &P_FASTMAIL), - ("fea.st", &P_FASTMAIL), - ("fmail.co.uk", &P_FASTMAIL), - ("fmailbox.com", &P_FASTMAIL), - ("fmgirl.com", &P_FASTMAIL), - ("fmguy.com", &P_FASTMAIL), - ("ftml.net", &P_FASTMAIL), - ("h-mail.us", &P_FASTMAIL), - ("hailmail.net", &P_FASTMAIL), - ("imap-mail.com", &P_FASTMAIL), - ("imap.cc", &P_FASTMAIL), - ("imapmail.org", &P_FASTMAIL), - ("inoutbox.com", &P_FASTMAIL), - ("internet-e-mail.com", &P_FASTMAIL), - ("internet-mail.org", &P_FASTMAIL), - ("internetemails.net", &P_FASTMAIL), - ("internetmailing.net", &P_FASTMAIL), - ("jetemail.net", &P_FASTMAIL), - ("justemail.net", &P_FASTMAIL), - ("letterboxes.org", &P_FASTMAIL), - ("mail-central.com", &P_FASTMAIL), - ("mail-page.com", &P_FASTMAIL), - ("mailandftp.com", &P_FASTMAIL), - ("mailas.com", &P_FASTMAIL), - ("mailbolt.com", &P_FASTMAIL), - ("mailc.net", &P_FASTMAIL), - ("mailcan.com", &P_FASTMAIL), - ("mailforce.net", &P_FASTMAIL), - ("mailftp.com", &P_FASTMAIL), - ("mailhaven.com", &P_FASTMAIL), - ("mailingaddress.org", &P_FASTMAIL), - ("mailite.com", &P_FASTMAIL), - ("mailmight.com", &P_FASTMAIL), - ("mailnew.com", &P_FASTMAIL), - ("mailsent.net", &P_FASTMAIL), - ("mailservice.ms", &P_FASTMAIL), - ("mailup.net", &P_FASTMAIL), - ("mailworks.org", &P_FASTMAIL), - ("ml1.net", &P_FASTMAIL), - ("mm.st", &P_FASTMAIL), - ("myfastmail.com", &P_FASTMAIL), - ("mymacmail.com", &P_FASTMAIL), - ("nospammail.net", &P_FASTMAIL), - ("ownmail.net", &P_FASTMAIL), - ("petml.com", &P_FASTMAIL), - ("postinbox.com", &P_FASTMAIL), - ("postpro.net", &P_FASTMAIL), - ("proinbox.com", &P_FASTMAIL), - ("promessage.com", &P_FASTMAIL), - ("realemail.net", &P_FASTMAIL), - ("reallyfast.biz", &P_FASTMAIL), - ("reallyfast.info", &P_FASTMAIL), - ("rushpost.com", &P_FASTMAIL), - ("sent.as", &P_FASTMAIL), - ("sent.at", &P_FASTMAIL), - ("sent.com", &P_FASTMAIL), - ("speedpost.net", &P_FASTMAIL), - ("speedymail.org", &P_FASTMAIL), - ("ssl-mail.com", &P_FASTMAIL), - ("swift-mail.com", &P_FASTMAIL), - ("the-fastest.net", &P_FASTMAIL), - ("the-quickest.com", &P_FASTMAIL), - ("theinternetemail.com", &P_FASTMAIL), - ("veryfast.biz", &P_FASTMAIL), - ("veryspeedy.net", &P_FASTMAIL), - ("warpmail.net", &P_FASTMAIL), - ("xsmail.com", &P_FASTMAIL), - ("yepmail.net", &P_FASTMAIL), - ("your-mail.com", &P_FASTMAIL), - ("firemail.at", &P_FIREMAIL_DE), - ("firemail.de", &P_FIREMAIL_DE), - ("freenet.de", &P_FREENET_DE), - ("gmail.com", &P_GMAIL), - ("googlemail.com", &P_GMAIL), - ("google.com", &P_GMAIL), - ("gmx.net", &P_GMX_NET), - ("gmx.de", &P_GMX_NET), - ("gmx.at", &P_GMX_NET), - ("gmx.ch", &P_GMX_NET), - ("gmx.org", &P_GMX_NET), - ("gmx.eu", &P_GMX_NET), - ("gmx.info", &P_GMX_NET), - ("gmx.biz", &P_GMX_NET), - ("gmx.com", &P_GMX_NET), - ("*.hermes.radio", &P_HERMES_RADIO), - ("*.aco-connexion.org", &P_HERMES_RADIO), - ("hey.com", &P_HEY_COM), - ("i.ua", &P_I_UA), - ("i3.net", &P_I3_NET), - ("icloud.com", &P_ICLOUD), - ("me.com", &P_ICLOUD), - ("mac.com", &P_ICLOUD), - ("ik.me", &P_INFOMANIAK_COM), - ("kolst.com", &P_KOLST_COM), - ("kontent.com", &P_KONTENT_COM), - ("email.com", &P_MAIL_COM), - ("groupmail.com", &P_MAIL_COM), - ("post.com", &P_MAIL_COM), - ("homemail.com", &P_MAIL_COM), - ("housemail.com", &P_MAIL_COM), - ("writeme.com", &P_MAIL_COM), - ("mail.com", &P_MAIL_COM), - ("mail-me.com", &P_MAIL_COM), - ("workmail.com", &P_MAIL_COM), - ("accountant.com", &P_MAIL_COM), - ("activist.com", &P_MAIL_COM), - ("adexec.com", &P_MAIL_COM), - ("allergist.com", &P_MAIL_COM), - ("alumni.com", &P_MAIL_COM), - ("alumnidirector.com", &P_MAIL_COM), - ("archaeologist.com", &P_MAIL_COM), - ("auctioneer.net", &P_MAIL_COM), - ("bartender.net", &P_MAIL_COM), - ("brew-master.com", &P_MAIL_COM), - ("chef.net", &P_MAIL_COM), - ("chemist.com", &P_MAIL_COM), - ("collector.org", &P_MAIL_COM), - ("columnist.com", &P_MAIL_COM), - ("comic.com", &P_MAIL_COM), - ("consultant.com", &P_MAIL_COM), - ("contractor.net", &P_MAIL_COM), - ("counsellor.com", &P_MAIL_COM), - ("deliveryman.com", &P_MAIL_COM), - ("diplomats.com", &P_MAIL_COM), - ("dr.com", &P_MAIL_COM), - ("engineer.com", &P_MAIL_COM), - ("financier.com", &P_MAIL_COM), - ("fireman.net", &P_MAIL_COM), - ("gardener.com", &P_MAIL_COM), - ("geologist.com", &P_MAIL_COM), - ("graphic-designer.com", &P_MAIL_COM), - ("graduate.org", &P_MAIL_COM), - ("hairdresser.net", &P_MAIL_COM), - ("instructor.net", &P_MAIL_COM), - ("insurer.com", &P_MAIL_COM), - ("journalist.com", &P_MAIL_COM), - ("legislator.com", &P_MAIL_COM), - ("lobbyist.com", &P_MAIL_COM), - ("minister.com", &P_MAIL_COM), - ("musician.org", &P_MAIL_COM), - ("optician.com", &P_MAIL_COM), - ("orthodontist.net", &P_MAIL_COM), - ("pediatrician.com", &P_MAIL_COM), - ("photographer.net", &P_MAIL_COM), - ("physicist.net", &P_MAIL_COM), - ("politician.com", &P_MAIL_COM), - ("presidency.com", &P_MAIL_COM), - ("priest.com", &P_MAIL_COM), - ("programmer.net", &P_MAIL_COM), - ("publicist.com", &P_MAIL_COM), - ("radiologist.net", &P_MAIL_COM), - ("realtyagent.com", &P_MAIL_COM), - ("registerednurses.com", &P_MAIL_COM), - ("repairman.com", &P_MAIL_COM), - ("representative.com", &P_MAIL_COM), - ("salesperson.net", &P_MAIL_COM), - ("secretary.net", &P_MAIL_COM), - ("socialworker.net", &P_MAIL_COM), - ("sociologist.com", &P_MAIL_COM), - ("songwriter.net", &P_MAIL_COM), - ("teachers.org", &P_MAIL_COM), - ("techie.com", &P_MAIL_COM), - ("technologist.com", &P_MAIL_COM), - ("therapist.net", &P_MAIL_COM), - ("umpire.com", &P_MAIL_COM), - ("worker.com", &P_MAIL_COM), - ("artlover.com", &P_MAIL_COM), - ("bikerider.com", &P_MAIL_COM), - ("birdlover.com", &P_MAIL_COM), - ("blader.com", &P_MAIL_COM), - ("kittymail.com", &P_MAIL_COM), - ("lovecat.com", &P_MAIL_COM), - ("marchmail.com", &P_MAIL_COM), - ("boardermail.com", &P_MAIL_COM), - ("catlover.com", &P_MAIL_COM), - ("clubmember.org", &P_MAIL_COM), - ("nonpartisan.com", &P_MAIL_COM), - ("petlover.com", &P_MAIL_COM), - ("doglover.com", &P_MAIL_COM), - ("greenmail.net", &P_MAIL_COM), - ("hackermail.com", &P_MAIL_COM), - ("theplate.com", &P_MAIL_COM), - ("bsdmail.com", &P_MAIL_COM), - ("computer4u.com", &P_MAIL_COM), - ("coolsite.net", &P_MAIL_COM), - ("cyberdude.com", &P_MAIL_COM), - ("cybergal.com", &P_MAIL_COM), - ("cyberservices.com", &P_MAIL_COM), - ("cyber-wizard.com", &P_MAIL_COM), - ("linuxmail.org", &P_MAIL_COM), - ("null.net", &P_MAIL_COM), - ("solution4u.com", &P_MAIL_COM), - ("tech-center.com", &P_MAIL_COM), - ("webname.com", &P_MAIL_COM), - ("acdcfan.com", &P_MAIL_COM), - ("angelic.com", &P_MAIL_COM), - ("discofan.com", &P_MAIL_COM), - ("elvisfan.com", &P_MAIL_COM), - ("hiphopfan.com", &P_MAIL_COM), - ("kissfans.com", &P_MAIL_COM), - ("madonnafan.com", &P_MAIL_COM), - ("metalfan.com", &P_MAIL_COM), - ("ninfan.com", &P_MAIL_COM), - ("ravemail.com", &P_MAIL_COM), - ("reggaefan.com", &P_MAIL_COM), - ("snakebite.com", &P_MAIL_COM), - ("bellair.net", &P_MAIL_COM), - ("californiamail.com", &P_MAIL_COM), - ("dallasmail.com", &P_MAIL_COM), - ("nycmail.com", &P_MAIL_COM), - ("pacific-ocean.com", &P_MAIL_COM), - ("pacificwest.com", &P_MAIL_COM), - ("sanfranmail.com", &P_MAIL_COM), - ("usa.com", &P_MAIL_COM), - ("africamail.com", &P_MAIL_COM), - ("asia-mail.com", &P_MAIL_COM), - ("australiamail.com", &P_MAIL_COM), - ("berlin.com", &P_MAIL_COM), - ("brazilmail.com", &P_MAIL_COM), - ("chinamail.com", &P_MAIL_COM), - ("dublin.com", &P_MAIL_COM), - ("dutchmail.com", &P_MAIL_COM), - ("englandmail.com", &P_MAIL_COM), - ("europe.com", &P_MAIL_COM), - ("arcticmail.com", &P_MAIL_COM), - ("europemail.com", &P_MAIL_COM), - ("germanymail.com", &P_MAIL_COM), - ("irelandmail.com", &P_MAIL_COM), - ("israelmail.com", &P_MAIL_COM), - ("italymail.com", &P_MAIL_COM), - ("koreamail.com", &P_MAIL_COM), - ("mexicomail.com", &P_MAIL_COM), - ("moscowmail.com", &P_MAIL_COM), - ("munich.com", &P_MAIL_COM), - ("asia.com", &P_MAIL_COM), - ("polandmail.com", &P_MAIL_COM), - ("safrica.com", &P_MAIL_COM), - ("samerica.com", &P_MAIL_COM), - ("scotlandmail.com", &P_MAIL_COM), - ("spainmail.com", &P_MAIL_COM), - ("swedenmail.com", &P_MAIL_COM), - ("swissmail.com", &P_MAIL_COM), - ("torontomail.com", &P_MAIL_COM), - ("aircraftmail.com", &P_MAIL_COM), - ("cash4u.com", &P_MAIL_COM), - ("disposable.com", &P_MAIL_COM), - ("execs.com", &P_MAIL_COM), - ("fastservice.com", &P_MAIL_COM), - ("instruction.com", &P_MAIL_COM), - ("job4u.com", &P_MAIL_COM), - ("net-shopping.com", &P_MAIL_COM), - ("planetmail.com", &P_MAIL_COM), - ("planetmail.net", &P_MAIL_COM), - ("qualityservice.com", &P_MAIL_COM), - ("rescueteam.com", &P_MAIL_COM), - ("surgical.net", &P_MAIL_COM), - ("atheist.com", &P_MAIL_COM), - ("disciples.com", &P_MAIL_COM), - ("muslim.com", &P_MAIL_COM), - ("protestant.com", &P_MAIL_COM), - ("reborn.com", &P_MAIL_COM), - ("reincarnate.com", &P_MAIL_COM), - ("religious.com", &P_MAIL_COM), - ("saintly.com", &P_MAIL_COM), - ("brew-meister.com", &P_MAIL_COM), - ("cutey.com", &P_MAIL_COM), - ("dbzmail.com", &P_MAIL_COM), - ("doramail.com", &P_MAIL_COM), - ("galaxyhit.com", &P_MAIL_COM), - ("hilarious.com", &P_MAIL_COM), - ("humanoid.net", &P_MAIL_COM), - ("hot-shot.com", &P_MAIL_COM), - ("inorbit.com", &P_MAIL_COM), - ("iname.com", &P_MAIL_COM), - ("innocent.com", &P_MAIL_COM), - ("keromail.com", &P_MAIL_COM), - ("myself.com", &P_MAIL_COM), - ("rocketship.com", &P_MAIL_COM), - ("toothfairy.com", &P_MAIL_COM), - ("toke.com", &P_MAIL_COM), - ("tvstar.com", &P_MAIL_COM), - ("uymail.com", &P_MAIL_COM), - ("2trom.com", &P_MAIL_COM), - ("mail.de", &P_MAIL_DE), - ("mail.ru", &P_MAIL_RU), - ("inbox.ru", &P_MAIL_RU), - ("internet.ru", &P_MAIL_RU), - ("bk.ru", &P_MAIL_RU), - ("list.ru", &P_MAIL_RU), - ("mail2tor.com", &P_MAIL2TOR), - ("mailbox.org", &P_MAILBOX_ORG), - ("secure.mailbox.org", &P_MAILBOX_ORG), - ("mailo.com", &P_MAILO_COM), - ("migadu.com", &P_MIGADU), - ("nauta.cu", &P_NAUTA_CU), - ("naver.com", &P_NAVER), - ("nine.testrun.org", &P_NINE_TESTRUN_ORG), - ("nubo.coop", &P_NUBO_COOP), - ("hotmail.com", &P_OUTLOOK_COM), - ("outlook.com", &P_OUTLOOK_COM), - ("office365.com", &P_OUTLOOK_COM), - ("outlook.com.tr", &P_OUTLOOK_COM), - ("live.com", &P_OUTLOOK_COM), - ("outlook.de", &P_OUTLOOK_COM), - ("ouvaton.org", &P_OUVATON_COOP), - ("posteo.de", &P_POSTEO), - ("posteo.af", &P_POSTEO), - ("posteo.at", &P_POSTEO), - ("posteo.be", &P_POSTEO), - ("posteo.ca", &P_POSTEO), - ("posteo.ch", &P_POSTEO), - ("posteo.cl", &P_POSTEO), - ("posteo.co", &P_POSTEO), - ("posteo.co.uk", &P_POSTEO), - ("posteo.com", &P_POSTEO), - ("posteo.com.br", &P_POSTEO), - ("posteo.cr", &P_POSTEO), - ("posteo.cz", &P_POSTEO), - ("posteo.dk", &P_POSTEO), - ("posteo.ee", &P_POSTEO), - ("posteo.es", &P_POSTEO), - ("posteo.eu", &P_POSTEO), - ("posteo.fi", &P_POSTEO), - ("posteo.gl", &P_POSTEO), - ("posteo.gr", &P_POSTEO), - ("posteo.hn", &P_POSTEO), - ("posteo.hr", &P_POSTEO), - ("posteo.hu", &P_POSTEO), - ("posteo.ie", &P_POSTEO), - ("posteo.in", &P_POSTEO), - ("posteo.is", &P_POSTEO), - ("posteo.it", &P_POSTEO), - ("posteo.jp", &P_POSTEO), - ("posteo.la", &P_POSTEO), - ("posteo.li", &P_POSTEO), - ("posteo.lt", &P_POSTEO), - ("posteo.lu", &P_POSTEO), - ("posteo.me", &P_POSTEO), - ("posteo.mx", &P_POSTEO), - ("posteo.my", &P_POSTEO), - ("posteo.net", &P_POSTEO), - ("posteo.nl", &P_POSTEO), - ("posteo.no", &P_POSTEO), - ("posteo.nz", &P_POSTEO), - ("posteo.org", &P_POSTEO), - ("posteo.pe", &P_POSTEO), - ("posteo.pl", &P_POSTEO), - ("posteo.pm", &P_POSTEO), - ("posteo.pt", &P_POSTEO), - ("posteo.ro", &P_POSTEO), - ("posteo.ru", &P_POSTEO), - ("posteo.se", &P_POSTEO), - ("posteo.sg", &P_POSTEO), - ("posteo.si", &P_POSTEO), - ("posteo.tn", &P_POSTEO), - ("posteo.uk", &P_POSTEO), - ("posteo.us", &P_POSTEO), - ("protonmail.com", &P_PROTONMAIL), - ("protonmail.ch", &P_PROTONMAIL), - ("pm.me", &P_PROTONMAIL), - ("purelymail.com", &P_PURELYMAIL_COM), - ("cheapermail.com", &P_PURELYMAIL_COM), - ("placeq.com", &P_PURELYMAIL_COM), - ("rethinkmail.com", &P_PURELYMAIL_COM), - ("worldofmail.com", &P_PURELYMAIL_COM), - ("qq.com", &P_QQ), - ("foxmail.com", &P_QQ), - ("rambler.ru", &P_RAMBLER_RU), - ("autorambler.ru", &P_RAMBLER_RU), - ("myrambler.ru", &P_RAMBLER_RU), - ("rambler.ua", &P_RAMBLER_RU), - ("lenta.ru", &P_RAMBLER_RU), - ("ro.ru", &P_RAMBLER_RU), - ("r0.ru", &P_RAMBLER_RU), - ("riseup.net", &P_RISEUP_NET), - ("rogers.com", &P_ROGERS_COM), - ("sonic.net", &P_SONIC), - ("stinpriza.net", &P_STINPRIZA_NET), - ("stinpriza.eu", &P_STINPRIZA_NET), - ("el-hoyo.net", &P_STINPRIZA_NET), - ("systemausfall.org", &P_SYSTEMAUSFALL_ORG), - ("solidaris.me", &P_SYSTEMAUSFALL_ORG), - ("systemli.org", &P_SYSTEMLI_ORG), - ("t-online.de", &P_T_ONLINE), - ("magenta.de", &P_T_ONLINE), - ("tiscali.it", &P_TISCALI_IT), - ("tutanota.com", &P_TUTANOTA), - ("tutanota.de", &P_TUTANOTA), - ("tutamail.com", &P_TUTANOTA), - ("tuta.io", &P_TUTANOTA), - ("keemail.me", &P_TUTANOTA), - ("ukr.net", &P_UKR_NET), - ("undernet.uy", &P_UNDERNET_UY), - ("vfemail.net", &P_VFEMAIL), - ("vivaldi.net", &P_VIVALDI), - ("vk.com", &P_VK_COM), - ("vodafone.de", &P_VODAFONE_DE), - ("vodafonemail.de", &P_VODAFONE_DE), - ("web.de", &P_WEB_DE), - ("email.de", &P_WEB_DE), - ("flirt.ms", &P_WEB_DE), - ("hallo.ms", &P_WEB_DE), - ("kuss.ms", &P_WEB_DE), - ("love.ms", &P_WEB_DE), - ("magic.ms", &P_WEB_DE), - ("singles.ms", &P_WEB_DE), - ("cool.ms", &P_WEB_DE), - ("kanzler.ms", &P_WEB_DE), - ("okay.ms", &P_WEB_DE), - ("party.ms", &P_WEB_DE), - ("pop.ms", &P_WEB_DE), - ("stars.ms", &P_WEB_DE), - ("techno.ms", &P_WEB_DE), - ("clever.ms", &P_WEB_DE), - ("deutschland.ms", &P_WEB_DE), - ("genial.ms", &P_WEB_DE), - ("ich.ms", &P_WEB_DE), - ("online.ms", &P_WEB_DE), - ("smart.ms", &P_WEB_DE), - ("wichtig.ms", &P_WEB_DE), - ("action.ms", &P_WEB_DE), - ("fussball.ms", &P_WEB_DE), - ("joker.ms", &P_WEB_DE), - ("planet.ms", &P_WEB_DE), - ("power.ms", &P_WEB_DE), - ("wkpb.de", &P_WKPB_DE), - ("yahoo.com", &P_YAHOO), - ("yahoo.de", &P_YAHOO), - ("yahoo.it", &P_YAHOO), - ("yahoo.fr", &P_YAHOO), - ("yahoo.es", &P_YAHOO), - ("yahoo.se", &P_YAHOO), - ("yahoo.co.uk", &P_YAHOO), - ("yahoo.co.nz", &P_YAHOO), - ("yahoo.com.au", &P_YAHOO), - ("yahoo.com.ar", &P_YAHOO), - ("yahoo.com.br", &P_YAHOO), - ("yahoo.com.mx", &P_YAHOO), - ("myyahoo.com", &P_YAHOO), - ("ymail.com", &P_YAHOO), - ("rocketmail.com", &P_YAHOO), - ("yahoodns.net", &P_YAHOO), - ("yandex.com", &P_YANDEX_RU), - ("yandex.by", &P_YANDEX_RU), - ("yandex.kz", &P_YANDEX_RU), - ("yandex.ru", &P_YANDEX_RU), - ("yandex.ua", &P_YANDEX_RU), - ("ya.ru", &P_YANDEX_RU), - ("narod.ru", &P_YANDEX_RU), - ("yggmail", &P_YGGMAIL), - ("ziggo.nl", &P_ZIGGO_NL), - ("zohomail.eu", &P_ZOHO), - ("zohomail.com", &P_ZOHO), - ("zoho.com", &P_ZOHO), -]; - -pub(crate) static PROVIDER_IDS: LazyLock> = - LazyLock::new(|| { - HashMap::from([ - ("163", &P_163), - ("aktivix.org", &P_AKTIVIX_ORG), - ("aliyun", &P_ALIYUN), - ("aol", &P_AOL), - ("arcor.de", &P_ARCOR_DE), - ("autistici.org", &P_AUTISTICI_ORG), - ("blindzeln.org", &P_BLINDZELN_ORG), - ("bluewin.ch", &P_BLUEWIN_CH), - ("chello.at", &P_CHELLO_AT), - ("comcast", &P_COMCAST), - ("dismail.de", &P_DISMAIL_DE), - ("disroot", &P_DISROOT), - ("e.email", &P_E_EMAIL), - ("espiv.net", &P_ESPIV_NET), - ("example.com", &P_EXAMPLE_COM), - ("fastmail", &P_FASTMAIL), - ("firemail.de", &P_FIREMAIL_DE), - ("freenet.de", &P_FREENET_DE), - ("gmail", &P_GMAIL), - ("gmx.net", &P_GMX_NET), - ("hermes.radio", &P_HERMES_RADIO), - ("hey.com", &P_HEY_COM), - ("i.ua", &P_I_UA), - ("i3.net", &P_I3_NET), - ("icloud", &P_ICLOUD), - ("infomaniak.com", &P_INFOMANIAK_COM), - ("kolst.com", &P_KOLST_COM), - ("kontent.com", &P_KONTENT_COM), - ("mail.com", &P_MAIL_COM), - ("mail.de", &P_MAIL_DE), - ("mail.ru", &P_MAIL_RU), - ("mail2tor", &P_MAIL2TOR), - ("mailbox.org", &P_MAILBOX_ORG), - ("mailo.com", &P_MAILO_COM), - ("migadu", &P_MIGADU), - ("nauta.cu", &P_NAUTA_CU), - ("naver", &P_NAVER), - ("nine.testrun.org", &P_NINE_TESTRUN_ORG), - ("nubo.coop", &P_NUBO_COOP), - ("outlook.com", &P_OUTLOOK_COM), - ("ouvaton.coop", &P_OUVATON_COOP), - ("posteo", &P_POSTEO), - ("protonmail", &P_PROTONMAIL), - ("purelymail.com", &P_PURELYMAIL_COM), - ("qq", &P_QQ), - ("rambler.ru", &P_RAMBLER_RU), - ("riseup.net", &P_RISEUP_NET), - ("rogers.com", &P_ROGERS_COM), - ("sonic", &P_SONIC), - ("stinpriza.net", &P_STINPRIZA_NET), - ("systemausfall.org", &P_SYSTEMAUSFALL_ORG), - ("systemli.org", &P_SYSTEMLI_ORG), - ("t-online", &P_T_ONLINE), - ("tiscali.it", &P_TISCALI_IT), - ("tutanota", &P_TUTANOTA), - ("ukr.net", &P_UKR_NET), - ("undernet.uy", &P_UNDERNET_UY), - ("vfemail", &P_VFEMAIL), - ("vivaldi", &P_VIVALDI), - ("vk.com", &P_VK_COM), - ("vodafone.de", &P_VODAFONE_DE), - ("web.de", &P_WEB_DE), - ("wkpb.de", &P_WKPB_DE), - ("yahoo", &P_YAHOO), - ("yandex.ru", &P_YANDEX_RU), - ("yggmail", &P_YGGMAIL), - ("ziggo.nl", &P_ZIGGO_NL), - ("zoho", &P_ZOHO), - ]) - }); - -pub static _PROVIDER_UPDATED: LazyLock = - LazyLock::new(|| chrono::NaiveDate::from_ymd_opt(2026, 5, 6).unwrap()); diff --git a/src/qr/dclogin_scheme.rs b/src/qr/dclogin_scheme.rs index 7459c66a71..97e06ceb87 100644 --- a/src/qr/dclogin_scheme.rs +++ b/src/qr/dclogin_scheme.rs @@ -5,10 +5,10 @@ use anyhow::{Context as _, Result, bail}; use deltachat_contact_tools::may_be_valid_addr; use super::{DCLOGIN_SCHEME, Qr}; +use crate::configure::server_params::Socket; use crate::login_param::{ EnteredCertificateChecks, EnteredImapLoginParam, EnteredLoginParam, EnteredSmtpLoginParam, }; -use crate::provider::Socket; /// Options for `dclogin:` scheme. #[derive(Debug, Clone, PartialEq, Eq)] diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index d1f901b5c6..fc1d8eb4a2 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -5,7 +5,6 @@ use std::collections::BTreeSet; use std::time::Duration; use anyhow::{Context as _, Result, ensure}; -use deltachat_contact_tools::EmailAddress; use deltachat_contact_tools::addr_cmp; use pgp::composed::SignedPublicKey; use rusqlite::OptionalExtension; @@ -15,7 +14,7 @@ use crate::configure::EnteredLoginParam; use crate::context::Context; use crate::key::DcKey; use crate::log::warn; -use crate::provider::get_provider_info; + use crate::sql::Sql; use crate::tools::{self, Time, inc_and_check, time_elapsed}; use crate::transport::ConfiguredLoginParam; @@ -1119,19 +1118,6 @@ UPDATE chats SET protected=1, type=120 WHERE type=130;"#, } if dbversion < 71 { - if let Ok(addr) = context.get_primary_self_addr().await { - if let Ok(domain) = EmailAddress::new(&addr).map(|email| email.domain) { - context - .set_config_internal( - Config::ConfiguredProvider, - get_provider_info(&domain).map(|provider| provider.id), - ) - .await?; - } else { - warn!(context, "Can't parse configured address: {:?}", addr); - } - } - sql.set_db_version(71).await?; } if dbversion < 72 && !sql.col_exists("msgs", "mime_modified").await? { diff --git a/src/transport.rs b/src/transport.rs index 82603e67f2..96d6bc6c91 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -16,13 +16,12 @@ use deltachat_contact_tools::{EmailAddress, addr_normalize}; use serde::{Deserialize, Serialize}; use crate::config::Config; -use crate::configure::server_params::{ServerParams, expand_param_vector}; use crate::context::Context; use crate::ensure_and_debug_assert; use crate::events::EventType; use crate::login_param::EnteredLoginParam; use crate::net::load_connection_timestamp; -use crate::provider::{Protocol, Provider, Socket, UsernamePattern, get_provider_by_id}; +use crate::provider::Socket; use crate::sql::Sql; use crate::sync::{RemovedTransportData, SyncData, TransportData}; @@ -69,9 +68,7 @@ impl TryFrom for ConnectionSecurity { #[repr(u32)] #[strum(serialize_all = "snake_case")] pub(crate) enum ConfiguredCertificateChecks { - /// Use configuration from the provider database. - /// If there is no provider database setting for certificate checks, - /// accept invalid certificates. + /// Accept invalid certificates. /// /// Must not be saved by new versions. /// @@ -95,9 +92,7 @@ pub(crate) enum ConfiguredCertificateChecks { /// Alias to `AcceptInvalidCertificates` for compatibility. AcceptInvalidCertificates2 = 3, - /// Use configuration from the provider database. - /// If there is no provider database setting for certificate checks, - /// apply strict checks to TLS certificates. + /// Apply strict checks to TLS certificates. Automatic = 4, } @@ -170,8 +165,7 @@ pub(crate) struct ConfiguredLoginParam { /// Custom IMAP user. /// - /// This overwrites autoconfig from the provider database - /// if non-empty. + /// This overwrites autoconfig if non-empty. pub imap_user: String, pub imap_password: String, @@ -187,14 +181,11 @@ pub(crate) struct ConfiguredLoginParam { /// Custom SMTP user. /// - /// This overwrites autoconfig from the provider database - /// if non-empty. + /// This overwrites autoconfig if non-empty. pub smtp_user: String, pub smtp_password: String, - pub provider: Option<&'static Provider>, - /// TLS options: whether to allow invalid certificates and/or /// invalid hostnames pub certificate_checks: ConfiguredCertificateChecks, @@ -218,16 +209,12 @@ pub(crate) struct ConfiguredLoginParamJson { pub smtp: Vec, pub smtp_user: String, pub smtp_password: String, - pub provider_id: Option, + pub certificate_checks: ConfiguredCertificateChecks, } impl fmt::Display for ConfiguredLoginParam { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let provider_id = match self.provider { - Some(provider) => provider.id, - None => "none", - }; let certificate_checks = self.certificate_checks; if let Ok(parsed_addr) = EmailAddress::new(&self.addr) { // Only include the domain. @@ -260,7 +247,7 @@ impl fmt::Display for ConfiguredLoginParam { write!(f, "{smtp}")?; first = false; } - write!(f, "] provider:{provider_id} cert_{certificate_checks}")?; + write!(f, "] cert_{certificate_checks}")?; Ok(()) } } @@ -344,12 +331,6 @@ impl ConfiguredLoginParam { .get_config(Config::ConfiguredMailPw) .await? .context("IMAP password is not configured")?; - - let provider = context - .get_config(Config::ConfiguredProvider) - .await? - .and_then(|cfg| get_provider_by_id(&cfg)); - let imap; let smtp; @@ -362,149 +343,7 @@ impl ConfiguredLoginParam { .await? .unwrap_or_default(); - if let Some(provider) = provider { - let parsed_addr = EmailAddress::new(&addr).context("Bad email-address")?; - let addr_localpart = parsed_addr.local; - - if provider.server.is_empty() { - let servers = vec![ - ServerParams { - protocol: Protocol::Imap, - hostname: context - .get_config(Config::ConfiguredMailServer) - .await? - .unwrap_or_default(), - port: context - .get_config_parsed::(Config::ConfiguredMailPort) - .await? - .unwrap_or_default(), - socket: context - .get_config_parsed::(Config::ConfiguredMailSecurity) - .await? - .and_then(num_traits::FromPrimitive::from_i32) - .unwrap_or_default(), - username: mail_user.clone(), - }, - ServerParams { - protocol: Protocol::Smtp, - hostname: context - .get_config(Config::ConfiguredSendServer) - .await? - .unwrap_or_default(), - port: context - .get_config_parsed::(Config::ConfiguredSendPort) - .await? - .unwrap_or_default(), - socket: context - .get_config_parsed::(Config::ConfiguredSendSecurity) - .await? - .and_then(num_traits::FromPrimitive::from_i32) - .unwrap_or_default(), - username: send_user.clone(), - }, - ]; - let servers = expand_param_vector(servers, &addr, &parsed_addr.domain); - imap = servers - .iter() - .filter_map(|params| { - let Ok(security) = params.socket.try_into() else { - return None; - }; - if params.protocol == Protocol::Imap { - Some(ConfiguredServerLoginParam { - connection: ConnectionCandidate { - host: params.hostname.clone(), - port: params.port, - security, - }, - user: params.username.clone(), - }) - } else { - None - } - }) - .collect(); - smtp = servers - .iter() - .filter_map(|params| { - let Ok(security) = params.socket.try_into() else { - return None; - }; - if params.protocol == Protocol::Smtp { - Some(ConfiguredServerLoginParam { - connection: ConnectionCandidate { - host: params.hostname.clone(), - port: params.port, - security, - }, - user: params.username.clone(), - }) - } else { - None - } - }) - .collect(); - } else { - imap = provider - .server - .iter() - .filter_map(|server| { - if server.protocol != Protocol::Imap { - return None; - } - - let Ok(security) = server.socket.try_into() else { - return None; - }; - - Some(ConfiguredServerLoginParam { - connection: ConnectionCandidate { - host: server.hostname.to_string(), - port: server.port, - security, - }, - user: if !mail_user.is_empty() { - mail_user.clone() - } else { - match server.username_pattern { - UsernamePattern::Email => addr.to_string(), - UsernamePattern::Emaillocalpart => addr_localpart.clone(), - } - }, - }) - }) - .collect(); - smtp = provider - .server - .iter() - .filter_map(|server| { - if server.protocol != Protocol::Smtp { - return None; - } - - let Ok(security) = server.socket.try_into() else { - return None; - }; - - Some(ConfiguredServerLoginParam { - connection: ConnectionCandidate { - host: server.hostname.to_string(), - port: server.port, - security, - }, - user: if !send_user.is_empty() { - send_user.clone() - } else { - match server.username_pattern { - UsernamePattern::Email => addr.to_string(), - UsernamePattern::Emaillocalpart => addr_localpart.clone(), - } - }, - }) - }) - .collect(); - } - } else if let (Some(configured_mail_servers), Some(configured_send_servers)) = ( + if let (Some(configured_mail_servers), Some(configured_send_servers)) = ( context.get_config(Config::ConfiguredImapServers).await?, context.get_config(Config::ConfiguredSmtpServers).await?, ) { @@ -571,7 +410,6 @@ impl ConfiguredLoginParam { smtp_user: send_user, smtp_password: send_pw, certificate_checks, - provider, })) } @@ -602,7 +440,6 @@ impl ConfiguredLoginParam { .is_none_or(|folder| !folder.is_empty()), "Configured watched folder name cannot be empty" ); - let provider = json.provider_id.and_then(|id| get_provider_by_id(&id)); Ok(ConfiguredLoginParam { addr: json.addr, @@ -613,7 +450,7 @@ impl ConfiguredLoginParam { smtp: json.smtp, smtp_user: json.smtp_user, smtp_password: json.smtp_password, - provider, + certificate_checks: json.certificate_checks, }) } @@ -624,13 +461,9 @@ impl ConfiguredLoginParam { } pub(crate) fn strict_tls(&self, connected_through_proxy: bool) -> bool { - let provider_strict_tls = self.provider.map(|provider| provider.opt.strict_tls); match self.certificate_checks { - ConfiguredCertificateChecks::OldAutomatic => { - provider_strict_tls.unwrap_or(connected_through_proxy) - } - ConfiguredCertificateChecks::Automatic => provider_strict_tls.unwrap_or(true), - ConfiguredCertificateChecks::Strict => true, + ConfiguredCertificateChecks::OldAutomatic => connected_through_proxy, + ConfiguredCertificateChecks::Automatic | ConfiguredCertificateChecks::Strict => true, ConfiguredCertificateChecks::AcceptInvalidCertificates | ConfiguredCertificateChecks::AcceptInvalidCertificates2 => false, } @@ -648,7 +481,7 @@ impl From for ConfiguredLoginParamJson { smtp: configured_login_param.smtp, smtp_user: configured_login_param.smtp_user, smtp_password: configured_login_param.smtp_password, - provider_id: configured_login_param.provider.map(|p| p.id.to_string()), + certificate_checks: configured_login_param.certificate_checks, } } diff --git a/src/transport/transport_tests.rs b/src/transport/transport_tests.rs index d0d41e3be7..f31661ca06 100644 --- a/src/transport/transport_tests.rs +++ b/src/transport/transport_tests.rs @@ -4,8 +4,6 @@ use std::time::Duration; use crate::tools::SystemTime; use super::*; -use crate::log::LogExt as _; -use crate::provider::get_provider_by_id; use crate::test_utils::TestContext; use crate::test_utils::TestContextManager; use crate::tools::time; @@ -47,7 +45,6 @@ async fn test_save_load_login_param() -> Result<()> { }], smtp_user: "".to_string(), smtp_password: "bar".to_string(), - provider: None, certificate_checks: ConfiguredCertificateChecks::Strict, }; @@ -55,7 +52,7 @@ async fn test_save_load_login_param() -> Result<()> { .clone() .save_to_transports_table(&t, &EnteredLoginParam::default(), time()) .await?; - let expected_param = r#"{"addr":"alice@example.org","imap":[{"connection":{"host":"imap.example.com","port":123,"security":"Starttls"},"user":"alice"}],"imap_folder":"Folder","imap_user":"","imap_password":"foo","smtp":[{"connection":{"host":"smtp.example.com","port":456,"security":"Tls"},"user":"alice@example.org"}],"smtp_user":"","smtp_password":"bar","provider_id":null,"certificate_checks":"Strict"}"#; + let expected_param = r#"{"addr":"alice@example.org","imap":[{"connection":{"host":"imap.example.com","port":123,"security":"Starttls"},"user":"alice"}],"imap_folder":"Folder","imap_user":"","imap_password":"foo","smtp":[{"connection":{"host":"smtp.example.com","port":456,"security":"Tls"},"user":"alice@example.org"}],"smtp_user":"","smtp_password":"bar","certificate_checks":"Strict"}"#; assert_eq!( t.sql .query_get_value::("SELECT configured_param FROM transports", ()) @@ -72,7 +69,6 @@ async fn test_save_load_login_param() -> Result<()> { assert!(formatted.contains(" imap:[imap.example.com:123:starttls]")); assert!(formatted.contains(" folder:\"Folder\"")); assert!(formatted.contains(" smtp:[smtp.example.com:456:tls]")); - assert!(formatted.contains(" provider:none")); assert!(formatted.contains(" cert_strict")); // Legacy ConfiguredImapCertificateChecks config is ignored @@ -91,176 +87,7 @@ async fn test_save_load_login_param() -> Result<()> { Ok(()) } -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn test_posteo_alias() -> Result<()> { - let t = TestContext::new().await; - - let user = "alice@posteo.de"; - - // Alice has old config with "alice@posteo.at" address - // and "alice@posteo.de" username. - t.set_config(Config::Configured, Some("1")).await?; - t.set_config(Config::ConfiguredProvider, Some("posteo")) - .await?; - t.sql - .set_raw_config(Config::ConfiguredAddr.as_ref(), Some("alice@posteo.at")) - .await?; - t.set_config(Config::ConfiguredMailServer, Some("posteo.de")) - .await?; - t.set_config(Config::ConfiguredMailPort, Some("993")) - .await?; - t.set_config(Config::ConfiguredMailSecurity, Some("1")) - .await?; // TLS - t.set_config(Config::ConfiguredMailUser, Some(user)).await?; - t.set_config(Config::ConfiguredMailPw, Some("foobarbaz")) - .await?; - t.set_config(Config::ConfiguredImapCertificateChecks, Some("1")) - .await?; // Strict - t.set_config(Config::ConfiguredSendServer, Some("posteo.de")) - .await?; - t.set_config(Config::ConfiguredSendPort, Some("465")) - .await?; - t.set_config(Config::ConfiguredSendSecurity, Some("1")) - .await?; // TLS - t.set_config(Config::ConfiguredSendUser, Some(user)).await?; - t.set_config(Config::ConfiguredSendPw, Some("foobarbaz")) - .await?; - - let param = ConfiguredLoginParam { - addr: "alice@posteo.at".to_string(), - imap: vec![ - ConfiguredServerLoginParam { - connection: ConnectionCandidate { - host: "posteo.de".to_string(), - port: 993, - security: ConnectionSecurity::Tls, - }, - user: user.to_string(), - }, - ConfiguredServerLoginParam { - connection: ConnectionCandidate { - host: "posteo.de".to_string(), - port: 143, - security: ConnectionSecurity::Starttls, - }, - user: user.to_string(), - }, - ], - imap_folder: None, - imap_user: "alice@posteo.de".to_string(), - imap_password: "foobarbaz".to_string(), - smtp: vec![ - ConfiguredServerLoginParam { - connection: ConnectionCandidate { - host: "posteo.de".to_string(), - port: 465, - security: ConnectionSecurity::Tls, - }, - user: user.to_string(), - }, - ConfiguredServerLoginParam { - connection: ConnectionCandidate { - host: "posteo.de".to_string(), - port: 587, - security: ConnectionSecurity::Starttls, - }, - user: user.to_string(), - }, - ], - smtp_user: "alice@posteo.de".to_string(), - smtp_password: "foobarbaz".to_string(), - provider: get_provider_by_id("posteo"), - certificate_checks: ConfiguredCertificateChecks::Strict, - }; - - let loaded = ConfiguredLoginParam::load_legacy(&t).await?.unwrap(); - assert_eq!(loaded, param); - - migrate_configured_login_param(&t).await; - let (_transport_id, loaded) = ConfiguredLoginParam::load(&t).await?.unwrap(); - assert_eq!(loaded, param); - - Ok(()) -} - -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn test_empty_server_list_legacy() -> Result<()> { - // Find a provider that does not have server list set. - // - // There is at least one such provider in the provider database. - let (domain, provider) = crate::provider::data::PROVIDER_DATA - .iter() - .find(|(_domain, provider)| provider.server.is_empty()) - .unwrap(); - - let t = TestContext::new().await; - - let addr = format!("alice@{domain}"); - - t.set_config(Config::Configured, Some("1")).await?; - t.set_config(Config::ConfiguredProvider, Some(provider.id)) - .await?; - t.sql - .set_raw_config(Config::ConfiguredAddr.as_ref(), Some(&addr)) - .await?; - t.set_config(Config::ConfiguredMailPw, Some("foobarbaz")) - .await?; - t.set_config(Config::ConfiguredImapCertificateChecks, Some("1")) - .await?; // Strict - t.set_config(Config::ConfiguredSendPw, Some("foobarbaz")) - .await?; - - let loaded = ConfiguredLoginParam::load_legacy(&t).await?.unwrap(); - assert_eq!(loaded.provider, Some(*provider)); - assert_eq!(loaded.imap.is_empty(), false); - assert_eq!(loaded.smtp.is_empty(), false); - - migrate_configured_login_param(&t).await; - - let (_transport_id, loaded) = ConfiguredLoginParam::load(&t).await?.unwrap(); - assert_eq!(loaded.provider, Some(*provider)); - assert_eq!(loaded.imap.is_empty(), false); - assert_eq!(loaded.smtp.is_empty(), false); - - Ok(()) -} - -async fn migrate_configured_login_param(t: &TestContext) { - t.sql.execute("DROP TABLE transports;", ()).await.unwrap(); - t.sql.set_raw_config_int("dbversion", 130).await.unwrap(); - t.sql.run_migrations(t).await.log_err(t).ok(); -} - -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn test_empty_server_list() -> Result<()> { - // Find a provider that does not have server list set. - // - // There is at least one such provider in the provider database. - let (domain, provider) = crate::provider::data::PROVIDER_DATA - .iter() - .find(|(_domain, provider)| provider.server.is_empty()) - .unwrap(); - - let t = TestContext::new().await; - - let addr = format!("alice@{domain}"); - - dummy_configured_login_param(&addr, Some(provider)) - .save_to_transports_table(&t, &EnteredLoginParam::default(), time()) - .await?; - - let (_transport_id, loaded) = ConfiguredLoginParam::load(&t).await?.unwrap(); - assert_eq!(loaded.provider, Some(*provider)); - assert_eq!(loaded.imap.is_empty(), false); - assert_eq!(loaded.smtp.is_empty(), false); - - Ok(()) -} - -fn dummy_configured_login_param( - addr: &str, - provider: Option<&'static Provider>, -) -> ConfiguredLoginParam { +fn dummy_configured_login_param(addr: &str) -> ConfiguredLoginParam { ConfiguredLoginParam { addr: addr.to_string(), imap: vec![ConfiguredServerLoginParam { @@ -284,7 +111,6 @@ fn dummy_configured_login_param( }], smtp_user: addr.to_string(), smtp_password: "foobarbaz".to_string(), - provider, certificate_checks: ConfiguredCertificateChecks::Automatic, } } @@ -312,7 +138,7 @@ async fn test_is_published_flag() -> Result<()> { ) .await; - dummy_configured_login_param("alice@otherprovider.com", None) + dummy_configured_login_param("alice@otherprovider.com") .save_to_transports_table( alice, &EnteredLoginParam { From fbf28940fdf721eb21226860201e89d620ae3d29 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Tue, 21 Jul 2026 10:29:05 +0200 Subject: [PATCH 2/4] add nauta.cu, hermes.radio and *.aco-connexion.org legacy options --- deltachat-repl/src/cmdline.rs | 2 +- src/configure.rs | 30 ++++++++- src/context.rs | 8 ++- src/provider.rs | 121 ++++++++++++++++++++++++++++++++++ src/transport.rs | 13 +++- 5 files changed, 168 insertions(+), 6 deletions(-) diff --git a/deltachat-repl/src/cmdline.rs b/deltachat-repl/src/cmdline.rs index 3c58e65849..244403100e 100644 --- a/deltachat-repl/src/cmdline.rs +++ b/deltachat-repl/src/cmdline.rs @@ -8,6 +8,7 @@ use std::time::Duration; use anyhow::{bail, ensure, Result}; use deltachat::chat::{self, Chat, ChatId, ChatItem, ChatVisibility, MuteDuration}; use deltachat::chatlist::*; +use deltachat::config; use deltachat::constants::*; use deltachat::contact::*; use deltachat::context::*; @@ -24,7 +25,6 @@ use deltachat::reaction::send_reaction; use deltachat::receive_imf::*; use deltachat::sql; use deltachat::tools::*; -use deltachat::config; use tokio::fs; /// Reset database tables. diff --git a/src/configure.rs b/src/configure.rs index e92a31616d..16b4fd5571 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -29,9 +29,10 @@ use crate::log::warn; pub use crate::login_param::EnteredLoginParam; use crate::login_param::{EnteredCertificateChecks, TransportListEntry}; use crate::net::proxy::ProxyConfig; -use crate::provider::{Protocol, Socket}; +use crate::provider::{self, Protocol, Socket}; use crate::qr::{login_param_from_account_qr, login_param_from_login_qr}; use crate::smtp::Smtp; +use crate::sync::Sync::Nosync; use crate::tools::time; use crate::transport::{ ConfiguredCertificateChecks, ConfiguredLoginParam, ConfiguredServerLoginParam, @@ -352,6 +353,7 @@ impl Context { }; self.set_config_internal(Config::NotifyAboutWrongPw, Some("1")) .await?; + apply_legacy_domain_config_defaults(self, ¶m.addr).await?; Ok(()) } @@ -392,6 +394,24 @@ impl Context { } } +/// Applies a few select non-default config values that used to come from provider database. +async fn apply_legacy_domain_config_defaults(context: &Context, addr: &str) -> Result<()> { + let settings = provider::legacy_settings_for_addr(addr); + + if settings.disable_mdns && !context.config_exists(Config::MdnsEnabled).await? { + context + .set_config_ex(Nosync, Config::MdnsEnabled, Some("0")) + .await?; + } + + if settings.worse_media_quality && !context.config_exists(Config::MediaQuality).await? { + context + .set_config_ex(Nosync, Config::MediaQuality, Some("1")) + .await?; + } + Ok(()) +} + /// Retrieves data from autoconfig /// to transform user-entered login parameters into complete configuration. async fn get_configured_param( @@ -427,7 +447,13 @@ async fn get_configured_param( && param.smtp.user.is_empty() { // no advanced parameters entered by the user: do Autoconfig - param_autoconfig = get_autoconfig(ctx, param, ¶m_domain).await; + // except for a few known legacy-domain overrides. + let legacy_servers = provider::legacy_settings_for_addr(¶m.addr).autoconfig_servers; + param_autoconfig = if legacy_servers.is_some() { + legacy_servers + } else { + get_autoconfig(ctx, param, ¶m_domain).await + }; } else { param_autoconfig = None; } diff --git a/src/context.rs b/src/context.rs index 44c124b055..b8842383be 100644 --- a/src/context.rs +++ b/src/context.rs @@ -574,9 +574,10 @@ impl Context { /// Returns maximum number of recipients a single email can be sent to. pub(crate) async fn get_max_smtp_rcpt_to(&self) -> Result { - let Some((transport_id, _param)) = ConfiguredLoginParam::load(self).await? else { + let Some((transport_id, param)) = ConfiguredLoginParam::load(self).await? else { bail!("Not configured"); }; + // A relay advertising its own limit via IMAP METADATA is authoritative. let metadata_limit = self .metadata .read() @@ -586,6 +587,11 @@ impl Context { if let Some(limit) = metadata_limit { return Ok(limit); } + // A few legacy domains (e.g. nauta.cu) need a hard-coded limit. + if let Some(limit) = crate::provider::legacy_settings_for_addr(¶m.addr).max_smtp_rcpt_to + { + return Ok(limit as u32); + } Ok(constants::DEFAULT_MAX_SMTP_RCPT_TO) } diff --git a/src/provider.rs b/src/provider.rs index b12d827ecb..00c79b5b79 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -1,7 +1,10 @@ //! Provider types. +use deltachat_contact_tools::EmailAddress; use serde::{Deserialize, Serialize}; +use crate::configure::server_params::ServerParams; + /// Server protocol. #[derive(Debug, Display, PartialEq, Eq, Copy, Clone, FromPrimitive, ToPrimitive)] #[repr(u8)] @@ -53,3 +56,121 @@ pub enum UsernamePattern { /// Part of address before `@` is used as username. Emaillocalpart = 2, } + +/// Returns true if `domain` is `suffix` itself or a subdomain of it. +fn is_exact_or_subdomain(domain: &str, suffix: &str) -> bool { + domain == suffix || domain.ends_with(&format!(".{suffix}")) +} + +/// Non-default settings that used to be looked up in provider.db for a few domains. +#[derive(Debug, Clone, PartialEq, Default)] +pub(crate) struct LegacyProviderSettings { + /// Servers to use instead of autoconfig, if any. + pub autoconfig_servers: Option>, + + /// Maximum number of recipients allowed in a single SMTP send, if limited. + pub max_smtp_rcpt_to: Option, + + /// Whether to disable strict TLS certificate checks by default. + pub disable_strict_tls: bool, + + /// Whether to disable local network contact discovery (mDNS) by default. + pub disable_mdns: bool, + + /// Whether to default to worse media quality (for slow/expensive connections). + pub worse_media_quality: bool, +} + +/// Returns hard-coded legacy settings for the domain of `addr`. +/// +/// Provider.db lookup was removed, but a handful of domains still need these overrides, +/// so they are hard-coded here instead. +pub(crate) fn legacy_settings_for_addr(addr: &str) -> LegacyProviderSettings { + let Ok(email) = EmailAddress::new(addr) else { + return LegacyProviderSettings::default(); + }; + let domain = email.domain.to_ascii_lowercase(); + + match domain.as_str() { + "nauta.cu" => LegacyProviderSettings { + autoconfig_servers: Some(vec![ + ServerParams { + protocol: Protocol::Imap, + socket: Socket::Starttls, + hostname: "imap.nauta.cu".to_string(), + port: 143, + username: String::new(), + }, + ServerParams { + protocol: Protocol::Smtp, + socket: Socket::Starttls, + hostname: "smtp.nauta.cu".to_string(), + port: 25, + username: String::new(), + }, + ]), + max_smtp_rcpt_to: Some(20), + disable_strict_tls: true, + worse_media_quality: true, + ..Default::default() + }, + _ if is_exact_or_subdomain(&domain, "hermes.radio") + || domain.ends_with(".aco-connexion.org") => + { + LegacyProviderSettings { + disable_strict_tls: true, + disable_mdns: true, + ..Default::default() + } + } + _ => LegacyProviderSettings { + autoconfig_servers: None, + max_smtp_rcpt_to: None, + disable_strict_tls: false, + disable_mdns: false, + worse_media_quality: false, + }, + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_legacy_domain_overrides() { + let nauta = legacy_settings_for_addr("alice@nauta.cu"); + assert_eq!(nauta.max_smtp_rcpt_to, Some(20)); + assert!(nauta.disable_strict_tls); + assert!(nauta.worse_media_quality); + let servers = nauta.autoconfig_servers.unwrap(); + assert_eq!(servers.len(), 2); + assert_eq!(servers[0].hostname, "imap.nauta.cu"); + assert_eq!(servers[1].hostname, "smtp.nauta.cu"); + + let hermes = legacy_settings_for_addr("alice@foo.hermes.radio"); + assert!(hermes.disable_strict_tls); + assert!(hermes.disable_mdns); + // hermes.radio itself (not just its subdomains) is also a valid provider domain. + assert!(legacy_settings_for_addr("alice@hermes.radio").disable_strict_tls); + + let aco = legacy_settings_for_addr("alice@foo.aco-connexion.org"); + assert!(aco.disable_strict_tls); + assert!(aco.disable_mdns); + // Unlike hermes.radio, aco-connexion.org itself is not a valid provider domain, + // only its subdomains are (matching the original provider.db entries). + let not_aco = legacy_settings_for_addr("alice@aco-connexion.org"); + assert_eq!(not_aco.autoconfig_servers, None); + assert_eq!(not_aco.max_smtp_rcpt_to, None); + assert!(!not_aco.disable_strict_tls); + assert!(!not_aco.disable_mdns); + assert!(!not_aco.worse_media_quality); + + let unknown = legacy_settings_for_addr("alice@example.org"); + assert_eq!(unknown.autoconfig_servers, None); + assert_eq!(unknown.max_smtp_rcpt_to, None); + assert!(!unknown.disable_strict_tls); + assert!(!unknown.disable_mdns); + assert!(!unknown.worse_media_quality); + } +} diff --git a/src/transport.rs b/src/transport.rs index 96d6bc6c91..9516040135 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -461,9 +461,18 @@ impl ConfiguredLoginParam { } pub(crate) fn strict_tls(&self, connected_through_proxy: bool) -> bool { + let disable_strict_tls = + crate::provider::legacy_settings_for_addr(&self.addr).disable_strict_tls; match self.certificate_checks { - ConfiguredCertificateChecks::OldAutomatic => connected_through_proxy, - ConfiguredCertificateChecks::Automatic | ConfiguredCertificateChecks::Strict => true, + ConfiguredCertificateChecks::OldAutomatic => { + if disable_strict_tls { + false + } else { + connected_through_proxy + } + } + ConfiguredCertificateChecks::Automatic => !disable_strict_tls, + ConfiguredCertificateChecks::Strict => true, ConfiguredCertificateChecks::AcceptInvalidCertificates | ConfiguredCertificateChecks::AcceptInvalidCertificates2 => false, } From 0c46959a4c1807102e3b19df973d493beaaa4d7e Mon Sep 17 00:00:00 2001 From: holger krekel Date: Tue, 21 Jul 2026 13:50:45 +0200 Subject: [PATCH 3/4] fixup CI failures --- deltachat-jsonrpc/typescript/test/online.ts | 1 - deltachat-rpc-client/tests/test_something.py | 22 ------------ python/tests/test_4_lowlevel.py | 8 ----- src/configure.rs | 38 +++++++++----------- 4 files changed, 17 insertions(+), 52 deletions(-) diff --git a/deltachat-jsonrpc/typescript/test/online.ts b/deltachat-jsonrpc/typescript/test/online.ts index 97f97fb515..e6bdf59759 100644 --- a/deltachat-jsonrpc/typescript/test/online.ts +++ b/deltachat-jsonrpc/typescript/test/online.ts @@ -148,7 +148,6 @@ describe("online tests", function () { expect(message2.text).equal("super secret message"); expect(message2.showPadlock).equal(true); }); - }); async function waitForEvent( diff --git a/deltachat-rpc-client/tests/test_something.py b/deltachat-rpc-client/tests/test_something.py index 1efb7c48de..214dfc730b 100644 --- a/deltachat-rpc-client/tests/test_something.py +++ b/deltachat-rpc-client/tests/test_something.py @@ -747,28 +747,6 @@ def test_early_failure(tmp_path) -> None: rpc.start() -def test_provider_info(rpc) -> None: - account_id = rpc.add_account() - - provider_info = rpc.get_provider_info(account_id, "example.org") - assert provider_info["id"] == "example.com" - - provider_info = rpc.get_provider_info(account_id, "uep7oiw4ahtaizuloith.org") - assert provider_info is None - - # Test MX record resolution. - # This previously resulted in Gmail provider - # because MX record pointed to google.com domain, - # but MX record resolution has been removed. - provider_info = rpc.get_provider_info(account_id, "github.com") - assert provider_info is None - - # Disable MX record resolution. - rpc.set_config(account_id, "proxy_enabled", "1") - provider_info = rpc.get_provider_info(account_id, "github.com") - assert provider_info is None - - def test_mdn_doesnt_break_autocrypt(acfactory) -> None: alice, bob = acfactory.get_online_accounts(2) diff --git a/python/tests/test_4_lowlevel.py b/python/tests/test_4_lowlevel.py index b70248fc22..683263f97e 100644 --- a/python/tests/test_4_lowlevel.py +++ b/python/tests/test_4_lowlevel.py @@ -171,14 +171,6 @@ def test_get_special_message_id_returns_empty_message(acfactory): assert msg.id == 0 -def test_provider_info_none(): - ctx = ffi.gc( - lib.dc_context_new(ffi.NULL, ffi.NULL, ffi.NULL), - lib.dc_context_unref, - ) - assert lib.dc_provider_new_from_email(ctx, cutil.as_dc_charpointer("email@unexistent.no")) == ffi.NULL - - def test_get_info_open(tmp_path): db_fname = tmp_path / "test.db" ctx = ffi.gc( diff --git a/src/configure.rs b/src/configure.rs index 16b4fd5571..bee801beb4 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -335,21 +335,18 @@ impl Context { self.try_make_space_for_new_relay().await?; } - match configure(self, param).await { - Err(error) => { - // Log entered and actual params - let configured_param = get_configured_param(self, param).await; - warn!( - self, - "configure failed: Entered params: {}. Used params: {}. Error: {error}.", - param.to_string(), - configured_param - .map(|param| param.to_string()) - .unwrap_or("error".to_owned()) - ); - return Err(error); - } - Ok(()) => (), + if let Err(error) = configure(self, param).await { + // Log entered and actual params + let configured_param = get_configured_param(self, param).await; + warn!( + self, + "configure failed: Entered params: {}. Used params: {}. Error: {error}.", + param.to_string(), + configured_param + .map(|param| param.to_string()) + .unwrap_or("error".to_owned()) + ); + return Err(error); }; self.set_config_internal(Config::NotifyAboutWrongPw, Some("1")) .await?; @@ -436,8 +433,7 @@ async fn get_configured_param( progress!(ctx, 200); - let param_autoconfig; - if param.imap.server.is_empty() + let param_autoconfig = if param.imap.server.is_empty() && param.imap.port == 0 && param.imap.security == Socket::Automatic && param.imap.user.is_empty() @@ -449,14 +445,14 @@ async fn get_configured_param( // no advanced parameters entered by the user: do Autoconfig // except for a few known legacy-domain overrides. let legacy_servers = provider::legacy_settings_for_addr(¶m.addr).autoconfig_servers; - param_autoconfig = if legacy_servers.is_some() { + if legacy_servers.is_some() { legacy_servers } else { get_autoconfig(ctx, param, ¶m_domain).await - }; + } } else { - param_autoconfig = None; - } + None + }; progress!(ctx, 500); From 2bfe06758b55b300e1e58550188d9b77a6795f25 Mon Sep 17 00:00:00 2001 From: holger krekel Date: Wed, 22 Jul 2026 20:36:35 +0200 Subject: [PATCH 4/4] address link2xt comments --- deltachat-jsonrpc/src/api/types/login_param.rs | 3 ++- src/context.rs | 4 +--- src/login_param.rs | 3 ++- src/provider.rs | 2 +- src/sql/migrations.rs | 4 +--- src/transport.rs | 12 ++++-------- 6 files changed, 11 insertions(+), 17 deletions(-) diff --git a/deltachat-jsonrpc/src/api/types/login_param.rs b/deltachat-jsonrpc/src/api/types/login_param.rs index de3f54b98b..72b8fd66b1 100644 --- a/deltachat-jsonrpc/src/api/types/login_param.rs +++ b/deltachat-jsonrpc/src/api/types/login_param.rs @@ -168,7 +168,8 @@ impl From for dc::Socket { #[derive(Serialize, Deserialize, TypeDef, schemars::JsonSchema, Default, PartialEq)] #[serde(rename_all = "camelCase")] pub enum EnteredCertificateChecks { - /// `Automatic` means strict certificate checks. + /// `Automatic` means strict certificate checks, + /// unless a legacy-domain override disables them. #[default] Automatic, diff --git a/src/context.rs b/src/context.rs index b8842383be..0930bd86c1 100644 --- a/src/context.rs +++ b/src/context.rs @@ -577,7 +577,6 @@ impl Context { let Some((transport_id, param)) = ConfiguredLoginParam::load(self).await? else { bail!("Not configured"); }; - // A relay advertising its own limit via IMAP METADATA is authoritative. let metadata_limit = self .metadata .read() @@ -587,10 +586,9 @@ impl Context { if let Some(limit) = metadata_limit { return Ok(limit); } - // A few legacy domains (e.g. nauta.cu) need a hard-coded limit. if let Some(limit) = crate::provider::legacy_settings_for_addr(¶m.addr).max_smtp_rcpt_to { - return Ok(limit as u32); + return Ok(limit); } Ok(constants::DEFAULT_MAX_SMTP_RCPT_TO) } diff --git a/src/login_param.rs b/src/login_param.rs index 9f6738c07a..723621b432 100644 --- a/src/login_param.rs +++ b/src/login_param.rs @@ -37,7 +37,8 @@ use crate::tools::ToOption; #[repr(u32)] #[strum(serialize_all = "snake_case")] pub enum EnteredCertificateChecks { - /// `Automatic` means strict certificate checks. + /// `Automatic` means strict certificate checks, + /// unless a legacy-domain override disables them. #[default] Automatic = 0, diff --git a/src/provider.rs b/src/provider.rs index 00c79b5b79..7a65ac497c 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -69,7 +69,7 @@ pub(crate) struct LegacyProviderSettings { pub autoconfig_servers: Option>, /// Maximum number of recipients allowed in a single SMTP send, if limited. - pub max_smtp_rcpt_to: Option, + pub max_smtp_rcpt_to: Option, /// Whether to disable strict TLS certificate checks by default. pub disable_strict_tls: bool, diff --git a/src/sql/migrations.rs b/src/sql/migrations.rs index fc1d8eb4a2..dd5cbc59dc 100644 --- a/src/sql/migrations.rs +++ b/src/sql/migrations.rs @@ -1117,9 +1117,7 @@ UPDATE chats SET protected=1, type=120 WHERE type=130;"#, .await?; } - if dbversion < 71 { - sql.set_db_version(71).await?; - } + // Migration 71 was removed together with the provider database it read from. if dbversion < 72 && !sql.col_exists("msgs", "mime_modified").await? { sql.execute_migration( r#" diff --git a/src/transport.rs b/src/transport.rs index 9516040135..70d551510a 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -92,7 +92,8 @@ pub(crate) enum ConfiguredCertificateChecks { /// Alias to `AcceptInvalidCertificates` for compatibility. AcceptInvalidCertificates2 = 3, - /// Apply strict checks to TLS certificates. + /// Apply strict checks to TLS certificates, + /// unless a legacy-domain override disables them. Automatic = 4, } @@ -464,13 +465,8 @@ impl ConfiguredLoginParam { let disable_strict_tls = crate::provider::legacy_settings_for_addr(&self.addr).disable_strict_tls; match self.certificate_checks { - ConfiguredCertificateChecks::OldAutomatic => { - if disable_strict_tls { - false - } else { - connected_through_proxy - } - } + ConfiguredCertificateChecks::OldAutomatic if disable_strict_tls => false, + ConfiguredCertificateChecks::OldAutomatic => connected_through_proxy, ConfiguredCertificateChecks::Automatic => !disable_strict_tls, ConfiguredCertificateChecks::Strict => true, ConfiguredCertificateChecks::AcceptInvalidCertificates