Support for groupwise recurrences.
authorChenthill Palanisamy <pchen@src.gnome.org>
Fri, 8 Jul 2005 11:04:19 +0000 (11:04 +0000)
committerChenthill Palanisamy <pchen@src.gnome.org>
Fri, 8 Jul 2005 11:04:19 +0000 (11:04 +0000)
calendar/ChangeLog
calendar/backends/groupwise/e-cal-backend-groupwise-utils.c
calendar/backends/groupwise/e-cal-backend-groupwise.c
calendar/libecal/e-cal-util.h
calendar/libecal/e-cal.c
calendar/libecal/e-cal.h
calendar/libedata-cal/e-cal-backend-cache.c
calendar/libedata-cal/e-cal-backend-cache.h

index 4d54c89..c30076b 100644 (file)
@@ -1,3 +1,41 @@
+2005-07-08  Chenthill Palanisamy  <pchenthill@novell.com>
+
+       * backends/groupwise/e-cal-backend-groupwise.c
+       (e_cal_backend_groupwise_remove_object): Use removeItemsRequest
+       for removing all the recurring posted appointments.
+       (get_gw_item_id): Get the item id from the component.
+       (get_deltas): Commented the read cursors request to get the icalids,
+       since we need recurrece keys as we use it as the uid for recurrence items.
+       Get the component from cache using uid and rid.
+       * e-cal.c (e_cal_remove_object): Used CALOBJ_MOD_THIS since we are just removing
+       one component.
+       
+2005-07-08  Harish Krishnaswamy  <kharish@novell.com>
+
+       * backends/groupwise/e-cal-backend-groupwise-utils.c:
+       (set_rrule_from_comp), (set_properties_from_cal_component),
+       (e_gw_item_to_cal_component), (e_gw_connection_send_appointment):
+        add  support for creation of recurrence items by sending the 
+       recurrence formula to the server instead of generating the 
+       instances at the client end.
+       * backends/groupwise/e-cal-backend-groupwise.c: 
+       (e_cal_backend_groupwise_get_static_capabilities):
+        add capability RECURRENCES_NO_MASTER.
+       (e_cal_backend_groupwise_remove_object): add support for 
+       removing all instances of a recurrence at one shot.
+       * libecal/e-cal-util.h: Add a static capability 
+       RECURRENCES_NO_MASTER. Backends that do not use master objects
+       to represent recurrence information and store them as individual
+       instances.
+       * libecal/e-cal.c: (e_cal_get_recurrences_no_master)
+       (e_cal_generate_instances_for_object): Do not expand instances for objects from 
+       backends that do not have master object to represent recurrences.
+       * libecal/e-cal.h:
+       * libedata-cal/e-cal-backend-cache.[ch]
+       (e_cal_backend_cache_get_components_by_uid):  Function to
+       fetch all items in the cache that have the same uid. (recurrence
+       items, detached instances etc.)
+
 2005-07-08  Sankar P  <psankar@novell.com>
        
        * backends/groupwise/e-cal-backend-groupwise.c: (get_deltas)
index 5143d2e..325d4c9 100644 (file)
@@ -395,6 +395,83 @@ set_attendees_to_item (EGwItem *item, ECalComponent *comp, icaltimezone *default
 
 }
 
