melib: add protocol extension info in MailBackendCapabilities
parent
2b3949ddb2
commit
ec0153e7b2
|
@ -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 {
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>>()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 ") {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue