caltemps/
vdir.rs

1use icalendar::Calendar;
2use std::ffi::OsString;
3use std::path::Path;
4
5#[derive(Debug)]
6struct IcsReadError {
7    path: OsString,
8    //error: Box<dyn std::error::Error>,
9}
10
11fn list_ics_from_dir(
12    path: &Path,
13) -> Result<impl Iterator<Item = OsString>, Box<dyn std::error::Error>> {
14    match std::fs::read_dir(path) {
15        Ok(dirs) => Ok(dirs.filter_map(|res| match res {
16            Ok(t) => {
17                if let Some(x) = t.path().extension() {
18                    if x.eq_ignore_ascii_case("ics") {
19                        Some(t.path().into_os_string())
20                    } else {
21                        None
22                    }
23                } else {
24                    None
25                }
26            }
27            Err(_) => None,
28        })),
29        Err(error) => Err(Box::new(error)),
30    }
31}
32
33fn read_ics_from_dir(
34    path: &Path,
35) -> Result<impl Iterator<Item = Result<Calendar, IcsReadError>>, Box<dyn std::error::Error>> {
36    match list_ics_from_dir(path) {
37        Ok(ics_it) => Ok(ics_it.map(|ipath| {
38            // Read file to output
39            let ics_path = ipath.to_os_string();
40            match &mut std::fs::File::open(ipath) {
41                Ok(f) => {
42                    let readable: &mut dyn std::io::Read = f;
43                    let mut output = String::new();
44                    match readable.read_to_string(&mut output) {
45                        Ok(_) => {
46                            //icalendar::parser::read_calendar(&output)
47                            match output.parse::<Calendar>() {
48                                Ok(read) => Ok(read),
49                                Err(_error) => Err(IcsReadError {
50                                    path: ics_path,
51                                    //error: Box::new(error.into()),
52                                }),
53                            }
54                        }
55                        Err(_error) => Err(IcsReadError {
56                            path: ics_path,
57                            //error: Box::new(error.to_string()),
58                        }),
59                    }
60                }
61                Err(_error) => Err(IcsReadError {
62                    path: ics_path,
63                    //error: Box::new(error.to_string()),
64                }),
65            }
66        })),
67        Err(error) => Err(error),
68    }
69}
70
71pub fn read_vdir_cal(path: &Path) -> Result<Calendar, Box<dyn std::error::Error>> {
72    // TODO: we can read some metadata like displayname and color
73    /*if path.join("displayname").is_file() {
74        cal.
75    }*/
76    match read_ics_from_dir(Path::new(path)) {
77        Ok(entries_it) => {
78            let mut cal = Calendar::new();
79            cal.components.extend(
80                entries_it
81                    .filter_map(|entry| match entry {
82                        Ok(p) => Some(p.components),
83                        Err(error) => {
84                            eprintln!("Issue reading {:#?}\n\t{:#?}", error.path, error);
85                            None
86                        }
87                    })
88                    .flatten(),
89            );
90            Ok(cal)
91        }
92        Err(error) => Err(error),
93    }
94}