On Tue, 2009-07-28 at 13:05 +0530, Chenthill wrote:
> On Fri, 2009-07-24 at 20:20 +0200, Patrick Ohly wrote:
> > I have not looked at the calendar API yet. Let me know what you think
> > about the attached patch for a new ebook API and I will continue with
> > calendar next, before implementing anything.
> Then changes made are reasonable. Nice api documentation! This can be
> done in calendar also. For calendars we use sequence numbers for items
> shared with people

I'm not sure what you mean with "items shared with people". Care to
explain?

>  and last-modified in general.

SyncEvolution is based on LAST-MODIFIED since 0.8.x, as mentioned on
this list before.

Attached is my current patch set, with one typo fix in the ebook part
and the ecal API also extended. Less functions need to be patched
because there is no async API.

> > In this current incarnation the patch tries a bit to provide simple
> > implementations of the new calls, but this isn't meant to be complete.
> Would be better to get these api's committed after the branching is done
> for 2.27.x. We will be merging the eds-addressbook dbus port this week
> (for 2.27.x) and the calendar part for evolution 3.0. Will keep you
> informed on the same.

Implementing the new API would require changing the libecal/ebook<->EDS
communication. Is that something that has to be done twice, once for the
old communication mechanism and once for D-Bus? Will there be a
configure switch to select between one or the other?

-- 
Bye, Patrick Ohly
--  
patrick.o...@gmx.de
http://www.estamos.de/

>From c7985fca473926b1058dc4859fb77f7b3dacb19b Mon Sep 17 00:00:00 2001
From: Patrick Ohly <patrick.o...@gmx.de>
Date: Fri, 17 Jul 2009 16:27:29 +0200
Subject: [PATCH 1/3] documentation fix

e_book_remove_contact_by_id() does not exist, probably
e_book_remove_contact() was meant.
---
 addressbook/libebook/e-book.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/addressbook/libebook/e-book.c b/addressbook/libebook/e-book.c
index e9b3b01..fefe4fa 100644
--- a/addressbook/libebook/e-book.c
+++ b/addressbook/libebook/e-book.c
@@ -1688,7 +1688,7 @@ e_book_remove_contact (EBook       *book,
  * @error: a #GError to set on failure
  *
  * Removes the contacts with ids from the list @ids from @book.  This is
- * always more efficient than calling e_book_remove_contact_by_id if you
+ * always more efficient than calling e_book_remove_contact() if you
  * have more than one id to remove, as some backends can implement it
  * as a batch request.
  *
@@ -1769,7 +1769,7 @@ e_book_async_remove_contact_by_id (EBook                 *book,
  * @closure: data to pass to callback function
  *
  * Removes the contacts with ids from the list @ids from @book.  This is
- * always more efficient than calling e_book_remove_contact_by_id() if you
+ * always more efficient than calling e_book_remove_contact() if you
  * have more than one id to remove, as some backends can implement it
  * as a batch request.
  *
-- 
1.6.2

>From 78a7b1bbe267b3171d7614946589b6b386c0c242 Mon Sep 17 00:00:00 2001
From: Patrick Ohly <patrick.o...@gmx.de>
Date: Fri, 24 Jul 2009 20:08:01 +0200
Subject: [PATCH 2/3] ebook atomic updates and deletes: check and return revision

Same API change as for ecal, using REV instead of LAST-MODIFIED.

The current API suffers from multiple race conditions: when
overwriting a contact, another client might have already made
an update that gets overwritten by older data. Removing a
contact is also affected => added an API extension that
allows backends a) to detect that clients want the more
careful data modifications and b) provides enough information
to do the checking based on the revision string in the backend
(EBOOK_STATIC_CAPABILITY_ATOMIC_MODIFICATIONS).

Software that does change tracking based on the revision string
(like SyncEvolution) needs to know which revision string was
assigned to an updated or added contact. Currently it must do
the operation, then ask for the whole contact. There is a small
window for a race condition here, but more important, this
requires another round-trip and transmit too much information.
With EBOOK_STATIC_CAPABILITY_RETURN_REV the client can be sure
to get the necessary information right away.
---
 addressbook/libebook/e-book-types.h |   12 ++
 addressbook/libebook/e-book.c       |  268 +++++++++++++++++++++++++++++++++-
 addressbook/libebook/e-book.h       |    6 +
 3 files changed, 278 insertions(+), 8 deletions(-)

