Revert "Remove libimagmail"
This reverts commit 74045e1800
.
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
This commit is contained in:
parent
27c0a30494
commit
f84cc8169f
7 changed files with 353 additions and 0 deletions
|
@ -34,6 +34,7 @@ members = [
|
|||
"lib/domain/libimagdiary",
|
||||
"lib/domain/libimaghabit",
|
||||
"lib/domain/libimaglog",
|
||||
"lib/domain/libimagmail",
|
||||
"lib/domain/libimagnotes",
|
||||
"lib/domain/libimagtimetrack",
|
||||
"lib/domain/libimagtodo",
|
||||
|
|
14
doc/src/05100-lib-mails.md
Normal file
14
doc/src/05100-lib-mails.md
Normal file
|
@ -0,0 +1,14 @@
|
|||
## libimagmails
|
||||
|
||||
The mail library implements everything that is needed for beeing used to
|
||||
implement a mail reader (MUA).
|
||||
|
||||
It therefor providea reading mailboxes, getting related content or mails, saving
|
||||
attachements to external locations, crafting new mails and responses,...
|
||||
|
||||
It also offers, natively, ways to search for mails (which are represented as
|
||||
imag entries) via tags, categories or even other metadata.
|
||||
|
||||
For more information on the domain of the `imag-mail` command, look at the
|
||||
documentation of the @sec:modules:mails module.
|
||||
|
30
lib/domain/libimagmail/Cargo.toml
Normal file
30
lib/domain/libimagmail/Cargo.toml
Normal file
|
@ -0,0 +1,30 @@
|
|||
[package]
|
||||
name = "libimagmail"
|
||||
version = "0.10.0"
|
||||
authors = ["Matthias Beyer <mail@beyermatthias.de>"]
|
||||
|
||||
description = "Library for the imag core distribution"
|
||||
|
||||
keywords = ["imag", "PIM", "personal", "information", "management"]
|
||||
readme = "../../../README.md"
|
||||
license = "LGPL-2.1"
|
||||
|
||||
documentation = "https://imag-pim.org/doc/"
|
||||
repository = "https://github.com/matthiasbeyer/imag"
|
||||
homepage = "http://imag-pim.org"
|
||||
|
||||
[badges]
|
||||
travis-ci = { repository = "matthiasbeyer/imag" }
|
||||
is-it-maintained-issue-resolution = { repository = "matthiasbeyer/imag" }
|
||||
is-it-maintained-open-issues = { repository = "matthiasbeyer/imag" }
|
||||
maintenance = { status = "actively-developed" }
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.0"
|
||||
email = "0.0.20"
|
||||
filters = "0.3"
|
||||
failure = "0.1"
|
||||
|
||||
libimagstore = { version = "0.10.0", path = "../../../lib/core/libimagstore" }
|
||||
libimagerror = { version = "0.10.0", path = "../../../lib/core/libimagerror" }
|
||||
libimagentryref = { version = "0.10.0", path = "../../../lib/entry/libimagentryref" }
|
1
lib/domain/libimagmail/README.md
Symbolic link
1
lib/domain/libimagmail/README.md
Symbolic link
|
@ -0,0 +1 @@
|
|||
../../../doc/src/05100-lib-mails.md
|
55
lib/domain/libimagmail/src/iter.rs
Normal file
55
lib/domain/libimagmail/src/iter.rs
Normal file
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// imag - the personal information management suite for the commandline
|
||||
// Copyright (C) 2015-2019 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
|
||||
//
|
||||
|
||||
//! 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 failure::Fallible as Result;
|
||||
|
||||
use libimagstore::store::FileLockEntry;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
pub struct MailIter<'a, I: Iterator<Item = FileLockEntry<'a>>> {
|
||||
_marker: PhantomData<I>,
|
||||
i: I,
|
||||
}
|
||||
|
||||
impl<'a, I: Iterator<Item = FileLockEntry<'a>>> MailIter<'a, I> {
|
||||
|
||||
pub fn new(i: I) -> MailIter<'a, I> {
|
||||
MailIter { _marker: PhantomData, i: i }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<'a, I: Iterator<Item = FileLockEntry<'a>>> Iterator for MailIter<'a, I> {
|
||||
type Item = Result<Mail<'a>>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.i.next().map(Mail::from_fle)
|
||||
}
|
||||
|
||||
}
|
||||
|
51
lib/domain/libimagmail/src/lib.rs
Normal file
51
lib/domain/libimagmail/src/lib.rs
Normal file
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// imag - the personal information management suite for the commandline
|
||||
// Copyright (C) 2015-2019 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
|
||||
//
|
||||
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
#![recursion_limit="256"]
|
||||
|
||||
#![deny(
|
||||
dead_code,
|
||||
non_camel_case_types,
|
||||
non_snake_case,
|
||||
path_statements,
|
||||
trivial_numeric_casts,
|
||||
unstable_features,
|
||||
unused_allocation,
|
||||
unused_import_braces,
|
||||
unused_imports,
|
||||
unused_must_use,
|
||||
unused_mut,
|
||||
unused_qualifications,
|
||||
while_true,
|
||||
)]
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
extern crate email;
|
||||
extern crate filters;
|
||||
extern crate failure;
|
||||
|
||||
extern crate libimagerror;
|
||||
extern crate libimagstore;
|
||||
extern crate libimagentryref;
|
||||
|
||||
pub mod iter;
|
||||
pub mod mail;
|
||||
|
201
lib/domain/libimagmail/src/mail.rs
Normal file
201
lib/domain/libimagmail/src/mail.rs
Normal file
|
@ -0,0 +1,201 @@
|
|||
//
|
||||
// imag - the personal information management suite for the commandline
|
||||
// Copyright (C) 2015-2019 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::path::Path;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::fs::OpenOptions;
|
||||
|
||||
use libimagstore::store::Store;
|
||||
use libimagstore::storeid::StoreId;
|
||||
use libimagstore::store::FileLockEntry;
|
||||
use libimagentryref::reference::Ref;
|
||||
use libimagentryref::refstore::RefStore;
|
||||
use libimagentryref::refstore::UniqueRefPathGenerator;
|
||||
use libimagerror::errors::ErrorMsg as EM;
|
||||
|
||||
use email::MimeMessage;
|
||||
use email::results::ParsingResult as EmailParsingResult;
|
||||
|
||||
use failure::Fallible as Result;
|
||||
use failure::ResultExt;
|
||||
use failure::Error;
|
||||
use failure::err_msg;
|
||||
|
||||
struct UniqueMailRefGenerator;
|
||||
impl UniqueRefPathGenerator for UniqueMailRefGenerator {
|
||||
/// The collection the `StoreId` should be created for
|
||||
fn collection() -> &'static str {
|
||||
"mail"
|
||||
}
|
||||
|
||||
/// A function which should generate a unique string for a Path
|
||||
fn unique_hash<A: AsRef<Path>>(path: A) -> Result<String> {
|
||||
use filters::filter::Filter;
|
||||
use email::Header;
|
||||
|
||||
let mut s = String::new();
|
||||
let _ = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(false)
|
||||
.create(false)
|
||||
.open(path)?
|
||||
.read_to_string(&mut s)?;
|
||||
|
||||
MimeMessage::parse(&s)
|
||||
.context(err_msg("Error creating ref"))
|
||||
.map_err(Error::from)
|
||||
.and_then(|mail| {
|
||||
let has_key = |hdr: &Header, exp: &str| hdr.name == exp;
|
||||
|
||||
let subject_filter = |hdr: &Header| has_key(hdr, "Subject");
|
||||
let from_filter = |hdr: &Header| has_key(hdr, "From");
|
||||
let to_filter = |hdr: &Header| has_key(hdr, "To");
|
||||
|
||||
let filter = subject_filter.or(from_filter).or(to_filter);
|
||||
|
||||
let mut v : Vec<String> = vec![];
|
||||
for hdr in mail.headers.iter().filter(|item| filter.filter(item)) {
|
||||
let s = hdr
|
||||
.get_value()
|
||||
.context(err_msg("Ref creation error"))?;
|
||||
|
||||
v.push(s);
|
||||
}
|
||||
let s : String = v.join("");
|
||||
Ok(s)
|
||||
})
|
||||
}
|
||||
|
||||
/// Postprocess the generated `StoreId` object
|
||||
fn postprocess_storeid(sid: StoreId) -> Result<StoreId> {
|
||||
Ok(sid)
|
||||
}
|
||||
}
|
||||
|
||||
struct Buffer(String);
|
||||
|
||||
impl Buffer {
|
||||
pub fn parsed(&self) -> EmailParsingResult<MimeMessage> {
|
||||
MimeMessage::parse(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Buffer {
|
||||
fn from(data: String) -> Buffer {
|
||||
Buffer(data)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Mail<'a>(FileLockEntry<'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> {
|
||||
debug!("Importing Mail from path");
|
||||
store.retrieve_ref::<UniqueMailRefGenerator, P>(p)
|
||||
.and_then(|reference| {
|
||||
debug!("Build reference file: {:?}", reference);
|
||||
reference.get_path()
|
||||
.context(err_msg("Ref handling error"))
|
||||
.map_err(Error::from)
|
||||
.and_then(|path| File::open(path).context(EM::IO).map_err(Error::from))
|
||||
.and_then(|mut file| {
|
||||
let mut s = String::new();
|
||||
file.read_to_string(&mut s)
|
||||
.map(|_| s)
|
||||
.context(EM::IO)
|
||||
.map_err(Error::from)
|
||||
})
|
||||
.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>> {
|
||||
debug!("Opening Mail by Hash");
|
||||
store.get_ref::<UniqueMailRefGenerator, S>(hash)
|
||||
.context(err_msg("Fetch by hash error"))
|
||||
.context(err_msg("Fetch error"))
|
||||
.map_err(Error::from)
|
||||
.and_then(|o| match o {
|
||||
Some(r) => Mail::from_fle(r).map(Some),
|
||||
None => Ok(None),
|
||||
})
|
||||
}
|
||||
|
||||
/// Implement me as TryFrom as soon as it is stable
|
||||
pub fn from_fle(fle: FileLockEntry<'a>) -> Result<Mail<'a>> {
|
||||
fle.get_path()
|
||||
.context(err_msg("Ref handling error"))
|
||||
.map_err(Error::from)
|
||||
.and_then(|path| File::open(path).context(EM::IO).map_err(Error::from))
|
||||
.and_then(|mut file| {
|
||||
let mut s = String::new();
|
||||
file.read_to_string(&mut s)
|
||||
.map(|_| s)
|
||||
.context(EM::IO)
|
||||
.map_err(Error::from)
|
||||
})
|
||||
.map(Buffer::from)
|
||||
.map(|buffer| Mail(fle, buffer))
|
||||
}
|
||||
|
||||
pub fn get_field(&self, field: &str) -> Result<Option<String>> {
|
||||
debug!("Getting field in mail: {:?}", field);
|
||||
self.1
|
||||
.parsed()
|
||||
.context(err_msg("Mail parsing error"))
|
||||
.map_err(Error::from)
|
||||
.map(|parsed| {
|
||||
parsed.headers
|
||||
.iter()
|
||||
.filter(|hdr| hdr.name == field)
|
||||
.nth(0)
|
||||
.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")
|
||||
}
|
||||
|
||||
pub fn fle(&self) -> &FileLockEntry<'a> {
|
||||
&self.0
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue