mirror of
https://git.meli.delivery/meli/meli
synced 2024-11-19 03:25:38 +00:00
imap: recognize EXPUNGE events
This commit is contained in:
parent
bfbaf3d617
commit
d7444a5b19
@ -127,6 +127,7 @@ pub struct UIDStore {
|
||||
uidvalidity: Arc<Mutex<HashMap<MailboxHash, UID>>>,
|
||||
hash_index: Arc<Mutex<HashMap<EnvelopeHash, (UID, MailboxHash)>>>,
|
||||
uid_index: Arc<Mutex<HashMap<(MailboxHash, UID), EnvelopeHash>>>,
|
||||
msn_index: Arc<Mutex<HashMap<MailboxHash, Vec<UID>>>>,
|
||||
|
||||
byte_cache: Arc<Mutex<HashMap<UID, EnvelopeCache>>>,
|
||||
tag_index: Arc<RwLock<BTreeMap<u64, String>>>,
|
||||
@ -145,6 +146,7 @@ impl Default for UIDStore {
|
||||
uidvalidity: Default::default(),
|
||||
hash_index: Default::default(),
|
||||
uid_index: Default::default(),
|
||||
msn_index: Default::default(),
|
||||
byte_cache: Default::default(),
|
||||
mailboxes: Arc::new(RwLock::new(Default::default())),
|
||||
tag_index: Arc::new(RwLock::new(Default::default())),
|
||||
@ -414,6 +416,7 @@ impl MailBackend for ImapType {
|
||||
debug!("responses len is {}", v.len());
|
||||
for UidFetchResponse {
|
||||
uid,
|
||||
message_sequence_number,
|
||||
flags,
|
||||
envelope,
|
||||
..
|
||||
@ -438,6 +441,13 @@ impl MailBackend for ImapType {
|
||||
env.labels_mut().push(hash);
|
||||
}
|
||||
}
|
||||
uid_store
|
||||
.msn_index
|
||||
.lock()
|
||||
.unwrap()
|
||||
.entry(mailbox_hash)
|
||||
.or_default()
|
||||
.insert(message_sequence_number - 1, uid);
|
||||
uid_store
|
||||
.hash_index
|
||||
.lock()
|
||||
|
@ -595,6 +595,30 @@ impl ImapConnection {
|
||||
self.uid_store.refresh_events.lock().unwrap().push(ev);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_uid_msn_cache(&mut self, mailbox_hash: MailboxHash, low: usize) -> Result<()> {
|
||||
debug_assert!(low > 0);
|
||||
let mut response = String::new();
|
||||
if self
|
||||
.current_mailbox
|
||||
.map(|h| h != mailbox_hash)
|
||||
.unwrap_or(true)
|
||||
{
|
||||
self.examine_mailbox(mailbox_hash, &mut response)?;
|
||||
}
|
||||
self.send_command(format!("UID SEARCH {}:*", low).as_bytes())?;
|
||||
self.read_response(&mut response, RequiredResponses::SEARCH)?;
|
||||
debug!("uid search response {:?}", &response);
|
||||
let mut msn_index_lck = self.uid_store.msn_index.lock().unwrap();
|
||||
let msn_index = msn_index_lck.entry(mailbox_hash).or_default();
|
||||
let _ = msn_index.drain(low - 1..);
|
||||
msn_index.extend(
|
||||
debug!(protocol_parser::search_results(response.as_bytes()))?
|
||||
.1
|
||||
.into_iter(),
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ImapBlockingConnection {
|
||||
|
@ -421,6 +421,7 @@ pub fn my_flags(input: &[u8]) -> IResult<&[u8], Flag> {
|
||||
#[derive(Debug)]
|
||||
pub struct UidFetchResponse<'a> {
|
||||
pub uid: UID,
|
||||
pub message_sequence_number: usize,
|
||||
pub flags: Option<(Flag, Vec<String>)>,
|
||||
pub body: Option<&'a [u8]>,
|
||||
pub envelope: Option<Envelope>,
|
||||
@ -471,7 +472,18 @@ pub fn uid_fetch_response(input: &str) -> ImapParseResult<UidFetchResponse<'_>>
|
||||
};
|
||||
}
|
||||
|
||||
while (input.as_bytes()[i] as char).is_numeric() {
|
||||
let mut ret = UidFetchResponse {
|
||||
uid: 0,
|
||||
message_sequence_number: 0,
|
||||
flags: None,
|
||||
body: None,
|
||||
envelope: None,
|
||||
};
|
||||
|
||||
while input.as_bytes()[i].is_ascii_digit() {
|
||||
let b: u8 = input.as_bytes()[i] - 0x30;
|
||||
ret.message_sequence_number *= 10;
|
||||
ret.message_sequence_number += b as usize;
|
||||
i += 1;
|
||||
bounds!();
|
||||
}
|
||||
@ -479,13 +491,6 @@ pub fn uid_fetch_response(input: &str) -> ImapParseResult<UidFetchResponse<'_>>
|
||||
eat_whitespace!();
|
||||
should_start_with!(input[i..], "FETCH (");
|
||||
i += "FETCH (".len();
|
||||
|
||||
let mut ret = UidFetchResponse {
|
||||
uid: 0,
|
||||
flags: None,
|
||||
body: None,
|
||||
envelope: None,
|
||||
};
|
||||
let mut has_attachments = false;
|
||||
while i < input.len() {
|
||||
eat_whitespace!(break);
|
||||
|
@ -74,7 +74,32 @@ impl ImapConnection {
|
||||
(std::time::Instant::now(), Err(reason.into()));
|
||||
}
|
||||
UntaggedResponse::Expunge(n) => {
|
||||
debug!("expunge {}", n);
|
||||
let deleted_uid = self
|
||||
.uid_store
|
||||
.msn_index
|
||||
.lock()
|
||||
.unwrap()
|
||||
.entry(mailbox_hash)
|
||||
.or_default()
|
||||
.remove(n);
|
||||
debug!("expunge {}, UID = {}", n, deleted_uid);
|
||||
let deleted_hash: crate::email::EnvelopeHash = self
|
||||
.uid_store
|
||||
.uid_index
|
||||
.lock()
|
||||
.unwrap()
|
||||
.remove(&(mailbox_hash, deleted_uid))
|
||||
.unwrap();
|
||||
self.uid_store
|
||||
.hash_index
|
||||
.lock()
|
||||
.unwrap()
|
||||
.remove(&deleted_hash);
|
||||
self.add_refresh_event(RefreshEvent {
|
||||
account_hash: self.uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: Remove(deleted_hash),
|
||||
});
|
||||
}
|
||||
UntaggedResponse::Exists(n) => {
|
||||
/* UID FETCH ALL UID, cross-ref, then FETCH difference headers
|
||||
|
@ -400,11 +400,37 @@ pub fn idle(kit: ImapWatchKit) -> Result<()> {
|
||||
}
|
||||
}
|
||||
Ok(Some(Expunge(n))) => {
|
||||
// The EXPUNGE response reports that the specified message sequence
|
||||
// number has been permanently removed from the mailbox. The message
|
||||
// sequence number for each successive message in the mailbox is
|
||||
// immediately decremented by 1, and this decrement is reflected in
|
||||
// message sequence numbers in subsequent responses (including other
|
||||
// untagged EXPUNGE responses).
|
||||
let mut conn = super::try_lock(&main_conn, Some(std::time::Duration::new(10, 0)))?;
|
||||
work_context
|
||||
.set_status
|
||||
.send((thread_id, format!("got `{} EXPUNGED` notification", n)))
|
||||
.unwrap();
|
||||
debug!("expunge {}", n);
|
||||
let deleted_uid = uid_store
|
||||
.msn_index
|
||||
.lock()
|
||||
.unwrap()
|
||||
.entry(mailbox_hash)
|
||||
.or_default()
|
||||
.remove(n);
|
||||
debug!("expunge {}, UID = {}", n, deleted_uid);
|
||||
let deleted_hash: EnvelopeHash = uid_store
|
||||
.uid_index
|
||||
.lock()
|
||||
.unwrap()
|
||||
.remove(&(mailbox_hash, deleted_uid))
|
||||
.unwrap();
|
||||
uid_store.hash_index.lock().unwrap().remove(&deleted_hash);
|
||||
conn.add_refresh_event(RefreshEvent {
|
||||
account_hash: uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: Remove(deleted_hash),
|
||||
});
|
||||
}
|
||||
Ok(Some(Exists(n))) => {
|
||||
let mut conn = super::try_lock(&main_conn, Some(std::time::Duration::new(10, 0)))?;
|
||||
|
Loading…
Reference in New Issue
Block a user