diff --git a/addressbook/libebook/e-book-types.h b/addressbook/libebook/e-book-types.h
index 00a814e..2dadf27 100644
--- a/addressbook/libebook/e-book-types.h
+++ b/addressbook/libebook/e-book-types.h
@@ -64,11 +64,23 @@ typedef enum {
 	E_BOOK_CHANGE_CARD_MODIFIED
 } EBookChangeType;
 
+typedef enum {
+	E_BOOK_UNDEFINED_REVISION_HANDLING = 0,
+	E_BOOK_IGNORE_REVISION = 1<<0,
+	E_BOOK_CHECK_REVISION = 1<<1,
+	E_BOOK_SET_REVISION = 1<<2
+} EBookRevisionHandlingFlags;
+
 typedef struct {
 	EBookChangeType  change_type;
 	EContact        *contact;
 } EBookChange;
 
+typedef struct {
+	const char *id;
+	const char *rev;
+} EBookContactInstance;
+
 G_END_DECLS
 
 #endif /* ! __E_BOOK_TYPES_H__ */
diff --git a/addressbook/libebook/e-book.c b/addressbook/libebook/e-book.c
index fefe4fa..07ab5d7 100644
--- a/addressbook/libebook/e-book.c
+++ b/addressbook/libebook/e-book.c
@@ -367,7 +367,10 @@ do_add_contact (gboolean          sync,
  * @contact: an #EContact
  * @error: a #GError to set on failure
  *
- * Adds @contact to @book.
+ * Adds @contact to @book. If the backend has the
+ * #EBOOK_STATIC_CAPABILITY_RETURN_REV, then the revision string
+ * assigned to the contact is guaranteed to be set in @contact when
+ * the function returns. The UID in @contact is set in all cases.
  *
  * Return value: %TRUE if successful, %FALSE otherwise.
  **/
@@ -393,7 +396,10 @@ e_book_add_contact (EBook           *book,
  * @cb: function to call when the operation finishes
  * @closure: data to pass to callback function
  *
- * Adds @contact to @book without blocking.
+ * Adds @contact to @book without blocking. If the backend has the
+ * #EBOOK_STATIC_CAPABILITY_RETURN_REV, then the revision string
+ * assigned to the contact is guaranteed to be set in @contact when
+ * the operation completes. The UID in @contact is set in all cases.
  *
  * Return value: %TRUE if the operation was started, %FALSE otherwise.
  **/
@@ -476,6 +482,7 @@ e_book_response_add_contact (EBook       *book,
 
 static gboolean
 do_commit_contact (gboolean        sync,
+		   int             flags,
 		   EBook          *book,
 		   EContact       *contact,
 		   GError        **error,
@@ -487,6 +494,12 @@ do_commit_contact (gboolean        sync,
 	CORBA_Environment ev;
 	char *vcard_str;
 
+	/* callers must decide what to do with the revision */
+	e_return_error_if_fail (flags, E_BOOK_ERROR_INVALID_ARG, FALSE);
+
+	/* TODO: backends don't implement anything else right now */
+	e_return_error_if_fail (flags != E_BOOK_IGNORE_REVISION, E_BOOK_ERROR_INVALID_ARG, FALSE);
+
 	g_mutex_lock (book->priv->mutex);
 
 	if (book->priv->load_state != E_BOOK_SOURCE_LOADED) {
@@ -577,7 +590,13 @@ do_commit_contact (gboolean        sync,
  * @error: a #GError to set on failure
  *
  * Applies the changes made to @contact to the stored version in
- * @book.
+ * @book. The revision set for @contact is ignored. The backend
+ * assigns a new, unique value automatically.
+ *
+ * If the backend has the #EBOOK_STATIC_CAPABILITY_RETURN_REV, then
+ * the revision string assigned to the contact is guaranteed to be set
+ * in @contact when the function returns. The UID in @contact is set
+ * in all cases.
  *
  * Return value: %TRUE if successful, %FALSE otherwise
  **/
@@ -589,7 +608,47 @@ e_book_commit_contact (EBook           *book,
 	e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG, FALSE);
 	e_return_error_if_fail (contact && E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG, FALSE);
 
-	return do_commit_contact (TRUE,
+	return do_commit_contact (TRUE, E_BOOK_IGNORE_REVISION,
+				  book, contact, error,
+				  NULL, NULL);
+
+}
+
+/**
+ * e_book_commit_contact_instance:
+ * @book: an #EBook
+ * @contact: an #EContact
+ * @flags: #E_BOOK_IGNORE_REVISION, #E_BOOK_CHECK_REVISION, or #E_BOOK_SET_REVISION
+ * @error: a #GError to set on failure
+ *
+ * Applies the changes made to @contact to the stored version in
+ * @book. The handling of the revision set for @contact depends on
+ * @flags. With E_BOOK_IGNORE_REVISION, the value is ignored. With
+ * E_BOOK_CHECK_REVISION, the string must match the current one at the
+ * time when the backend processes the request.  When it does not
+ * match, the commit fails. Using this is recommended to avoid
+ * overwriting changes that others might have made in the
+ * meantime. With E_BOOK_SET_REVISION, the contact is stored with the
+ * given revision, if possible. If this is not possible, then a new
+ * revision is assigned. Use this when restoring data from a backup.
+ *
+ * If the backend has the #EBOOK_STATIC_CAPABILITY_RETURN_REV, then
+ * the revision string assigned to the contact is guaranteed to be set
+ * in @contact when the function returns. The UID in @contact is set
+ * in all cases.
+ *
+ * Return value: %TRUE if successful, %FALSE otherwise
+ **/
+gboolean
+e_book_commit_contact_instance (EBook           *book,
+				EContact        *contact,
+				int              flags,
+				GError         **error)
+{
+	e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG, FALSE);
+	e_return_error_if_fail (contact && E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG, FALSE);
+
+	return do_commit_contact (TRUE, flags,
 				  book, contact, error,
 				  NULL, NULL);
 
@@ -602,8 +661,14 @@ e_book_commit_contact (EBook           *book,
  * @cb: function to call when the operation finishes
  * @closure: data to pass to callback function
  *
- * Applies the changes made to @contact to the stored version in
- * @book without blocking.
+ * Applies the changes made to @contact to the stored version in @book
+ * without blocking. The revision set for @contact is ignored. The
+ * backend assigns a new, unique value automatically.
+ *
+ * If the backend has the #EBOOK_STATIC_CAPABILITY_RETURN_REV, then
+ * the revision string assigned to the contact is guaranteed to be set
+ * in @contact when the function returns. The UID in @contact is set
+ * in all cases.
  *
  * Return value: %TRUE if the operation was started, %FALSE otherwise.
  **/
@@ -613,11 +678,50 @@ e_book_async_commit_contact (EBook                 *book,
 			     EBookCallback          cb,
 			     gpointer               closure)
 {
-	return !do_commit_contact (FALSE,
+	return !do_commit_contact (FALSE, E_BOOK_IGNORE_REVISION,
+				   book, contact, NULL,
+				   cb, closure);
+}
+
+/**
+ * e_book_async_commit_contact_instance:
+ * @book: an #EBook
+ * @contact: an #EContact
+ * @flags: #E_BOOK_IGNORE_REVISION, #E_BOOK_CHECK_REVISION, or #E_BOOK_SET_REVISION
+ * @cb: function to call when the operation finishes
+ * @closure: data to pass to callback function
+ *
+ * Applies the changes made to @contact to the stored version in @book
+ * without blocking. The handling of the revision set for @contact
+ * depends on @flags. With E_BOOK_IGNORE_REVISION, the value is
+ * ignored. With E_BOOK_CHECK_REVISION, the string must match the
+ * current one at the time when the backend processes the request.
+ * When it does not match, the commit fails. Using this is recommended
+ * to avoid overwriting changes that others might have made in the
+ * meantime. With E_BOOK_SET_REVISION, the contact is stored with the
+ * given revision, if possible. If this is not possible, then a new
+ * revision is assigned. Use this when restoring data from a backup.
+ *
+ * If the backend has the #EBOOK_STATIC_CAPABILITY_RETURN_REV, then
+ * the revision string assigned to the contact is guaranteed to be set
+ * in @contact when the function returns. The UID in @contact is set
+ * in all cases.
+ *
+ * Return value: %TRUE if the operation was started, %FALSE otherwise.
+ **/
+guint
+e_book_async_commit_contact_instance (EBook                 *book,
+				      EContact              *contact,
+				      int                    flags,
+				      EBookCallback          cb,
+				      gpointer               closure)
+{
+	return !do_commit_contact (FALSE, flags,
 				   book, contact, NULL,
 				   cb, closure);
 }
 
+
 static gboolean
 do_get_required_fields (gboolean             sync,
 			 EBook               *book,
@@ -1682,6 +1786,36 @@ e_book_remove_contact (EBook       *book,
 }
 
 /**
+ * e_book_remove_contact_instance:
+ * @book: an #EBook
+ * @id: a string
+ * @rev: the REV string of the contact which is to be removed, NULL allowed
+ * @error: a #GError to set on failure
+ *
+ * Removes the contact with id @id and revision @rev from @book. If
+ * @rev is NULL, then it does not matter what revision is currently in
+ * the @book. If @rev is not NULL, then the current revision has to
+ * match that string, otherwise removal is rejected with
+ * E_BOOK_ERROR_PERMISSION_DENIED. If @rev is not NULL and the backend
+ * does not support revision checking, then
+ * E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED is returned.
+ *
+ * Return value: %TRUE if successful, %FALSE otherwise
+ **/
+gboolean
+e_book_remove_contact_instance (EBook       *book,
+				const char  *id,
+				const char  *rev,
+				GError     **error)
+{
+	/* TODO: no backend supports revision checking right now */
+	e_return_error_if_fail (!rev, E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED, FALSE);
+
+	return e_book_remove_contact(book, id, error);
+}
+
+
+/**
  * e_book_remove_contacts:
  * @book: an #EBook
  * @ids: an #GList of const char *id's
@@ -1708,6 +1842,51 @@ e_book_remove_contacts (EBook    *book,
 }
 
 /**
+ * e_book_remove_contact_instances:
+ * @book: an #EBook
+ * @instances: an #GList of const EBookContactInstance *
+ * @error: a #GError to set on failure
+ *
+ * Removes the contacts with ids and revisions from the list @ids from
+ * @book. This is always more efficient than calling
+ * e_book_remove_contact_revision() if you have more than one id to remove, as
+ * some backends can implement it as a batch request.
+ *
+ * Revision checking for each contact is done as in
+ * e_book_remove_contact_instance().  Errors are returned if removal
+ * of any contact failed. In such a case, other contacts may have been
+ * removed successfully. If you need to know which contacts were
+ * removed, better use e_book_remove_contact_instance().
+ *
+ * Return value: %TRUE if successful, %FALSE otherwise
+ **/
+gboolean
+e_book_remove_contact_instances (EBook    *book,
+				 GList    *instances,
+				 GError  **error)
+{
+	GList *ids = NULL;
+	GList *next;
+	gboolean result = FALSE;
+
+	for (next = instances; next; next = next->next) {
+		EBookContactInstance *instance = next->data;
+
+		if (instance->rev) {
+			g_list_free (ids);
+			e_return_error_if_fail (!instance->rev, E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED, FALSE);
+		}
+		ids = g_list_prepend(ids, (void *)instance->id);
+	}
+
+	result = e_book_remove_contacts (book, ids, error);
+
+	g_list_free (ids);
+	return result;
+}
+
+
+/**
  * e_book_async_remove_contact:
  * @book: an #EBook
  * @contact: an #EContact
@@ -1734,6 +1913,30 @@ e_book_async_remove_contact (EBook                 *book,
 	return e_book_async_remove_contact_by_id (book, id, cb, closure);
 }
 
+
+
+/**
+ * e_book_async_remove_contact_instance:
+ * @book: an #EBook
+ * @contact: an #EContact
+ * @cb: a function to call when the operation finishes
+ * @closure: data to pass to callback function
+ *
+ * Removes @contact from @book. Does revision checking like
+ * e_book_remove_contact_instance(), if @contact has a revision set.
+ *
+ * Return value: %TRUE if successful, %FALSE otherwise
+ **/
+guint
+e_book_async_remove_contact_instance (EBook                 *book,
+				      EContact              *contact,
+				      EBookCallback          cb,
+				      gpointer               closure)
+{
+	// TODO: not implemented
+	return FALSE;
+}
+
 /**
  * e_book_async_remove_contact_by_id:
  * @book: an #EBook
@@ -1762,6 +1965,32 @@ e_book_async_remove_contact_by_id (EBook                 *book,
 }
 
 /**
+ * e_book_async_remove_contact_instance_by_id:
+ * @book: an #EBook
+ * @id: a unique ID string specifying the contact
+ * @rev: the REV string of the contact which is to be removed, NULL allowed
+ * @cb: a function to call when the operation finishes
+ * @closure: data to pass to callback function
+ *
+ * Removes the contact with id @id from @book. Does revision checking
+ * like e_book_remove_contact_instance() if @rev is not NULL.
+ *
+ * Return value: %TRUE if successful, %FALSE otherwise
+ **/
+guint
+e_book_async_remove_contact_instance_by_id (EBook                 *book,
+					    const char            *id,
+					    const char            *rev,
+					    EBookCallback          cb,
+					    gpointer               closure)
+{
+	/* TODO: no backend supports revision checking right now */
+	g_return_val_if_fail (!rev, FALSE);
+
+	return e_book_async_remove_contact_by_id (book, id, cb, closure);
+}
+
+/**
  * e_book_async_remove_contacts:
  * @book: an #EBook
  * @ids: a #GList of const char *id's
@@ -1769,7 +1998,7 @@ e_book_async_remove_contact_by_id (EBook                 *book,
  * @closure: data to pass to callback function
  *
  * Removes the contacts with ids from the list @ids from @book.  This is
- * always more efficient than calling e_book_remove_contact() if you
+ * always more efficient than calling e_book_async_remove_contact_by_id() if you
  * have more than one id to remove, as some backends can implement it
  * as a batch request.
  *
@@ -1789,6 +2018,29 @@ e_book_async_remove_contacts (EBook                 *book,
 				    cb, closure);
 }
 
+/**
+ * e_book_async_remove_contact_instances:
+ * @book: an #EBook
+ * @instances: a #GList of const EBookInstance *
+ * @cb: a function to call when the operation finishes
+ * @closure: data to pass to callback function
+ *
+ * Removes the contacts with ids and revision from the list @instances
+ * from @book. Revision checking and caveats as for
+ * e_book_remove_contact_instances().
+ *
+ * Return value: %TRUE if successful, %FALSE otherwise
+ **/
+guint
+e_book_async_remove_contact_instances (EBook                 *book,
+				       GList                 *instances,
+				       EBookCallback          cb,
+				       gpointer               closure)
+{
+	/* TODO: not implemented */
+	return FALSE;
+}
+
 
 static gboolean
 do_get_book_view (gboolean sync,
diff --git a/addressbook/libebook/e-book.h b/addressbook/libebook/e-book.h
index 8234572..f0707ee 100644
--- a/addressbook/libebook/e-book.h
+++ b/addressbook/libebook/e-book.h
@@ -228,6 +228,12 @@ void     e_book_free_change_list           (GList       *change_list);
 const char *e_book_get_uri                 (EBook       *book);
 ESource    *e_book_get_source              (EBook       *book);
 
+/** operations where the backend updates a contact's revision return the new revision */
+#define EBOOK_STATIC_CAPABILITY_RETURN_REV               "return-rev"
+
+/** backend supports atomic update/delete operations (the _instance variant of the calls) */
+#define EBOOK_STATIC_CAPABILITY_ATOMIC_MODIFICATIONS     "atomic-modifications"
+
 const char *e_book_get_static_capabilities (EBook    *book,
 					    GError  **error);
 gboolean    e_book_check_static_capability (EBook       *book,
-- 
1.6.2

>From 1e389129b7936497600004a1a5395aacde6ee567 Mon Sep 17 00:00:00 2001
From: Patrick Ohly <po...@pohly-mobl.(none)>
Date: Mon, 3 Aug 2009 18:12:08 +0200
Subject: [PATCH 3/3] ecal atomic updates and deletes: check and return revision

Same API change as for ebook, using the LAST-MODIFIED
property instead of REV.

The current API suffers from multiple race conditions: when
overwriting an item, another client might have already made
an update that gets overwritten by older data. Removing an
item is also affected => added an API extension that
allows backends a) to detect that clients want the more
careful data modifications and b) provides enough information
to do the checking based on the revision string in the backend
(CAL_STATIC_CAPABILITY_ATOMIC_MODIFICATIONS).

Software that does change tracking based on the last-modified string
(like SyncEvolution) needs to know which string was
assigned to an updated or added item. Currently it must do
the operation, then ask for the whole item. There is a small
window for a race condition here, but more important, this
requires another round-trip and transmits too much information.
With CAL_STATIC_CAPABILITY_RETURN_LAST_MODIFIED the client can be sure
to get the necessary information right away.
---
 calendar/libecal/e-cal-util.h |    6 +++
 calendar/libecal/e-cal.c      |   91 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 97 insertions(+), 0 deletions(-)

diff --git a/calendar/libecal/e-cal-util.h b/calendar/libecal/e-cal-util.h
index a369b59..be9b910 100644
--- a/calendar/libecal/e-cal-util.h
+++ b/calendar/libecal/e-cal-util.h
@@ -128,6 +128,12 @@ gboolean e_cal_util_event_dates_match (icalcomponent *icalcomp1, icalcomponent *
 #define CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY		 "delegate-to-many"
 #define CAL_STATIC_CAPABILITY_HAS_UNACCEPTED_MEETING     "has-unaccepted-meeting"
 
+/** operations where the backend updates an item's last-modified return the new value */
+#define CAL_STATIC_CAPABILITY_RETURN_LAST_MODIFIED	 "return-last-modified"
+
+/** backend supports atomic update/delete operations (the _instance variant of the calls) */
+#define CAL_STATIC_CAPABILITY_ATOMIC_MODIFICATIONS	 "atomic-modifications"
+
 /* Recurrent events. Management for instances */
 icalcomponent *e_cal_util_construct_instance (icalcomponent *icalcomp,
 					    struct icaltimetype rid);
diff --git a/calendar/libecal/e-cal.c b/calendar/libecal/e-cal.c
index 9603a52..9b0b1b4 100644
--- a/calendar/libecal/e-cal.c
+++ b/calendar/libecal/e-cal.c
@@ -4245,6 +4245,14 @@ e_cal_get_component_as_string (ECal *ecal, icalcomponent *icalcomp)
  * argument. Some backends would assign a specific UID to the newly created object,
  * in those cases that UID would be returned in the @uid argument.
  *
+ * If the backend has the #CAL_STATIC_CAPABILITY_RETURN_LAST_MODIFIED
+ * capability, then LAST-MODIFIED will be set to the value assigned by
+ * the backend. The value assigned to it when calling the function is
+ * ignored. In the somewhat unusual situation that an object has to be
+ * created with a specific LAST-MODIFIED value, create it and then
+ * update it with
+ * e_cal_modify_object_instance(flags=E_CAL_SET_LAST_MODIFIED)
+ *
  * Return value: TRUE if the operation was successful, FALSE otherwise.
  */
 gboolean
@@ -4387,6 +4395,51 @@ e_cal_modify_object (ECal *ecal, icalcomponent *icalcomp, CalObjModType mod, GEr
 }
 
 /**
+ * e_cal_modify_object_instance:
+ * @ecal: A calendar client.
+ * @icalcomp: Component to modify.
+ * @mod: Type of modification.
+ * @flags: #E_CAL_IGNORE_REVISION, #E_CAL_CHECK_REVISION, or #E_CAL_SET_REVISION
+ * @error: Placeholder for error information.
+ *
+ * Requests the calendar backend to modify an existing object. If the object
+ * does not exist on the calendar, an error will be returned.
+ *
+ * For recurrent appointments, the @mod argument specifies what to modify,
+ * if all instances (CALOBJ_MOD_ALL), a single instance (CALOBJ_MOD_THIS),
+ * or a specific set of instances (CALOBJ_MOD_THISNADPRIOR and
+ * CALOBJ_MOD_THISANDFUTURE).
+ *
+ * The handling of the last-modified value set for @icalcomp depends on
+ * @flags. With #E_CAL_IGNORE_REVISION, the value is ignored.
+ *
+ * With #E_CAL_CHECK_REVISION, the string must match the current one
+ * at the time when the backend processes the request. When it does
+ * not match, the commit fails. Using this is recommended to avoid
+ * overwriting changes that others might have made in the
+ * meantime. With CALOBJ_MOD_THIS, the value is compared against the
+ * selected object (main event if recurrence-id is empty, otherwise
+ * the detached recurrence). Otherwise it is always compared against
+ * the main event.
+ *
+ * With #E_CAL_SET_REVISION, the object is stored with the given
+ * last-modified value, if possible. If this is not possible, then a
+ * new value is assigned. Use this when restoring data from a backup.
+ *
+ * If the backend has the
+ * #CAL_STATIC_CAPABILITY_RETURN_LAST_MODIFIED, then the
+ * last-modified value assigned to the object is guaranteed to be set
+ * in @icalcomp when the function returns.
+ *
+ * Return value: TRUE if the operation was successful, FALSE otherwise.
+ */
+gboolean
+e_cal_modify_object_instance (ECal *ecal, icalcomponent *icalcomp, int flags, GError **error)
+{
+	return FALSE;
+}
+
+/**
  * e_cal_remove_object_with_mod:
  * @ecal: A calendar client.
  * @uid: UID og the object to remove.
@@ -4463,6 +4516,44 @@ e_cal_remove_object_with_mod (ECal *ecal, const char *uid,
 }
 
 /**
+ * e_cal_remove_object_instance:
+ * @ecal: A calendar client.
+ * @uid: UID og the object to remove.
+ * @rid: Recurrence ID of the specific recurrence to remove.
+ * @last_modified: Expected LAST-MODIFIED value, NULL allowed
+ * @mod: Type of removal.
+ * @error: Placeholder for error information.
+ *
+ * This function allows the removal of instances of a recurrent
+ * appointment. By using a combination of the @uid, @rid and @mod
+ * arguments, you can remove specific instances. If what you want
+ * is to remove all instances, use e_cal_remove_object instead.
+ *
+ * If not all instances are removed, the client will get a "obj_modified"
+ * signal, while it will get a "obj_removed" signal when all instances
+ * are removed.
+ *
+ * If @last_modified is non-NULL, then removing the object(s) will
+ * fail with #E_CAL_ERROR_PERMISSION_DENIED if the it does not match
+ * the value of the object at the time when the backend tries to
+ * remove the object.  The reference value in the backend is the same
+ * as for e_cal_modify_object_instance().
+ *
+ * If it is non-NULL and the backend does not support last-modified
+ * checking, #E_CAL_ERROR_PROTOCOL_NOT_SUPPORTED is returned. 
+ *
+ * Return value: TRUE if the operation was successful, FALSE otherwise.
+ */
+gboolean
+e_cal_remove_object_instance (ECal *ecal, const char *uid,
+			      const char *rid,
+			      const char *last_modified,
+			      CalObjModType mod, GError **error)
+{
+	return FALSE;
+}
+
+/**
  * e_cal_remove_object:
  * @ecal:  A calendar client.
  * @uid: Unique identifier of the calendar component to remove.
-- 
1.6.2

_______________________________________________
Evolution-hackers mailing list
Evolution-hackers@gnome.org
http://mail.gnome.org/mailman/listinfo/evolution-hackers

Reply via email to