mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
Separate IMAP and SMTP configuration
Co-Authored-By: link2xt <ilabdsf@gmail.com> Co-Authored-By: bjoern <r10s@b44t.com>
This commit is contained in:
@@ -274,10 +274,12 @@ char* dc_get_blobdir (const dc_context_t* context);
|
||||
* - `mail_user` = IMAP-username, guessed if left out
|
||||
* - `mail_pw` = IMAP-password (always needed)
|
||||
* - `mail_port` = IMAP-port, guessed if left out
|
||||
* - `mail_security`= IMAP-socket, one of @ref DC_SOCKET, defaults to #DC_SOCKET_AUTO
|
||||
* - `send_server` = SMTP-server, guessed if left out
|
||||
* - `send_user` = SMTP-user, guessed if left out
|
||||
* - `send_pw` = SMTP-password, guessed if left out
|
||||
* - `send_port` = SMTP-port, guessed if left out
|
||||
* - `send_security`= SMTP-socket, one of @ref DC_SOCKET, defaults to #DC_SOCKET_AUTO
|
||||
* - `server_flags` = IMAP-/SMTP-flags as a combination of @ref DC_LP flags, guessed if left out
|
||||
* - `imap_certificate_checks` = how to check IMAP certificates, one of the @ref DC_CERTCK flags, defaults to #DC_CERTCK_AUTO (0)
|
||||
* - `smtp_certificate_checks` = how to check SMTP certificates, one of the @ref DC_CERTCK flags, defaults to #DC_CERTCK_AUTO (0)
|
||||
@@ -4167,6 +4169,44 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
*/
|
||||
#define DC_MSG_VIDEOCHAT_INVITATION 70
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup DC_SOCKET DC_SOCKET
|
||||
*
|
||||
* These constants configure socket security.
|
||||
* To set socket security, use dc_set_config() with the keys "mail_security" and/or "send_security".
|
||||
* If no socket-configuration is explicitly specified, #DC_SOCKET_AUTO is used.
|
||||
*
|
||||
* @addtogroup DC_SOCKET
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Choose socket security automatically.
|
||||
*/
|
||||
#define DC_SOCKET_AUTO 0
|
||||
|
||||
|
||||
/**
|
||||
* Connect via SSL/TLS.
|
||||
*/
|
||||
#define DC_SOCKET_SSL 1
|
||||
|
||||
|
||||
/**
|
||||
* Connect via STARTTLS.
|
||||
*/
|
||||
#define DC_SOCKET_STARTTLS 2
|
||||
|
||||
|
||||
/**
|
||||
* Connect unencrypted, this should not be used.
|
||||
*/
|
||||
#define DC_SOCKET_PLAIN 3
|
||||
|
||||
/**
|
||||
* @}
|
||||
@@ -4201,54 +4241,11 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
|
||||
#define DC_LP_AUTH_NORMAL 0x4
|
||||
|
||||
|
||||
/**
|
||||
* Connect to IMAP via STARTTLS.
|
||||
* If this flag is set, automatic configuration is skipped.
|
||||
*/
|
||||
#define DC_LP_IMAP_SOCKET_STARTTLS 0x100
|
||||
|
||||
|
||||
/**
|
||||
* Connect to IMAP via SSL.
|
||||
* If this flag is set, automatic configuration is skipped.
|
||||
*/
|
||||
#define DC_LP_IMAP_SOCKET_SSL 0x200
|
||||
|
||||
|
||||
/**
|
||||
* Connect to IMAP unencrypted, this should not be used.
|
||||
* If this flag is set, automatic configuration is skipped.
|
||||
*/
|
||||
#define DC_LP_IMAP_SOCKET_PLAIN 0x400
|
||||
|
||||
|
||||
/**
|
||||
* Connect to SMTP via STARTTLS.
|
||||
* If this flag is set, automatic configuration is skipped.
|
||||
*/
|
||||
#define DC_LP_SMTP_SOCKET_STARTTLS 0x10000
|
||||
|
||||
|
||||
/**
|
||||
* Connect to SMTP via SSL.
|
||||
* If this flag is set, automatic configuration is skipped.
|
||||
*/
|
||||
#define DC_LP_SMTP_SOCKET_SSL 0x20000
|
||||
|
||||
|
||||
/**
|
||||
* Connect to SMTP unencrypted, this should not be used.
|
||||
* If this flag is set, automatic configuration is skipped.
|
||||
*/
|
||||
#define DC_LP_SMTP_SOCKET_PLAIN 0x40000 ///<
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#define DC_LP_AUTH_FLAGS (DC_LP_AUTH_OAUTH2|DC_LP_AUTH_NORMAL) // if none of these flags are set, the default is chosen
|
||||
#define DC_LP_IMAP_SOCKET_FLAGS (DC_LP_IMAP_SOCKET_STARTTLS|DC_LP_IMAP_SOCKET_SSL|DC_LP_IMAP_SOCKET_PLAIN) // if none of these flags are set, the default is chosen
|
||||
#define DC_LP_SMTP_SOCKET_FLAGS (DC_LP_SMTP_SOCKET_STARTTLS|DC_LP_SMTP_SOCKET_SSL|DC_LP_SMTP_SOCKET_PLAIN) // if none of these flags are set, the default is chosen
|
||||
|
||||
/**
|
||||
* @defgroup DC_CERTCK DC_CERTCK
|
||||
|
||||
@@ -25,11 +25,13 @@ pub enum Config {
|
||||
MailUser,
|
||||
MailPw,
|
||||
MailPort,
|
||||
MailSecurity,
|
||||
ImapCertificateChecks,
|
||||
SendServer,
|
||||
SendUser,
|
||||
SendPw,
|
||||
SendPort,
|
||||
SendSecurity,
|
||||
SmtpCertificateChecks,
|
||||
ServerFlags,
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
//! Documentation: https://developer.mozilla.org/en-US/docs/Mozilla/Thunderbird/Autoconfiguration */
|
||||
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::provider::Socket;
|
||||
|
||||
use super::read_url::read_url;
|
||||
use super::Error;
|
||||
@@ -83,10 +83,10 @@ fn parse_xml(in_emailaddr: &str, xml_raw: &str) -> Result<LoginParam, Error> {
|
||||
buf.clear();
|
||||
}
|
||||
|
||||
if moz_ac.out.mail_server.is_empty()
|
||||
|| moz_ac.out.mail_port == 0
|
||||
|| moz_ac.out.send_server.is_empty()
|
||||
|| moz_ac.out.send_port == 0
|
||||
if moz_ac.out.imap.server.is_empty()
|
||||
|| moz_ac.out.imap.port == 0
|
||||
|| moz_ac.out.smtp.server.is_empty()
|
||||
|| moz_ac.out.smtp.port == 0
|
||||
{
|
||||
Err(Error::IncompleteAutoconfig(moz_ac.out))
|
||||
} else {
|
||||
@@ -130,37 +130,37 @@ fn moz_autoconfigure_text_cb<B: std::io::BufRead>(
|
||||
|
||||
match moz_ac.tag_server {
|
||||
MozServer::Imap => match moz_ac.tag_config {
|
||||
MozConfigTag::Hostname => moz_ac.out.mail_server = val,
|
||||
MozConfigTag::Port => moz_ac.out.mail_port = val.parse().unwrap_or_default(),
|
||||
MozConfigTag::Username => moz_ac.out.mail_user = val,
|
||||
MozConfigTag::Hostname => moz_ac.out.imap.server = val,
|
||||
MozConfigTag::Port => moz_ac.out.imap.port = val.parse().unwrap_or_default(),
|
||||
MozConfigTag::Username => moz_ac.out.imap.user = val,
|
||||
MozConfigTag::Sockettype => {
|
||||
let val_lower = val.to_lowercase();
|
||||
if val_lower == "ssl" {
|
||||
moz_ac.out.server_flags |= DC_LP_IMAP_SOCKET_SSL as i32
|
||||
moz_ac.out.imap.security = Socket::SSL;
|
||||
}
|
||||
if val_lower == "starttls" {
|
||||
moz_ac.out.server_flags |= DC_LP_IMAP_SOCKET_STARTTLS as i32
|
||||
moz_ac.out.imap.security = Socket::STARTTLS;
|
||||
}
|
||||
if val_lower == "plain" {
|
||||
moz_ac.out.server_flags |= DC_LP_IMAP_SOCKET_PLAIN as i32
|
||||
moz_ac.out.imap.security = Socket::Plain;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
MozServer::Smtp => match moz_ac.tag_config {
|
||||
MozConfigTag::Hostname => moz_ac.out.send_server = val,
|
||||
MozConfigTag::Port => moz_ac.out.send_port = val.parse().unwrap_or_default(),
|
||||
MozConfigTag::Username => moz_ac.out.send_user = val,
|
||||
MozConfigTag::Hostname => moz_ac.out.smtp.server = val,
|
||||
MozConfigTag::Port => moz_ac.out.smtp.port = val.parse().unwrap_or_default(),
|
||||
MozConfigTag::Username => moz_ac.out.smtp.user = val,
|
||||
MozConfigTag::Sockettype => {
|
||||
let val_lower = val.to_lowercase();
|
||||
if val_lower == "ssl" {
|
||||
moz_ac.out.server_flags |= DC_LP_SMTP_SOCKET_SSL as i32
|
||||
moz_ac.out.smtp.security = Socket::SSL;
|
||||
}
|
||||
if val_lower == "starttls" {
|
||||
moz_ac.out.server_flags |= DC_LP_SMTP_SOCKET_STARTTLS as i32
|
||||
moz_ac.out.smtp.security = Socket::STARTTLS;
|
||||
}
|
||||
if val_lower == "plain" {
|
||||
moz_ac.out.server_flags |= DC_LP_SMTP_SOCKET_PLAIN as i32
|
||||
moz_ac.out.smtp.security = Socket::Plain;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -314,9 +314,9 @@ mod tests {
|
||||
</webMail>
|
||||
</clientConfig>";
|
||||
let res = parse_xml("example@outlook.com", xml_raw).expect("XML parsing failed");
|
||||
assert_eq!(res.mail_server, "outlook.office365.com");
|
||||
assert_eq!(res.mail_port, 993);
|
||||
assert_eq!(res.send_server, "smtp.office365.com");
|
||||
assert_eq!(res.send_port, 587);
|
||||
assert_eq!(res.imap.server, "outlook.office365.com");
|
||||
assert_eq!(res.imap.port, 993);
|
||||
assert_eq!(res.smtp.server, "smtp.office365.com");
|
||||
assert_eq!(res.smtp.port, 587);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
use quick_xml::events::BytesEnd;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::provider::Socket;
|
||||
|
||||
use super::read_url::read_url;
|
||||
use super::Error;
|
||||
@@ -15,7 +15,7 @@ struct OutlookAutodiscover {
|
||||
pub out_smtp_set: bool,
|
||||
pub config_type: Option<String>,
|
||||
pub config_server: String,
|
||||
pub config_port: i32,
|
||||
pub config_port: u16,
|
||||
pub config_ssl: String,
|
||||
pub config_redirecturl: Option<String>,
|
||||
}
|
||||
@@ -98,10 +98,10 @@ fn parse_xml(xml_raw: &str) -> Result<ParsingResult, Error> {
|
||||
let res = if outlk_ad.config_redirecturl.is_none()
|
||||
|| outlk_ad.config_redirecturl.as_ref().unwrap().is_empty()
|
||||
{
|
||||
if outlk_ad.out.mail_server.is_empty()
|
||||
|| outlk_ad.out.mail_port == 0
|
||||
|| outlk_ad.out.send_server.is_empty()
|
||||
|| outlk_ad.out.send_port == 0
|
||||
if outlk_ad.out.imap.server.is_empty()
|
||||
|| outlk_ad.out.imap.port == 0
|
||||
|| outlk_ad.out.smtp.server.is_empty()
|
||||
|| outlk_ad.out.smtp.port == 0
|
||||
{
|
||||
return Err(Error::IncompleteAutoconfig(outlk_ad.out));
|
||||
}
|
||||
@@ -142,23 +142,23 @@ fn outlk_autodiscover_endtag_cb(event: &BytesEnd, outlk_ad: &mut OutlookAutodisc
|
||||
let ssl_on = outlk_ad.config_ssl == "on";
|
||||
let ssl_off = outlk_ad.config_ssl == "off";
|
||||
if type_ == "imap" && !outlk_ad.out_imap_set {
|
||||
outlk_ad.out.mail_server =
|
||||
outlk_ad.out.imap.server =
|
||||
std::mem::replace(&mut outlk_ad.config_server, String::new());
|
||||
outlk_ad.out.mail_port = port;
|
||||
outlk_ad.out.imap.port = port;
|
||||
if ssl_on {
|
||||
outlk_ad.out.server_flags |= DC_LP_IMAP_SOCKET_SSL as i32
|
||||
outlk_ad.out.imap.security = Socket::SSL
|
||||
} else if ssl_off {
|
||||
outlk_ad.out.server_flags |= DC_LP_IMAP_SOCKET_PLAIN as i32
|
||||
outlk_ad.out.imap.security = Socket::Plain
|
||||
}
|
||||
outlk_ad.out_imap_set = true
|
||||
} else if type_ == "smtp" && !outlk_ad.out_smtp_set {
|
||||
outlk_ad.out.send_server =
|
||||
outlk_ad.out.smtp.server =
|
||||
std::mem::replace(&mut outlk_ad.config_server, String::new());
|
||||
outlk_ad.out.send_port = outlk_ad.config_port;
|
||||
outlk_ad.out.smtp.port = outlk_ad.config_port;
|
||||
if ssl_on {
|
||||
outlk_ad.out.server_flags |= DC_LP_SMTP_SOCKET_SSL as i32
|
||||
outlk_ad.out.smtp.security = Socket::SSL
|
||||
} else if ssl_off {
|
||||
outlk_ad.out.server_flags |= DC_LP_SMTP_SOCKET_PLAIN as i32
|
||||
outlk_ad.out.smtp.security = Socket::Plain
|
||||
}
|
||||
outlk_ad.out_smtp_set = true
|
||||
}
|
||||
@@ -229,10 +229,10 @@ mod tests {
|
||||
|
||||
match res {
|
||||
ParsingResult::LoginParam(lp) => {
|
||||
assert_eq!(lp.mail_server, "example.com");
|
||||
assert_eq!(lp.mail_port, 993);
|
||||
assert_eq!(lp.send_server, "smtp.example.com");
|
||||
assert_eq!(lp.send_port, 25);
|
||||
assert_eq!(lp.imap.server, "example.com");
|
||||
assert_eq!(lp.imap.port, 993);
|
||||
assert_eq!(lp.smtp.server, "smtp.example.com");
|
||||
assert_eq!(lp.smtp.port, 25);
|
||||
}
|
||||
ParsingResult::RedirectUrl(_) => {
|
||||
panic!("RedirectUrl is not expected");
|
||||
|
||||
@@ -13,14 +13,16 @@ use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::imap::Imap;
|
||||
use crate::login_param::{CertificateChecks, LoginParam};
|
||||
use crate::login_param::{CertificateChecks, LoginParam, LoginParamNew, ServerParams};
|
||||
use crate::message::Message;
|
||||
use crate::oauth2::*;
|
||||
use crate::provider::Socket;
|
||||
use crate::smtp::Smtp;
|
||||
use crate::{chat, e2ee, provider};
|
||||
|
||||
use auto_mozilla::moz_autoconfigure;
|
||||
use auto_outlook::outlk_autodiscover;
|
||||
use provider::{Protocol, UsernamePattern};
|
||||
|
||||
macro_rules! progress {
|
||||
($context:tt, $progress:expr) => {
|
||||
@@ -115,7 +117,7 @@ impl Context {
|
||||
}
|
||||
|
||||
async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
|
||||
let mut param_autoconfig: Option<LoginParam> = None;
|
||||
let mut param_autoconfig: Option<LoginParamNew> = None;
|
||||
let mut keep_flags = 0;
|
||||
|
||||
// Read login parameters from the database
|
||||
@@ -128,7 +130,7 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
|
||||
// the used oauth2 addr may differ, check this.
|
||||
// if dc_get_oauth2_addr() is not available in the oauth2 implementation, just use the given one.
|
||||
progress!(ctx, 10);
|
||||
if let Some(oauth2_addr) = dc_get_oauth2_addr(ctx, ¶m.addr, ¶m.mail_pw)
|
||||
if let Some(oauth2_addr) = dc_get_oauth2_addr(ctx, ¶m.addr, ¶m.imap.password)
|
||||
.await
|
||||
.and_then(|e| e.parse().ok())
|
||||
{
|
||||
@@ -152,11 +154,11 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
|
||||
// param.mail_user.is_empty() -- the user can enter a loginname which is used by autoconfig then
|
||||
// param.send_pw.is_empty() -- the password cannot be auto-configured and is no criterion for
|
||||
// autoconfig or not
|
||||
if param.mail_server.is_empty()
|
||||
&& param.mail_port == 0
|
||||
&& param.send_server.is_empty()
|
||||
&& param.send_port == 0
|
||||
&& param.send_user.is_empty()
|
||||
if param.imap.server.is_empty()
|
||||
&& param.imap.port == 0
|
||||
&& param.smtp.server.is_empty()
|
||||
&& param.smtp.port == 0
|
||||
&& param.smtp.user.is_empty()
|
||||
&& (param.server_flags & !DC_LP_AUTH_OAUTH2) == 0
|
||||
{
|
||||
// no advanced parameters entered by the user: query provider-database or do Autoconfig
|
||||
@@ -175,34 +177,32 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
|
||||
// C. Do we have any autoconfig result?
|
||||
progress!(ctx, 500);
|
||||
if let Some(ref cfg) = param_autoconfig {
|
||||
info!(ctx, "Got autoconfig: {}", &cfg);
|
||||
if !cfg.mail_user.is_empty() {
|
||||
param.mail_user = cfg.mail_user.clone();
|
||||
if let Some(cfg) = loginparam_new_to_old(ctx, cfg) {
|
||||
info!(ctx, "Got autoconfig: {:?}", &cfg);
|
||||
if !cfg.imap.user.is_empty() {
|
||||
param.imap.user = cfg.imap.user.clone();
|
||||
}
|
||||
// all other values are always NULL when entering autoconfig
|
||||
param.imap.server = cfg.imap.server.clone();
|
||||
param.imap.port = cfg.imap.port;
|
||||
param.imap.security = cfg.imap.security;
|
||||
param.smtp.server = cfg.smtp.server.clone();
|
||||
param.smtp.port = cfg.smtp.port;
|
||||
param.smtp.user = cfg.smtp.user.clone();
|
||||
param.smtp.security = cfg.smtp.security;
|
||||
param.server_flags = cfg.server_flags;
|
||||
// although param_autoconfig's data are no longer needed from,
|
||||
// it is used to later to prevent trying variations of port/server/logins
|
||||
}
|
||||
// all other values are always NULL when entering autoconfig
|
||||
param.mail_server = cfg.mail_server.clone();
|
||||
param.mail_port = cfg.mail_port;
|
||||
param.send_server = cfg.send_server.clone();
|
||||
param.send_port = cfg.send_port;
|
||||
param.send_user = cfg.send_user.clone();
|
||||
param.server_flags = cfg.server_flags;
|
||||
// although param_autoconfig's data are no longer needed from,
|
||||
// it is used to later to prevent trying variations of port/server/logins
|
||||
}
|
||||
param.server_flags |= keep_flags;
|
||||
|
||||
// Step 3: Fill missing fields with defaults
|
||||
if param.send_user.is_empty() {
|
||||
param.send_user = param.mail_user.clone();
|
||||
if param.smtp.user.is_empty() {
|
||||
param.smtp.user = param.imap.user.clone();
|
||||
}
|
||||
if param.send_pw.is_empty() {
|
||||
param.send_pw = param.mail_pw.clone()
|
||||
}
|
||||
if !dc_exactly_one_bit_set(param.server_flags & DC_LP_IMAP_SOCKET_FLAGS as i32) {
|
||||
param.server_flags &= !(DC_LP_IMAP_SOCKET_FLAGS as i32);
|
||||
}
|
||||
if !dc_exactly_one_bit_set(param.server_flags & (DC_LP_SMTP_SOCKET_FLAGS as i32)) {
|
||||
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
||||
if param.smtp.password.is_empty() {
|
||||
param.smtp.password = param.imap.password.clone()
|
||||
}
|
||||
if !dc_exactly_one_bit_set(param.server_flags & DC_LP_AUTH_FLAGS as i32) {
|
||||
param.server_flags &= !(DC_LP_AUTH_FLAGS as i32);
|
||||
@@ -211,7 +211,7 @@ async fn configure(ctx: &Context, param: &mut LoginParam) -> Result<()> {
|
||||
|
||||
// do we have a complete configuration?
|
||||
ensure!(
|
||||
!param.mail_pw.is_empty() && !param.send_pw.is_empty(),
|
||||
!param.imap.password.is_empty() && !param.smtp.password.is_empty(),
|
||||
"Account settings incomplete."
|
||||
);
|
||||
|
||||
@@ -337,7 +337,7 @@ async fn get_autoconfig(
|
||||
param: &LoginParam,
|
||||
param_domain: &str,
|
||||
param_addr_urlencoded: &str,
|
||||
) -> Option<LoginParam> {
|
||||
) -> Option<LoginParamNew> {
|
||||
let sources = AutoconfigSource::all(param_domain, param_addr_urlencoded);
|
||||
|
||||
let mut progress = 300;
|
||||
@@ -346,14 +346,14 @@ async fn get_autoconfig(
|
||||
progress!(ctx, progress);
|
||||
progress += 10;
|
||||
if let Ok(res) = res {
|
||||
return Some(res);
|
||||
return Some(loginparam_old_to_new(res));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn get_offline_autoconfig(context: &Context, param: &LoginParam) -> Option<LoginParam> {
|
||||
fn get_offline_autoconfig(context: &Context, param: &LoginParam) -> Option<LoginParamNew> {
|
||||
info!(
|
||||
context,
|
||||
"checking internal provider-info for offline autoconfig"
|
||||
@@ -364,39 +364,11 @@ fn get_offline_autoconfig(context: &Context, param: &LoginParam) -> Option<Login
|
||||
provider::Status::OK | provider::Status::PREPARATION => {
|
||||
let imap = provider.get_imap_server();
|
||||
let smtp = provider.get_smtp_server();
|
||||
// clippy complains about these is_some()/unwrap() settings,
|
||||
// however, rewriting the code to "if let" would make things less obvious,
|
||||
// esp. if we allow more combinations of servers (pop, jmap).
|
||||
// therefore, #[allow(clippy::unnecessary_unwrap)] is added above.
|
||||
if let Some(imap) = imap {
|
||||
if let Some(smtp) = smtp {
|
||||
let mut p = LoginParam::new();
|
||||
p.addr = param.addr.clone();
|
||||
|
||||
p.mail_server = imap.hostname.to_string();
|
||||
p.mail_user = imap.apply_username_pattern(param.addr.clone());
|
||||
p.mail_port = imap.port as i32;
|
||||
p.imap_certificate_checks = CertificateChecks::Automatic;
|
||||
p.server_flags |= match imap.socket {
|
||||
provider::Socket::STARTTLS => DC_LP_IMAP_SOCKET_STARTTLS,
|
||||
provider::Socket::SSL => DC_LP_IMAP_SOCKET_SSL,
|
||||
};
|
||||
|
||||
p.send_server = smtp.hostname.to_string();
|
||||
p.send_user = smtp.apply_username_pattern(param.addr.clone());
|
||||
p.send_port = smtp.port as i32;
|
||||
p.smtp_certificate_checks = CertificateChecks::Automatic;
|
||||
p.server_flags |= match smtp.socket {
|
||||
provider::Socket::STARTTLS => DC_LP_SMTP_SOCKET_STARTTLS as i32,
|
||||
provider::Socket::SSL => DC_LP_SMTP_SOCKET_SSL as i32,
|
||||
};
|
||||
|
||||
info!(context, "offline autoconfig found: {}", p);
|
||||
return Some(p);
|
||||
}
|
||||
}
|
||||
info!(context, "offline autoconfig found, but no servers defined");
|
||||
return None;
|
||||
return Some(LoginParamNew {
|
||||
addr: param.addr.clone(),
|
||||
imap,
|
||||
smtp,
|
||||
});
|
||||
}
|
||||
provider::Status::BROKEN => {
|
||||
info!(context, "offline autoconfig found, provider is broken");
|
||||
@@ -408,28 +380,83 @@ fn get_offline_autoconfig(context: &Context, param: &LoginParam) -> Option<Login
|
||||
None
|
||||
}
|
||||
|
||||
pub fn loginparam_new_to_old(context: &Context, servers: &LoginParamNew) -> Option<LoginParam> {
|
||||
let LoginParamNew { addr, imap, smtp } = servers;
|
||||
if let Some(imap) = imap.get(0) {
|
||||
if let Some(smtp) = smtp.get(0) {
|
||||
let mut p = LoginParam::new();
|
||||
p.addr = addr.clone();
|
||||
|
||||
p.imap.server = imap.hostname.to_string();
|
||||
p.imap.user = imap.apply_username_pattern(addr.clone());
|
||||
p.imap.port = imap.port;
|
||||
p.imap.security = imap.socket;
|
||||
p.imap.certificate_checks = CertificateChecks::Automatic;
|
||||
|
||||
p.smtp.server = smtp.hostname.to_string();
|
||||
p.smtp.user = smtp.apply_username_pattern(addr.clone());
|
||||
p.smtp.port = smtp.port;
|
||||
p.smtp.security = smtp.socket;
|
||||
p.smtp.certificate_checks = CertificateChecks::Automatic;
|
||||
|
||||
info!(context, "offline autoconfig found: {}", p);
|
||||
return Some(p);
|
||||
}
|
||||
}
|
||||
info!(context, "offline autoconfig found, but no servers defined");
|
||||
None
|
||||
}
|
||||
|
||||
pub fn loginparam_old_to_new(p: LoginParam) -> LoginParamNew {
|
||||
LoginParamNew {
|
||||
addr: p.addr.clone(),
|
||||
imap: vec![ServerParams {
|
||||
protocol: Protocol::IMAP,
|
||||
socket: p.imap.security,
|
||||
port: p.imap.port,
|
||||
hostname: p.imap.server,
|
||||
username_pattern: if p.imap.user.contains('@') {
|
||||
UsernamePattern::EMAIL
|
||||
} else {
|
||||
UsernamePattern::EMAILLOCALPART
|
||||
},
|
||||
}],
|
||||
smtp: vec![ServerParams {
|
||||
protocol: Protocol::SMTP,
|
||||
socket: p.smtp.security,
|
||||
port: p.smtp.port,
|
||||
hostname: p.smtp.server,
|
||||
username_pattern: if p.smtp.user.contains('@') {
|
||||
UsernamePattern::EMAIL
|
||||
} else {
|
||||
provider::UsernamePattern::EMAILLOCALPART
|
||||
},
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
async fn try_imap_hostnames(
|
||||
context: &Context,
|
||||
mut param: LoginParam,
|
||||
imap: &mut Imap,
|
||||
) -> Result<LoginParam> {
|
||||
if param.mail_server.is_empty() {
|
||||
if param.imap.server.is_empty() {
|
||||
let parsed: EmailAddress = param.addr.parse().context("Bad email-address")?;
|
||||
let param_domain = parsed.domain;
|
||||
|
||||
param.mail_server = param_domain.clone();
|
||||
param.imap.server = param_domain.clone();
|
||||
if let Ok(param) = try_imap_ports(context, param.clone(), imap).await {
|
||||
return Ok(param);
|
||||
}
|
||||
|
||||
progress!(context, 650);
|
||||
param.mail_server = "imap.".to_string() + ¶m_domain;
|
||||
param.imap.server = "imap.".to_string() + ¶m_domain;
|
||||
if let Ok(param) = try_imap_ports(context, param.clone(), imap).await {
|
||||
return Ok(param);
|
||||
}
|
||||
|
||||
progress!(context, 700);
|
||||
param.mail_server = "mail.".to_string() + ¶m_domain;
|
||||
param.imap.server = "mail.".to_string() + ¶m_domain;
|
||||
try_imap_ports(context, param, imap).await
|
||||
} else {
|
||||
progress!(context, 700);
|
||||
@@ -444,44 +471,39 @@ async fn try_imap_ports(
|
||||
imap: &mut Imap,
|
||||
) -> Result<LoginParam> {
|
||||
// Try to infer port from socket security.
|
||||
if param.mail_port == 0 {
|
||||
if 0 != param.server_flags & DC_LP_IMAP_SOCKET_SSL {
|
||||
param.mail_port = 993
|
||||
}
|
||||
if 0 != param.server_flags & (DC_LP_IMAP_SOCKET_STARTTLS | DC_LP_IMAP_SOCKET_PLAIN) {
|
||||
param.mail_port = 143
|
||||
if param.imap.port == 0 {
|
||||
param.imap.port = match param.imap.security {
|
||||
Socket::SSL => 993,
|
||||
Socket::STARTTLS | Socket::Plain => 143,
|
||||
Socket::Automatic => 0,
|
||||
}
|
||||
}
|
||||
|
||||
if param.mail_port == 0 {
|
||||
if param.imap.port == 0 {
|
||||
// Neither port nor security is set.
|
||||
//
|
||||
// Try common secure combinations.
|
||||
|
||||
// Try TLS over port 993
|
||||
param.server_flags &= !(DC_LP_IMAP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= DC_LP_IMAP_SOCKET_SSL as i32;
|
||||
param.mail_port = 993;
|
||||
param.imap.security = Socket::SSL;
|
||||
param.imap.port = 993;
|
||||
if let Ok(login_param) = try_imap_usernames(context, param.clone(), imap).await {
|
||||
return Ok(login_param);
|
||||
}
|
||||
|
||||
// Try STARTTLS over port 143
|
||||
param.server_flags &= !(DC_LP_IMAP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= DC_LP_IMAP_SOCKET_STARTTLS as i32;
|
||||
param.mail_port = 143;
|
||||
param.imap.security = Socket::STARTTLS;
|
||||
param.imap.port = 143;
|
||||
try_imap_usernames(context, param, imap).await
|
||||
} else if 0 == param.server_flags & DC_LP_SMTP_SOCKET_FLAGS as i32 {
|
||||
} else if param.imap.security == Socket::Automatic {
|
||||
// Try TLS over user-provided port.
|
||||
param.server_flags &= !(DC_LP_IMAP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= DC_LP_IMAP_SOCKET_SSL as i32;
|
||||
param.imap.security = Socket::SSL;
|
||||
if let Ok(login_param) = try_imap_usernames(context, param.clone(), imap).await {
|
||||
return Ok(login_param);
|
||||
}
|
||||
|
||||
// Try STARTTLS over user-provided port.
|
||||
param.server_flags &= !(DC_LP_IMAP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= DC_LP_IMAP_SOCKET_STARTTLS as i32;
|
||||
param.imap.security = Socket::STARTTLS;
|
||||
try_imap_usernames(context, param, imap).await
|
||||
} else {
|
||||
try_imap_usernames(context, param, imap).await
|
||||
@@ -493,11 +515,11 @@ async fn try_imap_usernames(
|
||||
mut param: LoginParam,
|
||||
imap: &mut Imap,
|
||||
) -> Result<LoginParam> {
|
||||
if param.mail_user.is_empty() {
|
||||
param.mail_user = param.addr.clone();
|
||||
if param.imap.user.is_empty() {
|
||||
param.imap.user = param.addr.clone();
|
||||
if let Err(e) = try_imap_one_param(context, ¶m, imap).await {
|
||||
if let Some(at) = param.mail_user.find('@') {
|
||||
param.mail_user = param.mail_user.split_at(at).0.to_string();
|
||||
if let Some(at) = param.imap.user.find('@') {
|
||||
param.imap.user = param.imap.user.split_at(at).0.to_string();
|
||||
try_imap_one_param(context, ¶m, imap).await?;
|
||||
} else {
|
||||
return Err(e);
|
||||
@@ -512,16 +534,25 @@ async fn try_imap_usernames(
|
||||
|
||||
async fn try_imap_one_param(context: &Context, param: &LoginParam, imap: &mut Imap) -> Result<()> {
|
||||
let inf = format!(
|
||||
"imap: {}@{}:{} flags=0x{:x} certificate_checks={}",
|
||||
param.mail_user,
|
||||
param.mail_server,
|
||||
param.mail_port,
|
||||
"imap: {}@{}:{} security={} certificate_checks={} flags=0x{:x}",
|
||||
param.imap.user,
|
||||
param.imap.server,
|
||||
param.imap.port,
|
||||
param.imap.security,
|
||||
param.imap.certificate_checks,
|
||||
param.server_flags,
|
||||
param.imap_certificate_checks
|
||||
);
|
||||
info!(context, "Trying: {}", inf);
|
||||
|
||||
if imap.connect(context, ¶m).await {
|
||||
if imap
|
||||
.connect(
|
||||
context,
|
||||
¶m.imap,
|
||||
¶m.addr,
|
||||
param.server_flags & DC_LP_AUTH_OAUTH2 != 0,
|
||||
)
|
||||
.await
|
||||
{
|
||||
info!(context, "success: {}", inf);
|
||||
return Ok(());
|
||||
}
|
||||
@@ -534,23 +565,23 @@ async fn try_smtp_hostnames(
|
||||
mut param: LoginParam,
|
||||
smtp: &mut Smtp,
|
||||
) -> Result<LoginParam> {
|
||||
if param.send_server.is_empty() {
|
||||
if param.smtp.server.is_empty() {
|
||||
let parsed: EmailAddress = param.addr.parse().context("Bad email-address")?;
|
||||
let param_domain = parsed.domain;
|
||||
|
||||
param.send_server = param_domain.clone();
|
||||
param.smtp.server = param_domain.clone();
|
||||
if let Ok(param) = try_smtp_ports(context, param.clone(), smtp).await {
|
||||
return Ok(param);
|
||||
}
|
||||
|
||||
progress!(context, 800);
|
||||
param.send_server = "smtp.".to_string() + ¶m_domain;
|
||||
param.smtp.server = "smtp.".to_string() + ¶m_domain;
|
||||
if let Ok(param) = try_smtp_ports(context, param.clone(), smtp).await {
|
||||
return Ok(param);
|
||||
}
|
||||
|
||||
progress!(context, 850);
|
||||
param.send_server = "mail.".to_string() + ¶m_domain;
|
||||
param.smtp.server = "mail.".to_string() + ¶m_domain;
|
||||
try_smtp_ports(context, param, smtp).await
|
||||
} else {
|
||||
progress!(context, 850);
|
||||
@@ -565,47 +596,39 @@ async fn try_smtp_ports(
|
||||
smtp: &mut Smtp,
|
||||
) -> Result<LoginParam> {
|
||||
// Try to infer port from socket security.
|
||||
if param.send_port == 0 {
|
||||
if 0 != param.server_flags & DC_LP_SMTP_SOCKET_STARTTLS as i32 {
|
||||
param.send_port = 587;
|
||||
}
|
||||
if 0 != param.server_flags & DC_LP_SMTP_SOCKET_PLAIN as i32 {
|
||||
param.send_port = 25;
|
||||
}
|
||||
if 0 != param.server_flags & DC_LP_SMTP_SOCKET_SSL as i32 {
|
||||
param.send_port = 465;
|
||||
}
|
||||
if param.smtp.port == 0 {
|
||||
param.smtp.port = match param.smtp.security {
|
||||
Socket::Automatic => 0,
|
||||
Socket::STARTTLS | Socket::Plain => 587,
|
||||
Socket::SSL => 465,
|
||||
};
|
||||
}
|
||||
|
||||
if param.send_port == 0 {
|
||||
if param.smtp.port == 0 {
|
||||
// Neither port nor security is set.
|
||||
//
|
||||
// Try common secure combinations.
|
||||
|
||||
// Try TLS over port 465.
|
||||
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= DC_LP_SMTP_SOCKET_SSL as i32;
|
||||
param.send_port = 465;
|
||||
param.smtp.security = Socket::SSL;
|
||||
param.smtp.port = 465;
|
||||
if let Ok(login_param) = try_smtp_usernames(context, param.clone(), smtp).await {
|
||||
return Ok(login_param);
|
||||
}
|
||||
|
||||
// Try STARTTLS over port 587.
|
||||
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= DC_LP_SMTP_SOCKET_STARTTLS as i32;
|
||||
param.send_port = 587;
|
||||
param.smtp.security = Socket::STARTTLS;
|
||||
param.smtp.port = 587;
|
||||
try_smtp_usernames(context, param, smtp).await
|
||||
} else if 0 == param.server_flags & DC_LP_SMTP_SOCKET_FLAGS as i32 {
|
||||
} else if param.smtp.security == Socket::Automatic {
|
||||
// Try TLS over user-provided port.
|
||||
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= DC_LP_SMTP_SOCKET_SSL as i32;
|
||||
param.smtp.security = Socket::SSL;
|
||||
if let Ok(param) = try_smtp_usernames(context, param.clone(), smtp).await {
|
||||
return Ok(param);
|
||||
}
|
||||
|
||||
// Try STARTTLS over user-provided port.
|
||||
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
||||
param.server_flags |= DC_LP_SMTP_SOCKET_STARTTLS as i32;
|
||||
param.smtp.security = Socket::STARTTLS;
|
||||
try_smtp_usernames(context, param, smtp).await
|
||||
} else {
|
||||
try_smtp_usernames(context, param, smtp).await
|
||||
@@ -617,11 +640,11 @@ async fn try_smtp_usernames(
|
||||
mut param: LoginParam,
|
||||
smtp: &mut Smtp,
|
||||
) -> Result<LoginParam> {
|
||||
if param.send_user.is_empty() {
|
||||
param.send_user = param.addr.clone();
|
||||
if param.smtp.user.is_empty() {
|
||||
param.smtp.user = param.addr.clone();
|
||||
if let Err(e) = try_smtp_one_param(context, ¶m, smtp).await {
|
||||
if let Some(at) = param.send_user.find('@') {
|
||||
param.send_user = param.send_user.split_at(at).0.to_string();
|
||||
if let Some(at) = param.smtp.user.find('@') {
|
||||
param.smtp.user = param.smtp.user.split_at(at).0.to_string();
|
||||
try_smtp_one_param(context, ¶m, smtp).await?;
|
||||
} else {
|
||||
return Err(e);
|
||||
@@ -636,12 +659,25 @@ async fn try_smtp_usernames(
|
||||
|
||||
async fn try_smtp_one_param(context: &Context, param: &LoginParam, smtp: &mut Smtp) -> Result<()> {
|
||||
let inf = format!(
|
||||
"smtp: {}@{}:{} flags: 0x{:x}",
|
||||
param.send_user, param.send_server, param.send_port, param.server_flags
|
||||
"smtp: {}@{}:{} security={} certificate_checks={} flags=0x{:x}",
|
||||
param.smtp.user,
|
||||
param.smtp.server,
|
||||
param.smtp.port,
|
||||
param.smtp.security,
|
||||
param.smtp.certificate_checks,
|
||||
param.server_flags
|
||||
);
|
||||
info!(context, "Trying: {}", inf);
|
||||
|
||||
if let Err(err) = smtp.connect(context, ¶m).await {
|
||||
if let Err(err) = smtp
|
||||
.connect(
|
||||
context,
|
||||
¶m.smtp,
|
||||
¶m.addr,
|
||||
param.server_flags & DC_LP_AUTH_OAUTH2 != 0,
|
||||
)
|
||||
.await
|
||||
{
|
||||
bail!("could not connect: {}", err);
|
||||
}
|
||||
|
||||
@@ -704,16 +740,13 @@ mod tests {
|
||||
let mut params = LoginParam::new();
|
||||
params.addr = "someone123@nauta.cu".to_string();
|
||||
let found_params = get_offline_autoconfig(&context, ¶ms).unwrap();
|
||||
assert_eq!(found_params.mail_server, "imap.nauta.cu".to_string());
|
||||
assert_eq!(found_params.send_server, "smtp.nauta.cu".to_string());
|
||||
assert_eq!(found_params.imap.len(), 1);
|
||||
assert_eq!(found_params.smtp.len(), 1);
|
||||
assert_eq!(found_params.imap[0].hostname, "imap.nauta.cu".to_string());
|
||||
assert_eq!(found_params.smtp[0].hostname, "smtp.nauta.cu".to_string());
|
||||
|
||||
assert_eq!(
|
||||
found_params.imap_certificate_checks,
|
||||
CertificateChecks::Automatic
|
||||
);
|
||||
assert_eq!(
|
||||
found_params.smtp_certificate_checks,
|
||||
CertificateChecks::Automatic
|
||||
);
|
||||
let lp_old = loginparam_new_to_old(&context, &found_params).unwrap();
|
||||
assert_eq!(lp_old.imap.certificate_checks, CertificateChecks::Automatic);
|
||||
assert_eq!(lp_old.smtp.certificate_checks, CertificateChecks::Automatic);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,38 +199,8 @@ pub const DC_LP_AUTH_OAUTH2: i32 = 0x2;
|
||||
/// If this flag is set, automatic configuration is skipped.
|
||||
pub const DC_LP_AUTH_NORMAL: i32 = 0x4;
|
||||
|
||||
/// Connect to IMAP via STARTTLS.
|
||||
/// If this flag is set, automatic configuration is skipped.
|
||||
pub const DC_LP_IMAP_SOCKET_STARTTLS: i32 = 0x100;
|
||||
|
||||
/// Connect to IMAP via SSL.
|
||||
/// If this flag is set, automatic configuration is skipped.
|
||||
pub const DC_LP_IMAP_SOCKET_SSL: i32 = 0x200;
|
||||
|
||||
/// Connect to IMAP unencrypted, this should not be used.
|
||||
/// If this flag is set, automatic configuration is skipped.
|
||||
pub const DC_LP_IMAP_SOCKET_PLAIN: i32 = 0x400;
|
||||
|
||||
/// Connect to SMTP via STARTTLS.
|
||||
/// If this flag is set, automatic configuration is skipped.
|
||||
pub const DC_LP_SMTP_SOCKET_STARTTLS: usize = 0x10000;
|
||||
|
||||
/// Connect to SMTP via SSL.
|
||||
/// If this flag is set, automatic configuration is skipped.
|
||||
pub const DC_LP_SMTP_SOCKET_SSL: usize = 0x20000;
|
||||
|
||||
/// Connect to SMTP unencrypted, this should not be used.
|
||||
/// If this flag is set, automatic configuration is skipped.
|
||||
pub const DC_LP_SMTP_SOCKET_PLAIN: usize = 0x40000;
|
||||
|
||||
/// if none of these flags are set, the default is chosen
|
||||
pub const DC_LP_AUTH_FLAGS: i32 = DC_LP_AUTH_OAUTH2 | DC_LP_AUTH_NORMAL;
|
||||
/// if none of these flags are set, the default is chosen
|
||||
pub const DC_LP_IMAP_SOCKET_FLAGS: i32 =
|
||||
DC_LP_IMAP_SOCKET_STARTTLS | DC_LP_IMAP_SOCKET_SSL | DC_LP_IMAP_SOCKET_PLAIN;
|
||||
/// if none of these flags are set, the default is chosen
|
||||
pub const DC_LP_SMTP_SOCKET_FLAGS: usize =
|
||||
DC_LP_SMTP_SOCKET_STARTTLS | DC_LP_SMTP_SOCKET_SSL | DC_LP_SMTP_SOCKET_PLAIN;
|
||||
|
||||
// QR code scanning (view from Bob, the joiner)
|
||||
pub const DC_VC_AUTH_REQUIRED: i32 = 2;
|
||||
|
||||
@@ -20,6 +20,7 @@ use crate::message::{MessageState, MsgId};
|
||||
use crate::mimeparser::AvatarAction;
|
||||
use crate::param::*;
|
||||
use crate::peerstate::*;
|
||||
use crate::provider::Socket;
|
||||
use crate::stock::StockMessage;
|
||||
|
||||
/// An object representing a single contact in memory.
|
||||
@@ -729,8 +730,8 @@ impl Contact {
|
||||
);
|
||||
cat_fingerprint(&mut ret, &loginparam.addr, &fingerprint_self, "");
|
||||
}
|
||||
} else if 0 == loginparam.server_flags & DC_LP_IMAP_SOCKET_PLAIN as i32
|
||||
&& 0 == loginparam.server_flags & DC_LP_SMTP_SOCKET_PLAIN as i32
|
||||
} else if loginparam.imap.security != Socket::Plain
|
||||
&& loginparam.smtp.security != Socket::Plain
|
||||
{
|
||||
ret += &context.stock_str(StockMessage::EncrTransp).await;
|
||||
} else {
|
||||
|
||||
@@ -22,12 +22,12 @@ use crate::dc_receive_imf::{
|
||||
use crate::events::EventType;
|
||||
use crate::headerdef::{HeaderDef, HeaderDefMap};
|
||||
use crate::job::{self, Action};
|
||||
use crate::login_param::{CertificateChecks, LoginParam};
|
||||
use crate::login_param::{CertificateChecks, LoginParam, ServerLoginParam};
|
||||
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;
|
||||
use crate::provider::{get_provider_info, Socket};
|
||||
use crate::{
|
||||
chat, dc_tools::dc_extract_grpid_from_rfc724_mid, scheduler::InterruptInfo, stock::StockMessage,
|
||||
};
|
||||
@@ -155,8 +155,9 @@ struct ImapConfig {
|
||||
pub imap_port: u16,
|
||||
pub imap_user: String,
|
||||
pub imap_pw: String,
|
||||
pub security: Socket,
|
||||
pub strict_tls: bool,
|
||||
pub server_flags: usize,
|
||||
pub oauth2: bool,
|
||||
pub selected_folder: Option<String>,
|
||||
pub selected_mailbox: Option<Mailbox>,
|
||||
pub selected_folder_needs_expunge: bool,
|
||||
@@ -175,8 +176,9 @@ impl Default for ImapConfig {
|
||||
imap_port: 0,
|
||||
imap_user: "".into(),
|
||||
imap_pw: "".into(),
|
||||
security: Default::default(),
|
||||
strict_tls: false,
|
||||
server_flags: 0,
|
||||
oauth2: false,
|
||||
selected_folder: None,
|
||||
selected_mailbox: None,
|
||||
selected_folder_needs_expunge: false,
|
||||
@@ -223,32 +225,32 @@ impl Imap {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let server_flags = self.config.server_flags as i32;
|
||||
let oauth2 = self.config.oauth2;
|
||||
|
||||
let connection_res: ImapResult<Client> =
|
||||
if (server_flags & (DC_LP_IMAP_SOCKET_STARTTLS | DC_LP_IMAP_SOCKET_PLAIN)) != 0 {
|
||||
let config = &mut self.config;
|
||||
let imap_server: &str = config.imap_server.as_ref();
|
||||
let imap_port = config.imap_port;
|
||||
let connection_res: ImapResult<Client> = if self.config.security == Socket::STARTTLS
|
||||
|| self.config.security == Socket::Plain
|
||||
{
|
||||
let config = &mut self.config;
|
||||
let imap_server: &str = config.imap_server.as_ref();
|
||||
let imap_port = config.imap_port;
|
||||
|
||||
match Client::connect_insecure((imap_server, imap_port)).await {
|
||||
Ok(client) => {
|
||||
if (server_flags & DC_LP_IMAP_SOCKET_STARTTLS) != 0 {
|
||||
client.secure(imap_server, config.strict_tls).await
|
||||
} else {
|
||||
Ok(client)
|
||||
}
|
||||
match Client::connect_insecure((imap_server, imap_port)).await {
|
||||
Ok(client) => {
|
||||
if config.security == Socket::STARTTLS {
|
||||
client.secure(imap_server, config.strict_tls).await
|
||||
} else {
|
||||
Ok(client)
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
} else {
|
||||
let config = &self.config;
|
||||
let imap_server: &str = config.imap_server.as_ref();
|
||||
let imap_port = config.imap_port;
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
} else {
|
||||
let config = &self.config;
|
||||
let imap_server: &str = config.imap_server.as_ref();
|
||||
let imap_port = config.imap_port;
|
||||
|
||||
Client::connect_secure((imap_server, imap_port), imap_server, config.strict_tls)
|
||||
.await
|
||||
};
|
||||
Client::connect_secure((imap_server, imap_port), imap_server, config.strict_tls).await
|
||||
};
|
||||
|
||||
let login_res = match connection_res {
|
||||
Ok(client) => {
|
||||
@@ -256,7 +258,7 @@ impl Imap {
|
||||
let imap_user: &str = config.imap_user.as_ref();
|
||||
let imap_pw: &str = config.imap_pw.as_ref();
|
||||
|
||||
if (server_flags & DC_LP_AUTH_OAUTH2) != 0 {
|
||||
if oauth2 {
|
||||
let addr: &str = config.addr.as_ref();
|
||||
|
||||
if let Some(token) =
|
||||
@@ -382,7 +384,15 @@ impl Imap {
|
||||
let param = LoginParam::from_database(context, "configured_").await;
|
||||
// the trailing underscore is correct
|
||||
|
||||
if self.connect(context, ¶m).await {
|
||||
if self
|
||||
.connect(
|
||||
context,
|
||||
¶m.imap,
|
||||
¶m.addr,
|
||||
param.server_flags & DC_LP_AUTH_OAUTH2 != 0,
|
||||
)
|
||||
.await
|
||||
{
|
||||
self.ensure_configured_folders(context, true).await
|
||||
} else {
|
||||
Err(Error::ConnectionFailed(format!("{}", param)))
|
||||
@@ -390,18 +400,24 @@ impl Imap {
|
||||
}
|
||||
|
||||
/// Tries connecting to imap account using the specific login parameters.
|
||||
pub async fn connect(&mut self, context: &Context, lp: &LoginParam) -> bool {
|
||||
if lp.mail_server.is_empty() || lp.mail_user.is_empty() || lp.mail_pw.is_empty() {
|
||||
///
|
||||
/// `addr` is used to renew token if OAuth2 authentication is used.
|
||||
pub async fn connect(
|
||||
&mut self,
|
||||
context: &Context,
|
||||
lp: &ServerLoginParam,
|
||||
addr: &str,
|
||||
oauth2: bool,
|
||||
) -> bool {
|
||||
if lp.server.is_empty() || lp.user.is_empty() || lp.password.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
let addr = &lp.addr;
|
||||
let imap_server = &lp.mail_server;
|
||||
let imap_port = lp.mail_port as u16;
|
||||
let imap_user = &lp.mail_user;
|
||||
let imap_pw = &lp.mail_pw;
|
||||
let server_flags = lp.server_flags as usize;
|
||||
let imap_server = &lp.server;
|
||||
let imap_port = lp.port;
|
||||
let imap_user = &lp.user;
|
||||
let imap_pw = &lp.password;
|
||||
|
||||
let mut config = &mut self.config;
|
||||
config.addr = addr.to_string();
|
||||
@@ -409,8 +425,8 @@ impl Imap {
|
||||
config.imap_port = imap_port;
|
||||
config.imap_user = imap_user.to_string();
|
||||
config.imap_pw = imap_pw.to_string();
|
||||
let provider = get_provider_info(&lp.addr);
|
||||
config.strict_tls = match lp.imap_certificate_checks {
|
||||
let provider = get_provider_info(&addr);
|
||||
config.strict_tls = match lp.certificate_checks {
|
||||
CertificateChecks::Automatic => {
|
||||
provider.map_or(false, |provider| provider.strict_tls)
|
||||
}
|
||||
@@ -418,7 +434,7 @@ impl Imap {
|
||||
CertificateChecks::AcceptInvalidCertificates
|
||||
| CertificateChecks::AcceptInvalidCertificates2 => false,
|
||||
};
|
||||
config.server_flags = server_flags;
|
||||
config.oauth2 = oauth2;
|
||||
}
|
||||
|
||||
if let Err(err) = self.setup_handle_if_needed(context).await {
|
||||
@@ -431,7 +447,7 @@ impl Imap {
|
||||
Some(ref mut session) => match session.capabilities().await {
|
||||
Ok(caps) => {
|
||||
if !context.sql.is_open().await {
|
||||
warn!(context, "IMAP-LOGIN as {} ok but ABORTING", lp.mail_user,);
|
||||
warn!(context, "IMAP-LOGIN as {} ok but ABORTING", lp.user,);
|
||||
true
|
||||
} else {
|
||||
let can_idle = caps.has_str("IDLE");
|
||||
@@ -451,7 +467,7 @@ impl Imap {
|
||||
context,
|
||||
EventType::ImapConnected(format!(
|
||||
"IMAP-LOGIN as {}, capabilities: {}",
|
||||
lp.mail_user, caps_list,
|
||||
lp.user, caps_list,
|
||||
))
|
||||
);
|
||||
false
|
||||
|
||||
19
src/job.rs
19
src/job.rs
@@ -26,7 +26,6 @@ use crate::error::{bail, ensure, format_err, Error, Result};
|
||||
use crate::events::EventType;
|
||||
use crate::imap::*;
|
||||
use crate::location;
|
||||
use crate::login_param::LoginParam;
|
||||
use crate::message::MsgId;
|
||||
use crate::message::{self, Message, MessageState};
|
||||
use crate::mimefactory::MimeFactory;
|
||||
@@ -343,12 +342,9 @@ impl Job {
|
||||
|
||||
pub(crate) async fn send_msg_to_smtp(&mut self, context: &Context, smtp: &mut Smtp) -> Status {
|
||||
// SMTP server, if not yet done
|
||||
if !smtp.is_connected().await {
|
||||
let loginparam = LoginParam::from_database(context, "configured_").await;
|
||||
if let Err(err) = smtp.connect(context, &loginparam).await {
|
||||
warn!(context, "SMTP connection failure: {:?}", err);
|
||||
return Status::RetryLater;
|
||||
}
|
||||
if let Err(err) = smtp.connect_configured(context).await {
|
||||
warn!(context, "SMTP connection failure: {:?}", err);
|
||||
return Status::RetryLater;
|
||||
}
|
||||
|
||||
let filename = job_try!(job_try!(self
|
||||
@@ -491,12 +487,9 @@ impl Job {
|
||||
let recipients = vec![recipient];
|
||||
|
||||
// connect to SMTP server, if not yet done
|
||||
if !smtp.is_connected().await {
|
||||
let loginparam = LoginParam::from_database(context, "configured_").await;
|
||||
if let Err(err) = smtp.connect(context, &loginparam).await {
|
||||
warn!(context, "SMTP connection failure: {:?}", err);
|
||||
return Status::RetryLater;
|
||||
}
|
||||
if let Err(err) = smtp.connect_configured(context).await {
|
||||
warn!(context, "SMTP connection failure: {:?}", err);
|
||||
return Status::RetryLater;
|
||||
}
|
||||
|
||||
self.smtp_send(context, recipients, body, self.job_id, smtp, || {
|
||||
|
||||
@@ -3,13 +3,19 @@
|
||||
use std::borrow::Cow;
|
||||
use std::fmt;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::{
|
||||
context::Context,
|
||||
provider::{Protocol, Socket, UsernamePattern},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Display, FromPrimitive, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
#[strum(serialize_all = "snake_case")]
|
||||
pub enum CertificateChecks {
|
||||
/// Same as AcceptInvalidCertificates unless overridden by
|
||||
/// `strict_tls` setting in provider database.
|
||||
Automatic = 0,
|
||||
|
||||
Strict = 1,
|
||||
|
||||
/// Same as AcceptInvalidCertificates
|
||||
@@ -25,21 +31,58 @@ impl Default for CertificateChecks {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ServerParams {
|
||||
pub protocol: Protocol,
|
||||
pub socket: Socket,
|
||||
pub hostname: String,
|
||||
pub port: u16,
|
||||
pub username_pattern: UsernamePattern,
|
||||
}
|
||||
|
||||
pub type ImapServers = Vec<ServerParams>;
|
||||
pub type SmtpServers = Vec<ServerParams>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct LoginParamNew {
|
||||
pub addr: String,
|
||||
pub imap: ImapServers,
|
||||
pub smtp: SmtpServers,
|
||||
}
|
||||
|
||||
impl ServerParams {
|
||||
pub fn apply_username_pattern(&self, addr: String) -> String {
|
||||
match self.username_pattern {
|
||||
UsernamePattern::EMAIL => addr,
|
||||
UsernamePattern::EMAILLOCALPART => {
|
||||
if let Some(at) = addr.find('@') {
|
||||
return addr.split_at(at).0.to_string();
|
||||
}
|
||||
addr
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Login parameters for a single server, either IMAP or SMTP
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct ServerLoginParam {
|
||||
pub server: String,
|
||||
pub user: String,
|
||||
pub password: String,
|
||||
pub port: u16,
|
||||
pub security: Socket,
|
||||
|
||||
/// TLS options: whether to allow invalid certificates and/or
|
||||
/// invalid hostnames
|
||||
pub certificate_checks: CertificateChecks,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct LoginParam {
|
||||
pub addr: String,
|
||||
pub mail_server: String,
|
||||
pub mail_user: String,
|
||||
pub mail_pw: String,
|
||||
pub mail_port: i32,
|
||||
/// IMAP TLS options: whether to allow invalid certificates and/or invalid hostnames
|
||||
pub imap_certificate_checks: CertificateChecks,
|
||||
pub send_server: String,
|
||||
pub send_user: String,
|
||||
pub send_pw: String,
|
||||
pub send_port: i32,
|
||||
/// SMTP TLS options: whether to allow invalid certificates and/or invalid hostnames
|
||||
pub smtp_certificate_checks: CertificateChecks,
|
||||
pub imap: ServerLoginParam,
|
||||
pub smtp: ServerLoginParam,
|
||||
pub server_flags: i32,
|
||||
}
|
||||
|
||||
@@ -77,6 +120,13 @@ impl LoginParam {
|
||||
let key = format!("{}mail_pw", prefix);
|
||||
let mail_pw = sql.get_raw_config(context, key).await.unwrap_or_default();
|
||||
|
||||
let key = format!("{}mail_security", prefix);
|
||||
let mail_security = sql
|
||||
.get_raw_config_int(context, key)
|
||||
.await
|
||||
.and_then(num_traits::FromPrimitive::from_i32)
|
||||
.unwrap_or_default();
|
||||
|
||||
let key = format!("{}imap_certificate_checks", prefix);
|
||||
let imap_certificate_checks =
|
||||
if let Some(certificate_checks) = sql.get_raw_config_int(context, key).await {
|
||||
@@ -100,6 +150,13 @@ impl LoginParam {
|
||||
let key = format!("{}send_pw", prefix);
|
||||
let send_pw = sql.get_raw_config(context, key).await.unwrap_or_default();
|
||||
|
||||
let key = format!("{}send_security", prefix);
|
||||
let send_security = sql
|
||||
.get_raw_config_int(context, key)
|
||||
.await
|
||||
.and_then(num_traits::FromPrimitive::from_i32)
|
||||
.unwrap_or_default();
|
||||
|
||||
let key = format!("{}smtp_certificate_checks", prefix);
|
||||
let smtp_certificate_checks =
|
||||
if let Some(certificate_checks) = sql.get_raw_config_int(context, key).await {
|
||||
@@ -116,16 +173,22 @@ impl LoginParam {
|
||||
|
||||
LoginParam {
|
||||
addr,
|
||||
mail_server,
|
||||
mail_user,
|
||||
mail_pw,
|
||||
mail_port,
|
||||
imap_certificate_checks,
|
||||
send_server,
|
||||
send_user,
|
||||
send_pw,
|
||||
send_port,
|
||||
smtp_certificate_checks,
|
||||
imap: ServerLoginParam {
|
||||
server: mail_server,
|
||||
user: mail_user,
|
||||
password: mail_pw,
|
||||
port: mail_port as u16,
|
||||
security: mail_security,
|
||||
certificate_checks: imap_certificate_checks,
|
||||
},
|
||||
smtp: ServerLoginParam {
|
||||
server: send_server,
|
||||
user: send_user,
|
||||
password: send_pw,
|
||||
port: send_port as u16,
|
||||
security: send_security,
|
||||
certificate_checks: smtp_certificate_checks,
|
||||
},
|
||||
server_flags,
|
||||
}
|
||||
}
|
||||
@@ -143,41 +206,51 @@ impl LoginParam {
|
||||
sql.set_raw_config(context, key, Some(&self.addr)).await?;
|
||||
|
||||
let key = format!("{}mail_server", prefix);
|
||||
sql.set_raw_config(context, key, Some(&self.mail_server))
|
||||
sql.set_raw_config(context, key, Some(&self.imap.server))
|
||||
.await?;
|
||||
|
||||
let key = format!("{}mail_port", prefix);
|
||||
sql.set_raw_config_int(context, key, self.mail_port).await?;
|
||||
sql.set_raw_config_int(context, key, self.imap.port as i32)
|
||||
.await?;
|
||||
|
||||
let key = format!("{}mail_user", prefix);
|
||||
sql.set_raw_config(context, key, Some(&self.mail_user))
|
||||
sql.set_raw_config(context, key, Some(&self.imap.user))
|
||||
.await?;
|
||||
|
||||
let key = format!("{}mail_pw", prefix);
|
||||
sql.set_raw_config(context, key, Some(&self.mail_pw))
|
||||
sql.set_raw_config(context, key, Some(&self.imap.password))
|
||||
.await?;
|
||||
|
||||
let key = format!("{}mail_security", prefix);
|
||||
sql.set_raw_config_int(context, key, self.imap.security as i32)
|
||||
.await?;
|
||||
|
||||
let key = format!("{}imap_certificate_checks", prefix);
|
||||
sql.set_raw_config_int(context, key, self.imap_certificate_checks as i32)
|
||||
sql.set_raw_config_int(context, key, self.imap.certificate_checks as i32)
|
||||
.await?;
|
||||
|
||||
let key = format!("{}send_server", prefix);
|
||||
sql.set_raw_config(context, key, Some(&self.send_server))
|
||||
sql.set_raw_config(context, key, Some(&self.smtp.server))
|
||||
.await?;
|
||||
|
||||
let key = format!("{}send_port", prefix);
|
||||
sql.set_raw_config_int(context, key, self.send_port).await?;
|
||||
sql.set_raw_config_int(context, key, self.smtp.port as i32)
|
||||
.await?;
|
||||
|
||||
let key = format!("{}send_user", prefix);
|
||||
sql.set_raw_config(context, key, Some(&self.send_user))
|
||||
sql.set_raw_config(context, key, Some(&self.smtp.user))
|
||||
.await?;
|
||||
|
||||
let key = format!("{}send_pw", prefix);
|
||||
sql.set_raw_config(context, key, Some(&self.send_pw))
|
||||
sql.set_raw_config(context, key, Some(&self.smtp.password))
|
||||
.await?;
|
||||
|
||||
let key = format!("{}send_security", prefix);
|
||||
sql.set_raw_config_int(context, key, self.smtp.security as i32)
|
||||
.await?;
|
||||
|
||||
let key = format!("{}smtp_certificate_checks", prefix);
|
||||
sql.set_raw_config_int(context, key, self.smtp_certificate_checks as i32)
|
||||
sql.set_raw_config_int(context, key, self.smtp.certificate_checks as i32)
|
||||
.await?;
|
||||
|
||||
let key = format!("{}server_flags", prefix);
|
||||
@@ -199,16 +272,24 @@ impl fmt::Display for LoginParam {
|
||||
f,
|
||||
"{} imap:{}:{}:{}:{}:cert_{} smtp:{}:{}:{}:{}:cert_{} {}",
|
||||
unset_empty(&self.addr),
|
||||
unset_empty(&self.mail_user),
|
||||
if !self.mail_pw.is_empty() { pw } else { unset },
|
||||
unset_empty(&self.mail_server),
|
||||
self.mail_port,
|
||||
self.imap_certificate_checks,
|
||||
unset_empty(&self.send_user),
|
||||
if !self.send_pw.is_empty() { pw } else { unset },
|
||||
unset_empty(&self.send_server),
|
||||
self.send_port,
|
||||
self.smtp_certificate_checks,
|
||||
unset_empty(&self.imap.user),
|
||||
if !self.imap.password.is_empty() {
|
||||
pw
|
||||
} else {
|
||||
unset
|
||||
},
|
||||
unset_empty(&self.imap.server),
|
||||
self.imap.port,
|
||||
self.imap.certificate_checks,
|
||||
unset_empty(&self.smtp.user),
|
||||
if !self.smtp.password.is_empty() {
|
||||
pw
|
||||
} else {
|
||||
unset
|
||||
},
|
||||
unset_empty(&self.smtp.server),
|
||||
self.smtp.port,
|
||||
self.smtp.certificate_checks,
|
||||
flags_readable,
|
||||
)
|
||||
}
|
||||
@@ -237,30 +318,6 @@ fn get_readable_flags(flags: i32) -> String {
|
||||
res += "AUTH_NORMAL ";
|
||||
flag_added = true;
|
||||
}
|
||||
if 1 << bit == 0x100 {
|
||||
res += "IMAP_STARTTLS ";
|
||||
flag_added = true;
|
||||
}
|
||||
if 1 << bit == 0x200 {
|
||||
res += "IMAP_SSL ";
|
||||
flag_added = true;
|
||||
}
|
||||
if 1 << bit == 0x400 {
|
||||
res += "IMAP_PLAIN ";
|
||||
flag_added = true;
|
||||
}
|
||||
if 1 << bit == 0x10000 {
|
||||
res += "SMTP_STARTTLS ";
|
||||
flag_added = true;
|
||||
}
|
||||
if 1 << bit == 0x20000 {
|
||||
res += "SMTP_SSL ";
|
||||
flag_added = true;
|
||||
}
|
||||
if 1 << bit == 0x40000 {
|
||||
res += "SMTP_PLAIN ";
|
||||
flag_added = true;
|
||||
}
|
||||
if flag_added {
|
||||
res += &format!("{:#0x}", 1 << bit);
|
||||
}
|
||||
|
||||
@@ -4,9 +4,12 @@ mod data;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::dc_tools::EmailAddress;
|
||||
use crate::provider::data::PROVIDER_DATA;
|
||||
use crate::{
|
||||
login_param::{ImapServers, ServerParams, SmtpServers},
|
||||
provider::data::PROVIDER_DATA,
|
||||
};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, ToPrimitive)]
|
||||
#[derive(Debug, Display, Copy, Clone, PartialEq, FromPrimitive, ToPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum Status {
|
||||
OK = 1,
|
||||
@@ -14,21 +17,29 @@ pub enum Status {
|
||||
BROKEN = 3,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, Display, PartialEq, Copy, Clone, FromPrimitive, ToPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum Protocol {
|
||||
SMTP = 1,
|
||||
IMAP = 2,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, Display, PartialEq, Copy, Clone, FromPrimitive, ToPrimitive)]
|
||||
#[repr(u8)]
|
||||
pub enum Socket {
|
||||
STARTTLS = 1,
|
||||
SSL = 2,
|
||||
Automatic = 0,
|
||||
SSL = 1,
|
||||
STARTTLS = 2,
|
||||
Plain = 3,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
impl Default for Socket {
|
||||
fn default() -> Self {
|
||||
Socket::Automatic
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
#[repr(u8)]
|
||||
pub enum UsernamePattern {
|
||||
EMAIL = 1,
|
||||
@@ -42,7 +53,7 @@ pub enum Oauth2Authorizer {
|
||||
Gmail = 2,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Server {
|
||||
pub protocol: Protocol,
|
||||
pub socket: Socket,
|
||||
@@ -51,20 +62,6 @@ pub struct Server {
|
||||
pub username_pattern: UsernamePattern,
|
||||
}
|
||||
|
||||
impl Server {
|
||||
pub fn apply_username_pattern(&self, addr: String) -> String {
|
||||
match self.username_pattern {
|
||||
UsernamePattern::EMAIL => addr,
|
||||
UsernamePattern::EMAILLOCALPART => {
|
||||
if let Some(at) = addr.find('@') {
|
||||
return addr.split_at(at).0.to_string();
|
||||
}
|
||||
addr
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ConfigDefault {
|
||||
pub key: Config,
|
||||
@@ -84,20 +81,25 @@ pub struct Provider {
|
||||
}
|
||||
|
||||
impl Provider {
|
||||
pub fn get_server(&self, protocol: Protocol) -> Option<&Server> {
|
||||
for record in self.server.iter() {
|
||||
if record.protocol == protocol {
|
||||
return Some(record);
|
||||
}
|
||||
}
|
||||
None
|
||||
pub fn get_server(&self, protocol: Protocol) -> Vec<ServerParams> {
|
||||
self.server
|
||||
.iter()
|
||||
.filter(|s| s.protocol == protocol)
|
||||
.map(|s| ServerParams {
|
||||
protocol: s.protocol,
|
||||
socket: s.socket,
|
||||
hostname: s.hostname.to_string(),
|
||||
port: s.port,
|
||||
username_pattern: s.username_pattern.clone(),
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn get_imap_server(&self) -> Option<&Server> {
|
||||
pub fn get_imap_server(&self) -> ImapServers {
|
||||
self.get_server(Protocol::IMAP)
|
||||
}
|
||||
|
||||
pub fn get_smtp_server(&self) -> Option<&Server> {
|
||||
pub fn get_smtp_server(&self) -> SmtpServers {
|
||||
self.get_server(Protocol::SMTP)
|
||||
}
|
||||
}
|
||||
@@ -139,13 +141,13 @@ mod tests {
|
||||
|
||||
let provider = get_provider_info("user@nauta.cu").unwrap();
|
||||
assert!(provider.status == Status::OK);
|
||||
let server = provider.get_imap_server().unwrap();
|
||||
let server = &provider.get_imap_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.get_smtp_server().unwrap();
|
||||
let server = &provider.get_smtp_server()[0];
|
||||
assert_eq!(server.protocol, Protocol::SMTP);
|
||||
assert_eq!(server.socket, Socket::STARTTLS);
|
||||
assert_eq!(server.hostname, "smtp.nauta.cu");
|
||||
|
||||
@@ -10,9 +10,9 @@ use async_smtp::*;
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::events::EventType;
|
||||
use crate::login_param::{dc_build_tls, CertificateChecks, LoginParam};
|
||||
use crate::login_param::{dc_build_tls, CertificateChecks, LoginParam, ServerLoginParam};
|
||||
use crate::oauth2::*;
|
||||
use crate::provider::get_provider_info;
|
||||
use crate::provider::{get_provider_info, Socket};
|
||||
use crate::stock::StockMessage;
|
||||
|
||||
/// SMTP write and read timeout in seconds.
|
||||
@@ -94,31 +94,53 @@ impl Smtp {
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Connect using configured parameters.
|
||||
pub async fn connect_configured(&mut self, context: &Context) -> Result<()> {
|
||||
if self.is_connected().await {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let lp = LoginParam::from_database(context, "configured_").await;
|
||||
self.connect(
|
||||
context,
|
||||
&lp.smtp,
|
||||
&lp.addr,
|
||||
lp.server_flags & DC_LP_AUTH_OAUTH2 != 0,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Connect using the provided login params.
|
||||
pub async fn connect(&mut self, context: &Context, lp: &LoginParam) -> Result<()> {
|
||||
pub async fn connect(
|
||||
&mut self,
|
||||
context: &Context,
|
||||
lp: &ServerLoginParam,
|
||||
addr: &str,
|
||||
oauth2: bool,
|
||||
) -> Result<()> {
|
||||
if self.is_connected().await {
|
||||
warn!(context, "SMTP already connected.");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if lp.send_server.is_empty() || lp.send_port == 0 {
|
||||
if lp.server.is_empty() || lp.port == 0 {
|
||||
context.emit_event(EventType::ErrorNetwork("SMTP bad parameters.".into()));
|
||||
return Err(Error::BadParameters);
|
||||
}
|
||||
|
||||
let from =
|
||||
EmailAddress::new(lp.addr.clone()).map_err(|err| Error::InvalidLoginAddress {
|
||||
address: lp.addr.clone(),
|
||||
EmailAddress::new(addr.to_string()).map_err(|err| Error::InvalidLoginAddress {
|
||||
address: addr.to_string(),
|
||||
error: err,
|
||||
})?;
|
||||
|
||||
self.from = Some(from);
|
||||
|
||||
let domain = &lp.send_server;
|
||||
let port = lp.send_port as u16;
|
||||
let domain = &lp.server;
|
||||
let port = lp.port;
|
||||
|
||||
let provider = get_provider_info(&lp.addr);
|
||||
let strict_tls = match lp.smtp_certificate_checks {
|
||||
let provider = get_provider_info(addr);
|
||||
let strict_tls = match lp.certificate_checks {
|
||||
CertificateChecks::Automatic => provider.map_or(false, |provider| provider.strict_tls),
|
||||
CertificateChecks::Strict => true,
|
||||
CertificateChecks::AcceptInvalidCertificates
|
||||
@@ -127,17 +149,16 @@ impl Smtp {
|
||||
let tls_config = dc_build_tls(strict_tls);
|
||||
let tls_parameters = ClientTlsParameters::new(domain.to_string(), tls_config);
|
||||
|
||||
let (creds, mechanism) = if 0 != lp.server_flags & (DC_LP_AUTH_OAUTH2 as i32) {
|
||||
let (creds, mechanism) = if oauth2 {
|
||||
// oauth2
|
||||
let addr = &lp.addr;
|
||||
let send_pw = &lp.send_pw;
|
||||
let send_pw = &lp.password;
|
||||
let access_token = dc_get_oauth2_access_token(context, addr, send_pw, false).await;
|
||||
if access_token.is_none() {
|
||||
return Err(Error::Oauth2Error {
|
||||
address: addr.to_string(),
|
||||
});
|
||||
}
|
||||
let user = &lp.send_user;
|
||||
let user = &lp.user;
|
||||
(
|
||||
smtp::authentication::Credentials::new(
|
||||
user.to_string(),
|
||||
@@ -147,8 +168,8 @@ impl Smtp {
|
||||
)
|
||||
} else {
|
||||
// plain
|
||||
let user = lp.send_user.clone();
|
||||
let pw = lp.send_pw.clone();
|
||||
let user = lp.user.clone();
|
||||
let pw = lp.password.clone();
|
||||
(
|
||||
smtp::authentication::Credentials::new(user, pw),
|
||||
vec![
|
||||
@@ -158,12 +179,9 @@ impl Smtp {
|
||||
)
|
||||
};
|
||||
|
||||
let security = if 0
|
||||
!= lp.server_flags & (DC_LP_SMTP_SOCKET_STARTTLS | DC_LP_SMTP_SOCKET_PLAIN) as i32
|
||||
{
|
||||
smtp::ClientSecurity::Opportunistic(tls_parameters)
|
||||
} else {
|
||||
smtp::ClientSecurity::Wrapper(tls_parameters)
|
||||
let security = match lp.security {
|
||||
Socket::STARTTLS | Socket::Plain => smtp::ClientSecurity::Opportunistic(tls_parameters),
|
||||
_ => smtp::ClientSecurity::Wrapper(tls_parameters),
|
||||
};
|
||||
|
||||
let client = smtp::SmtpClient::with_security((domain.as_str(), port), security)
|
||||
@@ -196,7 +214,7 @@ impl Smtp {
|
||||
|
||||
context.emit_event(EventType::SmtpConnected(format!(
|
||||
"SMTP-LOGIN as {} ok",
|
||||
lp.send_user,
|
||||
lp.user,
|
||||
)));
|
||||
|
||||
Ok(())
|
||||
|
||||
27
src/sql.rs
27
src/sql.rs
@@ -1288,6 +1288,33 @@ async fn open(
|
||||
update_icons = true;
|
||||
sql.set_raw_config_int(context, "dbversion", 66).await?;
|
||||
}
|
||||
if dbversion < 67 {
|
||||
info!(context, "[migration] v67");
|
||||
for prefix in &["", "configured_"] {
|
||||
if let Some(server_flags) = sql
|
||||
.get_raw_config_int(context, format!("{}server_flags", prefix))
|
||||
.await
|
||||
{
|
||||
let imap_socket_flags = server_flags & 0x700;
|
||||
let key = format!("{}mail_security", prefix);
|
||||
match imap_socket_flags {
|
||||
0x100 => sql.set_raw_config_int(context, key, 2).await?, // STARTTLS
|
||||
0x200 => sql.set_raw_config_int(context, key, 1).await?, // SSL/TLS
|
||||
0x400 => sql.set_raw_config_int(context, key, 3).await?, // Plain
|
||||
_ => sql.set_raw_config_int(context, key, 0).await?,
|
||||
}
|
||||
let smtp_socket_flags = server_flags & 0x70000;
|
||||
let key = format!("{}send_security", prefix);
|
||||
match smtp_socket_flags {
|
||||
0x10000 => sql.set_raw_config_int(context, key, 2).await?, // STARTTLS
|
||||
0x20000 => sql.set_raw_config_int(context, key, 1).await?, // SSL/TLS
|
||||
0x40000 => sql.set_raw_config_int(context, key, 3).await?, // Plain
|
||||
_ => sql.set_raw_config_int(context, key, 0).await?,
|
||||
}
|
||||
}
|
||||
}
|
||||
sql.set_raw_config_int(context, "dbversion", 67).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