[california] Handle malformed .ics and VCALENDAR w/o METHOD: Closes bug #729108
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [california] Handle malformed .ics and VCALENDAR w/o METHOD: Closes bug #729108
- Date: Mon, 28 Apr 2014 23:26:17 +0000 (UTC)
commit 7378dce72a12b050c6a730d9af0b3ead67c3e59f
Author: Jim Nelson <jim yorba org>
Date: Mon Apr 28 16:24:12 2014 -0700
Handle malformed .ics and VCALENDAR w/o METHOD: Closes bug #729108
EventBrite offers iCalendar VEVENTS with no UID or DTSTAMPs, so deal
with that situation when it arises by generating our own. Likewise,
their VCALENDARs don't have a METHOD, so use PUBLISH.
.../backing-eds-calendar-source-subscription.vala | 10 ++++--
src/component/component-event.vala | 5 ++-
src/component/component-icalendar.vala | 16 ++++++++-
src/component/component-instance.vala | 39 +++++++++++++++-----
vapi/libical.vapi | 2 +-
5 files changed, 56 insertions(+), 16 deletions(-)
---
diff --git a/src/backing/eds/backing-eds-calendar-source-subscription.vala
b/src/backing/eds/backing-eds-calendar-source-subscription.vala
index e4faf20..8378711 100644
--- a/src/backing/eds/backing-eds-calendar-source-subscription.vala
+++ b/src/backing/eds/backing-eds-calendar-source-subscription.vala
@@ -124,14 +124,18 @@ internal class EdsCalendarSourceSubscription : CalendarSourceSubscription {
private void on_objects_modified(SList<weak iCal.icalcomponent> objects) {
foreach (weak iCal.icalcomponent ical_component in objects) {
+ Component.Event? event = null;
+
// only update known objects
- Component.Event? event = for_uid(new Component.UID(ical_component.get_uid()))
- as Component.Event;
+ string? uid = ical_component.get_uid();
+ if (!String.is_empty(uid))
+ event = for_uid(new Component.UID(uid)) as Component.Event;
+
if (event == null)
continue;
try {
- event.full_update(ical_component);
+ event.full_update(ical_component, null);
} catch (Error err) {
debug("Unable to update event %s: %s", event.to_string(), err.message);
}
diff --git a/src/component/component-event.vala b/src/component/component-event.vala
index 3923383..a54834e 100644
--- a/src/component/component-event.vala
+++ b/src/component/component-event.vala
@@ -101,8 +101,9 @@ public class Event : Instance, Gee.Comparable<Event> {
/**
* @inheritDoc
*/
- protected override void update_from_component(iCal.icalcomponent ical_component) throws Error {
- base.update_from_component(ical_component);
+ protected override void update_from_component(iCal.icalcomponent ical_component, UID? supplied_uid)
+ throws Error {
+ base.update_from_component(ical_component, supplied_uid);
summary = ical_component.get_summary();
description = ical_component.get_description();
diff --git a/src/component/component-icalendar.vala b/src/component/component-icalendar.vala
index e9e9b92..a6daa9a 100644
--- a/src/component/component-icalendar.vala
+++ b/src/component/component-icalendar.vala
@@ -22,6 +22,16 @@ namespace California.Component {
public class iCalendar : BaseObject {
/**
+ * Default METHOD when one is not supplied with iCalendar.
+ *
+ * NONE is not viable, as some backends will choke and require one. PUBLISH is a good
+ * general METHOD for VCALENDARs lacking a METHOD.
+ *
+ * @see method
+ */
+ public const iCal.icalproperty_method DEFAULT_METHOD = iCal.icalproperty_method.PUBLISH;
+
+ /**
* The VCALENDAR's PRODID.
*
* See [[https://tools.ietf.org/html/rfc5545#section-3.7.3]]
@@ -41,7 +51,7 @@ public class iCalendar : BaseObject {
*
* See [[https://tools.ietf.org/html/rfc5545#section-3.7.2]]
*/
- public iCal.icalproperty_method method { get; private set; default = iCal.icalproperty_method.NONE; }
+ public iCal.icalproperty_method method { get; private set; default = DEFAULT_METHOD; }
/**
* The VCALENDAR's CALSCALE.
@@ -86,9 +96,13 @@ public class iCalendar : BaseObject {
if (prop != null)
calscale = prop.get_calscale();
+ // METHOD is important ... if not present, be sure it's set (important for adding, some
+ // backends may require its presence)
prop = root.get_first_property(iCal.icalproperty_kind.METHOD_PROPERTY);
if (prop != null)
method = prop.get_method();
+ else
+ root.set_method(DEFAULT_METHOD);
//
// Contained components
diff --git a/src/component/component-instance.vala b/src/component/component-instance.vala
index f5c62ba..40cb7e8 100644
--- a/src/component/component-instance.vala
+++ b/src/component/component-instance.vala
@@ -128,9 +128,10 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
_ical_component = ical_component.clone();
// this needs to be stored before calling update() or the equality check there will fail
- uid = new UID(_ical_component.get_uid());
+ string? ical_uid = _ical_component.get_uid();
+ uid = !String.is_empty(ical_uid) ? new UID(ical_uid) : UID.generate();
- full_update(_ical_component);
+ full_update(_ical_component, uid);
// watch for property changes and update ical_component when happens
notify.connect(on_notify);
@@ -176,14 +177,16 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
* This is also called by the Instance base class constructor to give subclasses a single
* code path for updating their state.
*
+ * The { link UID} may be supplied if the iCal component does not have one.
+ *
* @throws BackingError if eds_component is not for this Instance.
*/
- public void full_update(iCal.icalcomponent ical_component) throws Error {
+ public void full_update(iCal.icalcomponent ical_component, UID? supplied_uid) throws Error {
in_full_update = true;
bool notify = false;
try {
- update_from_component(ical_component);
+ update_from_component(ical_component, supplied_uid);
notify = true;
} finally {
in_full_update = false;
@@ -200,18 +203,36 @@ public abstract class Instance : BaseObject, Gee.Hashable<Instance> {
* It's highly recommended the subclass call the base class update_from_component() first to
* allow it to do basic sanity checking before proceeding to update its own state.
*
+ * If supplied_uid is non-null, it should be used in preference over the UID in the iCal
+ * component. In either case, at least one method should return a valid UID.
+ *
* @see full_update
*/
- protected virtual void update_from_component(iCal.icalcomponent ical_component) throws Error {
- Component.UID other_uid = new Component.UID(ical_component.get_uid());
+ protected virtual void update_from_component(iCal.icalcomponent ical_component, UID? supplied_uid)
+ throws Error {
+ if (supplied_uid == null)
+ assert(!String.is_empty(ical_component.get_uid()));
+
+ // use the supplied UID before using the one in the iCal component (for dealing with
+ // malformed iCal w/ no UID ... I'm looking at you, EventBrite)
+ Component.UID other_uid = supplied_uid ?? new Component.UID(ical_component.get_uid());
if (!uid.equal_to(other_uid)) {
throw new BackingError.MISMATCH("Attempt to update component %s with component %s",
this.uid.to_string(), other_uid.to_string());
}
- DateTime dt_stamp = new DateTime(ical_component, iCal.icalproperty_kind.DTSTAMP_PROPERTY);
- if (!dt_stamp.is_date)
- dtstamp = dt_stamp.to_exact_time();
+ try {
+ DateTime dt_stamp = new DateTime(ical_component, iCal.icalproperty_kind.DTSTAMP_PROPERTY);
+ if (!dt_stamp.is_date)
+ dtstamp = dt_stamp.to_exact_time();
+ } catch (ComponentError comperr) {
+ // if unavailable, generate a DTSTAMP ... like UID, this is for malformed iCal with
+ // no DTSTAMP, i.e. EventBrite
+ if (!(comperr is ComponentError.UNAVAILABLE))
+ throw comperr;
+
+ dtstamp = Calendar.System.now;
+ }
try {
rid = new DateTime(ical_component, iCal.icalproperty_kind.RECURRENCEID_PROPERTY);
diff --git a/vapi/libical.vapi b/vapi/libical.vapi
index a04d261..c583a74 100644
--- a/vapi/libical.vapi
+++ b/vapi/libical.vapi
@@ -133,7 +133,7 @@ namespace iCal {
[CCode (cname = "icalcomponent_get_timezone")]
public unowned iCal.icaltimezone get_timezone (string tzid);
[CCode (cname = "icalcomponent_get_uid")]
- public unowned string get_uid ();
+ public unowned string? get_uid ();
[CCode (cname = "icalcomponent_is_valid")]
public int is_valid ();
[CCode (cname = "icalcomponent_isa")]
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]