summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2020-01-03 14:02:43 +0100
committerMatthias Beyer <mail@beyermatthias.de>2020-01-03 14:02:43 +0100
commitb789a971c0170faf322f4d62476cc8edf7e4b1d6 (patch)
tree7401d8af7106deb6bf660f6bdaf9df79cee390bd
parent0122e59bb073a4bee0e74f6d1e09c32e077dc249 (diff)
parent7b4556c190656537e473deb435124d030948298b (diff)
Merge branch 'libimagmail/flags' into master
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r--lib/domain/libimagmail/src/lib.rs1
-rw-r--r--lib/domain/libimagmail/src/mail.rs69
-rw-r--r--lib/domain/libimagmail/src/mailflags.rs93
3 files changed, 162 insertions, 1 deletions
diff --git a/lib/domain/libimagmail/src/lib.rs b/lib/domain/libimagmail/src/lib.rs
index b3d5785b..2334a74f 100644
--- a/lib/domain/libimagmail/src/lib.rs
+++ b/lib/domain/libimagmail/src/lib.rs
@@ -56,6 +56,7 @@ module_entry_path_mod!("mail");
pub mod config;
pub mod hasher;
pub mod mail;
+pub mod mailflags;
pub mod mid;
pub mod store;
pub mod util;
diff --git a/lib/domain/libimagmail/src/mail.rs b/lib/domain/libimagmail/src/mail.rs
index 1d2f5a2d..db75b5d3 100644
--- a/lib/domain/libimagmail/src/mail.rs
+++ b/lib/domain/libimagmail/src/mail.rs
@@ -17,6 +17,8 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
+use std::str::FromStr;
+
use failure::Fallible as Result;
use failure::ResultExt;
use failure::Error;
@@ -29,6 +31,8 @@ use libimagentryref::reference::Config as RefConfig;
use libimagentryref::reference::{Ref, RefFassade};
use crate::mid::MessageId;
+use crate::mailflags::MailFlag;
+use crate::hasher::MailHasher;
provide_kindflag_path!(pub IsMail, "mail.is_mail");
@@ -40,6 +44,14 @@ pub trait Mail : RefFassade {
fn get_subject(&self, refconfig: &RefConfig) -> Result<Option<String>>;
fn get_message_id(&self, refconfig: &RefConfig) -> Result<Option<MessageId>>;
fn get_in_reply_to(&self, refconfig: &RefConfig) -> Result<Option<MessageId>>;
+
+ fn flags(&self, refconfig: &RefConfig) -> Result<Vec<MailFlag>>;
+ fn is_passed(&self, refconfig: &RefConfig) -> Result<bool>;
+ fn is_replied(&self, refconfig: &RefConfig) -> Result<bool>;
+ fn is_seen(&self, refconfig: &RefConfig) -> Result<bool>;
+ fn is_trashed(&self, refconfig: &RefConfig) -> Result<bool>;
+ fn is_draft(&self, refconfig: &RefConfig) -> Result<bool>;
+ fn is_flagged(&self, refconfig: &RefConfig) -> Result<bool>;
}
impl Mail for Entry {
@@ -51,7 +63,6 @@ impl Mail for Entry {
/// Get a value of a single field of the mail file
fn get_field(&self, refconfig: &RefConfig, field: &str) -> Result<Option<String>> {
use std::fs::read_to_string;
- use crate::hasher::MailHasher;
debug!("Getting field in mail: {:?}", field);
let mail_file_location = self.as_ref_with_hasher::<MailHasher>().get_path(refconfig)?;
@@ -134,6 +145,62 @@ impl Mail for Entry {
.map(|o| o.map(crate::util::strip_message_delimiters).map(MessageId::from))
}
+ /// Get the flags of the message
+ fn flags(&self, refconfig: &RefConfig) -> Result<Vec<MailFlag>> {
+ let path = self.as_ref_with_hasher::<MailHasher>().get_path(refconfig)?;
+
+ if !path.exists() {
+ return Err(format_err!("Path {} does not exist", path.display()))
+ }
+
+ {
+ // Now parse mail flags
+ path.to_str()
+ .ok_or_else(|| format_err!("Path is not UTF-8: {}", path.display()))?
+ .split("2,")
+ .map(String::from)
+ .collect::<Vec<String>>()
+ .split_last()
+ .ok_or_else(|| format_err!("Splitting path into prefix and flags failed: {}", path.display()))?
+ .0
+ .chars()
+ .map(|c| c.to_string())
+ .map(|c| MailFlag::from_str(&c))
+ .collect::<Result<Vec<_>>>()
+ }
+ }
+
+ /// Check whether the mail is passed
+ fn is_passed(&self, refconfig: &RefConfig) -> Result<bool> {
+ self.flags(refconfig).map(|fs| fs.into_iter().any(|f| MailFlag::Passed == f))
+ }
+
+ /// Check whether the mail is replied
+ fn is_replied(&self, refconfig: &RefConfig) -> Result<bool> {
+ self.flags(refconfig).map(|fs| fs.into_iter().any(|f| MailFlag::Replied == f))
+ }
+
+ /// Check whether the mail is seen
+ fn is_seen(&self, refconfig: &RefConfig) -> Result<bool> {
+ self.flags(refconfig).map(|fs| fs.into_iter().any(|f| MailFlag::Seen == f))
+ }
+
+ /// Check whether the mail is trashed
+ fn is_trashed(&self, refconfig: &RefConfig) -> Result<bool> {
+ self.flags(refconfig).map(|fs| fs.into_iter().any(|f| MailFlag::Trashed == f))
+ }
+
+ /// Check whether the mail is draft
+ fn is_draft(&self, refconfig: &RefConfig) -> Result<bool> {
+ self.flags(refconfig).map(|fs| fs.into_iter().any(|f| MailFlag::Draft == f))
+ }
+
+ /// Check whether the mail is flagged
+ fn is_flagged(&self, refconfig: &RefConfig) -> Result<bool> {
+ self.flags(refconfig).map(|fs| fs.into_iter().any(|f| MailFlag::Flagged == f))
+ }
+
+
}
#[derive(Debug)]
diff --git a/lib/domain/libimagmail/src/mailflags.rs b/lib/domain/libimagmail/src/mailflags.rs
new file mode 100644
index 00000000..5fd52761
--- /dev/null
+++ b/lib/domain/libimagmail/src/mailflags.rs
@@ -0,0 +1,93 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015-2020 Matthias Beyer <mail@beyermatthias.de> and contributors
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; version
+// 2.1 of the License.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+//
+
+use std::fmt::{Display, Result as FmtResult, Formatter};
+use std::str::FromStr;
+
+use failure::Fallible as Result;
+use failure::Error;
+
+/// Message flags
+///
+/// As defined by https://cr.yp.to/proto/maildir.html with strong typing
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum MailFlag {
+ /// Flag "P" (passed): the user has resent/forwarded/bounced this message to someone else.
+ Passed,
+
+ /// Flag "R" (replied): the user has replied to this message.
+ Replied,
+
+ /// Flag "S" (seen): the user has viewed this message, though perhaps he didn't read all the way through it.
+ Seen,
+
+ /// Flag "T" (trashed): the user has moved this message to the trash; the trash will be emptied by a later user action.
+ Trashed,
+
+ /// Flag "D" (draft): the user considers this message a draft; toggled at user discretion.
+ Draft,
+
+ /// Flag "F" (flagged): user-defined flag; toggled at user discretion.
+ Flagged,
+}
+
+impl MailFlag {
+ pub fn as_char(self) -> char {
+ match self {
+ MailFlag::Passed => 'P',
+ MailFlag::Replied => 'R',
+ MailFlag::Seen => 'S',
+ MailFlag::Trashed => 'T',
+ MailFlag::Draft => 'D',
+ MailFlag::Flagged => 'F',
+ }
+ }
+}
+
+impl FromStr for MailFlag {
+ type Err = Error;
+
+ fn from_str(s: &str) -> Result<MailFlag> {
+ match s {
+ "P" => Ok(MailFlag::Passed),
+ "R" => Ok(MailFlag::Replied),
+ "S" => Ok(MailFlag::Seen),
+ "T" => Ok(MailFlag::Trashed),
+ "D" => Ok(MailFlag::Draft),
+ "F" => Ok(MailFlag::Flagged),
+ _ => Err(format_err!("Unknown message flag: '{}'", s)),
+ }
+ }
+}
+
+impl Display for MailFlag {
+ fn fmt(&self, f: &mut Formatter) -> FmtResult {
+ let s = match self {
+ MailFlag::Passed => "Passed",
+ MailFlag::Replied => "Replied",
+ MailFlag::Seen => "Seen",
+ MailFlag::Trashed => "Trashed",
+ MailFlag::Draft => "Draft",
+ MailFlag::Flagged => "Flagged",
+ };
+
+ write!(f, "{}", s)
+ }
+}
+