From 62a4f70ac8cbb10fbbd8985a1eaec9c52f3e75d8 Mon Sep 17 00:00:00 2001 From: mdecimus Date: Sat, 2 Mar 2024 16:45:41 +0100 Subject: [PATCH] Store message headers in message metadata --- crates/imap/src/op/fetch.rs | 39 +++++++++++-------------------- crates/jmap/src/email/get.rs | 35 +++++++++------------------ crates/jmap/src/email/index.rs | 7 ++++++ crates/jmap/src/email/metadata.rs | 1 + 4 files changed, 33 insertions(+), 49 deletions(-) diff --git a/crates/imap/src/op/fetch.rs b/crates/imap/src/op/fetch.rs index 39f51489..8f8c3814 100644 --- a/crates/imap/src/op/fetch.rs +++ b/crates/imap/src/op/fetch.rs @@ -222,11 +222,11 @@ impl SessionData { for attribute in &arguments.attributes { match attribute { - Attribute::Envelope - | Attribute::Rfc822Header - | Attribute::Body - | Attribute::BodyStructure - | Attribute::BinarySize { .. } => { + Attribute::BodySection { sections, .. } + if sections.first().map_or(false, |s| { + matches!(s, Section::Header | Section::HeaderFields { .. }) + }) => {} + Attribute::Body | Attribute::BodyStructure | Attribute::BinarySize { .. } => { /* Note that this did not result in \Seen being set, because RFC822.HEADER response data occurs as a result of a FETCH @@ -319,7 +319,7 @@ impl SessionData { let raw_message = if needs_blobs { // Retrieve raw message if needed match self.jmap.get_blob(&email.blob_hash, 0..u32::MAX).await { - Ok(Some(raw_message)) => raw_message.into(), + Ok(Some(raw_message)) => raw_message, Ok(None) => { tracing::warn!(event = "not-found", account_id = account_id, @@ -334,11 +334,9 @@ impl SessionData { } } } else { - None + email.raw_headers }; - let message = email - .contents - .into_message(raw_message.as_deref().unwrap_or_default()); + let message = email.contents.into_message(&raw_message); // Build response let mut items = Vec::with_capacity(arguments.attributes.len()); @@ -403,15 +401,13 @@ impl SessionData { } Attribute::Rfc822 => { items.push(DataItem::Rfc822 { - contents: raw_message.as_ref().unwrap().into(), + contents: raw_message.as_slice().into(), }); } Attribute::Rfc822Header => { let message = message.root_part(); - if let Some(header) = raw_message - .as_ref() - .unwrap() - .get(message.offset_header..message.offset_body) + if let Some(header) = + raw_message.get(message.offset_header..message.offset_body) { items.push(DataItem::Rfc822Header { contents: header.into(), @@ -419,16 +415,9 @@ impl SessionData { } } Attribute::Rfc822Text => { - let message = message.root_part(); - if let Some(text) = raw_message - .as_ref() - .unwrap() - .get(message.offset_body..message.offset_end) - { - items.push(DataItem::Rfc822Text { - contents: text.into(), - }); - } + items.push(DataItem::Rfc822Text { + contents: raw_message.as_slice().into(), + }); } Attribute::Body => { items.push(DataItem::Body { diff --git a/crates/jmap/src/email/get.rs b/crates/jmap/src/email/get.rs index c3e64202..924e793c 100644 --- a/crates/jmap/src/email/get.rs +++ b/crates/jmap/src/email/get.rs @@ -130,24 +130,17 @@ impl JMAP { }; // Check if we need to fetch the raw headers or body - let mut needs_headers = false; let mut needs_body = false; for property in &properties { - match property { - Property::Header(_) | Property::Headers => { - needs_headers = true; - } + if matches!( + property, Property::BodyValues - | Property::TextBody - | Property::HtmlBody - | Property::Attachments - | Property::BodyStructure => { - needs_body = true; - } - _ => (), - } - - if needs_body { + | Property::TextBody + | Property::HtmlBody + | Property::Attachments + | Property::BodyStructure + ) { + needs_body = true; break; } } @@ -175,14 +168,8 @@ impl JMAP { }; // Retrieve raw message if needed - let raw_message = if needs_body || needs_headers { - let offset = if !needs_body { - metadata.contents.parts[0].offset_body as u32 - } else { - u32::MAX - }; - - if let Some(raw_message) = self.get_blob(&metadata.blob_hash, 0..offset).await? { + let raw_message = if needs_body { + if let Some(raw_message) = self.get_blob(&metadata.blob_hash, 0..u32::MAX).await? { raw_message } else { tracing::warn!(event = "not-found", @@ -195,7 +182,7 @@ impl JMAP { continue; } } else { - vec![] + metadata.raw_headers }; let blob_id = BlobId { hash: metadata.blob_hash.clone(), diff --git a/crates/jmap/src/email/index.rs b/crates/jmap/src/email/index.rs index 33769c6f..8cadfaee 100644 --- a/crates/jmap/src/email/index.rs +++ b/crates/jmap/src/email/index.rs @@ -161,11 +161,18 @@ impl IndexMessage for BatchBuilder { ); // Store message metadata + let root_part = message.root_part(); self.value( Property::BodyStructure, Bincode::new(MessageMetadata { preview: preview.unwrap_or_default().into_owned(), size: message.raw_message.len(), + raw_headers: message + .raw_message + .as_ref() + .get(root_part.offset_header..root_part.offset_body) + .unwrap_or_default() + .to_vec(), contents: message.into(), received_at, has_attachments, diff --git a/crates/jmap/src/email/metadata.rs b/crates/jmap/src/email/metadata.rs index 677b34cc..d48fbcd0 100644 --- a/crates/jmap/src/email/metadata.rs +++ b/crates/jmap/src/email/metadata.rs @@ -42,6 +42,7 @@ pub struct MessageMetadata<'x> { pub received_at: u64, pub preview: String, pub has_attachments: bool, + pub raw_headers: Vec, } #[derive(Debug, Serialize, Deserialize)]