Merge pull request #657 from matthiasbeyer/libimagmail/init
Libimagmail/init
This commit is contained in:
commit
1d3666eef4
8 changed files with 283 additions and 1 deletions
21
libimagmail/Cargo.toml
Normal file
21
libimagmail/Cargo.toml
Normal file
|
@ -0,0 +1,21 @@
|
|||
[package]
|
||||
name = "libimagmail"
|
||||
version = "0.2.0"
|
||||
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
||||
|
||||
[dependencies]
|
||||
log = "0.3"
|
||||
mailparse = "0.2.0"
|
||||
semver = "0.2"
|
||||
toml = "0.2.*"
|
||||
filters = "0.1.0"
|
||||
|
||||
[dependencies.libimagstore]
|
||||
path = "../libimagstore"
|
||||
|
||||
[dependencies.libimagerror]
|
||||
path = "../libimagerror"
|
||||
|
||||
[dependencies.libimagref]
|
||||
path = "../libimagref"
|
||||
|
16
libimagmail/src/error.rs
Normal file
16
libimagmail/src/error.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
generate_error_module!(
|
||||
generate_error_types!(MailError, MailErrorKind,
|
||||
RefCreationError => "Error creating a reference to a file/directory",
|
||||
RefHandlingError => "Error while handling the internal reference object",
|
||||
MailParsingError => "Error while parsing mail",
|
||||
|
||||
FetchByHashError => "Error fetching mail from Store by hash",
|
||||
FetchError => "Error fetching mail from Store",
|
||||
IOError => "IO Error"
|
||||
);
|
||||
);
|
||||
|
||||
pub use self::error::MailError;
|
||||
pub use self::error::MailErrorKind;
|
||||
pub use self::error::MapErrInto;
|
||||
|
64
libimagmail/src/hasher.rs
Normal file
64
libimagmail/src/hasher.rs
Normal file
|
@ -0,0 +1,64 @@
|
|||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use mailparse::{MailHeader, parse_mail};
|
||||
|
||||
use libimagref::hasher::Hasher;
|
||||
use libimagref::hasher::DefaultHasher;
|
||||
use libimagref::error::RefErrorKind as REK;
|
||||
use libimagref::error::MapErrInto;
|
||||
use libimagref::result::Result as RResult;
|
||||
use libimagerror::into::IntoError;
|
||||
|
||||
use error::MailErrorKind as MEK;
|
||||
|
||||
pub struct MailHasher {
|
||||
defaulthasher: DefaultHasher,
|
||||
}
|
||||
|
||||
impl MailHasher {
|
||||
|
||||
pub fn new() -> MailHasher {
|
||||
MailHasher { defaulthasher: DefaultHasher::new() }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl Hasher for MailHasher {
|
||||
|
||||
fn hash_name(&self) -> &'static str {
|
||||
"default_mail_hasher"
|
||||
}
|
||||
|
||||
fn create_hash<R: Read>(&mut self, pb: &PathBuf, c: &mut R) -> RResult<String> {
|
||||
use filters::filter::Filter;
|
||||
|
||||
let mut s = String::new();
|
||||
try!(c.read_to_string(&mut s).map_err_into(REK::UTF8Error).map_err_into(REK::IOError));
|
||||
|
||||
parse_mail(&s.as_bytes())
|
||||
.map_err(Box::new)
|
||||
.map_err(|e| MEK::MailParsingError.into_error_with_cause(e))
|
||||
.map_err_into(REK::RefHashingError)
|
||||
.and_then(|mail| {
|
||||
let has_key = |hdr: &MailHeader, exp: &str|
|
||||
hdr.get_key().map(|s| s == exp).unwrap_or(false);
|
||||
|
||||
let subject_filter = |hdr: &MailHeader| has_key(hdr, "Subject");
|
||||
let from_filter = |hdr: &MailHeader| has_key(hdr, "From");
|
||||
let to_filter = |hdr: &MailHeader| has_key(hdr, "To");
|
||||
|
||||
let filter = subject_filter.or(from_filter).or(to_filter);
|
||||
|
||||
let s : String = mail.headers
|
||||
.iter()
|
||||
.filter(|item| filter.filter(item))
|
||||
.filter_map(|hdr| hdr.get_value().ok()) // TODO: Do not hide error here
|
||||
.collect::<Vec<String>>()
|
||||
.join("");
|
||||
|
||||
self.defaulthasher.create_hash(pb, &mut s.as_bytes())
|
||||
})
|
||||
}
|
||||
|
||||
}
|
37
libimagmail/src/iter.rs
Normal file
37
libimagmail/src/iter.rs
Normal file
|
@ -0,0 +1,37 @@
|
|||
//! Module for the MailIter
|
||||
//!
|
||||
//! MailIter is a iterator which takes an Iterator that yields `Ref` and yields itself
|
||||
//! `Result<Mail>`, where `Err(_)` is returned if the Ref is not a Mail or parsing of the
|
||||
//! referenced mail file failed.
|
||||
//!
|
||||
|
||||
use mail::Mail;
|
||||
use result::Result;
|
||||
|
||||
use libimagref::reference::Ref;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
struct MailIter<'a, I: 'a + Iterator<Item = Ref<'a>>> {
|
||||
_marker: PhantomData<&'a I>,
|
||||
i: I,
|
||||
}
|
||||
|
||||
impl<'a, I: Iterator<Item = Ref<'a>>> MailIter<'a, I> {
|
||||
|
||||
pub fn new(i: I) -> MailIter<'a, I> {
|
||||
MailIter { _marker: PhantomData, i: i }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<'a, I: Iterator<Item = Ref<'a>>> Iterator for MailIter<'a, I> {
|
||||
|
||||
type Item = Result<Mail<'a>>;
|
||||
|
||||
fn next(&mut self) -> Option<Result<Mail<'a>>> {
|
||||
self.i.next().map(Mail::from_ref)
|
||||
}
|
||||
|
||||
}
|
||||
|
16
libimagmail/src/lib.rs
Normal file
16
libimagmail/src/lib.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
#[macro_use] extern crate log;
|
||||
extern crate mailparse;
|
||||
extern crate semver;
|
||||
extern crate toml;
|
||||
extern crate filters;
|
||||
|
||||
#[macro_use] extern crate libimagerror;
|
||||
extern crate libimagstore;
|
||||
extern crate libimagref;
|
||||
|
||||
pub mod error;
|
||||
pub mod hasher;
|
||||
pub mod iter;
|
||||
pub mod mail;
|
||||
pub mod result;
|
||||
|
120
libimagmail/src/mail.rs
Normal file
120
libimagmail/src/mail.rs
Normal file
|
@ -0,0 +1,120 @@
|
|||
use std::result::Result as RResult;
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
|
||||
use libimagstore::store::{FileLockEntry, Store};
|
||||
use libimagref::reference::Ref;
|
||||
use libimagref::flags::RefFlags;
|
||||
|
||||
use mailparse::{MailParseError, ParsedMail, parse_mail};
|
||||
|
||||
use hasher::MailHasher;
|
||||
use result::Result;
|
||||
use error::{MapErrInto, MailErrorKind as MEK};
|
||||
|
||||
struct Buffer(String);
|
||||
|
||||
impl Buffer {
|
||||
pub fn parsed<'a>(&'a self) -> RResult<ParsedMail<'a>, MailParseError> {
|
||||
parse_mail(self.0.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Buffer {
|
||||
fn from(data: String) -> Buffer {
|
||||
Buffer(data)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Mail<'a>(Ref<'a>, Buffer);
|
||||
|
||||
impl<'a> Mail<'a> {
|
||||
|
||||
/// Imports a mail from the Path passed
|
||||
pub fn import_from_path<P: AsRef<Path>>(store: &Store, p: P) -> Result<Mail> {
|
||||
let h = MailHasher::new();
|
||||
let f = RefFlags::default().with_content_hashing(true).with_permission_tracking(false);
|
||||
let p = PathBuf::from(p.as_ref());
|
||||
|
||||
Ref::create_with_hasher(store, p, f, h)
|
||||
.map_err_into(MEK::RefCreationError)
|
||||
.and_then(|reference| {
|
||||
reference.fs_file()
|
||||
.map_err_into(MEK::RefHandlingError)
|
||||
.and_then(|path| File::open(path).map_err_into(MEK::IOError))
|
||||
.and_then(|mut file| {
|
||||
let mut s = String::new();
|
||||
file.read_to_string(&mut s)
|
||||
.map(|_| s)
|
||||
.map_err_into(MEK::IOError)
|
||||
})
|
||||
.map(Buffer::from)
|
||||
.map(|buffer| Mail(reference, buffer))
|
||||
})
|
||||
}
|
||||
|
||||
/// Opens a mail by the passed hash
|
||||
pub fn open<S: AsRef<str>>(store: &Store, hash: S) -> Result<Option<Mail>> {
|
||||
Ref::get_by_hash(store, String::from(hash.as_ref()))
|
||||
.map_err_into(MEK::FetchByHashError)
|
||||
.map_err_into(MEK::FetchError)
|
||||
.and_then(|o| match o {
|
||||
Some(r) => Mail::from_ref(r).map(Some),
|
||||
None => Ok(None),
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
/// Implement me as TryFrom as soon as it is stable
|
||||
pub fn from_ref(r: Ref<'a>) -> Result<Mail> {
|
||||
r.fs_file()
|
||||
.map_err_into(MEK::RefHandlingError)
|
||||
.and_then(|path| File::open(path).map_err_into(MEK::IOError))
|
||||
.and_then(|mut file| {
|
||||
let mut s = String::new();
|
||||
file.read_to_string(&mut s)
|
||||
.map(|_| s)
|
||||
.map_err_into(MEK::IOError)
|
||||
})
|
||||
.map(Buffer::from)
|
||||
.map(|buffer| Mail(r, buffer))
|
||||
}
|
||||
|
||||
pub fn get_field(&self, field: &str) -> Result<Option<String>> {
|
||||
use mailparse::MailHeader;
|
||||
|
||||
self.1
|
||||
.parsed()
|
||||
.map_err_into(MEK::MailParsingError)
|
||||
.map(|parsed| {
|
||||
parsed.headers
|
||||
.iter()
|
||||
.filter(|hdr| hdr.get_key().map(|n| n == field).unwrap_or(false))
|
||||
.next()
|
||||
.and_then(|field| field.get_value().ok())
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_from(&self) -> Result<Option<String>> {
|
||||
self.get_field("From")
|
||||
}
|
||||
|
||||
pub fn get_to(&self) -> Result<Option<String>> {
|
||||
self.get_field("To")
|
||||
}
|
||||
|
||||
pub fn get_subject(&self) -> Result<Option<String>> {
|
||||
self.get_field("Subject")
|
||||
}
|
||||
|
||||
pub fn get_message_id(&self) -> Result<Option<String>> {
|
||||
self.get_field("Message-ID")
|
||||
}
|
||||
|
||||
pub fn get_in_reply_to(&self) -> Result<Option<String>> {
|
||||
self.get_field("In-Reply-To")
|
||||
}
|
||||
|
||||
}
|
6
libimagmail/src/result.rs
Normal file
6
libimagmail/src/result.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
use std::result::Result as RResult;
|
||||
|
||||
use error::MailError;
|
||||
|
||||
pub type Result<T> = RResult<T, MailError>;
|
||||
|
|
@ -41,7 +41,9 @@ generate_error_module!(
|
|||
RefTargetPermissionError => "Ref Target permissions insufficient for referencing",
|
||||
RefTargetCannotBeHashed => "Ref Target cannot be hashed (is it a directory?)",
|
||||
RefTargetFileCannotBeOpened => "Ref Target File cannot be open()ed",
|
||||
RefTargetCannotReadPermissions => "Ref Target: Cannot read permissions"
|
||||
RefTargetCannotReadPermissions => "Ref Target: Cannot read permissions",
|
||||
|
||||
RefHashingError => "Error while hashing"
|
||||
);
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in a new issue