2021-09-17 15:57:48 +00:00
|
|
|
use chrono::*; // For date
|
|
|
|
use std::fs; // To list files
|
|
|
|
use std::fs::File;
|
|
|
|
use std::io::BufReader;
|
|
|
|
use std::io::BufRead;
|
2021-09-18 12:28:11 +00:00
|
|
|
use std::process::Command;
|
2021-09-17 15:57:48 +00:00
|
|
|
|
2021-09-18 12:28:11 +00:00
|
|
|
/* Execute notify program */
|
|
|
|
fn notify (text: &String) {
|
|
|
|
if cfg!(target_os = "windows") {
|
|
|
|
println!("OS not suported");
|
|
|
|
} else {
|
|
|
|
let _ = Command::new("notify-send")
|
|
|
|
.arg("Anniversaires")
|
|
|
|
.arg(text)
|
|
|
|
.output()
|
|
|
|
.expect("failed to execute process");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Extract birthdate String from vcf file */
|
|
|
|
fn birthdate (filename: &String) -> String {
|
2021-09-17 15:57:48 +00:00
|
|
|
let file = File::open(filename).expect("file not found!");
|
|
|
|
let reader = BufReader::new(file);
|
|
|
|
for line in reader.lines() {
|
|
|
|
let l:String = line.unwrap();
|
|
|
|
if l.starts_with("BDAY") {
|
|
|
|
return l[5..].to_string();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "".to_string()
|
|
|
|
}
|
|
|
|
|
2021-09-18 12:28:11 +00:00
|
|
|
/* Extract full name from vcf file */
|
|
|
|
fn fullname (filename: &String) -> String {
|
|
|
|
let file = File::open(filename).expect("file not found!");
|
|
|
|
let reader = BufReader::new(file);
|
|
|
|
for line in reader.lines() {
|
|
|
|
let l:String = line.unwrap();
|
|
|
|
if l.starts_with("FN:") {
|
|
|
|
return l[3..].to_string();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "".to_string()
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test if date a is before b in civil year */
|
|
|
|
fn before_in_civil_year (a :&NaiveDate, b: &NaiveDate) -> bool{
|
|
|
|
a.month()*100 + a.day() < b.month()*100 + b.day()
|
|
|
|
}
|
|
|
|
|
2021-09-17 15:57:48 +00:00
|
|
|
fn main() {
|
|
|
|
/* Where are the vcf files */
|
|
|
|
let vcf_dir = "/home/ilya/.contacts/contacts";
|
|
|
|
|
|
|
|
/* How much day before */
|
2021-09-18 12:28:11 +00:00
|
|
|
let delta_d = 10;
|
|
|
|
|
|
|
|
let tz_today = Local::today();
|
|
|
|
let today = NaiveDate::from_ymd(tz_today.year(), tz_today.month(), tz_today.day());
|
2021-09-17 15:57:48 +00:00
|
|
|
|
|
|
|
let paths = fs::read_dir(vcf_dir).unwrap();
|
2021-09-18 12:28:11 +00:00
|
|
|
let mut output:String = "".to_string();
|
|
|
|
|
2021-09-17 15:57:48 +00:00
|
|
|
for path in paths {
|
2021-09-18 12:28:11 +00:00
|
|
|
/* Get date string from vcf file */
|
2021-09-17 15:57:48 +00:00
|
|
|
let filename :String = path.unwrap().path().into_os_string().into_string().unwrap();
|
2021-09-18 12:28:11 +00:00
|
|
|
let bdate:String = birthdate(&filename);
|
2021-09-17 15:57:48 +00:00
|
|
|
if bdate == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2021-09-18 12:28:11 +00:00
|
|
|
/* Parse the date */
|
|
|
|
let mut date = match bdate.len() {
|
|
|
|
8 => Some(NaiveDate::parse_from_str(&bdate.to_string(), "%Y%m%d").unwrap()),
|
|
|
|
10 => Some(NaiveDate::parse_from_str(&bdate.to_string(), "%Y-%m-%d").unwrap()),
|
|
|
|
_ => None,
|
|
|
|
}.expect("Date is of no known format");
|
|
|
|
|
|
|
|
/* set to y+1 to make it a future date, or to y */
|
|
|
|
if before_in_civil_year(&date, &today) {
|
|
|
|
date = date.with_year(today.year()+1).unwrap()
|
|
|
|
} else {
|
|
|
|
date = date.with_year(today.year()).unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
let bdate = UTC.from_local_date(&date).single().unwrap();
|
|
|
|
|
|
|
|
/* It is time to be alerted */
|
|
|
|
if bdate.num_days_from_ce() - tz_today.num_days_from_ce() <= delta_d {
|
|
|
|
output = format!("{}{}/{} {}\n", output, date.day(), date.month(), fullname(&filename));
|
|
|
|
}
|
2021-09-17 15:57:48 +00:00
|
|
|
}
|
2021-09-18 12:28:11 +00:00
|
|
|
notify(&output);
|
2021-09-17 15:57:48 +00:00
|
|
|
}
|