diff --git a/src/imap/mail_view.rs b/src/imap/mail_view.rs index 4b18021..6a6bede 100644 --- a/src/imap/mail_view.rs +++ b/src/imap/mail_view.rs @@ -79,7 +79,7 @@ impl<'a> MailView<'a> { seen = SeenFlag::MustAdd; } self.rfc822() - }, + } MessageDataItemName::Envelope => Ok(self.envelope()), MessageDataItemName::Body => self.body(), MessageDataItemName::BodyStructure => self.body_structure(), @@ -185,12 +185,14 @@ impl<'a> MailView<'a> { fn body(&self) -> Result> { Ok(MessageDataItem::Body(mime_view::bodystructure( self.content.as_msg()?.child.as_ref(), + false, )?)) } fn body_structure(&self) -> Result> { Ok(MessageDataItem::Body(mime_view::bodystructure( self.content.as_msg()?.child.as_ref(), + true, )?)) } diff --git a/src/imap/mailbox_view.rs b/src/imap/mailbox_view.rs index 3f8389b..027947f 100644 --- a/src/imap/mailbox_view.rs +++ b/src/imap/mailbox_view.rs @@ -1,7 +1,7 @@ use std::num::NonZeroU32; use std::sync::Arc; -use anyhow::{anyhow, Error, Context, Result}; +use anyhow::{anyhow, Context, Error, Result}; use futures::stream::{FuturesOrdered, StreamExt}; @@ -130,7 +130,8 @@ impl MailboxView { data.extend(self.flags_status()?.into_iter()); data.push(self.uidvalidity_status()?); data.push(self.uidnext_status()?); - self.unseen_first_status()?.map(|unseen_status| data.push(unseen_status)); + self.unseen_first_status()? + .map(|unseen_status| data.push(unseen_status)); Ok(data) } @@ -402,18 +403,23 @@ impl MailboxView { } fn unseen_first_status(&self) -> Result>> { - Ok(self.unseen_first()?.map(|unseen_id| { - Status::ok(None, Some(Code::Unseen(unseen_id)), "First unseen.").map(Body::Status) - }).transpose()?) + Ok(self + .unseen_first()? + .map(|unseen_id| { + Status::ok(None, Some(Code::Unseen(unseen_id)), "First unseen.").map(Body::Status) + }) + .transpose()?) } fn unseen_first(&self) -> Result> { - Ok(self.0.snapshot.table + Ok(self + .0 + .snapshot + .table .values() .enumerate() - .find(|(_i, (_imap_uid, flags))| { - !flags.contains(&"\\Seen".to_string()) - }).map(|(i, _)| NonZeroU32::try_from(i as u32 + 1)) + .find(|(_i, (_imap_uid, flags))| !flags.contains(&"\\Seen".to_string())) + .map(|(i, _)| NonZeroU32::try_from(i as u32 + 1)) .transpose()?) } diff --git a/src/imap/mime_view.rs b/src/imap/mime_view.rs index cf6c751..8fc043b 100644 --- a/src/imap/mime_view.rs +++ b/src/imap/mime_view.rs @@ -4,7 +4,10 @@ use std::num::NonZeroU32; use anyhow::{anyhow, bail, Result}; -use imap_codec::imap_types::body::{BasicFields, Body as FetchBody, BodyStructure, SpecificFields}; +use imap_codec::imap_types::body::{ + BasicFields, Body as FetchBody, BodyStructure, MultiPartExtensionData, SinglePartExtensionData, + SpecificFields, +}; use imap_codec::imap_types::core::{AString, IString, NString, NonEmptyVec}; use imap_codec::imap_types::fetch::{Part as FetchPart, Section as FetchSection}; @@ -78,8 +81,8 @@ pub fn body_ext<'a>( /// | parameter list /// b OK Fetch completed (0.001 + 0.000 secs). /// ``` -pub fn bodystructure(part: &AnyPart) -> Result> { - NodeMime(part).structure() +pub fn bodystructure(part: &AnyPart, is_ext: bool) -> Result> { + NodeMime(part).structure(is_ext) } /// NodeMime @@ -118,12 +121,12 @@ impl<'a> NodeMime<'a> { } } - fn structure(&self) -> Result> { + fn structure(&self, is_ext: bool) -> Result> { match self.0 { - AnyPart::Txt(x) => NodeTxt(self, x).structure(), - AnyPart::Bin(x) => NodeBin(self, x).structure(), - AnyPart::Mult(x) => NodeMult(self, x).structure(), - AnyPart::Msg(x) => NodeMsg(self, x).structure(), + AnyPart::Txt(x) => NodeTxt(self, x).structure(is_ext), + AnyPart::Bin(x) => NodeBin(self, x).structure(is_ext), + AnyPart::Mult(x) => NodeMult(self, x).structure(is_ext), + AnyPart::Msg(x) => NodeMsg(self, x).structure(is_ext), } } } @@ -359,7 +362,7 @@ impl<'a> SelectedMime<'a> { // --------------------------- struct NodeMsg<'a>(&'a NodeMime<'a>, &'a composite::Message<'a>); impl<'a> NodeMsg<'a> { - fn structure(&self) -> Result> { + fn structure(&self, is_ext: bool) -> Result> { let basic = SelectedMime(self.0 .0).basic_fields()?; Ok(BodyStructure::Single { @@ -367,17 +370,23 @@ impl<'a> NodeMsg<'a> { basic, specific: SpecificFields::Message { envelope: Box::new(ImfView(&self.1.imf).message_envelope()), - body_structure: Box::new(NodeMime(&self.1.child).structure()?), + body_structure: Box::new(NodeMime(&self.1.child).structure(is_ext)?), number_of_lines: nol(self.1.raw_part), }, }, - extension_data: None, + extension_data: match is_ext { + true => Some(SinglePartExtensionData { + md5: NString(None), + tail: None, + }), + _ => None, + }, }) } } struct NodeMult<'a>(&'a NodeMime<'a>, &'a composite::Multipart<'a>); impl<'a> NodeMult<'a> { - fn structure(&self) -> Result> { + fn structure(&self, is_ext: bool) -> Result> { let itype = &self.1.mime.interpreted_type; let subtype = IString::try_from(itype.subtype.to_string()) .unwrap_or(unchecked_istring("alternative")); @@ -386,7 +395,7 @@ impl<'a> NodeMult<'a> { .1 .children .iter() - .filter_map(|inner| NodeMime(&inner).structure().ok()) + .filter_map(|inner| NodeMime(&inner).structure(is_ext).ok()) .collect::>(); NonEmptyVec::validate(&inner_bodies)?; @@ -395,20 +404,22 @@ impl<'a> NodeMult<'a> { Ok(BodyStructure::Multi { bodies, subtype, - extension_data: None, - /*Some(MultipartExtensionData { - parameter_list: vec![], - disposition: None, - language: None, - location: None, - extension: vec![], - })*/ + extension_data: match is_ext { + true => Some(MultiPartExtensionData { + parameter_list: vec![( + IString::try_from("boundary").unwrap(), + IString::try_from(self.1.mime.interpreted_type.boundary.to_string())?, + )], + tail: None, + }), + _ => None, + }, }) } } struct NodeTxt<'a>(&'a NodeMime<'a>, &'a discrete::Text<'a>); impl<'a> NodeTxt<'a> { - fn structure(&self) -> Result> { + fn structure(&self, is_ext: bool) -> Result> { let mut basic = SelectedMime(self.0 .0).basic_fields()?; // Get the interpreted content type, set it @@ -435,14 +446,20 @@ impl<'a> NodeTxt<'a> { number_of_lines: nol(self.1.body), }, }, - extension_data: None, + extension_data: match is_ext { + true => Some(SinglePartExtensionData { + md5: NString(None), + tail: None, + }), + _ => None, + }, }) } } struct NodeBin<'a>(&'a NodeMime<'a>, &'a discrete::Binary<'a>); impl<'a> NodeBin<'a> { - fn structure(&self) -> Result> { + fn structure(&self, is_ext: bool) -> Result> { let basic = SelectedMime(self.0 .0).basic_fields()?; let default = mime::r#type::NaiveType { @@ -465,7 +482,13 @@ impl<'a> NodeBin<'a> { basic, specific: SpecificFields::Basic { r#type, subtype }, }, - extension_data: None, + extension_data: match is_ext { + true => Some(SinglePartExtensionData { + md5: NString(None), + tail: None, + }), + _ => None, + }, }) } }