mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 09:26:29 +03:00
refactor(configure): remove step-counter
This commit is contained in:
@@ -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,54 +66,34 @@ 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;
|
self,
|
||||||
|
&mut imap,
|
||||||
match exec_step(
|
&mut param,
|
||||||
self,
|
&mut param_domain,
|
||||||
&mut imap,
|
&mut param_autoconfig,
|
||||||
&mut param,
|
&mut param_addr_urlencoded,
|
||||||
&mut param_domain,
|
&mut keep_flags,
|
||||||
&mut param_autoconfig,
|
)
|
||||||
&mut param_addr_urlencoded,
|
.await;
|
||||||
&mut keep_flags,
|
|
||||||
&mut step_counter,
|
|
||||||
)
|
|
||||||
.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(¶m.addr) {
|
if let Some(provider) = provider::get_provider_info(¶m.addr) {
|
||||||
@@ -158,18 +136,22 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if success {
|
match success {
|
||||||
progress!(self, 1000);
|
Ok(_) => {
|
||||||
Ok(())
|
progress!(self, 1000);
|
||||||
} else {
|
Ok(())
|
||||||
progress!(self, 0);
|
}
|
||||||
Err(format_err!("Configure failed"))
|
Err(err) => {
|
||||||
|
error!(self, "Configure Failed: {}", err);
|
||||||
|
progress!(self, 0);
|
||||||
|
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,53 +159,43 @@ 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
|
progress!(ctx, 1);
|
||||||
1 => {
|
ensure!(!param.addr.is_empty(), "Please enter an email address.");
|
||||||
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, ¶m.addr, ¶m.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(¶m.addr, NON_ALPHANUMERIC).to_string();
|
|
||||||
} else {
|
|
||||||
bail!("Bad email-address.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Step 2: Autoconfig
|
|
||||||
4 => {
|
|
||||||
progress!(ctx, 200);
|
|
||||||
|
|
||||||
if param.mail_server.is_empty()
|
// Step 1: Load the parameters and check email-address and password
|
||||||
|
|
||||||
|
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, ¶m.addr, ¶m.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
|
||||||
|
|
||||||
|
let parsed: EmailAddress = param.addr.parse().context("Bad email-address")?;
|
||||||
|
*param_domain = parsed.domain;
|
||||||
|
*param_addr_urlencoded = utf8_percent_encode(¶m.addr, NON_ALPHANUMERIC).to_string();
|
||||||
|
|
||||||
|
// Step 2: Autoconfig
|
||||||
|
progress!(ctx, 200);
|
||||||
|
|
||||||
|
if param.mail_server.is_empty()
|
||||||
&& param.mail_port == 0
|
&& param.mail_port == 0
|
||||||
/* && 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_server.is_empty()
|
&& param.send_server.is_empty()
|
||||||
@@ -231,238 +203,230 @@ async fn exec_step(
|
|||||||
&& param.send_user.is_empty()
|
&& 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.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
|
&& (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
|
||||||
*keep_flags = param.server_flags & DC_LP_AUTH_OAUTH2;
|
*keep_flags = param.server_flags & DC_LP_AUTH_OAUTH2;
|
||||||
if let Some(new_param) = get_offline_autoconfig(ctx, ¶m) {
|
if let Some(new_param) = get_offline_autoconfig(ctx, ¶m) {
|
||||||
// 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 {
|
|
||||||
// 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, ¶m).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, ¶m).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, ¶m).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, ¶m).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, ¶m).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, ¶m).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, ¶m).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);
|
|
||||||
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?;
|
|
||||||
}
|
|
||||||
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.configure_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?;
|
|
||||||
ctx.sql.set_raw_config_bool(ctx, "configured", true).await?;
|
|
||||||
}
|
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// advanced parameters entered by the user: skip Autoconfig
|
||||||
|
use_autoconfig = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Step::Continue)
|
if !have_autoconfig {
|
||||||
|
get_autoconfig(
|
||||||
|
ctx,
|
||||||
|
param,
|
||||||
|
param_domain,
|
||||||
|
param_autoconfig,
|
||||||
|
param_addr_urlencoded,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* C. Do we have any autoconfig result? */
|
||||||
|
progress!(ctx, 500);
|
||||||
|
if use_autoconfig {
|
||||||
|
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 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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
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?;
|
||||||
|
|
||||||
|
progress!(ctx, 800);
|
||||||
|
try_smtp_connections(ctx, param, param_autoconfig.is_some()).await?;
|
||||||
|
|
||||||
|
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.configure_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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?;
|
||||||
|
ctx.sql.set_raw_config_bool(ctx, "configured", true).await?;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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, ¶m).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, ¶m).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, ¶m).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, ¶m).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, ¶m).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, ¶m).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, ¶m).await.ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::unnecessary_unwrap)]
|
#[allow(clippy::unnecessary_unwrap)]
|
||||||
|
|||||||
Reference in New Issue
Block a user