mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
Prefetch Message-ID header instead of envelope
Envelope has the same Message-ID, but using other fields from the envelope, such as From field, is error-prone. They may contain values different from the message body. As we don't parse the envelope later on, it is better not to fetch it during prefetch too.
This commit is contained in:
@@ -118,17 +118,18 @@ pub enum ImapActionResult {
|
||||
}
|
||||
|
||||
/// Prefetch:
|
||||
/// - Envelope to get From and Message-ID
|
||||
/// - Message-ID to check if we already have the message.
|
||||
/// - In-Reply-To and References to check if message is a reply to chat message.
|
||||
/// - Chat-Version to check if a message is a chat message
|
||||
/// - Autocrypt-Setup-Message to check if a message is an autocrypt setup message,
|
||||
/// not necessarily sent by Delta Chat.
|
||||
const PREFETCH_FLAGS: &str = "(UID ENVELOPE BODY.PEEK[HEADER.FIELDS (\
|
||||
const PREFETCH_FLAGS: &str = "(UID BODY.PEEK[HEADER.FIELDS (\
|
||||
MESSAGE-ID \
|
||||
IN-REPLY-TO REFERENCES \
|
||||
CHAT-VERSION \
|
||||
AUTOCRYPT-SETUP-MESSAGE\
|
||||
)])";
|
||||
const DELETE_CHECK_FLAGS: &str = "(UID ENVELOPE)";
|
||||
const DELETE_CHECK_FLAGS: &str = "(UID BODY.PEEK[HEADER.FIELDS (MESSAGE-ID)])";
|
||||
const JUST_UID: &str = "(UID)";
|
||||
const BODY_FLAGS: &str = "(FLAGS BODY.PEEK[])";
|
||||
const SELECT_ALL: &str = "1:*";
|
||||
@@ -627,8 +628,9 @@ impl Imap {
|
||||
}
|
||||
read_cnt += 1;
|
||||
|
||||
let message_id = prefetch_get_message_id(fetch).unwrap_or_default();
|
||||
let show = prefetch_should_download(context, fetch, show_emails).unwrap_or(true);
|
||||
let headers = get_fetch_headers(fetch)?;
|
||||
let message_id = prefetch_get_message_id(&headers).unwrap_or_default();
|
||||
let show = prefetch_should_download(context, &headers, show_emails).unwrap_or(true);
|
||||
|
||||
if show && !precheck_imf(context, &message_id, folder.as_ref(), cur_uid) {
|
||||
// check passed, go fetch the rest
|
||||
@@ -972,7 +974,9 @@ impl Imap {
|
||||
if let Some(ref mut session) = &mut *self.session.lock().await {
|
||||
match session.uid_fetch(set, DELETE_CHECK_FLAGS).await {
|
||||
Ok(msgs) => {
|
||||
if msgs.is_empty() {
|
||||
let fetch = if let Some(fetch) = msgs.first() {
|
||||
fetch
|
||||
} else {
|
||||
warn!(
|
||||
context,
|
||||
"Cannot delete on IMAP, {}: imap entry gone '{}'",
|
||||
@@ -980,9 +984,11 @@ impl Imap {
|
||||
message_id,
|
||||
);
|
||||
return ImapActionResult::Failed;
|
||||
}
|
||||
let remote_message_id =
|
||||
prefetch_get_message_id(msgs.first().unwrap()).unwrap_or_default();
|
||||
};
|
||||
|
||||
let remote_message_id = get_fetch_headers(fetch)
|
||||
.and_then(|headers| prefetch_get_message_id(&headers))
|
||||
.unwrap_or_default();
|
||||
|
||||
if remote_message_id != message_id {
|
||||
warn!(
|
||||
@@ -1263,8 +1269,7 @@ fn precheck_imf(context: &Context, rfc724_mid: &str, server_folder: &str, server
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_message_id(message_id: &[u8]) -> crate::error::Result<String> {
|
||||
let value = std::str::from_utf8(message_id)?;
|
||||
fn parse_message_id(value: &str) -> crate::error::Result<String> {
|
||||
let addrs = mailparse::addrparse(value)
|
||||
.map_err(|err| format_err!("failed to parse message id {:?}", err))?;
|
||||
|
||||
@@ -1275,20 +1280,6 @@ fn parse_message_id(message_id: &[u8]) -> crate::error::Result<String> {
|
||||
bail!("could not parse message_id: {}", value);
|
||||
}
|
||||
|
||||
fn prefetch_get_message_id(prefetch_msg: &Fetch) -> Result<String> {
|
||||
if prefetch_msg.envelope().is_none() {
|
||||
return Err(Error::Other(
|
||||
"prefetch: message has no envelope".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(message_id) = prefetch_msg.envelope().unwrap().message_id {
|
||||
parse_message_id(&message_id).map_err(Into::into)
|
||||
} else {
|
||||
Err(Error::Other("prefetch: No message ID found".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_fetch_headers(prefetch_msg: &Fetch) -> Result<Vec<mailparse::MailHeader>> {
|
||||
let header_bytes = match prefetch_msg.header() {
|
||||
Some(header_bytes) => header_bytes,
|
||||
@@ -1298,6 +1289,14 @@ fn get_fetch_headers(prefetch_msg: &Fetch) -> Result<Vec<mailparse::MailHeader>>
|
||||
Ok(headers)
|
||||
}
|
||||
|
||||
fn prefetch_get_message_id(headers: &[mailparse::MailHeader]) -> Result<String> {
|
||||
if let Some(message_id) = headers.get_first_value(&HeaderDef::MessageId.get_headername())? {
|
||||
Ok(parse_message_id(&message_id)?)
|
||||
} else {
|
||||
Err(Error::Other("prefetch: No message ID found".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks if fetch result contains a header
|
||||
fn prefetch_has_header(headers: &[mailparse::MailHeader], headerdef: HeaderDef) -> Result<bool> {
|
||||
Ok(headers
|
||||
@@ -1326,10 +1325,9 @@ fn prefetch_is_reply_to_chat_message(
|
||||
|
||||
fn prefetch_should_download(
|
||||
context: &Context,
|
||||
prefetch_msg: &Fetch,
|
||||
headers: &[mailparse::MailHeader],
|
||||
show_emails: ShowEmails,
|
||||
) -> Result<bool> {
|
||||
let headers = get_fetch_headers(prefetch_msg)?;
|
||||
let is_chat_message = prefetch_has_header(&headers, HeaderDef::ChatVersion)?;
|
||||
let is_autocrypt_setup_message =
|
||||
prefetch_has_header(&headers, HeaderDef::AutocryptSetupMessage)?;
|
||||
@@ -1361,11 +1359,11 @@ mod tests {
|
||||
#[test]
|
||||
fn test_parse_message_id() {
|
||||
assert_eq!(
|
||||
parse_message_id(b"Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org").unwrap(),
|
||||
parse_message_id("Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org").unwrap(),
|
||||
"Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org"
|
||||
);
|
||||
assert_eq!(
|
||||
parse_message_id(b"<Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org>").unwrap(),
|
||||
parse_message_id("<Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org>").unwrap(),
|
||||
"Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user