sync: handle empty Message-Id again

This commit is contained in:
FliegendeWurst 2021-04-21 19:59:55 +02:00 committed by Arne Keller
parent 451fac9edc
commit 00e5ddf5c6
2 changed files with 22 additions and 19 deletions

View File

@ -63,10 +63,12 @@ fn sync(
continue; continue;
} }
let header = m.header().unwrap(); let header = m.header().unwrap();
let message_id = parse_header(header).map(|x| x.0.get_value()) let mut message_id = parse_header(header).map(|x| x.0.get_value()).unwrap_or_default();
.unwrap_or_else(|_| fallback_mid(mailbox, id)); if message_id.is_empty() {
message_id = fallback_mid(mailbox, id);
}
let flags = flags.iter().map(|x| remove_cow(x)).collect_vec(); let flags = flags.iter().map(|x| remove_cow(x)).collect_vec();
mails.insert(message_id, (id.uid_validity, id.uid, id.to_u64(), flags)); mails.insert(message_id, (id.uid_validity, id.uid, id, flags));
} }
remote.insert(mailbox, mails); remote.insert(mailbox, mails);
} }
@ -139,24 +141,19 @@ fn sync(
let mut to_fetch = Vec::new(); let mut to_fetch = Vec::new();
for (message_id, entry) in remote_mails.iter_mut() { for (message_id, entry) in remote_mails.iter_mut() {
let (uid1, uid2, full_uid, remote_flags) = entry; let (uid1, uid2, full_uid, remote_flags) = entry;
let local = have_mail.query_map(params![message_id], |row| Ok(( let local = have_mail.query_map(params![message_id], map3rows::<String, MaildirID, String>)?.map(|x| x.unwrap()).collect_vec();
row.get::<_, String>(0)?,
load_i64(row.get::<_, i64>(1)?),
row.get::<_, String>(2)?
)))?.map(|x| x.unwrap()).collect_vec();
macro_rules! update_flags { macro_rules! update_flags {
($full_uid:expr, $flags:expr) => { ($id:expr, $flags:expr) => {
let uid = ($full_uid << 32) >> 32;
let local_s = $flags.contains('S'); let local_s = $flags.contains('S');
let local_u = $flags.contains(UNREAD); let local_u = $flags.contains(UNREAD);
let remote_s = remote_flags.contains(&Flag::Seen); let remote_s = remote_flags.contains(&Flag::Seen);
if local_s && !remote_s { if local_s && !remote_s {
println!("setting Seen flag on {}/{}", mailbox, uid); println!("setting Seen flag on {}/{}", mailbox, $id.uid);
imap_session.uid_store(uid.to_string(), "+FLAGS.SILENT (\\Seen)")?; imap_session.uid_store($id.to_imap(), "+FLAGS.SILENT (\\Seen)")?;
remote_flags.push(Flag::Seen); remote_flags.push(Flag::Seen);
} else if local_u && remote_s { } else if local_u && remote_s {
println!("removing Seen flag on {}/{}", mailbox, uid); println!("removing Seen flag on {}/{}", mailbox, $id.uid);
imap_session.uid_store(uid.to_string(), "-FLAGS.SILENT (\\Seen)")?; imap_session.uid_store($id.to_imap(), "-FLAGS.SILENT (\\Seen)")?;
remote_flags.remove(remote_flags.iter().position(|x| x == &Flag::Seen).unwrap()); remote_flags.remove(remote_flags.iter().position(|x| x == &Flag::Seen).unwrap());
} }
} }
@ -167,9 +164,7 @@ fn sync(
} }
if !local.is_empty() { if !local.is_empty() {
let (inbox, full_uid, flags) = &local[0]; let (inbox, full_uid, flags) = &local[0];
let local_uid1 = (full_uid >> 32) as u32; let local_id = full_uid.to_string();
let local_uid2 = ((full_uid << 32) >> 32) as u32;
let local_id = gen_id(local_uid1, local_uid2);
let new_uid = MaildirID::new(*uid1, *uid2); let new_uid = MaildirID::new(*uid1, *uid2);
let new_id = new_uid.to_string(); let new_id = new_uid.to_string();
// hardlink mail // hardlink mail
@ -178,8 +173,9 @@ fn sync(
println!("hardlinking: {}/{} -> {}/{}", inbox, local_id, mailbox, new_id); println!("hardlinking: {}/{} -> {}/{}", inbox, local_id, mailbox, new_id);
maildir_cp(maildir1, maildir2, &local_id, &new_id, flags, false)?; maildir_cp(maildir1, maildir2, &local_id, &new_id, flags, false)?;
save_mail.execute(params![mailbox, new_uid.to_i64(), message_id, flags])?; save_mail.execute(params![mailbox, new_uid.to_i64(), message_id, flags])?;
update_flags!(new_uid.to_u64(), flags); update_flags!(new_uid, flags);
} else if !is_trash { // do not fetch trashed mail } else if !is_trash { // do not fetch trashed mail
println!("fetching {:?} {:?} as it is not in {:?}", uid2, message_id, local);
to_fetch.push(uid2); to_fetch.push(uid2);
} }
} }

View File

@ -12,7 +12,7 @@ use mailparse::{MailHeaderMap, ParsedMail, SingleInfo, addrparse, dateparse};
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use parking_lot::RwLock; use parking_lot::RwLock;
use petgraph::{Graph, graph::NodeIndex}; use petgraph::{Graph, graph::NodeIndex};
use rusqlite::{Connection, ToSql, params, types::ToSqlOutput}; use rusqlite::{Connection, ToSql, params, types::{FromSql, ToSqlOutput}};
use rustls_connector::{RustlsConnector, rustls::{ClientSession, StreamOwned}}; use rustls_connector::{RustlsConnector, rustls::{ClientSession, StreamOwned}};
use serde::{Deserializer, Serializer}; use serde::{Deserializer, Serializer};
use serde::de::Visitor; use serde::de::Visitor;
@ -118,6 +118,13 @@ impl ToSql for MaildirID {
} }
} }
impl FromSql for MaildirID {
fn column_result(value: rusqlite::types::ValueRef<'_>) -> rusqlite::types::FromSqlResult<Self> {
let x = i64::column_result(value)?;
Ok(MaildirID::from(x))
}
}
impl Display for MaildirID { impl Display for MaildirID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}_{}", self.uid_validity, self.uid) write!(f, "{}_{}", self.uid_validity, self.uid)