mirror of
https://github.com/chatmail/core.git
synced 2026-05-05 14:26:30 +03:00
imap: skip sync flags update if highest modseq has not increased
This commit is contained in:
@@ -9,6 +9,7 @@
|
|||||||
- remove direct dependency on `byteorder` crate #3031
|
- remove direct dependency on `byteorder` crate #3031
|
||||||
- make it possible to cancel message sending by removing the message #3034,
|
- make it possible to cancel message sending by removing the message #3034,
|
||||||
this was previosuly removed in 1.71.0 #2939
|
this was previosuly removed in 1.71.0 #2939
|
||||||
|
- always skip Seen flag synchronization when there are no updates #3039
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- fix splitting off text from webxdc messages #3032
|
- fix splitting off text from webxdc messages #3032
|
||||||
|
|||||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -1090,6 +1090,7 @@ dependencies = [
|
|||||||
"hex",
|
"hex",
|
||||||
"humansize",
|
"humansize",
|
||||||
"image",
|
"image",
|
||||||
|
"imap-proto",
|
||||||
"kamadak-exif",
|
"kamadak-exif",
|
||||||
"lettre_email",
|
"lettre_email",
|
||||||
"libc",
|
"libc",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ escaper = "0.1"
|
|||||||
futures = "0.3"
|
futures = "0.3"
|
||||||
hex = "0.4.0"
|
hex = "0.4.0"
|
||||||
image = { version = "0.23.5", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] }
|
image = { version = "0.23.5", default-features=false, features = ["gif", "jpeg", "ico", "png", "pnm", "webp", "bmp"] }
|
||||||
|
imap-proto = "0.14.3"
|
||||||
kamadak-exif = "0.5"
|
kamadak-exif = "0.5"
|
||||||
lettre_email = { git = "https://github.com/deltachat/lettre", branch = "master" }
|
lettre_email = { git = "https://github.com/deltachat/lettre", branch = "master" }
|
||||||
libc = "0.2"
|
libc = "0.2"
|
||||||
|
|||||||
43
src/imap.rs
43
src/imap.rs
@@ -1023,23 +1023,33 @@ impl Imap {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.with_context(|| format!("No mailbox selected, folder: {}", folder))?;
|
.with_context(|| format!("No mailbox selected, folder: {}", folder))?;
|
||||||
|
|
||||||
// Check if the mailbox supports MODSEQ.
|
let remote_highest_modseq = if let Some(remote_highest_modseq) = mailbox.highest_modseq {
|
||||||
// We are not interested in actual value of HIGHESTMODSEQ.
|
remote_highest_modseq
|
||||||
if mailbox.highest_modseq.is_none() {
|
} else {
|
||||||
info!(
|
info!(
|
||||||
context,
|
context,
|
||||||
"Mailbox {} does not support mod-sequences, skipping flag synchronization.", folder
|
"Mailbox {} does not support mod-sequences, skipping flag synchronization.", folder
|
||||||
);
|
);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut highest_modseq = get_modseq(context, folder)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("failed to get MODSEQ for folder {}", folder))?;
|
||||||
|
if highest_modseq >= remote_highest_modseq {
|
||||||
|
info!(
|
||||||
|
context,
|
||||||
|
"MODSEQ {} is already new, HIGHESTMODSEQ={}, skipping seen flag update",
|
||||||
|
highest_modseq,
|
||||||
|
remote_highest_modseq
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut updated_chat_ids = BTreeSet::new();
|
let mut updated_chat_ids = BTreeSet::new();
|
||||||
let uid_validity = get_uidvalidity(context, folder)
|
let uid_validity = get_uidvalidity(context, folder)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("failed to get UID validity for folder {}", folder))?;
|
.with_context(|| format!("failed to get UID validity for folder {}", folder))?;
|
||||||
let mut highest_modseq = get_modseq(context, folder)
|
|
||||||
.await
|
|
||||||
.with_context(|| format!("failed to get MODSEQ for folder {}", folder))?;
|
|
||||||
let mut list = session
|
let mut list = session
|
||||||
.uid_fetch("1:*", format!("(FLAGS) (CHANGEDSINCE {})", highest_modseq))
|
.uid_fetch("1:*", format!("(FLAGS) (CHANGEDSINCE {})", highest_modseq))
|
||||||
.await
|
.await
|
||||||
@@ -1074,6 +1084,10 @@ impl Imap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if remote_highest_modseq > highest_modseq {
|
||||||
|
// We haven't seen the message with the highest MODSEQ, maybe it was deleted already.
|
||||||
|
highest_modseq = remote_highest_modseq;
|
||||||
|
}
|
||||||
set_modseq(context, folder, highest_modseq)
|
set_modseq(context, folder, highest_modseq)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("failed to set MODSEQ for folder {}", folder))?;
|
.with_context(|| format!("failed to set MODSEQ for folder {}", folder))?;
|
||||||
@@ -1570,6 +1584,23 @@ impl Imap {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update HIGHESTMODSEQ on selected mailbox.
|
||||||
|
///
|
||||||
|
/// Should be called when MODSEQ is seen on the response, such as IDLE response.
|
||||||
|
pub(crate) fn update_modseq(&mut self, modseq: u64) {
|
||||||
|
self.config.selected_mailbox =
|
||||||
|
self.config
|
||||||
|
.selected_mailbox
|
||||||
|
.as_ref()
|
||||||
|
.map(|mailbox| Mailbox {
|
||||||
|
highest_modseq: Some(std::cmp::max(
|
||||||
|
mailbox.highest_modseq.unwrap_or_default(),
|
||||||
|
modseq,
|
||||||
|
)),
|
||||||
|
..mailbox.clone()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// Return whether the server sent an unsolicited EXISTS response.
|
/// Return whether the server sent an unsolicited EXISTS response.
|
||||||
/// Drains all responses from `session.unsolicited_responses` in the process.
|
/// Drains all responses from `session.unsolicited_responses` in the process.
|
||||||
/// If this returns `true`, this means that new emails arrived and you should
|
/// If this returns `true`, this means that new emails arrived and you should
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use super::Imap;
|
|||||||
use anyhow::{bail, Context as _, Result};
|
use anyhow::{bail, Context as _, Result};
|
||||||
use async_imap::extensions::idle::IdleResponse;
|
use async_imap::extensions::idle::IdleResponse;
|
||||||
use async_std::prelude::*;
|
use async_std::prelude::*;
|
||||||
|
use imap_proto::types::{AttributeValue, Response};
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
use crate::{context::Context, scheduler::InterruptInfo};
|
use crate::{context::Context, scheduler::InterruptInfo};
|
||||||
@@ -71,6 +72,13 @@ impl Imap {
|
|||||||
match fut.await {
|
match fut.await {
|
||||||
Ok(Event::IdleResponse(IdleResponse::NewData(x))) => {
|
Ok(Event::IdleResponse(IdleResponse::NewData(x))) => {
|
||||||
info!(context, "Idle has NewData {:?}", x);
|
info!(context, "Idle has NewData {:?}", x);
|
||||||
|
if let Response::Fetch(_message, attrs) = x.parsed() {
|
||||||
|
for attr in attrs {
|
||||||
|
if let AttributeValue::ModSeq(modseq) = attr {
|
||||||
|
self.update_modseq(*modseq);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(Event::IdleResponse(IdleResponse::Timeout)) => {
|
Ok(Event::IdleResponse(IdleResponse::Timeout)) => {
|
||||||
info!(context, "Idle-wait timeout or interruption");
|
info!(context, "Idle-wait timeout or interruption");
|
||||||
|
|||||||
Reference in New Issue
Block a user