diff --git a/Cargo.toml b/Cargo.toml index 643fc62..6cd0147 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ native-tls = { version = "0.2.2", optional = true } rustls-connector = { version = "0.16.1", optional = true } regex = "1.0" bufstream = "0.1.3" -imap-proto = "0.15.0" +imap-proto = "0.16.0" nom = { version = "7.1.0", default-features = false } base64 = "0.13" chrono = { version = "0.4", default-features = false, features = ["std"]} diff --git a/src/parse.rs b/src/parse.rs index 0df2a0a..32ddccc 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -417,7 +417,7 @@ mod tests { let first = names.get(0).unwrap(); assert_eq!( first.attributes(), - &[NameAttribute::from("\\HasNoChildren")] + &[NameAttribute::Extension(Cow::Borrowed("\\HasNoChildren"))] ); assert_eq!(first.delimiter(), Some(".")); assert_eq!(first.name(), "INBOX"); @@ -507,7 +507,7 @@ mod tests { let first = names.get(0).unwrap(); assert_eq!( first.attributes(), - &[NameAttribute::from("\\HasNoChildren")] + &[NameAttribute::Extension(Cow::Borrowed("\\HasNoChildren"))] ); assert_eq!(first.delimiter(), Some(".")); assert_eq!(first.name(), "INBOX"); diff --git a/src/types/fetch.rs b/src/types/fetch.rs index 8ea6370..417da00 100644 --- a/src/types/fetch.rs +++ b/src/types/fetch.rs @@ -219,6 +219,17 @@ impl<'a> Fetch<'a> { }) } + /// Extract the `X-GM-LABELS` of a `FETCH` response + /// + /// This is a Gmail-specific extension. See their + /// [developer's page](https://developers.google.com/gmail/imap/imap-extensions) for details. + pub fn gmail_labels(&'a self) -> Option> { + self.fetch.iter().find_map(|av| match av { + AttributeValue::GmailLabels(labels) => Some(labels.iter().map(|cow| cow.as_ref())), + _ => None, + }) + } + /// Get an owned copy of the [`Fetch`]. pub fn into_owned(self) -> Fetch<'static> { Fetch { diff --git a/src/types/mod.rs b/src/types/mod.rs index ba04668..0e6438d 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -113,7 +113,7 @@ mod mailbox; pub use self::mailbox::Mailbox; mod name; -pub use self::name::{Name, NameAttribute, Names}; +pub use self::name::{Name, Names}; mod capabilities; pub use self::capabilities::Capabilities; diff --git a/src/types/name.rs b/src/types/name.rs index e9808fd..70918c9 100644 --- a/src/types/name.rs +++ b/src/types/name.rs @@ -1,7 +1,7 @@ use crate::error::Error; use crate::parse::{parse_many_into, MapOrNot}; use crate::types::UnsolicitedResponse; -use imap_proto::{MailboxDatum, Response}; +use imap_proto::{MailboxDatum, NameAttribute, Response}; use ouroboros::self_referencing; use std::borrow::Cow; use std::slice::Iter; @@ -28,11 +28,11 @@ impl Names { let mut names = Vec::new(); parse_many_into(input, &mut names, unsolicited, |response| match response { Response::MailboxData(MailboxDatum::List { - flags, + name_attributes, delimiter, name, }) => Ok(MapOrNot::Map(Name { - attributes: flags.into_iter().map(NameAttribute::from).collect(), + attributes: name_attributes, delimiter, name, })), @@ -73,84 +73,6 @@ pub struct Name<'a> { pub(crate) name: Cow<'a, str>, } -/// An attribute set for an IMAP name. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] -pub enum NameAttribute<'a> { - /// It is not possible for any child levels of hierarchy to exist - /// under this name; no child levels exist now and none can be - /// created in the future. - NoInferiors, - - /// It is not possible to use this name as a selectable mailbox. - NoSelect, - - /// The mailbox has been marked "interesting" by the server; the - /// mailbox probably contains messages that have been added since - /// the last time the mailbox was selected. - Marked, - - /// The mailbox does not contain any additional messages since the - /// last time the mailbox was selected. - Unmarked, - - /// A non-standard user- or server-defined name attribute. - Custom(Cow<'a, str>), -} - -impl NameAttribute<'static> { - fn system(s: &str) -> Option { - match s { - "\\Noinferiors" => Some(NameAttribute::NoInferiors), - "\\Noselect" => Some(NameAttribute::NoSelect), - "\\Marked" => Some(NameAttribute::Marked), - "\\Unmarked" => Some(NameAttribute::Unmarked), - _ => None, - } - } -} - -impl<'a> NameAttribute<'a> { - fn into_owned(self) -> NameAttribute<'static> { - match self { - NameAttribute::NoInferiors => NameAttribute::NoInferiors, - NameAttribute::NoSelect => NameAttribute::NoSelect, - NameAttribute::Marked => NameAttribute::Marked, - NameAttribute::Unmarked => NameAttribute::Unmarked, - NameAttribute::Custom(cow) => NameAttribute::Custom(Cow::Owned(cow.into_owned())), - } - } -} - -impl<'a> From for NameAttribute<'a> { - fn from(s: String) -> Self { - if let Some(f) = NameAttribute::system(&s) { - f - } else { - NameAttribute::Custom(Cow::Owned(s)) - } - } -} - -impl<'a> From> for NameAttribute<'a> { - fn from(s: Cow<'a, str>) -> Self { - if let Some(f) = NameAttribute::system(&*s) { - f - } else { - NameAttribute::Custom(s) - } - } -} - -impl<'a> From<&'a str> for NameAttribute<'a> { - fn from(s: &'a str) -> Self { - if let Some(f) = NameAttribute::system(s) { - f - } else { - NameAttribute::Custom(Cow::Borrowed(s)) - } - } -} - impl<'a> Name<'a> { /// Attributes of this name. pub fn attributes(&self) -> &[NameAttribute<'a>] {