the basics work

This commit is contained in:
dignifiedquire
2020-03-18 15:11:36 +01:00
parent 94c6a01420
commit f85b14a7f7
8 changed files with 504 additions and 533 deletions

View File

@@ -10,6 +10,7 @@ use crate::config::Config;
use crate::constants::*;
use crate::context::Context;
use crate::dc_tools::*;
use crate::error::{Error, Result};
use crate::imap::Imap;
use crate::login_param::{CertificateChecks, LoginParam};
use crate::oauth2::*;
@@ -37,31 +38,28 @@ impl Context {
}
/// Configures this account with the currently set parameters.
pub async fn configure(&self) {
if self.has_ongoing().await {
warn!(self, "There is already another ongoing process running.",);
return;
}
pub async fn configure(&self) -> Result<()> {
ensure!(
!self.has_ongoing().await,
"There is already another ongoing process running."
);
ensure!(
!self.scheduler.read().await.is_running(),
"Can not configure, already running"
);
ensure!(
self.sql.is_open().await,
"Cannot configure, database not opened."
);
ensure!(
self.alloc_ongoing().await,
"Cannot allocate ongoing process"
);
if self.scheduler.read().await.is_running() {
warn!(self, "Can not configure, already running");
return;
}
if !self.sql.is_open().await {
error!(self, "Cannot configure, database not opened.",);
progress!(self, 0);
return;
}
if !self.alloc_ongoing().await {
error!(self, "Cannot allocate ongoing process");
progress!(self, 0);
return;
}
let mut success = false;
let mut param_autoconfig: Option<LoginParam> = None;
info!(self, "Configure ...",);
info!(self, "Configure ...");
// Variables that are shared between steps:
let mut param = LoginParam::from_database(self, "").await;
@@ -72,9 +70,6 @@ impl Context {
"Internal Error: this value should never be used".to_owned();
let mut keep_flags = 0;
const STEP_12_USE_AUTOCONFIG: u8 = 12;
const STEP_13_AFTER_AUTOCONFIG: u8 = 13;
let mut step_counter: u8 = 0;
let (_s, r) = async_std::sync::channel(1);
let mut imap = Imap::new(r);
@@ -83,349 +78,38 @@ impl Context {
while !self.shall_stop_ongoing().await {
step_counter += 1;
let success = match step_counter {
// Read login parameters from the database
1 => {
progress!(self, 1);
if param.addr.is_empty() {
error!(self, "Please enter an email address.",);
}
!param.addr.is_empty()
}
// Step 1: Load the parameters and check email-address and password
2 => {
if 0 != param.server_flags & DC_LP_AUTH_OAUTH2 {
// 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!(self, 10);
if let Some(oauth2_addr) =
dc_get_oauth2_addr(self, &param.addr, &param.mail_pw)
.await
.and_then(|e| e.parse().ok())
{
info!(self, "Authorized address is {}", oauth2_addr);
param.addr = oauth2_addr;
self.sql
.set_raw_config(self, "addr", Some(param.addr.as_str()))
.await
.ok();
}
progress!(self, 20);
}
true // no oauth? - just continue it's no error
}
3 => {
if let Ok(parsed) = param.addr.parse() {
let parsed: EmailAddress = parsed;
param_domain = parsed.domain;
param_addr_urlencoded =
utf8_percent_encode(&param.addr, NON_ALPHANUMERIC).to_string();
true
} else {
error!(self, "Bad email-address.");
false
match exec_step(
self,
&mut imap,
&mut is_imap_connected,
&mut param,
&mut param_domain,
&mut param_autoconfig,
&mut param_addr_urlencoded,
&mut keep_flags,
&mut step_counter,
)
.await
{
Ok(step) => {
success = true;
match step {
Step::Continue => {}
Step::Done => break,
}
}
// Step 2: Autoconfig
4 => {
progress!(self, 200);
if param.mail_server.is_empty()
&& param.mail_port == 0
/*&&param.mail_user.is_empty() -- the user can enter a loginname which is used by autoconfig then */
&& param.send_server.is_empty()
&& param.send_port == 0
&& param.send_user.is_empty()
/*&&param.send_pw.is_empty() -- the password cannot be auto-configured and is no criterion for autoconfig or not */
&& (param.server_flags & !DC_LP_AUTH_OAUTH2) == 0
{
// no advanced parameters entered by the user: query provider-database or do Autoconfig
keep_flags = param.server_flags & DC_LP_AUTH_OAUTH2;
if let Some(new_param) = get_offline_autoconfig(self, &param) {
// got parameters from our provider-database, skip Autoconfig, preserve the OAuth2 setting
param_autoconfig = Some(new_param);
step_counter = STEP_12_USE_AUTOCONFIG - 1; // minus one as step_counter is increased on next loop
}
} else {
// advanced parameters entered by the user: skip Autoconfig
step_counter = STEP_13_AFTER_AUTOCONFIG - 1; // minus one as step_counter is increased on next loop
}
true
}
/* A. Search configurations from the domain used in the email-address, prefer encrypted */
5 => {
if param_autoconfig.is_none() {
let url = format!(
"https://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
param_domain, param_addr_urlencoded
);
param_autoconfig = moz_autoconfigure(self, &url, &param).ok();
}
true
}
6 => {
progress!(self, 300);
if param_autoconfig.is_none() {
// the doc does not mention `emailaddress=`, however, Thunderbird adds it, see https://releases.mozilla.org/pub/thunderbird/ , which makes some sense
let url = format!(
"https://{}/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress={}",
param_domain, param_addr_urlencoded
);
param_autoconfig = moz_autoconfigure(self, &url, &param).ok();
}
true
}
/* Outlook section start ------------- */
/* Outlook uses always SSL but different domains (this comment describes the next two steps) */
7 => {
progress!(self, 310);
if param_autoconfig.is_none() {
let url = format!("https://{}/autodiscover/autodiscover.xml", param_domain);
param_autoconfig = outlk_autodiscover(self, &url, &param).ok();
}
true
}
8 => {
progress!(self, 320);
if param_autoconfig.is_none() {
let url = format!(
"https://{}{}/autodiscover/autodiscover.xml",
"autodiscover.", param_domain
);
param_autoconfig = outlk_autodiscover(self, &url, &param).ok();
}
true
}
/* ----------- Outlook section end */
9 => {
progress!(self, 330);
if param_autoconfig.is_none() {
let url = format!(
"http://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
param_domain, param_addr_urlencoded
);
param_autoconfig = moz_autoconfigure(self, &url, &param).ok();
}
true
}
10 => {
progress!(self, 340);
if param_autoconfig.is_none() {
// do not transfer the email-address unencrypted
let url = format!(
"http://{}/.well-known/autoconfig/mail/config-v1.1.xml",
param_domain
);
param_autoconfig = moz_autoconfigure(self, &url, &param).ok();
}
true
}
/* B. If we have no configuration yet, search configuration in Thunderbird's centeral database */
11 => {
progress!(self, 350);
if param_autoconfig.is_none() {
/* always SSL for Thunderbird's database */
let url =
format!("https://autoconfig.thunderbird.net/v1.1/{}", param_domain);
param_autoconfig = moz_autoconfigure(self, &url, &param).ok();
}
true
}
/* C. Do we have any autoconfig result?
If you change the match-number here, also update STEP_12_COPY_AUTOCONFIG above
*/
STEP_12_USE_AUTOCONFIG => {
progress!(self, 500);
if let Some(ref cfg) = param_autoconfig {
info!(self, "Got autoconfig: {}", &cfg);
if !cfg.mail_user.is_empty() {
param.mail_user = cfg.mail_user.clone();
}
param.mail_server = cfg.mail_server.clone(); /* all other values are always NULL when entering autoconfig */
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;
true
}
// Step 3: Fill missing fields with defaults
// If you change the match-number here, also update STEP_13_AFTER_AUTOCONFIG above
STEP_13_AFTER_AUTOCONFIG => {
if param.mail_server.is_empty() {
param.mail_server = format!("imap.{}", param_domain,)
}
if param.mail_port == 0 {
param.mail_port = if 0 != param.server_flags & (0x100 | 0x400) {
143
} else {
993
}
}
if param.mail_user.is_empty() {
param.mail_user = param.addr.clone();
}
if param.send_server.is_empty() && !param.mail_server.is_empty() {
param.send_server = param.mail_server.clone();
if param.send_server.starts_with("imap.") {
param.send_server = param.send_server.replacen("imap", "smtp", 1);
}
}
if param.send_port == 0 {
param.send_port =
if 0 != param.server_flags & DC_LP_SMTP_SOCKET_STARTTLS as i32 {
587
} else if 0 != param.server_flags & DC_LP_SMTP_SOCKET_PLAIN as i32 {
25
} else {
465
}
}
if param.send_user.is_empty() && !param.mail_user.is_empty() {
param.send_user = param.mail_user.clone();
}
if param.send_pw.is_empty() && !param.mail_pw.is_empty() {
param.send_pw = param.mail_pw.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);
param.server_flags |= DC_LP_AUTH_NORMAL as i32
}
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);
param.server_flags |= if param.send_port == 143 {
DC_LP_IMAP_SOCKET_STARTTLS as i32
} else {
DC_LP_IMAP_SOCKET_SSL 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);
param.server_flags |= if param.send_port == 587 {
DC_LP_SMTP_SOCKET_STARTTLS as i32
} else if param.send_port == 25 {
DC_LP_SMTP_SOCKET_PLAIN as i32
} else {
DC_LP_SMTP_SOCKET_SSL as i32
}
}
/* do we have a complete configuration? */
if param.mail_server.is_empty()
|| param.mail_port == 0
|| param.mail_user.is_empty()
|| param.mail_pw.is_empty()
|| param.send_server.is_empty()
|| param.send_port == 0
|| param.send_user.is_empty()
|| param.send_pw.is_empty()
|| param.server_flags == 0
{
error!(self, "Account settings incomplete.");
false
} else {
true
}
}
14 => {
progress!(self, 600);
/* try to connect to IMAP - if we did not got an autoconfig,
do some further tries with different settings and username variations */
is_imap_connected = try_imap_connections(
self,
&mut param,
param_autoconfig.is_some(),
&mut imap,
)
.await;
is_imap_connected
}
15 => {
progress!(self, 800);
try_smtp_connections(self, &mut param, param_autoconfig.is_some()).await
}
16 => {
progress!(self, 900);
let create_mvbox = self.get_config_bool(Config::MvboxWatch).await
|| self.get_config_bool(Config::MvboxMove).await;
if let Err(err) = imap.ensure_configured_folders(self, create_mvbox).await {
warn!(self, "configuring folders failed: {:?}", err);
false
} else {
let res = imap.select_with_uidvalidity(self, "INBOX").await;
if let Err(err) = res {
error!(self, "could not read INBOX status: {:?}", err);
false
} else {
true
}
}
}
17 => {
progress!(self, 910);
/* configuration success - write back the configured parameters with the "configured_" prefix; also write the "configured"-flag */
param
.save_to_database(
self,
"configured_", /*the trailing underscore is correct*/
)
.await
.ok();
self.sql
.set_raw_config_bool(self, "configured", true)
.await
.ok();
true
}
18 => {
progress!(self, 920);
// we generate the keypair just now - we could also postpone this until the first message is sent, however,
// this may result in a unexpected and annoying delay when the user sends his very first message
// (~30 seconds on a Moto G4 play) and might looks as if message sending is always that slow.
success = e2ee::ensure_secret_key_exists(self).await.is_ok();
info!(self, "key generation completed");
progress!(self, 940);
break; // We are done here
}
_ => {
error!(self, "Internal error: step counter out of bound",);
Err(err) => {
error!(self, "{}", err);
success = false;
break;
}
};
if !success {
break;
}
}
if is_imap_connected {
imap.disconnect(self).await;
}
// remember the entered parameters on success
// and restore to last-entered on failure.
// this way, the parameters visible to the ui are always in-sync with the current configuration.
if success {
LoginParam::from_database(self, "")
.await
.save_to_database(self, "configured_raw_")
.await
.ok();
} else {
LoginParam::from_database(self, "configured_raw_")
.await
.save_to_database(self, "")
.await
.ok();
}
if let Some(provider) = provider::get_provider_info(&param.addr) {
if !provider.after_login_hint.is_empty() {
let mut msg = Message::new(Viewtype::Text);
@@ -439,11 +123,334 @@ impl Context {
}
}
self.free_ongoing().await;
progress!(self, if success { 1000 } else { 0 });
// remember the entered parameters on success
// and restore to last-entered on failure.
// this way, the parameters visible to the ui are always in-sync with the current configuration.
if success {
assert!(self.is_configured().await, "epic fail");
LoginParam::from_database(self, "")
.await
.save_to_database(self, "configured_raw_")
.await
.ok();
self.free_ongoing().await;
progress!(self, 1000);
Ok(())
} else {
LoginParam::from_database(self, "configured_raw_")
.await
.save_to_database(self, "")
.await
.ok();
self.free_ongoing().await;
progress!(self, 0);
Err(Error::Message("Configure failed".to_string()))
}
}
}
async fn exec_step(
ctx: &Context,
imap: &mut Imap,
is_imap_connected: &mut bool,
param: &mut LoginParam,
param_domain: &mut String,
param_autoconfig: &mut Option<LoginParam>,
param_addr_urlencoded: &mut String,
keep_flags: &mut i32,
step_counter: &mut u8,
) -> Result<Step> {
const STEP_12_USE_AUTOCONFIG: u8 = 12;
const STEP_13_AFTER_AUTOCONFIG: u8 = 13;
match *step_counter {
// Read login parameters from the database
1 => {
progress!(ctx, 1);
ensure!(!param.addr.is_empty(), "Please enter an email address.");
}
// Step 1: Load the parameters and check email-address and password
2 => {
if 0 != param.server_flags & DC_LP_AUTH_OAUTH2 {
// 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, &param.addr, &param.mail_pw)
.await
.and_then(|e| e.parse().ok())
{
info!(ctx, "Authorized address is {}", oauth2_addr);
param.addr = oauth2_addr;
ctx.sql
.set_raw_config(ctx, "addr", Some(param.addr.as_str()))
.await?;
}
progress!(ctx, 20);
}
// no oauth? - just continue it's no error
}
3 => {
if let Ok(parsed) = param.addr.parse() {
let parsed: EmailAddress = parsed;
*param_domain = parsed.domain;
*param_addr_urlencoded =
utf8_percent_encode(&param.addr, NON_ALPHANUMERIC).to_string();
} else {
bail!("Bad email-address.");
}
}
// Step 2: Autoconfig
4 => {
progress!(ctx, 200);
if param.mail_server.is_empty()
&& param.mail_port == 0
/* && param.mail_user.is_empty() -- the user can enter a loginname which is used by autoconfig then */
&& param.send_server.is_empty()
&& param.send_port == 0
&& param.send_user.is_empty()
/* && param.send_pw.is_empty() -- the password cannot be auto-configured and is no criterion for autoconfig or not */
&& (param.server_flags & !DC_LP_AUTH_OAUTH2) == 0
{
// no advanced parameters entered by the user: query provider-database or do Autoconfig
*keep_flags = param.server_flags & DC_LP_AUTH_OAUTH2;
if let Some(new_param) = get_offline_autoconfig(ctx, &param) {
// got parameters from our provider-database, skip Autoconfig, preserve the OAuth2 setting
*param_autoconfig = Some(new_param);
*step_counter = STEP_12_USE_AUTOCONFIG - 1; // minus one as step_counter is increased on next loop
}
} else {
// advanced parameters entered by the user: skip Autoconfig
*step_counter = STEP_13_AFTER_AUTOCONFIG - 1; // minus one as step_counter is increased on next loop
}
}
/* A. Search configurations from the domain used in the email-address, prefer encrypted */
5 => {
if param_autoconfig.is_none() {
let url = format!(
"https://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
param_domain, param_addr_urlencoded
);
*param_autoconfig = moz_autoconfigure(ctx, &url, &param).ok();
}
}
6 => {
progress!(ctx, 300);
if param_autoconfig.is_none() {
// the doc does not mention `emailaddress=`, however, Thunderbird adds it, see https://releases.mozilla.org/pub/thunderbird/ , which makes some sense
let url = format!(
"https://{}/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress={}",
param_domain, param_addr_urlencoded
);
*param_autoconfig = moz_autoconfigure(ctx, &url, &param).ok();
}
}
/* Outlook section start ------------- */
/* Outlook uses always SSL but different domains (this comment describes the next two steps) */
7 => {
progress!(ctx, 310);
if param_autoconfig.is_none() {
let url = format!("https://{}/autodiscover/autodiscover.xml", param_domain);
*param_autoconfig = outlk_autodiscover(ctx, &url, &param).ok();
}
}
8 => {
progress!(ctx, 320);
if param_autoconfig.is_none() {
let url = format!(
"https://{}{}/autodiscover/autodiscover.xml",
"autodiscover.", param_domain
);
*param_autoconfig = outlk_autodiscover(ctx, &url, &param).ok();
}
}
/* ----------- Outlook section end */
9 => {
progress!(ctx, 330);
if param_autoconfig.is_none() {
let url = format!(
"http://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
param_domain, param_addr_urlencoded
);
*param_autoconfig = moz_autoconfigure(ctx, &url, &param).ok();
}
}
10 => {
progress!(ctx, 340);
if param_autoconfig.is_none() {
// do not transfer the email-address unencrypted
let url = format!(
"http://{}/.well-known/autoconfig/mail/config-v1.1.xml",
param_domain
);
*param_autoconfig = moz_autoconfigure(ctx, &url, &param).ok();
}
}
/* B. If we have no configuration yet, search configuration in Thunderbird's centeral database */
11 => {
progress!(ctx, 350);
if param_autoconfig.is_none() {
/* always SSL for Thunderbird's database */
let url = format!("https://autoconfig.thunderbird.net/v1.1/{}", param_domain);
*param_autoconfig = moz_autoconfigure(ctx, &url, &param).ok();
}
}
/* C. Do we have any autoconfig result?
If you change the match-number here, also update STEP_12_COPY_AUTOCONFIG above
*/
STEP_12_USE_AUTOCONFIG => {
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();
}
param.mail_server = cfg.mail_server.clone(); /* all other values are always NULL when entering autoconfig */
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 you change the match-number here, also update STEP_13_AFTER_AUTOCONFIG above
STEP_13_AFTER_AUTOCONFIG => {
if param.mail_server.is_empty() {
param.mail_server = format!("imap.{}", param_domain,)
}
if param.mail_port == 0 {
param.mail_port = if 0 != param.server_flags & (0x100 | 0x400) {
143
} else {
993
}
}
if param.mail_user.is_empty() {
param.mail_user = param.addr.clone();
}
if param.send_server.is_empty() && !param.mail_server.is_empty() {
param.send_server = param.mail_server.clone();
if param.send_server.starts_with("imap.") {
param.send_server = param.send_server.replacen("imap", "smtp", 1);
}
}
if param.send_port == 0 {
param.send_port = if 0 != param.server_flags & DC_LP_SMTP_SOCKET_STARTTLS as i32 {
587
} else if 0 != param.server_flags & DC_LP_SMTP_SOCKET_PLAIN as i32 {
25
} else {
465
}
}
if param.send_user.is_empty() && !param.mail_user.is_empty() {
param.send_user = param.mail_user.clone();
}
if param.send_pw.is_empty() && !param.mail_pw.is_empty() {
param.send_pw = param.mail_pw.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);
param.server_flags |= DC_LP_AUTH_NORMAL as i32
}
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);
param.server_flags |= if param.send_port == 143 {
DC_LP_IMAP_SOCKET_STARTTLS as i32
} else {
DC_LP_IMAP_SOCKET_SSL 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);
param.server_flags |= if param.send_port == 587 {
DC_LP_SMTP_SOCKET_STARTTLS as i32
} else if param.send_port == 25 {
DC_LP_SMTP_SOCKET_PLAIN as i32
} else {
DC_LP_SMTP_SOCKET_SSL as i32
}
}
/* do we have a complete configuration? */
if param.mail_server.is_empty()
|| param.mail_port == 0
|| param.mail_user.is_empty()
|| param.mail_pw.is_empty()
|| param.send_server.is_empty()
|| param.send_port == 0
|| param.send_user.is_empty()
|| param.send_pw.is_empty()
|| param.server_flags == 0
{
bail!("Account settings incomplete.");
}
}
14 => {
progress!(ctx, 600);
/* try to connect to IMAP - if we did not got an autoconfig,
do some further tries with different settings and username variations */
try_imap_connections(ctx, param, param_autoconfig.is_some(), imap).await?;
*is_imap_connected = true;
}
15 => {
progress!(ctx, 800);
try_smtp_connections(ctx, param, param_autoconfig.is_some()).await?;
}
16 => {
progress!(ctx, 900);
let create_mvbox = ctx.get_config_bool(Config::MvboxWatch).await
|| ctx.get_config_bool(Config::MvboxMove).await;
if let Err(err) = imap.ensure_configured_folders(ctx, create_mvbox).await {
bail!("configuring folders failed: {:?}", err);
}
if let Err(err) = imap.select_with_uidvalidity(ctx, "INBOX").await {
bail!("could not read INBOX status: {:?}", err);
}
}
17 => {
progress!(ctx, 910);
// configuration success - write back the configured parameters with the
// "configured_" prefix; also write the "configured"-flag */
// the trailing underscore is correct
param.save_to_database(ctx, "configured_").await?;
println!("storing configured val");
ctx.sql.set_raw_config_bool(ctx, "configured", true).await?;
println!("stored configured val");
}
18 => {
progress!(ctx, 920);
// we generate the keypair just now - we could also postpone this until the first message is sent, however,
// this may result in a unexpected and annoying delay when the user sends his very first message
// (~30 seconds on a Moto G4 play) and might looks as if message sending is always that slow.
e2ee::ensure_secret_key_exists(ctx).await?;
info!(ctx, "key generation completed");
progress!(ctx, 940);
return Ok(Step::Done);
}
_ => {
bail!("Internal error: step counter out of bound");
}
}
Ok(Step::Continue)
}
#[derive(Debug)]
enum Step {
Done,
Continue,
}
#[allow(clippy::unnecessary_unwrap)]
fn get_offline_autoconfig(context: &Context, param: &LoginParam) -> Option<LoginParam> {
info!(
@@ -507,10 +514,13 @@ async fn try_imap_connections(
mut param: &mut LoginParam,
was_autoconfig: bool,
imap: &mut Imap,
) -> bool {
) -> Result<()> {
// progress 650 and 660
if let Some(res) = try_imap_connection(context, &mut param, was_autoconfig, 0, imap).await {
return res;
if try_imap_connection(context, &mut param, was_autoconfig, 0, imap)
.await
.is_ok()
{
return Ok(());
}
progress!(context, 670);
param.server_flags &= !(DC_LP_IMAP_SOCKET_FLAGS);
@@ -524,11 +534,9 @@ async fn try_imap_connections(
param.send_user = param.send_user.split_at(at).0.to_string();
}
// progress 680 and 690
if let Some(res) = try_imap_connection(context, &mut param, was_autoconfig, 1, imap).await {
res
} else {
false
}
try_imap_connection(context, &mut param, was_autoconfig, 1, imap).await?;
Ok(())
}
async fn try_imap_connection(
@@ -537,18 +545,18 @@ async fn try_imap_connection(
was_autoconfig: bool,
variation: usize,
imap: &mut Imap,
) -> Option<bool> {
if let Some(res) = try_imap_one_param(context, &param, imap).await {
return Some(res);
) -> Result<()> {
if try_imap_one_param(context, &param, imap).await.is_ok() {
return Ok(());
}
if was_autoconfig {
return Some(false);
bail!("autoconfig");
}
progress!(context, 650 + variation * 30);
param.server_flags &= !(DC_LP_IMAP_SOCKET_FLAGS);
param.server_flags |= DC_LP_IMAP_SOCKET_STARTTLS;
if let Some(res) = try_imap_one_param(context, &param, imap).await {
return Some(res);
if try_imap_one_param(context, &param, imap).await.is_ok() {
return Ok(());
}
progress!(context, 660 + variation * 30);
@@ -557,11 +565,7 @@ async fn try_imap_connection(
try_imap_one_param(context, &param, imap).await
}
async fn try_imap_one_param(
context: &Context,
param: &LoginParam,
imap: &mut Imap,
) -> Option<bool> {
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,
@@ -571,78 +575,59 @@ async fn try_imap_one_param(
param.imap_certificate_checks
);
info!(context, "Trying: {}", inf);
if imap.connect(context, &param).await {
info!(context, "success: {}", inf);
return Some(true);
return Ok(());
}
if context.shall_stop_ongoing().await {
return Some(false);
}
info!(context, "Could not connect: {}", inf);
None
bail!("Could not connect: {}", inf);
}
async fn try_smtp_connections(
context: &Context,
mut param: &mut LoginParam,
was_autoconfig: bool,
) -> bool {
) -> Result<()> {
let mut smtp = Smtp::new();
/* try to connect to SMTP - if we did not got an autoconfig, the first try was SSL-465 and we do a second try with STARTTLS-587 */
if let Some(res) = try_smtp_one_param(context, &param, &mut smtp).await {
return res;
if try_smtp_one_param(context, &param, &mut smtp).await.is_ok() {
return Ok(());
}
if was_autoconfig {
return false;
bail!("autoconfig");
}
progress!(context, 850);
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
param.server_flags |= DC_LP_SMTP_SOCKET_STARTTLS as i32;
param.send_port = 587;
if let Some(res) = try_smtp_one_param(context, &param, &mut smtp).await {
if res {
smtp.disconnect().await;
}
return res;
if try_smtp_one_param(context, &param, &mut smtp).await.is_ok() {
return Ok(());
}
progress!(context, 860);
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
param.server_flags |= DC_LP_SMTP_SOCKET_STARTTLS as i32;
param.send_port = 25;
if let Some(res) = try_smtp_one_param(context, &param, &mut smtp).await {
if res {
smtp.disconnect().await;
}
return res;
}
false
try_smtp_one_param(context, &param, &mut smtp).await?;
Ok(())
}
async fn try_smtp_one_param(
context: &Context,
param: &LoginParam,
smtp: &mut Smtp,
) -> Option<bool> {
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
);
info!(context, "Trying: {}", inf);
match smtp.connect(context, &param).await {
Ok(()) => {
info!(context, "success: {}", inf);
Some(true)
}
Err(err) => {
if context.shall_stop_ongoing().await {
Some(false)
} else {
warn!(context, "could not connect: {}", err);
None
}
}
if let Err(err) = smtp.connect(context, &param).await {
bail!("could not connect: {}", err);
}
info!(context, "success: {}", inf);
smtp.disconnect().await;
Ok(())
}
#[cfg(test)]
@@ -663,7 +648,7 @@ mod tests {
.set_config(Config::MailPw, Some("123456"))
.await
.unwrap();
t.ctx.configure().await;
assert!(t.ctx.configure().await.is_err());
}
#[async_std::test]