diff options
Diffstat (limited to 'src/imap')
-rw-r--r-- | src/imap/capability.rs | 74 | ||||
-rw-r--r-- | src/imap/command/authenticated.rs | 5 | ||||
-rw-r--r-- | src/imap/mod.rs | 4 |
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, |