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