diff --git a/melib/src/backends.rs b/melib/src/backends.rs index ff7104f17..132002e09 100644 --- a/melib/src/backends.rs +++ b/melib/src/backends.rs @@ -105,6 +105,12 @@ impl Default for Backends { } } +#[cfg(feature = "jmap_backend")] +pub const JMAP_ERROR_MSG: &str = ""; + +#[cfg(not(feature = "jmap_backend"))] +pub const JMAP_ERROR_MSG: &str = "This library build lacks JMAP support. JMAP requires an HTTP client dependency and thus is turned off by default when compiling."; + #[cfg(feature = "notmuch_backend")] pub const NOTMUCH_ERROR_MSG: &str = "libnotmuch5 was not found in your system. Make sure it is installed and in the library paths. For a custom file path, use `library_file_path` setting in your notmuch account.\n"; @@ -219,6 +225,11 @@ impl Backends { { eprint!("{}", NOTMUCH_ERROR_DETAILS); } + } else if key == "jmap" { + #[cfg(not(feature = "jmap_backend"))] + { + eprintln!("{}", JMAP_ERROR_MSG); + } } panic!("{} is not a valid mail backend", key); } @@ -247,6 +258,8 @@ impl Backends { key, if cfg!(feature = "notmuch_backend") && key == "notmuch" { NOTMUCH_ERROR_DETAILS + } else if !cfg!(feature = "jmap_backend") && key == "jmap" { + JMAP_ERROR_MSG } else { "" }, diff --git a/melib/src/backends/jmap/connection.rs b/melib/src/backends/jmap/connection.rs index 1cff3a957..906002da7 100644 --- a/melib/src/backends/jmap/connection.rs +++ b/melib/src/backends/jmap/connection.rs @@ -20,6 +20,7 @@ */ use super::*; +use crate::error::IntoMeliError; use isahc::config::Configurable; use std::sync::MutexGuard; @@ -34,6 +35,12 @@ pub struct JmapConnection { impl JmapConnection { pub fn new(server_conf: &JmapServerConf, store: Arc) -> Result { + (store.event_consumer)( + store.account_hash, + crate::backends::BackendEvent::AccountStateChange { + message: "Creating connection.".into(), + }, + ); let client = HttpClient::builder() .timeout(std::time::Duration::from_secs(10)) .redirect_policy(RedirectPolicy::Limit(10)) @@ -53,6 +60,15 @@ impl JmapConnection { }) } + #[inline(always)] + pub(crate) fn account_state_change(&self, message: impl Into>) { + let message = message.into(); + (self.store.event_consumer)( + self.store.account_hash, + crate::backends::BackendEvent::AccountStateChange { message }, + ); + } + pub async fn connect(&mut self) -> Result<()> { if self.store.online_status.lock().await.1.is_ok() { return Ok(()); @@ -63,12 +79,16 @@ impl JmapConnection { jmap_session_resource_url.push_str(&self.server_conf.server_port.to_string()); } jmap_session_resource_url.push_str("/.well-known/jmap"); + self.account_state_change(format!("Requesting {}…", &jmap_session_resource_url)); - let mut req = self.client.get_async(&jmap_session_resource_url).await.map_err(|err| { - let err = MeliError::new(format!("Could not connect to JMAP server endpoint for {}. Is your server hostname setting correct? (i.e. \"jmap.mailserver.org\") (Note: only session resource discovery via /.well-known/jmap is supported. DNS SRV records are not suppported.)\nError connecting to server: {}", &self.server_conf.server_hostname, &err)).set_source(Some(Arc::new(err))); - //*self.store.online_status.lock().await = (Instant::now(), Err(err.clone())); - err - })?; + let mut req = match self.client.get_async(&jmap_session_resource_url).await { + Err(err) => { + let err = err.set_err_summary(format!("Could not connect to JMAP server endpoint for {}. Is your server hostname setting correct? (i.e. \"jmap.mailserver.org\") (Note: only session resource discovery via /.well-known/jmap is supported. DNS SRV records are not suppported.)\nError connecting to server.", &self.server_conf.server_hostname)); + *self.store.online_status.lock().await = (Instant::now(), Err(err.clone())); + return Err(err); + } + Ok(r) => r, + }; if !req.status().is_success() { let kind: crate::error::NetworkErrorKind = req.status().into(); @@ -86,7 +106,7 @@ impl JmapConnection { let session: JmapSession = match serde_json::from_str(&res_text) { Err(err) => { - let err = MeliError::new(format!("Could not connect to JMAP server endpoint for {}. Is your server hostname setting correct? (i.e. \"jmap.mailserver.org\") (Note: only session resource discovery via /.well-known/jmap is supported. DNS SRV records are not suppported.)\nReply from server: {}", &self.server_conf.server_hostname, &res_text)).set_source(Some(Arc::new(err))); + let err = err.set_err_summary(format!("Could not connect to JMAP server endpoint for {}. Is your server hostname setting correct? (i.e. \"jmap.mailserver.org\") (Note: only session resource discovery via /.well-known/jmap is supported. DNS SRV records are not suppported.)\nReply from server: {}", &self.server_conf.server_hostname, &res_text)); *self.store.online_status.lock().await = (Instant::now(), Err(err.clone())); return Err(err); } diff --git a/melib/src/backends/jmap/protocol.rs b/melib/src/backends/jmap/protocol.rs index a8bd2ff4d..54a91f273 100644 --- a/melib/src/backends/jmap/protocol.rs +++ b/melib/src/backends/jmap/protocol.rs @@ -85,6 +85,7 @@ pub struct JsonResponse<'a> { } pub async fn get_mailboxes(conn: &JmapConnection) -> Result> { + conn.account_state_change("Fetching mailbox list…"); let seq = get_request_no!(conn.request_no); let api_url = conn.session.lock().unwrap().api_url.clone(); let mut res = conn @@ -180,6 +181,7 @@ pub async fn get_message_list( conn: &JmapConnection, mailbox: &JmapMailbox, ) -> Result>> { + conn.account_state_change(format!("Fetching email list for {}…", mailbox.name())); let email_call: EmailQuery = EmailQuery::new( Query::new() .account_id(conn.mail_account_id().clone())