diff --git a/src/imap/mod.rs b/src/imap/mod.rs index bdae76880..eabd82679 100644 --- a/src/imap/mod.rs +++ b/src/imap/mod.rs @@ -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 { - let value = std::str::from_utf8(message_id)?; +fn parse_message_id(value: &str) -> crate::error::Result { 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 { bail!("could not parse message_id: {}", value); } -fn prefetch_get_message_id(prefetch_msg: &Fetch) -> Result { - 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> { let header_bytes = match prefetch_msg.header() { Some(header_bytes) => header_bytes, @@ -1298,6 +1289,14 @@ fn get_fetch_headers(prefetch_msg: &Fetch) -> Result> Ok(headers) } +fn prefetch_get_message_id(headers: &[mailparse::MailHeader]) -> Result { + 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 { 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 { - 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"").unwrap(), + parse_message_id("").unwrap(), "Mr.PRUe8HJBoaO.3whNvLCMFU0@testrun.org" ); }