use chrono::*; // For date use std::fs; // To list files use std::fs::File; use std::io::BufReader; use std::io::BufRead; use std::process::Command; /* 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 { 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() } /* 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() } fn main() { /* Where are the vcf files */ let vcf_dir = "/home/ilya/.contacts/contacts"; /* How much day before */ let delta_d = 10; let tz_today = Local::today(); let today = NaiveDate::from_ymd(tz_today.year(), tz_today.month(), tz_today.day()); let paths = fs::read_dir(vcf_dir).unwrap(); let mut output:String = "".to_string(); for path in paths { /* Get date string from vcf file */ let filename :String = path.unwrap().path().into_os_string().into_string().unwrap(); let bdate:String = birthdate(&filename); if bdate == "" { continue } /* 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)); } } notify(&output); }