#![forbid(unsafe_code)]
#![deny(
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,
)]
extern crate clap;
#[macro_use] extern crate log;
#[macro_use] extern crate failure;
extern crate toml_query;
#[macro_use] extern crate indoc;
extern crate resiter;
extern crate libimagrt;
extern crate libimagmail;
extern crate libimagerror;
extern crate libimagstore;
extern crate libimagutil;
extern crate libimagentryref;
use std::io::Write;
use std::path::PathBuf;
use failure::Fallible as Result;
use failure::err_msg;
use failure::Error;
use toml_query::read::TomlValueReadTypeExt;
use clap::App;
use resiter::AndThen;
use resiter::IterInnerOkOrElse;
use libimagmail::mail::Mail;
use libimagmail::store::MailStore;
use libimagmail::util;
use libimagentryref::reference::{Ref, RefFassade};
use libimagentryref::util::get_ref_config;
use libimagrt::runtime::Runtime;
use libimagrt::application::ImagApplication;
use libimagutil::info_result::*;
use libimagstore::store::FileLockEntry;
use libimagstore::storeid::StoreIdIterator;
use libimagstore::iter::get::StoreIdGetIteratorExtension;
mod ui;
pub enum ImagMail {}
impl ImagApplication for ImagMail {
fn run(rt: Runtime) -> Result<()> {
match rt.cli().subcommand_name().ok_or_else(|| err_msg("No subcommand called"))? {
"import-mail" => import_mail(&rt),
"list" => list(&rt),
"mail-store" => mail_store(&rt),
other => {
debug!("Unknown command");
if rt.handle_unknown_subcommand("imag-mail", other, rt.cli())?.success() {
Ok(())
} else {
Err(err_msg("Failed to handle unknown subcommand"))
}
},
}
}
fn build_cli<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
ui::build_ui(app)
}
fn name() -> &'static str {
env!("CARGO_PKG_NAME")
}
fn description() -> &'static str {
"Mail collection tool"
}
fn version() -> &'static str {
env!("CARGO_PKG_VERSION")
}
}
fn import_mail(rt: &Runtime) -> Result<()> {
let collection_name = get_ref_collection_name(rt)?;
let refconfig = get_ref_config(rt, "imag-mail")?;
let scmd = rt.cli().subcommand_matches("import-mail").unwrap();
let store = rt.store();
debug!(r#"Importing mail with
collection_name = {}
refconfig = {:?}
"#, collection_name, refconfig);
scmd.values_of("path")
.unwrap() .map(PathBuf::from)
.map(|path| {
if scmd.is_present("ignore-existing-ids") {
store.retrieve_mail_from_path(path, &collection_name, &refconfig)
} else {
store.create_mail_from_path(path, &collection_name, &refconfig)
}
.map_info_str("Ok")
})
.and_then_ok(|e| rt.report_touched(e.get_location()).map_err(Error::from))
.collect::<Result<Vec<()>>>()
.map(|_| ())
}
fn list(rt: &Runtime) -> Result<()> {
let refconfig = get_ref_config(rt, "imag-mail")?;
let scmd = rt.cli().subcommand_matches("list").unwrap(); let print_content = scmd.is_present("list-read");
if print_content {
warn!("{}", indoc!(r#"You requested to print the content of the mail as well.
We use the 'mailparse' crate underneath, but its implementation is nonoptimal.
Thus, the content might be printed as empty (no text in the email)
This is not reliable and might be wrong."#));
}
fn list_mail<'a>(rt: &Runtime,
refconfig: &::libimagentryref::reference::Config,
m: &FileLockEntry<'a>,
print_content: bool) -> Result<()> {
let id = match m.get_message_id(&refconfig)? {
Some(f) => f,
None => "<no id>".to_owned(),
};
let from = match m.get_from(&refconfig)? {
Some(f) => f,
None => "<no from>".to_owned(),
};
let to = match m.get_to(&refconfig)? {
Some(f) => f,
None => "<no to>".to_owned(),
};
let subject = match m.get_subject(&refconfig)? {
Some(f) => f,
None => "<no subject>".to_owned(),
};
if print_content {
use libimagmail::hasher::MailHasher;
let content = m.as_ref_with_hasher::<MailHasher>()
.get_path(&refconfig)
.and_then(util::get_mail_text_content)?;
writeln!(rt.stdout(),
"Mail: {id}\nFrom: {from}\nTo: {to}\n{subj}\n---\n{content}\n---\n",
from = from,
id = id,
subj = subject,
to = to,
content = content
)?;
} else {
writeln!(rt.stdout(),
"Mail: {id}\nFrom: {from}\nTo: {to}\n{subj}\n",
from = from,
id = id,
subj = subject,
to = to
)?;
}
rt.report_touched(m.get_location())?;
Ok(())
}
if rt.ids_from_stdin() {
let iter = rt
.ids::<crate::ui::PathProvider>()?
.ok_or_else(|| err_msg("No ids supplied"))?
.into_iter()
.map(Ok);
StoreIdIterator::new(Box::new(iter))
} else {
rt.store()
.all_mails()?
.into_storeid_iter()
}
.inspect(|id| debug!("Found: {:?}", id))
.into_get_iter(rt.store())
.map_inner_ok_or_else(|| err_msg("Did not find one entry"))
.and_then_ok(|m| list_mail(&rt, &refconfig, &m, print_content))
.collect::<Result<Vec<_>>>()
.map(|_| ())
}
fn mail_store(rt: &Runtime) -> Result<()> {
let _ = rt.cli().subcommand_matches("mail-store").unwrap();
Err(format_err!("This feature is currently not implemented."))
}
fn get_ref_collection_name(rt: &Runtime) -> Result<String> {
let setting_name = "mail.ref_collection_name";
debug!("Getting configuration: {}", setting_name);
rt.config()
.ok_or_else(|| format_err!("No configuration, cannot find collection name for mail collection"))?
.read_string(setting_name)?
.ok_or_else(|| format_err!("Setting missing: {}", setting_name))
}