append ignore dates instead of failing
This commit is contained in:
parent
b91c64920d
commit
74686ebb77
5 changed files with 89 additions and 12 deletions
|
@ -58,7 +58,7 @@ aws-sdk-s3 = "1.9.0"
|
||||||
eml-codec = { git = "https://git.deuxfleurs.fr/Deuxfleurs/eml-codec.git", branch = "main" }
|
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-message = { git = "http://github.com/Alexis211/kannader", branch = "feature/lmtp" }
|
||||||
smtp-server = { 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" }
|
imap-flow = { git = "https://github.com/duesee/imap-flow.git", rev = "e45ce7bb6ab6bda3c71a0c7b05e9b558a5902e90" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -1,10 +1,24 @@
|
||||||
use imap_codec::imap_types::core::NonEmptyVec;
|
use imap_codec::imap_types::core::NonEmptyVec;
|
||||||
use imap_codec::imap_types::response::Capability;
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ServerCapability {
|
pub struct ServerCapability {
|
||||||
r#move: bool,
|
r#move: bool,
|
||||||
unselect: bool,
|
unselect: bool,
|
||||||
|
condstore: bool,
|
||||||
|
qresync: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ServerCapability {
|
impl Default for ServerCapability {
|
||||||
|
@ -12,6 +26,8 @@ impl Default for ServerCapability {
|
||||||
Self {
|
Self {
|
||||||
r#move: true,
|
r#move: true,
|
||||||
unselect: true,
|
unselect: true,
|
||||||
|
condstore: false,
|
||||||
|
qresync: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,8 +39,64 @@ impl ServerCapability {
|
||||||
acc.push(Capability::Move);
|
acc.push(Capability::Move);
|
||||||
}
|
}
|
||||||
if self.unselect {
|
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()
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -305,6 +305,9 @@ impl<'a> AuthenticatedContext<'a> {
|
||||||
StatusDataItemName::DeletedStorage => {
|
StatusDataItemName::DeletedStorage => {
|
||||||
bail!("quota not implemented, can't return freed storage after EXPUNGE will be run");
|
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() {
|
if date.is_some() {
|
||||||
bail!("Cannot set date when appending message");
|
tracing::warn!("Cannot set date when appending message");
|
||||||
}
|
}
|
||||||
|
|
||||||
let msg =
|
let msg =
|
||||||
|
|
|
@ -89,7 +89,7 @@ async fn client_wrapper(ctx: ClientContext) {
|
||||||
let addr = ctx.addr.clone();
|
let addr = ctx.addr.clone();
|
||||||
match client(ctx).await {
|
match client(ctx).await {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
tracing::info!("closing successful session for {:?}", addr);
|
tracing::debug!("closing successful session for {:?}", addr);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("closing errored session for {:?}: {}", addr, 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,
|
Some(cmd_recv) => cmd_recv,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
tracing::debug!(cmd=?cmd, sock=%ctx.addr, "command");
|
||||||
let maybe_response = session.command(cmd).await;
|
let maybe_response = session.command(cmd).await;
|
||||||
|
tracing::debug!(cmd=?maybe_response.completion, sock=%ctx.addr, "response");
|
||||||
|
|
||||||
match resp_tx.send(maybe_response) {
|
match resp_tx.send(maybe_response) {
|
||||||
Err(_) => break,
|
Err(_) => break,
|
||||||
|
|
|
@ -9,7 +9,7 @@ use base64::Engine;
|
||||||
use futures::{future::BoxFuture, FutureExt};
|
use futures::{future::BoxFuture, FutureExt};
|
||||||
//use tokio::io::AsyncReadExt;
|
//use tokio::io::AsyncReadExt;
|
||||||
use tokio::sync::watch;
|
use tokio::sync::watch;
|
||||||
use tracing::{error, info, warn};
|
use tracing::{debug, error, info, warn};
|
||||||
|
|
||||||
use crate::cryptoblob;
|
use crate::cryptoblob;
|
||||||
use crate::login::{Credentials, PublicCredentials};
|
use crate::login::{Credentials, PublicCredentials};
|
||||||
|
@ -62,7 +62,7 @@ async fn incoming_mail_watch_process_internal(
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let maybe_updated_incoming_key = if *lock_held.borrow() {
|
let maybe_updated_incoming_key = if *lock_held.borrow() {
|
||||||
info!("incoming lock held");
|
debug!("incoming lock held");
|
||||||
|
|
||||||
let wait_new_mail = async {
|
let wait_new_mail = async {
|
||||||
loop {
|
loop {
|
||||||
|
@ -83,7 +83,7 @@ async fn incoming_mail_watch_process_internal(
|
||||||
_ = rx_inbox_id.changed() => None,
|
_ = rx_inbox_id.changed() => None,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
info!("incoming lock not held");
|
debug!("incoming lock not held");
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
_ = lock_held.changed() => None,
|
_ = lock_held.changed() => None,
|
||||||
_ = rx_inbox_id.changed() => None,
|
_ = rx_inbox_id.changed() => None,
|
||||||
|
@ -93,11 +93,11 @@ async fn incoming_mail_watch_process_internal(
|
||||||
let user = match Weak::upgrade(&user) {
|
let user = match Weak::upgrade(&user) {
|
||||||
Some(user) => user,
|
Some(user) => user,
|
||||||
None => {
|
None => {
|
||||||
info!("User no longer available, exiting incoming loop.");
|
debug!("User no longer available, exiting incoming loop.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
info!("User still available");
|
debug!("User still available");
|
||||||
|
|
||||||
// If INBOX no longer is same mailbox, open new mailbox
|
// If INBOX no longer is same mailbox, open new mailbox
|
||||||
let inbox_id = *rx_inbox_id.borrow();
|
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 watch_lock_loop: BoxFuture<Result<()>> = async {
|
||||||
let mut ct = row_ref.clone();
|
let mut ct = row_ref.clone();
|
||||||
loop {
|
loop {
|
||||||
info!("k2v watch lock loop iter: ct = {:?}", ct);
|
debug!("k2v watch lock loop iter: ct = {:?}", ct);
|
||||||
match storage.row_poll(&ct).await {
|
match storage.row_poll(&ct).await {
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!(
|
error!(
|
||||||
|
@ -263,7 +263,7 @@ async fn k2v_lock_loop_internal(
|
||||||
}
|
}
|
||||||
let new_ct = cv.row_ref;
|
let new_ct = cv.row_ref;
|
||||||
|
|
||||||
info!(
|
debug!(
|
||||||
"k2v watch lock loop: changed, old ct = {:?}, new ct = {:?}, v = {:?}",
|
"k2v watch lock loop: changed, old ct = {:?}, new ct = {:?}, v = {:?}",
|
||||||
ct, new_ct, lock_state
|
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);
|
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() {
|
if !held_tx.is_closed() {
|
||||||
warn!("weird...");
|
warn!("weird...");
|
||||||
|
|
Loading…
Reference in a new issue