aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorQuentin Dufour <quentin@deuxfleurs.fr>2024-01-03 16:52:31 +0100
committerQuentin Dufour <quentin@deuxfleurs.fr>2024-01-03 16:52:31 +0100
commit74686ebb778b740ccfccfbf61ccd24628f60e9d0 (patch)
tree0eefb4982d14499b47c7d57c7256004500f7edb3
parentb91c64920d7454d50b60ad3abb58fad9d09f0511 (diff)
downloadaerogramme-74686ebb778b740ccfccfbf61ccd24628f60e9d0.tar.gz
aerogramme-74686ebb778b740ccfccfbf61ccd24628f60e9d0.zip
append ignore dates instead of failing
-rw-r--r--Cargo.toml2
-rw-r--r--src/imap/capability.rs74
-rw-r--r--src/imap/command/authenticated.rs5
-rw-r--r--src/imap/mod.rs4
-rw-r--r--src/mail/incoming.rs16
5 files changed, 89 insertions, 12 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 1cc143e..557be55 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -58,7 +58,7 @@ aws-sdk-s3 = "1.9.0"
eml-codec = { git = "https://git.deuxfleurs.fr/Deuxfleurs/eml-codec.git", branch = "main" }
smtp-message = { git = "http://github.com/Alexis211/kannader", branch = "feature/lmtp" }
smtp-server = { git = "http://github.com/Alexis211/kannader", branch = "feature/lmtp" }
-imap-codec = { version = "1.0.0", features = ["quirk_crlf_relaxed", "bounded-static"] }
+imap-codec = { version = "1.0.0", features = ["quirk_crlf_relaxed", "bounded-static", "ext_condstore_qresync"] }
imap-flow = { git = "https://github.com/duesee/imap-flow.git", rev = "e45ce7bb6ab6bda3c71a0c7b05e9b558a5902e90" }
[dev-dependencies]
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,
diff --git a/src/mail/incoming.rs b/src/mail/incoming.rs
index 04d2ef1..781d8dc 100644
--- a/src/mail/incoming.rs
+++ b/src/mail/incoming.rs
@@ -9,7 +9,7 @@ use base64::Engine;
use futures::{future::BoxFuture, FutureExt};
//use tokio::io::AsyncReadExt;
use tokio::sync::watch;
-use tracing::{error, info, warn};
+use tracing::{debug, error, info, warn};
use crate::cryptoblob;
use crate::login::{Credentials, PublicCredentials};
@@ -62,7 +62,7 @@ async fn incoming_mail_watch_process_internal(
loop {
let maybe_updated_incoming_key = if *lock_held.borrow() {
- info!("incoming lock held");
+ debug!("incoming lock held");
let wait_new_mail = async {
loop {
@@ -83,7 +83,7 @@ async fn incoming_mail_watch_process_internal(
_ = rx_inbox_id.changed() => None,
}
} else {
- info!("incoming lock not held");
+ debug!("incoming lock not held");
tokio::select! {
_ = lock_held.changed() => None,
_ = rx_inbox_id.changed() => None,
@@ -93,11 +93,11 @@ async fn incoming_mail_watch_process_internal(
let user = match Weak::upgrade(&user) {
Some(user) => user,
None => {
- info!("User no longer available, exiting incoming loop.");
+ debug!("User no longer available, exiting incoming loop.");
break;
}
};
- info!("User still available");
+ debug!("User still available");
// If INBOX no longer is same mailbox, open new mailbox
let inbox_id = *rx_inbox_id.borrow();
@@ -235,7 +235,7 @@ async fn k2v_lock_loop_internal(
let watch_lock_loop: BoxFuture<Result<()>> = async {
let mut ct = row_ref.clone();
loop {
- info!("k2v watch lock loop iter: ct = {:?}", ct);
+ debug!("k2v watch lock loop iter: ct = {:?}", ct);
match storage.row_poll(&ct).await {
Err(e) => {
error!(
@@ -263,7 +263,7 @@ async fn k2v_lock_loop_internal(
}
let new_ct = cv.row_ref;
- info!(
+ debug!(
"k2v watch lock loop: changed, old ct = {:?}, new ct = {:?}, v = {:?}",
ct, new_ct, lock_state
);
@@ -378,7 +378,7 @@ async fn k2v_lock_loop_internal(
let _ = futures::try_join!(watch_lock_loop, lock_notify_loop, take_lock_loop);
- info!("lock loop exited, releasing");
+ debug!("lock loop exited, releasing");
if !held_tx.is_closed() {
warn!("weird...");