melib: add protocol extension info in MailBackendCapabilities

memfd
Manos Pitsidianakis 2020-08-01 12:36:47 +03:00
parent 2b3949ddb2
commit ec0153e7b2
Signed by: Manos Pitsidianakis
GPG Key ID: 73627C2F690DF710
12 changed files with 223 additions and 71 deletions

View File

@ -293,14 +293,22 @@ impl NotifyFn {
} }
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Clone)]
pub struct MailBackendCapabilities { pub struct MailBackendCapabilities {
pub is_async: bool, pub is_async: bool,
pub is_remote: bool, pub is_remote: bool,
pub extensions: Option<Vec<(String, MailBackendExtensionStatus)>>,
pub supports_search: bool, pub supports_search: bool,
pub supports_tags: bool, pub supports_tags: bool,
} }
#[derive(Debug, Copy, Clone)]
pub enum MailBackendExtensionStatus {
Unsupported { comment: Option<&'static str> },
Supported { comment: Option<&'static str> },
Enabled { comment: Option<&'static str> },
}
pub type ResultFuture<T> = Result<Pin<Box<dyn Future<Output = Result<T>> + Send + 'static>>>; pub type ResultFuture<T> = Result<Pin<Box<dyn Future<Output = Result<T>> + Send + 'static>>>;
pub trait MailBackend: ::std::fmt::Debug + Send + Sync { pub trait MailBackend: ::std::fmt::Debug + Send + Sync {

View File

@ -191,13 +191,70 @@ pub struct ImapType {
impl MailBackend for ImapType { impl MailBackend for ImapType {
fn capabilities(&self) -> MailBackendCapabilities { fn capabilities(&self) -> MailBackendCapabilities {
const CAPABILITIES: MailBackendCapabilities = MailBackendCapabilities { let mut extensions = self
.uid_store
.capabilities
.lock()
.unwrap()
.iter()
.map(|c| {
(
String::from_utf8_lossy(c).into(),
MailBackendExtensionStatus::Unsupported { comment: None },
)
})
.collect::<Vec<(String, MailBackendExtensionStatus)>>();
if let ImapProtocol::IMAP {
extension_use:
ImapExtensionUse {
idle,
#[cfg(feature = "deflate_compression")]
deflate,
},
} = self.server_conf.protocol
{
for (name, status) in extensions.iter_mut() {
match name.as_str() {
"IDLE" => {
if idle {
*status = MailBackendExtensionStatus::Enabled { comment: None };
} else {
*status = MailBackendExtensionStatus::Supported {
comment: Some("Disabled by user configuration"),
};
}
}
"COMPRESS=DEFLATE" => {
if cfg!(feature = "deflate_compression") {
if deflate {
*status = MailBackendExtensionStatus::Enabled { comment: None };
} else {
*status = MailBackendExtensionStatus::Supported {
comment: Some("Disabled by user configuration"),
};
}
} else {
*status = MailBackendExtensionStatus::Unsupported {
comment: Some("melib not compiled with DEFLATE."),
};
}
}
_ => {
if SUPPORTED_CAPABILITIES.contains(&name.as_str()) {
*status = MailBackendExtensionStatus::Enabled { comment: None };
}
}
}
}
}
extensions.sort_by(|a, b| a.0.cmp(&b.0));
MailBackendCapabilities {
is_async: true, is_async: true,
is_remote: true, is_remote: true,
supports_search: true, supports_search: true,
extensions: Some(extensions),
supports_tags: true, supports_tags: true,
}; }
CAPABILITIES
} }
fn fetch_async( fn fetch_async(

View File

@ -56,7 +56,7 @@ impl Default for ImapExtensionUse {
Self { Self {
idle: true, idle: true,
#[cfg(feature = "deflate_compression")] #[cfg(feature = "deflate_compression")]
deflate: false, deflate: true,
} }
} }
} }

View File

@ -195,6 +195,7 @@ impl MailBackend for JmapType {
is_async: false, is_async: false,
is_remote: true, is_remote: true,
supports_search: true, supports_search: true,
extensions: None,
supports_tags: true, supports_tags: true,
}; };
CAPABILITIES CAPABILITIES

View File

@ -180,6 +180,7 @@ impl MailBackend for MaildirType {
is_async: false, is_async: false,
is_remote: false, is_remote: false,
supports_search: false, supports_search: false,
extensions: None,
supports_tags: false, supports_tags: false,
}; };
CAPABILITIES CAPABILITIES

View File

@ -699,6 +699,7 @@ impl MailBackend for MboxType {
is_async: false, is_async: false,
is_remote: false, is_remote: false,
supports_search: false, supports_search: false,
extensions: None,
supports_tags: false, supports_tags: false,
}; };
CAPABILITIES CAPABILITIES

View File

@ -81,7 +81,7 @@ impl std::ops::Deref for IsSubscribedFn {
&self.0 &self.0
} }
} }
type Capabilities = HashSet<Vec<u8>>; type Capabilities = HashSet<String>;
#[derive(Debug)] #[derive(Debug)]
pub struct UIDStore { pub struct UIDStore {
@ -129,13 +129,57 @@ pub struct NntpType {
impl MailBackend for NntpType { impl MailBackend for NntpType {
fn capabilities(&self) -> MailBackendCapabilities { fn capabilities(&self) -> MailBackendCapabilities {
const CAPABILITIES: MailBackendCapabilities = MailBackendCapabilities { let mut extensions = self
.uid_store
.capabilities
.lock()
.unwrap()
.iter()
.map(|c| {
(
c.to_string(),
MailBackendExtensionStatus::Unsupported { comment: None },
)
})
.collect::<Vec<(String, MailBackendExtensionStatus)>>();
let NntpExtensionUse {
#[cfg(feature = "deflate_compression")]
deflate,
} = self.server_conf.extension_use;
{
for (name, status) in extensions.iter_mut() {
match name.as_str() {
"COMPRESS DEFLATE" => {
if cfg!(feature = "deflate_compression") {
if deflate {
*status = MailBackendExtensionStatus::Enabled { comment: None };
} else {
*status = MailBackendExtensionStatus::Supported {
comment: Some("Disabled by user configuration"),
};
}
} else {
*status = MailBackendExtensionStatus::Unsupported {
comment: Some("melib not compiled with DEFLATE."),
};
}
}
_ => {
if SUPPORTED_CAPABILITIES.contains(&name.as_str()) {
*status = MailBackendExtensionStatus::Enabled { comment: None };
}
}
}
}
}
extensions.sort_by(|a, b| a.0.cmp(&b.0));
MailBackendCapabilities {
is_async: true, is_async: true,
is_remote: true, is_remote: true,
supports_search: false, supports_search: false,
extensions: Some(extensions),
supports_tags: false, supports_tags: false,
}; }
CAPABILITIES
} }
fn fetch_async( fn fetch_async(
@ -372,7 +416,10 @@ impl NntpType {
use_tls, use_tls,
use_starttls, use_starttls,
danger_accept_invalid_certs, danger_accept_invalid_certs,
extension_use: NntpExtensionUse::default(), extension_use: NntpExtensionUse {
#[cfg(feature = "deflate_compression")]
deflate: get_conf_val!(s["use_deflate"], true)?,
},
}; };
let account_hash = { let account_hash = {
let mut hasher = DefaultHasher::new(); let mut hasher = DefaultHasher::new();
@ -488,7 +535,7 @@ impl NntpType {
.lock() .lock()
.unwrap() .unwrap()
.iter() .iter()
.map(|c| String::from_utf8_lossy(c).into()) .map(|c| c.clone())
.collect::<Vec<String>>() .collect::<Vec<String>>()
} }
} }

View File

@ -99,7 +99,7 @@ impl NntpStream {
let mut res = String::with_capacity(8 * 1024); let mut res = String::with_capacity(8 * 1024);
let mut ret = NntpStream { let mut ret = NntpStream {
stream, stream,
extension_use: NntpExtensionUse::default(), extension_use: server_conf.extension_use,
current_mailbox: MailboxSelection::None, current_mailbox: MailboxSelection::None,
}; };
@ -196,11 +196,10 @@ impl NntpStream {
&server_conf.server_hostname, res &server_conf.server_hostname, res
))); )));
} }
let capabilities: HashSet<Vec<u8>> = let capabilities: HashSet<String> = res.lines().skip(1).map(|l| l.to_string()).collect();
res.lines().skip(1).map(|l| l.as_bytes().to_vec()).collect();
#[cfg(feature = "deflate_compression")] #[cfg(feature = "deflate_compression")]
#[cfg(feature = "deflate_compression")] #[cfg(feature = "deflate_compression")]
if capabilities.contains(&b"COMPRESS DEFLATE"[..]) && ret.extension_use.deflate { if capabilities.contains("COMPRESS DEFLATE") && ret.extension_use.deflate {
ret.send_command(b"COMPRESS DEFLATE").await?; ret.send_command(b"COMPRESS DEFLATE").await?;
ret.read_response(&mut res, false).await?; ret.read_response(&mut res, false).await?;
if !res.starts_with("206 ") { if !res.starts_with("206 ") {

View File

@ -323,6 +323,7 @@ impl MailBackend for NotmuchDb {
is_async: false, is_async: false,
is_remote: false, is_remote: false,
supports_search: true, supports_search: true,
extensions: None,
supports_tags: true, supports_tags: true,
}; };
CAPABILITIES CAPABILITIES

View File

@ -414,7 +414,6 @@ impl Component for AccountStatus {
self.dirty = false; self.dirty = false;
let (width, height) = self.content.size(); let (width, height) = self.content.size();
let a = &context.accounts[self.account_pos]; let a = &context.accounts[self.account_pos];
let backend_lck = a.backend.read().unwrap();
let (_x, _y) = write_string_to_grid( let (_x, _y) = write_string_to_grid(
"(Press Esc to return)", "(Press Esc to return)",
&mut self.content, &mut self.content,
@ -450,7 +449,7 @@ impl Component for AccountStatus {
); );
line += 1; line += 1;
let (_x, _y) = write_string_to_grid( let (_x, _y) = write_string_to_grid(
"Cache backend: ", "Search backend: ",
&mut self.content, &mut self.content,
self.theme_default.fg, self.theme_default.fg,
self.theme_default.bg, self.theme_default.bg,
@ -537,72 +536,108 @@ impl Component for AccountStatus {
} }
line += 1; line += 1;
if a.settings.account().format() == "imap" { if let Some(ref extensions) = a.backend_capabilities.extensions {
let b = (*backend_lck).as_any(); write_string_to_grid(
if let Some(imap_backend) = b.downcast_ref::<melib::backends::ImapType>() { "Server Extensions:",
&mut self.content,
self.theme_default.fg,
self.theme_default.bg,
Attr::BOLD,
((1, line), (width - 1, height - 1)),
None,
);
let max_name_width = std::cmp::max(
"Server Extensions:".len(),
extensions.iter().map(|(n, _)| n.len()).max().unwrap_or(0),
);
write_string_to_grid(
"meli support:",
&mut self.content,
self.theme_default.fg,
self.theme_default.bg,
self.theme_default.attrs,
((max_name_width + 6, line), (width - 1, height - 1)),
None,
);
line += 1;
for (i, (name, status)) in extensions.into_iter().enumerate() {
let (width, height) = self.content.size();
write_string_to_grid( write_string_to_grid(
"Server Capabilities:", &name,
&mut self.content,
self.theme_default.fg,
self.theme_default.bg,
Attr::BOLD,
((1, line), (width - 1, height - 1)),
None,
);
let mut capabilities = imap_backend.capabilities();
let max_name_width = std::cmp::max(
"Server Capabilities:".len(),
capabilities.iter().map(String::len).max().unwrap_or(0),
);
write_string_to_grid(
"meli support:",
&mut self.content, &mut self.content,
self.theme_default.fg, self.theme_default.fg,
self.theme_default.bg, self.theme_default.bg,
self.theme_default.attrs, self.theme_default.attrs,
((max_name_width + 6, line), (width - 1, height - 1)), ((1, line + i), (width - 1, height - 1)),
None, None,
); );
capabilities.sort();
line += 1; use melib::backends::MailBackendExtensionStatus;
for (i, cap) in capabilities.into_iter().enumerate() { let (width, height) = self.content.size();
let (width, height) = self.content.size(); let (x, y) = match status {
write_string_to_grid( MailBackendExtensionStatus::Unsupported { comment: _ } => write_string_to_grid(
&cap, "not supported",
&mut self.content, &mut self.content,
self.theme_default.fg, Color::Red,
self.theme_default.bg, self.theme_default.bg,
self.theme_default.attrs, self.theme_default.attrs,
((1, line + i), (width - 1, height - 1)), ((max_name_width + 6, line + i), (width - 1, height - 1)),
None, None,
); ),
MailBackendExtensionStatus::Supported { comment: _ } => write_string_to_grid(
let (width, height) = self.content.size(); "supported",
if melib::backends::imap::SUPPORTED_CAPABILITIES &mut self.content,
.iter() Color::Green,
.any(|c| cap.eq_ignore_ascii_case(c)) self.theme_default.bg,
{ self.theme_default.attrs,
write_string_to_grid( ((max_name_width + 6, line + i), (width - 1, height - 1)),
"supported", None,
&mut self.content, ),
Color::Green, MailBackendExtensionStatus::Enabled { comment: _ } => write_string_to_grid(
self.theme_default.bg, "enabled",
self.theme_default.attrs, &mut self.content,
((max_name_width + 6, line + i), (width - 1, height - 1)), Color::Green,
None, self.theme_default.bg,
); self.theme_default.attrs,
} else { ((max_name_width + 6, line + i), (width - 1, height - 1)),
write_string_to_grid( None,
"not supported", ),
&mut self.content, };
Color::Red, match status {
self.theme_default.bg, MailBackendExtensionStatus::Unsupported { comment }
self.theme_default.attrs, | MailBackendExtensionStatus::Supported { comment }
((max_name_width + 6, line + i), (width - 1, height - 1)), | MailBackendExtensionStatus::Enabled { comment } => {
None, if let Some(s) = comment {
); let (x, y) = write_string_to_grid(
" (",
&mut self.content,
self.theme_default.fg,
self.theme_default.bg,
self.theme_default.attrs,
((x, y), (width - 1, height - 1)),
None,
);
let (x, y) = write_string_to_grid(
s,
&mut self.content,
self.theme_default.fg,
self.theme_default.bg,
self.theme_default.attrs,
((x, y), (width - 1, height - 1)),
None,
);
write_string_to_grid(
")",
&mut self.content,
self.theme_default.fg,
self.theme_default.bg,
self.theme_default.attrs,
((x, y), (width - 1, height - 1)),
None,
);
}
} }
} };
} }
} }

View File

@ -445,6 +445,7 @@ impl Account {
} else { } else {
self.backend.read().unwrap().mailboxes()? self.backend.read().unwrap().mailboxes()?
}; };
self.backend_capabilities = self.backend.read().unwrap().capabilities();
let mut mailbox_entries: HashMap<MailboxHash, MailboxEntry> = let mut mailbox_entries: HashMap<MailboxHash, MailboxEntry> =
HashMap::with_capacity_and_hasher(ref_mailboxes.len(), Default::default()); HashMap::with_capacity_and_hasher(ref_mailboxes.len(), Default::default());
let mut mailboxes_order: Vec<MailboxHash> = Vec::with_capacity(ref_mailboxes.len()); let mut mailboxes_order: Vec<MailboxHash> = Vec::with_capacity(ref_mailboxes.len());

View File

@ -70,6 +70,7 @@ impl MailBackend for PluginBackend {
is_async: false, is_async: false,
is_remote: false, is_remote: false,
supports_search: false, supports_search: false,
extensions: None,
supports_tags: false, supports_tags: false,
}; };
CAPABILITIES CAPABILITIES