1use anyhow::anyhow;
2use anyhow::Result;
3use std::borrow::ToOwned;
4use std::env;
5use std::fs;
6use std::io;
7use std::io::{Read, Write};
8use std::path;
9
10use atomicwrites::{AllowOverwrite, AtomicFile};
11
12use crate::editor;
13use crate::utils;
14use crate::utils::CustomPathExt;
15
16#[inline]
17fn get_pwd() -> path::PathBuf {
18 env::current_dir().ok().expect("Failed to get CWD")
19}
20
21#[inline]
22fn get_envvar(key: &str) -> Option<String> {
23 match env::var(key) {
24 Ok(x) => Some(x),
25 Err(env::VarError::NotPresent) => None,
26 Err(env::VarError::NotUnicode(_)) => panic!("{} is not unicode.", key),
27 }
28}
29
30pub fn index_contact(index_path: &path::Path, contact: &utils::Contact) -> Result<()> {
31 let mut index_fp = fs::OpenOptions::new()
32 .append(true)
33 .write(true)
34 .open(&index_path)?;
35
36 let index_entry = utils::index_item_from_contact(contact)?;
37 index_fp.write_all(index_entry.as_bytes())?;
38 Ok(())
39}
40
41pub fn build_index(outfile: &path::Path, dir: &path::Path) -> Result<()> {
42 if !dir.is_dir() {
43 return Err(anyhow!("MATES_DIR must be a directory."));
44 };
45
46 let af = AtomicFile::new(&outfile, AllowOverwrite);
47 let mut errors = false;
48
49 af.write::<(), io::Error, _>(|outf| {
50 for entry in fs::read_dir(dir)? {
51 let entry = match entry {
52 Ok(x) => x,
53 Err(e) => {
54 println!("Error while listing directory: {}", e);
55 errors = true;
56 continue;
57 }
58 };
59
60 let pathbuf = entry.path();
61
62 if pathbuf.str_extension().unwrap_or("") != "vcf" || !pathbuf.is_file() {
63 continue;
64 };
65
66 let contact = match utils::Contact::from_file(&pathbuf) {
67 Ok(x) => x,
68 Err(e) => {
69 println!("Error while reading {}: {}", pathbuf.display(), e);
70 errors = true;
71 continue;
72 }
73 };
74
75 match utils::index_item_from_contact(&contact) {
76 Ok(index_string) => {
77 outf.write_all(index_string.as_bytes())?;
78 }
79 Err(e) => {
80 println!("Error while indexing {}: {}", pathbuf.display(), e);
81 errors = true;
82 continue;
83 }
84 };
85 }
86 Ok(())
87 })?;
88
89 if errors {
90 Err(anyhow!(
91 "Several errors happened while generating the index."
92 ))
93 } else {
94 Ok(())
95 }
96}
97
98pub fn edit_contact(config: &Configuration, query: &str) -> Result<()> {
99 let results = if get_pwd().join(query).is_file() {
100 vec![path::PathBuf::from(query)]
101 } else {
102 utils::file_query(config, query)?.into_iter().collect()
103 };
104
105 if results.len() < 1 {
106 return Err(anyhow!("No such contact."));
107 } else if results.len() > 1 {
108 return Err(anyhow!("Ambiguous query."));
109 }
110
111 let fpath = &results[0];
112 editor::cli_main(fpath);
113
114 let fcontent = {
115 let mut fcontent = String::new();
116 let mut file = fs::File::open(fpath)?;
117 file.read_to_string(&mut fcontent)?;
118 fcontent
119 };
120
121 if (&fcontent[..]).trim().len() == 0 {
122 fs::remove_file(fpath)?;
123 return Err(anyhow!("Contact emptied, file removed."));
124 };
125
126 Ok(())
127}
128
129pub fn mutt_query(config: &Configuration, disable_first_line: bool, query: &str) -> Result<()> {
130 if !disable_first_line {
133 println!();
134 }
135
136 if let Ok(items) = utils::index_query(config, query) {
137 for item in items {
138 if item.email.len() > 0 && item.name.len() > 0 {
139 println!("{}\t{}", item.email, item.name);
140 };
141 }
142 };
143 Ok(())
144}
145
146pub fn file_query(config: &Configuration, query: &str) -> Result<()> {
147 for path in utils::file_query(config, query)?.iter() {
148 println!("{}", path.display());
149 }
150 Ok(())
151}
152
153pub fn email_query(config: &Configuration, query: &str) -> Result<()> {
154 for item in utils::index_query(config, query)? {
155 if item.name.len() > 0 && item.email.len() > 0 {
156 println!("{} <{}>", item.name, item.email);
157 };
158 }
159 Ok(())
160}
161
162pub struct Configuration {
163 pub index_path: path::PathBuf,
164 pub vdir_path: path::PathBuf,
165 pub grep_cmd: String,
166}
167
168impl Configuration {
169 pub fn new() -> Result<Configuration, String> {
170 Ok(Configuration {
171 index_path: match get_envvar("MATES_INDEX") {
172 Some(x) => path::PathBuf::from(&x),
173 None => match get_envvar("HOME") {
174 Some(home) => get_pwd().join(&home).join(".mates_index"),
175 None => return Err("Unable to determine user's home directory.".to_owned()),
176 },
177 },
178 vdir_path: match get_envvar("MATES_DIR") {
179 Some(x) => path::PathBuf::from(&x),
180 None => {
181 return Err(
182 "MATES_DIR must be set to your vdir path (directory of vcf-files)."
183 .to_owned(),
184 )
185 }
186 },
187 grep_cmd: match get_envvar("MATES_GREP") {
188 Some(x) => x,
189 None => "grep -i".to_owned(),
190 },
191 })
192 }
193}