mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 13:36:30 +03:00
Query MX records during provider autoconfiguration
Previously MX records were queried only for OAuth 2 configuration and did not affect the list of servers tried. User was required to manually configure the servers for Google Workspace (former GSuite) domains. Now MX records are queried during configuration. If provider is found in offline database, its ID, corresponding to the filename, is saved as `configured_provider`. `configured_provider` is also set during database migration if email address uses the domain from the provider database, but no MX querying is done.
This commit is contained in:
committed by
link2xt
parent
6edff503aa
commit
f4c8ffca4c
@@ -3358,7 +3358,7 @@ pub unsafe extern "C" fn dc_provider_new_from_email(
|
||||
return ptr::null();
|
||||
}
|
||||
let addr = to_string_lossy(addr);
|
||||
match provider::get_provider_info(addr.as_str()) {
|
||||
match block_on(provider::get_provider_info(addr.as_str())) {
|
||||
Some(provider) => provider,
|
||||
None => ptr::null_mut(),
|
||||
}
|
||||
|
||||
@@ -1055,7 +1055,7 @@ pub async fn cmdline(context: Context, line: &str, chat_id: &mut ChatId) -> Resu
|
||||
}
|
||||
"providerinfo" => {
|
||||
ensure!(!arg1.is_empty(), "Argument <addr> missing.");
|
||||
match provider::get_provider_info(arg1) {
|
||||
match provider::get_provider_info(arg1).await {
|
||||
Some(info) => {
|
||||
println!("Information for provider belonging to {}:", arg1);
|
||||
println!("status: {}", info.status as u32);
|
||||
|
||||
@@ -116,6 +116,7 @@ pub enum Config {
|
||||
ConfiguredInboxFolder,
|
||||
ConfiguredMvboxFolder,
|
||||
ConfiguredSentboxFolder,
|
||||
ConfiguredProvider,
|
||||
Configured,
|
||||
|
||||
#[strum(serialize = "sys.version")]
|
||||
|
||||
@@ -85,7 +85,7 @@ impl Context {
|
||||
let success = configure(self, &mut param).await;
|
||||
self.set_config(Config::NotifyAboutWrongPw, None).await?;
|
||||
|
||||
if let Some(provider) = provider::get_provider_info(¶m.addr) {
|
||||
if let Some(provider) = param.provider {
|
||||
if let Some(config_defaults) = &provider.config_defaults {
|
||||
for def in config_defaults.iter() {
|
||||
if !self.config_exists(def.key).await {
|
||||
@@ -205,9 +205,51 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
|
||||
{
|
||||
// no advanced parameters entered by the user: query provider-database or do Autoconfig
|
||||
|
||||
if let Some(servers) = get_offline_autoconfig(ctx, ¶m.addr) {
|
||||
param_autoconfig = Some(servers);
|
||||
info!(
|
||||
ctx,
|
||||
"checking internal provider-info for offline autoconfig"
|
||||
);
|
||||
|
||||
if let Some(provider) = provider::get_provider_info(¶m_domain).await {
|
||||
param.provider = Some(provider);
|
||||
match provider.status {
|
||||
provider::Status::OK | provider::Status::PREPARATION => {
|
||||
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)
|
||||
}
|
||||
}
|
||||
provider::Status::BROKEN => {
|
||||
info!(ctx, "offline autoconfig found, provider is broken");
|
||||
param_autoconfig = None;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info!(ctx, "no offline autoconfig found");
|
||||
param_autoconfig =
|
||||
get_autoconfig(ctx, param, ¶m_domain, ¶m_addr_urlencoded).await;
|
||||
}
|
||||
@@ -257,6 +299,7 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
|
||||
.filter(|params| params.protocol == Protocol::SMTP)
|
||||
.cloned()
|
||||
.collect();
|
||||
let provider_strict_tls = param.provider.map_or(false, |provider| provider.strict_tls);
|
||||
|
||||
let smtp_config_task = task::spawn(async move {
|
||||
let mut smtp_configured = false;
|
||||
@@ -267,8 +310,15 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
|
||||
smtp_param.port = smtp_server.port;
|
||||
smtp_param.security = smtp_server.socket;
|
||||
|
||||
match try_smtp_one_param(&context_smtp, &smtp_param, &smtp_addr, oauth2, &mut smtp)
|
||||
.await
|
||||
match try_smtp_one_param(
|
||||
&context_smtp,
|
||||
&smtp_param,
|
||||
&smtp_addr,
|
||||
oauth2,
|
||||
provider_strict_tls,
|
||||
&mut smtp,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
smtp_configured = true;
|
||||
@@ -304,7 +354,16 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
|
||||
param.imap.port = imap_server.port;
|
||||
param.imap.security = imap_server.socket;
|
||||
|
||||
match try_imap_one_param(ctx, ¶m.imap, ¶m.addr, oauth2, &mut imap).await {
|
||||
match try_imap_one_param(
|
||||
ctx,
|
||||
¶m.imap,
|
||||
¶m.addr,
|
||||
oauth2,
|
||||
provider_strict_tls,
|
||||
&mut imap,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(_) => {
|
||||
imap_configured = true;
|
||||
break;
|
||||
@@ -446,59 +505,12 @@ async fn get_autoconfig(
|
||||
None
|
||||
}
|
||||
|
||||
fn get_offline_autoconfig(context: &Context, addr: &str) -> Option<Vec<ServerParams>> {
|
||||
info!(
|
||||
context,
|
||||
"checking internal provider-info for offline autoconfig"
|
||||
);
|
||||
|
||||
if let Some(provider) = provider::get_provider_info(&addr) {
|
||||
match provider.status {
|
||||
provider::Status::OK | provider::Status::PREPARATION => {
|
||||
if provider.server.is_empty() {
|
||||
info!(context, "offline autoconfig found, but no servers defined");
|
||||
None
|
||||
} else {
|
||||
info!(context, "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 => addr.to_string(),
|
||||
UsernamePattern::EMAILLOCALPART => {
|
||||
if let Some(at) = addr.find('@') {
|
||||
addr.split_at(at).0.to_string()
|
||||
} else {
|
||||
addr.to_string()
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
.collect();
|
||||
Some(servers)
|
||||
}
|
||||
}
|
||||
provider::Status::BROKEN => {
|
||||
info!(context, "offline autoconfig found, provider is broken");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info!(context, "no offline autoconfig found");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
async fn try_imap_one_param(
|
||||
context: &Context,
|
||||
param: &ServerLoginParam,
|
||||
addr: &str,
|
||||
oauth2: bool,
|
||||
provider_strict_tls: bool,
|
||||
imap: &mut Imap,
|
||||
) -> Result<(), ConfigurationError> {
|
||||
let inf = format!(
|
||||
@@ -507,7 +519,10 @@ async fn try_imap_one_param(
|
||||
);
|
||||
info!(context, "Trying: {}", inf);
|
||||
|
||||
if let Err(err) = imap.connect(context, param, addr, oauth2).await {
|
||||
if let Err(err) = imap
|
||||
.connect(context, param, addr, oauth2, provider_strict_tls)
|
||||
.await
|
||||
{
|
||||
info!(context, "failure: {}", err);
|
||||
Err(ConfigurationError {
|
||||
config: inf,
|
||||
@@ -524,6 +539,7 @@ async fn try_smtp_one_param(
|
||||
param: &ServerLoginParam,
|
||||
addr: &str,
|
||||
oauth2: bool,
|
||||
provider_strict_tls: bool,
|
||||
smtp: &mut Smtp,
|
||||
) -> Result<(), ConfigurationError> {
|
||||
let inf = format!(
|
||||
@@ -532,7 +548,10 @@ async fn try_smtp_one_param(
|
||||
);
|
||||
info!(context, "Trying: {}", inf);
|
||||
|
||||
if let Err(err) = smtp.connect(context, param, addr, oauth2).await {
|
||||
if let Err(err) = smtp
|
||||
.connect(context, param, addr, oauth2, provider_strict_tls)
|
||||
.await
|
||||
{
|
||||
info!(context, "failure: {}", err);
|
||||
Err(ConfigurationError {
|
||||
config: inf,
|
||||
@@ -601,7 +620,6 @@ pub enum Error {
|
||||
mod tests {
|
||||
#![allow(clippy::indexing_slicing)]
|
||||
|
||||
use super::*;
|
||||
use crate::config::*;
|
||||
use crate::test_utils::*;
|
||||
|
||||
@@ -614,20 +632,4 @@ mod tests {
|
||||
t.set_config(Config::MailPw, Some("123456")).await.unwrap();
|
||||
assert!(t.configure().await.is_err());
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_get_offline_autoconfig() {
|
||||
let context = TestContext::new().await.ctx;
|
||||
|
||||
let addr = "someone123@example.org";
|
||||
assert!(get_offline_autoconfig(&context, addr).is_none());
|
||||
|
||||
let addr = "someone123@nauta.cu";
|
||||
let found_params = get_offline_autoconfig(&context, addr).unwrap();
|
||||
assert_eq!(found_params.len(), 2);
|
||||
assert_eq!(found_params[0].protocol, Protocol::IMAP);
|
||||
assert_eq!(found_params[0].hostname, "imap.nauta.cu".to_string());
|
||||
assert_eq!(found_params[1].protocol, Protocol::SMTP);
|
||||
assert_eq!(found_params[1].hostname, "smtp.nauta.cu".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ use crate::message::{self, update_server_uid, MessageState};
|
||||
use crate::mimeparser;
|
||||
use crate::oauth2::dc_get_oauth2_access_token;
|
||||
use crate::param::Params;
|
||||
use crate::provider::{get_provider_info, Socket};
|
||||
use crate::provider::Socket;
|
||||
use crate::{
|
||||
chat, dc_tools::dc_extract_grpid_from_rfc724_mid, scheduler::InterruptInfo, stock::StockMessage,
|
||||
};
|
||||
@@ -339,6 +339,7 @@ impl Imap {
|
||||
¶m.imap,
|
||||
¶m.addr,
|
||||
param.server_flags & DC_LP_AUTH_OAUTH2 != 0,
|
||||
param.provider.map_or(false, |provider| provider.strict_tls),
|
||||
)
|
||||
.await
|
||||
{
|
||||
@@ -360,6 +361,7 @@ impl Imap {
|
||||
lp: &ServerLoginParam,
|
||||
addr: &str,
|
||||
oauth2: bool,
|
||||
provider_strict_tls: bool,
|
||||
) -> Result<()> {
|
||||
if lp.server.is_empty() || lp.user.is_empty() || lp.password.is_empty() {
|
||||
bail!("Incomplete IMAP connection parameters");
|
||||
@@ -369,11 +371,8 @@ impl Imap {
|
||||
let mut config = &mut self.config;
|
||||
config.addr = addr.to_string();
|
||||
config.lp = lp.clone();
|
||||
let provider = get_provider_info(&addr);
|
||||
config.strict_tls = match lp.certificate_checks {
|
||||
CertificateChecks::Automatic => {
|
||||
provider.map_or(false, |provider| provider.strict_tls)
|
||||
}
|
||||
CertificateChecks::Automatic => provider_strict_tls,
|
||||
CertificateChecks::Strict => true,
|
||||
CertificateChecks::AcceptInvalidCertificates
|
||||
| CertificateChecks::AcceptInvalidCertificates2 => false,
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
|
||||
use crate::provider::{get_provider_by_id, Provider};
|
||||
use crate::{context::Context, provider::Socket};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Display, FromPrimitive, PartialEq, Eq)]
|
||||
@@ -48,6 +49,7 @@ pub struct LoginParam {
|
||||
pub imap: ServerLoginParam,
|
||||
pub smtp: ServerLoginParam,
|
||||
pub server_flags: i32,
|
||||
pub provider: Option<&'static Provider>,
|
||||
}
|
||||
|
||||
impl LoginParam {
|
||||
@@ -130,6 +132,12 @@ impl LoginParam {
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
|
||||
let key = format!("{}provider", prefix);
|
||||
let provider = sql
|
||||
.get_raw_config(context, key)
|
||||
.await
|
||||
.and_then(|provider_id| get_provider_by_id(&provider_id));
|
||||
|
||||
LoginParam {
|
||||
addr,
|
||||
imap: ServerLoginParam {
|
||||
@@ -148,6 +156,7 @@ impl LoginParam {
|
||||
security: send_security,
|
||||
certificate_checks: smtp_certificate_checks,
|
||||
},
|
||||
provider,
|
||||
server_flags,
|
||||
}
|
||||
}
|
||||
@@ -216,6 +225,11 @@ impl LoginParam {
|
||||
sql.set_raw_config_int(context, key, self.server_flags)
|
||||
.await?;
|
||||
|
||||
if let Some(provider) = self.provider {
|
||||
let key = format!("{}provider", prefix);
|
||||
sql.set_raw_config(context, key, Some(provider.id)).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
//! OAuth 2 module
|
||||
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use async_std_resolver::{config, resolver};
|
||||
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
|
||||
use serde::Deserialize;
|
||||
|
||||
@@ -19,7 +17,6 @@ const OAUTH2_GMAIL: Oauth2 = Oauth2 {
|
||||
init_token: "https://accounts.google.com/o/oauth2/token?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&code=$CODE&grant_type=authorization_code",
|
||||
refresh_token: "https://accounts.google.com/o/oauth2/token?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&refresh_token=$REFRESH_TOKEN&grant_type=refresh_token",
|
||||
get_userinfo: Some("https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=$ACCESS_TOKEN"),
|
||||
mx_pattern: Some(r"^aspmx\.l\.google\.com\.$"),
|
||||
};
|
||||
|
||||
const OAUTH2_YANDEX: Oauth2 = Oauth2 {
|
||||
@@ -29,11 +26,8 @@ const OAUTH2_YANDEX: Oauth2 = Oauth2 {
|
||||
init_token: "https://oauth.yandex.com/token?grant_type=authorization_code&code=$CODE&client_id=$CLIENT_ID&client_secret=58b8c6e94cf44fbe952da8511955dacf",
|
||||
refresh_token: "https://oauth.yandex.com/token?grant_type=refresh_token&refresh_token=$REFRESH_TOKEN&client_id=$CLIENT_ID&client_secret=58b8c6e94cf44fbe952da8511955dacf",
|
||||
get_userinfo: None,
|
||||
mx_pattern: None,
|
||||
};
|
||||
|
||||
const OAUTH2_PROVIDERS: [Oauth2; 1] = [OAUTH2_GMAIL];
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
struct Oauth2 {
|
||||
client_id: &'static str,
|
||||
@@ -41,7 +35,6 @@ struct Oauth2 {
|
||||
init_token: &'static str,
|
||||
refresh_token: &'static str,
|
||||
get_userinfo: Option<&'static str>,
|
||||
mx_pattern: Option<&'static str>,
|
||||
}
|
||||
|
||||
/// OAuth 2 Access Token Response
|
||||
@@ -276,47 +269,16 @@ impl Oauth2 {
|
||||
.find('@')
|
||||
.map(|index| addr_normalized.split_at(index + 1).1)
|
||||
{
|
||||
if let Some(provider) = provider::get_provider_info(&addr_normalized) {
|
||||
match &provider.oauth2_authorizer {
|
||||
Some(Oauth2Authorizer::Gmail) => Some(OAUTH2_GMAIL),
|
||||
Some(Oauth2Authorizer::Yandex) => Some(OAUTH2_YANDEX),
|
||||
None => None, // provider known to not support oauth2, no mx-lookup required
|
||||
}
|
||||
} else {
|
||||
Oauth2::lookup_mx(domain).await
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
async fn lookup_mx(domain: impl AsRef<str>) -> Option<Self> {
|
||||
if let Ok(resolver) = resolver(
|
||||
config::ResolverConfig::default(),
|
||||
config::ResolverOpts::default(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
let mut fqdn: String = String::from(domain.as_ref());
|
||||
if !fqdn.ends_with('.') {
|
||||
fqdn.push('.');
|
||||
}
|
||||
|
||||
if let Ok(res) = resolver.mx_lookup(fqdn).await {
|
||||
for provider in OAUTH2_PROVIDERS.iter() {
|
||||
if let Some(pattern) = provider.mx_pattern {
|
||||
let re = Regex::new(pattern).unwrap();
|
||||
|
||||
for rr in res.iter() {
|
||||
if re.is_match(&rr.exchange().to_lowercase().to_utf8()) {
|
||||
return Some(provider.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(oauth2_authorizer) = provider::get_provider_info(&domain)
|
||||
.await
|
||||
.and_then(|provider| provider.oauth2_authorizer.as_ref())
|
||||
{
|
||||
return Some(match oauth2_authorizer {
|
||||
Oauth2Authorizer::Gmail => OAUTH2_GMAIL,
|
||||
Oauth2Authorizer::Yandex => OAUTH2_YANDEX,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ use once_cell::sync::Lazy;
|
||||
|
||||
// aktivix.org.md: aktivix.org
|
||||
static P_AKTIVIX_ORG: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "aktivix.org",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -39,6 +40,7 @@ static P_AKTIVIX_ORG: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
// aol.md: aol.com
|
||||
static P_AOL: Lazy<Provider> = Lazy::new(|| {
|
||||
Provider {
|
||||
id: "aol",
|
||||
status: Status::PREPARATION,
|
||||
before_login_hint: "To log in to AOL with Delta Chat, you need to set up an app password in the AOL web interface.",
|
||||
after_login_hint: "",
|
||||
@@ -56,6 +58,7 @@ static P_AOL: Lazy<Provider> = Lazy::new(|| {
|
||||
|
||||
// arcor.de.md: arcor.de
|
||||
static P_ARCOR_DE: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "arcor.de",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -84,6 +87,7 @@ static P_ARCOR_DE: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// autistici.org.md: autistici.org
|
||||
static P_AUTISTICI_ORG: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "autistici.org",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -112,6 +116,7 @@ static P_AUTISTICI_ORG: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// bluewin.ch.md: bluewin.ch
|
||||
static P_BLUEWIN_CH: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "bluewin.ch",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -140,6 +145,7 @@ static P_BLUEWIN_CH: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// buzon.uy.md: buzon.uy
|
||||
static P_BUZON_UY: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "buzon.uy",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -168,6 +174,7 @@ static P_BUZON_UY: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// chello.at.md: chello.at
|
||||
static P_CHELLO_AT: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "chello.at",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -196,6 +203,7 @@ static P_CHELLO_AT: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// comcast.md: xfinity.com, comcast.net
|
||||
static P_COMCAST: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "comcast",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -209,6 +217,7 @@ static P_COMCAST: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// dismail.de.md: dismail.de
|
||||
static P_DISMAIL_DE: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "dismail.de",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -222,6 +231,7 @@ static P_DISMAIL_DE: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// disroot.md: disroot.org
|
||||
static P_DISROOT: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "disroot",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -235,6 +245,7 @@ static P_DISROOT: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// dubby.org.md: dubby.org
|
||||
static P_DUBBY_ORG: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "dubby.org",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -285,9 +296,24 @@ static P_DUBBY_ORG: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
oauth2_authorizer: None,
|
||||
});
|
||||
|
||||
// example.com.md: example.com, example.org
|
||||
// espiv.net.md: espiv.net
|
||||
static P_ESPIV_NET: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "espiv.net",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
overview_page: "https://providers.delta.chat/espiv-net",
|
||||
server: vec![],
|
||||
config_defaults: None,
|
||||
strict_tls: true,
|
||||
max_smtp_rcpt_to: None,
|
||||
oauth2_authorizer: None,
|
||||
});
|
||||
|
||||
// example.com.md: example.com, example.org, example.net
|
||||
static P_EXAMPLE_COM: Lazy<Provider> = Lazy::new(|| {
|
||||
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 for Delta Chat, take a look at providers.delta.chat!",
|
||||
@@ -305,6 +331,7 @@ static P_EXAMPLE_COM: Lazy<Provider> = Lazy::new(|| {
|
||||
|
||||
// fastmail.md: fastmail.com
|
||||
static P_FASTMAIL: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "fastmail",
|
||||
status: Status::PREPARATION,
|
||||
before_login_hint:
|
||||
"You must create an app-specific password for Delta Chat before you can log in.",
|
||||
@@ -320,6 +347,7 @@ static P_FASTMAIL: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
// firemail.de.md: firemail.at, firemail.de
|
||||
static P_FIREMAIL_DE: Lazy<Provider> = Lazy::new(|| {
|
||||
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.",
|
||||
@@ -335,6 +363,7 @@ static P_FIREMAIL_DE: Lazy<Provider> = Lazy::new(|| {
|
||||
|
||||
// five.chat.md: five.chat
|
||||
static P_FIVE_CHAT: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "five.chat",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -365,6 +394,7 @@ static P_FIVE_CHAT: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// freenet.de.md: freenet.de
|
||||
static P_FREENET_DE: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "freenet.de",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -391,9 +421,10 @@ static P_FREENET_DE: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
oauth2_authorizer: None,
|
||||
});
|
||||
|
||||
// gmail.md: gmail.com, googlemail.com
|
||||
// gmail.md: gmail.com, googlemail.com, google.com
|
||||
static P_GMAIL: Lazy<Provider> = Lazy::new(|| {
|
||||
Provider {
|
||||
id: "gmail",
|
||||
status: Status::PREPARATION,
|
||||
before_login_hint: "For Gmail accounts, you need to create an app-password if you have \"2-Step Verification\" enabled. If this setting is not available, you need to enable \"less secure apps\".",
|
||||
after_login_hint: "",
|
||||
@@ -411,6 +442,7 @@ static P_GMAIL: Lazy<Provider> = Lazy::new(|| {
|
||||
|
||||
// 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: Lazy<Provider> = Lazy::new(|| 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: "",
|
||||
@@ -446,6 +478,7 @@ static P_GMX_NET: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// hermes.radio.md: hermes.radio
|
||||
static P_HERMES_RADIO: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "hermes.radio",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -477,6 +510,7 @@ static P_HERMES_RADIO: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
// hey.com.md: hey.com
|
||||
static P_HEY_COM: Lazy<Provider> = Lazy::new(|| {
|
||||
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 with Delta Chat to hey.com.",
|
||||
after_login_hint: "",
|
||||
@@ -492,6 +526,7 @@ static P_HEY_COM: Lazy<Provider> = Lazy::new(|| {
|
||||
|
||||
// i.ua.md: i.ua
|
||||
static P_I_UA: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "i.ua",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -505,6 +540,7 @@ static P_I_UA: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// icloud.md: icloud.com, me.com, mac.com
|
||||
static P_ICLOUD: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "icloud",
|
||||
status: Status::PREPARATION,
|
||||
before_login_hint:
|
||||
"You must create an app-specific password for Delta Chat before you can login.",
|
||||
@@ -534,6 +570,7 @@ static P_ICLOUD: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// kolst.com.md: kolst.com
|
||||
static P_KOLST_COM: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "kolst.com",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -547,6 +584,7 @@ static P_KOLST_COM: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// kontent.com.md: kontent.com
|
||||
static P_KONTENT_COM: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "kontent.com",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -560,6 +598,7 @@ static P_KONTENT_COM: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// mail.ru.md: mail.ru, inbox.ru, bk.ru, list.ru
|
||||
static P_MAIL_RU: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "mail.ru",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -573,6 +612,7 @@ static P_MAIL_RU: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// mailbox.org.md: mailbox.org, secure.mailbox.org
|
||||
static P_MAILBOX_ORG: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "mailbox.org",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -587,6 +627,7 @@ static P_MAILBOX_ORG: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
// nauta.cu.md: nauta.cu
|
||||
static P_NAUTA_CU: Lazy<Provider> = Lazy::new(|| {
|
||||
Provider {
|
||||
id: "nauta.cu",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "Atención - con nauta.cu, puede enviar mensajes sólo a un máximo de 20 personas a la vez. En grupos más grandes, no puede enviar mensajes o abandonar el grupo.",
|
||||
@@ -614,6 +655,7 @@ static P_NAUTA_CU: Lazy<Provider> = Lazy::new(|| {
|
||||
// outlook.com.md: hotmail.com, outlook.com, office365.com, outlook.com.tr, live.com
|
||||
static P_OUTLOOK_COM: Lazy<Provider> = Lazy::new(|| {
|
||||
Provider {
|
||||
id: "outlook.com",
|
||||
status: Status::BROKEN,
|
||||
before_login_hint: "Outlook.com email addresses will not work as expected as these servers remove some important transport information. Hopefully sooner or later there will be a fix, for now we suggest to use another email address.",
|
||||
after_login_hint: "Outlook.com email addresses will not work as expected as these servers remove some important transport information. Unencrypted 1-on-1 chats kind of work, but groups and encryption don't. Hopefully sooner or later there will be a fix, for now we suggest to use another email address.",
|
||||
@@ -631,6 +673,7 @@ static P_OUTLOOK_COM: Lazy<Provider> = Lazy::new(|| {
|
||||
|
||||
// posteo.md: posteo.de, posteo.af, posteo.at, posteo.be, posteo.ch, posteo.cl, posteo.co, posteo.co.uk, 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.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: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "posteo",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -660,6 +703,7 @@ static P_POSTEO: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
// protonmail.md: protonmail.com, protonmail.ch
|
||||
static P_PROTONMAIL: Lazy<Provider> = Lazy::new(|| {
|
||||
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 Delta Chat to Protonmail.",
|
||||
after_login_hint: "To use Delta Chat with Protonmail, the IMAP bridge must be running in the background. If you have connectivity issues, double check whether it works as expected.",
|
||||
@@ -675,6 +719,7 @@ static P_PROTONMAIL: Lazy<Provider> = Lazy::new(|| {
|
||||
|
||||
// riseup.net.md: riseup.net
|
||||
static P_RISEUP_NET: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "riseup.net",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -688,6 +733,7 @@ static P_RISEUP_NET: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// rogers.com.md: rogers.com
|
||||
static P_ROGERS_COM: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "rogers.com",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -701,6 +747,7 @@ static P_ROGERS_COM: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// systemli.org.md: systemli.org
|
||||
static P_SYSTEMLI_ORG: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "systemli.org",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -715,6 +762,7 @@ static P_SYSTEMLI_ORG: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
// t-online.md: t-online.de, magenta.de
|
||||
static P_T_ONLINE: Lazy<Provider> = Lazy::new(|| {
|
||||
Provider {
|
||||
id: "t-online",
|
||||
status: Status::PREPARATION,
|
||||
before_login_hint: "To use Delta Chat with a T-Online email address, you need to create an app password in the web interface.",
|
||||
after_login_hint: "",
|
||||
@@ -732,6 +780,7 @@ static P_T_ONLINE: Lazy<Provider> = Lazy::new(|| {
|
||||
|
||||
// testrun.md: testrun.org
|
||||
static P_TESTRUN: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "testrun",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -784,6 +833,7 @@ static P_TESTRUN: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// tiscali.it.md: tiscali.it
|
||||
static P_TISCALI_IT: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "tiscali.it",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -812,6 +862,7 @@ static P_TISCALI_IT: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// ukr.net.md: ukr.net
|
||||
static P_UKR_NET: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "ukr.net",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -825,6 +876,7 @@ static P_UKR_NET: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// undernet.uy.md: undernet.uy
|
||||
static P_UNDERNET_UY: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "undernet.uy",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -853,6 +905,7 @@ static P_UNDERNET_UY: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// vfemail.md: vfemail.net
|
||||
static P_VFEMAIL: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "vfemail",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -866,6 +919,7 @@ static P_VFEMAIL: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// vodafone.de.md: vodafone.de, vodafonemail.de
|
||||
static P_VODAFONE_DE: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "vodafone.de",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -895,6 +949,7 @@ static P_VODAFONE_DE: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
// 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: Lazy<Provider> = Lazy::new(|| {
|
||||
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",
|
||||
@@ -914,6 +969,7 @@ static P_WEB_DE: Lazy<Provider> = Lazy::new(|| {
|
||||
// yahoo.md: yahoo.com, yahoo.de, yahoo.it, yahoo.fr, yahoo.es, yahoo.se, yahoo.co.uk, yahoo.co.nz, yahoo.com.au, yahoo.com.ar, yahoo.com.br, yahoo.com.mx, ymail.com, rocketmail.com, yahoodns.net
|
||||
static P_YAHOO: Lazy<Provider> = Lazy::new(|| {
|
||||
Provider {
|
||||
id: "yahoo",
|
||||
status: Status::PREPARATION,
|
||||
before_login_hint: "To use Delta Chat with your Yahoo email address you have to create an \"App-Password\" in the account security screen.",
|
||||
after_login_hint: "",
|
||||
@@ -931,6 +987,7 @@ static P_YAHOO: Lazy<Provider> = Lazy::new(|| {
|
||||
|
||||
// yandex.ru.md: yandex.com, yandex.by, yandex.kz, yandex.ru, yandex.ua, ya.ru, narod.ru
|
||||
static P_YANDEX_RU: Lazy<Provider> = Lazy::new(|| 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: "",
|
||||
@@ -959,6 +1016,7 @@ static P_YANDEX_RU: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
|
||||
// ziggo.nl.md: ziggo.nl
|
||||
static P_ZIGGO_NL: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
id: "ziggo.nl",
|
||||
status: Status::OK,
|
||||
before_login_hint: "",
|
||||
after_login_hint: "",
|
||||
@@ -985,7 +1043,7 @@ static P_ZIGGO_NL: Lazy<Provider> = Lazy::new(|| Provider {
|
||||
oauth2_authorizer: None,
|
||||
});
|
||||
|
||||
pub static PROVIDER_DATA: Lazy<HashMap<&'static str, &'static Provider>> = Lazy::new(|| {
|
||||
pub(crate) static PROVIDER_DATA: Lazy<HashMap<&'static str, &'static Provider>> = Lazy::new(|| {
|
||||
[
|
||||
("aktivix.org", &*P_AKTIVIX_ORG),
|
||||
("aol.com", &*P_AOL),
|
||||
@@ -999,8 +1057,10 @@ pub static PROVIDER_DATA: Lazy<HashMap<&'static str, &'static Provider>> = Lazy:
|
||||
("dismail.de", &*P_DISMAIL_DE),
|
||||
("disroot.org", &*P_DISROOT),
|
||||
("dubby.org", &*P_DUBBY_ORG),
|
||||
("espiv.net", &*P_ESPIV_NET),
|
||||
("example.com", &*P_EXAMPLE_COM),
|
||||
("example.org", &*P_EXAMPLE_COM),
|
||||
("example.net", &*P_EXAMPLE_COM),
|
||||
("fastmail.com", &*P_FASTMAIL),
|
||||
("firemail.at", &*P_FIREMAIL_DE),
|
||||
("firemail.de", &*P_FIREMAIL_DE),
|
||||
@@ -1008,6 +1068,7 @@ pub static PROVIDER_DATA: Lazy<HashMap<&'static str, &'static Provider>> = Lazy:
|
||||
("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),
|
||||
@@ -1156,5 +1217,58 @@ pub static PROVIDER_DATA: Lazy<HashMap<&'static str, &'static Provider>> = Lazy:
|
||||
.collect()
|
||||
});
|
||||
|
||||
pub(crate) static PROVIDER_IDS: Lazy<HashMap<&'static str, &'static Provider>> = Lazy::new(|| {
|
||||
[
|
||||
("aktivix.org", &*P_AKTIVIX_ORG),
|
||||
("aol", &*P_AOL),
|
||||
("arcor.de", &*P_ARCOR_DE),
|
||||
("autistici.org", &*P_AUTISTICI_ORG),
|
||||
("bluewin.ch", &*P_BLUEWIN_CH),
|
||||
("buzon.uy", &*P_BUZON_UY),
|
||||
("chello.at", &*P_CHELLO_AT),
|
||||
("comcast", &*P_COMCAST),
|
||||
("dismail.de", &*P_DISMAIL_DE),
|
||||
("disroot", &*P_DISROOT),
|
||||
("dubby.org", &*P_DUBBY_ORG),
|
||||
("espiv.net", &*P_ESPIV_NET),
|
||||
("example.com", &*P_EXAMPLE_COM),
|
||||
("fastmail", &*P_FASTMAIL),
|
||||
("firemail.de", &*P_FIREMAIL_DE),
|
||||
("five.chat", &*P_FIVE_CHAT),
|
||||
("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),
|
||||
("icloud", &*P_ICLOUD),
|
||||
("kolst.com", &*P_KOLST_COM),
|
||||
("kontent.com", &*P_KONTENT_COM),
|
||||
("mail.ru", &*P_MAIL_RU),
|
||||
("mailbox.org", &*P_MAILBOX_ORG),
|
||||
("nauta.cu", &*P_NAUTA_CU),
|
||||
("outlook.com", &*P_OUTLOOK_COM),
|
||||
("posteo", &*P_POSTEO),
|
||||
("protonmail", &*P_PROTONMAIL),
|
||||
("riseup.net", &*P_RISEUP_NET),
|
||||
("rogers.com", &*P_ROGERS_COM),
|
||||
("systemli.org", &*P_SYSTEMLI_ORG),
|
||||
("t-online", &*P_T_ONLINE),
|
||||
("testrun", &*P_TESTRUN),
|
||||
("tiscali.it", &*P_TISCALI_IT),
|
||||
("ukr.net", &*P_UKR_NET),
|
||||
("undernet.uy", &*P_UNDERNET_UY),
|
||||
("vfemail", &*P_VFEMAIL),
|
||||
("vodafone.de", &*P_VODAFONE_DE),
|
||||
("web.de", &*P_WEB_DE),
|
||||
("yahoo", &*P_YAHOO),
|
||||
("yandex.ru", &*P_YANDEX_RU),
|
||||
("ziggo.nl", &*P_ZIGGO_NL),
|
||||
]
|
||||
.iter()
|
||||
.copied()
|
||||
.collect()
|
||||
});
|
||||
|
||||
pub static PROVIDER_UPDATED: Lazy<chrono::NaiveDate> =
|
||||
Lazy::new(|| chrono::NaiveDate::from_ymd(2020, 12, 26));
|
||||
Lazy::new(|| chrono::NaiveDate::from_ymd(2021, 1, 8));
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
mod data;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::dc_tools::EmailAddress;
|
||||
use crate::provider::data::{PROVIDER_DATA, PROVIDER_UPDATED};
|
||||
use crate::provider::data::{PROVIDER_DATA, PROVIDER_IDS, PROVIDER_UPDATED};
|
||||
use async_std_resolver::{config, resolver};
|
||||
use chrono::{NaiveDateTime, NaiveTime};
|
||||
|
||||
#[derive(Debug, Display, Copy, Clone, PartialEq, FromPrimitive, ToPrimitive)]
|
||||
@@ -68,6 +68,8 @@ pub struct ConfigDefault {
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Provider {
|
||||
/// Unique ID, corresponding to provider database filename.
|
||||
pub id: &'static str,
|
||||
pub status: Status,
|
||||
pub before_login_hint: &'static str,
|
||||
pub after_login_hint: &'static str,
|
||||
@@ -79,20 +81,84 @@ pub struct Provider {
|
||||
pub oauth2_authorizer: Option<Oauth2Authorizer>,
|
||||
}
|
||||
|
||||
pub fn get_provider_info(addr: &str) -> Option<&Provider> {
|
||||
let domain = match addr.parse::<EmailAddress>() {
|
||||
Ok(addr) => addr.domain,
|
||||
Err(_err) => return None,
|
||||
}
|
||||
.to_lowercase();
|
||||
/// Returns provider for the given domain.
|
||||
///
|
||||
/// This function looks up domain in offline database first. If not
|
||||
/// found, it queries MX record for the domain and looks up offline
|
||||
/// database for MX domains.
|
||||
///
|
||||
/// For compatibility, email address can be passed to this function
|
||||
/// instead of the domain.
|
||||
pub async fn get_provider_info(domain: &str) -> Option<&'static Provider> {
|
||||
let domain = domain.rsplitn(2, '@').next()?;
|
||||
|
||||
if let Some(provider) = PROVIDER_DATA.get(domain.as_str()) {
|
||||
if let Some(provider) = get_provider_by_domain(domain) {
|
||||
return Some(provider);
|
||||
}
|
||||
|
||||
if let Some(provider) = get_provider_by_mx(domain).await {
|
||||
return Some(provider);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Finds a provider in offline database based on domain.
|
||||
pub fn get_provider_by_domain(domain: &str) -> Option<&'static Provider> {
|
||||
if let Some(provider) = PROVIDER_DATA.get(domain.to_lowercase().as_str()) {
|
||||
return Some(*provider);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
/// Finds a provider based on MX record for the given domain.
|
||||
///
|
||||
/// For security reasons, only Gmail can be configured this way.
|
||||
pub async fn get_provider_by_mx(domain: impl AsRef<str>) -> Option<&'static Provider> {
|
||||
if let Ok(resolver) = resolver(
|
||||
config::ResolverConfig::default(),
|
||||
config::ResolverOpts::default(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
let mut fqdn: String = String::from(domain.as_ref());
|
||||
if !fqdn.ends_with('.') {
|
||||
fqdn.push('.');
|
||||
}
|
||||
|
||||
if let Ok(mx_domains) = resolver.mx_lookup(fqdn).await {
|
||||
for (provider_domain, provider) in PROVIDER_DATA.iter() {
|
||||
if provider.id != "gmail" {
|
||||
// MX lookup is limited to Gmail for security reasons
|
||||
continue;
|
||||
}
|
||||
|
||||
let provider_fqdn = provider_domain.to_string() + ".";
|
||||
let provider_fqdn_dot = ".".to_string() + &provider_fqdn;
|
||||
|
||||
for mx_domain in mx_domains.iter() {
|
||||
let mx_domain = mx_domain.exchange().to_lowercase().to_utf8();
|
||||
|
||||
if mx_domain == provider_fqdn || mx_domain.ends_with(&provider_fqdn_dot) {
|
||||
return Some(provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_provider_by_id(id: &str) -> Option<&'static Provider> {
|
||||
if let Some(provider) = PROVIDER_IDS.get(id) {
|
||||
Some(&provider)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// returns update timestamp in seconds, UTC, compatible for comparison with time() and database times
|
||||
pub fn get_provider_update_timestamp() -> i64 {
|
||||
NaiveDateTime::new(*PROVIDER_UPDATED, NaiveTime::from_hms(0, 0, 0)).timestamp_millis() / 1_000
|
||||
@@ -107,24 +173,21 @@ mod tests {
|
||||
use chrono::NaiveDate;
|
||||
|
||||
#[test]
|
||||
fn test_get_provider_info_unexistant() {
|
||||
let provider = get_provider_info("user@unexistant.org");
|
||||
fn test_get_provider_by_domain_unexistant() {
|
||||
let provider = get_provider_by_domain("unexistant.org");
|
||||
assert!(provider.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_provider_info_mixed_case() {
|
||||
let provider = get_provider_info("uSer@nAUta.Cu").unwrap();
|
||||
fn test_get_provider_by_domain_mixed_case() {
|
||||
let provider = get_provider_by_domain("nAUta.Cu").unwrap();
|
||||
assert!(provider.status == Status::OK);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_provider_info() {
|
||||
let provider = get_provider_info("nauta.cu"); // this is no email address
|
||||
assert!(provider.is_none());
|
||||
|
||||
let addr = "user@nauta.cu";
|
||||
let provider = get_provider_info(addr).unwrap();
|
||||
fn test_get_provider_by_domain() {
|
||||
let addr = "nauta.cu";
|
||||
let provider = get_provider_by_domain(addr).unwrap();
|
||||
assert!(provider.status == Status::OK);
|
||||
let server = &provider.server[0];
|
||||
assert_eq!(server.protocol, Protocol::IMAP);
|
||||
@@ -139,15 +202,30 @@ mod tests {
|
||||
assert_eq!(server.port, 25);
|
||||
assert_eq!(server.username_pattern, UsernamePattern::EMAIL);
|
||||
|
||||
let provider = get_provider_info("user@gmail.com").unwrap();
|
||||
let provider = get_provider_by_domain("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("user@googlemail.com").unwrap();
|
||||
let provider = get_provider_by_domain("googlemail.com").unwrap();
|
||||
assert!(provider.status == Status::PREPARATION);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_provider_by_id() {
|
||||
let provider = get_provider_by_id("gmail").unwrap();
|
||||
assert!(provider.id == "gmail");
|
||||
}
|
||||
|
||||
#[async_std::test]
|
||||
async fn test_get_provider_info() {
|
||||
assert!(get_provider_info("").await.is_none());
|
||||
assert!(get_provider_info("google.com").await.unwrap().id == "gmail");
|
||||
|
||||
// get_provider_info() accepts email addresses for backwards compatibility
|
||||
assert!(get_provider_info("example@google.com").await.unwrap().id == "gmail");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_provider_update_timestamp() {
|
||||
let timestamp_past = NaiveDateTime::new(
|
||||
|
||||
@@ -8,7 +8,8 @@ import datetime
|
||||
|
||||
out_all = ""
|
||||
out_domains = ""
|
||||
domains_dict = {}
|
||||
out_ids = ""
|
||||
domains_set = set()
|
||||
|
||||
def camel(name):
|
||||
words = name.split("_")
|
||||
@@ -22,15 +23,19 @@ def cleanstr(s):
|
||||
return s
|
||||
|
||||
|
||||
def file2id(f):
|
||||
return os.path.basename(f).replace(".md", "")
|
||||
|
||||
|
||||
def file2varname(f):
|
||||
f = f[f.rindex("/")+1:].replace(".md", "")
|
||||
f = file2id(f)
|
||||
f = f.replace(".", "_")
|
||||
f = f.replace("-", "_")
|
||||
return "P_" + f.upper()
|
||||
|
||||
|
||||
def file2url(f):
|
||||
f = f[f.rindex("/")+1:].replace(".md", "")
|
||||
f = file2id(f)
|
||||
f = f.replace(".", "-")
|
||||
return "https://providers.delta.chat/" + f
|
||||
|
||||
@@ -61,14 +66,16 @@ def process_data(data, file):
|
||||
if domain == "" or domain.count(".") < 1 or domain.lower() != domain:
|
||||
raise TypeError("bad domain: " + domain)
|
||||
|
||||
global domains_dict
|
||||
if domains_dict.get(domain, False):
|
||||
global domains_set
|
||||
if domain in domains_set:
|
||||
raise TypeError("domain used twice: " + domain)
|
||||
domains_dict[domain] = True
|
||||
domains_set.add(domain)
|
||||
|
||||
domains += " (\"" + domain + "\", &*" + file2varname(file) + "),\n"
|
||||
comment += domain + ", "
|
||||
|
||||
ids = ""
|
||||
ids += " (\"" + file2id(file) + "\", &*" + file2varname(file) + "),\n"
|
||||
|
||||
server = ""
|
||||
has_imap = False
|
||||
@@ -115,6 +122,7 @@ def process_data(data, file):
|
||||
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) + ": Lazy<Provider> = Lazy::new(|| Provider {\n"
|
||||
provider += " id: \"" + file2id(file) + "\",\n"
|
||||
provider += " status: Status::" + status + ",\n"
|
||||
provider += " before_login_hint: \"" + before_login_hint + "\",\n"
|
||||
provider += " after_login_hint: \"" + after_login_hint + "\",\n"
|
||||
@@ -132,13 +140,14 @@ def process_data(data, file):
|
||||
raise TypeError("status PREPARATION or BROKEN requires before_login_hint: " + file)
|
||||
|
||||
# finally, add the provider
|
||||
global out_all, out_domains
|
||||
global out_all, out_domains, out_ids
|
||||
out_all += "// " + file[file.rindex("/")+1:] + ": " + comment.strip(", ") + "\n"
|
||||
|
||||
# also add provider with no special things to do -
|
||||
# eg. _not_ supporting oauth2 is also an information and we can skip the mx-lookup in this case
|
||||
out_all += provider
|
||||
out_domains += domains
|
||||
out_ids += ids
|
||||
|
||||
|
||||
def process_file(file):
|
||||
@@ -172,10 +181,14 @@ if __name__ == "__main__":
|
||||
|
||||
process_dir(sys.argv[1])
|
||||
|
||||
out_all += "pub static PROVIDER_DATA: Lazy<HashMap<&'static str, &'static Provider>> = Lazy::new(|| [\n"
|
||||
out_all += "pub(crate) static PROVIDER_DATA: Lazy<HashMap<&'static str, &'static Provider>> = Lazy::new(|| [\n"
|
||||
out_all += out_domains;
|
||||
out_all += "].iter().copied().collect());\n\n"
|
||||
|
||||
out_all += "pub(crate) static PROVIDER_IDS: Lazy<HashMap<&'static str, &'static Provider>> = Lazy::new(|| [\n"
|
||||
out_all += out_ids;
|
||||
out_all += "].iter().copied().collect());\n\n"
|
||||
|
||||
now = datetime.datetime.utcnow()
|
||||
out_all += "pub static PROVIDER_UPDATED: Lazy<chrono::NaiveDate> = "\
|
||||
"Lazy::new(|| chrono::NaiveDate::from_ymd("+str(now.year)+", "+str(now.month)+", "+str(now.day)+"));\n"
|
||||
|
||||
@@ -12,7 +12,7 @@ use crate::context::Context;
|
||||
use crate::events::EventType;
|
||||
use crate::login_param::{dc_build_tls, CertificateChecks, LoginParam, ServerLoginParam};
|
||||
use crate::oauth2::*;
|
||||
use crate::provider::{get_provider_info, Socket};
|
||||
use crate::provider::Socket;
|
||||
use crate::stock::StockMessage;
|
||||
|
||||
/// SMTP write and read timeout in seconds.
|
||||
@@ -107,6 +107,7 @@ impl Smtp {
|
||||
&lp.smtp,
|
||||
&lp.addr,
|
||||
lp.server_flags & DC_LP_AUTH_OAUTH2 != 0,
|
||||
lp.provider.map_or(false, |provider| provider.strict_tls),
|
||||
)
|
||||
.await;
|
||||
if let Err(ref err) = res {
|
||||
@@ -130,6 +131,7 @@ impl Smtp {
|
||||
lp: &ServerLoginParam,
|
||||
addr: &str,
|
||||
oauth2: bool,
|
||||
provider_strict_tls: bool,
|
||||
) -> Result<()> {
|
||||
if self.is_connected().await {
|
||||
warn!(context, "SMTP already connected.");
|
||||
@@ -151,9 +153,8 @@ impl Smtp {
|
||||
let domain = &lp.server;
|
||||
let port = lp.port;
|
||||
|
||||
let provider = get_provider_info(addr);
|
||||
let strict_tls = match lp.certificate_checks {
|
||||
CertificateChecks::Automatic => provider.map_or(false, |provider| provider.strict_tls),
|
||||
CertificateChecks::Automatic => provider_strict_tls,
|
||||
CertificateChecks::Strict => true,
|
||||
CertificateChecks::AcceptInvalidCertificates
|
||||
| CertificateChecks::AcceptInvalidCertificates2 => false,
|
||||
|
||||
@@ -7,7 +7,7 @@ use crate::config::Config;
|
||||
use crate::constants::DEFAULT_MAX_SMTP_RCPT_TO;
|
||||
use crate::context::Context;
|
||||
use crate::events::EventType;
|
||||
use crate::provider::get_provider_info;
|
||||
use crate::provider::get_provider_by_id;
|
||||
use itertools::Itertools;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -38,9 +38,9 @@ impl Smtp {
|
||||
let message_len_bytes = message.len();
|
||||
|
||||
let mut chunk_size = DEFAULT_MAX_SMTP_RCPT_TO;
|
||||
if let Some(provider) = get_provider_info(
|
||||
if let Some(provider) = get_provider_by_id(
|
||||
&context
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.get_config(Config::ConfiguredProvider)
|
||||
.await
|
||||
.unwrap_or_default(),
|
||||
) {
|
||||
|
||||
18
src/sql.rs
18
src/sql.rs
@@ -16,6 +16,7 @@ use crate::ephemeral::start_ephemeral_timers;
|
||||
use crate::error::format_err;
|
||||
use crate::param::*;
|
||||
use crate::peerstate::*;
|
||||
use crate::provider::get_provider_by_domain;
|
||||
use crate::{
|
||||
chat::{update_device_icon, update_saved_messages_icon},
|
||||
config::Config,
|
||||
@@ -1395,6 +1396,23 @@ CREATE INDEX devmsglabels_index1 ON devmsglabels (label);
|
||||
.await?;
|
||||
sql.set_raw_config_int(context, "dbversion", 69).await?;
|
||||
}
|
||||
if dbversion < 70 {
|
||||
info!(context, "[migration] v70");
|
||||
if let Some(addr) = context.get_config(Config::ConfiguredAddr).await {
|
||||
if let Ok(domain) = addr.parse::<EmailAddress>().map(|email| email.domain) {
|
||||
context
|
||||
.set_config(
|
||||
Config::ConfiguredProvider,
|
||||
get_provider_by_domain(&domain).map(|provider| provider.id),
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
warn!(context, "Can't parse configured address: {:?}", addr);
|
||||
}
|
||||
}
|
||||
|
||||
sql.set_raw_config_int(context, "dbversion", 70).await?;
|
||||
}
|
||||
|
||||
// (2) updates that require high-level objects
|
||||
// (the structure is complete now and all objects are usable)
|
||||
|
||||
Reference in New Issue
Block a user