Fix incorrect UID NEXT when mailbox is empty (#1201)

This commit is contained in:
mdecimus
2025-02-28 11:31:42 +01:00
parent 7e9a793cb6
commit d1f18d5fe8
2 changed files with 33 additions and 28 deletions

View File

@@ -7,14 +7,17 @@
use std::{collections::BTreeMap, sync::Arc}; use std::{collections::BTreeMap, sync::Arc};
use ahash::AHashMap; use ahash::AHashMap;
use common::{listener::SessionStream, NextMailboxState}; use common::{NextMailboxState, listener::SessionStream};
use email::mailbox::UidMailbox; use email::mailbox::UidMailbox;
use imap_proto::protocol::{expunge, select::Exists, Sequence}; use imap_proto::protocol::{Sequence, expunge, select::Exists};
use jmap_proto::{ use jmap_proto::{
object::Object, object::Object,
types::{collection::Collection, property::Property, value::Value}, types::{collection::Collection, property::Property, value::Value},
}; };
use store::write::assert::HashedValue; use store::{
ValueKey,
write::{ValueClass, assert::HashedValue},
};
use trc::AddContext; use trc::AddContext;
use crate::core::ImapId; use crate::core::ImapId;
@@ -37,8 +40,9 @@ impl<T: SessionStream> SessionData<T> {
.await? .await?
.unwrap_or_default(); .unwrap_or_default();
// Obtain UID validity // Obtain UID validity and UID next
let uid_validity = self.get_uid_validity(mailbox).await?; let uid_validity = self.get_uid_validity(mailbox).await?;
let uid_next = self.get_uid_next(mailbox).await?;
// Obtain current state // Obtain current state
let modseq = self let modseq = self
@@ -104,7 +108,7 @@ impl<T: SessionStream> SessionData<T> {
} }
let mut state = MailboxState { let mut state = MailboxState {
uid_next: uid_max + 1, uid_next,
uid_validity, uid_validity,
total_messages: id_to_imap.len(), total_messages: id_to_imap.len(),
id_to_imap, id_to_imap,
@@ -245,6 +249,21 @@ impl<T: SessionStream> SessionData<T> {
}) })
.map(|v| v as u32) .map(|v| v as u32)
} }
pub async fn get_uid_next(&self, mailbox: &MailboxId) -> trc::Result<u32> {
self.server
.core
.storage
.data
.get_counter(ValueKey {
account_id: mailbox.account_id,
collection: Collection::Mailbox.into(),
document_id: mailbox.mailbox_id,
class: ValueClass::Property(Property::EmailIds.into()),
})
.await
.map(|v| (v + 1) as u32)
}
} }
impl SelectedMailbox { impl SelectedMailbox {

View File

@@ -11,24 +11,22 @@ use crate::{
op::ImapContext, op::ImapContext,
spawn_op, spawn_op,
}; };
use common::{listener::SessionStream, Mailbox}; use common::{Mailbox, listener::SessionStream};
use directory::Permission; use directory::Permission;
use imap_proto::{ use imap_proto::{
Command, ResponseCode, StatusResponse,
parser::PushUnique, parser::PushUnique,
protocol::status::{Status, StatusItem, StatusItemType}, protocol::status::{Status, StatusItem, StatusItemType},
receiver::Request, receiver::Request,
Command, ResponseCode, StatusResponse,
}; };
use jmap_proto::{ use jmap_proto::{
object::Object, object::Object,
types::{collection::Collection, id::Id, keyword::Keyword, property::Property, value::Value}, types::{collection::Collection, id::Id, keyword::Keyword, property::Property, value::Value},
}; };
use store::{
roaring::RoaringBitmap,
write::{key::DeserializeBigEndian, ValueClass},
IndexKeyPrefix, IterateParams, ValueKey,
};
use store::{Deserialize, U32_LEN}; use store::{Deserialize, U32_LEN};
use store::{
IndexKeyPrefix, IterateParams, roaring::RoaringBitmap, write::key::DeserializeBigEndian,
};
use trc::AddContext; use trc::AddContext;
use super::ToModSeq; use super::ToModSeq;
@@ -251,22 +249,10 @@ impl<T: SessionStream> SessionData<T> {
for item in items_update { for item in items_update {
let result = match item { let result = match item {
Status::Messages => mailbox_message_ids.as_ref().map(|v| v.len()).unwrap_or(0), Status::Messages => mailbox_message_ids.as_ref().map(|v| v.len()).unwrap_or(0),
Status::UidNext => { Status::UidNext => self
(self .get_uid_next(&mailbox)
.server
.core
.storage
.data
.get_counter(ValueKey {
account_id: mailbox.account_id,
collection: Collection::Mailbox.into(),
document_id: mailbox.mailbox_id,
class: ValueClass::Property(Property::EmailIds.into()),
})
.await .await
.caused_by(trc::location!())? .caused_by(trc::location!())? as u64,
+ 1) as u64
}
Status::UidValidity => self Status::UidValidity => self
.server .server
.get_property::<Object<Value>>( .get_property::<Object<Value>>(