summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2020-01-05 16:10:41 +0100
committerMatthias Beyer <mail@beyermatthias.de>2020-01-05 16:11:27 +0100
commit5944284b7c6023dea95190c75507c50129bc7824 (patch)
tree4c6b60fb49aa830ed72e72495f60a9938c36afb6
parent56a85113b7bfb89ca22180f0923bf8cd30515daf (diff)
WIP: Add function to parse mail and make data accessible
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r--lib/domain/libimagmail/Cargo.toml2
-rw-r--r--lib/domain/libimagmail/src/mail.rs110
2 files changed, 111 insertions, 1 deletions
diff --git a/lib/domain/libimagmail/Cargo.toml b/lib/domain/libimagmail/Cargo.toml
index 96c9ae90..4d75d7e0 100644
--- a/lib/domain/libimagmail/Cargo.toml
+++ b/lib/domain/libimagmail/Cargo.toml
@@ -23,7 +23,7 @@ maintenance = { status = "actively-developed" }
log = "0.4.6"
toml = "0.5.1"
toml-query = "0.9.2"
-mailparse = "0.8.0"
+mailparse = "0.10"
filters = "0.3.0"
failure = "0.1.5"
resiter = "0.4.0"
diff --git a/lib/domain/libimagmail/src/mail.rs b/lib/domain/libimagmail/src/mail.rs
index dc7b3c0d..de3d8827 100644
--- a/lib/domain/libimagmail/src/mail.rs
+++ b/lib/domain/libimagmail/src/mail.rs
@@ -18,11 +18,17 @@
//
use std::path::PathBuf;
+use std::fs::OpenOptions;
+use std::io::Read;
+use std::fmt::{Debug, Result as FmtResult, Formatter};
use failure::Fallible as Result;
use failure::Error;
use toml_query::read::TomlValueReadTypeExt;
use chrono::NaiveDateTime;
+use mailparse::ParsedMail as MPParsedMail;
+use resiter::Filter;
+use resiter::AndThen;
use libimagstore::store::Entry;
use libimagentryutil::isa::IsKindHeaderPathProvider;
@@ -140,4 +146,108 @@ impl<'a> LoadedMail<'a> {
})
}
+ // Parsing the actual mail file for further processing
+ pub fn parsed(&'a self) -> Result<ParsedMail<'a>> {
+ let mut buffer = Vec::with_capacity(4096);
+ OpenOptions::new()
+ .read(true)
+ .open(self.get_filename())?
+ .read_to_end(&mut buffer)?;
+
+ Ok(ParsedMail {
+ loaded: self,
+ raw_data: buffer,
+ parsed: mailparse::parse_mail(&buffer)?,
+ })
+ }
+}
+
+pub struct ParsedMail<'a> {
+ loaded: &'a LoadedMail<'a>,
+ raw_data: Vec<u8>,
+ parsed: MPParsedMail<'a>,
+}
+
+impl<'a> Debug for ParsedMail<'a> {
+ fn fmt(&self, f: &mut Formatter) -> FmtResult {
+ write!(f, "ParsedMail {{ {:?}, ... }}", self.loaded)
+ }
+}
+
+impl<'a> ParsedMail<'a> {
+
+ pub fn get_keys(&self) -> Result<Vec<String>> {
+ self.parsed
+ .headers
+ .iter()
+ .map(|hdr| hdr.get_key().map_err(Error::from))
+ .collect()
+ }
+
+ pub fn get_values(&self) -> Result<Vec<String>> {
+ self.parsed
+ .headers
+ .iter()
+ .map(|hdr| hdr.get_value().map_err(Error::from))
+ .collect()
+ }
+
+ pub fn get(&self, key: &str) -> Result<Option<String>> {
+ self.parsed
+ .headers
+ .iter()
+ .map(|hdr| hdr.get_key().map_err(Error::from).map(|k| (k == key, hdr)))
+ .filter_ok(|tpl| tpl.0)
+ .and_then_ok(|tpl| tpl.1.get_value().map_err(Error::from))
+ .next()
+ .transpose()
+ }
+
+ pub fn body(&self) -> Result<String> {
+ self.parsed.get_body().map_err(Error::from)
+ }
+
+ pub fn subject(&self) -> Result<Option<String>> {
+ self.get("Subject")
+ }
+
+ pub fn message_id(&self) -> Result<Option<String>> {
+ self.get("Message-Id")
+ }
+
+ pub fn from(&self) -> Result<Option<String>> {
+ self.get("From")
+ }
+
+ pub fn to(&self) -> Result<Option<String>> {
+ self.get("To")
+ }
+
+ pub fn cc(&self) -> Result<Option<String>> {
+ self.get("Cc")
+ }
+
+ pub fn bcc(&self) -> Result<Option<String>> {
+ self.get("bcc")
+ }
+
+ pub fn in_reply_to(&self) -> Result<Option<String>> {
+ self.get("In-Reply-To")
+ }
+
+ pub fn user_agent(&self) -> Result<Option<String>> {
+ self.get("User-Agent")
+ }
+
+ pub fn reply_to(&self) -> Result<Option<String>> {
+ self.get("Reply-To")
+ }
+
+ pub fn date(&self) -> Result<Option<String>> {
+ self.get("Date")
+ }
+
+ pub fn references(&self) -> Result<Option<String>> {
+ self.get("References")
+ }
}