[evolution-mapi] Bug #642022 - Modified instances in a recurrent event disappear
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-mapi] Bug #642022 - Modified instances in a recurrent event disappear
- Date: Thu, 17 Feb 2011 17:21:46 +0000 (UTC)
commit bb7e7d839dcd985b7d4622c0f27b05d61ba9eb12
Author: Sean Finney <seanius seanius net>
Date: Thu Feb 17 18:20:51 2011 +0100
Bug #642022 - Modified instances in a recurrent event disappear
src/calendar/e-cal-backend-mapi.c | 54 +++--
.../exchange-mapi-cal-recur-utils.c | 235 ++++++++++++++++++--
.../exchange-mapi-cal-recur-utils.h | 2 +-
src/libexchangemapi/exchange-mapi-cal-utils.c | 14 +-
src/libexchangemapi/exchange-mapi-cal-utils.h | 2 +-
5 files changed, 270 insertions(+), 37 deletions(-)
---
diff --git a/src/calendar/e-cal-backend-mapi.c b/src/calendar/e-cal-backend-mapi.c
index 586f8b1..c46290d 100644
--- a/src/calendar/e-cal-backend-mapi.c
+++ b/src/calendar/e-cal-backend-mapi.c
@@ -420,6 +420,7 @@ mapi_cal_get_changes_cb (FetchItemsCallbackData *item_data, gpointer data)
GSList *streams = item_data->streams;
GSList *recipients = item_data->recipients;
GSList *attachments = item_data->attachments;
+ GSList *detached = NULL, *d_i = NULL;
ECalBackendMAPI *cbmapi = data;
ECalBackendMAPIPrivate *priv = cbmapi->priv;
icalcomponent_kind kind;
@@ -450,20 +451,27 @@ mapi_cal_get_changes_cb (FetchItemsCallbackData *item_data, gpointer data)
if (cache_comp == NULL) {
ECalComponent *comp = exchange_mapi_cal_util_mapi_props_to_comp (item_data->conn, kind, tmp, array,
streams, recipients, attachments,
- cache_dir, priv->default_zone, FALSE);
+ cache_dir, priv->default_zone, FALSE, &detached);
- if (E_IS_CAL_COMPONENT (comp)) {
- gchar *comp_str;
+ detached = g_slist_prepend (detached, comp);
- e_cal_component_commit_sequence (comp);
- comp_str = e_cal_component_get_as_string (comp);
+ for (d_i = detached; d_i; d_i = g_slist_next (d_i)) {
+ comp = d_i->data;
- put_component_to_store (cbmapi, comp);
- e_cal_backend_notify_object_created (E_CAL_BACKEND (cbmapi), (const gchar *) comp_str);
+ if (E_IS_CAL_COMPONENT (comp)) {
+ gchar *comp_str;
- g_free (comp_str);
+ e_cal_component_commit_sequence (comp);
+ put_component_to_store (cbmapi, comp);
+
+ comp_str = e_cal_component_get_as_string (comp);
+ e_cal_backend_notify_object_created (E_CAL_BACKEND (cbmapi), comp_str);
+ g_free (comp_str);
+ }
+
+ g_object_unref (comp);
}
- g_object_unref (comp);
+ g_slist_free (detached);
} else {
struct timeval t;
@@ -483,7 +491,7 @@ mapi_cal_get_changes_cb (FetchItemsCallbackData *item_data, gpointer data)
comp = exchange_mapi_cal_util_mapi_props_to_comp (item_data->conn, kind, tmp, array,
streams, recipients, attachments,
- cache_dir, priv->default_zone, FALSE);
+ cache_dir, priv->default_zone, FALSE, NULL);
e_cal_component_commit_sequence (comp);
modif_comp_str = e_cal_component_get_as_string (comp);
@@ -1190,6 +1198,7 @@ mapi_cal_cache_create_cb (FetchItemsCallbackData *item_data, gpointer data)
GSList *streams = item_data->streams;
GSList *recipients = item_data->recipients;
GSList *attachments = item_data->attachments;
+ GSList *detached = NULL, *d_i = NULL;
ECalBackendMAPI *cbmapi = E_CAL_BACKEND_MAPI (data);
ECalBackendMAPIPrivate *priv = cbmapi->priv;
icalcomponent_kind kind;
@@ -1225,18 +1234,27 @@ mapi_cal_cache_create_cb (FetchItemsCallbackData *item_data, gpointer data)
tmp = exchange_mapi_util_mapi_id_to_string (mid);
comp = exchange_mapi_cal_util_mapi_props_to_comp (item_data->conn, kind, tmp, properties,
streams, recipients, attachments,
- cache_dir, priv->default_zone, FALSE);
+ cache_dir, priv->default_zone, FALSE, &detached);
g_free (tmp);
- if (E_IS_CAL_COMPONENT (comp)) {
- gchar *comp_str;
- e_cal_component_commit_sequence (comp);
- comp_str = e_cal_component_get_as_string (comp);
- e_cal_backend_notify_object_created (E_CAL_BACKEND (cbmapi), (const gchar *) comp_str);
- g_free (comp_str);
- put_component_to_store (cbmapi, comp);
+ detached = g_slist_prepend (detached, comp);
+ for (d_i = detached; d_i; d_i = g_slist_next (d_i)) {
+ comp = d_i->data;
+
+ if (E_IS_CAL_COMPONENT (comp)) {
+ gchar *comp_str;
+
+ e_cal_component_commit_sequence (comp);
+ put_component_to_store (cbmapi, comp);
+
+ comp_str = e_cal_component_get_as_string (comp);
+ e_cal_backend_notify_object_created (E_CAL_BACKEND (cbmapi), comp_str);
+ g_free (comp_str);
+ }
+
g_object_unref (comp);
}
+ g_slist_free (detached);
exchange_mapi_util_free_stream_list (&streams);
exchange_mapi_util_free_recipient_list (&recipients);
diff --git a/src/libexchangemapi/exchange-mapi-cal-recur-utils.c b/src/libexchangemapi/exchange-mapi-cal-recur-utils.c
index 452a235..1af71cf 100644
--- a/src/libexchangemapi/exchange-mapi-cal-recur-utils.c
+++ b/src/libexchangemapi/exchange-mapi-cal-recur-utils.c
@@ -26,6 +26,7 @@
#endif
#include "exchange-mapi-cal-recur-utils.h"
+#include <libecal/e-cal-util.h>
/* Reader/Writer versions */
#define READER_VERSION 0x3004
@@ -76,6 +77,18 @@ struct ExceptionInfo {
};
#endif
+/* Override flags defining what fields might be found in ExceptionInfo */
+#define ARO_SUBJECT 0x0001
+#define ARO_MEETINGTYPE 0x0002
+#define ARO_REMINDERDELTA 0x0004
+#define ARO_REMINDER 0x0008
+#define ARO_LOCATION 0x0010
+#define ARO_BUSYSTATUS 0x0020
+#define ARO_ATTACHMENT 0x0040
+#define ARO_SUBTYPE 0x0080
+#define ARO_APPTCOLOR 0x0100
+#define ARO_EXCEPTIONAL_BODY 0x0200
+
static icalrecurrencetype_weekday
get_ical_weekstart (uint32_t fdow)
{
@@ -234,11 +247,11 @@ check_calendar_type (guint16 type)
}
gboolean
-exchange_mapi_cal_util_bin_to_rrule (GByteArray *ba, ECalComponent *comp)
+exchange_mapi_cal_util_bin_to_rrule (GByteArray *ba, ECalComponent *comp, GSList **extra_detached)
{
struct icalrecurrencetype rt;
guint16 flag16;
- guint32 flag32;
+ guint32 flag32, writer_version;
guint8 *ptr = ba->data;
gint i;
GSList *exdate_list = NULL;
@@ -632,7 +645,9 @@ exchange_mapi_cal_util_bin_to_rrule (GByteArray *ba, ECalComponent *comp)
/* number of changed exceptions */
flag32 = *((guint32 *)ptr);
ptr += sizeof (guint32);
- /* FIXME: Parse modified instances */
+ /* For each changed exception, there will be a corresponding
+ ExceptionInfo below. So at present we don't need to do
+ anything with the information here beyond skipping it */
if (flag32)
ptr += flag32 * sizeof (guint32);
@@ -654,11 +669,11 @@ exchange_mapi_cal_util_bin_to_rrule (GByteArray *ba, ECalComponent *comp)
return FALSE;
/* some constant */
- flag32 = *((guint32 *)ptr);
+ writer_version = *((guint32 *)ptr);
ptr += sizeof (guint32);
/* It should be set, but not must. It can be, technically, any value.
Seen were 0x3006, 0x3008, 0x3009. It affects format of extended exception info
- if (flag32 != WRITER_VERSION2)
+ if (writer_version != WRITER_VERSION2)
return FALSE; */
/* start time in mins */
@@ -669,15 +684,6 @@ exchange_mapi_cal_util_bin_to_rrule (GByteArray *ba, ECalComponent *comp)
flag32 = *((guint32 *)ptr);
ptr += sizeof (guint32);
- /* modified exceptions */
- flag16 = *((guint16 *)ptr);
- ptr += sizeof (guint16);
- /* FIXME: there are flag16 count modified exceptions here, which
- are variable in size, followed by a ReservedBlock1{Size,}
- and ReservedBlock2{Size,}. However, since we have nothing
- else to do until we are able to parse these modified
- instances, we just stop now. */
-
/* Set the recurrence */
{
GSList l;
@@ -691,6 +697,207 @@ exchange_mapi_cal_util_bin_to_rrule (GByteArray *ba, ECalComponent *comp)
/* FIXME: this also has modified instances */
e_cal_component_set_exdate_list (comp, exdate_list);
+ /* modified exceptions, an ExceptionCount sized list of
+ ExceptionInfo instances */
+ flag16 = *((guint16 *)ptr);
+ ptr += sizeof (guint16);
+ if (flag16 && extra_detached) {
+ gint count = flag16;
+
+ e_cal_component_commit_sequence (comp);
+
+ for (i = 0; i < count; i++) {
+ uint32_t starttime, endtime, origtime;
+ guint16 overrideflags;
+ struct icaltimetype tt;
+ ECalComponent *detached = NULL;
+ ECalComponentDateTime edt;
+ ECalComponentRange rid;
+
+ /* ExceptionInfo.StartTime */
+ starttime = *((guint32 *)ptr);
+ ptr += sizeof (guint32);
+
+ /* ExceptionInfo.EndTime */
+ endtime = *((guint32 *)ptr);
+ ptr += sizeof (guint32);
+
+ /* ExceptionInfo.OriginalStartDate */
+ origtime = *((guint32 *)ptr);
+ ptr += sizeof (guint32);
+
+ /* make a shallow clone of comp */
+ detached = e_cal_component_clone (comp);
+
+ tt = icaltime_from_timet_with_zone (convert_recurrence_minutes_to_timet (origtime), 0, 0);
+ rid.type = E_CAL_COMPONENT_RANGE_SINGLE;
+ rid.datetime.value = &tt;
+ rid.datetime.tzid = "UTC";
+ e_cal_component_set_recurid (detached, &rid);
+
+ tt = icaltime_from_timet_with_zone (convert_recurrence_minutes_to_timet (starttime), 0, 0);
+ edt.value = &tt;
+ edt.tzid = "UTC";
+ e_cal_component_set_dtstart (detached, &edt);
+
+ tt = icaltime_from_timet_with_zone (convert_recurrence_minutes_to_timet (endtime), 0, 0);
+ edt.value = &tt;
+ edt.tzid = "UTC";
+ e_cal_component_set_dtend (detached, &edt);
+
+ e_cal_component_set_rdate_list (detached, NULL);
+ e_cal_component_set_rrule_list (detached, NULL);
+ e_cal_component_set_exdate_list (detached, NULL);
+ e_cal_component_set_exrule_list (detached, NULL);
+
+ /* continue parsing stuff we don't need, because we need to
+ get to the next ExceptionInfo object or back out to the
+ containing AppointmentRecurrencePattern object */
+
+ /* ExceptionInfo.OverrideFlags */
+ overrideflags = *((guint16 *) ptr);
+ ptr += sizeof (guint16);
+
+ if (overrideflags & ARO_SUBJECT) {
+ ECalComponentText text = { 0 };
+ gchar *str;
+
+ /* ExceptionInfo.SubjectLength, ExceptionInfo.SubjectLength2
+ and ExceptionInfo.Subject */
+ ptr += sizeof (guint16);
+ flag16 = *(guint16 *)ptr; /* use SubjectLength2 */
+ ptr += sizeof (guint16);
+ /* note a discrepency in MS-OXOCAL here, which suggests that
+ Subject is actually 2 bytes */
+
+ str = g_strndup ((const gchar *) ptr, flag16);
+ text.value = str;
+ e_cal_component_set_summary (detached, &text);
+ g_free (str);
+
+ ptr += flag16;
+ }
+
+ if (overrideflags & ARO_MEETINGTYPE) {
+ /* ExceptionInfo.MeetingType */
+ ptr += sizeof (guint32);
+ }
+
+ if (overrideflags & ARO_REMINDERDELTA) {
+ /* ExceptionInfo.ReminderDelta */
+ ptr += sizeof (guint32);
+ }
+
+ if (overrideflags & ARO_REMINDER) {
+ /* ExceptionInfo.ReminderSet */
+ ptr += sizeof (guint32);
+ }
+
+ if (overrideflags & ARO_LOCATION) {
+ gchar *str;
+
+ /* ExceptionInfo.LocationLength, ExceptionInfo.LocationLength2
+ and ExceptionInfo.Location */
+ ptr += sizeof (guint16);
+ flag16 = *(guint16 *) ptr; /* use LocationLength2 */
+ ptr += sizeof (guint16);
+ /* note a discrepency in MS-OXOCAL here, which suggests that
+ Location is actually 4 bytes */
+
+ str = g_strndup ((const gchar *) ptr, flag16);
+ e_cal_component_set_location (detached, str);
+ g_free (str);
+
+ ptr += flag16;
+ }
+
+ if (overrideflags & ARO_BUSYSTATUS) {
+ /* ExceptionInfo.BusyStatus */
+ ptr += sizeof (guint32);
+ }
+
+ if (overrideflags & ARO_ATTACHMENT) {
+ /* ExceptionInfo.Attachment */
+ ptr += sizeof (guint32);
+ }
+
+ if (overrideflags & ARO_SUBTYPE) {
+ /* ExceptionInfo.Subtype */
+ ptr += sizeof (guint32);
+ }
+
+ if (overrideflags & ARO_APPTCOLOR) {
+ /* ExceptionInfo.AppointmentColor */
+ ptr += sizeof (guint32);
+ }
+
+ /* ExceptionInfo.ReservedBlock1Size */
+ flag32 = *((guint32 *)ptr);
+ ptr += sizeof (guint32) * 2;
+ /* The spec is self-contradicting regarding ReservedBlock1Size
+ And Reserved1Block here. Observations are that the former
+ exists as a 4 byte integer which "MUST" be but isn't always
+ set to 0, and ReservedBlock1 simply doesn't exist.
+ */
+
+ if (writer_version >= 0x3009) {
+ /* ChangeHighlight struct */
+ flag32 = *((guint32 *)ptr);
+ ptr += sizeof (guint32) * (1 + flag32);
+ }
+
+ /* ReservedBlockEE1Size */
+ flag32 = *((guint32 *)ptr);
+ ptr += sizeof (guint32);
+ if (!flag32) {
+ /* it's supposed to be 0 */
+
+ /* StartTime */
+ ptr += sizeof (guint32);
+
+ /* EndTime */
+ ptr += sizeof (guint32);
+
+ /* OriginalStartDate */
+ ptr += sizeof (guint32);
+
+ if (overrideflags & ARO_SUBJECT) {
+ ECalComponentText text = { 0 };
+ gchar *str;
+
+ /* SubjectLength */
+ flag16 = *(guint16 *)ptr;
+ ptr += sizeof (guint16);
+
+ str = g_convert ((const gchar *) ptr, flag16 * 2, "UTF-8", "UTF-16", NULL, NULL, NULL);
+ text.value = str;
+ e_cal_component_set_summary (detached, &text);
+ g_free (str);
+
+ ptr += flag16 * 2;
+ }
+
+ if (overrideflags & ARO_LOCATION) {
+ gchar *str;
+
+ /* LocationLength */
+ flag16 = *(guint16 *)ptr;
+ ptr += sizeof (guint16);
+
+ str = g_convert ((const gchar *) ptr, flag16 * 2, "UTF-8", "UTF-16", NULL, NULL, NULL);
+ e_cal_component_set_location (detached, str);
+ g_free (str);
+
+ ptr += flag16 * 2;
+ }
+ }
+
+ *extra_detached = g_slist_append (*extra_detached, detached);
+ }
+ }
+
+ /* in case anyone ever needs to traverse further, from this point ptr
+ should be pointing at AppointmentRecurrencePattern.ReservedBlock1Size */
return TRUE;
}
diff --git a/src/libexchangemapi/exchange-mapi-cal-recur-utils.h b/src/libexchangemapi/exchange-mapi-cal-recur-utils.h
index 621b8d9..faa26b4 100644
--- a/src/libexchangemapi/exchange-mapi-cal-recur-utils.h
+++ b/src/libexchangemapi/exchange-mapi-cal-recur-utils.h
@@ -31,7 +31,7 @@
G_BEGIN_DECLS
gboolean
-exchange_mapi_cal_util_bin_to_rrule (GByteArray *ba, ECalComponent *comp);
+exchange_mapi_cal_util_bin_to_rrule (GByteArray *ba, ECalComponent *comp, GSList **extra_detached);
GByteArray *
exchange_mapi_cal_util_rrule_to_bin (ECalComponent *comp, GSList *modified_comps);
diff --git a/src/libexchangemapi/exchange-mapi-cal-utils.c b/src/libexchangemapi/exchange-mapi-cal-utils.c
index a3c87ce..4e91253 100644
--- a/src/libexchangemapi/exchange-mapi-cal-utils.c
+++ b/src/libexchangemapi/exchange-mapi-cal-utils.c
@@ -692,7 +692,7 @@ id_to_string (GByteArray *ba)
ECalComponent *
exchange_mapi_cal_util_mapi_props_to_comp (ExchangeMapiConnection *conn, icalcomponent_kind kind, const gchar *mid, struct mapi_SPropValue_array *properties,
GSList *streams, GSList *recipients, GSList *attachments,
- const gchar *local_store_uri, const icaltimezone *default_zone, gboolean is_reply)
+ const gchar *local_store_uri, const icaltimezone *default_zone, gboolean is_reply, GSList **detached_components)
{
ECalComponent *comp = NULL;
struct timeval t;
@@ -957,7 +957,7 @@ exchange_mapi_cal_util_mapi_props_to_comp (ExchangeMapiConnection *conn, icalcom
if (b && *b) {
stream = exchange_mapi_util_find_stream (streams, PidLidAppointmentRecur);
if (stream) {
- exchange_mapi_cal_util_bin_to_rrule (stream->value, comp);
+ exchange_mapi_cal_util_bin_to_rrule (stream->value, comp, detached_components);
}
}
@@ -1074,6 +1074,7 @@ fetch_camel_cal_comp_cb (FetchItemsCallbackData *item_data, gpointer data)
{
struct fetch_camel_cal_data *fccd = data;
ECalComponent *comp = NULL;
+ GSList *detached_recurrences = NULL, *d_i = NULL;
mapi_id_t mid = 0;
icalcomponent *icalcomp = NULL;
gchar *str = NULL, *smid = NULL, *filepath;
@@ -1093,7 +1094,8 @@ fetch_camel_cal_comp_cb (FetchItemsCallbackData *item_data, gpointer data)
smid = e_cal_component_gen_uid();
comp = exchange_mapi_cal_util_mapi_props_to_comp (item_data->conn, fccd->kind, smid,
item_data->properties, item_data->streams, item_data->recipients,
- item_data->attachments, filepath, NULL, TRUE);
+ item_data->attachments, filepath, NULL, TRUE,
+ &detached_recurrences);
g_free (smid);
}
@@ -1105,10 +1107,16 @@ fetch_camel_cal_comp_cb (FetchItemsCallbackData *item_data, gpointer data)
if (comp)
icalcomponent_add_component (icalcomp,
icalcomponent_new_clone(e_cal_component_get_icalcomponent(comp)));
+ for (d_i = detached_recurrences; d_i; d_i = g_slist_next (d_i)) {
+ icalcomponent_add_component (icalcomp,
+ icalcomponent_new_clone (e_cal_component_get_icalcomponent (d_i->data)));
+ g_object_unref (d_i->data);
+ }
str = icalcomponent_as_ical_string_r (icalcomp);
icalcomponent_free (icalcomp);
if (comp)
g_object_unref (comp);
+ g_slist_free (detached_recurrences);
exchange_mapi_util_free_stream_list (&item_data->streams);
exchange_mapi_util_free_recipient_list (&item_data->recipients);
diff --git a/src/libexchangemapi/exchange-mapi-cal-utils.h b/src/libexchangemapi/exchange-mapi-cal-utils.h
index d88acfa..0d6a1c3 100644
--- a/src/libexchangemapi/exchange-mapi-cal-utils.h
+++ b/src/libexchangemapi/exchange-mapi-cal-utils.h
@@ -85,7 +85,7 @@ exchange_mapi_cal_util_fetch_attachments (ECalComponent *comp, GSList **attach_l
ECalComponent *
exchange_mapi_cal_util_mapi_props_to_comp (ExchangeMapiConnection *conn, icalcomponent_kind kind, const gchar *mid, struct mapi_SPropValue_array *properties,
GSList *streams, GSList *recipients, GSList *attachments,
- const gchar *local_store_uri, const icaltimezone *default_zone, gboolean is_reply);
+ const gchar *local_store_uri, const icaltimezone *default_zone, gboolean is_reply, GSList **detached_components);
void
exchange_mapi_cal_util_generate_globalobjectid (gboolean is_clean, const gchar *uid, struct Binary_r *sb);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]