From 0a46e649719e90928606c69e839c2c83cf5ad3d5 Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 2 Sep 2024 01:18:38 +0000 Subject: [PATCH] fix: use default server list for providers that don't have one There are providers in the provider database that do not have servers specified. For such providers default list should be tried just like when configuring unknown providers. --- src/configure.rs | 2 +- src/login_param.rs | 228 ++++++++++++++++++++++++++++++++++----------- src/provider.rs | 2 +- 3 files changed, 174 insertions(+), 58 deletions(-) diff --git a/src/configure.rs b/src/configure.rs index 34c2cee70..8e4dcdddf 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -11,7 +11,7 @@ mod auto_mozilla; mod auto_outlook; -mod server_params; +pub(crate) mod server_params; use anyhow::{bail, ensure, Context as _, Result}; use auto_mozilla::moz_autoconfigure; diff --git a/src/login_param.rs b/src/login_param.rs index e63047b87..90a41d774 100644 --- a/src/login_param.rs +++ b/src/login_param.rs @@ -3,9 +3,11 @@ use std::fmt; use anyhow::{format_err, Context as _, Result}; +use deltachat_contact_tools::EmailAddress; use serde::{Deserialize, Serialize}; use crate::config::Config; +use crate::configure::server_params::{expand_param_vector, ServerParams}; use crate::constants::{DC_LP_AUTH_FLAGS, DC_LP_AUTH_NORMAL, DC_LP_AUTH_OAUTH2}; use crate::context::Context; use crate::net::load_connection_timestamp; @@ -479,69 +481,147 @@ impl ConfiguredLoginParam { .unwrap_or_default(); if let Some(provider) = provider { - let addr_localpart = if let Some(at) = addr.find('@') { - addr.split_at(at).0.to_string() + 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 { - addr.to_string() - }; - imap = provider - .server - .iter() - .filter_map(|server| { - if server.protocol != Protocol::Imap { - return None; - } + imap = provider + .server + .iter() + .filter_map(|server| { + if server.protocol != Protocol::Imap { + return None; + } - let Ok(security) = server.socket.try_into() else { - 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(), - } - }, + 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; - } + .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; - }; + 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(), - } - }, + 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(); + .collect(); + } } else if let (Some(configured_mail_servers), Some(configured_send_servers)) = ( context.get_config(Config::ConfiguredImapServers).await?, context.get_config(Config::ConfiguredSmtpServers).await?, @@ -898,4 +978,40 @@ mod tests { 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}"); + + t.set_config(Config::Configured, Some("1")).await?; + t.set_config(Config::ConfiguredProvider, Some(provider.id)) + .await?; + t.set_config(Config::ConfiguredAddr, 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?; + t.set_config(Config::ConfiguredSmtpCertificateChecks, Some("1")) + .await?; // Strict + t.set_config(Config::ConfiguredServerFlags, Some("0")) + .await?; + + let 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(()) + } } diff --git a/src/provider.rs b/src/provider.rs index 8316f6d98..a909d3ead 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -1,6 +1,6 @@ //! [Provider database](https://providers.delta.chat/) module. -mod data; +pub(crate) mod data; use anyhow::Result; use deltachat_contact_tools::EmailAddress;