diff --git a/src/chat.rs b/src/chat.rs index 1d787a1d0..f21ce144a 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -2669,10 +2669,12 @@ pub(crate) async fn get_chat_id_by_grpid( /// Adds a message to device chat. /// /// Optional `label` can be provided to ensure that message is added only once. -pub async fn add_device_msg( +/// If `important` is true, a notification will be sent. +pub async fn add_device_msg_with_importance( context: &Context, label: Option<&str>, msg: Option<&mut Message>, + important: bool, ) -> Result { ensure!( label.is_some() || msg.is_some(), @@ -2732,12 +2734,24 @@ pub async fn add_device_msg( } if !msg_id.is_unset() { - context.emit_event(Event::IncomingMsg { chat_id, msg_id }); + if important { + context.emit_event(Event::IncomingMsg { chat_id, msg_id }); + } else { + context.emit_event(Event::MsgsChanged { chat_id, msg_id }); + } } Ok(msg_id) } +pub async fn add_device_msg( + context: &Context, + label: Option<&str>, + msg: Option<&mut Message>, +) -> Result { + add_device_msg_with_importance(context, label, msg, false).await +} + pub async fn was_device_msg_ever_added(context: &Context, label: &str) -> Result { ensure!(!label.is_empty(), "empty label"); if let Ok(()) = context diff --git a/src/config.rs b/src/config.rs index 2c59d6435..ddb266e7b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -117,6 +117,11 @@ pub enum Config { #[strum(serialize = "sys.config_keys")] SysConfigKeys, + + #[strum(props(default = "0"))] + /// Whether we send a warning if the password is wrong (set to false when we send a warning + /// because we do not want to send a second warning) + NotifyAboutWrongPw, } impl Context { diff --git a/src/configure/mod.rs b/src/configure/mod.rs index 4894ee747..7afa6be98 100644 --- a/src/configure/mod.rs +++ b/src/configure/mod.rs @@ -70,6 +70,7 @@ impl Context { let mut param = LoginParam::from_database(self, "").await; let success = configure(self, &mut param).await; + self.set_config(Config::NotifyAboutWrongPw, None).await?; if let Some(provider) = provider::get_provider_info(¶m.addr) { if let Some(config_defaults) = &provider.config_defaults { @@ -100,11 +101,12 @@ impl Context { match success { Ok(_) => { + self.set_config(Config::NotifyAboutWrongPw, Some("1")) + .await?; progress!(self, 1000); Ok(()) } Err(err) => { - error!(self, "Configure Failed: {}", err); progress!(self, 0); Err(err) } @@ -457,7 +459,10 @@ async fn try_imap_connections( .await .is_ok() { - return Ok(()); // we directly return here if it was autoconfig or the connection succeeded + return Ok(()); + } + if was_autoconfig { + bail!("autoconfig did not succeed"); } progress!(context, 670); @@ -491,7 +496,7 @@ async fn try_imap_connection( return Ok(()); } if was_autoconfig { - return Ok(()); + bail!("autoconfig did not succeed"); } progress!(context, 650 + variation * 30); @@ -551,7 +556,7 @@ async fn try_smtp_connections( return Ok(()); } if was_autoconfig { - return Ok(()); + bail!("No SMTP connection"); } progress!(context, 850); diff --git a/src/context.rs b/src/context.rs index 016c27d4f..5458282bf 100644 --- a/src/context.rs +++ b/src/context.rs @@ -53,6 +53,8 @@ pub struct InnerContext { pub(crate) generating_key_mutex: Mutex<()>, /// Mutex to enforce only a single running oauth2 is running. pub(crate) oauth2_mutex: Mutex<()>, + /// Mutex to prevent a race condition when a "your pw is wrong" warning is sent, resulting in multiple messeges being sent. + pub(crate) wrong_pw_warning_mutex: Mutex<()>, pub(crate) translated_stockstrings: RwLock>, pub(crate) events: Events, @@ -120,6 +122,7 @@ impl Context { last_smeared_timestamp: RwLock::new(0), generating_key_mutex: Mutex::new(()), oauth2_mutex: Mutex::new(()), + wrong_pw_warning_mutex: Mutex::new(()), translated_stockstrings: RwLock::new(HashMap::new()), events: Events::default(), scheduler: RwLock::new(Scheduler::Stopped), diff --git a/src/imap/mod.rs b/src/imap/mod.rs index cd9779c4a..bb095d2e6 100644 --- a/src/imap/mod.rs +++ b/src/imap/mod.rs @@ -28,7 +28,7 @@ use crate::mimeparser; use crate::oauth2::dc_get_oauth2_access_token; use crate::param::Params; use crate::provider::get_provider_info; -use crate::{scheduler::InterruptInfo, stock::StockMessage}; +use crate::{chat, scheduler::InterruptInfo, stock::StockMessage}; mod client; mod idle; @@ -36,6 +36,7 @@ pub mod select_folder; mod session; use client::Client; +use message::Message; use session::Session; type Result = std::result::Result; @@ -116,6 +117,7 @@ pub struct Imap { connected: bool, interrupt: Option, should_reconnect: bool, + login_failed_once: bool, } #[derive(Debug)] @@ -189,6 +191,7 @@ impl Imap { connected: Default::default(), interrupt: Default::default(), should_reconnect: Default::default(), + login_failed_once: Default::default(), } } @@ -293,18 +296,40 @@ impl Imap { // needs to be set here to ensure it is set on reconnects. self.connected = true; self.session = Some(session); + self.login_failed_once = false; Ok(()) } + Err((err, _)) => { let imap_user = self.config.imap_user.to_owned(); let message = context .stock_string_repl_str(StockMessage::CannotLogin, &imap_user) .await; - emit_event!( - context, - Event::ErrorNetwork(format!("{} ({})", message, err)) - ); + warn!(context, "{} ({})", message, err); + emit_event!(context, Event::ErrorNetwork(message.clone())); + + let lock = context.wrong_pw_warning_mutex.lock().await; + if self.login_failed_once + && context.get_config_bool(Config::NotifyAboutWrongPw).await + { + if let Err(e) = context.set_config(Config::NotifyAboutWrongPw, None).await { + warn!(context, "{}", e); + } + drop(lock); + + let mut msg = Message::new(Viewtype::Text); + msg.text = Some(message); + if let Err(e) = + chat::add_device_msg_with_importance(context, None, Some(&mut msg), true) + .await + { + warn!(context, "{}", e); + } + } else { + self.login_failed_once = true; + } + self.trigger_reconnect(); Err(Error::LoginFailed(format!("cannot login as {}", imap_user))) } diff --git a/src/smtp/mod.rs b/src/smtp/mod.rs index 1296c796c..2e4ad6e57 100644 --- a/src/smtp/mod.rs +++ b/src/smtp/mod.rs @@ -183,7 +183,7 @@ impl Smtp { .stock_string_repl_str2( StockMessage::ServerResponse, format!("SMTP {}:{}", domain, port), - format!("{}, ({:?})", err.to_string(), err), + err.to_string(), ) .await; diff --git a/src/stock.rs b/src/stock.rs index 9754b1d3a..84ef72f09 100644 --- a/src/stock.rs +++ b/src/stock.rs @@ -130,7 +130,9 @@ pub enum StockMessage { ))] AcSetupMsgBody = 43, - #[strum(props(fallback = "Cannot login as %1$s."))] + #[strum(props( + fallback = "Cannot login as \"%1$s\". Please check if the email address and the password are correct." + ))] CannotLogin = 60, #[strum(props(fallback = "Could not connect to %1$s: %2$s"))]