aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ics.rs136
-rw-r--r--src/main.rs13
2 files changed, 148 insertions, 1 deletions
diff --git a/src/ics.rs b/src/ics.rs
new file mode 100644
index 0000000..3373d14
--- /dev/null
+++ b/src/ics.rs
@@ -0,0 +1,136 @@
+use std::io;
+use std::io::BufReader;
+use std::fs::File;
+use std::path::Path;
+use std::str::FromStr;
+use std::num::ParseIntError;
+use std::fmt;
+
+use ical::parser;
+use ical::IcalParser;
+use chrono;
+use chrono_tz::{Tz, UTC};
+use chrono::prelude::{DateTime, TimeZone};
+
+
+#[derive(Debug)]
+pub enum Date {
+ Time(DateTime<Tz>),
+ AllDay(chrono::Date<Tz>),
+}
+
+#[derive(Debug)]
+pub struct Event {
+ pub start: Date,
+ pub end: Date,
+ pub summary: String,
+ pub location: String,
+ pub description: String,
+}
+
+pub fn parse<P: AsRef<Path>>(ics: P) -> Result<Vec<Event>, IcsError> {
+ let buf = BufReader::new(File::open(ics)?);
+ let reader = IcalParser::new(buf);
+ let mut events = Vec::new();
+
+ for line in reader {
+ for ev in line?.events {
+ let mut event = Event::new();
+ for property in ev.properties {
+ let value = property.value.unwrap_or("".to_string());
+ let mut time_zone = "".to_string();
+
+ for (param, value) in property.params.unwrap_or(vec![]) {
+ if param == "TZID" && value.len() > 0 {
+ time_zone = value[0].clone();
+ }
+ }
+
+ match property.name.as_ref() {
+ "SUMMARY" => event.summary = value,
+ "LOCATION" => event.location = value,
+ "DESCRIPTION" => event.description = value,
+ "DTSTART" => event.start = parse_date(value, time_zone)?,
+ "DTEND" => event.end = parse_date(value, time_zone)?,
+ _ => (),
+ };
+ }
+ events.push(event);
+ }
+ }
+
+ Ok(events)
+}
+
+fn parse_date(date: String, time_zone: String) -> Result<Date, IcsError> {
+ let tz: Tz = time_zone.parse().unwrap_or(UTC);
+ let date = match date.find("T") {
+ Some(_) => {
+ let time = tz.datetime_from_str(&date, "%Y%m%dT%H%M%S").unwrap_or(
+ UTC.timestamp(
+ 0,
+ 0,
+ ),
+ );
+ Date::Time(time)
+ }
+ None => {
+ Date::AllDay(tz.ymd(
+ i32::from_str(&date[0..4])?,
+ u32::from_str(&date[4..6])?,
+ u32::from_str(&date[6..8])?,
+ ))
+ }
+ };
+ Ok(date)
+}
+
+impl Event {
+ fn new() -> Event {
+ return Event {
+ summary: "".to_string(),
+ location: "".to_string(),
+ description: "".to_string(),
+ start: Date::Time(UTC.timestamp(0, 0)),
+ end: Date::Time(UTC.timestamp(0, 0)),
+ };
+ }
+}
+
+impl fmt::Display for Event {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}: {}", self.start, self.summary)?;
+ if !self.location.is_empty() {
+ write!(f, " ({})", self.location)?;
+ }
+ if !self.description.is_empty() {
+ write!(f, "\n\t{}", self.description)?;
+ }
+ Ok(())
+ }
+}
+
+#[derive(Debug)]
+pub enum IcsError {
+ IoError(io::Error),
+ IcalError(parser::errors::Error),
+ IntError(ParseIntError),
+}
+
+impl From<io::Error> for IcsError {
+ fn from(err: io::Error) -> IcsError {
+ IcsError::IoError(err)
+ }
+}
+
+impl From<parser::errors::Error> for IcsError {
+ fn from(err: parser::errors::Error) -> IcsError {
+ IcsError::IcalError(err)
+ }
+}
+
+impl From<ParseIntError> for IcsError {
+ fn from(err: ParseIntError) -> IcsError {
+ IcsError::IntError(err)
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index e7a11a9..4d9b703 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,14 @@
+extern crate ical;
+extern crate chrono;
+extern crate chrono_tz;
+
+use std::env;
+mod ics;
+
fn main() {
- println!("Hello, world!");
+ let args: Vec<_> = env::args().collect();
+ let events = ics::parse(&args[1]).unwrap();
+ for event in events {
+ println!("{}", event);
+ }
}