+static void
+set_rrule_from_comp (ECalComponent *comp, EGwItem *item, ECalBackendGroupwise *cbgw)
+{
+
+       EGwItemRecurrenceRule *item_rrule;
+       struct icalrecurrencetype *ical_recur;
+       GSList *rrule_list = NULL, *exdate_list;
+       int i;
+
+       item_rrule = g_new0 (EGwItemRecurrenceRule, 1);
+       e_cal_component_get_rrule_list (comp, &rrule_list);
+       if (rrule_list) {
+               /* assumes only one rrule is present  */
+               ical_recur = (struct icalrecurrencetype *) rrule_list->data;
+               
+               g_message ("DEBUG: Processing rule\n%s\n", icalrecurrencetype_as_string (ical_recur));
+               /*set the data */
+               switch (ical_recur->freq) {
+                       case ICAL_DAILY_RECURRENCE :
+                               item_rrule->frequency = E_GW_ITEM_RECURRENCE_FREQUENCY_DAILY;
+                               break;
+                       case ICAL_WEEKLY_RECURRENCE:
+                               item_rrule->frequency = E_GW_ITEM_RECURRENCE_FREQUENCY_WEEKLY;
+                               break;
+                       case ICAL_MONTHLY_RECURRENCE:
+                               item_rrule->frequency = E_GW_ITEM_RECURRENCE_FREQUENCY_MONTHLY;
+                               break;
+                       case ICAL_YEARLY_RECURRENCE:
+                               item_rrule->frequency = E_GW_ITEM_RECURRENCE_FREQUENCY_YEARLY;
+                               break;
+                       default:
+                               break;
+               }
+               if (ical_recur->count != 0)
+                       item_rrule->count = ical_recur->count;
+               else
+                       item_rrule->until =  g_strdup (icaltime_as_ical_string (ical_recur->until)); 
+
+               item_rrule->interval = ical_recur->interval;
+
+               /*xxx -byday, bymonthday and byyearday not handled FIXME*/
+               for (i = 0; i < ICAL_BY_DAY_SIZE; i++)
+                       item_rrule->by_day[i] = ical_recur->by_day[i];
+               for (i = 0; i < ICAL_BY_MONTHDAY_SIZE; i++)
+                       item_rrule->by_month_day[i] = ical_recur->by_month_day[i];
+               for (i = 0; i < ICAL_BY_YEARDAY_SIZE; i++)
+                       item_rrule->by_year_day[i] = ical_recur->by_year_day[i];
+               for (i = 0; i < ICAL_BY_MONTH_SIZE; i++)
+                       item_rrule->by_month[i] = ical_recur->by_month[i];
+
+               e_gw_item_set_rrule (item, item_rrule);
+
+               /* set exceptions */
+               if (e_cal_component_has_exdates (comp)) {
+                       GSList *l, *item_exdate_list = NULL;
+                       icaltimezone *default_zone, *utc;
+                       struct icaltimetype itt_utc;
+                       
+
+                       e_cal_component_get_exdate_list (comp, &exdate_list);
+                       default_zone = e_cal_backend_groupwise_get_default_zone (cbgw);
+                       utc = icaltimezone_get_utc_timezone ();
+                       for (l = exdate_list; l ; l = l->next) {
+                               ECalComponentDateTime *dt = (ECalComponentDateTime *) l->data; 
+                               if (dt->value) {
+                                       if (!icaltime_get_timezone (*(dt->value)))
+                                               icaltime_set_timezone (dt->value, default_zone ? default_zone : utc);
+                                       itt_utc = icaltime_convert_to_zone (*dt->value, utc);
+                                       item_exdate_list = g_slist_append (item_exdate_list, g_strdup (icaltime_as_ical_string (itt_utc)));
+                               }
+                       }                       
+                       e_gw_item_set_exdate_list (item, item_exdate_list);
+                       e_cal_component_free_exdate_list (exdate_list);
+               }
+       } 
+}
+
 static EGwItem *
 set_properties_from_cal_component (EGwItem *item, ECalComponent *comp, ECalBackendGroupwise *cbgw)
 {
@@ -584,18 +661,22 @@ set_properties_from_cal_component (EGwItem *item, ECalComponent *comp, ECalBacke
        
        /* check if recurrences exist and update the item */
        if (e_cal_component_has_recurrences (comp)) {
+               if (e_cal_component_has_rrules (comp))
+                       set_rrule_from_comp (comp, item, cbgw);
+               else {
 
-               GSList *recur_dates = NULL;
-               
-               if (dt.tzid)
-                       e_cal_recur_generate_instances (comp, -1, -1,get_recur_instance, &recur_dates, resolve_tzid_cb, NULL, (icaltimezone *) default_zone);           
-               else 
-                       e_cal_recur_generate_instances (comp, -1, -1,get_recur_instance, &recur_dates, resolve_tzid_cb, NULL, utc);             
+                       GSList *recur_dates = NULL;
+                       
+                       if (dt.tzid)
+                               e_cal_recur_generate_instances (comp, -1, -1,get_recur_instance, &recur_dates, resolve_tzid_cb, NULL, (icaltimezone *) default_zone);           
+                       else 
+                               e_cal_recur_generate_instances (comp, -1, -1,get_recur_instance, &recur_dates, resolve_tzid_cb, NULL, utc);             
 
-               recur_dates = g_slist_delete_link (recur_dates, recur_dates);
-               
-               e_gw_item_set_recurrence_dates (item, recur_dates);
-           }
+                       recur_dates = g_slist_delete_link (recur_dates, recur_dates);
+                       
+                       e_gw_item_set_recurrence_dates (item, recur_dates);
+               }
+       }
        
        /* attachments */
        if (e_cal_component_has_attachments (comp)) {
@@ -710,6 +791,7 @@ set_attachments_to_cal_component (EGwItem *item, ECalComponent *comp, ECalBacken
        e_cal_component_set_attachment_list (comp, comp_attachment_list);
 
 }
+
 ECalComponent *
 e_gw_item_to_cal_component (EGwItem *item, ECalBackendGroupwise *cbgw)
 {
@@ -761,15 +843,7 @@ e_gw_item_to_cal_component (EGwItem *item, ECalBackendGroupwise *cbgw)
                icalcomponent_add_property (e_cal_component_get_icalcomponent (comp), icalprop);
        }
 
-       /* UID */
-       uid = e_gw_item_get_icalid (item);
-       if (uid)
-               e_cal_component_set_uid (comp, e_gw_item_get_icalid (item));
-       else {
-               g_object_unref (comp);
-               return NULL;
-       }
-
+       
        if (e_gw_item_get_reply_request (item)) {
                char *reply_within; 
                const char *mess = e_gw_item_get_message (item);
@@ -875,6 +949,31 @@ e_gw_item_to_cal_component (EGwItem *item, ECalBackendGroupwise *cbgw)
        else 
                return NULL;
        
+       /* UID */
+       if (e_gw_item_get_recurrence_key (item) != 0) {
+
+               ECalComponentRange *recur_id;
+               char *recur_key = g_strdup_printf ("%d", e_gw_item_get_recurrence_key (item));
+
+               e_cal_component_set_uid (comp, (const char *) recur_key);
+               g_free (recur_key);
+
+               /* set the recurrence id and the X-GW-RECORDID  too */
+               recur_id = g_new0 (ECalComponentRange, 1);
+               recur_id->type = E_CAL_COMPONENT_RANGE_SINGLE;
+               recur_id->datetime = dt;
+               e_cal_component_set_recurid (comp, recur_id);
+
+       } else {
+
+               uid = e_gw_item_get_icalid (item);
+               if (uid)
+                       e_cal_component_set_uid (comp, e_gw_item_get_icalid (item));
+               else {
+                       g_object_unref (comp);
+                       return NULL;
+               }
+       }
 
        /* classification */
        description = e_gw_item_get_classification (item);
@@ -1067,7 +1166,10 @@ e_gw_connection_send_appointment (ECalBackendGroupwise *cbgw, const char *contai
        EGwConnectionStatus status;
        icalparameter_partstat partstat;
        char *item_id;
-       
+       gboolean all_instances = FALSE;
+       icalproperty *icalprop;
+       icalcomponent *icalcomp;
+       const char *recurrence_key = NULL;
 
        cnc = e_cal_backend_groupwise_get_connection (cbgw);
        g_return_val_if_fail (E_IS_GW_CONNECTION (cnc), E_GW_CONNECTION_STATUS_INVALID_CONNECTION);
@@ -1077,17 +1179,40 @@ e_gw_connection_send_appointment (ECalBackendGroupwise *cbgw, const char *contai
        /* When the icalcomponent is obtained through the itip message rather
         * than from the SOAP protocol, the container id has to be explicitly 
         * added to the xgwrecordid inorder to obtain the item id. */
-       
-       switch  (e_cal_component_get_vtype (comp)) {
-       case E_CAL_COMPONENT_EVENT: 
-               item_id = g_strconcat (e_cal_component_get_gw_id (comp), GW_EVENT_TYPE_ID, container, NULL);
-               break;
-       case E_CAL_COMPONENT_TODO:
-               item_id = g_strconcat (e_cal_component_get_gw_id (comp), GW_TODO_TYPE_ID, container, NULL);
-               break;
-       default:
-               return E_GW_CONNECTION_STATUS_INVALID_OBJECT;
+
+       /* handle recurrences - All */
+       icalcomp = e_cal_component_get_icalcomponent (comp);
+
+       icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
+       while (icalprop) {
+               const char *x_name;
+
+               x_name = icalproperty_get_x_name (icalprop);
+               if (!strcmp (x_name, "X-GW-RECUR-INSTANCE-MOD-TYPE")) {
+                       if (!strcmp (icalproperty_get_x (icalprop), "All"))
+                               all_instances = TRUE;
+                       if (recurrence_key)
+                               break;
+               }
+               if (!strcmp (x_name, "X-GW-RECURRENCE-KEY")) {
+                       recurrence_key = icalproperty_get_x (icalprop);
+               }
+               icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY);
+       }       
+               
+       if (all_instances) {
+               switch  (e_cal_component_get_vtype (comp)) {
+               case E_CAL_COMPONENT_EVENT: 
+                       item_id = g_strconcat (e_cal_component_get_gw_id (comp), GW_EVENT_TYPE_ID, container, NULL);
+                       break;
+               case E_CAL_COMPONENT_TODO:
+                       item_id = g_strconcat (e_cal_component_get_gw_id (comp), GW_TODO_TYPE_ID, container, NULL);
+                       break;
+               default:
+                       return E_GW_CONNECTION_STATUS_INVALID_OBJECT;
+               }
        }
+       
        switch (method) {
        case ICAL_METHOD_REQUEST:
                /* get attendee here and add the list along. */
@@ -1130,17 +1255,31 @@ e_gw_connection_send_appointment (ECalBackendGroupwise *cbgw, const char *contai
                        
                case ICAL_PARTSTAT_ACCEPTED: 
                        e_cal_component_get_transparency (comp, &transp);
-                       if (transp == E_CAL_COMPONENT_TRANSP_OPAQUE) 
-                               status = e_gw_connection_accept_request (cnc, item_id, "Busy");
-                       else 
-                               status = e_gw_connection_accept_request (cnc, item_id, "Free");
+                       if (transp == E_CAL_COMPONENT_TRANSP_OPAQUE)  {
+                               if (all_instances)
+                                       status = e_gw_connection_accept_request_by_recurrence_key (cnc, recurrence_key, "Busy", NULL);
+                               else
+                                       status = e_gw_connection_accept_request (cnc, item_id, "Busy");
+                       }
+                       else {
+                               if (all_instances)
+                                       status = e_gw_connection_accept_request_by_recurrence_key (cnc, recurrence_key, "Free", NULL);
+                               else
+                                       status = e_gw_connection_accept_request (cnc, item_id, "Free");
+                       }
                        break;
                case ICAL_PARTSTAT_DECLINED:
-                       status = e_gw_connection_decline_request (cnc, item_id);
+                       if (all_instances)
+                               status = e_gw_connection_decline_request_by_recurrence_key (cnc, recurrence_key, NULL);
+                       else
+                               status = e_gw_connection_decline_request (cnc, item_id);
                        *remove = TRUE;
                        break;
                case ICAL_PARTSTAT_TENTATIVE:
-                       status = e_gw_connection_accept_request (cnc, item_id, "Tentative");
+                       if (all_instances)
+                               status = e_gw_connection_accept_request_by_recurrence_key (cnc, recurrence_key, "Tentative", NULL);
+                       else
+                               status = e_gw_connection_accept_request (cnc, item_id, "Tentative");
                        break;
                case ICAL_PARTSTAT_COMPLETED:
                        status = e_gw_connection_complete_request (cnc, item_id);
@@ -1163,6 +1302,7 @@ e_gw_connection_send_appointment (ECalBackendGroupwise *cbgw, const char *contai
        if (status == E_GW_CONNECTION_STATUS_ITEM_ALREADY_ACCEPTED)
                return status;
 
+       /*FIXME - handling recurrence items */
        if (!*remove && status == E_GW_CONNECTION_STATUS_OK) {
                EGwItem *item;
 
index 48103cb..c3b6b9b 100644 (file)
@@ -372,14 +372,18 @@ get_deltas (gpointer handle)
                item = E_GW_ITEM(item_list->data);
                ECalComponent *modified_comp = NULL, *cache_comp = NULL;
                char *cache_comp_str = NULL;
-
+               const char *uid, *rid = NULL;
 
                modified_comp = e_gw_item_to_cal_component (item, cbgw);
                if (!modified_comp) {
                        g_message ("Invalid component returned in update");
                        continue;
                }
-               cache_comp = e_cal_backend_cache_get_component (cache, e_gw_item_get_icalid (item), NULL);
+               if ((r_key = e_gw_item_get_recurrence_key (item)) != 0)
+                       rid = e_cal_component_get_recurid_as_string (modified_comp) 
+               
+               e_cal_component_get_uid (modified_comp, &uid);          
+               cache_comp = e_cal_backend_cache_get_component (cache, uid, rid);
                e_cal_component_commit_sequence (modified_comp);
                e_cal_component_commit_sequence (cache_comp);
 
@@ -390,6 +394,7 @@ get_deltas (gpointer handle)
                        cache_comp_str = NULL;
                }
                e_cal_backend_cache_put_component (cache, modified_comp);
+
                g_object_unref (item);
                g_object_unref (modified_comp);
        }
@@ -422,10 +427,15 @@ get_deltas (gpointer handle)
                g_list_free (item_list);
                item_list = NULL;
        }
-
+       
+       /* TODO currently the read cursors response does not give us the recurrencKey, uncomment
+          this once the  response gives the recurrenceKey */
+#if 0
+       /* handle deleted items here by going over the entire cache and
+        * checking for deleted items.*/
        position = E_GW_CURSOR_POSITION_END;
        cursor = 0;
-       status = e_gw_connection_create_cursor (cnc, cbgw->priv->container_id, "iCalId", NULL, &cursor);
+       status = e_gw_connection_create_cursor (cnc, cbgw->priv->container_id, "iCalId recurrenceKey", NULL, &cursor);
 
        if (status != E_GW_CONNECTION_STATUS_OK) {
                if (status == E_GW_CONNECTION_STATUS_NO_RESPONSE) {
@@ -438,9 +448,6 @@ get_deltas (gpointer handle)
                return TRUE;
        }
 
-       /* handle deleted items here by going over the entire cache and
-        * checking for deleted items.*/
-
        cache_keys = e_cal_backend_cache_get_keys (cache);
        done = FALSE;
        while (!done) {
@@ -507,6 +514,7 @@ get_deltas (gpointer handle)
                g_slist_free (cache_keys);
                item_list = NULL;
        }
+#endif
 
        g_static_mutex_unlock (&connecting);
 
@@ -957,10 +965,12 @@ e_cal_backend_groupwise_get_static_capabilities (ECalBackendSync *backend, EData
                                  CAL_STATIC_CAPABILITY_NO_CONV_TO_ASSIGN_TASK "," \
                                  CAL_STATIC_CAPABILITY_NO_CONV_TO_RECUR "," \
                                  CAL_STATIC_CAPABILITY_REQ_SEND_OPTIONS "," \
+                                 CAL_STATIC_CAPABILITY_SAVE_SCHEDULES "," \
                                  CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ACCEPT "," \
                                  CAL_STATIC_CAPABILITY_DELEGATE_SUPPORTED "," \
                                  CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY "," \
                                  CAL_STATIC_CAPABILITY_NO_ORGANIZER "," \
+                                 CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER "," \
                                  CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
 
        return GNOME_Evolution_Calendar_Success;
@@ -1802,6 +1812,27 @@ e_cal_backend_groupwise_modify_object (ECalBackendSync *backend, EDataCal *cal,
        return GNOME_Evolution_Calendar_Success;
 }
 
+static const char *
+get_gw_item_id (icalcomponent *icalcomp) 
+{
+       icalproperty *icalprop; 
+
+       /* search the component for the X-GWRECORDID property */
+       icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
+       while (icalprop) {
+               const char *x_name, *x_val;
+
+               x_name = icalproperty_get_x_name (icalprop);
+               x_val = icalproperty_get_x (icalprop);
+               if (!strcmp (x_name, "X-GWRECORDID")) {
+                       return x_val;
+               }
+
+               icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY);
+       }
+       return NULL;
+}
+
 /* Remove_object handler for the file backend */
 static ECalBackendSyncStatus
 e_cal_backend_groupwise_remove_object (ECalBackendSync *backend, EDataCal *cal,
@@ -1822,74 +1853,97 @@ e_cal_backend_groupwise_remove_object (ECalBackendSync *backend, EDataCal *cal,
        if (priv->mode == CAL_MODE_REMOTE) {
                ECalBackendSyncStatus status;
                const char *id_to_remove = NULL;
-               icalproperty *icalprop;
                icalcomponent *icalcomp;
 
-               status = e_cal_backend_groupwise_get_object (backend, cal, uid, rid, &calobj);
-               if (status != GNOME_Evolution_Calendar_Success)
-                       return status;
-
-               *old_object = strdup (calobj);
+               if (mod == CALOBJ_MOD_THIS) {
 
-               icalcomp = icalparser_parse_string (calobj);
-               if (!icalcomp) {
-                       g_free (calobj);
-                       return GNOME_Evolution_Calendar_InvalidObject;
-               }
+                       status = e_cal_backend_groupwise_get_object (backend, cal, uid, rid, &calobj);
+                       if (status != GNOME_Evolution_Calendar_Success)
+                               return status;
 
-               /* search the component for the X-GWRECORDID property */
-               icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
-               while (icalprop) {
-                       const char *x_name, *x_val;
+                       *old_object = strdup (calobj);
 
-                       x_name = icalproperty_get_x_name (icalprop);
-                       x_val = icalproperty_get_x (icalprop);
-                       if (!strcmp (x_name, "X-GWRECORDID")) {
-                               id_to_remove = x_val;
-                               break;
+                       icalcomp = icalparser_parse_string (calobj);
+                       if (!icalcomp) {
+                               g_free (calobj);
+                               return GNOME_Evolution_Calendar_InvalidObject;
+                       }
+               
+                       id_to_remove = get_gw_item_id (icalcomp); 
+                       if (!id_to_remove) {
+                               /* use the iCalId to remove the object */
+                               id_to_remove = uid;
                        }
 
-                       icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY);
-               }
+                       /* remove the object */
+                       status = e_gw_connection_remove_item (priv->cnc, priv->container_id, id_to_remove);
 
-               if (!id_to_remove) {
-                       /* use the iCalId to remove the object */
-                       id_to_remove = uid;
-               }
+                       if (status == E_GW_CONNECTION_STATUS_INVALID_CONNECTION)
+                               status = e_gw_connection_remove_item (priv->cnc, priv->container_id, id_to_remove);
+
+                       icalcomponent_free (icalcomp);
+                       if (status == E_GW_CONNECTION_STATUS_OK) {
+                               /* remove the component from the cache */
+                               if (!e_cal_backend_cache_remove_component (priv->cache, uid, rid)) {
+                                       g_free (calobj);
+                                       return GNOME_Evolution_Calendar_ObjectNotFound;
+                               }
+                               *object = NULL;
+                               g_free (calobj);
+                               return GNOME_Evolution_Calendar_Success;
+                       } else {
+                               g_free (calobj);
+                               return GNOME_Evolution_Calendar_OtherError;
+                       }
+               } else if (mod == CALOBJ_MOD_ALL) {
+                       GSList *l, *comp_list = e_cal_backend_cache_get_components_by_uid (priv->cache, uid);
 
-               /* remove the object */
-               status = e_gw_connection_remove_item (priv->cnc, priv->container_id, id_to_remove);
+                       if (e_cal_component_has_attendees (E_CAL_COMPONENT (comp_list->data))) {
+                               /* get recurrence key and send it to
+                                * e_gw_connection_remove_recurrence_item */
+                               status = e_gw_connection_decline_request_by_recurrence_key (priv->cnc, uid, NULL);
+                               if (status == E_GW_CONNECTION_STATUS_INVALID_CONNECTION)
+                                       status = e_gw_connection_decline_request_by_recurrence_key (priv->cnc, uid, NULL);
+                       } else {
+                               GList *item_ids;        
+                               for (l = comp_list; l; l = l->next) {
+                                       ECalComponent *comp = E_CAL_COMPONENT (l->data);
+
+                                       id_to_remove = get_gw_item_id (e_cal_component_get_icalcomponent (comp)); 
+                                       item_ids = g_list_append (item_ids, (char *) id_to_remove);
+                               }
+                               status = e_gw_connection_remove_items (priv->cnc, priv->container_id, item_ids);
+                               
+                               if (status == E_GW_CONNECTION_STATUS_INVALID_CONNECTION)
+                                       status = e_gw_connection_remove_items (priv->cnc, priv->container_id, item_ids);
+                       }
 
-               if (status == E_GW_CONNECTION_STATUS_INVALID_CONNECTION)
-                       status = e_gw_connection_remove_item (priv->cnc, priv->container_id, id_to_remove);
+                       if (status == E_GW_CONNECTION_STATUS_OK) {
 
-               icalcomponent_free (icalcomp);
-               if (status == E_GW_CONNECTION_STATUS_OK) {
-                       /* remove the component from the cache */
-                       if (!e_cal_backend_cache_remove_component (priv->cache, uid, rid)) {
-                               g_free (calobj);
-                               return GNOME_Evolution_Calendar_ObjectNotFound;
+                               for (l = comp_list; l; l = l->next) {
+                                       ECalComponent *comp = E_CAL_COMPONENT (l->data);
+                                       e_cal_backend_cache_remove_component (priv->cache, uid, 
+                                                       e_cal_component_get_recurid_as_string (comp));
+                                       e_cal_backend_notify_object_removed (E_CAL_BACKEND (cbgw), 
+                                                            uid, e_cal_component_get_as_string (comp), NULL);
+                                       g_object_unref (comp);
+                               
+                               }
+                               /* Setting NULL would trigger another signal.
+                                * We do not set the *object to NULL  */
+                               g_slist_free (comp_list);
+                               return GNOME_Evolution_Calendar_Success;
+                       } else {
+                               return GNOME_Evolution_Calendar_OtherError;
                        }
-                       *object = NULL;
-                       g_free (calobj);
-                       return GNOME_Evolution_Calendar_Success;
-               } else {
-                       g_free (calobj);
-                       return GNOME_Evolution_Calendar_OtherError;
-               }
+               } else
+                       return GNOME_Evolution_Calendar_UnsupportedMethod;
        } else if (priv->mode == CAL_MODE_LOCAL) {
                in_offline (cbgw);
                return GNOME_Evolution_Calendar_RepositoryOffline;
-       }
-
-       /* remove the component from the cache */
-       if (!e_cal_backend_cache_remove_component (priv->cache, uid, rid)) {
-               g_free (calobj);
-               return GNOME_Evolution_Calendar_ObjectNotFound;
-       }
-
-       g_free (calobj);
-       return GNOME_Evolution_Calendar_Success;
+       } else
+               return GNOME_Evolution_Calendar_CalListener_MODE_NOT_SUPPORTED;
+       
 }
 
 static void
@@ -1985,6 +2039,7 @@ receive_object (ECalBackendGroupwise *cbgw, EDataCal *cal, icalcomponent *icalco
        if (e_cal_component_has_attachments (comp))
                fetch_attachments (cbgw, comp);
 
+       modif_comp = comp;
        status = e_gw_connection_send_appointment (cbgw, priv->container_id, comp, method, &remove, &modif_comp);
 
        if (status == E_GW_CONNECTION_STATUS_INVALID_CONNECTION)
index 14d7835..1f3418b 100644 (file)
@@ -123,6 +123,7 @@ gboolean e_cal_util_event_dates_match (icalcomponent *icalcomp1, icalcomponent *
 #define CAL_STATIC_CAPABILITY_NO_CONV_TO_RECUR           "no-conv-to-recur"
 #define CAL_STATIC_CAPABILITY_NO_GEN_OPTIONS             "no-general-options"
 #define CAL_STATIC_CAPABILITY_REQ_SEND_OPTIONS           "require-send-options"
+#define CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER       "recurrences-no-master-object"
 #define CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ACCEPT      "organizer-must-accept"
 #define CAL_STATIC_CAPABILITY_DELEGATE_SUPPORTED        "delegate-support"
 #define CAL_STATIC_CAPABILITY_NO_ORGANIZER              "no-organizer"
index a36a49e..ef22d05 100644 (file)
@@ -2421,6 +2421,24 @@ e_cal_get_organizer_must_attend (ECal *ecal)
 }
 
 /**
+ * e_cal_get_recurrences_no_master:
+ * @ecal: A calendar client.
+ *
+ * Checks if the calendar has a master object for recurrences.
+ *
+ * Return value: TRUE if the calendar has a master object for recurrences,
+ * FALSE otherwise.
+ */
+gboolean 
+e_cal_get_recurrences_no_master (ECal *ecal)
+{
+       g_return_val_if_fail (ecal != NULL, FALSE);
+       g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
+
+       return check_capability (ecal, CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER);
+}
+
+/**
  * e_cal_get_static_capability:
  * @ecal: A calendar client.
  * @cap: Name of the static capability to check.
@@ -2507,7 +2525,6 @@ e_cal_set_mode (ECal *ecal, CalMode mode)
        return retval;
 }
 
-
 /* This is used in the callback which fetches all the timezones needed for an
    object. */
 typedef struct _ECalGetTimezonesData ECalGetTimezonesData;
@@ -3502,6 +3519,17 @@ e_cal_generate_instances_for_object (ECal *ecal, icalcomponent *icalcomp,
        comp = e_cal_component_new ();
        e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
 
+       /*If the backend stores it as individual instances and does not 
+        * have a master object - do not expand*/
+       if (e_cal_get_static_capability (ecal, CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER)) {
+               time_t start, end;
+               /*return the same instance */
+               result = (* cb)  (comp, icaltime_as_timet_with_zone (icalcomponent_get_dtstart (icalcomp), ecal->priv->default_zone),
+                               icaltime_as_timet_with_zone (icalcomponent_get_dtend (icalcomp), ecal->priv->default_zone), cb_data);
+               g_object_unref (comp);
+               return;
+       }
+               
        e_cal_component_get_uid (comp, &uid);
        rid = e_cal_component_get_recurid_as_string (comp);
 
@@ -4213,7 +4241,7 @@ e_cal_remove_object (ECal *ecal, const char *uid, GError **error)
        e_return_error_if_fail (ecal && E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
        e_return_error_if_fail (uid, E_CALENDAR_STATUS_INVALID_ARG);
 
-       return e_cal_remove_object_with_mod (ecal, uid, NULL, CALOBJ_MOD_ALL, error);
+       return e_cal_remove_object_with_mod (ecal, uid, NULL, CALOBJ_MOD_THIS, error);
 }
 
 /**
index 46dc836..d24e277 100644 (file)
@@ -204,7 +204,7 @@ gboolean    e_cal_set_default (ECal  *ecal, GError **error);
 gboolean    e_cal_set_default_source (ESource *source, ECalSourceType type, GError **error);
 gboolean    e_cal_get_sources (ESourceList **sources, ECalSourceType type, GError **error);
 const char * e_cal_get_local_attachment_store (ECal *ecal);
-
+gboolean e_cal_get_recurrences_no_master (ECal *ecal);
 G_END_DECLS
 
 #endif
index 714fd9d..34795a6 100644 (file)
@@ -452,6 +452,55 @@ e_cal_backend_cache_get_components (ECalBackendCache *cache)
 }
 
 /**
+ * e_cal_backend_cache_get_components_by_uid:
+ * @cache: An #ECalBackendCache object.
+ * @uid: ID of the component to retrieve.
+ *
+ * Retrieves a ical components from the cache.
+ *
+ * Return value: The list of calendar components if found, or NULL otherwise.
+ */
+GSList *
+e_cal_backend_cache_get_components_by_uid (ECalBackendCache *cache, const char *uid)
+{
+        char *comp_str;
+        GSList *l;
+       GSList *list = NULL;
+       icalcomponent *icalcomp;
+       ECalComponent *comp = NULL;
+        
+        /* return null if cache is not a valid Backend Cache.  */
+       g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), NULL);
+        l = e_file_cache_get_objects (E_FILE_CACHE (cache));
+        if (!l)
+                return NULL;
+        for ( ; l != NULL; l = g_slist_next (l)) {
+                comp_str = l->data;
+                if (comp_str) {
+                        icalcomp = icalparser_parse_string (comp_str);
+                        if (icalcomp) {
+                               icalcomponent_kind kind;
+
+                               kind = icalcomponent_isa (icalcomp);
+                               if (kind == ICAL_VEVENT_COMPONENT || kind == ICAL_VTODO_COMPONENT) {
+                                       comp = e_cal_component_new ();
+                                       if ((e_cal_component_set_icalcomponent (comp, icalcomp)) &&
+                                               !strcmp (icalcomponent_get_uid (icalcomp), uid)) 
+                                                       list = g_slist_append (list, comp);
+                                       else {
+                                               g_object_unref (comp);
+                                       }
+                               } else
+                                       icalcomponent_free (icalcomp);
+                        }
+                }
+                
+        }
+
+        return list;
+}
+
+/**
  * e_cal_backend_cache_get_timezone:
  * @cache: An #ECalBackendCache object.
  * @tzid: ID of the timezone to retrieve.
index f9edd29..984d9c0 100644 (file)
@@ -55,6 +55,8 @@ gboolean            e_cal_backend_cache_remove_component (ECalBackendCache *cach
                                                          const char *uid,
                                                          const char *rid);
 GList              *e_cal_backend_cache_get_components (ECalBackendCache *cache);
+GSList             *e_cal_backend_cache_get_components_by_uid (ECalBackendCache *cache, const char *uid);
+
 
 
 const icaltimezone *e_cal_backend_cache_get_timezone (ECalBackendCache *cache, const char *tzid);