aboutsummaryrefslogtreecommitdiff
path: root/src/imap
diff options
context:
space:
mode:
Diffstat (limited to 'src/imap')
-rw-r--r--src/imap/capability.rs74
-rw-r--r--src/imap/command/authenticated.rs5
-rw-r--r--src/imap/mod.rs4
3 files changed, 80 insertions, 3 deletions
diff --git a/src/imap/capability.rs b/src/imap/capability.rs
index b98e8f8..f6b5a51 100644
--- a/src/imap/capability.rs
+++ b/src/imap/capability.rs
@@ -1,10 +1,24 @@
use imap_codec::imap_types::core::NonEmptyVec;
use imap_codec::imap_types::response::Capability;
+fn capability_unselect() -> Capability<'static> {
+ Capability::try_from("UNSELECT").unwrap()
+}
+
+fn capability_condstore() -> Capability<'static> {
+ Capability::try_from("CONDSTORE").unwrap()
+}
+
+fn capability_qresync() -> Capability<'static> {
+ Capability::try_from("QRESYNC").unwrap()
+}
+
#[derive(Debug, Clone)]
pub struct ServerCapability {
r#move: bool,
unselect: bool,
+ condstore: bool,
+ qresync: bool,
}
impl Default for ServerCapability {
@@ -12,6 +26,8 @@ impl Default for ServerCapability {
Self {
r#move: true,
unselect: true,
+ condstore: false,
+ qresync: false,
}
}
}
@@ -23,8 +39,64 @@ impl ServerCapability {
acc.push(Capability::Move);
}
if self.unselect {
- acc.push(Capability::try_from("UNSELECT").unwrap());
+ acc.push(capability_unselect());
+ }
+ if self.condstore {
+ acc.push(capability_condstore());
+ }
+ if self.qresync {
+ acc.push(capability_qresync());
}
acc.try_into().unwrap()
}
+
+ pub fn support(&self, cap: &Capability<'static>) -> bool {
+ match cap {
+ Capability::Imap4Rev1 => true,
+ Capability::Move => self.r#move,
+ x if *x == capability_condstore() => self.condstore,
+ x if *x == capability_qresync() => self.qresync,
+ x if *x == capability_unselect() => self.unselect,
+ _ => false,
+ }
+ }
+}
+
+pub struct ClientCapability {
+ condstore: bool,
+ qresync: bool,
+}
+
+impl Default for ClientCapability {
+ fn default() -> Self {
+ Self {
+ condstore: false,
+ qresync: false,
+ }
+ }
+}
+
+impl ClientCapability {
+ pub fn try_enable(
+ &mut self,
+ srv: &ServerCapability,
+ caps: &[Capability<'static>],
+ ) -> Vec<Capability<'static>> {
+ let mut enabled = vec![];
+ for cap in caps {
+ match cap {
+ x if *x == capability_condstore() && srv.condstore && !self.condstore => {
+ self.condstore = true;
+ enabled.push(x.clone());
+ }
+ x if *x == capability_qresync() && srv.qresync && !self.qresync => {
+ self.qresync = true;
+ enabled.push(x.clone());
+ }
+ _ => (),
+ }
+ }
+
+ enabled
+ }
}
diff --git a/src/imap/command/authenticated.rs b/src/imap/command/authenticated.rs
index 2970b63..fbf29f9 100644
--- a/src/imap/command/authenticated.rs
+++ b/src/imap/command/authenticated.rs
@@ -305,6 +305,9 @@ impl<'a> AuthenticatedContext<'a> {
StatusDataItemName::DeletedStorage => {
bail!("quota not implemented, can't return freed storage after EXPUNGE will be run");
},
+ StatusDataItemName::HighestModSeq => {
+ bail!("highestmodseq not yet implemented");
+ }
});
}
@@ -524,7 +527,7 @@ impl<'a> AuthenticatedContext<'a> {
};
if date.is_some() {
- bail!("Cannot set date when appending message");
+ tracing::warn!("Cannot set date when appending message");
}
let msg =
diff --git a/src/imap/mod.rs b/src/imap/mod.rs
index 0b5555a..aac1fd3 100644
--- a/src/imap/mod.rs
+++ b/src/imap/mod.rs
@@ -89,7 +89,7 @@ async fn client_wrapper(ctx: ClientContext) {
let addr = ctx.addr.clone();
match client(ctx).await {
Ok(()) => {
- tracing::info!("closing successful session for {:?}", addr);
+ tracing::debug!("closing successful session for {:?}", addr);
}
Err(e) => {
tracing::error!("closing errored session for {:?}: {}", addr, e);
@@ -127,7 +127,9 @@ async fn client(mut ctx: ClientContext) -> Result<()> {
Some(cmd_recv) => cmd_recv,
};
+ tracing::debug!(cmd=?cmd, sock=%ctx.addr, "command");
let maybe_response = session.command(cmd).await;
+ tracing::debug!(cmd=?maybe_response.completion, sock=%ctx.addr, "response");
match resp_tx.send(maybe_response) {
Err(_) => break,