summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2017-11-08 18:15:02 +0100
committerGitHub <noreply@github.com>2017-11-08 18:15:02 +0100
commit6efd0a9450d5d52d6f8e75a5c30ae48c0c8ec00e (patch)
treed339c3e1f4ea4f40875ba2e815bb6673d78ba572
parent23820e322e8693321ca9c3800b9100456d241cbe (diff)
parentdfbc69400a578edcb77e248c821d949e2bc68217 (diff)
downloadimag-6efd0a9450d5d52d6f8e75a5c30ae48c0c8ec00e.zip
imag-6efd0a9450d5d52d6f8e75a5c30ae48c0c8ec00e.tar.gz
Merge pull request #1110 from matthiasbeyer/libimagcontact/init
Libimagcontact/init
-rw-r--r--Cargo.toml1
-rw-r--r--doc/src/05100-lib-contacts.md47
-rw-r--r--lib/domain/libimagcontact/Cargo.toml26
l---------lib/domain/libimagcontact/README.md1
-rw-r--r--lib/domain/libimagcontact/src/contact.rs90
-rw-r--r--lib/domain/libimagcontact/src/error.rs52
-rw-r--r--lib/domain/libimagcontact/src/iter.rs69
-rw-r--r--lib/domain/libimagcontact/src/lib.rs53
-rw-r--r--lib/domain/libimagcontact/src/store.rs86
-rw-r--r--lib/domain/libimagcontact/src/util.rs45
10 files changed, 470 insertions, 0 deletions
diff --git a/Cargo.toml b/Cargo.toml
index e927600..21f3a85 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,6 +21,7 @@ members = [
"lib/core/libimagrt",
"lib/core/libimagstore",
"lib/domain/libimagbookmark",
+ "lib/domain/libimagcontact",
"lib/domain/libimagdiary",
"lib/domain/libimagmail",
"lib/domain/libimagnotes",
diff --git a/doc/src/05100-lib-contacts.md b/doc/src/05100-lib-contacts.md
index 4bdd537..25e6906 100644
--- a/doc/src/05100-lib-contacts.md
+++ b/doc/src/05100-lib-contacts.md
@@ -1,2 +1,49 @@
## libimagcontacts
+The contact library basically only creates references to the actual icalendar
+and vcard files, though it also can parse (via the `vobject` crate) the
+information and return it from an entry directly.
+
+The architecture of indirections is as follows:
+
+```{.numberLines}
+
++--------------------------------+
+| |
+| Store, as ContactStore |
+| |
++----------------+---------------+
+ |
+ | Provides access to
+ |
++----------------v---------------+
+| |
+| (FileLock)Entry as Contact |
+| |
+| which is actually a: |
+| |
+| (FileLock)Entry as Ref |
+| |
++----------------+---------------+
+ |
+ | refers to
+ |
++----------------v---------------+
+| |
+| vcard file (outside store) |
+| |
++----------------+---------------+
+ |
+ | contains
+ |
++----------------v---------------+
+| |
+| vcard data |
+| |
++--------------------------------+
+
+```
+
+As the library is build upon `libimagentryref`, it does not create a new
+subcollection in the store `/contacts`, but uses the infrastructure of
+`libimagentryref` which automatically puts all references in `/ref`.
diff --git a/lib/domain/libimagcontact/Cargo.toml b/lib/domain/libimagcontact/Cargo.toml
new file mode 100644
index 0000000..acc420a
--- /dev/null
+++ b/lib/domain/libimagcontact/Cargo.toml
@@ -0,0 +1,26 @@
+[package]
+name = "libimagcontact"
+version = "0.5.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://matthiasbeyer.github.io/imag/imag_documentation/index.html"
+repository = "https://github.com/matthiasbeyer/imag"
+homepage = "http://imag-pim.org"
+
+[dependencies]
+error-chain = "0.11"
+log = "0.3"
+toml = "0.4"
+toml-query = "0.4"
+vobject = { git = 'https://github.com/matthiasbeyer/rust-vobject', branch = "next" }
+
+libimagstore = { version = "0.5.0", path = "../../../lib/core/libimagstore" }
+libimagerror = { version = "0.5.0", path = "../../../lib/core/libimagerror" }
+libimagentryref = { version = "0.5.0", path = "../../../lib/entry/libimagentryref/" }
+
diff --git a/lib/domain/libimagcontact/README.md b/lib/domain/libimagcontact/README.md
new file mode 120000
index 0000000..e097eec
--- /dev/null
+++ b/lib/domain/libimagcontact/README.md
@@ -0,0 +1 @@
+../../../doc/src/05100-lib-contacts.md \ No newline at end of file
diff --git a/lib/domain/libimagcontact/src/contact.rs b/lib/domain/libimagcontact/src/contact.rs
new file mode 100644
index 0000000..14a80e3
--- /dev/null
+++ b/lib/domain/libimagcontact/src/contact.rs
@@ -0,0 +1,90 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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::ops::Deref;
+
+use vobject::Component;
+use toml::Value;
+use toml_query::read::TomlValueReadExt;
+
+use libimagstore::store::Entry;
+use libimagentryref::reference::Ref;
+
+use error::ContactError as CE;
+use error::ContactErrorKind as CEK;
+use error::Result;
+use util;
+
+/// Trait to be implemented on ::libimagstore::store::Entry
+///
+/// Based on the functionality from libimagentryref, for fetching the Ical data from disk
+pub trait Contact : Ref {
+
+ fn is_contact(&self) -> Result<bool>;
+
+ // getting data
+
+ fn get_contact_data(&self) -> Result<ContactData>;
+
+ // More convenience functionality may follow
+
+}
+
+impl Contact for Entry {
+
+ fn is_contact(&self) -> Result<bool> {
+ let location = "contact.marker";
+ match self.get_header().read(location)? {
+ Some(&Value::Boolean(b)) => Ok(b),
+ Some(_) => Err(CE::from_kind(CEK::HeaderTypeError("boolean", location))),
+ None => Ok(false)
+ }
+ }
+
+ fn get_contact_data(&self) -> Result<ContactData> {
+ let component = self
+ .fs_file()
+ .map_err(From::from)
+ .and_then(util::read_to_string)
+ .and_then(util::parse)?;
+
+ Ok(ContactData(component))
+ }
+
+}
+
+pub struct ContactData(Component);
+
+impl ContactData {
+
+ pub fn into_inner(self) -> Component {
+ self.0
+ }
+
+}
+
+impl Deref for ContactData {
+ type Target = Component;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+
diff --git a/lib/domain/libimagcontact/src/error.rs b/lib/domain/libimagcontact/src/error.rs
new file mode 100644
index 0000000..c3c8147
--- /dev/null
+++ b/lib/domain/libimagcontact/src/error.rs
@@ -0,0 +1,52 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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 libimagstore::storeid::StoreId;
+
+error_chain! {
+ types {
+ ContactError, ContactErrorKind, ResultExt, Result;
+ }
+
+ links {
+ StoreError(::libimagstore::error::StoreError, ::libimagstore::error::StoreErrorKind);
+ RefError(::libimagentryref::error::RefError, ::libimagentryref::error::RefErrorKind);
+ VObjectError(::vobject::error::VObjectError, ::vobject::error::VObjectErrorKind);
+ }
+
+ foreign_links {
+ Io(::std::io::Error);
+ TomlQueryError(::toml_query::error::Error);
+ }
+
+ errors {
+
+ HeaderTypeError(ty: &'static str, loc: &'static str) {
+ description("Type error in header")
+ display("Type error in header, expected {} at '{}', found other type", ty, loc)
+ }
+
+ EntryNotFound(sid: StoreId) {
+ description("Entry not found with StoreId")
+ display("Entry {:?} not found", sid)
+ }
+
+ }
+}
+
diff --git a/lib/domain/libimagcontact/src/iter.rs b/lib/domain/libimagcontact/src/iter.rs
new file mode 100644
index 0000000..b5f8974
--- /dev/null
+++ b/lib/domain/libimagcontact/src/iter.rs
@@ -0,0 +1,69 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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 libimagstore::storeid::StoreIdIterator;
+use libimagstore::store::Store;
+use libimagstore::store::FileLockEntry;
+
+use contact::Contact;
+use error::ContactError as CE;
+use error::ContactErrorKind as CEK;
+use error::Result;
+
+pub struct ContactIter<'a>(StoreIdIterator, &'a Store);
+
+/// Iterator over contacts
+///
+/// As the libimagcontact works with libimagentryref in the backend, we must hold a reference to the
+/// Store here as well, so we can check whether a fetched StoreId actually points to a contact
+/// reference or not.
+///
+/// So, the Iterator `Store::get()`s the object pointed to by the StoreId and returns it if
+/// everything worked.
+impl<'a> ContactIter<'a> {
+
+ pub fn new(sii: StoreIdIterator, store: &'a Store) -> ContactIter<'a> {
+ ContactIter(sii, store)
+ }
+
+}
+
+impl<'a> Iterator for ContactIter<'a> {
+ type Item = Result<FileLockEntry<'a>>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ loop {
+ match self.0.next() {
+ None => return None,
+ Some(sid) => match self.1.get(sid.clone()).map_err(From::from) {
+ Err(e) => return Some(Err(e)),
+ Ok(None) => return Some(Err(CE::from_kind(CEK::EntryNotFound(sid)))),
+ Ok(Some(entry)) => match entry.is_contact().map_err(From::from) {
+ Ok(true) => return Some(Ok(entry)),
+ Ok(false) => continue,
+ Err(e) => return Some(Err(e)),
+ },
+
+ },
+ }
+ }
+ }
+
+}
+
diff --git a/lib/domain/libimagcontact/src/lib.rs b/lib/domain/libimagcontact/src/lib.rs
new file mode 100644
index 0000000..efdb8a6
--- /dev/null
+++ b/lib/domain/libimagcontact/src/lib.rs
@@ -0,0 +1,53 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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
+//
+
+#![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;
+#[macro_use] extern crate error_chain;
+extern crate vobject;
+extern crate toml;
+extern crate toml_query;
+
+#[macro_use] extern crate libimagstore;
+extern crate libimagerror;
+extern crate libimagentryref;
+
+module_entry_path_mod!("contact");
+
+pub mod contact;
+pub mod error;
+pub mod iter;
+pub mod store;
+mod util;
+
diff --git a/lib/domain/libimagcontact/src/store.rs b/lib/domain/libimagcontact/src/store.rs
new file mode 100644
index 0000000..770c08f
--- /dev/null
+++ b/lib/domain/libimagcontact/src/store.rs
@@ -0,0 +1,86 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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::PathBuf;
+
+use vobject::parse_component;
+use toml::Value;
+use toml_query::insert::TomlValueInsertExt;
+
+use libimagstore::store::Store;
+use libimagstore::store::FileLockEntry;
+use libimagstore::storeid::StoreIdIterator;
+use libimagentryref::refstore::RefStore;
+use libimagentryref::flags::RefFlags;
+
+use error::Result;
+use util;
+
+pub trait ContactStore<'a> : RefStore {
+
+ // creating
+
+ fn create_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>>;
+
+ /// Create contact ref from buffer
+ ///
+ /// Needs the `p` argument as we're finally creating a reference by path, the buffer is only for
+ /// collecting metadata.
+ fn create_from_buf(&'a self, p: &PathBuf, buf: &String) -> Result<FileLockEntry<'a>>;
+
+ // getting
+
+ fn all_contacts(&'a self) -> Result<StoreIdIterator>;
+}
+
+/// The extension for the Store to work with contacts
+///
+/// The contact functionality is implemented by using the `libimagentryref` library, so basically
+/// we only reference vcard files from outside the store.
+///
+/// Because of this, we do not have an own store collection `/contacts` or something like that, but
+/// must stress the `libimagentryref` API for everything.
+impl<'a> ContactStore<'a> for Store {
+
+ fn create_from_path(&'a self, p: &PathBuf) -> Result<FileLockEntry<'a>> {
+ util::read_to_string(p).and_then(|buf| self.create_from_buf(p, &buf))
+ }
+
+ /// Create contact ref from buffer
+ fn create_from_buf(&'a self, p: &PathBuf, buf: &String) -> Result<FileLockEntry<'a>> {
+ let component = parse_component(&buf)?;
+ debug!("Parsed: {:?}", component);
+
+ let flags = RefFlags::default().with_content_hashing(true).with_permission_tracking(false);
+ RefStore::create(self, p.clone(), flags)
+ .map_err(From::from)
+ .and_then(|mut entry| {
+ entry.get_header_mut()
+ .insert("contact.marker", Value::Boolean(true))
+ .map_err(From::from)
+ .map(|_| entry)
+ })
+ }
+
+ fn all_contacts(&'a self) -> Result<StoreIdIterator> {
+ self.all_references().map_err(From::from)
+ }
+
+}
+
diff --git a/lib/domain/libimagcontact/src/util.rs b/lib/domain/libimagcontact/src/util.rs
new file mode 100644
index 0000000..0dad597
--- /dev/null
+++ b/lib/domain/libimagcontact/src/util.rs
@@ -0,0 +1,45 @@
+//
+// imag - the personal information management suite for the commandline
+// Copyright (C) 2015, 2016 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::fmt::Debug;
+use std::fs::File;
+use std::io::Read;
+
+use error::Result;
+
+use vobject::Component;
+
+pub fn read_to_string<A: AsRef<Path> + Debug>(pb: A) -> Result<String> {
+ let mut cont = String::new();
+
+ let mut file = File::open(pb.as_ref())?;
+ let bytes = file.read_to_string(&mut cont)?;
+
+ debug!("Read {} bytes from {:?}", bytes, pb);
+
+ Ok(cont)
+}
+
+/// Helper for chaining results nicely
+pub fn parse(buf: String) -> Result<Component> {
+ use vobject::parse_component;
+ parse_component(&buf).map_err(From::from)
+}
+