refactor(configure): remove step-counter

This commit is contained in:
dignifiedquire
2020-05-28 23:16:52 +02:00
parent b6161c431b
commit 43f49f8917

View File

@@ -4,7 +4,7 @@ mod auto_mozilla;
mod auto_outlook; mod auto_outlook;
mod read_url; mod read_url;
use anyhow::{bail, ensure, format_err, Result}; use anyhow::{bail, ensure, Context as _, Result};
use async_std::prelude::*; use async_std::prelude::*;
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC}; use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
@@ -66,29 +66,25 @@ impl Context {
} }
async fn inner_configure(&self) -> Result<()> { async fn inner_configure(&self) -> Result<()> {
let mut success = false;
let mut param_autoconfig: Option<LoginParam> = None;
info!(self, "Configure ..."); info!(self, "Configure ...");
let mut param_autoconfig: Option<LoginParam> = None;
// Variables that are shared between steps: // Variables that are shared between steps:
let mut param = LoginParam::from_database(self, "").await; let mut param = LoginParam::from_database(self, "").await;
// need all vars here to be mutable because rust thinks the same step could be called multiple times // need all vars here to be mutable because rust thinks the same step could be called
// and also initialize, because otherwise rust thinks it's used while unitilized, even if thats not the case as the loop goes only forward // multiple times and also initialize, because otherwise rust thinks it's used while
// unitialized, even if thats not the case as the loop goes only forward
let mut param_domain = "undefined.undefined".to_owned(); let mut param_domain = "undefined.undefined".to_owned();
let mut param_addr_urlencoded: String = let mut param_addr_urlencoded: String =
"Internal Error: this value should never be used".to_owned(); "Internal Error: this value should never be used".to_owned();
let mut keep_flags = 0; let mut keep_flags = 0;
let mut step_counter: u8 = 0;
let (_s, r) = async_std::sync::channel(1); let (_s, r) = async_std::sync::channel(1);
let mut imap = Imap::new(r); let mut imap = Imap::new(r);
let was_configured_before = self.is_configured().await; let was_configured_before = self.is_configured().await;
while !self.shall_stop_ongoing().await { let success = exec(
step_counter += 1;
match exec_step(
self, self,
&mut imap, &mut imap,
&mut param, &mut param,
@@ -96,24 +92,8 @@ impl Context {
&mut param_autoconfig, &mut param_autoconfig,
&mut param_addr_urlencoded, &mut param_addr_urlencoded,
&mut keep_flags, &mut keep_flags,
&mut step_counter,
) )
.await .await;
{
Ok(step) => {
success = true;
match step {
Step::Continue => {}
Step::Done => break,
}
}
Err(err) => {
error!(self, "{}", err);
success = false;
break;
}
}
}
if imap.is_connected() { if imap.is_connected() {
imap.disconnect(self).await; imap.disconnect(self).await;
@@ -122,18 +102,16 @@ impl Context {
// remember the entered parameters on success // remember the entered parameters on success
// and restore to last-entered on failure. // and restore to last-entered on failure.
// this way, the parameters visible to the ui are always in-sync with the current configuration. // this way, the parameters visible to the ui are always in-sync with the current configuration.
if success { if success.is_ok() {
LoginParam::from_database(self, "") LoginParam::from_database(self, "")
.await .await
.save_to_database(self, "configured_raw_") .save_to_database(self, "configured_raw_")
.await .await?;
.ok();
} else { } else {
LoginParam::from_database(self, "configured_raw_") LoginParam::from_database(self, "configured_raw_")
.await .await
.save_to_database(self, "") .save_to_database(self, "")
.await .await?;
.ok();
} }
if let Some(provider) = provider::get_provider_info(&param.addr) { if let Some(provider) = provider::get_provider_info(&param.addr) {
@@ -158,18 +136,22 @@ impl Context {
} }
} }
if success { match success {
Ok(_) => {
progress!(self, 1000); progress!(self, 1000);
Ok(()) Ok(())
} else { }
Err(err) => {
error!(self, "Configure Failed: {}", err);
progress!(self, 0); progress!(self, 0);
Err(format_err!("Configure failed")) Err(err)
}
} }
} }
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
async fn exec_step( async fn exec(
ctx: &Context, ctx: &Context,
imap: &mut Imap, imap: &mut Imap,
param: &mut LoginParam, param: &mut LoginParam,
@@ -177,19 +159,16 @@ async fn exec_step(
param_autoconfig: &mut Option<LoginParam>, param_autoconfig: &mut Option<LoginParam>,
param_addr_urlencoded: &mut String, param_addr_urlencoded: &mut String,
keep_flags: &mut i32, keep_flags: &mut i32,
step_counter: &mut u8, ) -> Result<()> {
) -> Result<Step> { let mut use_autoconfig = true;
const STEP_12_USE_AUTOCONFIG: u8 = 12; let mut have_autoconfig = false;
const STEP_13_AFTER_AUTOCONFIG: u8 = 13;
match *step_counter {
// Read login parameters from the database // Read login parameters from the database
1 => {
progress!(ctx, 1); progress!(ctx, 1);
ensure!(!param.addr.is_empty(), "Please enter an email address."); ensure!(!param.addr.is_empty(), "Please enter an email address.");
}
// Step 1: Load the parameters and check email-address and password // Step 1: Load the parameters and check email-address and password
2 => {
if 0 != param.server_flags & DC_LP_AUTH_OAUTH2 { if 0 != param.server_flags & DC_LP_AUTH_OAUTH2 {
// 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, // if dc_get_oauth2_addr() is not available in the oauth2 implementation,
@@ -208,19 +187,12 @@ async fn exec_step(
progress!(ctx, 20); progress!(ctx, 20);
} }
// no oauth? - just continue it's no error // no oauth? - just continue it's no error
}
3 => { let parsed: EmailAddress = param.addr.parse().context("Bad email-address")?;
if let Ok(parsed) = param.addr.parse() {
let parsed: EmailAddress = parsed;
*param_domain = parsed.domain; *param_domain = parsed.domain;
*param_addr_urlencoded = *param_addr_urlencoded = utf8_percent_encode(&param.addr, NON_ALPHANUMERIC).to_string();
utf8_percent_encode(&param.addr, NON_ALPHANUMERIC).to_string();
} else {
bail!("Bad email-address.");
}
}
// Step 2: Autoconfig // Step 2: Autoconfig
4 => {
progress!(ctx, 200); progress!(ctx, 200);
if param.mail_server.is_empty() if param.mail_server.is_empty()
@@ -237,89 +209,27 @@ async fn exec_step(
if let Some(new_param) = get_offline_autoconfig(ctx, &param) { if let Some(new_param) = get_offline_autoconfig(ctx, &param) {
// got parameters from our provider-database, skip Autoconfig, preserve the OAuth2 setting // got parameters from our provider-database, skip Autoconfig, preserve the OAuth2 setting
*param_autoconfig = Some(new_param); *param_autoconfig = Some(new_param);
*step_counter = STEP_12_USE_AUTOCONFIG - 1; // minus one as step_counter is increased on next loop have_autoconfig = true;
} }
} else { } else {
// advanced parameters entered by the user: skip Autoconfig // 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 use_autoconfig = false;
} }
if !have_autoconfig {
get_autoconfig(
ctx,
param,
param_domain,
param_autoconfig,
param_addr_urlencoded,
)
.await?;
} }
/* A. Search configurations from the domain used in the email-address, prefer encrypted */
5 => { /* C. Do we have any autoconfig result? */
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).await.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).await.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).await.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).await.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).await.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).await.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).await.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); progress!(ctx, 500);
if use_autoconfig {
if let Some(ref cfg) = param_autoconfig { if let Some(ref cfg) = param_autoconfig {
info!(ctx, "Got autoconfig: {}", &cfg); info!(ctx, "Got autoconfig: {}", &cfg);
if !cfg.mail_user.is_empty() { if !cfg.mail_user.is_empty() {
@@ -336,9 +246,8 @@ async fn exec_step(
} }
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 you change the match-number here, also update STEP_13_AFTER_AUTOCONFIG above
STEP_13_AFTER_AUTOCONFIG => {
if param.mail_server.is_empty() { if param.mail_server.is_empty() {
param.mail_server = format!("imap.{}", param_domain,) param.mail_server = format!("imap.{}", param_domain,)
} }
@@ -408,18 +317,15 @@ async fn exec_step(
{ {
bail!("Account settings incomplete."); bail!("Account settings incomplete.");
} }
}
14 => {
progress!(ctx, 600); progress!(ctx, 600);
/* try to connect to IMAP - if we did not got an autoconfig, /* try to connect to IMAP - if we did not got an autoconfig,
do some further tries with different settings and username variations */ do some further tries with different settings and username variations */
try_imap_connections(ctx, param, param_autoconfig.is_some(), imap).await?; try_imap_connections(ctx, param, param_autoconfig.is_some(), imap).await?;
}
15 => {
progress!(ctx, 800); progress!(ctx, 800);
try_smtp_connections(ctx, param, param_autoconfig.is_some()).await?; try_smtp_connections(ctx, param, param_autoconfig.is_some()).await?;
}
16 => {
progress!(ctx, 900); progress!(ctx, 900);
let create_mvbox = ctx.get_config_bool(Config::MvboxWatch).await let create_mvbox = ctx.get_config_bool(Config::MvboxWatch).await
@@ -432,37 +338,95 @@ async fn exec_step(
if let Err(err) = imap.select_with_uidvalidity(ctx, "INBOX").await { if let Err(err) = imap.select_with_uidvalidity(ctx, "INBOX").await {
bail!("could not read INBOX status: {:?}", err); bail!("could not read INBOX status: {:?}", err);
} }
}
17 => {
progress!(ctx, 910); progress!(ctx, 910);
// configuration success - write back the configured parameters with the // configuration success - write back the configured parameters with the
// "configured_" prefix; also write the "configured"-flag */ // "configured_" prefix; also write the "configured"-flag */
// the trailing underscore is correct // the trailing underscore is correct
param.save_to_database(ctx, "configured_").await?; param.save_to_database(ctx, "configured_").await?;
ctx.sql.set_raw_config_bool(ctx, "configured", true).await?; ctx.sql.set_raw_config_bool(ctx, "configured", true).await?;
}
18 => {
progress!(ctx, 920); progress!(ctx, 920);
// we generate the keypair just now - we could also postpone this until the first message is sent, however, // 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 // 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. // (~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?; e2ee::ensure_secret_key_exists(ctx).await?;
info!(ctx, "key generation completed"); info!(ctx, "key generation completed");
progress!(ctx, 940);
return Ok(Step::Done);
}
_ => {
bail!("Internal error: step counter out of bound");
}
}
Ok(Step::Continue) progress!(ctx, 940);
Ok(())
} }
#[derive(Debug)] async fn get_autoconfig(
enum Step { ctx: &Context,
Done, param: &mut LoginParam,
Continue, param_domain: &mut String,
param_autoconfig: &mut Option<LoginParam>,
param_addr_urlencoded: &mut String,
) -> Result<()> {
/* A. Search configurations from the domain used in the email-address, prefer encrypted */
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).await.ok();
}
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).await.ok();
}
/* Outlook section start ------------- */
/* Outlook uses always SSL but different domains (this comment describes the next two steps) */
progress!(ctx, 310);
if param_autoconfig.is_none() {
let url = format!("https://{}/autodiscover/autodiscover.xml", param_domain);
*param_autoconfig = outlk_autodiscover(ctx, &url, &param).await.ok();
}
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).await.ok();
}
/* ----------- Outlook section end */
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).await.ok();
}
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).await.ok();
}
/* B. If we have no configuration yet, search configuration in Thunderbird's centeral database */
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).await.ok();
}
Ok(())
} }
#[allow(clippy::unnecessary_unwrap)] #[allow(clippy::unnecessary_unwrap)]