mirror of
https://github.com/chatmail/core.git
synced 2026-05-08 09:26:29 +03:00
the basics work
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
extern crate deltachat;
|
extern crate deltachat;
|
||||||
|
|
||||||
use async_std::task;
|
|
||||||
|
|
||||||
use std::time;
|
use std::time;
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
|
|
||||||
@@ -41,13 +39,9 @@ async fn main() {
|
|||||||
println!("info: {:#?}", info);
|
println!("info: {:#?}", info);
|
||||||
|
|
||||||
let ctx1 = ctx.clone();
|
let ctx1 = ctx.clone();
|
||||||
task::spawn(async move {
|
std::thread::spawn(move || loop {
|
||||||
loop {
|
|
||||||
if let Ok(event) = ctx1.get_next_event() {
|
if let Ok(event) = ctx1.get_next_event() {
|
||||||
cb(event);
|
cb(event);
|
||||||
} else {
|
|
||||||
task::sleep(time::Duration::from_millis(100)).await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -62,11 +56,10 @@ async fn main() {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
ctx.configure().await;
|
ctx.configure().await.unwrap();
|
||||||
|
|
||||||
println!("------ RUN ------");
|
println!("------ RUN ------");
|
||||||
ctx.run().await;
|
ctx.clone().run().await;
|
||||||
|
|
||||||
println!("--- SENDING A MESSAGE ---");
|
println!("--- SENDING A MESSAGE ---");
|
||||||
|
|
||||||
let contact_id = Contact::create(&ctx, "dignifiedquire", "dignifiedquire@gmail.com")
|
let contact_id = Contact::create(&ctx, "dignifiedquire", "dignifiedquire@gmail.com")
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use crate::config::Config;
|
|||||||
use crate::constants::*;
|
use crate::constants::*;
|
||||||
use crate::context::Context;
|
use crate::context::Context;
|
||||||
use crate::dc_tools::*;
|
use crate::dc_tools::*;
|
||||||
|
use crate::error::{Error, Result};
|
||||||
use crate::imap::Imap;
|
use crate::imap::Imap;
|
||||||
use crate::login_param::{CertificateChecks, LoginParam};
|
use crate::login_param::{CertificateChecks, LoginParam};
|
||||||
use crate::oauth2::*;
|
use crate::oauth2::*;
|
||||||
@@ -37,31 +38,28 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Configures this account with the currently set parameters.
|
/// Configures this account with the currently set parameters.
|
||||||
pub async fn configure(&self) {
|
pub async fn configure(&self) -> Result<()> {
|
||||||
if self.has_ongoing().await {
|
ensure!(
|
||||||
warn!(self, "There is already another ongoing process running.",);
|
!self.has_ongoing().await,
|
||||||
return;
|
"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 success = false;
|
||||||
let mut param_autoconfig: Option<LoginParam> = None;
|
let mut param_autoconfig: Option<LoginParam> = None;
|
||||||
|
|
||||||
info!(self, "Configure ...",);
|
info!(self, "Configure ...");
|
||||||
|
|
||||||
// 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;
|
||||||
@@ -72,9 +70,6 @@ impl Context {
|
|||||||
"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;
|
||||||
|
|
||||||
const STEP_12_USE_AUTOCONFIG: u8 = 12;
|
|
||||||
const STEP_13_AFTER_AUTOCONFIG: u8 = 13;
|
|
||||||
|
|
||||||
let mut step_counter: u8 = 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);
|
||||||
@@ -83,14 +78,100 @@ impl Context {
|
|||||||
while !self.shall_stop_ongoing().await {
|
while !self.shall_stop_ongoing().await {
|
||||||
step_counter += 1;
|
step_counter += 1;
|
||||||
|
|
||||||
let success = match step_counter {
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
error!(self, "{}", err);
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_imap_connected {
|
||||||
|
imap.disconnect(self).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(provider) = provider::get_provider_info(¶m.addr) {
|
||||||
|
if !provider.after_login_hint.is_empty() {
|
||||||
|
let mut msg = Message::new(Viewtype::Text);
|
||||||
|
msg.text = Some(provider.after_login_hint.to_string());
|
||||||
|
if chat::add_device_msg(self, Some("core-provider-info"), Some(&mut msg))
|
||||||
|
.await
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
warn!(self, "cannot add after_login_hint as core-provider-info");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
// Read login parameters from the database
|
||||||
1 => {
|
1 => {
|
||||||
progress!(self, 1);
|
progress!(ctx, 1);
|
||||||
if param.addr.is_empty() {
|
ensure!(!param.addr.is_empty(), "Please enter an email address.");
|
||||||
error!(self, "Please enter an email address.",);
|
|
||||||
}
|
|
||||||
!param.addr.is_empty()
|
|
||||||
}
|
}
|
||||||
// Step 1: Load the parameters and check email-address and password
|
// Step 1: Load the parameters and check email-address and password
|
||||||
2 => {
|
2 => {
|
||||||
@@ -98,60 +179,55 @@ impl Context {
|
|||||||
// 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,
|
||||||
// just use the given one.
|
// just use the given one.
|
||||||
progress!(self, 10);
|
progress!(ctx, 10);
|
||||||
if let Some(oauth2_addr) =
|
if let Some(oauth2_addr) = dc_get_oauth2_addr(ctx, ¶m.addr, ¶m.mail_pw)
|
||||||
dc_get_oauth2_addr(self, ¶m.addr, ¶m.mail_pw)
|
|
||||||
.await
|
.await
|
||||||
.and_then(|e| e.parse().ok())
|
.and_then(|e| e.parse().ok())
|
||||||
{
|
{
|
||||||
info!(self, "Authorized address is {}", oauth2_addr);
|
info!(ctx, "Authorized address is {}", oauth2_addr);
|
||||||
param.addr = oauth2_addr;
|
param.addr = oauth2_addr;
|
||||||
self.sql
|
ctx.sql
|
||||||
.set_raw_config(self, "addr", Some(param.addr.as_str()))
|
.set_raw_config(ctx, "addr", Some(param.addr.as_str()))
|
||||||
.await
|
.await?;
|
||||||
.ok();
|
|
||||||
}
|
}
|
||||||
progress!(self, 20);
|
progress!(ctx, 20);
|
||||||
}
|
}
|
||||||
true // no oauth? - just continue it's no error
|
// no oauth? - just continue it's no error
|
||||||
}
|
}
|
||||||
3 => {
|
3 => {
|
||||||
if let Ok(parsed) = param.addr.parse() {
|
if let Ok(parsed) = param.addr.parse() {
|
||||||
let parsed: EmailAddress = parsed;
|
let parsed: EmailAddress = parsed;
|
||||||
param_domain = parsed.domain;
|
*param_domain = parsed.domain;
|
||||||
param_addr_urlencoded =
|
*param_addr_urlencoded =
|
||||||
utf8_percent_encode(¶m.addr, NON_ALPHANUMERIC).to_string();
|
utf8_percent_encode(¶m.addr, NON_ALPHANUMERIC).to_string();
|
||||||
true
|
|
||||||
} else {
|
} else {
|
||||||
error!(self, "Bad email-address.");
|
bail!("Bad email-address.");
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Step 2: Autoconfig
|
// Step 2: Autoconfig
|
||||||
4 => {
|
4 => {
|
||||||
progress!(self, 200);
|
progress!(ctx, 200);
|
||||||
|
|
||||||
if param.mail_server.is_empty()
|
if param.mail_server.is_empty()
|
||||||
&& param.mail_port == 0
|
&& param.mail_port == 0
|
||||||
/*&¶m.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()
|
||||||
&& param.send_port == 0
|
&& param.send_port == 0
|
||||||
&& param.send_user.is_empty()
|
&& param.send_user.is_empty()
|
||||||
/*&¶m.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(self, ¶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
|
*step_counter = STEP_12_USE_AUTOCONFIG - 1; // minus one as step_counter is increased on next loop
|
||||||
}
|
}
|
||||||
} 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
|
*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 */
|
/* A. Search configurations from the domain used in the email-address, prefer encrypted */
|
||||||
5 => {
|
5 => {
|
||||||
@@ -160,85 +236,77 @@ impl Context {
|
|||||||
"https://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
|
"https://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
|
||||||
param_domain, param_addr_urlencoded
|
param_domain, param_addr_urlencoded
|
||||||
);
|
);
|
||||||
param_autoconfig = moz_autoconfigure(self, &url, ¶m).ok();
|
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).ok();
|
||||||
}
|
}
|
||||||
true
|
|
||||||
}
|
}
|
||||||
6 => {
|
6 => {
|
||||||
progress!(self, 300);
|
progress!(ctx, 300);
|
||||||
if param_autoconfig.is_none() {
|
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
|
// the doc does not mention `emailaddress=`, however, Thunderbird adds it, see https://releases.mozilla.org/pub/thunderbird/ , which makes some sense
|
||||||
let url = format!(
|
let url = format!(
|
||||||
"https://{}/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress={}",
|
"https://{}/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress={}",
|
||||||
param_domain, param_addr_urlencoded
|
param_domain, param_addr_urlencoded
|
||||||
);
|
);
|
||||||
param_autoconfig = moz_autoconfigure(self, &url, ¶m).ok();
|
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).ok();
|
||||||
}
|
}
|
||||||
true
|
|
||||||
}
|
}
|
||||||
/* Outlook section start ------------- */
|
/* Outlook section start ------------- */
|
||||||
/* Outlook uses always SSL but different domains (this comment describes the next two steps) */
|
/* Outlook uses always SSL but different domains (this comment describes the next two steps) */
|
||||||
7 => {
|
7 => {
|
||||||
progress!(self, 310);
|
progress!(ctx, 310);
|
||||||
if param_autoconfig.is_none() {
|
if param_autoconfig.is_none() {
|
||||||
let url = format!("https://{}/autodiscover/autodiscover.xml", param_domain);
|
let url = format!("https://{}/autodiscover/autodiscover.xml", param_domain);
|
||||||
param_autoconfig = outlk_autodiscover(self, &url, ¶m).ok();
|
*param_autoconfig = outlk_autodiscover(ctx, &url, ¶m).ok();
|
||||||
}
|
}
|
||||||
true
|
|
||||||
}
|
}
|
||||||
8 => {
|
8 => {
|
||||||
progress!(self, 320);
|
progress!(ctx, 320);
|
||||||
if param_autoconfig.is_none() {
|
if param_autoconfig.is_none() {
|
||||||
let url = format!(
|
let url = format!(
|
||||||
"https://{}{}/autodiscover/autodiscover.xml",
|
"https://{}{}/autodiscover/autodiscover.xml",
|
||||||
"autodiscover.", param_domain
|
"autodiscover.", param_domain
|
||||||
);
|
);
|
||||||
param_autoconfig = outlk_autodiscover(self, &url, ¶m).ok();
|
*param_autoconfig = outlk_autodiscover(ctx, &url, ¶m).ok();
|
||||||
}
|
}
|
||||||
true
|
|
||||||
}
|
}
|
||||||
/* ----------- Outlook section end */
|
/* ----------- Outlook section end */
|
||||||
9 => {
|
9 => {
|
||||||
progress!(self, 330);
|
progress!(ctx, 330);
|
||||||
if param_autoconfig.is_none() {
|
if param_autoconfig.is_none() {
|
||||||
let url = format!(
|
let url = format!(
|
||||||
"http://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
|
"http://autoconfig.{}/mail/config-v1.1.xml?emailaddress={}",
|
||||||
param_domain, param_addr_urlencoded
|
param_domain, param_addr_urlencoded
|
||||||
);
|
);
|
||||||
param_autoconfig = moz_autoconfigure(self, &url, ¶m).ok();
|
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).ok();
|
||||||
}
|
}
|
||||||
true
|
|
||||||
}
|
}
|
||||||
10 => {
|
10 => {
|
||||||
progress!(self, 340);
|
progress!(ctx, 340);
|
||||||
if param_autoconfig.is_none() {
|
if param_autoconfig.is_none() {
|
||||||
// do not transfer the email-address unencrypted
|
// do not transfer the email-address unencrypted
|
||||||
let url = format!(
|
let url = format!(
|
||||||
"http://{}/.well-known/autoconfig/mail/config-v1.1.xml",
|
"http://{}/.well-known/autoconfig/mail/config-v1.1.xml",
|
||||||
param_domain
|
param_domain
|
||||||
);
|
);
|
||||||
param_autoconfig = moz_autoconfigure(self, &url, ¶m).ok();
|
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).ok();
|
||||||
}
|
}
|
||||||
true
|
|
||||||
}
|
}
|
||||||
/* B. If we have no configuration yet, search configuration in Thunderbird's centeral database */
|
/* B. If we have no configuration yet, search configuration in Thunderbird's centeral database */
|
||||||
11 => {
|
11 => {
|
||||||
progress!(self, 350);
|
progress!(ctx, 350);
|
||||||
if param_autoconfig.is_none() {
|
if param_autoconfig.is_none() {
|
||||||
/* always SSL for Thunderbird's database */
|
/* always SSL for Thunderbird's database */
|
||||||
let url =
|
let url = format!("https://autoconfig.thunderbird.net/v1.1/{}", param_domain);
|
||||||
format!("https://autoconfig.thunderbird.net/v1.1/{}", param_domain);
|
*param_autoconfig = moz_autoconfigure(ctx, &url, ¶m).ok();
|
||||||
param_autoconfig = moz_autoconfigure(self, &url, ¶m).ok();
|
|
||||||
}
|
}
|
||||||
true
|
|
||||||
}
|
}
|
||||||
/* C. Do we have any autoconfig result?
|
/* C. Do we have any autoconfig result?
|
||||||
If you change the match-number here, also update STEP_12_COPY_AUTOCONFIG above
|
If you change the match-number here, also update STEP_12_COPY_AUTOCONFIG above
|
||||||
*/
|
*/
|
||||||
STEP_12_USE_AUTOCONFIG => {
|
STEP_12_USE_AUTOCONFIG => {
|
||||||
progress!(self, 500);
|
progress!(ctx, 500);
|
||||||
if let Some(ref cfg) = param_autoconfig {
|
if let Some(ref cfg) = param_autoconfig {
|
||||||
info!(self, "Got autoconfig: {}", &cfg);
|
info!(ctx, "Got autoconfig: {}", &cfg);
|
||||||
if !cfg.mail_user.is_empty() {
|
if !cfg.mail_user.is_empty() {
|
||||||
param.mail_user = cfg.mail_user.clone();
|
param.mail_user = cfg.mail_user.clone();
|
||||||
}
|
}
|
||||||
@@ -251,8 +319,7 @@ impl Context {
|
|||||||
/* although param_autoconfig's data are no longer needed from,
|
/* although param_autoconfig's data are no longer needed from,
|
||||||
it is used to later to prevent trying variations of port/server/logins */
|
it is used to later to prevent trying variations of port/server/logins */
|
||||||
}
|
}
|
||||||
param.server_flags |= keep_flags;
|
param.server_flags |= *keep_flags;
|
||||||
true
|
|
||||||
}
|
}
|
||||||
// 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
|
// If you change the match-number here, also update STEP_13_AFTER_AUTOCONFIG above
|
||||||
@@ -277,8 +344,7 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if param.send_port == 0 {
|
if param.send_port == 0 {
|
||||||
param.send_port =
|
param.send_port = if 0 != param.server_flags & DC_LP_SMTP_SOCKET_STARTTLS as i32 {
|
||||||
if 0 != param.server_flags & DC_LP_SMTP_SOCKET_STARTTLS as i32 {
|
|
||||||
587
|
587
|
||||||
} else if 0 != param.server_flags & DC_LP_SMTP_SOCKET_PLAIN as i32 {
|
} else if 0 != param.server_flags & DC_LP_SMTP_SOCKET_PLAIN as i32 {
|
||||||
25
|
25
|
||||||
@@ -296,8 +362,7 @@ impl Context {
|
|||||||
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
|
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)
|
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 &= !(DC_LP_IMAP_SOCKET_FLAGS as i32);
|
||||||
param.server_flags |= if param.send_port == 143 {
|
param.server_flags |= if param.send_port == 143 {
|
||||||
DC_LP_IMAP_SOCKET_STARTTLS as i32
|
DC_LP_IMAP_SOCKET_STARTTLS as i32
|
||||||
@@ -305,9 +370,7 @@ impl Context {
|
|||||||
DC_LP_IMAP_SOCKET_SSL as i32
|
DC_LP_IMAP_SOCKET_SSL as i32
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !dc_exactly_one_bit_set(
|
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 &= !(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 {
|
param.server_flags |= if param.send_port == 587 {
|
||||||
DC_LP_SMTP_SOCKET_STARTTLS as i32
|
DC_LP_SMTP_SOCKET_STARTTLS as i32
|
||||||
@@ -328,120 +391,64 @@ impl Context {
|
|||||||
|| param.send_pw.is_empty()
|
|| param.send_pw.is_empty()
|
||||||
|| param.server_flags == 0
|
|| param.server_flags == 0
|
||||||
{
|
{
|
||||||
error!(self, "Account settings incomplete.");
|
bail!("Account settings incomplete.");
|
||||||
false
|
|
||||||
} else {
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
14 => {
|
14 => {
|
||||||
progress!(self, 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 */
|
||||||
is_imap_connected = try_imap_connections(
|
try_imap_connections(ctx, param, param_autoconfig.is_some(), imap).await?;
|
||||||
self,
|
*is_imap_connected = true;
|
||||||
&mut param,
|
|
||||||
param_autoconfig.is_some(),
|
|
||||||
&mut imap,
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
is_imap_connected
|
|
||||||
}
|
}
|
||||||
15 => {
|
15 => {
|
||||||
progress!(self, 800);
|
progress!(ctx, 800);
|
||||||
try_smtp_connections(self, &mut param, param_autoconfig.is_some()).await
|
try_smtp_connections(ctx, param, param_autoconfig.is_some()).await?;
|
||||||
}
|
}
|
||||||
16 => {
|
16 => {
|
||||||
progress!(self, 900);
|
progress!(ctx, 900);
|
||||||
let create_mvbox = self.get_config_bool(Config::MvboxWatch).await
|
let create_mvbox = ctx.get_config_bool(Config::MvboxWatch).await
|
||||||
|| self.get_config_bool(Config::MvboxMove).await;
|
|| ctx.get_config_bool(Config::MvboxMove).await;
|
||||||
if let Err(err) = imap.ensure_configured_folders(self, create_mvbox).await {
|
if let Err(err) = imap.ensure_configured_folders(ctx, create_mvbox).await {
|
||||||
warn!(self, "configuring folders failed: {:?}", err);
|
bail!("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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Err(err) = imap.select_with_uidvalidity(ctx, "INBOX").await {
|
||||||
|
bail!("could not read INBOX status: {:?}", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
17 => {
|
17 => {
|
||||||
progress!(self, 910);
|
progress!(ctx, 910);
|
||||||
/* configuration success - write back the configured parameters with the "configured_" prefix; also write the "configured"-flag */
|
// configuration success - write back the configured parameters with the
|
||||||
param
|
// "configured_" prefix; also write the "configured"-flag */
|
||||||
.save_to_database(
|
// the trailing underscore is correct
|
||||||
self,
|
param.save_to_database(ctx, "configured_").await?;
|
||||||
"configured_", /*the trailing underscore is correct*/
|
println!("storing configured val");
|
||||||
)
|
ctx.sql.set_raw_config_bool(ctx, "configured", true).await?;
|
||||||
.await
|
println!("stored configured val");
|
||||||
.ok();
|
|
||||||
|
|
||||||
self.sql
|
|
||||||
.set_raw_config_bool(self, "configured", true)
|
|
||||||
.await
|
|
||||||
.ok();
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
18 => {
|
18 => {
|
||||||
progress!(self, 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.
|
||||||
success = e2ee::ensure_secret_key_exists(self).await.is_ok();
|
e2ee::ensure_secret_key_exists(ctx).await?;
|
||||||
info!(self, "key generation completed");
|
info!(ctx, "key generation completed");
|
||||||
progress!(self, 940);
|
progress!(ctx, 940);
|
||||||
break; // We are done here
|
return Ok(Step::Done);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!(self, "Internal error: step counter out of bound",);
|
bail!("Internal error: step counter out of bound");
|
||||||
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(¶m.addr) {
|
|
||||||
if !provider.after_login_hint.is_empty() {
|
|
||||||
let mut msg = Message::new(Viewtype::Text);
|
|
||||||
msg.text = Some(provider.after_login_hint.to_string());
|
|
||||||
if chat::add_device_msg(self, Some("core-provider-info"), Some(&mut msg))
|
|
||||||
.await
|
|
||||||
.is_err()
|
|
||||||
{
|
|
||||||
warn!(self, "cannot add after_login_hint as core-provider-info");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.free_ongoing().await;
|
Ok(Step::Continue)
|
||||||
progress!(self, if success { 1000 } else { 0 });
|
}
|
||||||
}
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum Step {
|
||||||
|
Done,
|
||||||
|
Continue,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::unnecessary_unwrap)]
|
#[allow(clippy::unnecessary_unwrap)]
|
||||||
@@ -507,10 +514,13 @@ async fn try_imap_connections(
|
|||||||
mut param: &mut LoginParam,
|
mut param: &mut LoginParam,
|
||||||
was_autoconfig: bool,
|
was_autoconfig: bool,
|
||||||
imap: &mut Imap,
|
imap: &mut Imap,
|
||||||
) -> bool {
|
) -> Result<()> {
|
||||||
// progress 650 and 660
|
// progress 650 and 660
|
||||||
if let Some(res) = try_imap_connection(context, &mut param, was_autoconfig, 0, imap).await {
|
if try_imap_connection(context, &mut param, was_autoconfig, 0, imap)
|
||||||
return res;
|
.await
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
progress!(context, 670);
|
progress!(context, 670);
|
||||||
param.server_flags &= !(DC_LP_IMAP_SOCKET_FLAGS);
|
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();
|
param.send_user = param.send_user.split_at(at).0.to_string();
|
||||||
}
|
}
|
||||||
// progress 680 and 690
|
// progress 680 and 690
|
||||||
if let Some(res) = try_imap_connection(context, &mut param, was_autoconfig, 1, imap).await {
|
try_imap_connection(context, &mut param, was_autoconfig, 1, imap).await?;
|
||||||
res
|
|
||||||
} else {
|
Ok(())
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn try_imap_connection(
|
async fn try_imap_connection(
|
||||||
@@ -537,18 +545,18 @@ async fn try_imap_connection(
|
|||||||
was_autoconfig: bool,
|
was_autoconfig: bool,
|
||||||
variation: usize,
|
variation: usize,
|
||||||
imap: &mut Imap,
|
imap: &mut Imap,
|
||||||
) -> Option<bool> {
|
) -> Result<()> {
|
||||||
if let Some(res) = try_imap_one_param(context, ¶m, imap).await {
|
if try_imap_one_param(context, ¶m, imap).await.is_ok() {
|
||||||
return Some(res);
|
return Ok(());
|
||||||
}
|
}
|
||||||
if was_autoconfig {
|
if was_autoconfig {
|
||||||
return Some(false);
|
bail!("autoconfig");
|
||||||
}
|
}
|
||||||
progress!(context, 650 + variation * 30);
|
progress!(context, 650 + variation * 30);
|
||||||
param.server_flags &= !(DC_LP_IMAP_SOCKET_FLAGS);
|
param.server_flags &= !(DC_LP_IMAP_SOCKET_FLAGS);
|
||||||
param.server_flags |= DC_LP_IMAP_SOCKET_STARTTLS;
|
param.server_flags |= DC_LP_IMAP_SOCKET_STARTTLS;
|
||||||
if let Some(res) = try_imap_one_param(context, ¶m, imap).await {
|
if try_imap_one_param(context, ¶m, imap).await.is_ok() {
|
||||||
return Some(res);
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
progress!(context, 660 + variation * 30);
|
progress!(context, 660 + variation * 30);
|
||||||
@@ -557,11 +565,7 @@ async fn try_imap_connection(
|
|||||||
try_imap_one_param(context, ¶m, imap).await
|
try_imap_one_param(context, ¶m, imap).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn try_imap_one_param(
|
async fn try_imap_one_param(context: &Context, param: &LoginParam, imap: &mut Imap) -> Result<()> {
|
||||||
context: &Context,
|
|
||||||
param: &LoginParam,
|
|
||||||
imap: &mut Imap,
|
|
||||||
) -> Option<bool> {
|
|
||||||
let inf = format!(
|
let inf = format!(
|
||||||
"imap: {}@{}:{} flags=0x{:x} certificate_checks={}",
|
"imap: {}@{}:{} flags=0x{:x} certificate_checks={}",
|
||||||
param.mail_user,
|
param.mail_user,
|
||||||
@@ -571,78 +575,59 @@ async fn try_imap_one_param(
|
|||||||
param.imap_certificate_checks
|
param.imap_certificate_checks
|
||||||
);
|
);
|
||||||
info!(context, "Trying: {}", inf);
|
info!(context, "Trying: {}", inf);
|
||||||
|
|
||||||
if imap.connect(context, ¶m).await {
|
if imap.connect(context, ¶m).await {
|
||||||
info!(context, "success: {}", inf);
|
info!(context, "success: {}", inf);
|
||||||
return Some(true);
|
return Ok(());
|
||||||
}
|
}
|
||||||
if context.shall_stop_ongoing().await {
|
|
||||||
return Some(false);
|
bail!("Could not connect: {}", inf);
|
||||||
}
|
|
||||||
info!(context, "Could not connect: {}", inf);
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn try_smtp_connections(
|
async fn try_smtp_connections(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
mut param: &mut LoginParam,
|
mut param: &mut LoginParam,
|
||||||
was_autoconfig: bool,
|
was_autoconfig: bool,
|
||||||
) -> bool {
|
) -> Result<()> {
|
||||||
let mut smtp = Smtp::new();
|
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 */
|
/* 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, ¶m, &mut smtp).await {
|
if try_smtp_one_param(context, ¶m, &mut smtp).await.is_ok() {
|
||||||
return res;
|
return Ok(());
|
||||||
}
|
}
|
||||||
if was_autoconfig {
|
if was_autoconfig {
|
||||||
return false;
|
bail!("autoconfig");
|
||||||
}
|
}
|
||||||
progress!(context, 850);
|
progress!(context, 850);
|
||||||
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
||||||
param.server_flags |= DC_LP_SMTP_SOCKET_STARTTLS as i32;
|
param.server_flags |= DC_LP_SMTP_SOCKET_STARTTLS as i32;
|
||||||
param.send_port = 587;
|
param.send_port = 587;
|
||||||
|
|
||||||
if let Some(res) = try_smtp_one_param(context, ¶m, &mut smtp).await {
|
if try_smtp_one_param(context, ¶m, &mut smtp).await.is_ok() {
|
||||||
if res {
|
return Ok(());
|
||||||
smtp.disconnect().await;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
progress!(context, 860);
|
progress!(context, 860);
|
||||||
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
param.server_flags &= !(DC_LP_SMTP_SOCKET_FLAGS as i32);
|
||||||
param.server_flags |= DC_LP_SMTP_SOCKET_STARTTLS as i32;
|
param.server_flags |= DC_LP_SMTP_SOCKET_STARTTLS as i32;
|
||||||
param.send_port = 25;
|
param.send_port = 25;
|
||||||
if let Some(res) = try_smtp_one_param(context, ¶m, &mut smtp).await {
|
try_smtp_one_param(context, ¶m, &mut smtp).await?;
|
||||||
if res {
|
|
||||||
smtp.disconnect().await;
|
Ok(())
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn try_smtp_one_param(
|
async fn try_smtp_one_param(context: &Context, param: &LoginParam, smtp: &mut Smtp) -> Result<()> {
|
||||||
context: &Context,
|
|
||||||
param: &LoginParam,
|
|
||||||
smtp: &mut Smtp,
|
|
||||||
) -> Option<bool> {
|
|
||||||
let inf = format!(
|
let inf = format!(
|
||||||
"smtp: {}@{}:{} flags: 0x{:x}",
|
"smtp: {}@{}:{} flags: 0x{:x}",
|
||||||
param.send_user, param.send_server, param.send_port, param.server_flags
|
param.send_user, param.send_server, param.send_port, param.server_flags
|
||||||
);
|
);
|
||||||
info!(context, "Trying: {}", inf);
|
info!(context, "Trying: {}", inf);
|
||||||
match smtp.connect(context, ¶m).await {
|
|
||||||
Ok(()) => {
|
if let Err(err) = smtp.connect(context, ¶m).await {
|
||||||
|
bail!("could not connect: {}", err);
|
||||||
|
}
|
||||||
|
|
||||||
info!(context, "success: {}", inf);
|
info!(context, "success: {}", inf);
|
||||||
Some(true)
|
smtp.disconnect().await;
|
||||||
}
|
Ok(())
|
||||||
Err(err) => {
|
|
||||||
if context.shall_stop_ongoing().await {
|
|
||||||
Some(false)
|
|
||||||
} else {
|
|
||||||
warn!(context, "could not connect: {}", err);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -663,7 +648,7 @@ mod tests {
|
|||||||
.set_config(Config::MailPw, Some("123456"))
|
.set_config(Config::MailPw, Some("123456"))
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
t.ctx.configure().await;
|
assert!(t.ctx.configure().await.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_std::test]
|
#[async_std::test]
|
||||||
|
|||||||
@@ -128,18 +128,16 @@ impl Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(&self) {
|
pub async fn run(&self) {
|
||||||
let ctx = self.clone();
|
if self.inner.scheduler.read().await.is_running() {
|
||||||
println!("RUN LOCK START");
|
panic!("Already running");
|
||||||
let l = &mut *self.inner.scheduler.write().await;
|
}
|
||||||
println!("RUN LOCK AQ");
|
|
||||||
l.run(ctx);
|
let scheduler = Scheduler::run(self.clone());
|
||||||
println!("RUN LOCK DONE");
|
*self.inner.scheduler.write().await = scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn stop(&self) {
|
pub async fn stop(&self) {
|
||||||
if self.inner.scheduler.read().await.is_running() {
|
self.inner.stop().await;
|
||||||
self.inner.scheduler.write().await.stop().await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns database file path.
|
/// Returns database file path.
|
||||||
@@ -469,11 +467,19 @@ impl Context {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Context {
|
impl InnerContext {
|
||||||
|
async fn stop(&self) {
|
||||||
|
if self.scheduler.read().await.is_running() {
|
||||||
|
self.scheduler.write().await.stop().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for InnerContext {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
async_std::task::block_on(async move {
|
async_std::task::block_on(async move {
|
||||||
self.stop().await;
|
self.stop().await;
|
||||||
self.sql.close(self).await;
|
self.sql.close().await;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -377,7 +377,7 @@ impl Imap {
|
|||||||
if self.is_connected() && !self.should_reconnect() {
|
if self.is_connected() && !self.should_reconnect() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if !context.sql.get_raw_config_bool(context, "configured").await {
|
if !context.is_configured().await {
|
||||||
return Err(Error::ConnectWithoutConfigure);
|
return Err(Error::ConnectWithoutConfigure);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
15
src/imex.rs
15
src/imex.rs
@@ -52,13 +52,10 @@ pub enum ImexMode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Import/export things.
|
/// Import/export things.
|
||||||
/// For this purpose, the function creates a job that is executed in the IMAP-thread then;
|
|
||||||
/// this requires to call dc_perform_inbox_jobs() regularly.
|
|
||||||
///
|
///
|
||||||
/// What to do is defined by the *what* parameter.
|
/// What to do is defined by the *what* parameter.
|
||||||
///
|
///
|
||||||
/// While dc_imex() returns immediately, the started job may take a while,
|
/// During execution of the job,
|
||||||
/// you can stop it using dc_stop_ongoing_process(). During execution of the job,
|
|
||||||
/// some events are sent out:
|
/// some events are sent out:
|
||||||
///
|
///
|
||||||
/// - A number of #DC_EVENT_IMEX_PROGRESS events are sent and may be used to create
|
/// - A number of #DC_EVENT_IMEX_PROGRESS events are sent and may be used to create
|
||||||
@@ -67,7 +64,7 @@ pub enum ImexMode {
|
|||||||
/// - For each file written on export, the function sends #DC_EVENT_IMEX_FILE_WRITTEN
|
/// - For each file written on export, the function sends #DC_EVENT_IMEX_FILE_WRITTEN
|
||||||
///
|
///
|
||||||
/// Only one import-/export-progress can run at the same time.
|
/// Only one import-/export-progress can run at the same time.
|
||||||
/// To cancel an import-/export-progress, use dc_stop_ongoing_process().
|
/// To cancel an import-/export-progress, drop the future returned by this function.
|
||||||
pub async fn imex(
|
pub async fn imex(
|
||||||
context: &Context,
|
context: &Context,
|
||||||
what: ImexMode,
|
what: ImexMode,
|
||||||
@@ -101,7 +98,7 @@ pub async fn has_backup(context: &Context, dir_name: impl AsRef<Path>) -> Result
|
|||||||
newest_backup_time = curr_backup_time;
|
newest_backup_time = curr_backup_time;
|
||||||
}
|
}
|
||||||
info!(context, "backup_time of {} is {}", name, curr_backup_time);
|
info!(context, "backup_time of {} is {}", name, curr_backup_time);
|
||||||
sql.close(&context).await;
|
sql.close().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -423,7 +420,7 @@ async fn import_backup(context: &Context, backup_to_import: impl AsRef<Path>) ->
|
|||||||
!context.is_configured().await,
|
!context.is_configured().await,
|
||||||
"Cannot import backups to accounts in use."
|
"Cannot import backups to accounts in use."
|
||||||
);
|
);
|
||||||
context.sql.close(&context).await;
|
context.sql.close().await;
|
||||||
dc_delete_file(context, context.get_dbfile()).await;
|
dc_delete_file(context, context.get_dbfile()).await;
|
||||||
ensure!(
|
ensure!(
|
||||||
!context.get_dbfile().exists().await,
|
!context.get_dbfile().exists().await,
|
||||||
@@ -528,7 +525,7 @@ async fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
|
|||||||
context.sql.execute("VACUUM;", paramsv![]).await.ok();
|
context.sql.execute("VACUUM;", paramsv![]).await.ok();
|
||||||
|
|
||||||
// we close the database during the copy of the dbfile
|
// we close the database during the copy of the dbfile
|
||||||
context.sql.close(context).await;
|
context.sql.close().await;
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
"Backup '{}' to '{}'.",
|
"Backup '{}' to '{}'.",
|
||||||
@@ -568,7 +565,7 @@ async fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
dest_sql.close(context).await;
|
dest_sql.close().await;
|
||||||
|
|
||||||
Ok(res?)
|
Ok(res?)
|
||||||
}
|
}
|
||||||
|
|||||||
41
src/job.rs
41
src/job.rs
@@ -3,8 +3,8 @@
|
|||||||
//! This module implements a job queue maintained in the SQLite database
|
//! This module implements a job queue maintained in the SQLite database
|
||||||
//! and job types.
|
//! and job types.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::{fmt, time};
|
|
||||||
|
|
||||||
use deltachat_derive::{FromSql, ToSql};
|
use deltachat_derive::{FromSql, ToSql};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
@@ -581,45 +581,6 @@ async fn kill_ids(context: &Context, job_ids: &[u32]) -> sql::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_next_wakeup_time(context: &Context, thread: Thread) -> time::Duration {
|
|
||||||
let t: i64 = context
|
|
||||||
.sql
|
|
||||||
.query_get_value(
|
|
||||||
context,
|
|
||||||
"SELECT MIN(desired_timestamp) FROM jobs WHERE thread=?;",
|
|
||||||
paramsv![thread],
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.unwrap_or_default();
|
|
||||||
|
|
||||||
let mut wakeup_time = time::Duration::new(10 * 60, 0);
|
|
||||||
let now = time();
|
|
||||||
if t > 0 {
|
|
||||||
if t > now {
|
|
||||||
wakeup_time = time::Duration::new((t - now) as u64, 0);
|
|
||||||
} else {
|
|
||||||
wakeup_time = time::Duration::new(0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wakeup_time
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn maybe_network(context: &Context) {
|
|
||||||
unimplemented!();
|
|
||||||
// {
|
|
||||||
// context.smtp.state.write().await.probe_network = true;
|
|
||||||
// context
|
|
||||||
// .probe_imap_network
|
|
||||||
// .store(true, std::sync::atomic::Ordering::Relaxed);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// interrupt_smtp_idle(context).await;
|
|
||||||
// interrupt_inbox_idle(context).await;
|
|
||||||
// interrupt_mvbox_idle(context).await;
|
|
||||||
// interrupt_sentbox_idle(context).await;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn action_exists(context: &Context, action: Action) -> bool {
|
pub async fn action_exists(context: &Context, action: Action) -> bool {
|
||||||
context
|
context
|
||||||
.sql
|
.sql
|
||||||
|
|||||||
@@ -19,10 +19,16 @@ pub(crate) enum Scheduler {
|
|||||||
mvbox: ImapConnectionState,
|
mvbox: ImapConnectionState,
|
||||||
sentbox: ImapConnectionState,
|
sentbox: ImapConnectionState,
|
||||||
smtp: SmtpConnectionState,
|
smtp: SmtpConnectionState,
|
||||||
|
probe_network: bool,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context {
|
impl Context {
|
||||||
|
/// Indicate that the network likely has come back.
|
||||||
|
pub async fn maybe_network(&self) {
|
||||||
|
self.scheduler.write().await.maybe_network().await;
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn interrupt_inbox(&self) {
|
pub(crate) async fn interrupt_inbox(&self) {
|
||||||
self.scheduler.read().await.interrupt_inbox().await;
|
self.scheduler.read().await.interrupt_inbox().await;
|
||||||
}
|
}
|
||||||
@@ -52,14 +58,14 @@ async fn inbox_loop(ctx: Context, inbox_handlers: ImapConnectionHandlers) {
|
|||||||
connection.connect_configured(&ctx).await.unwrap();
|
connection.connect_configured(&ctx).await.unwrap();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// TODO: correct value
|
let probe_network = ctx.scheduler.read().await.get_probe_network();
|
||||||
let probe_network = false;
|
|
||||||
match job::load_next(&ctx, Thread::Imap, probe_network)
|
match job::load_next(&ctx, Thread::Imap, probe_network)
|
||||||
.timeout(Duration::from_millis(200))
|
.timeout(Duration::from_millis(200))
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(Some(job)) => {
|
Ok(Some(job)) => {
|
||||||
job::perform_job(&ctx, job::Connection::Inbox(&mut connection), job).await;
|
job::perform_job(&ctx, job::Connection::Inbox(&mut connection), job).await;
|
||||||
|
ctx.scheduler.write().await.set_probe_network(false);
|
||||||
}
|
}
|
||||||
Ok(None) | Err(async_std::future::TimeoutError { .. }) => {
|
Ok(None) | Err(async_std::future::TimeoutError { .. }) => {
|
||||||
let watch_folder = get_watch_folder(&ctx, "configured_inbox_folder")
|
let watch_folder = get_watch_folder(&ctx, "configured_inbox_folder")
|
||||||
@@ -106,14 +112,14 @@ async fn smtp_loop(ctx: Context, smtp_handlers: SmtpConnectionHandlers) {
|
|||||||
|
|
||||||
let fut = async move {
|
let fut = async move {
|
||||||
loop {
|
loop {
|
||||||
// TODO: correct value
|
let probe_network = ctx.scheduler.read().await.get_probe_network();
|
||||||
let probe_network = false;
|
|
||||||
match job::load_next(&ctx, Thread::Smtp, probe_network)
|
match job::load_next(&ctx, Thread::Smtp, probe_network)
|
||||||
.timeout(Duration::from_millis(200))
|
.timeout(Duration::from_millis(200))
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(Some(job)) => {
|
Ok(Some(job)) => {
|
||||||
job::perform_job(&ctx, job::Connection::Smtp(&mut connection), job).await;
|
job::perform_job(&ctx, job::Connection::Smtp(&mut connection), job).await;
|
||||||
|
ctx.scheduler.write().await.set_probe_network(false);
|
||||||
}
|
}
|
||||||
Ok(None) | Err(async_std::future::TimeoutError { .. }) => {
|
Ok(None) | Err(async_std::future::TimeoutError { .. }) => {
|
||||||
use futures::future::FutureExt;
|
use futures::future::FutureExt;
|
||||||
@@ -133,38 +139,63 @@ async fn smtp_loop(ctx: Context, smtp_handlers: SmtpConnectionHandlers) {
|
|||||||
|
|
||||||
impl Scheduler {
|
impl Scheduler {
|
||||||
/// Start the scheduler, panics if it is already running.
|
/// Start the scheduler, panics if it is already running.
|
||||||
pub fn run(&mut self, ctx: Context) {
|
pub fn run(ctx: Context) -> Self {
|
||||||
match self {
|
|
||||||
Scheduler::Stopped => {
|
|
||||||
let (mvbox, mvbox_handlers) = ImapConnectionState::new();
|
let (mvbox, mvbox_handlers) = ImapConnectionState::new();
|
||||||
let (sentbox, sentbox_handlers) = ImapConnectionState::new();
|
let (sentbox, sentbox_handlers) = ImapConnectionState::new();
|
||||||
let (smtp, smtp_handlers) = SmtpConnectionState::new();
|
let (smtp, smtp_handlers) = SmtpConnectionState::new();
|
||||||
let (inbox, inbox_handlers) = ImapConnectionState::new();
|
let (inbox, inbox_handlers) = ImapConnectionState::new();
|
||||||
|
|
||||||
let ctx1 = ctx.clone();
|
let ctx1 = ctx.clone();
|
||||||
let _ = task::spawn(async move { inbox_loop(ctx1, inbox_handlers).await });
|
task::spawn(async move { inbox_loop(ctx1, inbox_handlers).await });
|
||||||
|
|
||||||
// TODO: mvbox
|
// TODO: mvbox
|
||||||
// TODO: sentbox
|
// TODO: sentbox
|
||||||
|
|
||||||
let ctx1 = ctx.clone();
|
let ctx1 = ctx.clone();
|
||||||
let _ = task::spawn(async move { smtp_loop(ctx1, smtp_handlers).await });
|
task::spawn(async move { smtp_loop(ctx1, smtp_handlers).await });
|
||||||
|
|
||||||
*self = Scheduler::Running {
|
let res = Scheduler::Running {
|
||||||
inbox,
|
inbox,
|
||||||
mvbox,
|
mvbox,
|
||||||
sentbox,
|
sentbox,
|
||||||
smtp,
|
smtp,
|
||||||
|
probe_network: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
info!(ctx, "scheduler is running");
|
info!(ctx, "scheduler is running");
|
||||||
println!("RUN DONE");
|
println!("RUN DONE");
|
||||||
|
res
|
||||||
}
|
}
|
||||||
Scheduler::Running { .. } => {
|
|
||||||
// TODO: return an error
|
fn set_probe_network(&mut self, val: bool) {
|
||||||
panic!("WARN: already running");
|
match self {
|
||||||
|
Scheduler::Running {
|
||||||
|
ref mut probe_network,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
*probe_network = val;
|
||||||
|
}
|
||||||
|
_ => panic!("set_probe_network can only be called when running"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_probe_network(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Scheduler::Running { probe_network, .. } => *probe_network,
|
||||||
|
_ => panic!("get_probe_network can only be called when running"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn maybe_network(&mut self) {
|
||||||
|
if !self.is_running() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.set_probe_network(true);
|
||||||
|
self.interrupt_inbox()
|
||||||
|
.join(self.interrupt_mvbox())
|
||||||
|
.join(self.interrupt_sentbox())
|
||||||
|
.join(self.interrupt_smtp())
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn interrupt_inbox(&self) {
|
async fn interrupt_inbox(&self) {
|
||||||
@@ -206,6 +237,7 @@ impl Scheduler {
|
|||||||
mvbox,
|
mvbox,
|
||||||
sentbox,
|
sentbox,
|
||||||
smtp,
|
smtp,
|
||||||
|
..
|
||||||
} => {
|
} => {
|
||||||
inbox
|
inbox
|
||||||
.stop()
|
.stop()
|
||||||
@@ -213,6 +245,7 @@ impl Scheduler {
|
|||||||
.join(sentbox.stop())
|
.join(sentbox.stop())
|
||||||
.join(smtp.stop())
|
.join(smtp.stop())
|
||||||
.await;
|
.await;
|
||||||
|
*self = Scheduler::Stopped;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
src/sql.rs
12
src/sql.rs
@@ -87,12 +87,10 @@ impl Sql {
|
|||||||
self.pool.read().await.is_some()
|
self.pool.read().await.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn close(&self, context: &Context) {
|
pub async fn close(&self) {
|
||||||
let _ = self.pool.write().await.take();
|
let _ = self.pool.write().await.take();
|
||||||
self.in_use.remove();
|
self.in_use.remove();
|
||||||
// drop closes the connection
|
// drop closes the connection
|
||||||
|
|
||||||
info!(context, "Database closed.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return true on success, false on failure
|
// return true on success, false on failure
|
||||||
@@ -101,7 +99,7 @@ impl Sql {
|
|||||||
Ok(_) => true,
|
Ok(_) => true,
|
||||||
Err(crate::error::Error::SqlError(Error::SqlAlreadyOpen)) => false,
|
Err(crate::error::Error::SqlError(Error::SqlAlreadyOpen)) => false,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
self.close(context).await;
|
self.close().await;
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -374,10 +372,8 @@ impl Sql {
|
|||||||
pub async fn get_raw_config_bool(&self, context: &Context, key: impl AsRef<str>) -> bool {
|
pub async fn get_raw_config_bool(&self, context: &Context, key: impl AsRef<str>) -> bool {
|
||||||
// Not the most obvious way to encode bool as string, but it is matter
|
// Not the most obvious way to encode bool as string, but it is matter
|
||||||
// of backward compatibility.
|
// of backward compatibility.
|
||||||
self.get_raw_config_int(context, key)
|
let res = self.get_raw_config_int(context, key).await;
|
||||||
.await
|
res.unwrap_or_default() > 0
|
||||||
.unwrap_or_default()
|
|
||||||
> 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_raw_config_bool<T>(&self, context: &Context, key: T, value: bool) -> Result<()>
|
pub async fn set_raw_config_bool<T>(&self, context: &Context, key: T, value: bool) -> Result<()>
|
||||||
|
|||||||
Reference in New Issue
Block a user