Compare commits

...

1 Commits

Author SHA1 Message Date
link2xt
820171bf8f feat(imap): detect NOTIFY extension 2023-11-16 03:07:21 +00:00
6 changed files with 47 additions and 2 deletions

View File

@@ -296,6 +296,12 @@ pub enum Config {
#[strum(props(default = "0"))]
DisableIdle,
/// Whether to avoid using IMAP NOTIFY even if the server supports it.
///
/// This is a developer option for testing prefetch without NOTIFY.
#[strum(props(default = "0"))]
DisableNotify,
/// Defines the max. size (in bytes) of messages downloaded automatically.
/// 0 = no limit.
#[strum(props(default = "0"))]

View File

@@ -595,6 +595,7 @@ impl Context {
let bcc_self = self.get_config_int(Config::BccSelf).await?;
let sync_msgs = self.get_config_int(Config::SyncMsgs).await?;
let disable_idle = self.get_config_bool(Config::DisableIdle).await?;
let disable_notify = self.get_config_bool(Config::DisableNotify).await?;
let prv_key_cnt = self.sql.count("SELECT COUNT(*) FROM keypairs;", ()).await?;
@@ -708,6 +709,7 @@ impl Context {
res.insert("bcc_self", bcc_self.to_string());
res.insert("sync_msgs", sync_msgs.to_string());
res.insert("disable_idle", disable_idle.to_string());
res.insert("disable_notify", disable_notify.to_string());
res.insert("private_key_count", prv_key_cnt.to_string());
res.insert("public_key_count", pub_key_cnt.to_string());
res.insert("fingerprint", fingerprint_str);

View File

@@ -448,6 +448,22 @@ impl Imap {
self.session = None;
}
/// Tries to setup NOTIFY.
pub async fn setup_notify(&mut self, context: &Context) -> Result<()> {
let session = self
.session
.as_mut()
.context("no IMAP connection established")?;
if session.can_notify() && !session.notify_set {
let cmd = format!("NOTIFY SET (selected (Messagenew {PREFETCH_FLAGS} messageexpunge))");
session.run_command_and_check_ok(cmd).await?;
info!(context, "Enabled NOTIFY");
session.notify_set = true;
}
Ok(())
}
/// FETCH-MOVE-DELETE iteration.
///
/// Prefetches headers and downloads new message from the folder, moves messages away from the
@@ -720,7 +736,9 @@ impl Imap {
.await
.context("prefetch_existing_msgs")?
} else {
self.prefetch(old_uid_next).await.context("prefetch")?
self.prefetch(context, old_uid_next)
.await
.context("prefetch")?
};
let read_cnt = msgs.len();
@@ -1329,7 +1347,13 @@ impl Imap {
/// Prefetch all messages greater than or equal to `uid_next`. Returns a list of fetch results
/// in the order of ascending delivery time to the server (INTERNALDATE).
async fn prefetch(&mut self, uid_next: u32) -> Result<Vec<(u32, async_imap::types::Fetch)>> {
async fn prefetch(
&mut self,
context: &Context,
uid_next: u32,
) -> Result<Vec<(u32, async_imap::types::Fetch)>> {
self.setup_notify(context).await?;
let session = self
.session
.as_mut()

View File

@@ -9,6 +9,10 @@ pub(crate) struct Capabilities {
/// <https://tools.ietf.org/html/rfc2177>
pub can_idle: bool,
/// True if the server has NOTIFY capability as defined in
/// <https://tools.ietf.org/html/rfc5465>
pub can_notify: bool,
/// True if the server has MOVE capability as defined in
/// <https://tools.ietf.org/html/rfc6851>
pub can_move: bool,

View File

@@ -56,6 +56,7 @@ async fn determine_capabilities(
};
let capabilities = Capabilities {
can_idle: caps.has_str("IDLE"),
can_notify: caps.has_str("NOTIFY"),
can_move: caps.has_str("MOVE"),
can_check_quota: caps.has_str("QUOTA"),
can_condstore: caps.has_str("CONDSTORE"),

View File

@@ -19,6 +19,9 @@ pub(crate) struct Session {
pub selected_mailbox: Option<Mailbox>,
pub selected_folder_needs_expunge: bool,
/// True if NOTIFY SET command was executed in this session.
pub notify_set: bool,
}
impl Deref for Session {
@@ -46,6 +49,7 @@ impl Session {
selected_folder: None,
selected_mailbox: None,
selected_folder_needs_expunge: false,
notify_set: false,
}
}
@@ -53,6 +57,10 @@ impl Session {
self.capabilities.can_idle
}
pub fn can_notify(&self) -> bool {
self.capabilities.can_notify
}
pub fn can_move(&self) -> bool {
self.capabilities.can_move
}