summaryrefslogtreecommitdiffstats
path: root/src/icalwrap
diff options
context:
space:
mode:
authorVincent Breitmoser <look@my.amazin.horse>2019-01-22 00:26:08 +0100
committerVincent Breitmoser <look@my.amazin.horse>2019-01-22 00:26:09 +0100
commitc29e7535e7b0cdfd1ac75e6d0b32a16105032f40 (patch)
tree5cd8cb5f7b6b3c4b7e8f544cf46923b733a6002d /src/icalwrap
parenta129d318c3e2b26f453ba16d3f408ef3436354bf (diff)
work around race conditions in libical
libical has some weird behavior that makes it not thread-safe. we synchronize calls to libical timezone conversion methods to work around this problem. https://github.com/libical/libical/issues/86 https://github.com/libical/libical/commit/0ebf2d9a7183be94991c2681c6e3f009c64cf7cc
Diffstat (limited to 'src/icalwrap')
-rw-r--r--src/icalwrap/icaltime.rs21
-rw-r--r--src/icalwrap/icalvevent.rs14
-rw-r--r--src/icalwrap/mod.rs10
3 files changed, 37 insertions, 8 deletions
diff --git a/src/icalwrap/icaltime.rs b/src/icalwrap/icaltime.rs
index 5ab54cd..72aa533 100644
--- a/src/icalwrap/icaltime.rs
+++ b/src/icalwrap/icaltime.rs
@@ -4,6 +4,7 @@ use chrono::prelude::*;
use ical;
use utils::dateutil;
use super::IcalTimeZone;
+use super::TZ_MUTEX;
use std::fmt::{Error,Display,Formatter};
use std::str::FromStr;
@@ -17,6 +18,7 @@ impl IcalTime {
}
pub fn from_timestamp(timestamp: i64) -> Self {
+ let _lock = TZ_MUTEX.lock();
let utc = IcalTimeZone::utc();
let is_date = 0;
let time = unsafe {
@@ -25,6 +27,11 @@ impl IcalTime {
IcalTime{ time }
}
+ pub fn get_timestamp(&self) -> i64 {
+ let _lock = TZ_MUTEX.lock();
+ unsafe { ical::icaltime_as_timet_with_zone(self.time, self.time.zone) }
+ }
+
pub fn as_date(&self) -> IcalTime {
let mut time = self.time.clone();
time.is_date = 1;
@@ -39,10 +46,12 @@ impl IcalTime {
}
pub fn with_timezone(&self, timezone: &IcalTimeZone) -> IcalTime {
+ let _lock = TZ_MUTEX.lock();
let time = unsafe {
ical::icaltime_convert_to_zone(self.time, **timezone)
};
- IcalTime { time }
+ let result = IcalTime { time };
+ result
}
}
@@ -85,6 +94,12 @@ impl FromStr for IcalTime {
}
}
+impl From<ical::icaltimetype> for IcalTime {
+ fn from(time: ical::icaltimetype) -> IcalTime {
+ IcalTime { time }
+ }
+}
+
impl<T: Into<IcalTime> + Clone> From<&T> for IcalTime {
fn from(time: &T) -> IcalTime {
time.clone().into()
@@ -132,6 +147,7 @@ mod tests {
let now = IcalTime::now();
assert_eq!("20130101T010203Z", now.to_string());
+ assert_eq!(1357002123, now.get_timestamp());
}
#[test]
@@ -141,7 +157,7 @@ mod tests {
let time = IcalTime::from(local_time);
assert_eq!("Europe/Berlin", time.get_timezone().get_name());
- assert_eq!("20140101T010203", time.to_string());
+ assert_eq!(1388534523, time.get_timestamp());
}
#[test]
@@ -153,6 +169,7 @@ mod tests {
assert_eq!("US/Eastern", time.get_timezone().get_name());
assert_eq!("20121231T200203", time.to_string());
+ assert_eq!(1357002123, time.get_timestamp());
}
#[test]
diff --git a/src/icalwrap/icalvevent.rs b/src/icalwrap/icalvevent.rs
index a57b0da..126eb77 100644
--- a/src/icalwrap/icalvevent.rs
+++ b/src/icalwrap/icalvevent.rs
@@ -3,6 +3,7 @@ use std::ffi::CStr;
use super::IcalComponent;
use super::IcalVCalendar;
+use super::IcalTime;
use ical;
pub struct IcalVEvent {
@@ -61,15 +62,16 @@ impl IcalVEvent {
}
}
- pub fn get_dtstart_unix(&self) -> Option<i64> {
+ pub fn get_dtstart_ical(&self) -> Option<IcalTime> {
match self.instance_timestamp {
- Some(timestamp) => Some(timestamp.timestamp()),
+ Some(timestamp) => Some(IcalTime::from_timestamp(timestamp.timestamp())),
None => unsafe {
let dtstart = ical::icalcomponent_get_dtstart(self.ptr);
if ical::icaltime_is_null_time(dtstart) == 1 {
None
} else {
- Some(ical::icaltime_as_timet_with_zone(dtstart, dtstart.zone))
+ let icaltime = IcalTime::from(dtstart);
+ Some(icaltime)
}
}
}
@@ -77,12 +79,12 @@ impl IcalVEvent {
pub fn get_dtend(&self) -> Option<DateTime<Local>> {
let dtend = self.get_dtend_unix()?;
- Some(Utc.timestamp(dtend, 0).with_timezone(&Local))
+ Some(Local.timestamp(dtend, 0))
}
pub fn get_dtstart(&self) -> Option<DateTime<Local>> {
- let dtstart = self.get_dtstart_unix()?;
- Some(Utc.timestamp(dtstart, 0).with_timezone(&Local))
+ let dtstart = self.get_dtstart_ical()?.get_timestamp();
+ Some(Local.timestamp(dtstart, 0))
}
pub fn get_dtstart_date(&self) -> Option<Date<Local>> {
diff --git a/src/icalwrap/mod.rs b/src/icalwrap/mod.rs
index dc41b71..ca0e0da 100644
--- a/src/icalwrap/mod.rs
+++ b/src/icalwrap/mod.rs
@@ -5,6 +5,16 @@ mod icalcomponent;
mod icaltime;
mod icaltimezone;
+// libical does some weird, non-threadsafe things in timezone methods, notably
+// icaltime_convert_to_zone (which is also called in icaltime_as_timet_with_zone)
+// see these two (independent!) bugs:
+// https://github.com/libical/libical/issues/86
+// https://github.com/libical/libical/commit/0ebf2d9a7183be94991c2681c6e3f009c64cf7cc
+use std::sync::Mutex;
+lazy_static! {
+ static ref TZ_MUTEX: Mutex<i32> = Mutex::new(0);
+}
+
pub use self::icalvcalendar::IcalVCalendar;
pub use self::icalvcalendar::IcalEventIter;
pub use self::icalvevent::IcalVEvent;