summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2019-02-17 11:44:54 +0100
committerMatthias Beyer <mail@beyermatthias.de>2019-02-17 11:44:54 +0100
commitc562f352223fe5732424e5302a37c88698e3a1b4 (patch)
tree17a1e6628d7dc2d5acafe6d7aa14256f70ea458c
parent820ac41443d829e9e0c56cc58a915fa4e5fbd2c3 (diff)
parentf9a980c344227898df1fec54a41c84275f7325b2 (diff)
Merge branch 'rewrite-libimagentryref'
This is the merge for the "ref"-infrastructure rewrite. Finally. The refs are now stored with three bits of information: * The "collection" (named basepath) * The "relpath" (relative path) * The hash (sha1 as of now) The "collection" is a name which has to be accociated with a path to a directory (in the config file). That gives the user the opportunity to have (for example) their music collection in $HOME/music on one device and in $HOME/media/music on another. The "relpath" is the relative path, which results in the path to the actual file when being joined with the "collection" path. The hash is a sha1 hash as of now. Re-checking this hash with libimagentryref is not yet tested. This merge also removes the "mail" code completely, for the sake of seperating concerns into branches. The respective commits might be removed later. Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r--Cargo.toml2
-rw-r--r--bin/core/imag-ref/src/main.rs112
-rw-r--r--bin/core/imag-ref/src/ui.rs108
-rw-r--r--bin/core/imag/build.rs2
-rw-r--r--bin/domain/imag-mail/Cargo.toml37
l---------bin/domain/imag-mail/README.md1
-rw-r--r--bin/domain/imag-mail/src/main.rs175
-rw-r--r--bin/domain/imag-mail/src/ui.rs74
-rw-r--r--doc/src/05100-lib-entryref.md92
-rw-r--r--doc/src/05100-lib-mails.md14
-rw-r--r--imagrc.toml7
-rw-r--r--lib/domain/libimagmail/Cargo.toml30
l---------lib/domain/libimagmail/README.md1
-rw-r--r--lib/domain/libimagmail/src/iter.rs55
-rw-r--r--lib/domain/libimagmail/src/lib.rs51
-rw-r--r--lib/domain/libimagmail/src/mail.rs201
-rw-r--r--lib/entry/libimagentrymarkdown/Cargo.toml8
-rw-r--r--lib/entry/libimagentrymarkdown/src/lib.rs1
-rw-r--r--lib/entry/libimagentrymarkdown/src/processor.rs105
-rw-r--r--lib/entry/libimagentryref/Cargo.toml28
-rw-r--r--lib/entry/libimagentryref/src/generators/mod.rs276
-rw-r--r--lib/entry/libimagentryref/src/hasher.rs (renamed from lib/entry/libimagentryref/src/generators/base.rs)42
-rw-r--r--lib/entry/libimagentryref/src/lib.rs38
-rw-r--r--lib/entry/libimagentryref/src/reference.rs488
-rw-r--r--lib/entry/libimagentryref/src/refstore.rs128
25 files changed, 773 insertions, 1303 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 20f7d34f..4276aff5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -22,7 +22,6 @@ members = [
"bin/domain/imag-diary",
"bin/domain/imag-habit",
"bin/domain/imag-log",
- "bin/domain/imag-mail",
"bin/domain/imag-notes",
"bin/domain/imag-timetrack",
"bin/domain/imag-todo",
@@ -35,7 +34,6 @@ members = [
"lib/domain/libimagdiary",
"lib/domain/libimaghabit",
"lib/domain/libimaglog",
- "lib/domain/libimagmail",
"lib/domain/libimagnotes",
"lib/domain/libimagtimetrack",
"lib/domain/libimagtodo",
diff --git a/bin/core/imag-ref/src/main.rs b/bin/core/imag-ref/src/main.rs
index 9d8e131a..332e9477 100644
--- a/bin/core/imag-ref/src/main.rs
+++ b/bin/core/imag-ref/src/main.rs
@@ -47,15 +47,17 @@ extern crate libimagutil;
mod ui;
use ui::build_ui;
-use std::path::PathBuf;
use std::process::exit;
+use std::io::Write;
use libimagerror::trace::MapErrTrace;
use libimagerror::exit::ExitUnwrap;
use libimagrt::setup::generate_runtime_setup;
use libimagrt::runtime::Runtime;
-use libimagstore::storeid::IntoStoreId;
use libimagentryref::reference::Ref;
+use libimagentryref::reference::MutRef;
+use libimagentryref::reference::RefFassade;
+use libimagentryref::hasher::default::DefaultHasher;
fn main() {
let version = make_imag_version!();
@@ -69,6 +71,7 @@ fn main() {
debug!("Call: {}", name);
match name {
"deref" => deref(&rt),
+ "create" => create(&rt),
"remove" => remove(&rt),
other => {
debug!("Unknown command");
@@ -82,47 +85,43 @@ fn main() {
}
fn deref(rt: &Runtime) {
- let cmd = rt.cli().subcommand_matches("deref").unwrap();
- let id = cmd.value_of("ID")
- .map(String::from)
- .map(PathBuf::from)
- .unwrap() // saved by clap
- .into_storeid()
- .map_err_trace_exit_unwrap();
-
- match rt.store().get(id.clone()).map_err_trace_exit_unwrap() {
- Some(entry) => {
- entry
- .get_path()
- .map_err_trace_exit_unwrap()
- .to_str()
- .ok_or_else(|| {
- error!("Could not transform path into string!");
+ let cmd = rt.cli().subcommand_matches("deref").unwrap();
+ let ids = rt.ids::<::ui::PathProvider>().map_err_trace_exit_unwrap();
+ let out = rt.stdout();
+ let mut outlock = out.lock();
+
+ ids.into_iter()
+ .for_each(|id| {
+ match rt.store().get(id.clone()).map_err_trace_exit_unwrap() {
+ Some(entry) => {
+ entry
+ .as_ref_with_hasher::<DefaultHasher>()
+ .get_path()
+ .map_err_trace_exit_unwrap()
+ .to_str()
+ .ok_or_else(|| {
+ error!("Could not transform path into string!");
+ exit(1)
+ })
+ .map(|s| writeln!(outlock, "{}", s))
+ .ok(); // safe here because we exited already in the error case
+
+ let _ = rt.report_touched(&id).unwrap_or_exit();
+ },
+ None => {
+ error!("No entry for id '{}' found", id);
exit(1)
- })
- .map(|s| info!("{}", s))
- .ok(); // safe here because we exited already in the error case
-
- let _ = rt.report_touched(&id).unwrap_or_exit();
- },
- None => {
- error!("No entry for id '{}' found", id);
- exit(1)
- },
- };
+ },
+ }
+ });
}
fn remove(rt: &Runtime) {
use libimaginteraction::ask::ask_bool;
- let cmd = rt.cli().subcommand_matches("remove").unwrap();
- let yes = cmd.is_present("yes");
- let id = cmd.value_of("ID")
- .map(String::from)
- .map(PathBuf::from)
- .unwrap() // saved by clap
- .into_storeid()
- .map_err_trace_exit_unwrap();
+ let cmd = rt.cli().subcommand_matches("remove").unwrap();
+ let yes = cmd.is_present("yes");
+ let ids = rt.ids::<::ui::PathProvider>().map_err_trace_exit_unwrap();
let mut input = rt.stdin().unwrap_or_else(|| {
error!("No input stream. Cannot ask for permission");
@@ -131,21 +130,30 @@ fn remove(rt: &Runtime) {
let mut output = rt.stdout();
- match rt.store().get(id.clone()).map_err_trace_exit_unwrap() {
- Some(mut entry) => {
- if yes ||
- ask_bool(&format!("Delete ref from entry '{}'", id), None, &mut input, &mut output)
- .map_err_trace_exit_unwrap()
- {
- let _ = entry.remove_ref().map_err_trace_exit_unwrap();
- } else {
- info!("Aborted");
+ ids.into_iter()
+ .for_each(|id| {
+ match rt.store().get(id.clone()).map_err_trace_exit_unwrap() {
+ Some(mut entry) => {
+ if yes ||
+ ask_bool(&format!("Delete ref from entry '{}'", id), None, &mut input, &mut output)
+ .map_err_trace_exit_unwrap()
+ {
+ let _ = entry.as_ref_with_hasher_mut::<DefaultHasher>()
+ .remove_ref()
+ .map_err_trace_exit_unwrap();
+ } else {
+ info!("Aborted");
+ }
+ },
+ None => {
+ error!("No entry for id '{}' found", id);
+ exit(1)
+ },
}
- },
- None => {
- error!("No entry for id '{}' found", id);
- exit(1)
- },
- };
+ });
+}
+
+fn create(rt: &Runtime) {
+ unimplemented!()
}
diff --git a/bin/core/imag-ref/src/ui.rs b/bin/core/imag-ref/src/ui.rs
index e7d714ee..c14eafe2 100644
--- a/bin/core/imag-ref/src/ui.rs
+++ b/bin/core/imag-ref/src/ui.rs
@@ -17,19 +17,34 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
-use clap::{Arg, App, SubCommand};
+use std::path::PathBuf;
+
+use clap::{Arg, App, ArgMatches, SubCommand};
+
+use libimagstore::storeid::StoreId;
+use libimagstore::storeid::IntoStoreId;
+use libimagrt::runtime::IdPathProvider;
+use libimagerror::trace::MapErrTrace;
pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
app
.subcommand(SubCommand::with_name("deref")
- .about("'Dereference' a ref. This prints the Path of the referenced file")
+ .about("'Dereference a ref. This prints the Path(es) of the referenced file(s)")
.version("0.1")
.arg(Arg::with_name("ID")
.index(1)
.takes_value(true)
- .required(true)
- .help("The id of the store entry to dereference")
+ .required(false)
+ .multiple(true)
+ .help("The id of the store entry to dereference.")
.value_name("ID"))
+
+ .arg(Arg::with_name("ignore-noref")
+ .long("ignore-noref")
+ .takes_value(false)
+ .required(false)
+ .multiple(false)
+ .help("Ignore store entries which are not refs and do not print error message"))
)
.subcommand(SubCommand::with_name("remove")
@@ -38,14 +53,89 @@ pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
.arg(Arg::with_name("ID")
.index(1)
.takes_value(true)
- .required(true)
+ .required(false)
.multiple(true)
.help("Remove the reference from this store entry")
.value_name("ENTRIES"))
- .arg(Arg::with_name("yes")
- .long("yes")
- .short("y")
- .help("Don't ask whether this really should be done"))
+ .arg(Arg::with_name("ignore-noref")
+ .long("ignore-noref")
+ .takes_value(false)
+ .required(false)
+ .multiple(false)
+ .help("Ignore store entries which are not refs and do not print error message"))
)
+
+ .subcommand(SubCommand::with_name("create")
+ .about("Create a reference to a file")
+ .version("0.1")
+ .arg(Arg::with_name("ID")
+ .index(1)
+ .takes_value(true)
+ .required(true)
+ .multiple(false)
+ .help("Create a reference with that ID in the store. If the store id exists, it will be made into a reference.")
+ .value_name("ID"))
+
+ .arg(Arg::with_name("path")
+ .index(2)
+ .takes_value(true)
+ .required(true)
+ .multiple(false)
+ .help("The path to refer to. If there is no basepath configuration in the config file for the path this file is located at, the operation will error.")
+ .value_name("ID"))
+
+ .arg(Arg::with_name("force")
+ .long("force")
+ .takes_value(false)
+ .required(false)
+ .multiple(false)
+ .help("Use force to override existing references"))
+ )
+}
+
+pub struct PathProvider;
+impl IdPathProvider for PathProvider {
+ fn get_ids(matches: &ArgMatches) -> Vec<StoreId> {
+ match matches.subcommand() {
+ ("deref", Some(subm)) => {
+ subm.values_of("ID")
+ .ok_or_else(|| {
+ error!("No StoreId found");
+ ::std::process::exit(1)
+ })
+ .unwrap()
+ .into_iter()
+ .map(PathBuf::from)
+ .map(|pb| pb.into_storeid())
+ .collect::<Result<Vec<_>, _>>()
+ .map_err_trace_exit_unwrap()
+ },
+
+ ("remove", Some(subm)) => {
+ subm.values_of("ID")
+ .ok_or_else(|| {
+ error!("No StoreId found");
+ ::std::process::exit(1)
+ })
+ .unwrap()
+ .into_iter()
+ .map(PathBuf::from)
+ .map(|pb| pb.into_storeid())
+ .collect::<Result<Vec<_>, _>>()
+ .map_err_trace_exit_unwrap()
+ },
+
+ ("create", _) => {
+ error!("Command does not get IDs as input");
+ ::std::process::exit(1)
+ },
+
+
+ (other, _) => {
+ error!("Not a known command: {}", other);
+ ::std::process::exit(1)
+ }
+ }
+ }
}
diff --git a/bin/core/imag/build.rs b/bin/core/imag/build.rs
index 7d91385c..33dfc978 100644
--- a/bin/core/imag/build.rs
+++ b/bin/core/imag/build.rs
@@ -99,7 +99,6 @@ gen_mods_buildui!(
("../../../bin/domain/imag-diary/src/ui.rs" , imagdiary) ,
("../../../bin/domain/imag-habit/src/ui.rs" , imaghabit) ,
("../../../bin/domain/imag-log/src/ui.rs" , imaglog) ,
- ("../../../bin/domain/imag-mail/src/ui.rs" , imagmail) ,
("../../../bin/domain/imag-notes/src/ui.rs" , imagnotes) ,
("../../../bin/domain/imag-timetrack/src/ui.rs" , imagtimetrack) ,
("../../../bin/domain/imag-todo/src/ui.rs" , imagtodo) ,
@@ -129,7 +128,6 @@ fn main() {
.subcommand(build_subcommand!("init" , imaginit , version))
.subcommand(build_subcommand!("link" , imaglink , version))
.subcommand(build_subcommand!("log" , imaglog , version))
- .subcommand(build_subcommand!("mail" , imagmail , version))
.subcommand(build_subcommand!("mv" , imagmv , version))
.subcommand(build_subcommand!("notes" , imagnotes , version))
.subcommand(build_subcommand!("ref" , imagref , version))
diff --git a/bin/domain/imag-mail/Cargo.toml b/bin/domain/imag-mail/Cargo.toml
deleted file mode 100644
index 68836c55..00000000
--- a/bin/domain/imag-mail/Cargo.toml
+++ /dev/null
@@ -1,37 +0,0 @@
-[package]
-name = "imag-mail"
-version = "0.10.0"
-authors = ["Matthias Beyer <mail@beyermatthias.de>"]
-
-description = "Part of the imag core distribution: imag-mail command"
-
-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"
-
-build = "../../../build.rs"
-
-[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"
-failure = "0.1"
-
-libimagrt = { version = "0.10.0", path = "../../../lib/core/libimagrt" }
-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" }
-
-[dependencies.clap]
-version = "^2.29"
-default-features = false
-features = ["color", "suggestions", "wrap_help"]
-
diff --git a/bin/domain/imag-mail/README.md b/bin/domain/imag-mail/README.md
deleted file mode 120000
index 764e9f33..00000000
--- a/bin/domain/imag-mail/README.md
+++ /dev/null
@@ -1 +0,0 @@
-../../../doc/src/04020-module-mails.md \ No newline at end of file
diff --git a/bin/domain/imag-mail/src/main.rs b/bin/domain/imag-mail/src/main.rs
deleted file mode 100644
index d9b9dfbd..00000000
--- a/bin/domain/imag-mail/src/main.rs
+++ /dev/null
@@ -1,175 +0,0 @@
-//
-// 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)]
-
-#![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;
-extern crate failure;
-
-#[macro_use] extern crate libimagrt;
-extern crate libimagmail;
-extern crate libimagerror;
-extern crate libimagutil;
-
-use std::io::Write;
-
-use failure::Error;
-use failure::err_msg;
-
-use libimagerror::trace::{MapErrTrace, trace_error};
-use libimagerror::iter::TraceIterator;
-use libimagerror::exit::ExitUnwrap;
-use libimagerror::io::ToExitCode;
-use libimagmail::mail::Mail;
-use libimagrt::runtime::Runtime;
-use libimagrt::setup::generate_runtime_setup;
-use libimagutil::info_result::*;
-
-mod ui;
-
-use ui::build_ui;
-
-fn main() {
- let version = make_imag_version!();
- let rt = generate_runtime_setup("imag-mail",
- &version,
- "Mail collection tool",
- build_ui);
-
- rt.cli()
- .subcommand_name()
- .map(|name| {
- debug!("Call {}", name);
- match name {
- "import-mail" => import_mail(&rt),
- "list" => list(&rt),
- "mail-store" => mail_store(&rt),
- other => {
- debug!("Unknown command");
- let _ = rt.handle_unknown_subcommand("imag-mail", other, rt.cli())
- .map_err_trace_exit_unwrap()
- .code()
- .map(::std::process::exit);
- }
- }
- });
-}
-
-fn import_mail(rt: &Runtime) {
- let scmd = rt.cli().subcommand_matches("import-mail").unwrap();
- let path = scmd.value_of("path").unwrap(); // enforced by clap
-
- let mail = Mail::import_from_path(rt.store(), path)
- .map_info_str("Ok")
- .map_err_trace_exit_unwrap();
-
- let _ = rt.report_touched(mail.fle().get_location()).unwrap_or_exit();
-}
-
-fn list(rt: &Runtime) {
- use failure::ResultExt;
-
- // TODO: Implement lister type in libimagmail for this
- fn list_mail(rt: &Runtime, m: Mail) {
- let id = match m.get_message_id() {
- Ok(Some(f)) => f,
- Ok(None) => "<no id>".to_owned(),
- Err(e) => {
- trace_error(&e);
- "<error>".to_owned()
- },
- };
-
- let from = match m.get_from() {
- Ok(Some(f)) => f,
- Ok(None) => "<no from>".to_owned(),
- Err(e) => {
- trace_error(&e);
- "<error>".to_owned()
- },
- };
-
- let to = match m.get_to() {
- Ok(Some(f)) => f,
- Ok(None) => "<no to>".to_owned(),
- Err(e) => {
- trace_error(&e);
- "<error>".to_owned()
- },
- };
-
- let subject = match m.get_subject() {
- Ok(Some(f)) => f,
- Ok(None) => "<no subject>".to_owned(),
- Err(e) => {
- trace_error(&e);
- "<error>".to_owned()
- },
- };
-
- writeln!(rt.stdout(),
- "Mail: {id}\n\tFrom: {from}\n\tTo: {to}\n\t{subj}\n",
- from = from,
- id = id,
- subj = subject,
- to = to
- ).to_exit_code().unwrap_or_exit();
-
- let _ = rt.report_touched(m.fle().get_location()).unwrap_or_exit();
- }
-
- let _ = rt.store()
- .entries()
- .map_err_trace_exit_unwrap()
- .trace_unwrap_exit()
- .filter(|id| id.is_in_collection(&["mail"]))
- .filter_map(|id| {
- rt.store()
- .get(id)
- .context(err_msg("Ref handling error"))
- .map_err(Error::from)
- .map_err_trace_exit_unwrap()
- .map(|fle| Mail::from_fle(fle).map_err_trace().ok())
- })
- .filter_map(|e| e)
- .for_each(|m| list_mail(&rt, m));
-}
-
-fn mail_store(rt: &Runtime) {
- let _ = rt.cli().subcommand_matches("mail-store").unwrap();
- error!("This feature is currently not implemented.");
- unimplemented!()
-}
-
diff --git a/bin/domain/imag-mail/src/ui.rs b/bin/domain/imag-mail/src/ui.rs
deleted file mode 100644
index 938764eb..00000000
--- a/bin/domain/imag-mail/src/ui.rs
+++ /dev/null
@@ -1,74 +0,0 @@
-//
-// 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 clap::{Arg, App, SubCommand};
-
-pub fn build_ui<'a>(app: App<'a, 'a>) -> App<'a, 'a> {
- app
- .subcommand(SubCommand::with_name("import-mail")
- .about("Import a mail (create a reference to it) (Maildir)")
- .version("0.1")
- .arg(Arg::with_name("path")
- .long("path")
- .short("p")
- .takes_value(true)
- .required(true)
- .help("Path to the mail file or a directory which is then searched recursively")
- .value_name("PATH"))
- )
-
- .subcommand(SubCommand::with_name("list")
- .about("List all stored references to mails")
- .version("0.1")
-
- // TODO: Thee following four arguments are the same as in imag-ref.
- // We should make these importable from libimagentryref.
-
- .arg(Arg::with_name("check-dead")
- .long("check-dead")
- .short("d")
- .help("Check each reference whether it is dead"))
-
- .arg(Arg::with_name("check-changed")
- .long("check-changed")
- .short("c")
- .help("Check whether a reference had changed (content or permissions)"))
-
- .arg(Arg::with_name("check-changed-content")
- .long("check-changed-content")
- .short("C")
- .help("Check whether the content of the referenced file changed"))
-
- .arg(Arg::with_name("check-changed-permissions")
- .long("check-changed-perms")
- .short("P")
- .help("Check whether the permissions of the referenced file changed"))
-
- )
-
- .subcommand(SubCommand::with_name("mail-store")
- .about("Operations on (subsets of) all mails")
- .version("0.1")
- .subcommand(SubCommand::with_name("update-refs")
- .about("Create references based on Message-IDs for all loaded mails")
- .version("0.1"))
- // TODO: We really should be able to filter here.
- )
-}
-
diff --git a/doc/src/05100-lib-entryref.md b/doc/src/05100-lib-entryref.md
index b54ba102..46409205 100644
--- a/doc/src/05100-lib-entryref.md
+++ b/doc/src/05100-lib-entryref.md
@@ -3,52 +3,74 @@
This library crate contains functionality to generate _references_ within the
imag store.
-A reference is a "pointer" to a file or directory on the filesystem and outside
-the store.
-It differs from `libimagentrylink`/external linking as
-it is designed exclusively for filesystem references, not for URLs.
+### Problem
-A reference is created with a unique identifier, like a hash. The implementation
-how this hash is calculated can be defined by the user of `libimagentryref`.
+The problem this library solves is the following: A user wants to refer to a
+file which exists on her filesystem from within imag.
+But unfortunately, the user has several devices and the filesystem layout (the
+way the $HOME is organized) is not the same on every device.
+With this library, the user is able to refer to a file, but without specifying
+the whole path.
-So this library helps to resemble something like a _symlink_.
+Each device can have a different "base path", files are re-found via their
+hashes and file names, assuming that the files are equal on different devices or
+have at least the same name.
-### Usage
-Users have to implement the `UniqueRefPathGenerator` trait which should
-implement a hashing functionality for pathes.
+### User Story / Usecase
+
+Alice has a music library on her workstation and on her notebook. On her
+workstation, the music collection is at `home/alice/music`, on the notebook, it
+exists in `/home/al/media/music`.
+
+From within imag, alice wants to create a link to a file
+`$music_store/Psy_trance_2018_yearmix.mp3`.
+
+`libimagentryref` helps her, because she can provide a "base path" in the
+imag configuration file of each device and then link the file. imag only stores
+data about the file and its relative path, but not its abolute path.
+
+When moving the imag store from the workstation to the notebook, the base path
+for the music collection is not `/home/alice/music` anymore, but
+`/home/al/media/music` and imag can find the file automatically.
-### Limits
-This is _not_ intended to be a version control system or something like that.
-We also can not use _real symlinks_ as we need imag-store-objects to be able to
-link stuff.
+### Solution, Details
-### Usecase
+libimagentryref does store the following data:
-This library offers functionality to refer to content outside of the store.
-It can be used to refer to _nearly static stuff_ pretty easily - think of a
-Maildir - you add new mails by fetching them, but you mostly do not remove
-mails.
-If mails get moved, they can be re-found via their hash, because Maildir objects
-hardly change. Or because the hash implementation which is used to refer to them
-hashes only the `Message-Id` and that does not change.
+```toml
+[ref]
+filehash.sha1 = "<sha1 hash of the file>"
+relpath = "Psy_trance_2018_yearmix.mp3"
+collection = "music"
+```
-### Long-term TODO
+The filehash is stored so that libimagentryref can re-find the file whenever it
+was moved. The `sha1` key is added to be able to upgrade hashes later to other
+hashing algorithms.
+`relpath` is the part of the path that when joined with the "base" path from
+the configuration results in the full path of the file for the current machine.
+The "collection" key hints to the configuration key in the imag config file.
-Not implemented yet:
+The configuration section for the collections looks like this:
-- [ ] Re-finding of files via their hash.
- This must be implemented with several things in mind
- * The user of the library should be able to provide a way how the
- filesystem is searched. Basically a Functor which yields pathes to
- check based on the original path of the missing file.
- This enables implementations which do only search a certain subset
- of pathes, or does depth-first-search rather than
- breadth-first-search.
+```toml
+[ref.basepathes]
+music = "/home/alice/music"
+documents = "/home/alice/doc"
+```
+
+libimagentryref provides functionality to get the file.
+libimagentryref also offers functionality to find files _only_ using their
+filename (x)or filehash and correct the filehash or filename respectively
+(automatically or explicitely).
+
+
+### Limits
-### Known problems
+As soon as the file is renamed _and_ modified, this fails.
+This does also not cover the use case where the same file has different names on
+different machines.
-The functionality this library provides fails to work when syncing the imag
-store between two devices where the data layout is different on each device.
diff --git a/doc/src/05100-lib-mails.md b/doc/src/05100-lib-mails.md
deleted file mode 100644
index fde0879f..00000000
--- a/doc/src/05100-lib-mails.md
+++ /dev/null
@@ -1,14 +0,0 @@
-## 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.
-
diff --git a/imagrc.toml b/imagrc.toml
index 8e21f8d8..b1c5478d 100644
--- a/imagrc.toml
+++ b/imagrc.toml</