diff options
Diffstat (limited to 'src/imap/mail_view.rs')
-rw-r--r-- | src/imap/mail_view.rs | 94 |
1 files changed, 38 insertions, 56 deletions
diff --git a/src/imap/mail_view.rs b/src/imap/mail_view.rs index 94215dc..1f87f02 100644 --- a/src/imap/mail_view.rs +++ b/src/imap/mail_view.rs @@ -1,9 +1,9 @@ use std::num::NonZeroU32; -use anyhow::{anyhow, bail, Result, Context}; +use anyhow::{anyhow, bail, Result}; use chrono::{Offset, TimeZone, Utc}; -use imap_codec::imap_types::core::{IString, NString}; +use imap_codec::imap_types::core::NString; use imap_codec::imap_types::datetime::DateTime; use imap_codec::imap_types::fetch::{ MessageDataItem, MessageDataItemName, Section as FetchSection, @@ -16,87 +16,73 @@ use eml_codec::{ part::{composite::Message, AnyPart}, }; + +use crate::mail::query::QueryResult; + use crate::imap::attributes::AttributesProxy; use crate::imap::flags; use crate::imap::imf_view::message_envelope; -use crate::imap::mailbox_view::MailIdentifiers; use crate::imap::mime_view; use crate::imap::response::Body; -use crate::mail::query::QueryResult; +use crate::imap::index::MailIndex; pub struct MailView<'a> { + pub in_idx: MailIndex<'a>, pub query_result: &'a QueryResult<'a>, pub content: FetchedMail<'a>, } impl<'a> MailView<'a> { - pub fn new(query_result: &'a QueryResult<'a>) -> Result<Self> { + pub fn new(query_result: &'a QueryResult<'a>, in_idx: MailIndex<'a>) -> Result<MailView<'a>> { Ok(Self { + in_idx, query_result, content: match query_result { QueryResult::FullResult { content, .. } => { - let (_, parsed) = eml_codec::parse_message(content).context("Invalid mail body")?; + let (_, parsed) = eml_codec::parse_message(&content).or(Err(anyhow!("Invalid mail body")))?; FetchedMail::new_from_message(parsed) }, QueryResult::PartialResult { metadata, .. } => { - let (_, parsed) = eml_codec::parse_imf(&metadata.headers).context("Invalid mail headers")?; + let (_, parsed) = eml_codec::parse_imf(&metadata.headers).or(Err(anyhow!("unable to parse email headers")))?; FetchedMail::Partial(parsed) } - QueryResult::IndexResult { .. } => FetchedMail::None, + QueryResult::IndexResult { .. } => FetchedMail::IndexOnly, } }) } - + fn uid(&self) -> MessageDataItem<'static> { - MessageDataItem::Uid(self.ids.uid.clone()) + MessageDataItem::Uid(self.in_idx.uid.clone()) } fn flags(&self) -> MessageDataItem<'static> { MessageDataItem::Flags( - self.flags + self.in_idx + .flags .iter() .filter_map(|f| flags::from_str(f)) .collect(), ) } - fn rfc_822_size(&self) -> MessageDataItem<'static> { - MessageDataItem::Rfc822Size(self.meta.rfc822_size as u32) + fn rfc_822_size(&self) -> Result<MessageDataItem<'static>> { + let sz = self.query_result.metadata().ok_or(anyhow!("mail metadata are required"))?.rfc822_size; + Ok(MessageDataItem::Rfc822Size(sz as u32)) } - fn rfc_822_header(&self) -> MessageDataItem<'static> { - MessageDataItem::Rfc822Header(NString( - self.meta - .headers - .to_vec() - .try_into() - .ok() - .map(IString::Literal), - )) + fn rfc_822_header(&self) -> Result<MessageDataItem<'static>> { + let hdrs: NString = self.query_result.metadata().ok_or(anyhow!("mail metadata are required"))?.headers.to_vec().try_into()?; + Ok(MessageDataItem::Rfc822Header(hdrs)) } fn rfc_822_text(&self) -> Result<MessageDataItem<'static>> { - Ok(MessageDataItem::Rfc822Text(NString( - self.content - .as_full()? - .raw_body - .to_vec() - .try_into() - .ok() - .map(IString::Literal), - ))) + let txt: NString = self.content.as_full()?.raw_body.to_vec().try_into()?; + Ok(MessageDataItem::Rfc822Text(txt)) } fn rfc822(&self) -> Result<MessageDataItem<'static>> { - Ok(MessageDataItem::Rfc822(NString( - self.content - .as_full()? - .raw_part - .to_vec() - .try_into() - .ok() - .map(IString::Literal), - ))) + let full: NString = self.content.as_full()?.raw_part.to_vec().try_into()?; + Ok(MessageDataItem::Rfc822(full)) } fn envelope(&self) -> MessageDataItem<'static> { @@ -119,16 +105,16 @@ impl<'a> MailView<'a> { /// peek does not implicitly set the \Seen flag /// eg. BODY[HEADER.FIELDS (DATE FROM)] /// eg. BODY[]<0.2048> - fn body_ext<'b>( + fn body_ext( &self, - section: &Option<FetchSection<'b>>, + section: &Option<FetchSection<'static>>, partial: &Option<(u32, NonZeroU32)>, peek: &bool, - ) -> Result<(MessageDataItem<'b>, SeenFlag)> { + ) -> Result<(MessageDataItem<'static>, SeenFlag)> { // Manage Seen flag let mut seen = SeenFlag::DoNothing; let seen_flag = Flag::Seen.to_string(); - if !peek && !self.flags.iter().any(|x| *x == seen_flag) { + if !peek && !self.in_idx.flags.iter().any(|x| *x == seen_flag) { // Add \Seen flag //self.mailbox.add_flags(uuid, &[seen_flag]).await?; seen = SeenFlag::MustAdd; @@ -141,7 +127,7 @@ impl<'a> MailView<'a> { mime_view::BodySection::Slice { body, origin_octet } => (body, Some(origin_octet)), }; - let data = NString(text.to_vec().try_into().ok().map(IString::Literal)); + let data: NString = text.to_vec().try_into()?; return Ok(( MessageDataItem::BodyExt { @@ -156,13 +142,13 @@ impl<'a> MailView<'a> { fn internal_date(&self) -> Result<MessageDataItem<'static>> { let dt = Utc .fix() - .timestamp_opt(i64::try_from(self.meta.internaldate / 1000)?, 0) + .timestamp_opt(i64::try_from(self.query_result.metadata().ok_or(anyhow!("mail metadata were not fetched"))?.internaldate / 1000)?, 0) .earliest() .ok_or(anyhow!("Unable to parse internal date"))?; Ok(MessageDataItem::InternalDate(DateTime::unvalidated(dt))) } - pub fn filter<'b>(&self, ap: &AttributesProxy) -> Result<(Body<'static>, SeenFlag)> { + pub fn filter(&self, ap: &AttributesProxy) -> Result<(Body<'static>, SeenFlag)> { let mut seen = SeenFlag::DoNothing; let res_attrs = ap .attrs @@ -170,8 +156,8 @@ impl<'a> MailView<'a> { .map(|attr| match attr { MessageDataItemName::Uid => Ok(self.uid()), MessageDataItemName::Flags => Ok(self.flags()), - MessageDataItemName::Rfc822Size => Ok(self.rfc_822_size()), - MessageDataItemName::Rfc822Header => Ok(self.rfc_822_header()), + MessageDataItemName::Rfc822Size => self.rfc_822_size(), + MessageDataItemName::Rfc822Header => self.rfc_822_header(), MessageDataItemName::Rfc822Text => self.rfc_822_text(), MessageDataItemName::Rfc822 => self.rfc822(), MessageDataItemName::Envelope => Ok(self.envelope()), @@ -192,7 +178,7 @@ impl<'a> MailView<'a> { Ok(( Body::Data(Data::Fetch { - seq: self.ids.i, + seq: self.in_idx.i, items: res_attrs.try_into()?, }), seen, @@ -208,19 +194,15 @@ pub enum SeenFlag { // ------------------- pub enum FetchedMail<'a> { - None, + IndexOnly, Partial(imf::Imf<'a>), Full(AnyPart<'a>), } impl<'a> FetchedMail<'a> { pub fn new_from_message(msg: Message<'a>) -> Self { - FetchedMail::Full(AnyPart::Msg(msg)) + Self::Full(AnyPart::Msg(msg)) } - /*fn new_from_header(hdr: imf::Imf<'a>) -> Self { - FetchedMail::Partial(hdr) - }*/ - fn as_anypart(&self) -> Result<&AnyPart<'a>> { match self { FetchedMail::Full(x) => Ok(&x), |