diff options
Diffstat (limited to 'src/icalwrap')
-rw-r--r-- | src/icalwrap/icalcomponent.rs | 131 | ||||
-rw-r--r-- | src/icalwrap/icalduration.rs | 177 | ||||
-rw-r--r-- | src/icalwrap/icalproperty.rs | 60 | ||||
-rw-r--r-- | src/icalwrap/icaltime.rs | 365 | ||||
-rw-r--r-- | src/icalwrap/icaltimezone.rs | 153 | ||||
-rw-r--r-- | src/icalwrap/icalvcalendar.rs | 670 | ||||
-rw-r--r-- | src/icalwrap/icalvevent.rs | 394 | ||||
-rw-r--r-- | src/icalwrap/mod.rs | 26 |
8 files changed, 0 insertions, 1976 deletions
diff --git a/src/icalwrap/icalcomponent.rs b/src/icalwrap/icalcomponent.rs deleted file mode 100644 index 4da7eba..0000000 --- a/src/icalwrap/icalcomponent.rs +++ /dev/null @@ -1,131 +0,0 @@ -use std::ffi::CString; - -use super::IcalProperty; -use crate::ical; - -pub trait IcalComponent { - fn get_ptr(&self) -> *mut ical::icalcomponent; - fn as_component(&self) -> &dyn IcalComponent; - - fn get_property(&self, property_kind: ical::icalproperty_kind) -> Option<IcalProperty<'_>> { - let property = unsafe { - ical::icalcomponent_get_first_property(self.get_ptr(), property_kind) - }; - if !property.is_null() { - Some(IcalProperty::from_ptr(property, self.as_component())) - } else { - None - } - } - - fn get_properties(self: &Self, property_kind: ical::icalproperty_kind) -> Vec<IcalProperty<'_>> { - let mut properties = Vec::new(); - unsafe { - let mut property_ptr = ical::icalcomponent_get_first_property(self.get_ptr(), property_kind); - while !property_ptr.is_null() { - let property = IcalProperty::from_ptr(property_ptr, self.as_component()); - properties.push(property); - property_ptr = ical::icalcomponent_get_next_property(self.get_ptr(), property_kind); - } - } - properties - } - - fn get_properties_all(&self) -> Vec<IcalProperty<'_>> { - self.get_properties(ical::icalproperty_kind_ICAL_ANY_PROPERTY) - } - - fn get_properties_by_name(&self, property_name: &str) -> Vec<IcalProperty> { - let property_kind = unsafe { - let c_str = CString::new(property_name).unwrap(); - ical::icalproperty_string_to_kind(c_str.as_ptr()) - }; - self.get_properties(property_kind) - } - - fn get_property_by_name(&self, property_name: &str) -> Option<IcalProperty> { - let property_kind = unsafe { - let c_str = CString::new(property_name).unwrap(); - ical::icalproperty_string_to_kind(c_str.as_ptr()) - }; - self.get_property(property_kind) - } - - unsafe fn remove_property_all(&self, kind: ical::icalproperty_kind) -> usize { - - unsafe fn remove_property_inner(comp: *mut ical::icalcomponent, kind: ical::icalproperty_kind) -> usize { - let mut count = 0; - let mut prop = ical::icalcomponent_get_first_property(comp, kind); - while !prop.is_null() { - ical::icalcomponent_remove_property(comp, prop); - count += 1; - prop = ical::icalcomponent_get_current_property(comp); - } - let mut inner_comp = ical::icalcomponent_get_first_component(comp, ical::icalcomponent_kind_ICAL_ANY_COMPONENT); - while !inner_comp.is_null() { - count += remove_property_inner(inner_comp, kind); - inner_comp = ical::icalcomponent_get_next_component(comp, ical::icalcomponent_kind_ICAL_ANY_COMPONENT) - } - count - } - - let comp = self.get_ptr(); - remove_property_inner(comp, kind) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::testdata; - use crate::icalwrap::IcalVCalendar; - - #[test] - fn get_property_test() { - let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_MULTIDAY, None).unwrap(); - let event = cal.get_principal_event(); - let prop_name = "SUMMARY"; - let prop_value: String = event.get_property_by_name(prop_name).unwrap().get_value(); - - assert_eq!("Festival International de Jazz de Montreal".to_string(), prop_value); - } - - #[test] - fn get_property_test_lastmodified() { - let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_MULTIDAY_LASTMODIFIED, None).unwrap(); - let event = cal.get_principal_event(); - let prop_name = "LAST-MODIFIED"; - let prop_value: String = event.get_property_by_name(prop_name).unwrap().get_value(); - - assert_eq!("20070423T123432Z".to_string(), prop_value); - } - - #[test] - fn get_property_test_cal() { - let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_MULTIDAY, None).unwrap(); - let prop_name = "PRODID"; - let prop_value: String = cal.get_property_by_name(prop_name).unwrap().get_value(); - - assert_eq!("-//ABC Corporation//NONSGML My Product//EN".to_string(), prop_value); - } - - #[test] - fn get_property_test_negative() { - let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_MULTIDAY, None).unwrap(); - let event = cal.get_principal_event(); - let prop_name = "DESCRIPTION"; - let prop = event.get_property_by_name(prop_name); - - assert!(prop.is_none()); - } - - #[test] - fn get_property_by_name_test() { - let cal = IcalVCalendar::from_str(testdata::TEST_EVENT_MULTIDAY, None).unwrap(); - let event = cal.get_principal_event(); - let prop_name = "NONSENSE"; - let prop = event.get_property_by_name(prop_name); - - assert!(prop.is_none()); - } -} diff --git a/src/icalwrap/icalduration.rs b/src/icalwrap/icalduration.rs deleted file mode 100644 index 7ad1d13..0000000 --- a/src/icalwrap/icalduration.rs +++ /dev/null @@ -1,177 +0,0 @@ -use std::ops::{Deref,Add}; -use std::ffi::{CStr,CString}; -use crate::ical; -use std::fmt::{Error,Display,Formatter}; -use std::str::FromStr; -use std::cmp::Ordering; - - -#[derive(Clone,Debug)] -pub struct IcalDuration { - duration: ical::icaldurationtype, -} - -impl IcalDuration { - pub fn from_seconds(seconds: i32) -> IcalDuration { - let duration = unsafe { ical::icaldurationtype_from_int(seconds) }; - IcalDuration{ duration } - } - - pub fn to_seconds(&self) -> i32 { - unsafe { ical::icaldurationtype_as_int(self.duration) } - } -} - -impl Deref for IcalDuration { - type Target = ical::icaldurationtype; - - fn deref(&self) -> &ical::icaldurationtype { - &self.duration - } -} - -impl Display for IcalDuration { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - let cstr = unsafe { - CStr::from_ptr(ical::icaldurationtype_as_ical_string(self.duration)) - }; - let string = cstr.to_string_lossy(); - write!(f, "{}", string) - } -} - -impl FromStr for IcalDuration { - type Err = String; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - let c_str = CString::new(s).unwrap(); - let duration = unsafe { - let duration = ical::icaldurationtype_from_string(c_str.as_ptr()); - if ical::icaldurationtype_is_null_duration(duration) == 0 { - Some(duration) - } else { - None - } - }; - if let Some(duration) = duration { - Ok(IcalDuration { duration }) - } else { - return Err(format!("Could not parse duration {}", s)); - } - } -} - -impl PartialEq<IcalDuration> for IcalDuration { - fn eq(&self, rhs: &IcalDuration) -> bool { - self.to_seconds() == rhs.to_seconds() - } -} - -impl Eq for IcalDuration {} - -impl PartialOrd for IcalDuration { - fn partial_cmp(&self, rhs: &IcalDuration) -> Option<Ordering> { - Some(self.cmp(rhs)) - } -} - -impl Ord for IcalDuration { - fn cmp(&self, rhs: &IcalDuration) -> Ordering { - let left = self.to_seconds(); - let right = rhs.to_seconds(); - if left == right { - Ordering::Equal - } else if left < right { - Ordering::Less - } else { - Ordering::Greater - } - } -} - -impl From<ical::icaldurationtype> for IcalDuration { - fn from(duration: ical::icaldurationtype) -> IcalDuration { - IcalDuration { duration } - } -} - -impl From<IcalDuration> for chrono::Duration { - fn from(duration: IcalDuration) -> chrono::Duration { - chrono::Duration::seconds(i64::from(duration.to_seconds())) - } -} - -impl From<chrono::Duration> for IcalDuration { - fn from(duration: chrono::Duration) -> IcalDuration { - IcalDuration::from_seconds(duration.num_seconds() as i32) - } -} -impl Add for IcalDuration { - type Output = IcalDuration; - - fn add(self, other: IcalDuration) -> IcalDuration { - let seconds = self.to_seconds() + other.to_seconds(); - IcalDuration::from_seconds(seconds) - } -} - - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parse() { - let duration = "PT86400S".parse::<IcalDuration>().unwrap(); - assert_eq!(IcalDuration::from_seconds(24*60*60), duration); - assert_eq!(86400, duration.to_seconds()); - } - - #[test] - fn test_parse_fail() { - let duration = "swag".parse::<IcalDuration>(); - assert!(duration.is_err()); - } - - #[test] - fn test_display() { - let duration = IcalDuration::from_seconds(5*24*60*60 + 22*60*60 + 33*60 + 33); - assert_eq!("P5DT22H33M33S", duration.to_string()); - } - - #[test] - fn test_to_chrono() { - let from_duration = IcalDuration::from_seconds(5*24*60*60 + 22*60*60 + 33*60 + 33); - let duration: chrono::Duration = from_duration.into(); - assert_eq!(chrono::Duration::seconds(5*24*60*60 + 22*60*60 + 33*60 + 33), duration); - } - - #[test] - fn test_from_chrono() { - let from_duration = chrono::Duration::seconds(5*24*60*60 + 22*60*60 + 33*60 + 33); - let duration: IcalDuration = from_duration.into(); - assert_eq!(IcalDuration::from_seconds(5*24*60*60 + 22*60*60 + 33*60 + 33), duration); - } - - #[test] - fn test_add() { - let fst = IcalDuration::from_seconds(123); - let snd = IcalDuration::from_seconds(4567); - - let sum = fst + snd; - - assert_eq!(IcalDuration::from_seconds(123+4567), sum); - } - - #[test] - fn test_cmp() { - let more = IcalDuration::from_seconds(49128); - let less = IcalDuration::from_seconds(5); - - assert!(less == less); - assert!(more == more); - assert!(less < more); - assert!(!(more < less)); - assert!(!(more == less)); - } -} diff --git a/src/icalwrap/icalproperty.rs b/src/icalwrap/icalproperty.rs deleted file mode 100644 index ad903c1..0000000 --- a/src/icalwrap/icalproperty.rs +++ /dev/null @@ -1,60 +0,0 @@ -use chrono::NaiveDate; -use std::ffi::CStr; -use std::fmt; - -use super::icalcomponent::IcalComponent; -use crate::ical; - -pub struct IcalProperty<'a> { - pub ptr: *mut ical::icalproperty, - _parent: &'a dyn IcalComponent, -} - -impl<'a> Drop for IcalProperty<'a> { - fn drop(&mut self) { - unsafe { - ical::icalproperty_free(self.ptr); - } - } -} - -impl<'a> fmt::Debug for IcalProperty<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.as_ical_string()) - } -} - -impl<'a> IcalProperty<'a> { - pub fn from_ptr(ptr: *mut ical::icalproperty, parent: &'a dyn IcalComponent) -> Self { - IcalProperty { ptr, _parent: parent } - } - - pub fn get_name(&self) -> String { - unsafe { - let cstr = CStr::from_ptr(ical::icalproperty_get_property_name(self.ptr)); - cstr.to_string_lossy().into_owned() - } - } - - pub fn get_value(&self) -> String { - unsafe { - let cstr = CStr::from_ptr(ical::icalproperty_get_value_as_string(self.ptr)); - cstr.to_string_lossy().into_owned() - } - } - - pub fn as_ical_string(&self) -> String { - unsafe { - let cstr = CStr::from_ptr(ical::icalproperty_as_ical_string(self.ptr)); - cstr.to_string_lossy().trim().to_owned() - } - } - - pub fn get_value_as_date(&self) -> Option<NaiveDate> { - unsafe { - let date = ical::icaltime_from_string(ical::icalproperty_get_value_as_string(self.ptr)); - NaiveDate::from_ymd_opt(date.year, date.month as u32, date.day as u32) - } - } -} - diff --git a/src/icalwrap/icaltime.rs b/src/icalwrap/icaltime.rs deleted file mode 100644 index 18a2b80..0000000 --- a/src/icalwrap/icaltime.rs +++ /dev/null @@ -1,365 +0,0 @@ -use std::ops::{Add,Deref}; -use std::ffi::{CStr,CString}; -use chrono::{Date,DateTime,TimeZone,Utc,Local}; -use crate::ical; -use crate::utils::dateutil; -use super::IcalTimeZone; -use super::IcalDuration; -use super::TZ_MUTEX; -use std::fmt::{Error,Display,Formatter}; -use std::str::FromStr; - -#[derive(Clone,Debug)] -pub struct IcalTime { - time: ical::icaltimetype, -} - -impl IcalTime { - pub fn utc() -> Self { - dateutil::now().into() - } - - pub fn local() -> Self { - dateutil::now().with_timezone(&Local).into() - } - - pub fn floating_ymd(year: i32, month: i32, day: i32) -> Self { - let time = ical::icaltimetype{ - year, month, day, - hour: 0, minute: 0, second: 0, - is_date: 1, - is_daylight: 0, - zone: ::std::ptr::null(), - }; - IcalTime{ time } - } - - pub fn and_hms(&self, hour: i32, minute: i32, second: i32) -> Self { - let mut time = self.time; - time.hour = hour; - time.minute = minute; - time.second = second; - time.is_date = 0; - - IcalTime{ time } - } - - pub fn from_timestamp(timestamp: i64) -> Self { - let _lock = TZ_MUTEX.lock(); - let utc = IcalTimeZone::utc(); - let is_date = 0; - let time = unsafe { - ical::icaltime_from_timet_with_zone(timestamp, is_date, *utc) - }; - IcalTime{ time } - } - - pub fn timestamp(&self) -> i64 { - let _lock = TZ_MUTEX.lock(); - unsafe { ical::icaltime_as_timet_with_zone(self.time, self.time.zone) } - } - - pub fn is_date(&self) -> bool { - self.time.is_date != 0 - } - - pub fn as_date(&self) -> IcalTime { - let mut time = self.time; - time.is_date = 1; - IcalTime{ time } - } - - pub fn get_timezone(&self) -> Option<IcalTimeZone> { - if self.time.zone.is_null() { - return None; - } - let tz_ptr = unsafe { - ical::icaltime_get_timezone(self.time) - }; - Some(IcalTimeZone::from_ptr_copy(tz_ptr)) - } - - pub fn with_timezone(&self, timezone: &IcalTimeZone) -> IcalTime { - let _lock = TZ_MUTEX.lock(); - let mut time = unsafe { - ical::icaltime_convert_to_zone(self.time, **timezone) - }; - //icaltime_convert_to_zone does nothing if is_date == 1 - time.zone = **timezone; - IcalTime { time } - } - - pub fn pred(&self) -> IcalTime { - let mut time = self.time; - time.day -= 1; - let time = unsafe { ical::icaltime_normalize(time) }; - IcalTime{ time } - } - - pub fn succ(&self) -> IcalTime { - let mut time = self.time; - time.day += 1; - let time = unsafe { ical::icaltime_normalize(time) }; - IcalTime{ time } - } -} - -impl Deref for IcalTime { - type Target = ical::icaltimetype; - - fn deref(&self) -> &ical::icaltimetype { - &self.time - } -} - -impl Display for IcalTime { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - let cstr = unsafe { - CStr::from_ptr(ical::icaltime_as_ical_string(self.time)) - }; - let string = cstr.to_string_lossy(); - write!(f, "{}", string) - } -} - -impl FromStr for IcalTime { - type Err = String; - - fn from_str(s: &str) -> Result<Self, Self::Err> { - unsafe { - let c_str = CString::new(s).unwrap(); - let time = ical::icaltime_from_string(c_str.as_ptr()); - if ical::icaltime_is_null_time(time) == 0 { - Ok(IcalTime { time }) - } else { - Err(format!("Could not parse time {}", s)) - } - } - } -} - -impl PartialEq<IcalTime> for IcalTime { - fn eq(&self, rhs: &IcalTime) -> bool { - let _lock = TZ_MUTEX.lock(); - let cmp = unsafe { ical::icaltime_compare(self.time, rhs.time) }; - cmp == 0 - } -} - -impl Eq for IcalTime {} - -impl From<ical::icaltimetype> for IcalTime { - fn from(time: ical::icaltimetype) -> IcalTime { - IcalTime { time } - } -} - -impl Add<IcalDuration> for IcalTime { - type Output = IcalTime; - - fn add(self, other: IcalDuration) -> IcalTime { - let time = unsafe { ical::icaltime_add(self.time, *other) }; - IcalTime { time } - } -} - -impl<T: Into<IcalTime> + Clone> From<&T> for IcalTime { - fn from(time: &T) -> IcalTime { - time.clone().into() - } -} - -impl From<DateTime<Local>> for IcalTime { - fn from(time: DateTime<Local>) -> IcalTime { - let timestamp = time.timestamp(); - let local = IcalTimeZone::local(); - IcalTime::from_timestamp(timestamp).with_timezone(&local) - } -} - -impl From<DateTime<Utc>> for IcalTime { - fn from(time: DateTime<Utc>) -> IcalTime { - let timestamp = time.timestamp(); - IcalTime::from_timestamp(timestamp) - } -} - -impl From<Date<Local>> for IcalTime { - fn from(date: Date<Local>) -> IcalTime { - let timestamp = date.with_timezone(&Utc).and_hms(0, 0, 0).timestamp(); - let timezone = IcalTimeZone::local(); - IcalTime::from_timestamp(timestamp).with_timezone(&timezone).as_date() - } -} - -impl From<Date<Utc>> for IcalTime { - fn from(date: Date<Utc>) -> IcalTime { - let timestamp = date.and_hms(0, 0, 0).timestamp(); - IcalTime::from_timestamp(timestamp).as_date() - } -} - -impl From<IcalTime> for Date<Local> { - fn from(time: IcalTime) -> Date<Local> { - Local.timestamp(time.timestamp(), 0).date() - } -} - -impl From<IcalTime> for DateTime<Local> { - fn from(time: IcalTime) -> DateTime<Local> { - Local.timestamp(time.timestamp(), 0) - } -} - -impl From<IcalTime> for Date<Utc> { - fn from(time: IcalTime) -> Date<Utc> { - Utc.timestamp(time.timestamp(), 0).date() - } -} - -impl From<IcalTime> for DateTime<Utc> { - fn from(time: IcalTime) -> DateTime<Utc> { - Utc.timestamp(time.timestamp(), 0) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use crate::testdata; - - #[test] - fn test_now() { - let now = IcalTime::utc(); - - assert_eq!("20130101T010203Z", now.to_string()); - assert_eq!(1357002123, now.timestamp()); - } - - #[test] - fn test_from_local() { - testdata::setup(); - let local_time = Local.ymd(2014, 01, 01).and_hms(01, 02, 03); - let time = IcalTime::from(local_time); - - assert_eq!("Europe/Berlin", time.get_timezone().unwrap().get_name()); - assert_eq!(1388534523, time.timestamp()); - } - - #[test] - fn test_local() { - testdata::setup(); - let time = IcalTime::local(); - assert_eq!("20130101T020203", time.to_string()); - } - - #[test] - fn test_parse() { - let time = "20130101T010203Z".parse::<IcalTime>().unwrap(); - assert_eq!("20130101T010203Z", time.to_string()); - } - - #[test] - fn test_parse_negative() { - let time = "201XXX01T010203Z".parse::<IcalTime>(); - assert!(time.is_err()); - } - - #[test] - fn test_with_timezone() { - let utc = IcalTime::utc(); - let tz = IcalTimeZone::from_name("US/Eastern").unwrap(); - - let time = utc.with_timezone(&tz); - - assert_eq!("US/Eastern", time.get_timezone().unwrap().get_name()); - assert_eq!("20121231T200203", time.to_string()); - assert_eq!(1357002123, time.timestamp()); - } - - #[test] - fn test_get_timezone_negative() { - let time = IcalTime::floating_ymd(2018, 02, 03); - assert!(time.get_timezone().is_none()); - } - - #[test] - fn test_from_local_date() { - testdata::setup(); - let local_date = Local.ymd(2014, 01, 01); - let time = IcalTime::from(local_date); - - assert_eq!("Europe/Berlin", time.get_timezone().unwrap().get_name()); - assert_eq!("20140101", time.to_string()); - } - - #[test] - fn test_from_utc_date() { - let utc_date = Utc.ymd(2014, 01, 01); - let time = IcalTime::from(utc_date); - - assert_eq!("UTC", time.get_timezone().unwrap().get_name()); - assert_eq!("20140101", time.to_string()); - } - - #[test] - fn test_into_utc_date() { - let time = IcalTimeZone::utc().ymd(2014, 02, 02); - let date: Date<Utc> = time.into(); - assert_eq!(Utc.ymd(2014, 02, 02), date); - } - - #[test] - fn test_into_utc_datetime() { - let time = IcalTimeZone::utc().ymd(2014, 02, 02).and_hms(13, 37, 00); - let datetime: DateTime<Utc> = time.into(); - assert_eq!(Utc.ymd(2014, 02, 02).and_hms(13, 37, 00), datetime); - } - - #[test] - fn test_into_local_date() { - testdata::setup(); - let time = IcalTimeZone::local().ymd(2014, 02, 02); - let date: Date<Local> = time.into(); - assert_eq!(Local.ymd(2014, 02, 02), date); - } - - #[test] - fn test_into_local_datetime() { - testdata::setup(); - let time = IcalTimeZone::local().ymd(2014, 02, 02).and_hms(13, 37, 00); - let datetime: DateTime<Local> = time.into(); - assert_eq!(Local.ymd(2014, 02, 02).and_hms(13, 37, 00), datetime); - } - - #[test] - fn test_into_local_datetime_utc() { - testdata::setup(); - let time = IcalTimeZone::utc().ymd(2014, 02, 02).and_hms(13, 37, 00); - let datetime: DateTime<Local> = time.into(); - assert_eq!(Local.ymd(2014, 02, 02).and_hms(14, 37, 00), datetime); - } - - #[test] - fn test_add() { - let now = IcalTime::utc(); - let duration = IcalDuration::from_seconds(123); - - let sum = now + duration; - - assert_eq!(1357002123 + 123, sum.timestamp()); - } - - #[test] - fn test_pred() { - let time = IcalTime::utc(); - assert_eq!("20121231T010203Z", time.pred().to_string()); - } - - #[test] - fn test_succ() { - let time = IcalTime::utc(); - assert_eq!("20130102T010203Z", time.succ().to_string()); - } -} diff --git a/src/icalwrap/icaltimezone.rs b/src/icalwrap/icaltimezone.rs deleted file mode 100644 index 90fe4cf..0000000 --- a/src/icalwrap/icaltimezone.rs +++ /dev/null @@ -1,153 +0,0 @@ -use std::ops::Deref; -use std::ffi::{CString,CStr}; -use crate::ical; - -use crate::utils::dateutil; -use super::IcalTime; - -pub struct IcalTimeZone { - timezone: *mut ical::icaltimezone, -} - -impl Deref for IcalTimeZone { - type Target = *mut ical::icaltimezone; - - fn deref(&self) -> &*mut ical::icaltimezone { - &self.timezone - } -} - - -impl IcalTimeZone { - pub fn from_ptr_copy(ptr: *const ical::icaltimezone) -> Self { - let timezone = unsafe { - // unsafe, but we know icaltimezone_copy doesn't actually mutate - ical::icaltimezone_copy(ptr as *mut ical::icaltimezone) - }; - IcalTimeZone{ timezone } - } - - pub fn from_name(tz_name: &str) -> Result<Self,String> { - let tz_cstr = CString::new(tz_name).unwrap(); - let builtin = unsafe { ical::icaltimezone_get_builtin_timezone(tz_cstr.as_ptr()) }; - if !builtin.is_null() { - // need to copy here to guarantee we don't touch the builtin zones - let timezone = unsafe { ical::icaltimezone_copy(builtin) }; - Ok(IcalTimeZone{ timezone }) - } else { - Err(format!("Unknown timezone: {}", tz_name)) - } - } - - pub fn local() -> Self { - let tz_name = dateutil::find_local_timezone(); - IcalTimeZone::from_name(&tz_name).unwrap() - } - - pub fn utc() -> Self { - let timezone = unsafe { ical::icaltimezone_get_utc_timezone() }; - IcalTimeZone{ timezone } - } - - pub fn get_name(&self) -> String { - unsafe { - let name = ical::icaltimezone_get_display_name(self.timezone); - CStr::from_ptr(name).to_string_lossy().trim().to_string() - } - } - - pub fn get_offset_at_time(&self, time: &IcalTime) -> i32 { - let mut icaltime = **time; - let mut is_dst = 0; - unsafe { - ical::icaltimezone_get_utc_offset(self.timezone, &mut icaltime , &mut is_dst) - } - } - - pub fn ymd(&self, year: i32, month: i32, day: i32) -> IcalTime { - IcalTime::floating_ymd(year, month, day).with_timezone(&self) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - use crate::testdata; - - #[test] - fn test_utc() { - let tz = IcalTimeZone::utc(); - assert_eq!("UTC", tz.get_name()); - } - - #[test] - fn test_local() { - testdata::setup(); - let tz = IcalTimeZone::local(); - assert_eq!("Europe/Berlin", tz.get_name()); - } - - #[test] - fn test_get_offset_utc() { - testdata::setup(); - let tz = IcalTimeZone::utc(); - let time = IcalTime::utc(); - - let offset = tz.get_offset_at_time(&time); - - assert_eq!(0, offset); - } - - #[test] - fn test_get_offset_local() { - testdata::setup(); - let time = IcalTime::utc(); - let tz = IcalTimeZone::local(); - - let offset = tz.get_offset_at_time(&time); - - assert_eq!(60*60, offset); - } - - #[test] - fn test_ymd() { - let tz = IcalTimeZone::from_name("US/Eastern").unwrap(); - let date = tz.ymd(2014,3,1); - assert_eq!(IcalTime::floating_ymd(2014,3,1), date); - assert_eq!(1393650000, date.timestamp()); - assert_eq!("US/Eastern", date.get_timezone().unwrap().get_name()); - } - - #[test] - fn test_ymd_and_hms() { - let tz = IcalTimeZone::from_name("US/Eastern").unwrap(); - let date = tz.ymd(2014,3,1).and_hms(17, 20, 0); - assert_eq!(IcalTime::floating_ymd(2014,3,1).and_hms(17, 20, 0), date); - assert_eq!(1393712400, date.timestamp()); - assert_eq!("US/Eastern", date.get_timezone().unwrap().get_name()); - } - - #[test] - fn test_from_name() { - let tz = IcalTimeZone::from_name("US/Eastern").unwrap(); - assert_eq!("US/Eastern", tz.get_name()); - } - - #[test] - fn test_from_name_fail() { - let tz = IcalTimeZone::from_name("lulz"); - assert!(tz.is_err()); - } - - #[test] - fn test_get_offset_eastern() { - let time = IcalTime::utc(); - let tz = IcalTimeZone::from_name("US/Eastern").unwrap(); - - let offset = tz.get_offset_at_time(&time); - - assert_eq!(-5*60*60, offset); - } - -} diff --git a/src/icalwrap/icalvcalendar.rs b/src/icalwrap/icalvcalendar.rs deleted file mode 100644 index ced299a..0000000 --- a/src/icalwrap/icalvcalendar.rs +++ /dev/null @@ -1,670 +0,0 @@ -use std::ffi::{CStr, CString}; -use std::io; -use std::path::{Path, PathBuf}; -use std::rc::Rc; - -use super::IcalComponent; -use super::IcalTime; -use super::IcalVEvent; -use crate::ical; -use crate::khevent::KhEvent; - -pub struct IcalVCalendar { - comp: Rc<IcalComponentOwner>, - path: Option<PathBuf>, - instance_timestamp: Option<IcalTime>, -} - -pub struct IcalEventIter<'a> { - iter: ical::icalcompiter, - parent: &'a IcalVCalendar, -} - -impl IcalComponent for IcalVCalendar { - fn get_ptr(&self) -> *mut ical::icalcomponent { - self.comp.ptr - } - - fn as_component(&self) -> &dyn IcalComponent { - self - } -} - -impl Clone for IcalVCalendar { - fn clone(&self) -> Self { - let new_comp_ptr = unsafe { ical::icalcomponent_new_clone(self.comp.ptr) }; - let mut new_calendar = IcalVCalendar::from_ptr(new_comp_ptr); - new_calendar.path = self.path.clone(); - new_calendar.instance_timestamp = self.instance_timestamp.clone(); - new_calendar - } -} - -impl IcalVCalendar { - fn from_ptr(ptr: *mut ical::icalcomponent) -> Self { - IcalVCalendar { - comp: Rc::new(IcalComponentOwner { ptr }), - path: None, - instance_timestamp: None, - } - } - - pub fn shallow_copy(&self) -> Self { - IcalVCalendar { - comp: self.comp.clone(), - path: self.path.clone(), - instance_timestamp: self.instance_timestamp.clone(), - } - } - - //pub fn with_internal_timestamp(mut self, datetime: &IcalTime) -> IcalVCalendar { - //self.instance_timestamp = Some(datetime.clone()); - //self - //} - - pub fn with_path(mut self, path: &Path) -> IcalVCalendar { - self.path = Some(path.to_path_buf()); - self - } - - //TODO should probably be private - pub fn from_str(str: &str, path: Option<&Path>) -> io::Result<Self> { - unsafe { - let c_str = CString::new(str).unwrap(); - let parsed_cal = ical::icalparser_parse_string(c_str.as_ptr()); - if parsed_cal.is_null() { - return Err(io::Error::new(io::ErrorKind::Other, "calendar has no path")); - } - - let kind = ical::icalcomponent_isa(parsed_cal); - if kind != ical::icalcomponent_kind_ICAL_VCALENDAR_COMPONENT { - let kind = CStr::from_ptr(ical::icalcomponent_kind_to_string(kind)).to_string_lossy(); - return Err(io::Error::new( - io::ErrorKind::Other, - format!("expected VCALENDAR component, got {}", kind), - )); - } - - let mut cal = IcalVCalendar::from_ptr(parsed_cal); - cal.path = path.map(|path| path.to_path_buf()); - - Ok(cal) - } - } - - pub fn with_normalize(self) -> Self { - unsafe { - ical::icalcomponent_normalize(self.get_ptr()); - } - self - } - - pub fn to_string(&self) -> String { - unsafe { - let ical_cstr = CStr::from_ptr(ical::icalcomponent_as_ical_string(self.get_ptr())); - ical_cstr.to_string_lossy().into_owned() - } - } - - pub fn get_uid(&self) -> String { - unsafe { - let uid_cstr = CStr::from_ptr(ical::icalcomponent_get_uid( - self.get_principal_event().get_ptr(), - )); - uid_cstr.to_string_lossy().into_owned() - } - } - - pub fn with_uid(mut self, uid: &str) -> Result<Self, String> { - { - let events = self.events_iter(); - if events.unique_uid_count() > 1 { - return Err(format!( - "More than one event in file: {}", - self.get_path_as_string().unwrap_or_else(|| "".to_string()) - )); - } - let events = self.events_iter(); - let uid_cstr = CString::new(uid).unwrap(); - for event in events { - unsafe { - ical::icalcomponent_set_uid(event.get_ptr(), uid_cstr.as_ptr()); - } - } - } - self.path = self - .path - .map(|path| path.with_file_name(uid.to_owned() + ".ics")); - Ok(self) - } - - pub fn with_dtstamp_now(self) -> Self { - let dtstamp = IcalTime::utc(); - unsafe { - ical::icalcomponent_set_dtstamp(self.get_ptr(), *dtstamp); - } - self - } - - pub fn with_dtstart(self, dtstart: &IcalTime) -> Self { - let event = self.get_principal_event(); - unsafe { - let timezone = event.get_dtstart().and_then(|x| x.get_timezone()); - match timezone { - Some(timezone) => { - ical::icalcomponent_set_dtstart(event.get_ptr(), *dtstart.with_timezone(&timezone)); - } - None => { - ical::icalcomponent_set_dtstart(event.get_ptr(), **dtstart); - } - } - } - self - } - - pub fn with_dtend(self, dtend: &IcalTime) -> Self { - let event = self.get_principal_event(); - unsafe { - let timezone = event.get_dtend().and_then(|x| x.get_timezone()); - match timezone { - Some(timezone) => { - ical::icalcomponent_set_dtend(event.get_ptr(), *dtend.with_timezone(&timezone)); - } - None => { - ical::icalcomponent_set_dtend(event.get_ptr(), **dtend); - } - } - } - self - } - - pub fn with_location(self, location: &str) -> Self { - let event = self.get_principal_event(); - unsafe { - let c_str = CString::new(location).unwrap(); - ical::icalcomponent_set_location(event.get_ptr(), c_str.as_ptr()); - } - self - } - - pub fn with_summary(self, summary: &str) -> Self { - let event = self.get_principal_event(); - unsafe { - let c_str = CString::new(summary).unwrap(); - ical::icalcomponent_set_summary(event.get_ptr(), c_str.as_ptr()); - } - self - } - - pub fn with_last_modified_now(self) -> Self { - let event = self.get_principal_event(); - unsafe { - let now_icaltime = IcalTime::utc(); - - let last_modified_kind = ic |