append ignore dates instead of failing

This commit is contained in:
Quentin 2024-01-03 16:52:31 +01:00
parent b91c64920d
commit 74686ebb77
Signed by: quentin
GPG key ID: E9602264D639FF68
5 changed files with 89 additions and 12 deletions

View file

@ -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]

View file

@ -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
}
}

View file

@ -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 =

View file

@ -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,

View file

@ -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...");