~matthiasbeyer/imag

418535ec97b5684e9556e6e8152ed3007a122814 — Matthias Beyer 1 year, 10 months ago b789a97 + 0ad852f
Merge branch 'imag-mail/list-format' into master

Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
M bin/domain/imag-mail/Cargo.toml => bin/domain/imag-mail/Cargo.toml +2 -1
@@ 22,8 22,8 @@ maintenance                       = { status     = "actively-developed" }
[dependencies]
log = "0.4.6"
failure = "0.1.5"
indoc = "0.3.3"
resiter = "0.4"
handlebars = "2"

libimagrt       = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
libimagstore    = { version = "0.10.0", path = "../../../lib/core/libimagstore" }


@@ 31,6 31,7 @@ libimagerror    = { version = "0.10.0", path = "../../../lib/core/libimagerror" 
libimagmail     = { version = "0.10.0", path = "../../../lib/domain/libimagmail" }
libimagutil     = { version = "0.10.0", path = "../../../lib/etc/libimagutil" }
libimagentryref = { version = "0.10.0", path = "../../../lib/entry/libimagentryref" }
libimaginteraction = { version = "0.10.0", path = "../../../lib/etc/libimaginteraction" }

[dependencies.clap]
version = "2.33.0"

M bin/domain/imag-mail/src/lib.rs => bin/domain/imag-mail/src/lib.rs +15 -77
@@ 38,8 38,8 @@ 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 handlebars;

extern crate libimagrt;
extern crate libimagmail;


@@ 47,6 47,7 @@ extern crate libimagerror;
extern crate libimagstore;
extern crate libimagutil;
extern crate libimagentryref;
extern crate libimaginteraction;

use std::io::Write;
use std::path::PathBuf;


@@ 59,19 60,16 @@ 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;
mod util;

/// Marker enum for implementing ImagApplication on
///


@@ 141,77 139,10 @@ fn import_mail(rt: &Runtime) -> Result<()> {
}

fn list(rt: &Runtime) -> Result<()> {
    let refconfig       = get_ref_config(rt, "imag-mail")?;
    let scmd            = rt.cli().subcommand_matches("list").unwrap(); // safe via clap
    let print_content   = scmd.is_present("list-read");

    if print_content {
        // TODO: Check whether workaround with "{}" is still necessary when updating "indoc"
        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."#));

        // TODO: Fix above.
    }

    // TODO: Implement lister type in libimagmail for this
    //
    // Optimization: Pass refconfig here instead of call get_ref_config() in lister function. This
    // way we do not call get_ref_config() multiple times.
    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.into(),
            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(())
    }
    let refconfig   = get_ref_config(rt, "imag-mail")?;
    let scmd        = rt.cli().subcommand_matches("list").unwrap(); // safe via clap
    let list_format = util::get_mail_print_format("mail.list_format", rt, &scmd)?;
    let mut i = 0;

    if rt.ids_from_stdin() {
        let iter = rt


@@ 229,7 160,14 @@ fn list(rt: &Runtime) -> Result<()> {
    .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))
    .and_then_ok(|m| {
        let data = util::build_data_object_for_handlebars(i, &m, &refconfig)?;
        let s = list_format.render("format", &data)?;
        writeln!(rt.stdout(), "{}", s)?;
        rt.report_touched(m.get_location())?;
        i += 1;
        Ok(())
    })
    .collect::<Result<Vec<_>>>()
    .map(|_| ())
}

M bin/domain/imag-mail/src/ui.rs => bin/domain/imag-mail/src/ui.rs +6 -8
@@ 51,14 51,6 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
                    .about("List all stored references to mails")
                    .version("0.1")

                    .arg(Arg::with_name("list-read")
                         .long("read")
                         .short("r")
                         .takes_value(false)
                         .required(false)
                         .multiple(false)
                         .help("Print the textual content of the mail itself as well"))

                    .arg(Arg::with_name("list-id")
                         .index(1)
                         .takes_value(true)


@@ 66,6 58,12 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
                         .multiple(true)
                         .help("The ids of the mails to list information for"))

                    .arg(Arg::with_name("format")
                         .long("format")
                         .takes_value(true)
                         .required(false)
                         .multiple(false)
                         .help("The format to list the mails with"))
                    )

        .subcommand(SubCommand::with_name("mail-store")

A bin/domain/imag-mail/src/util.rs => bin/domain/imag-mail/src/util.rs +87 -0
@@ 0,0 1,87 @@
//
// 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::collections::BTreeMap;

use clap::ArgMatches;
use failure::Error;
use failure::Fallible as Result;
use failure::err_msg;
use handlebars::Handlebars;
use toml_query::read::TomlValueReadTypeExt;

use libimagmail::mail::Mail;
use libimagrt::runtime::Runtime;
use libimagstore::store::FileLockEntry;
use libimagentryref::reference::Config as RefConfig;

pub fn get_mail_print_format(config_value_path: &'static str, rt: &Runtime, scmd: &ArgMatches) -> Result<Handlebars> {
    let fmt = match scmd.value_of("format").map(String::from) {
        Some(s) => Ok(s),
        None => {
            rt.config()
                .ok_or_else(|| err_msg("No configuration file"))?
                .read_string(config_value_path)
                .map_err(Error::from)?
                .ok_or_else(|| format_err!("Configuration '{}' does not exist", config_value_path))
        }
    }?;

    let mut hb = Handlebars::new();
    hb.register_template_string("format", fmt)?;

    hb.register_escape_fn(::handlebars::no_escape);
    ::libimaginteraction::format::register_all_color_helpers(&mut hb);
    ::libimaginteraction::format::register_all_format_helpers(&mut hb);
    Ok(hb)
}

pub fn build_data_object_for_handlebars(i: usize, m: &FileLockEntry, refconfig: &RefConfig) -> Result<BTreeMap<&'static str, String>> {
    let mut data = BTreeMap::new();

    data.insert("i", format!("{}", i));

    let id = match m.get_message_id(refconfig)? {
        Some(f) => f.into(),
        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(),
    };

    data.insert("id"      , id);
    data.insert("from"    , from);
    data.insert("to"      , to);
    data.insert("subject" , subject);

    Ok(data)
}


M imagrc.toml => imagrc.toml +1 -0
@@ 374,6 374,7 @@ calendars = "/home/user/calendars"
[mail]
# The name of the mail reference collection
ref_collection_name = "mail"
list_format = "{{i}} - {{id}} - {{from}} -> {{to}}\t: {{subject}}"

[todo]
show_format = """