diff --git a/src/imap/mail_view.rs b/src/imap/mail_view.rs index 7da21c4..4b18021 100644 --- a/src/imap/mail_view.rs +++ b/src/imap/mail_view.rs @@ -74,7 +74,12 @@ impl<'a> MailView<'a> { MessageDataItemName::Rfc822Size => self.rfc_822_size(), MessageDataItemName::Rfc822Header => self.rfc_822_header(), MessageDataItemName::Rfc822Text => self.rfc_822_text(), - MessageDataItemName::Rfc822 => self.rfc822(), + MessageDataItemName::Rfc822 => { + if self.is_not_yet_seen() { + seen = SeenFlag::MustAdd; + } + self.rfc822() + }, MessageDataItemName::Envelope => Ok(self.envelope()), MessageDataItemName::Body => self.body(), MessageDataItemName::BodyStructure => self.body_structure(), @@ -189,6 +194,11 @@ impl<'a> MailView<'a> { )?)) } + fn is_not_yet_seen(&self) -> bool { + let seen_flag = Flag::Seen.to_string(); + !self.in_idx.flags.iter().any(|x| *x == seen_flag) + } + /// maps to BODY[
]<> and BODY.PEEK[
]<> /// peek does not implicitly set the \Seen flag /// eg. BODY[HEADER.FIELDS (DATE FROM)] @@ -201,8 +211,7 @@ impl<'a> MailView<'a> { ) -> Result<(MessageDataItem<'static>, SeenFlag)> { // Manage Seen flag let mut seen = SeenFlag::DoNothing; - let seen_flag = Flag::Seen.to_string(); - if !peek && !self.in_idx.flags.iter().any(|x| *x == seen_flag) { + if !peek && self.is_not_yet_seen() { // Add \Seen flag //self.mailbox.add_flags(uuid, &[seen_flag]).await?; seen = SeenFlag::MustAdd; diff --git a/src/imap/mailbox_view.rs b/src/imap/mailbox_view.rs index 77fe7f7..3f8389b 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, Result}; +use anyhow::{anyhow, Error, Context, Result}; use futures::stream::{FuturesOrdered, StreamExt}; @@ -130,6 +130,7 @@ 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)); Ok(data) } @@ -400,6 +401,22 @@ impl MailboxView { Ok(Body::Data(Data::Recent(self.recent()?))) } + 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()?) + } + + fn unseen_first(&self) -> Result> { + 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)) + .transpose()?) + } + pub(crate) fn recent(&self) -> Result { let recent = self .0