melib/imap: fix cache not being updated in some events
parent
6302d9d618
commit
209bd98814
|
@ -50,6 +50,7 @@ impl core::fmt::Display for ModSequence {
|
|||
#[derive(Debug)]
|
||||
pub struct CachedEnvelope {
|
||||
pub inner: Envelope,
|
||||
pub uid: UID,
|
||||
pub mailbox_hash: MailboxHash,
|
||||
pub modsequence: Option<ModSequence>,
|
||||
}
|
||||
|
@ -206,6 +207,7 @@ mod sqlite3_m {
|
|||
env.hash(),
|
||||
CachedEnvelope {
|
||||
inner: env,
|
||||
uid,
|
||||
mailbox_hash,
|
||||
modsequence: modseq,
|
||||
},
|
||||
|
@ -279,6 +281,104 @@ mod sqlite3_m {
|
|||
tx.commit()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update(
|
||||
&mut self,
|
||||
mailbox_hash: MailboxHash,
|
||||
refresh_events: &[(UID, RefreshEvent)],
|
||||
) -> Result<()> {
|
||||
debug!(
|
||||
"update with refresh_events mailbox_hash {} len {}",
|
||||
mailbox_hash,
|
||||
refresh_events.len()
|
||||
);
|
||||
if self.mailbox_state(mailbox_hash)?.is_none() {
|
||||
debug!(self.mailbox_state(mailbox_hash)?.is_none());
|
||||
let uidvalidity = self
|
||||
.uid_store
|
||||
.uidvalidity
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(&mailbox_hash)
|
||||
.cloned();
|
||||
let highestmodseq = self
|
||||
.uid_store
|
||||
.highestmodseqs
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(&mailbox_hash)
|
||||
.cloned();
|
||||
debug!(&uidvalidity);
|
||||
debug!(&highestmodseq);
|
||||
if let Some(uidvalidity) = uidvalidity {
|
||||
debug!(self.clear(
|
||||
mailbox_hash,
|
||||
uidvalidity,
|
||||
highestmodseq.and_then(|v| v.ok()),
|
||||
))?;
|
||||
}
|
||||
}
|
||||
let Self {
|
||||
ref mut connection,
|
||||
ref uid_store,
|
||||
} = self;
|
||||
let tx = connection.transaction()?;
|
||||
let mut hash_index_lck = uid_store.hash_index.lock().unwrap();
|
||||
for (uid, event) in refresh_events {
|
||||
match debug!(&event.kind) {
|
||||
RefreshEventKind::Remove(env_hash) => {
|
||||
hash_index_lck.remove(&env_hash);
|
||||
tx.execute(
|
||||
"DELETE FROM envelopes WHERE mailbox_hash = ?1 AND uid = ?2;",
|
||||
sqlite3::params![mailbox_hash as i64, *uid as i64],
|
||||
)
|
||||
.chain_err_summary(|| {
|
||||
format!(
|
||||
"Could not remove envelope {} uid {} from mailbox {} account {}",
|
||||
env_hash, *uid, mailbox_hash, uid_store.account_name
|
||||
)
|
||||
})?;
|
||||
}
|
||||
RefreshEventKind::NewFlags(env_hash, (flags, tags)) => {
|
||||
let mut stmt = tx.prepare(
|
||||
"SELECT envelope FROM envelopes WHERE mailbox_hash = ?1 AND uid = ?2;",
|
||||
)?;
|
||||
|
||||
let mut ret: Vec<Envelope> = stmt
|
||||
.query_map(sqlite3::params![mailbox_hash as i64, *uid as i64], |row| {
|
||||
Ok(row.get(0)?)
|
||||
})?
|
||||
.collect::<std::result::Result<_, _>>()?;
|
||||
if let Some(mut env) = ret.pop() {
|
||||
env.set_flags(*flags);
|
||||
env.labels_mut().clear();
|
||||
env.labels_mut().extend(tags.iter().map(|t| tag_hash!(t)));
|
||||
tx.execute(
|
||||
"UPDATE envelopes SET envelope = ?1 WHERE mailbox_hash = ?2 AND uid = ?3;",
|
||||
sqlite3::params![&env, mailbox_hash as i64, *uid as i64],
|
||||
)
|
||||
.chain_err_summary(|| {
|
||||
format!(
|
||||
"Could not update envelope {} uid {} from mailbox {} account {}",
|
||||
env_hash, *uid, mailbox_hash, uid_store.account_name
|
||||
)
|
||||
})?;
|
||||
uid_store
|
||||
.envelopes
|
||||
.lock()
|
||||
.unwrap()
|
||||
.entry(*env_hash)
|
||||
.and_modify(|entry| {
|
||||
entry.inner = env;
|
||||
});
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
tx.commit()?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -128,7 +128,7 @@ impl ImapConnection {
|
|||
//rfc4549_Synchronization_Operations_for_Disconnected_IMAP4_Clients
|
||||
pub async fn resync_basic(
|
||||
&mut self,
|
||||
cache_handle: CacheHandle,
|
||||
mut cache_handle: CacheHandle,
|
||||
mailbox_hash: MailboxHash,
|
||||
) -> Result<Option<Vec<Envelope>>> {
|
||||
let mut payload = vec![];
|
||||
|
@ -319,34 +319,41 @@ impl ImapConnection {
|
|||
.labels_mut()
|
||||
.extend(tags.iter().map(|t| tag_hash!(t)));
|
||||
});
|
||||
refresh_events.push(RefreshEvent {
|
||||
mailbox_hash,
|
||||
account_hash: self.uid_store.account_hash,
|
||||
kind: RefreshEventKind::NewFlags(env_hash, (flags, tags)),
|
||||
});
|
||||
refresh_events.push((
|
||||
uid,
|
||||
RefreshEvent {
|
||||
mailbox_hash,
|
||||
account_hash: self.uid_store.account_hash,
|
||||
kind: RefreshEventKind::NewFlags(env_hash, (flags, tags)),
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
for env_hash in valid_envs.difference(
|
||||
&env_lck
|
||||
.iter()
|
||||
.filter_map(|(h, cenv)| {
|
||||
if cenv.mailbox_hash == mailbox_hash {
|
||||
Some(*h)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
) {
|
||||
for env_hash in env_lck
|
||||
.iter()
|
||||
.filter_map(|(h, cenv)| {
|
||||
if cenv.mailbox_hash == mailbox_hash {
|
||||
Some(*h)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<BTreeSet<EnvelopeHash>>()
|
||||
.difference(&valid_envs)
|
||||
{
|
||||
refresh_events.push((
|
||||
env_lck[env_hash].uid,
|
||||
RefreshEvent {
|
||||
mailbox_hash,
|
||||
account_hash: self.uid_store.account_hash,
|
||||
kind: RefreshEventKind::Remove(*env_hash),
|
||||
},
|
||||
));
|
||||
env_lck.remove(env_hash);
|
||||
refresh_events.push(RefreshEvent {
|
||||
mailbox_hash,
|
||||
account_hash: self.uid_store.account_hash,
|
||||
kind: RefreshEventKind::Remove(*env_hash),
|
||||
});
|
||||
}
|
||||
drop(env_lck);
|
||||
for ev in refresh_events {
|
||||
cache_handle.update(mailbox_hash, &refresh_events)?;
|
||||
for (_uid, ev) in refresh_events {
|
||||
self.add_refresh_event(ev);
|
||||
}
|
||||
Ok(Some(payload.into_iter().map(|(_, env)| env).collect()))
|
||||
|
@ -356,7 +363,7 @@ impl ImapConnection {
|
|||
//Section 6.1
|
||||
pub async fn resync_condstore(
|
||||
&mut self,
|
||||
cache_handle: CacheHandle,
|
||||
mut cache_handle: CacheHandle,
|
||||
mailbox_hash: MailboxHash,
|
||||
) -> Result<Option<Vec<Envelope>>> {
|
||||
let mut payload = vec![];
|
||||
|
@ -598,11 +605,14 @@ impl ImapConnection {
|
|||
.labels_mut()
|
||||
.extend(tags.iter().map(|t| tag_hash!(t)));
|
||||
});
|
||||
refresh_events.push(RefreshEvent {
|
||||
mailbox_hash,
|
||||
account_hash: self.uid_store.account_hash,
|
||||
kind: RefreshEventKind::NewFlags(env_hash, (flags, tags)),
|
||||
});
|
||||
refresh_events.push((
|
||||
uid,
|
||||
RefreshEvent {
|
||||
mailbox_hash,
|
||||
account_hash: self.uid_store.account_hash,
|
||||
kind: RefreshEventKind::NewFlags(env_hash, (flags, tags)),
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
self.uid_store
|
||||
|
@ -622,9 +632,9 @@ impl ImapConnection {
|
|||
for uid in v {
|
||||
valid_envs.insert(generate_envelope_hash(&mailbox_path, &uid));
|
||||
}
|
||||
let mut env_lck = self.uid_store.envelopes.lock().unwrap();
|
||||
for env_hash in valid_envs.difference(
|
||||
&env_lck
|
||||
{
|
||||
let mut env_lck = self.uid_store.envelopes.lock().unwrap();
|
||||
for env_hash in env_lck
|
||||
.iter()
|
||||
.filter_map(|(h, cenv)| {
|
||||
if cenv.mailbox_hash == mailbox_hash {
|
||||
|
@ -633,17 +643,23 @@ impl ImapConnection {
|
|||
None
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
) {
|
||||
env_lck.remove(env_hash);
|
||||
refresh_events.push(RefreshEvent {
|
||||
mailbox_hash,
|
||||
account_hash: self.uid_store.account_hash,
|
||||
kind: RefreshEventKind::Remove(*env_hash),
|
||||
});
|
||||
.collect::<BTreeSet<EnvelopeHash>>()
|
||||
.difference(&valid_envs)
|
||||
{
|
||||
refresh_events.push((
|
||||
env_lck[env_hash].uid,
|
||||
RefreshEvent {
|
||||
mailbox_hash,
|
||||
account_hash: self.uid_store.account_hash,
|
||||
kind: RefreshEventKind::Remove(*env_hash),
|
||||
},
|
||||
));
|
||||
env_lck.remove(env_hash);
|
||||
}
|
||||
drop(env_lck);
|
||||
}
|
||||
drop(env_lck);
|
||||
for ev in refresh_events {
|
||||
cache_handle.update(mailbox_hash, &refresh_events)?;
|
||||
for (_uid, ev) in refresh_events {
|
||||
self.add_refresh_event(ev);
|
||||
}
|
||||
Ok(Some(payload.into_iter().map(|(_, env)| env).collect()))
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
* along with meli. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
use super::{ImapConnection, MailboxSelection};
|
||||
use super::{ImapConnection, MailboxSelection, UID};
|
||||
use crate::backends::imap::protocol_parser::{
|
||||
generate_envelope_hash, FetchResponse, ImapLineSplit, RequiredResponses, UntaggedResponse,
|
||||
};
|
||||
|
@ -58,6 +58,7 @@ impl ImapConnection {
|
|||
let mailbox =
|
||||
std::clone::Clone::clone(&self.uid_store.mailboxes.lock().await[&mailbox_hash]);
|
||||
|
||||
let mut cache_handle = super::cache::CacheHandle::get(self.uid_store.clone())?;
|
||||
let mut response = String::with_capacity(8 * 1024);
|
||||
let untagged_response =
|
||||
match super::protocol_parser::untagged_responses(line).map(|(_, v, _)| v) {
|
||||
|
@ -81,23 +82,38 @@ impl ImapConnection {
|
|||
.or_default()
|
||||
.remove(n);
|
||||
debug!("expunge {}, UID = {}", n, deleted_uid);
|
||||
let deleted_hash: crate::email::EnvelopeHash = self
|
||||
let deleted_hash: crate::email::EnvelopeHash = match self
|
||||
.uid_store
|
||||
.uid_index
|
||||
.lock()
|
||||
.unwrap()
|
||||
.remove(&(mailbox_hash, deleted_uid))
|
||||
.unwrap();
|
||||
{
|
||||
Some(v) => v,
|
||||
None => return Ok(true),
|
||||
};
|
||||
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),
|
||||
});
|
||||
let mut event: [(UID, RefreshEvent); 1] = [(
|
||||
deleted_uid,
|
||||
RefreshEvent {
|
||||
account_hash: self.uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: Remove(deleted_hash),
|
||||
},
|
||||
)];
|
||||
cache_handle.update(mailbox_hash, &event)?;
|
||||
self.add_refresh_event(std::mem::replace(
|
||||
&mut event[0].1,
|
||||
RefreshEvent {
|
||||
account_hash: self.uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: Rescan,
|
||||
},
|
||||
));
|
||||
}
|
||||
UntaggedResponse::Exists(n) => {
|
||||
/* UID FETCH ALL UID, cross-ref, then FETCH difference headers
|
||||
|
@ -166,11 +182,23 @@ impl ImapConnection {
|
|||
mailbox.unseen.lock().unwrap().insert_new(env.hash());
|
||||
}
|
||||
mailbox.exists.lock().unwrap().insert_new(env.hash());
|
||||
self.add_refresh_event(RefreshEvent {
|
||||
account_hash: self.uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: Create(Box::new(env)),
|
||||
});
|
||||
let mut event: [(UID, RefreshEvent); 1] = [(
|
||||
uid,
|
||||
RefreshEvent {
|
||||
account_hash: self.uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: Create(Box::new(env)),
|
||||
},
|
||||
)];
|
||||
cache_handle.update(mailbox_hash, &event)?;
|
||||
self.add_refresh_event(std::mem::replace(
|
||||
&mut event[0].1,
|
||||
RefreshEvent {
|
||||
account_hash: self.uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: Rescan,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -256,11 +284,23 @@ impl ImapConnection {
|
|||
}
|
||||
|
||||
mailbox.exists.lock().unwrap().insert_new(env.hash());
|
||||
self.add_refresh_event(RefreshEvent {
|
||||
account_hash: self.uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: Create(Box::new(env)),
|
||||
});
|
||||
let mut event: [(UID, RefreshEvent); 1] = [(
|
||||
uid,
|
||||
RefreshEvent {
|
||||
account_hash: self.uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: Create(Box::new(env)),
|
||||
},
|
||||
)];
|
||||
cache_handle.update(mailbox_hash, &event)?;
|
||||
self.add_refresh_event(std::mem::replace(
|
||||
&mut event[0].1,
|
||||
RefreshEvent {
|
||||
account_hash: self.uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: Rescan,
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -334,9 +374,13 @@ impl ImapConnection {
|
|||
}
|
||||
};
|
||||
debug!("fetch uid {} {:?}", uid, flags);
|
||||
let lck = self.uid_store.uid_index.lock().unwrap();
|
||||
let env_hash = lck.get(&(mailbox_hash, uid)).copied();
|
||||
drop(lck);
|
||||
let env_hash = self
|
||||
.uid_store
|
||||
.uid_index
|
||||
.lock()
|
||||
.unwrap()
|
||||
.get(&(mailbox_hash, uid))
|
||||
.copied();
|
||||
if let Some(env_hash) = env_hash {
|
||||
if !flags.0.intersects(crate::email::Flag::SEEN) {
|
||||
mailbox.unseen.lock().unwrap().insert_new(env_hash);
|
||||
|
@ -357,12 +401,23 @@ impl ImapConnection {
|
|||
.unwrap()
|
||||
.insert(env_hash, modseq);
|
||||
}
|
||||
|
||||
self.add_refresh_event(RefreshEvent {
|
||||
account_hash: self.uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: NewFlags(env_hash, flags),
|
||||
});
|
||||
let mut event: [(UID, RefreshEvent); 1] = [(
|
||||
uid,
|
||||
RefreshEvent {
|
||||
account_hash: self.uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: NewFlags(env_hash, flags),
|
||||
},
|
||||
)];
|
||||
cache_handle.update(mailbox_hash, &event)?;
|
||||
self.add_refresh_event(std::mem::replace(
|
||||
&mut event[0].1,
|
||||
RefreshEvent {
|
||||
account_hash: self.uid_store.account_hash,
|
||||
mailbox_hash,
|
||||
kind: Rescan,
|
||||
},
|
||||
));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue