[california] Support DURATION when DTEND not present: Bug #737709
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [california] Support DURATION when DTEND not present: Bug #737709
- Date: Wed, 29 Oct 2014 23:34:38 +0000 (UTC)
commit be88a2f6d2ad9f2d0402fafd2e15aa306721d370
Author: Jim Nelson <jim yorba org>
Date: Wed Oct 29 16:33:39 2014 -0700
Support DURATION when DTEND not present: Bug #737709
DTEND is optional in VEVENTs. If not present, iCal specifies rules
for determining it, including using DURATION.
src/component/component-date-time.vala | 51 +++++++++++++++++++++++++++++++-
src/component/component-event.vala | 34 ++++++++++++++++++++-
vapi/libical.vapi | 28 +++++++++---------
3 files changed, 96 insertions(+), 17 deletions(-)
---
diff --git a/src/component/component-date-time.vala b/src/component/component-date-time.vala
index d7a0d66..a4cf2b8 100644
--- a/src/component/component-date-time.vala
+++ b/src/component/component-date-time.vala
@@ -80,8 +80,19 @@ public class DateTime : BaseObject, Gee.Hashable<DateTime>, Gee.Comparable<DateT
init_from_property(prop);
}
+ private DateTime.from_icaltimetype(iCal.icaltimetype dt, iCal.icalproperty_kind kind) {
+ this.dt = dt;
+ this.kind = kind;
+ this.value = "";
+ }
+
private void init_from_property(iCal.icalproperty prop) throws ComponentError {
- unowned iCal.icalvalue prop_value = prop.get_value();
+ unowned iCal.icalvalue? prop_value = prop.get_value();
+ if (prop_value == null) {
+ throw new ComponentError.UNAVAILABLE("Property of kind %s has no associated value",
+ prop.isa().to_string());
+ }
+
switch (prop_value.isa()) {
case iCal.icalvalue_kind.DATE_VALUE:
dt = prop_value.get_date();
@@ -167,6 +178,44 @@ public class DateTime : BaseObject, Gee.Hashable<DateTime>, Gee.Comparable<DateT
}
/**
+ * Return a { link DateTime} adjusted with the supplied iCal component's DURATION and the
+ * supplied property kind.
+ *
+ * The returned DateTime will have an empty string for its value.
+ *
+ * @throws ComponentError.UNAVAILABLE if DURATION not found
+ * @throws ComponentError.INVALID if not a valid DURATION (including a null DURATION)
+ */
+ public DateTime adjust_duration(iCal.icalcomponent ical_component, iCal.icalproperty_kind new_kind)
+ throws ComponentError {
+ unowned iCal.icalproperty? prop = ical_component.get_first_property(
+ iCal.icalproperty_kind.DURATION_PROPERTY);
+ if (prop == null)
+ throw new ComponentError.UNAVAILABLE("No DURATION property found");
+
+ unowned iCal.icalvalue? value = prop.get_value();
+ if (value == null)
+ throw new ComponentError.UNAVAILABLE("No value for DURATION property");
+
+ if (value.isa() != iCal.icalvalue_kind.DURATION_VALUE)
+ throw new ComponentError.INVALID("DURATION property does not have a DURATION value");
+
+ iCal.icaldurationtype duration = value.get_duration();
+ if (duration.is_bad_duration() != 0 || duration.is_null_duration() != 0)
+ throw new ComponentError.INVALID("DURATION value is bad or null");
+
+ // if adjusting a DATE DTSTART, only days and weeks are to be respected in the adjustment:
+ // https://tools.ietf.org/html/rfc5545#section-3.8.2.5
+ if (kind == iCal.icalproperty_kind.DTSTART_PROPERTY && is_date) {
+ duration.hours = 0;
+ duration.minutes = 0;
+ duration.seconds = 0;
+ }
+
+ return new DateTime.from_icaltimetype(iCal.icaltime_add(dt, duration), new_kind);
+ }
+
+ /**
* Converts the stored iCal DATE-TIME to an { link Calendar.ExactTime}.
*
* Returns null if { link is_date} is true.
diff --git a/src/component/component-event.vala b/src/component/component-event.vala
index 1ead71e..00f13c8 100644
--- a/src/component/component-event.vala
+++ b/src/component/component-event.vala
@@ -122,12 +122,42 @@ public class Event : Instance, Gee.Comparable<Event> {
description = ical_component.get_description();
DateTime dt_start = new DateTime(ical_component, iCal.icalproperty_kind.DTSTART_PROPERTY);
- DateTime dt_end = new DateTime(ical_component, iCal.icalproperty_kind.DTEND_PROPERTY);
+
+ // DTSTART is required for a valid VEVENT but DTEND is not. See
+ // https://tools.ietf.org/html/rfc5545#section-3.6.1 for how a missing DTEND is treated
+ // when interpreting a VEVENT.
+ DateTime? dt_end = null;
+ try {
+ dt_end = new DateTime(ical_component, iCal.icalproperty_kind.DTEND_PROPERTY);
+ } catch (ComponentError comperr) {
+ // if UNAVAILABLE, fall through and follow interpretation rules in iCal spec
+ if (!(comperr is ComponentError.UNAVAILABLE))
+ throw comperr;
+ }
+
+ // If no DTEND, look for a DURATION
+ if (dt_end == null) {
+ try {
+ dt_end = dt_start.adjust_duration(ical_component, iCal.icalproperty_kind.DTEND_PROPERTY);
+ } catch (ComponentError comperr) {
+ // fall through
+ }
+ }
+
+ bool dtend_inclusive = false;
+ if (dt_end == null) {
+ // For DTSTART w/ DATE, treat DTEND as one-day event; for DATETIME, use DTSTART for DTEND.
+ // Because DTEND is non-inclusive in VEVENTs, that means use the same value in both cases
+ // and just don't convert as non-inclusive
+ dt_end = dt_start;
+ dtend_inclusive = true;
+ }
+
// convert start and end DATE/DATE-TIMEs to internal values ... note that VEVENT dtend
// is non-inclusive (see https://tools.ietf.org/html/rfc5545#section-3.6.1)
Calendar.DateSpan? date_span;
Calendar.ExactTimeSpan? exact_time_span;
- DateTime.to_span(dt_start, dt_end, false, out date_span, out exact_time_span);
+ DateTime.to_span(dt_start, dt_end, dtend_inclusive, out date_span, out exact_time_span);
if (exact_time_span != null) {
set_event_exact_time_span(exact_time_span);
} else {
diff --git a/vapi/libical.vapi b/vapi/libical.vapi
index 9b50119..5ad3c1a 100644
--- a/vapi/libical.vapi
+++ b/vapi/libical.vapi
@@ -99,7 +99,7 @@ namespace iCal {
[CCode (cname = "icalcomponent_get_due")]
public iCal.icaltimetype get_due ();
[CCode (cname = "icalcomponent_get_duration")]
- public unowned iCal.icaldurationtype get_duration ();
+ public iCal.icaldurationtype get_duration ();
[CCode (cname = "icalcomponent_get_first_component")]
public unowned iCal.icalcomponent? get_first_component (iCal.icalcomponent_kind kind);
[CCode (cname = "icalcomponent_get_first_property")]
@@ -213,9 +213,9 @@ namespace iCal {
[CCode (cname = "icalcomponent_new_xstandard", has_construct_function = false)]
public icalcomponent.xstandard ();
}
- [CCode (cheader_filename = "libical/ical.h")]
- [Compact]
- public class icaldurationtype {
+ [CCode (cheader_filename = "libical/ical.h", cname="struct icaldurationtype")]
+ [SimpleType]
+ public struct icaldurationtype {
public uint days;
public uint hours;
public int is_neg;
@@ -229,17 +229,17 @@ namespace iCal {
[CCode (cname = "icaldurationtype_as_int")]
public int as_int ();
[CCode (cname = "icaldurationtype_bad_duration")]
- public static unowned iCal.icaldurationtype bad_duration ();
+ public static iCal.icaldurationtype bad_duration ();
[CCode (cname = "icaldurationtype_from_int")]
- public static unowned iCal.icaldurationtype from_int (int t);
+ public static iCal.icaldurationtype from_int (int t);
[CCode (cname = "icaldurationtype_from_string")]
- public static unowned iCal.icaldurationtype from_string (string p1);
+ public static iCal.icaldurationtype from_string (string p1);
[CCode (cname = "icaldurationtype_is_bad_duration")]
public int is_bad_duration ();
[CCode (cname = "icaldurationtype_is_null_duration")]
public int is_null_duration ();
[CCode (cname = "icaldurationtype_null_duration")]
- public static unowned iCal.icaldurationtype null_duration ();
+ public static iCal.icaldurationtype null_duration ();
}
[CCode (cheader_filename = "libical/ical.h", free_function = "icalparameter_free")]
[Compact]
@@ -657,7 +657,7 @@ namespace iCal {
[CCode (cname = "icalproperty_get_due")]
public iCal.icaltimetype get_due ();
[CCode (cname = "icalproperty_get_duration")]
- public unowned iCal.icaldurationtype get_duration ();
+ public iCal.icaldurationtype get_duration ();
[CCode (cname = "icalproperty_get_exdate")]
public iCal.icaltimetype get_exdate ();
[CCode (cname = "icalproperty_get_expand")]
@@ -779,7 +779,7 @@ namespace iCal {
[CCode (cname = "icalproperty_get_url")]
public unowned string get_url ();
[CCode (cname = "icalproperty_get_value")]
- public unowned iCal.icalvalue get_value ();
+ public unowned iCal.icalvalue? get_value ();
[CCode (cname = "icalproperty_get_value_as_string")]
public unowned string get_value_as_string ();
[CCode (cname = "icalproperty_get_value_as_string_r")]
@@ -1502,7 +1502,7 @@ namespace iCal {
[CCode (cname = "icalvalue_get_datetimeperiod")]
public iCal.icaldatetimeperiodtype get_datetimeperiod ();
[CCode (cname = "icalvalue_get_duration")]
- public unowned iCal.icaldurationtype get_duration ();
+ public iCal.icaldurationtype get_duration ();
[CCode (cname = "icalvalue_get_float")]
public global::float get_float ();
[CCode (cname = "icalvalue_get_geo")]
@@ -1694,7 +1694,7 @@ namespace iCal {
public struct icalperiodtype {
public iCal.icaltimetype start;
public iCal.icaltimetype end;
- public weak iCal.icaldurationtype duration;
+ public iCal.icaldurationtype duration;
[CCode (cname = "icalperiodtype_as_ical_string")]
public unowned string as_ical_string ();
[CCode (cname = "icalperiodtype_as_ical_string_r")]
@@ -1789,7 +1789,7 @@ namespace iCal {
[CCode (cheader_filename = "libical/ical.h")]
public struct icaltriggertype {
public iCal.icaltimetype time;
- public weak iCal.icaldurationtype duration;
+ public iCal.icaldurationtype duration;
[CCode (cname = "icaltriggertype_from_int")]
public static iCal.icaltriggertype from_int (int reltime);
[CCode (cname = "icaltriggertype_from_string")]
@@ -2640,7 +2640,7 @@ namespace iCal {
[CCode (cheader_filename = "libical/ical.h", cname = "icaltime_start_doy_week")]
public static int icaltime_start_doy_week (iCal.icaltimetype t, int fdow);
[CCode (cheader_filename = "libical/ical.h", cname = "icaltime_subtract")]
- public static unowned iCal.icaldurationtype icaltime_subtract (iCal.icaltimetype t1,
iCal.icaltimetype t2);
+ public static iCal.icaldurationtype icaltime_subtract (iCal.icaltimetype t1, iCal.icaltimetype t2);
[CCode (cheader_filename = "libical/ical.h", cname = "icaltime_today")]
public static iCal.icaltimetype icaltime_today ();
[CCode (cheader_filename = "libical/ical.h", cname = "icaltime_week_number")]
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]