sync: mailcore 0.2.1-beta

This commit is contained in:
Eugen Kaparulin
2026-05-17 01:23:31 +03:00
parent 0100d848bd
commit 3c266c390f
6 changed files with 516 additions and 26 deletions

View File

@@ -465,6 +465,7 @@ impl ImapClient {
has_attachments,
pgp_status,
flag: message_flag,
account_email: self.email.clone(),
});
}
@@ -541,6 +542,7 @@ impl ImapClient {
attachments,
pgp_status: crate::types::PgpStatus::None,
signature_fingerprint: None,
sender_public_key: None,
})
}
@@ -761,7 +763,9 @@ impl ImapClient {
if should_be_present && !server_uids.contains(&local.uid) {
tracing::debug!("Pruning UID {} from {}", local.uid, mailbox);
let _ = storage.delete_header(mailbox, local.uid);
if let Err(e) = storage.delete_header(mailbox, local.uid) {
tracing::error!("Failed to prune UID {} from {}: {}", local.uid, mailbox, e);
}
}
}
@@ -1033,30 +1037,48 @@ impl ImapClient {
mailbox: &str,
content: &[u8],
_flags: Option<String>,
) -> Result<(), Box<dyn Error + Send + Sync>> {
) -> Result<u32, Box<dyn Error + Send + Sync>> {
let session = self.session.as_mut().ok_or("Not connected")?;
// Capture UIDNEXT before the APPEND so we can return the assigned UID.
// RFC 3501 §2.3.1.1 guarantees UIDs are monotonically increasing and
// APPEND assigns the next available UID.
let mb = session.select(mailbox).await.map_err(|e| e.to_string())?;
let uid_next = mb.uid_next.unwrap_or(0);
session
.append(mailbox, content)
.await
.map_err(|e| e.to_string())?;
Ok(())
Ok(uid_next)
}
pub async fn delete_all_messages(
&mut self,
mailbox: &str,
) -> Result<(), Box<dyn Error + Send + Sync>> {
self.select_mailbox(mailbox).await?;
let (_, exists) = self.select_mailbox(mailbox).await?;
// RFC 3501: "1:*" is undefined on an empty mailbox; some servers return NO.
if exists == 0 {
return Ok(());
}
let session = self.session.as_mut().ok_or("Not connected")?;
// Mark every message as deleted
session
.uid_store("1:*", "+FLAGS (\\Deleted)")
.await
.map_err(|e| e.to_string())?
.try_collect::<Vec<_>>()
.await
.map_err(|e| e.to_string())?;
// Mark messages deleted in batches of 500 sequence numbers. A single
// "1:*" STORE on thousands of messages causes Gmail (and other large
// servers) to stall for minutes before responding; batching keeps each
// round-trip fast. Use .SILENT to suppress per-message FETCH responses.
const BATCH: u32 = 500;
let mut start = 1u32;
while start <= exists {
let end = (start + BATCH - 1).min(exists);
session
.store(format!("{start}:{end}"), "+FLAGS.SILENT (\\Deleted)")
.await
.map_err(|e| e.to_string())?
.try_collect::<Vec<_>>()
.await
.map_err(|e| e.to_string())?;
start += BATCH;
}
// Expunge to permanently remove
session
@@ -1070,6 +1092,34 @@ impl ImapClient {
Ok(())
}
pub async fn delete_messages_permanently(
&mut self,
mailbox: &str,
uids: &[u32],
) -> Result<(), Box<dyn Error + Send + Sync>> {
if uids.is_empty() {
return Ok(());
}
self.select_mailbox(mailbox).await?;
let session = self.session.as_mut().ok_or("Not connected")?;
let uid_set = uids.iter().map(|u| u.to_string()).collect::<Vec<_>>().join(",");
session
.uid_store(&uid_set, "+FLAGS.SILENT (\\Deleted)")
.await
.map_err(|e| e.to_string())?
.try_collect::<Vec<_>>()
.await
.map_err(|e| e.to_string())?;
session
.expunge()
.await
.map_err(|e| e.to_string())?
.try_collect::<Vec<_>>()
.await
.map_err(|e| e.to_string())?;
Ok(())
}
pub async fn delete_message(
&mut self,
mailbox: &str,