aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/pcs/cal-backend-file.c
diff options
context:
space:
mode:
Diffstat (limited to 'calendar/pcs/cal-backend-file.c')
-rw-r--r--calendar/pcs/cal-backend-file.c220
1 files changed, 180 insertions, 40 deletions
diff --git a/calendar/pcs/cal-backend-file.c b/calendar/pcs/cal-backend-file.c
index 58429ecbe6..ab7b23dc83 100644
--- a/calendar/pcs/cal-backend-file.c
+++ b/calendar/pcs/cal-backend-file.c
@@ -274,7 +274,7 @@ lookup_component (CalBackendFile *cbfile, const char *uid)
static CalBackendSyncStatus
cal_backend_file_is_read_only (CalBackendSync *backend, Cal *cal, gboolean *read_only)
{
- CalBackendFile *cbfile = backend;
+ CalBackendFile *cbfile = (CalBackendFile *) backend;
*read_only = cbfile->priv->read_only;
@@ -396,7 +396,7 @@ check_dup_uid (CalBackendFile *cbfile, CalComponent *comp)
mark_dirty (cbfile);
}
-static char *
+static const char *
get_rid_string (CalComponent *comp)
{
CalComponentRange range;
@@ -412,6 +412,21 @@ get_rid_string (CalComponent *comp)
icaltime_as_ical_string (tt) : "0";
}
+static struct icaltimetype
+get_rid_icaltime (CalComponent *comp)
+{
+ CalComponentRange range;
+ struct icaltimetype tt;
+
+ cal_component_get_recurid (comp, &range);
+ if (!range.datetime.value)
+ return icaltime_null_time ();
+ tt = *range.datetime.value;
+ cal_component_free_range (&range);
+
+ return tt;
+}
+
/* Tries to add an icalcomponent to the file backend. We only store the objects
* of the types we support; all others just remain in the toplevel component so
* that we don't lose them.
@@ -427,7 +442,7 @@ add_component (CalBackendFile *cbfile, CalComponent *comp, gboolean add_to_tople
priv = cbfile->priv;
if (cal_component_is_instance (comp)) { /* FIXME: more checks needed, to detect detached instances */
- char *rid;
+ const char *rid;
cal_component_get_uid (comp, &uid);
@@ -485,7 +500,6 @@ remove_recurrence_cb (gpointer key, gpointer value, gpointer data)
GSList *categories;
icalcomponent *icalcomp;
CalBackendFilePrivate *priv;
- char *rid = key;
CalComponent *comp = value;
CalBackendFile *cbfile = data;
@@ -551,7 +565,7 @@ remove_component (CalBackendFile *cbfile, CalComponent *comp)
cal_backend_unref_categories (CAL_BACKEND (cbfile), categories);
cal_component_free_categories_list (categories);
- free_object (uid, obj_data, NULL);
+ free_object ((gpointer) uid, (gpointer) obj_data, NULL);
}
/* Scans the toplevel VCALENDAR component and stores the objects it finds */
@@ -1413,8 +1427,9 @@ cal_backend_file_modify_object (CalBackendSync *backend, Cal *cal, const char *c
CalBackendFilePrivate *priv;
icalcomponent *icalcomp;
icalcomponent_kind kind;
- const char *comp_uid;
- CalComponent *comp;
+ const char *comp_uid, *rid;
+ char *real_rid;
+ CalComponent *comp, *recurrence;
CalBackendFileObject *obj_data;
struct icaltimetype current;
@@ -1428,7 +1443,7 @@ cal_backend_file_modify_object (CalBackendSync *backend, Cal *cal, const char *c
if (!icalcomp)
return GNOME_Evolution_Calendar_InvalidObject;
- /* FIXME Check kind with the parent */
+ /* check kind with the parent */
kind = icalcomponent_isa (icalcomp);
if (kind != ICAL_VEVENT_COMPONENT && kind != ICAL_VTODO_COMPONENT) {
icalcomponent_free (icalcomp);
@@ -1453,15 +1468,58 @@ cal_backend_file_modify_object (CalBackendSync *backend, Cal *cal, const char *c
cal_component_set_last_modified (comp, &current);
/* handle mod_type */
- if (cal_component_is_instance (comp) ||
- mod != CALOBJ_MOD_ALL) {
- /* FIXME */
- } else {
+ switch (mod) {
+ case CALOBJ_MOD_THIS :
+ rid = get_rid_string (comp);
+ if (!rid || !*rid) {
+ g_object_unref (comp);
+ return GNOME_Evolution_Calendar_ObjectNotFound;
+ }
+
+ if (g_hash_table_lookup_extended (obj_data->recurrences, rid,
+ &real_rid, &recurrence)) {
+ /* remove the component from our data */
+ icalcomponent_remove_component (priv->icalcomp,
+ cal_component_get_icalcomponent (recurrence));
+ priv->comp = g_list_remove (priv->comp, recurrence);
+ g_hash_table_remove (obj_data->recurrences, rid);
+
+ /* free memory */
+ g_free (real_rid);
+ g_object_unref (recurrence);
+ } else {
+ char *old, *new;
+
+ old = cal_component_get_as_string (obj_data->full_object);
+
+ cal_util_remove_instances (cal_component_get_icalcomponent (obj_data->full_object),
+ get_rid_icaltime (comp),
+ mod);
+
+ new = cal_component_get_as_string (obj_data->full_object);
+
+ cal_backend_notify_object_modified (CAL_BACKEND (backend), old, new);
+
+ g_free (old);
+ g_free (new);
+ }
+
+ /* add the detached instance */
+ g_hash_table_insert (obj_data->recurrences, g_strdup (get_rid_string (comp)), comp);
+ break;
+ case CALOBJ_MOD_THISANDPRIOR :
+ break;
+ case CALOBJ_MOD_THISANDFUTURE :
+ break;
+ case CALOBJ_MOD_ALL :
+ /* in this case, we blow away all recurrences, and start over
+ with a clean component */
/* Remove the old version */
remove_component (cbfile, obj_data->full_object);
- /* Add the object */
+ /* Add the new object */
add_component (cbfile, comp, TRUE);
+ break;
}
mark_dirty (cbfile);
@@ -1472,6 +1530,92 @@ cal_backend_file_modify_object (CalBackendSync *backend, Cal *cal, const char *c
return GNOME_Evolution_Calendar_Success;
}
+static void
+remove_instance (CalBackendFile *cbfile, CalBackendFileObject *obj_data, const char *rid)
+{
+ char *hash_rid;
+ CalComponent *comp;
+ GSList *categories;
+
+ if (!rid || !*rid)
+ return;
+
+ if (g_hash_table_lookup_extended (obj_data->recurrences, rid, &hash_rid, &comp)) {
+ /* remove the component from our data */
+ icalcomponent_remove_component (cbfile->priv->icalcomp,
+ cal_component_get_icalcomponent (comp));
+ cbfile->priv->comp = g_list_remove (cbfile->priv->comp, comp);
+ g_hash_table_remove (obj_data->recurrences, rid);
+
+ /* update the set of categories */
+ cal_component_get_categories_list (comp, &categories);
+ cal_backend_unref_categories (CAL_BACKEND (cbfile), categories);
+ cal_component_free_categories_list (categories);
+
+ /* free memory */
+ g_free (hash_rid);
+ g_object_unref (comp);
+
+ return;
+ }
+
+ /* remove the component from our data, temporarily */
+ icalcomponent_remove_component (cbfile->priv->icalcomp,
+ cal_component_get_icalcomponent (obj_data->full_object));
+ cbfile->priv->comp = g_list_remove (cbfile->priv->comp, obj_data->full_object);
+
+ cal_util_remove_instances (cal_component_get_icalcomponent (obj_data->full_object),
+ icaltime_from_string (rid), CALOBJ_MOD_THIS);
+
+ /* add the modified object to the beginning of the list,
+ so that it's always before any detached instance we
+ might have */
+ cbfile->priv->comp = g_list_prepend (cbfile->priv->comp, obj_data->full_object);
+}
+
+typedef struct {
+ CalBackendFile *cbfile;
+ CalBackendFileObject *obj_data;
+ const char *rid;
+ CalObjModType mod;
+} RemoveRecurrenceData;
+
+static gboolean
+remove_object_instance_cb (gpointer key, gpointer value, gpointer user_data)
+{
+ time_t fromtt, instancett;
+ GSList *categories;
+ char *rid = key;
+ CalComponent *instance = value;
+ RemoveRecurrenceData *rrdata = user_data;
+
+ fromtt = icaltime_as_timet (icaltime_from_string (rrdata->rid));
+ instancett = icaltime_as_timet (get_rid_icaltime (instance));
+
+ if (fromtt > 0 && instancett > 0) {
+ if ((rrdata->mod == CALOBJ_MOD_THISANDPRIOR && instancett <= fromtt) ||
+ (rrdata->mod == CALOBJ_MOD_THISANDFUTURE && instancett >= fromtt)) {
+ /* remove the component from our data */
+ icalcomponent_remove_component (rrdata->cbfile->priv->icalcomp,
+ cal_component_get_icalcomponent (instance));
+ rrdata->cbfile->priv->comp = g_list_remove (rrdata->cbfile->priv->comp, instance);
+
+ /* update the set of categories */
+ cal_component_get_categories_list (instance, &categories);
+ cal_backend_unref_categories (CAL_BACKEND (rrdata->cbfile), categories);
+ cal_component_free_categories_list (categories);
+
+ /* free memory */
+ g_free (rid);
+ g_object_unref (instance);
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
/* Remove_object handler for the file backend */
static CalBackendSyncStatus
cal_backend_file_remove_object (CalBackendSync *backend, Cal *cal,
@@ -1482,8 +1626,8 @@ cal_backend_file_remove_object (CalBackendSync *backend, Cal *cal,
CalBackendFilePrivate *priv;
CalBackendFileObject *obj_data;
CalComponent *comp;
- char *hash_rid;
GSList *categories;
+ RemoveRecurrenceData rrdata;
cbfile = CAL_BACKEND_FILE (backend);
priv = cbfile->priv;
@@ -1495,36 +1639,24 @@ cal_backend_file_remove_object (CalBackendSync *backend, Cal *cal,
if (!obj_data)
return GNOME_Evolution_Calendar_ObjectNotFound;
- if (rid && *rid) {
- if (g_hash_table_lookup_extended (obj_data->recurrences, rid,
- &hash_rid, &comp)) {
- /* remove the component from our data */
- icalcomponent_remove_component (priv->icalcomp,
- cal_component_get_icalcomponent (comp));
- priv->comp = g_list_remove (priv->comp, comp);
- g_hash_table_remove (obj_data->recurrences, rid);
-
- /* update the set of categories */
- cal_component_get_categories_list (comp, &categories);
- cal_backend_unref_categories (CAL_BACKEND (cbfile), categories);
- cal_component_free_categories_list (categories);
-
- /* free memory */
- g_free (hash_rid);
- g_object_unref (comp);
-
- mark_dirty (cbfile);
-
- return GNOME_Evolution_Calendar_Success;
- }
- }
-
comp = obj_data->full_object;
- if (mod != CALOBJ_MOD_ALL) {
+ switch (mod) {
+ case CALOBJ_MOD_ALL :
*object = cal_component_get_as_string (comp);
remove_component (cbfile, comp);
- } else {
+ break;
+ case CALOBJ_MOD_THIS :
+ if (!rid || !*rid)
+ return GNOME_Evolution_Calendar_ObjectNotFound;
+
+ remove_instance (cbfile, obj_data, rid);
+ break;
+ case CALOBJ_MOD_THISANDPRIOR :
+ case CALOBJ_MOD_THISANDFUTURE :
+ if (!rid || !*rid)
+ return GNOME_Evolution_Calendar_ObjectNotFound;
+
/* remove the component from our data, temporarily */
icalcomponent_remove_component (priv->icalcomp,
cal_component_get_icalcomponent (comp));
@@ -1533,10 +1665,18 @@ cal_backend_file_remove_object (CalBackendSync *backend, Cal *cal,
cal_util_remove_instances (cal_component_get_icalcomponent (comp),
icaltime_from_string (rid), mod);
+ /* now remove all detached instances */
+ rrdata.cbfile = cbfile;
+ rrdata.obj_data = obj_data;
+ rrdata.rid = rid;
+ rrdata.mod = mod;
+ g_hash_table_foreach_remove (obj_data->recurrences, (GHRFunc) remove_object_instance_cb, &rrdata);
+
/* add the modified object to the beginning of the list,
so that it's always before any detached instance we
might have */
priv->comp = g_list_prepend (priv->comp, comp);
+ break;
}
mark_dirty (cbfile);