melib: make MailBackend::is_online() return Result<()>
Return Result<()> instead of bool to indicate connection status in order to be able to show errors to user.memfd
parent
18a8d22b85
commit
2e38ea11e2
|
@ -245,7 +245,7 @@ pub enum FolderOperation {
|
||||||
type NewFolderName = String;
|
type NewFolderName = String;
|
||||||
|
|
||||||
pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
|
pub trait MailBackend: ::std::fmt::Debug + Send + Sync {
|
||||||
fn is_online(&self) -> bool;
|
fn is_online(&self) -> Result<()>;
|
||||||
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>>;
|
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>>;
|
||||||
fn watch(
|
fn watch(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -45,6 +45,7 @@ use std::collections::{hash_map::DefaultHasher, BTreeMap};
|
||||||
use std::hash::Hasher;
|
use std::hash::Hasher;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
|
use std::time::Instant;
|
||||||
pub type UID = usize;
|
pub type UID = usize;
|
||||||
|
|
||||||
pub static SUPPORTED_CAPABILITIES: &'static [&'static str] =
|
pub static SUPPORTED_CAPABILITIES: &'static [&'static str] =
|
||||||
|
@ -123,7 +124,7 @@ pub struct UIDStore {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ImapType {
|
pub struct ImapType {
|
||||||
account_name: String,
|
account_name: String,
|
||||||
online: Arc<Mutex<bool>>,
|
online: Arc<Mutex<(Instant, Result<()>)>>,
|
||||||
is_subscribed: Arc<IsSubscribedFn>,
|
is_subscribed: Arc<IsSubscribedFn>,
|
||||||
connection: Arc<Mutex<ImapConnection>>,
|
connection: Arc<Mutex<ImapConnection>>,
|
||||||
server_conf: ImapServerConf,
|
server_conf: ImapServerConf,
|
||||||
|
@ -135,8 +136,8 @@ pub struct ImapType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MailBackend for ImapType {
|
impl MailBackend for ImapType {
|
||||||
fn is_online(&self) -> bool {
|
fn is_online(&self) -> Result<()> {
|
||||||
*self.online.lock().unwrap()
|
self.online.lock().unwrap().1.clone()
|
||||||
}
|
}
|
||||||
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
||||||
macro_rules! exit_on_error {
|
macro_rules! exit_on_error {
|
||||||
|
@ -285,7 +286,7 @@ impl MailBackend for ImapType {
|
||||||
) -> Result<std::thread::ThreadId> {
|
) -> Result<std::thread::ThreadId> {
|
||||||
let folders = self.folders.clone();
|
let folders = self.folders.clone();
|
||||||
let tag_index = self.tag_index.clone();
|
let tag_index = self.tag_index.clone();
|
||||||
let conn = ImapConnection::new_connection(&self.server_conf);
|
let conn = ImapConnection::new_connection(&self.server_conf, self.online.clone());
|
||||||
let main_conn = self.connection.clone();
|
let main_conn = self.connection.clone();
|
||||||
let is_online = self.online.clone();
|
let is_online = self.online.clone();
|
||||||
let uid_store = self.uid_store.clone();
|
let uid_store = self.uid_store.clone();
|
||||||
|
@ -342,7 +343,6 @@ impl MailBackend for ImapType {
|
||||||
f.children.retain(|c| keys.contains(c));
|
f.children.retain(|c| keys.contains(c));
|
||||||
}
|
}
|
||||||
drop(uid_lock);
|
drop(uid_lock);
|
||||||
*self.online.lock().unwrap() = true;
|
|
||||||
Ok(folders
|
Ok(folders
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(h, f)| (*h, Box::new(Clone::clone(f)) as Folder))
|
.map(|(h, f)| (*h, Box::new(Clone::clone(f)) as Folder))
|
||||||
|
@ -510,11 +510,15 @@ impl ImapType {
|
||||||
use_starttls,
|
use_starttls,
|
||||||
danger_accept_invalid_certs,
|
danger_accept_invalid_certs,
|
||||||
};
|
};
|
||||||
let connection = ImapConnection::new_connection(&server_conf);
|
let online = Arc::new(Mutex::new((
|
||||||
|
Instant::now(),
|
||||||
|
Err(MeliError::new("Account is uninitialised.")),
|
||||||
|
)));
|
||||||
|
let connection = ImapConnection::new_connection(&server_conf, online.clone());
|
||||||
|
|
||||||
Ok(Box::new(ImapType {
|
Ok(Box::new(ImapType {
|
||||||
account_name: s.name().to_string(),
|
account_name: s.name().to_string(),
|
||||||
online: Arc::new(Mutex::new(false)),
|
online,
|
||||||
server_conf,
|
server_conf,
|
||||||
is_subscribed: Arc::new(IsSubscribedFn(is_subscribed)),
|
is_subscribed: Arc::new(IsSubscribedFn(is_subscribed)),
|
||||||
|
|
||||||
|
@ -532,7 +536,7 @@ impl ImapType {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn shell(&mut self) {
|
pub fn shell(&mut self) {
|
||||||
let mut conn = ImapConnection::new_connection(&self.server_conf);
|
let mut conn = ImapConnection::new_connection(&self.server_conf, self.online.clone());
|
||||||
let mut res = String::with_capacity(8 * 1024);
|
let mut res = String::with_capacity(8 * 1024);
|
||||||
conn.send_command(b"NOOP").unwrap();
|
conn.send_command(b"NOOP").unwrap();
|
||||||
conn.read_response(&mut res).unwrap();
|
conn.read_response(&mut res).unwrap();
|
||||||
|
|
|
@ -29,6 +29,8 @@ use fnv::FnvHashSet;
|
||||||
use native_tls::TlsConnector;
|
use native_tls::TlsConnector;
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
use super::protocol_parser;
|
use super::protocol_parser;
|
||||||
use super::{Capabilities, ImapServerConf};
|
use super::{Capabilities, ImapServerConf};
|
||||||
|
@ -44,6 +46,7 @@ pub struct ImapConnection {
|
||||||
pub stream: Result<ImapStream>,
|
pub stream: Result<ImapStream>,
|
||||||
pub server_conf: ImapServerConf,
|
pub server_conf: ImapServerConf,
|
||||||
pub capabilities: Capabilities,
|
pub capabilities: Capabilities,
|
||||||
|
pub online: Arc<Mutex<(Instant, Result<()>)>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for ImapStream {
|
impl Drop for ImapStream {
|
||||||
|
@ -317,11 +320,15 @@ impl ImapStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImapConnection {
|
impl ImapConnection {
|
||||||
pub fn new_connection(server_conf: &ImapServerConf) -> ImapConnection {
|
pub fn new_connection(
|
||||||
|
server_conf: &ImapServerConf,
|
||||||
|
online: Arc<Mutex<(Instant, Result<()>)>>,
|
||||||
|
) -> ImapConnection {
|
||||||
ImapConnection {
|
ImapConnection {
|
||||||
stream: Err(MeliError::new("Offline".to_string())),
|
stream: Err(MeliError::new("Offline".to_string())),
|
||||||
server_conf: server_conf.clone(),
|
server_conf: server_conf.clone(),
|
||||||
capabilities: Capabilities::default(),
|
capabilities: Capabilities::default(),
|
||||||
|
online,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -331,7 +338,16 @@ impl ImapConnection {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (capabilities, mut stream) = ImapStream::new_connection(&self.server_conf)?;
|
let new_stream = ImapStream::new_connection(&self.server_conf);
|
||||||
|
if new_stream.is_err() {
|
||||||
|
*self.online.lock().unwrap() = (
|
||||||
|
Instant::now(),
|
||||||
|
Err(new_stream.as_ref().unwrap_err().clone()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
*self.online.lock().unwrap() = (Instant::now(), Ok(()));
|
||||||
|
}
|
||||||
|
let (capabilities, mut stream) = new_stream?;
|
||||||
let ret = stream.read_response(ret);
|
let ret = stream.read_response(ret);
|
||||||
if ret.is_ok() {
|
if ret.is_ok() {
|
||||||
self.stream = Ok(stream);
|
self.stream = Ok(stream);
|
||||||
|
@ -346,7 +362,16 @@ impl ImapConnection {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (capabilities, mut stream) = ImapStream::new_connection(&self.server_conf)?;
|
let new_stream = ImapStream::new_connection(&self.server_conf);
|
||||||
|
if new_stream.is_err() {
|
||||||
|
*self.online.lock().unwrap() = (
|
||||||
|
Instant::now(),
|
||||||
|
Err(new_stream.as_ref().unwrap_err().clone()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
*self.online.lock().unwrap() = (Instant::now(), Ok(()));
|
||||||
|
}
|
||||||
|
let (capabilities, mut stream) = new_stream?;
|
||||||
let ret = stream.read_lines(ret, &termination_string);
|
let ret = stream.read_lines(ret, &termination_string);
|
||||||
if ret.is_ok() {
|
if ret.is_ok() {
|
||||||
self.stream = Ok(stream);
|
self.stream = Ok(stream);
|
||||||
|
@ -361,7 +386,16 @@ impl ImapConnection {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (capabilities, mut stream) = ImapStream::new_connection(&self.server_conf)?;
|
let new_stream = ImapStream::new_connection(&self.server_conf);
|
||||||
|
if new_stream.is_err() {
|
||||||
|
*self.online.lock().unwrap() = (
|
||||||
|
Instant::now(),
|
||||||
|
Err(new_stream.as_ref().unwrap_err().clone()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
*self.online.lock().unwrap() = (Instant::now(), Ok(()));
|
||||||
|
}
|
||||||
|
let (capabilities, mut stream) = new_stream?;
|
||||||
let ret = stream.wait_for_continuation_request();
|
let ret = stream.wait_for_continuation_request();
|
||||||
if ret.is_ok() {
|
if ret.is_ok() {
|
||||||
self.stream = Ok(stream);
|
self.stream = Ok(stream);
|
||||||
|
@ -376,7 +410,16 @@ impl ImapConnection {
|
||||||
return Ok(ret);
|
return Ok(ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (capabilities, mut stream) = ImapStream::new_connection(&self.server_conf)?;
|
let new_stream = ImapStream::new_connection(&self.server_conf);
|
||||||
|
if new_stream.is_err() {
|
||||||
|
*self.online.lock().unwrap() = (
|
||||||
|
Instant::now(),
|
||||||
|
Err(new_stream.as_ref().unwrap_err().clone()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
*self.online.lock().unwrap() = (Instant::now(), Ok(()));
|
||||||
|
}
|
||||||
|
let (capabilities, mut stream) = new_stream?;
|
||||||
let ret = stream.send_command(command);
|
let ret = stream.send_command(command);
|
||||||
if ret.is_ok() {
|
if ret.is_ok() {
|
||||||
self.stream = Ok(stream);
|
self.stream = Ok(stream);
|
||||||
|
@ -391,7 +434,16 @@ impl ImapConnection {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (capabilities, mut stream) = ImapStream::new_connection(&self.server_conf)?;
|
let new_stream = ImapStream::new_connection(&self.server_conf);
|
||||||
|
if new_stream.is_err() {
|
||||||
|
*self.online.lock().unwrap() = (
|
||||||
|
Instant::now(),
|
||||||
|
Err(new_stream.as_ref().unwrap_err().clone()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
*self.online.lock().unwrap() = (Instant::now(), Ok(()));
|
||||||
|
}
|
||||||
|
let (capabilities, mut stream) = new_stream?;
|
||||||
let ret = stream.send_literal(data);
|
let ret = stream.send_literal(data);
|
||||||
if ret.is_ok() {
|
if ret.is_ok() {
|
||||||
self.stream = Ok(stream);
|
self.stream = Ok(stream);
|
||||||
|
@ -406,8 +458,16 @@ impl ImapConnection {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (capabilities, mut stream) = ImapStream::new_connection(&self.server_conf)?;
|
let new_stream = ImapStream::new_connection(&self.server_conf);
|
||||||
|
if new_stream.is_err() {
|
||||||
|
*self.online.lock().unwrap() = (
|
||||||
|
Instant::now(),
|
||||||
|
Err(new_stream.as_ref().unwrap_err().clone()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
*self.online.lock().unwrap() = (Instant::now(), Ok(()));
|
||||||
|
}
|
||||||
|
let (capabilities, mut stream) = new_stream?;
|
||||||
let ret = stream.send_raw(raw);
|
let ret = stream.send_raw(raw);
|
||||||
if ret.is_ok() {
|
if ret.is_ok() {
|
||||||
self.stream = Ok(stream);
|
self.stream = Ok(stream);
|
||||||
|
@ -422,7 +482,16 @@ impl ImapConnection {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let (capabilities, mut stream) = ImapStream::new_connection(&self.server_conf)?;
|
let new_stream = ImapStream::new_connection(&self.server_conf);
|
||||||
|
if new_stream.is_err() {
|
||||||
|
*self.online.lock().unwrap() = (
|
||||||
|
Instant::now(),
|
||||||
|
Err(new_stream.as_ref().unwrap_err().clone()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
*self.online.lock().unwrap() = (Instant::now(), Ok(()));
|
||||||
|
}
|
||||||
|
let (capabilities, mut stream) = new_stream?;
|
||||||
let ret = stream.set_nonblocking(val);
|
let ret = stream.set_nonblocking(val);
|
||||||
if ret.is_ok() {
|
if ret.is_ok() {
|
||||||
self.stream = Ok(stream);
|
self.stream = Ok(stream);
|
||||||
|
|
|
@ -25,7 +25,7 @@ use std::sync::{Arc, Mutex, RwLock};
|
||||||
/// Arguments for IMAP watching functions
|
/// Arguments for IMAP watching functions
|
||||||
pub struct ImapWatchKit {
|
pub struct ImapWatchKit {
|
||||||
pub conn: ImapConnection,
|
pub conn: ImapConnection,
|
||||||
pub is_online: Arc<Mutex<bool>>,
|
pub is_online: Arc<Mutex<(Instant, Result<()>)>>,
|
||||||
pub main_conn: Arc<Mutex<ImapConnection>>,
|
pub main_conn: Arc<Mutex<ImapConnection>>,
|
||||||
pub uid_store: Arc<UIDStore>,
|
pub uid_store: Arc<UIDStore>,
|
||||||
pub folders: Arc<RwLock<FnvHashMap<FolderHash, ImapFolder>>>,
|
pub folders: Arc<RwLock<FnvHashMap<FolderHash, ImapFolder>>>,
|
||||||
|
@ -62,7 +62,7 @@ pub fn poll_with_examine(kit: ImapWatchKit) -> Result<()> {
|
||||||
tag_index,
|
tag_index,
|
||||||
} = kit;
|
} = kit;
|
||||||
loop {
|
loop {
|
||||||
if *is_online.lock().unwrap() {
|
if is_online.lock().unwrap().1.is_ok() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
@ -114,7 +114,7 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
|
||||||
tag_index,
|
tag_index,
|
||||||
} = kit;
|
} = kit;
|
||||||
loop {
|
loop {
|
||||||
if *is_online.lock().unwrap() {
|
if is_online.lock().unwrap().1.is_ok() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
|
|
@ -31,6 +31,7 @@ use reqwest::blocking::Client;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
use std::sync::{Arc, Mutex, RwLock};
|
||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! _impl {
|
macro_rules! _impl {
|
||||||
|
@ -182,7 +183,7 @@ pub struct Store {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct JmapType {
|
pub struct JmapType {
|
||||||
account_name: String,
|
account_name: String,
|
||||||
online: Arc<Mutex<bool>>,
|
online: Arc<Mutex<(Instant, Result<()>)>>,
|
||||||
is_subscribed: Arc<IsSubscribedFn>,
|
is_subscribed: Arc<IsSubscribedFn>,
|
||||||
server_conf: JmapServerConf,
|
server_conf: JmapServerConf,
|
||||||
connection: Arc<JmapConnection>,
|
connection: Arc<JmapConnection>,
|
||||||
|
@ -192,8 +193,8 @@ pub struct JmapType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MailBackend for JmapType {
|
impl MailBackend for JmapType {
|
||||||
fn is_online(&self) -> bool {
|
fn is_online(&self) -> Result<()> {
|
||||||
*self.online.lock().unwrap()
|
self.online.lock().unwrap().1.clone()
|
||||||
}
|
}
|
||||||
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
||||||
let mut w = AsyncBuilder::new();
|
let mut w = AsyncBuilder::new();
|
||||||
|
@ -277,7 +278,7 @@ impl JmapType {
|
||||||
s: &AccountSettings,
|
s: &AccountSettings,
|
||||||
is_subscribed: Box<dyn Fn(&str) -> bool + Send + Sync>,
|
is_subscribed: Box<dyn Fn(&str) -> bool + Send + Sync>,
|
||||||
) -> Result<Box<dyn MailBackend>> {
|
) -> Result<Box<dyn MailBackend>> {
|
||||||
let online = Arc::new(Mutex::new(false));
|
let online = Arc::new(Mutex::new(Err(MeliError::new("Account is uninitialised."))));
|
||||||
let server_conf = JmapServerConf::new(s)?;
|
let server_conf = JmapServerConf::new(s)?;
|
||||||
|
|
||||||
Ok(Box::new(JmapType {
|
Ok(Box::new(JmapType {
|
||||||
|
|
|
@ -26,16 +26,17 @@ pub struct JmapConnection {
|
||||||
pub session: JmapSession,
|
pub session: JmapSession,
|
||||||
pub request_no: Arc<Mutex<usize>>,
|
pub request_no: Arc<Mutex<usize>>,
|
||||||
pub client: Arc<Mutex<Client>>,
|
pub client: Arc<Mutex<Client>>,
|
||||||
pub online_status: Arc<Mutex<bool>>,
|
pub online_status: Arc<Mutex<(Instant, Result<()>)>>,
|
||||||
pub server_conf: JmapServerConf,
|
pub server_conf: JmapServerConf,
|
||||||
pub account_id: Arc<Mutex<String>>,
|
pub account_id: Arc<Mutex<String>>,
|
||||||
pub method_call_states: Arc<Mutex<FnvHashMap<&'static str, String>>>,
|
pub method_call_states: Arc<Mutex<FnvHashMap<&'static str, String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl JmapConnection {
|
impl JmapConnection {
|
||||||
pub fn new(server_conf: &JmapServerConf, online_status: Arc<Mutex<bool>>) -> Result<Self> {
|
pub fn new(server_conf: &JmapServerConf, online_status: Arc<Mutex<(Instant, Result<()>)>>) -> Result<Self> {
|
||||||
use reqwest::header;
|
use reqwest::header;
|
||||||
let mut headers = header::HeaderMap::new();
|
let mut headers = header::HeaderMap::new();
|
||||||
|
let connection_start = std::time::Instant::now();
|
||||||
headers.insert(
|
headers.insert(
|
||||||
header::ACCEPT,
|
header::ACCEPT,
|
||||||
header::HeaderValue::from_static("application/json"),
|
header::HeaderValue::from_static("application/json"),
|
||||||
|
@ -68,20 +69,29 @@ impl JmapConnection {
|
||||||
.send()?;
|
.send()?;
|
||||||
let res_text = req.text()?;
|
let res_text = req.text()?;
|
||||||
|
|
||||||
let session: JmapSession = serde_json::from_str(&res_text).map_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.)", &server_conf.server_hostname)))?;
|
let session: JmapSession = serde_json::from_str(&res_text).map_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.)", &server_conf.server_hostname);
|
||||||
|
*online_status.lock().unwrap() = (Instant::new(), Err(err.clone()));
|
||||||
|
err
|
||||||
|
))?;
|
||||||
if !session
|
if !session
|
||||||
.capabilities
|
.capabilities
|
||||||
.contains_key("urn:ietf:params:jmap:core")
|
.contains_key("urn:ietf:params:jmap:core")
|
||||||
{
|
{
|
||||||
return Err(MeliError::new(format!("Server {} did not return JMAP Core capability (urn:ietf:params:jmap:core). Returned capabilities were: {}", &server_conf.server_hostname, session.capabilities.keys().map(String::as_str).collect::<Vec<&str>>().join(", "))));
|
let err = Err(MeliError::new(format!("Server {} did not return JMAP Core capability (urn:ietf:params:jmap:core). Returned capabilities were: {}", &server_conf.server_hostname, session.capabilities.keys().map(String::as_str).collect::<Vec<&str>>().join(", "))));
|
||||||
|
*online_status.lock().unwrap() = (Instant::new(), Err(err.clone()));
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
if !session
|
if !session
|
||||||
.capabilities
|
.capabilities
|
||||||
.contains_key("urn:ietf:params:jmap:mail")
|
.contains_key("urn:ietf:params:jmap:mail")
|
||||||
{
|
{
|
||||||
return Err(MeliError::new(format!("Server {} does not support JMAP Mail capability (urn:ietf:params:jmap:mail). Returned capabilities were: {}", &server_conf.server_hostname, session.capabilities.keys().map(String::as_str).collect::<Vec<&str>>().join(", "))));
|
let err = Err(MeliError::new(format!("Server {} does not support JMAP Mail capability (urn:ietf:params:jmap:mail). Returned capabilities were: {}", &server_conf.server_hostname, session.capabilities.keys().map(String::as_str).collect::<Vec<&str>>().join(", "))));
|
||||||
|
*online_status.lock().unwrap() = (Instant::new(), Err(err.clone()));
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*online_status.lock().unwrap() = (Instant::new(), Ok(()));
|
||||||
let server_conf = server_conf.clone();
|
let server_conf = server_conf.clone();
|
||||||
Ok(JmapConnection {
|
Ok(JmapConnection {
|
||||||
session,
|
session,
|
||||||
|
|
|
@ -184,8 +184,8 @@ fn move_to_cur(p: PathBuf) -> Result<PathBuf> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MailBackend for MaildirType {
|
impl MailBackend for MaildirType {
|
||||||
fn is_online(&self) -> bool {
|
fn is_online(&self) -> Result<()> {
|
||||||
true
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn folders(&self) -> Result<FnvHashMap<FolderHash, Folder>> {
|
fn folders(&self) -> Result<FnvHashMap<FolderHash, Folder>> {
|
||||||
|
|
|
@ -370,8 +370,8 @@ pub struct MboxType {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MailBackend for MboxType {
|
impl MailBackend for MboxType {
|
||||||
fn is_online(&self) -> bool {
|
fn is_online(&self) -> Result<()> {
|
||||||
true
|
Ok(())
|
||||||
}
|
}
|
||||||
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
||||||
let mut w = AsyncBuilder::new();
|
let mut w = AsyncBuilder::new();
|
||||||
|
|
|
@ -242,8 +242,8 @@ impl NotmuchDb {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MailBackend for NotmuchDb {
|
impl MailBackend for NotmuchDb {
|
||||||
fn is_online(&self) -> bool {
|
fn is_online(&self) -> Result<()> {
|
||||||
true
|
Ok(())
|
||||||
}
|
}
|
||||||
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
fn get(&mut self, folder: &Folder) -> Async<Result<Vec<Envelope>>> {
|
||||||
let mut w = AsyncBuilder::new();
|
let mut w = AsyncBuilder::new();
|
||||||
|
|
|
@ -295,29 +295,10 @@ impl Component for Listing {
|
||||||
}
|
}
|
||||||
|
|
||||||
if right_component_width == total_cols {
|
if right_component_width == total_cols {
|
||||||
if !context.is_online(self.cursor_pos.0) {
|
if let Err(err) = context.is_online(self.cursor_pos.0) {
|
||||||
clear_area(grid, area);
|
clear_area(grid, area);
|
||||||
write_string_to_grid(
|
let (x, _) = write_string_to_grid(
|
||||||
"offline",
|
"offline: ",
|
||||||
grid,
|
|
||||||
Color::Byte(243),
|
|
||||||
Color::Default,
|
|
||||||
Attr::Default,
|
|
||||||
area,
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
context.dirty_areas.push_back(area);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.component.draw(grid, area, context);
|
|
||||||
} else if right_component_width == 0 {
|
|
||||||
self.draw_menu(grid, area, context);
|
|
||||||
} else {
|
|
||||||
self.draw_menu(grid, (upper_left, (mid, get_y(bottom_right))), context);
|
|
||||||
if !context.is_online(self.cursor_pos.0) {
|
|
||||||
clear_area(grid, (set_x(upper_left, mid + 1), bottom_right));
|
|
||||||
write_string_to_grid(
|
|
||||||
"offline",
|
|
||||||
grid,
|
grid,
|
||||||
Color::Byte(243),
|
Color::Byte(243),
|
||||||
Color::Default,
|
Color::Default,
|
||||||
|
@ -325,12 +306,50 @@ impl Component for Listing {
|
||||||
(set_x(upper_left, mid + 1), bottom_right),
|
(set_x(upper_left, mid + 1), bottom_right),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
write_string_to_grid(
|
||||||
|
&err.to_string(),
|
||||||
|
grid,
|
||||||
|
Color::Red,
|
||||||
|
Color::Default,
|
||||||
|
Attr::Default,
|
||||||
|
(set_x(upper_left, x + 1), bottom_right),
|
||||||
|
None,
|
||||||
|
);
|
||||||
context.dirty_areas.push_back(area);
|
context.dirty_areas.push_back(area);
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
self.component.draw(grid, area, context);
|
||||||
}
|
}
|
||||||
|
} else if right_component_width == 0 {
|
||||||
|
self.draw_menu(grid, area, context);
|
||||||
|
} else {
|
||||||
|
self.draw_menu(grid, (upper_left, (mid, get_y(bottom_right))), context);
|
||||||
|
if let Err(err) = context.is_online(self.cursor_pos.0) {
|
||||||
|
clear_area(grid, (set_x(upper_left, mid + 1), bottom_right));
|
||||||
|
let (x, _) = write_string_to_grid(
|
||||||
|
"offline: ",
|
||||||
|
grid,
|
||||||
|
Color::Byte(243),
|
||||||
|
Color::Default,
|
||||||
|
Attr::Default,
|
||||||
|
(set_x(upper_left, mid + 1), bottom_right),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
write_string_to_grid(
|
||||||
|
&err.to_string(),
|
||||||
|
grid,
|
||||||
|
Color::Red,
|
||||||
|
Color::Default,
|
||||||
|
Attr::Default,
|
||||||
|
(set_x(upper_left, x + 1), bottom_right),
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
context.dirty_areas.push_back(area);
|
||||||
|
} else {
|
||||||
self.component
|
self.component
|
||||||
.draw(grid, (set_x(upper_left, mid + 1), bottom_right), context);
|
.draw(grid, (set_x(upper_left, mid + 1), bottom_right), context);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
}
|
}
|
||||||
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
fn process_event(&mut self, event: &mut UIEvent, context: &mut Context) -> bool {
|
||||||
|
|
|
@ -991,12 +991,12 @@ impl Account {
|
||||||
|
|
||||||
/* Call only in Context::is_online, since only Context can launch the watcher threads if an
|
/* Call only in Context::is_online, since only Context can launch the watcher threads if an
|
||||||
* account goes from offline to online. */
|
* account goes from offline to online. */
|
||||||
pub fn is_online(&mut self) -> bool {
|
pub fn is_online(&mut self) -> Result<()> {
|
||||||
let ret = self.backend.read().unwrap().is_online();
|
let ret = self.backend.read().unwrap().is_online();
|
||||||
if ret != self.is_online && ret {
|
if ret.is_ok() != self.is_online && ret.is_ok() {
|
||||||
self.init();
|
self.init();
|
||||||
}
|
}
|
||||||
self.is_online = ret;
|
self.is_online = ret.is_ok();
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -135,14 +135,15 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_online(&mut self, account_pos: usize) -> bool {
|
pub fn is_online(&mut self, account_pos: usize) -> Result<()> {
|
||||||
let Context {
|
let Context {
|
||||||
ref mut accounts,
|
ref mut accounts,
|
||||||
ref mut mailbox_hashes,
|
ref mut mailbox_hashes,
|
||||||
..
|
..
|
||||||
} = self;
|
} = self;
|
||||||
let was_online = accounts[account_pos].is_online;
|
let was_online = accounts[account_pos].is_online;
|
||||||
if accounts[account_pos].is_online() {
|
let ret = accounts[account_pos].is_online();
|
||||||
|
if ret.is_ok() {
|
||||||
if !was_online {
|
if !was_online {
|
||||||
for folder in accounts[account_pos].list_folders() {
|
for folder in accounts[account_pos].list_folders() {
|
||||||
debug!("hash & folder: {:?} {}", folder.hash(), folder.name());
|
debug!("hash & folder: {:?} {}", folder.hash(), folder.name());
|
||||||
|
@ -157,10 +158,8 @@ impl Context {
|
||||||
*/
|
*/
|
||||||
accounts[account_pos].watch();
|
accounts[account_pos].watch();
|
||||||
}
|
}
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
|
ret
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn work_controller(&self) -> &WorkController {
|
pub fn work_controller(&self) -> &WorkController {
|
||||||
|
@ -291,7 +290,7 @@ impl State {
|
||||||
s.switch_to_alternate_screen();
|
s.switch_to_alternate_screen();
|
||||||
debug!("inserting mailbox hashes:");
|
debug!("inserting mailbox hashes:");
|
||||||
for i in 0..s.context.accounts.len() {
|
for i in 0..s.context.accounts.len() {
|
||||||
if s.context.is_online(i) && s.context.accounts[i].is_empty() {
|
if s.context.is_online(i).is_ok() && s.context.accounts[i].is_empty() {
|
||||||
return Err(MeliError::new(format!(
|
return Err(MeliError::new(format!(
|
||||||
"Account {} has no folders configured.",
|
"Account {} has no folders configured.",
|
||||||
s.context.accounts[i].name()
|
s.context.accounts[i].name()
|
||||||
|
@ -722,7 +721,7 @@ impl State {
|
||||||
pub fn check_accounts(&mut self) {
|
pub fn check_accounts(&mut self) {
|
||||||
let mut ctr = 0;
|
let mut ctr = 0;
|
||||||
for i in 0..self.context.accounts.len() {
|
for i in 0..self.context.accounts.len() {
|
||||||
if self.context.is_online(i) {
|
if self.context.is_online(i).is_ok() {
|
||||||
ctr += 1;
|
ctr += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue