mirror of
https://github.com/chatmail/core.git
synced 2026-05-03 05:16:28 +03:00
fix: allow IMAP servers not returning UIDNEXT on SELECT and STATUS
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -2461,8 +2461,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "imap-proto"
|
name = "imap-proto"
|
||||||
version = "0.16.3"
|
version = "0.16.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/djc/tokio-imap.git?rev=01ff256a7e42a9f7d2732706f8b71a16ce93427e#01ff256a7e42a9f7d2732706f8b71a16ce93427e"
|
||||||
checksum = "305c25c6e69416059e3396c4a062b84dc7b0a782cd4c84d82bab268eb0421ec7"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"nom",
|
"nom",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ opt-level = "z"
|
|||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
strip = true
|
strip = true
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
imap-proto = { git = "https://github.com/djc/tokio-imap.git", rev = "01ff256a7e42a9f7d2732706f8b71a16ce93427e" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
deltachat_derive = { path = "./deltachat_derive" }
|
deltachat_derive = { path = "./deltachat_derive" }
|
||||||
format-flowed = { path = "./format-flowed" }
|
format-flowed = { path = "./format-flowed" }
|
||||||
|
|||||||
@@ -84,4 +84,5 @@ license-files = [
|
|||||||
github = [
|
github = [
|
||||||
"async-email",
|
"async-email",
|
||||||
"deltachat",
|
"deltachat",
|
||||||
|
"djc",
|
||||||
]
|
]
|
||||||
|
|||||||
44
src/imap.rs
44
src/imap.rs
@@ -572,9 +572,6 @@ impl Imap {
|
|||||||
/// When selecting a folder for the first time, sets the uid_next to the current
|
/// When selecting a folder for the first time, sets the uid_next to the current
|
||||||
/// mailbox.uid_next so that no old emails are fetched.
|
/// mailbox.uid_next so that no old emails are fetched.
|
||||||
///
|
///
|
||||||
/// Makes sure that UIDNEXT is known for `selected_mailbox`
|
|
||||||
/// and errors out if UIDNEXT cannot be determined.
|
|
||||||
///
|
|
||||||
/// Returns Result<new_emails> (i.e. whether new emails arrived),
|
/// Returns Result<new_emails> (i.e. whether new emails arrived),
|
||||||
/// if in doubt, returns new_emails=true so emails are fetched.
|
/// if in doubt, returns new_emails=true so emails are fetched.
|
||||||
pub(crate) async fn select_with_uidvalidity(
|
pub(crate) async fn select_with_uidvalidity(
|
||||||
@@ -592,11 +589,18 @@ impl Imap {
|
|||||||
.as_mut()
|
.as_mut()
|
||||||
.with_context(|| format!("No mailbox selected, folder: {folder}"))?;
|
.with_context(|| format!("No mailbox selected, folder: {folder}"))?;
|
||||||
|
|
||||||
|
let old_uid_validity = get_uidvalidity(context, folder)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("failed to get old UID validity for folder {folder}"))?;
|
||||||
|
let old_uid_next = get_uid_next(context, folder)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("failed to get old UID NEXT for folder {folder}"))?;
|
||||||
|
|
||||||
let new_uid_validity = mailbox
|
let new_uid_validity = mailbox
|
||||||
.uid_validity
|
.uid_validity
|
||||||
.with_context(|| format!("No UIDVALIDITY for folder {folder}"))?;
|
.with_context(|| format!("No UIDVALIDITY for folder {folder}"))?;
|
||||||
let new_uid_next = if let Some(uid_next) = mailbox.uid_next {
|
let new_uid_next = if let Some(uid_next) = mailbox.uid_next {
|
||||||
uid_next
|
Some(uid_next)
|
||||||
} else {
|
} else {
|
||||||
warn!(
|
warn!(
|
||||||
context,
|
context,
|
||||||
@@ -621,18 +625,15 @@ impl Imap {
|
|||||||
.await
|
.await
|
||||||
.with_context(|| format!("STATUS (UIDNEXT) error for {folder:?}"))?;
|
.with_context(|| format!("STATUS (UIDNEXT) error for {folder:?}"))?;
|
||||||
|
|
||||||
status
|
if status.uid_next.is_none() {
|
||||||
.uid_next
|
// This happens with mail.163.com as of 2023-11-26.
|
||||||
.with_context(|| format!("STATUS {folder} (UIDNEXT) did not return UIDNEXT"))?
|
// It does not return UIDNEXT on SELECT and returns invalid
|
||||||
|
// `* STATUS "INBOX" ()` response on explicit request for UIDNEXT.
|
||||||
|
warn!(context, "STATUS {folder} (UIDNEXT) did not return UIDNEXT.");
|
||||||
|
}
|
||||||
|
status.uid_next
|
||||||
};
|
};
|
||||||
mailbox.uid_next = Some(new_uid_next);
|
mailbox.uid_next = new_uid_next;
|
||||||
|
|
||||||
let old_uid_validity = get_uidvalidity(context, folder)
|
|
||||||
.await
|
|
||||||
.with_context(|| format!("failed to get old UID validity for folder {folder}"))?;
|
|
||||||
let old_uid_next = get_uid_next(context, folder)
|
|
||||||
.await
|
|
||||||
.with_context(|| format!("failed to get old UID NEXT for folder {folder}"))?;
|
|
||||||
|
|
||||||
if new_uid_validity == old_uid_validity {
|
if new_uid_validity == old_uid_validity {
|
||||||
let new_emails = if newly_selected == NewlySelected::No {
|
let new_emails = if newly_selected == NewlySelected::No {
|
||||||
@@ -641,7 +642,7 @@ impl Imap {
|
|||||||
// the caller tries to fetch new messages (we could of course run a SELECT command now, but trying to fetch
|
// the caller tries to fetch new messages (we could of course run a SELECT command now, but trying to fetch
|
||||||
// new messages is only one command, just as a SELECT command)
|
// new messages is only one command, just as a SELECT command)
|
||||||
true
|
true
|
||||||
} else {
|
} else if let Some(new_uid_next) = new_uid_next {
|
||||||
if new_uid_next < old_uid_next {
|
if new_uid_next < old_uid_next {
|
||||||
warn!(
|
warn!(
|
||||||
context,
|
context,
|
||||||
@@ -651,7 +652,11 @@ impl Imap {
|
|||||||
context.schedule_resync().await?;
|
context.schedule_resync().await?;
|
||||||
}
|
}
|
||||||
new_uid_next != old_uid_next // If UIDNEXT changed, there are new emails
|
new_uid_next != old_uid_next // If UIDNEXT changed, there are new emails
|
||||||
|
} else {
|
||||||
|
// We have no UIDNEXT and if in doubt, return true.
|
||||||
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(new_emails);
|
return Ok(new_emails);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -660,6 +665,7 @@ impl Imap {
|
|||||||
|
|
||||||
// ============== uid_validity has changed or is being set the first time. ==============
|
// ============== uid_validity has changed or is being set the first time. ==============
|
||||||
|
|
||||||
|
let new_uid_next = new_uid_next.unwrap_or_default();
|
||||||
set_uid_next(context, folder, new_uid_next).await?;
|
set_uid_next(context, folder, new_uid_next).await?;
|
||||||
set_uidvalidity(context, folder, new_uid_validity).await?;
|
set_uidvalidity(context, folder, new_uid_validity).await?;
|
||||||
|
|
||||||
@@ -876,11 +882,7 @@ impl Imap {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.with_context(|| format!("Expected {folder:?} to be selected"))?
|
.with_context(|| format!("Expected {folder:?} to be selected"))?
|
||||||
.uid_next
|
.uid_next
|
||||||
.with_context(|| {
|
.unwrap_or_default();
|
||||||
format!(
|
|
||||||
"Expected UIDNEXT to be determined for {folder:?} by select_with_uidvalidity"
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
let new_uid_next = max(
|
let new_uid_next = max(
|
||||||
max(largest_uid_fetched, largest_uid_skipped.unwrap_or(0)) + 1,
|
max(largest_uid_fetched, largest_uid_skipped.unwrap_or(0)) + 1,
|
||||||
mailbox_uid_next,
|
mailbox_uid_next,
|
||||||
|
|||||||
Reference in New Issue
Block a user