IMAP4rev1 Recent flag support
This commit is contained in:
@@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user