IMAP4rev1 Recent flag support

This commit is contained in:
mdecimus
2023-11-27 15:21:43 +01:00
parent 8f6ac2d114
commit 0168c1dca8
14 changed files with 265 additions and 87 deletions

View File

@@ -36,10 +36,10 @@ use super::{SelectedMailbox, Session, SessionData, State, IMAP};
impl<T: AsyncRead> Session<T> {
pub async fn ingest(&mut self, bytes: &[u8]) -> crate::Result<bool> {
for line in String::from_utf8_lossy(bytes).split("\r\n") {
/*for line in String::from_utf8_lossy(bytes).split("\r\n") {
//let c = println!("<- {:?}", &line[..std::cmp::min(line.len(), 100)]);
let c = println!("{}", line);
}
}*/
tracing::trace!(parent: &self.span,
event = "read",
@@ -373,8 +373,16 @@ impl State {
matches!(self, State::Authenticated { .. } | State::Selected { .. })
}
pub fn is_mailbox_selected(&self) -> bool {
matches!(self, State::Selected { .. })
pub fn close_mailbox(&self) -> bool {
match self {
State::Selected { mailbox, data } => {
if mailbox.is_select {
data.clear_recent(&mailbox.id);
}
true
}
_ => false,
}
}
}

View File

@@ -33,11 +33,14 @@ use jmap_proto::{
object::Object,
types::{collection::Collection, property::Property, value::Value},
};
use store::write::{assert::HashedValue, BatchBuilder, F_VALUE};
use store::{
roaring::RoaringBitmap,
write::{assert::HashedValue, BatchBuilder, F_VALUE},
};
use crate::core::ImapId;
use super::{MailboxId, MailboxState, NextMailboxState, SelectedMailbox, SessionData};
use super::{Mailbox, MailboxId, MailboxState, NextMailboxState, SelectedMailbox, SessionData};
pub(crate) const MAX_RETRIES: usize = 10;
@@ -107,7 +110,7 @@ impl SessionData {
)
.await?
.into_iter()
.zip(message_ids.into_iter())
.zip(message_ids.iter())
{
// Make sure the message is still in this mailbox
if let Some(uid_mailbox) = uid_mailbox {
@@ -137,6 +140,7 @@ impl SessionData {
let mut try_count = 0;
let mut uid_next = 1;
let mut uid_other = 0;
let mut recent_messages = RoaringBitmap::new();
// Shuffle unassigned
/*if unassigned.len() > 1 {
@@ -231,6 +235,7 @@ impl SessionData {
message_id = message_id,
"Duplicate UID");
}
recent_messages.insert(message_id);
}
Err(store::Error::AssertValueFailed)
if try_count < MAX_RETRIES =>
@@ -309,6 +314,21 @@ impl SessionData {
uid_to_id.insert(uid, message_id);
}
// Update recent flags
for account in self.mailboxes.lock().iter_mut() {
if account.account_id == mailbox.account_id {
let mailbox = account
.mailbox_state
.entry(mailbox.mailbox_id)
.or_insert_with(Mailbox::default);
mailbox.recent_messages &= &message_ids;
if !recent_messages.is_empty() {
mailbox.recent_messages |= &recent_messages;
}
break;
}
}
Ok(MailboxState {
uid_next,
uid_validity,
@@ -424,6 +444,38 @@ impl SessionData {
Err(StatusResponse::database_failure())
}
}
pub fn get_recent(&self, mailbox: &MailboxId) -> RoaringBitmap {
for account in self.mailboxes.lock().iter() {
if account.account_id == mailbox.account_id {
if let Some(mailbox) = account.mailbox_state.get(&mailbox.mailbox_id) {
return mailbox.recent_messages.clone();
}
}
}
RoaringBitmap::new()
}
pub fn get_recent_count(&self, mailbox: &MailboxId) -> usize {
for account in self.mailboxes.lock().iter() {
if account.account_id == mailbox.account_id {
if let Some(mailbox) = account.mailbox_state.get(&mailbox.mailbox_id) {
return mailbox.recent_messages.len() as usize;
}
}
}
0
}
pub fn clear_recent(&self, mailbox: &MailboxId) {
for account in self.mailboxes.lock().iter_mut() {
if account.account_id == mailbox.account_id {
if let Some(mailbox) = account.mailbox_state.get_mut(&mailbox.mailbox_id) {
mailbox.recent_messages.clear();
}
}
}
}
}
impl SelectedMailbox {

View File

@@ -42,6 +42,7 @@ use jmap::{
JMAP,
};
use parking_lot::Mutex;
use store::roaring::RoaringBitmap;
use tokio::{
io::{AsyncRead, ReadHalf},
sync::{mpsc, watch},
@@ -127,6 +128,7 @@ pub struct Mailbox {
pub uid_validity: Option<u32>,
pub uid_next: Option<u32>,
pub size: Option<u32>,
pub recent_messages: RoaringBitmap,
}
#[derive(Debug)]

View File

@@ -58,7 +58,7 @@ pub fn spawn_writer(mut stream: Event, span: tracing::Span) -> mpsc::Sender<Even
size = bytes.len()
);
let c = print!("{}", String::from_utf8_lossy(&bytes));
//let c = print!("{}", String::from_utf8_lossy(&bytes));
match stream_tx.write_all(bytes.as_ref()).await {
Ok(_) => {
@@ -101,7 +101,7 @@ pub fn spawn_writer(mut stream: Event, span: tracing::Span) -> mpsc::Sender<Even
size = bytes.len()
);
let c = print!("{}", String::from_utf8_lossy(&bytes));
//let c = print!("{}", String::from_utf8_lossy(&bytes));
match stream_tx.write_all(bytes.as_ref()).await {
Ok(_) => {
@@ -132,10 +132,10 @@ impl<T: AsyncRead> Session<T> {
pub async fn write_bytes(&self, bytes: impl Into<Cow<'static, [u8]>>) -> crate::OpResult {
let bytes = bytes.into();
let c = println!(
"{:?}",
/*let c = println!(
"-> {:?}",
String::from_utf8_lossy(&bytes[..std::cmp::min(bytes.len(), 100)])
);
);*/
if let Err(err) = self.writer.send(Event::Bytes(bytes)).await {
debug!("Failed to send bytes: {}", err);
@@ -149,10 +149,10 @@ impl<T: AsyncRead> Session<T> {
impl SessionData {
pub async fn write_bytes(&self, bytes: impl Into<Cow<'static, [u8]>>) -> bool {
let bytes = bytes.into();
let c = println!(
"{:?}",
/*let c = println!(
"-> {:?}",
String::from_utf8_lossy(&bytes[..std::cmp::min(bytes.len(), 100)])
);
);*/
if let Err(err) = self.writer.send(Event::Bytes(bytes)).await {
debug!("Failed to send bytes: {}", err);