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 is_async: bool,
pub is_remote: bool,
pub extensions: Option<Vec<(String, MailBackendExtensionStatus)>>,
pub supports_search: 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 trait MailBackend: ::std::fmt::Debug + Send + Sync {

View File

@ -191,13 +191,70 @@ pub struct ImapType {
impl MailBackend for ImapType {
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_remote: true,
supports_search: true,
extensions: Some(extensions),
supports_tags: true,
};
CAPABILITIES
}
}
fn fetch_async(

View File

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

View File

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

View File

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

View File

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

View File

@ -81,7 +81,7 @@ impl std::ops::Deref for IsSubscribedFn {
&self.0
}
}
type Capabilities = HashSet<Vec<u8>>;
type Capabilities = HashSet<String>;
#[derive(Debug)]
pub struct UIDStore {
@ -129,13 +129,57 @@ pub struct NntpType {
impl MailBackend for NntpType {
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_remote: true,
supports_search: false,
extensions: Some(extensions),
supports_tags: false,
};
CAPABILITIES
}
}
fn fetch_async(
@ -372,7 +416,10 @@ impl NntpType {
use_tls,
use_starttls,
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 mut hasher = DefaultHasher::new();
@ -488,7 +535,7 @@ impl NntpType {
.lock()
.unwrap()
.iter()
.map(|c| String::from_utf8_lossy(c).into())
.map(|c| c.clone())
.collect::<Vec<String>>()
}
}

View File

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

View File

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

View File

@ -414,7 +414,6 @@ impl Component for AccountStatus {
self.dirty = false;
let (width, height) = self.content.size();
let a = &context.accounts[self.account_pos];
let backend_lck = a.backend.read().unwrap();
let (_x, _y) = write_string_to_grid(
"(Press Esc to return)",
&mut self.content,
@ -450,7 +449,7 @@ impl Component for AccountStatus {
);
line += 1;
let (_x, _y) = write_string_to_grid(
"Cache backend: ",
"Search backend: ",
&mut self.content,
self.theme_default.fg,
self.theme_default.bg,
@ -537,11 +536,9 @@ impl Component for AccountStatus {
}
line += 1;
if a.settings.account().format() == "imap" {
let b = (*backend_lck).as_any();
if let Some(imap_backend) = b.downcast_ref::<melib::backends::ImapType>() {
if let Some(ref extensions) = a.backend_capabilities.extensions {
write_string_to_grid(
"Server Capabilities:",
"Server Extensions:",
&mut self.content,
self.theme_default.fg,
self.theme_default.bg,
@ -549,10 +546,9 @@ impl Component for AccountStatus {
((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),
"Server Extensions:".len(),
extensions.iter().map(|(n, _)| n.len()).max().unwrap_or(0),
);
write_string_to_grid(
"meli support:",
@ -563,12 +559,11 @@ impl Component for AccountStatus {
((max_name_width + 6, line), (width - 1, height - 1)),
None,
);
capabilities.sort();
line += 1;
for (i, cap) in capabilities.into_iter().enumerate() {
for (i, (name, status)) in extensions.into_iter().enumerate() {
let (width, height) = self.content.size();
write_string_to_grid(
&cap,
&name,
&mut self.content,
self.theme_default.fg,
self.theme_default.bg,
@ -577,22 +572,10 @@ impl Component for AccountStatus {
None,
);
use melib::backends::MailBackendExtensionStatus;
let (width, height) = self.content.size();
if melib::backends::imap::SUPPORTED_CAPABILITIES
.iter()
.any(|c| cap.eq_ignore_ascii_case(c))
{
write_string_to_grid(
"supported",
&mut self.content,
Color::Green,
self.theme_default.bg,
self.theme_default.attrs,
((max_name_width + 6, line + i), (width - 1, height - 1)),
None,
);
} else {
write_string_to_grid(
let (x, y) = match status {
MailBackendExtensionStatus::Unsupported { comment: _ } => write_string_to_grid(
"not supported",
&mut self.content,
Color::Red,
@ -600,9 +583,61 @@ impl Component for AccountStatus {
self.theme_default.attrs,
((max_name_width + 6, line + i), (width - 1, height - 1)),
None,
),
MailBackendExtensionStatus::Supported { comment: _ } => write_string_to_grid(
"supported",
&mut self.content,
Color::Green,
self.theme_default.bg,
self.theme_default.attrs,
((max_name_width + 6, line + i), (width - 1, height - 1)),
None,
),
MailBackendExtensionStatus::Enabled { comment: _ } => write_string_to_grid(
"enabled",
&mut self.content,
Color::Green,
self.theme_default.bg,
self.theme_default.attrs,
((max_name_width + 6, line + i), (width - 1, height - 1)),
None,
),
};
match status {
MailBackendExtensionStatus::Unsupported { comment }
| MailBackendExtensionStatus::Supported { comment }
| MailBackendExtensionStatus::Enabled { comment } => {
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 {
self.backend.read().unwrap().mailboxes()?
};
self.backend_capabilities = self.backend.read().unwrap().capabilities();
let mut mailbox_entries: HashMap<MailboxHash, MailboxEntry> =
HashMap::with_capacity_and_hasher(ref_mailboxes.len(), Default::default());
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_remote: false,
supports_search: false,
extensions: None,
supports_tags: false,
};
CAPABILITIES