commit a780f922ddb4c60b90fab141953d2d3894c42524
Author: Tristan Van Berkom <tristan.van.berkom@gmail.com>
Date:   Thu Aug 4 14:18:46 2011 -0400

    Added e_cal_get_revision().
    
    Adds e_cal_get_revision() async/sync api to access an
    opaque revision string which will be NULL for a backend that
    does not implement it. Adds all the needed gdbus machinery and
    implements a revision in the file backend.
    
    This is implemented by checking the calendar file timestamp and
    maintaining a modification counter to ensure there are no races
    when multiple revisions happen in the same second. When the backend
    is asked for it's revision and it's currently dirty... the calendar
    file is forcefully saved to ensure a correct revision string.
    
    Bug: https://bugzilla.gnome.org/show_bug.cgi?id=652177

diff --git a/calendar/backends/file/e-cal-backend-file.c b/calendar/backends/file/e-cal-backend-file.c
index a9facd5..7e29a31 100644
--- a/calendar/backends/file/e-cal-backend-file.c
+++ b/calendar/backends/file/e-cal-backend-file.c
@@ -26,6 +26,7 @@
 #endif
 
 #include <string.h>
+#include <time.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -116,6 +117,9 @@ struct _ECalBackendFilePrivate {
 
 	/* timeour id for refresh type "2" */
 	guint refresh_timeout_id;
+
+	/* Just an incremental number to ensure uniqueness across revisions */
+	guint revision_counter;
 };
 
 
@@ -275,6 +279,7 @@ save (ECalBackendFile *cbfile)
 
 	g_static_rec_mutex_lock (&priv->idle_save_rmutex);
 	priv->is_dirty = TRUE;
+	priv->revision_counter++;
 
 	if (!priv->dirty_idle_id)
 		priv->dirty_idle_id = g_idle_add ((GSourceFunc) save_file_when_idle, cbfile);
@@ -425,6 +430,54 @@ e_cal_backend_file_get_cal_address (ECalBackendSync *backend, EDataCal *cal, gch
 	*address = NULL;
 }
 
+/* Get_revision handler for the file backend */
+static gchar *
+get_revision_string (ECalBackendFile *cbfile)
+{
+	gchar time_string[100] = {0};
+	struct stat sb;
+	struct tm  *timeval;
+
+	if (g_stat (cbfile->priv->path, &sb) < 0)
+		/* Called before ical file exists, shouldn't happen */
+		return NULL;
+
+	timeval = gmtime (&sb.st_mtime);
+
+	if (timeval)
+		strftime (time_string, 100, "%Y-%m-%dT%H:%M:%SZ", timeval);
+	else
+		g_critical ("Failed to generate revision string");
+
+	return g_strdup_printf ("%s(%d)", time_string, cbfile->priv->revision_counter);
+}
+
+static void
+e_cal_backend_file_get_revision (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+{
+	ECalBackendFile *cbfile = E_CAL_BACKEND_FILE (backend);
+	gchar *revision;
+
+	/* Sync the file right now because we need a timestamp to
+	 * make a revision
+	 */
+	if (cbfile->priv->is_dirty) {
+		if (cbfile->priv->dirty_idle_id) {
+			g_source_remove (cbfile->priv->dirty_idle_id);
+			cbfile->priv->dirty_idle_id = 0;
+		}
+		save_file_when_idle (cbfile);
+
+		/* Do we need to reset 'refresh_skip' here ?? */
+		/* priv->refresh_skip = 0; */
+	}
+
+	/* Notify with the revision */
+	revision = get_revision_string (cbfile);
+	e_data_cal_notify_revision (cal, context, NULL, revision);
+	g_free (revision);
+}
+
 static void
 e_cal_backend_file_get_ldap_attribute (ECalBackendSync *backend, EDataCal *cal, gchar **attribute, GError **perror)
 {
@@ -3444,6 +3497,7 @@ e_cal_backend_file_class_init (ECalBackendFileClass *class)
 	sync_class->get_freebusy_sync = e_cal_backend_file_get_free_busy;
 	sync_class->get_changes_sync = e_cal_backend_file_get_changes;
 
+	backend_class->get_revision = e_cal_backend_file_get_revision;
 	backend_class->is_loaded = e_cal_backend_file_is_loaded;
 	backend_class->start_query = e_cal_backend_file_start_query;
 	backend_class->get_mode = e_cal_backend_file_get_mode;
diff --git a/calendar/libecal/e-cal.c b/calendar/libecal/e-cal.c
index fc10525..f67b6ea 100644
--- a/calendar/libecal/e-cal.c
+++ b/calendar/libecal/e-cal.c
@@ -1561,6 +1561,103 @@ e_cal_remove (ECal *ecal, GError **error)
 	return TRUE;
 }
 
+/**
+ * e_cal_get_revision:
+ * @cal: an #ECal
+ * @revision: (out) (transfer: full): Return location for the opaque revision string
+ * @error: a #GError to set on failure
+ *
+ * Gets the opaque revision string for @cal, revision strings
+ * can be used to check if the entire database has changed state
+ * at all between two checkpoints without itterating through
+ * the actual data and checking for changes.
+ *
+ * Not every backend reports a revision string, if @revision is 
+ * set to %NULL then the caller must assume that the backend 
+ * does not provide any revision string and compare the database 
+ * changes by hand.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise
+ *
+ * Since: 2.32
+ **/
+gboolean
+e_cal_get_revision (ECal       *cal,
+		    gchar      **revision,
+		    GError     **error)
+{
+	e_return_error_if_fail (E_IS_CAL (cal), E_CALENDAR_STATUS_INVALID_ARG);
+	e_return_error_if_fail (cal->priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
+	e_return_error_if_fail (revision && !(*revision), E_CALENDAR_STATUS_INVALID_ARG);
+
+	if (!e_gdbus_cal_call_get_revision_sync (cal->priv->gdbus_cal, revision, NULL, error))
+		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
+
+	return TRUE;
+}
+
+static void
+get_revision_reply (GObject *gdbus_cal, GAsyncResult *res, gpointer user_data)
+{
+	gchar                 *revision = NULL;
+	GError                *error = NULL;
+	AsyncData             *data = user_data;
+	ECalIdAsyncCallback    cb = data->callback;
+
+	e_gdbus_cal_call_get_revision_finish (E_GDBUS_CAL (gdbus_cal), &revision, res, &error);
+
+	unwrap_gerror (&error);
+
+	/* Protect against garbage return values on error */
+	if (error)
+		revision = NULL;
+
+	if (cb)
+		cb (data->cal, error, error ? NULL : revision, data->user_data);
+
+	if (error)
+		g_error_free (error);
+
+	g_free (revision);
+	g_object_unref (data->cal);
+	g_slice_free (AsyncData, data);
+}
+
+/**
+ * e_cal_get_revision_async:
+ * @cal: an #ECal
+ * @cb: function to call when operation finishes
+ * @user_data: data to pass to callback function
+ *
+ * Retrieves the opaque revision string of @cal if
+ * @cal implements revision strings, otherwise it
+ * will report %NULL as the revision.
+ *
+ * Returns: %FALSE if successful, %TRUE otherwise
+ *
+ * Since: 2.32
+ **/
+gboolean
+e_cal_get_revision_async (ECal                *cal,
+			  ECalIdAsyncCallback  cb,
+			  gpointer             user_data)
+{
+	AsyncData *data;
+
+	g_return_val_if_fail (E_IS_CAL (cal), FALSE);
+	g_return_val_if_fail (cal->priv->gdbus_cal, FALSE);
+
+	data = g_slice_new0 (AsyncData);
+	data->cal = g_object_ref (cal);
+	data->callback = cb;
+	data->user_data = user_data;
+
+	e_gdbus_cal_call_get_revision (cal->priv->gdbus_cal, NULL, get_revision_reply, data);
+
+	return TRUE;
+}
+
+
 #if 0
 /* Builds an URI list out of a CORBA string sequence */
 static GList *
diff --git a/calendar/libecal/e-cal.h b/calendar/libecal/e-cal.h
index c7bd500..3f56c37 100644
--- a/calendar/libecal/e-cal.h
+++ b/calendar/libecal/e-cal.h
@@ -129,6 +129,8 @@ gboolean e_cal_open (ECal *ecal, gboolean only_if_exists, GError **error);
 void e_cal_open_async (ECal *ecal, gboolean only_if_exists);
 gboolean e_cal_refresh (ECal *ecal, GError **error);
 gboolean e_cal_remove (ECal *ecal, GError **error);
+gboolean e_cal_get_revision (ECal *ecal, gchar **revision, GError **error);
+gboolean e_cal_get_revision_async (ECal *ecal, ECalIdAsyncCallback cb, gpointer closure);
 
 GList *e_cal_uri_list (ECal *ecal, CalMode mode);
 
diff --git a/calendar/libedata-cal/e-cal-backend-sync.c b/calendar/libedata-cal/e-cal-backend-sync.c
index 514c99d..8d80b01 100644
--- a/calendar/libedata-cal/e-cal-backend-sync.c
+++ b/calendar/libedata-cal/e-cal-backend-sync.c
@@ -86,6 +86,24 @@ e_cal_backend_sync_get_cal_address  (ECalBackendSync *backend, EDataCal *cal, gc
 }
 
 /**
+ * e_cal_backend_sync_get_revision:
+ * @backend: An ECalBackendSync object.
+ * @cal: An EDataCal object.
+ * @revision: Return value for the revision.
+ * @error: Out parameter for a #GError.
+ *
+ * Calls the get_revision method on the given backend.
+ */
+void
+e_cal_backend_sync_get_revision  (ECalBackendSync *backend, EDataCal *cal, gchar **revision, GError **error)
+{
+	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
+	e_return_data_cal_error_if_fail (revision, InvalidArg);
+
+	LOCK_WRAPPER (get_revision_sync, (backend, cal, revision, error));
+}
+
+/**
  * e_cal_backend_sync_get_alarm_email_address:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
@@ -552,6 +570,19 @@ _e_cal_backend_get_cal_address (ECalBackend *backend, EDataCal *cal, EServerMeth
 }
 
 static void
+_e_cal_backend_get_revision (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+{
+	GError *error = NULL;
+	gchar *revision = NULL;
+
+	e_cal_backend_sync_get_cal_address (E_CAL_BACKEND_SYNC (backend), cal, &revision, &error);
+
+	e_data_cal_notify_revision (cal, context, error, revision);
+
+	g_free (revision);
+}
+
+static void
 _e_cal_backend_get_alarm_email_address (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
 {
 	GError *error = NULL;
@@ -974,6 +1005,7 @@ e_cal_backend_sync_class_init (ECalBackendSyncClass *klass)
 
 	backend_class->is_read_only = _e_cal_backend_is_read_only;
 	backend_class->get_cal_address = _e_cal_backend_get_cal_address;
+	backend_class->get_revision = _e_cal_backend_get_revision;
 	backend_class->get_alarm_email_address = _e_cal_backend_get_alarm_email_address;
 	backend_class->get_ldap_attribute = _e_cal_backend_get_ldap_attribute;
 	backend_class->get_static_capabilities = _e_cal_backend_get_static_capabilities;
diff --git a/calendar/libedata-cal/e-cal-backend-sync.h b/calendar/libedata-cal/e-cal-backend-sync.h
index 5080582..fcb0539 100644
--- a/calendar/libedata-cal/e-cal-backend-sync.h
+++ b/calendar/libedata-cal/e-cal-backend-sync.h
@@ -32,6 +32,7 @@ struct _ECalBackendSyncClass {
 	/* Virtual methods */
 	void (*is_read_only_sync)  (ECalBackendSync *backend, EDataCal *cal, gboolean *read_only, GError **perror);
 	void (*get_cal_address_sync)  (ECalBackendSync *backend, EDataCal *cal, gchar **address, GError **perror);
+	void (*get_revision_sync)  (ECalBackendSync *backend, EDataCal *cal, gchar **revision, GError **perror);
 	void (*get_alarm_email_address_sync)  (ECalBackendSync *backend, EDataCal *cal, gchar **address, GError **perror);
 	void (*get_ldap_attribute_sync)  (ECalBackendSync *backend, EDataCal *cal, gchar **attribute, GError **perror);
 	void (*get_static_capabilities_sync)  (ECalBackendSync *backend, EDataCal *cal, gchar **capabilities, GError **perror);
@@ -86,6 +87,10 @@ void	e_cal_backend_sync_get_cal_address	(ECalBackendSync *backend,
 						 EDataCal *cal,
 						 gchar **address,
 						 GError **error);
+void	e_cal_backend_sync_get_revision         (ECalBackendSync *backend,
+						 EDataCal *cal,
+						 gchar **revision,
+						 GError **error);
 void	e_cal_backend_sync_get_alarm_email_address
 						(ECalBackendSync *backend,
 						 EDataCal *cal,
diff --git a/calendar/libedata-cal/e-cal-backend.c b/calendar/libedata-cal/e-cal-backend.c
index f654c24..67935fc 100644
--- a/calendar/libedata-cal/e-cal-backend.c
+++ b/calendar/libedata-cal/e-cal-backend.c
@@ -621,6 +621,28 @@ e_cal_backend_get_cal_address (ECalBackend *backend, EDataCal *cal, EServerMetho
 	(* CLASS (backend)->get_cal_address) (backend, cal, context);
 }
 
+/**
+ * e_cal_backend_get_revision:
+ * @backend: an #ECalBackend
+ *
+ * Gets the revision of the backend if implemented, otherwise %NULL is reported as
+ * the revision string.
+ *
+ * See e_cal_get_revision() for an explanation about revision strings.
+ **/
+void
+e_cal_backend_get_revision (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+
+	if (E_CAL_BACKEND_GET_CLASS (backend)->get_revision)
+		(* E_CAL_BACKEND_GET_CLASS (backend)->get_revision) (backend, cal, context);
+	else
+		/* If the backend does not implement, return a NULL string with no error */
+		e_data_cal_notify_revision (cal, context, NULL, NULL);
+}
+
 void
 e_cal_backend_notify_readonly (ECalBackend *backend, gboolean read_only)
 {
diff --git a/calendar/libedata-cal/e-cal-backend.h b/calendar/libedata-cal/e-cal-backend.h
index d9fccf8..51282ef 100644
--- a/calendar/libedata-cal/e-cal-backend.h
+++ b/calendar/libedata-cal/e-cal-backend.h
@@ -64,6 +64,7 @@ struct _ECalBackendClass {
 	/* Virtual methods */
 	gboolean (* is_loaded) (ECalBackend *backend);
 	void (* is_read_only) (ECalBackend *backend, EDataCal *cal);
+	void (* get_revision) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
 	void (* get_cal_address) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
 	void (* get_alarm_email_address) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
 	void (* get_ldap_attribute) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
@@ -126,6 +127,7 @@ void e_cal_backend_remove_query (ECalBackend *backend, EDataCalView *query);
 
 void e_cal_backend_is_read_only (ECalBackend *backend, EDataCal *cal);
 void e_cal_backend_get_cal_address (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
+void e_cal_backend_get_revision (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
 void e_cal_backend_get_alarm_email_address (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
 void e_cal_backend_get_ldap_attribute (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
 void e_cal_backend_get_static_capabilities (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
diff --git a/calendar/libedata-cal/e-data-cal.c b/calendar/libedata-cal/e-data-cal.c
index c8246f6..0bd0fe0 100644
--- a/calendar/libedata-cal/e-data-cal.c
+++ b/calendar/libedata-cal/e-data-cal.c
@@ -274,6 +274,15 @@ impl_Cal_remove (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal
 	return TRUE;
 }
 
+/* EDataCal::getRevision method */
+static gboolean
+impl_Cal_getRevision (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
+{
+	e_cal_backend_get_revision (cal->priv->backend, cal, invocation);
+
+	return TRUE;
+}
+
 /* EDataCal::isReadOnly method */
 static gboolean
 impl_Cal_isReadOnly (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
@@ -612,6 +621,26 @@ e_data_cal_notify_cal_address (EDataCal *cal, EServerMethodContext context, GErr
 }
 
 /**
+ * e_data_cal_notify_revision:
+ * @cal: A calendar client interface.
+ * @error: Operation error, if any, automatically freed if passed it.
+ * @revision: The revision string.
+ *
+ * Notifies listeners of the completion of the get_revision method call.
+ */
+void
+e_data_cal_notify_revision (EDataCal *cal, EServerMethodContext context, GError *error, const gchar *revision)
+{
+	GDBusMethodInvocation *invocation = context;
+	if (error) {
+		/* Translators: The '%s' is replaced with a detailed error message */
+		data_cal_return_error (invocation, error, _("Cannot retrieve calendar revision: %s"));
+		g_error_free (error);
+	} else
+		e_gdbus_cal_complete_get_revision (cal->priv->gdbus_object, invocation, revision ? revision : "");
+}
+
+/**
  * e_data_cal_notify_alarm_email_address:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
@@ -1170,6 +1199,7 @@ e_data_cal_init (EDataCal *ecal)
 	g_signal_connect (gdbus_object, "handle-remove", G_CALLBACK (impl_Cal_remove), ecal);
 	g_signal_connect (gdbus_object, "handle-is-read-only", G_CALLBACK (impl_Cal_isReadOnly), ecal);
 	g_signal_connect (gdbus_object, "handle-get-cal-address", G_CALLBACK (impl_Cal_getCalAddress), ecal);
+	g_signal_connect (gdbus_object, "handle-get-revision", G_CALLBACK (impl_Cal_getRevision), ecal);
 	g_signal_connect (gdbus_object, "handle-get-alarm-email-address", G_CALLBACK (impl_Cal_getAlarmEmailAddress), ecal);
 	g_signal_connect (gdbus_object, "handle-get-ldap-attribute", G_CALLBACK (impl_Cal_getLdapAttribute), ecal);
 	g_signal_connect (gdbus_object, "handle-get-scheduling-information", G_CALLBACK (impl_Cal_getSchedulingInformation), ecal);
diff --git a/calendar/libedata-cal/e-data-cal.h b/calendar/libedata-cal/e-data-cal.h
index 95a4401..ac80cff 100644
--- a/calendar/libedata-cal/e-data-cal.h
+++ b/calendar/libedata-cal/e-data-cal.h
@@ -114,6 +114,8 @@ void e_data_cal_notify_read_only           (EDataCal *cal, GError *error,
 					    gboolean read_only);
 void e_data_cal_notify_cal_address         (EDataCal *cal, EServerMethodContext context, GError *error,
 					    const gchar *address);
+void e_data_cal_notify_revision            (EDataCal *cal, EServerMethodContext context, GError *error,
+					    const gchar *revision);
 void e_data_cal_notify_alarm_email_address (EDataCal *cal, EServerMethodContext context, GError *error,
 					    const gchar *address);
 void e_data_cal_notify_ldap_attribute      (EDataCal *cal, EServerMethodContext context, GError *error,
diff --git a/calendar/libegdbus/e-gdbus-egdbuscal.c b/calendar/libegdbus/e-gdbus-egdbuscal.c
index de5d534..92cc9d8 100644
--- a/calendar/libegdbus/e-gdbus-egdbuscal.c
+++ b/calendar/libegdbus/e-gdbus-egdbuscal.c
@@ -74,6 +74,7 @@ enum
   __REFRESH_METHOD,
   __CLOSE_METHOD,
   __REMOVE_METHOD,
+  __GET_REVISION_METHOD,
   __IS_READ_ONLY_METHOD,
   __GET_CAL_ADDRESS_METHOD,
   __GET_ALARM_EMAIL_ADDRESS_METHOD,
@@ -318,6 +319,7 @@ e_gdbus_cal_default_init (EGdbusCalIface *iface)
   g_hash_table_insert (_method_name_to_id, (gpointer) "refresh", GUINT_TO_POINTER (__REFRESH_METHOD));
   g_hash_table_insert (_method_name_to_id, (gpointer) "close", GUINT_TO_POINTER (__CLOSE_METHOD));
   g_hash_table_insert (_method_name_to_id, (gpointer) "remove", GUINT_TO_POINTER (__REMOVE_METHOD));
+  g_hash_table_insert (_method_name_to_id, (gpointer) "getRevision", GUINT_TO_POINTER (__GET_REVISION_METHOD));
   g_hash_table_insert (_method_name_to_id, (gpointer) "isReadOnly", GUINT_TO_POINTER (__IS_READ_ONLY_METHOD));
   g_hash_table_insert (_method_name_to_id, (gpointer) "getCalAddress", GUINT_TO_POINTER (__GET_CAL_ADDRESS_METHOD));
   g_hash_table_insert (_method_name_to_id, (gpointer) "getAlarmEmailAddress", GUINT_TO_POINTER (__GET_ALARM_EMAIL_ADDRESS_METHOD));
@@ -616,6 +618,30 @@ e_gdbus_cal_default_init (EGdbusCalIface *iface)
                   1,
                   G_TYPE_DBUS_METHOD_INVOCATION);
   /**
+   * EGdbusCal::handle-get-revision:
+   * @object: The exported object emitting the signal.
+   * @invocation: A #GDBusMethodInvocation object that can be used to return a value or error.
+   *
+   * On exported objects, this signal is emitted when a remote process (identified by @invocation) invokes the <literal>getRevision</literal> D-Bus method on @object. Use e_gdbus_cal_complete_get_revision() to return a value or g_dbus_method_invocation_return_error() to return an error.
+   *
+   * The signal is emitted in the thread-default main loop of the thread that e_gdbus_cal_register_object() was called from.
+   *
+   * On proxies, this signal is never emitted.
+   *
+   * Returns: %TRUE if you want to handle the method call (will stop further handlers from being called), %FALSE otherwise.
+   */
+  signals[__GET_REVISION_METHOD] =
+    g_signal_new ("handle-get-revision",
+                  G_TYPE_FROM_INTERFACE (iface),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (EGdbusCalIface, handle_get_revision),
+                  g_signal_accumulator_true_handled,
+                  NULL,
+                  _e_gdbus_gdbus_cclosure_marshaller_BOOLEAN__OBJECT,
+                  G_TYPE_BOOLEAN,
+                  1,
+                  G_TYPE_DBUS_METHOD_INVOCATION);
+  /**
    * EGdbusCal::handle-is-read-only:
    * @object: The exported object emitting the signal.
    * @invocation: A #GDBusMethodInvocation object that can be used to return a value or error.
@@ -1843,6 +1869,122 @@ _out:
   return _ret;
 }
 
+
+/**
+ * e_gdbus_cal_call_get_revision:
+ * @proxy: A #EGdbusCal.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL if you don't care about the result of the method invocation.
+ * @user_data: Data to pass to @callback.
+ *
+ * Invokes the <literal>org.gnome.evolution.dataserver.calendar.Cal.getRevision</literal>
+ * D-Bus method on the remote object represented by @proxy.
+ *
+ * This is an asynchronous method. When the operation is finished,
+ * callback will be invoked in the thread-default main loop of the
+ * thread you are calling this method from. You can then call
+ * e_gdbus_cal_call_get_revision_finish() to get the result of the operation.
+ *
+ * See e_gdbus_cal_call_get_revision_sync() for the synchronous version of this method.
+ */
+void e_gdbus_cal_call_get_revision (
+        EGdbusCal *proxy,
+        GCancellable *cancellable,
+        GAsyncReadyCallback callback,
+        gpointer user_data)
+{
+  g_dbus_proxy_call (G_DBUS_PROXY (proxy),
+                     "getRevision",
+                     NULL,
+                     G_DBUS_CALL_FLAGS_NONE,
+                     -1,
+                     cancellable,
+                     callback,
+                     user_data);
+}
+
+/**
+ * e_gdbus_cal_call_get_revision_finish:
+ * @proxy: A #EGdbusCal.
+ * @out_revision: Return location for out parameter or %NULL. Free with g_free().
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback passed to e_gdbus_cal_call_get_revision().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes invoking the <literal>org.gnome.evolution.dataserver.calendar.Cal.getRevision</literal>
+ * D-Bus method on the remote object represented by @proxy.
+ *
+ * Returns: %TRUE if the call succeeded, %FALSE if @error is set.
+ */
+gboolean e_gdbus_cal_call_get_revision_finish (
+        EGdbusCal *proxy,
+        gchar **out_revision,
+        GAsyncResult *res,
+        GError **error)
+{
+  gboolean _ret = FALSE;
+  GVariant *_result;
+  _result = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, error);
+  if (_result == NULL)
+    goto _out;
+  {
+    g_variant_get (_result,
+                   "(s)",
+                   out_revision);
+  }
+  g_variant_unref (_result);
+  _ret = TRUE;
+_out:
+  return _ret;
+}
+
+/**
+ * e_gdbus_cal_call_get_revision_sync:
+ * @proxy: A #EGdbusCal.
+ * @out_revision: Return location for out parameter or %NULL. Free with g_free().
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Synchronously invokes the <literal>org.gnome.evolution.dataserver.calendar.Cal.getRevision</literal>
+ * D-Bus method on the remote object represented by @proxy.
+ *
+ * The calling thread is blocked until a reply is received. See
+ * e_gdbus_cal_call_get_revision() for the asynchronous version of this method.
+ *
+ * Returns: %TRUE if the call succeeded, %FALSE if @error is set.
+ */
+gboolean e_gdbus_cal_call_get_revision_sync (
+        EGdbusCal *proxy,
+        gchar **out_revision,
+        GCancellable *cancellable,
+        GError **error)
+{
+  gboolean _ret = FALSE;
+  GVariant *_params;
+  GVariant *_result;
+  _params = NULL;
+  _result = g_dbus_proxy_call_sync (G_DBUS_PROXY (proxy),
+				    "getRevision",
+				    _params,
+				    G_DBUS_CALL_FLAGS_NONE,
+				    -1,
+				    cancellable,
+				    error);
+
+  if (_result == NULL)
+    goto _out;
+  {
+    g_variant_get (_result,
+                   "(s)",
+                   out_revision);
+  }
+  g_variant_unref (_result);
+  _ret = TRUE;
+_out:
+
+  return _ret;
+}
+
+
 /**
  * e_gdbus_cal_call_is_read_only:
  * @proxy: A #EGdbusCal.
@@ -4576,6 +4718,32 @@ void e_gdbus_cal_complete_get_cal_address (
   g_dbus_method_invocation_return_value (invocation, _params);
 }
 
+
+/**
+ * e_gdbus_cal_complete_get_revision:
+ * @object: A #EGdbusCal.
+ * @invocation: A #GDBusMethodInvocation.
+ * @out_revision: Value to return.
+ *
+ * Completes handling the <literal>org.gnome.evolution.dataserver.calendar.Cal.getRevision</literal>
+ * D-Bus method invocation by returning a value.
+ *
+ * If you want to return an error, use g_dbus_method_invocation_return_error()
+ * or similar instead.
+ *
+ * This method will free @invocation, you cannot use it afterwards.
+ */
+void e_gdbus_cal_complete_get_revision (
+        EGdbusCal *object,
+        GDBusMethodInvocation *invocation,
+        const gchar *out_revision)
+{
+  GVariant *_params;
+  _params = g_variant_new ("(s)",
+                           out_revision);
+  g_dbus_method_invocation_return_value (invocation, _params);
+}
+
 /**
  * e_gdbus_cal_complete_get_alarm_email_address:
  * @object: A #EGdbusCal.
@@ -5328,6 +5496,33 @@ static const GDBusMethodInfo e_gdbus_cal_method_getCalAddress =
   (GDBusAnnotationInfo **) NULL,
 };
 
+
+
+
+
+
+static const GDBusArgInfo e_gdbus_cal_method_out_getRevision_revision =
+{
+  -1,
+  (gchar *) "revision",
+  (gchar *) "s",
+  (GDBusAnnotationInfo **) NULL,
+};
+static const GDBusArgInfo * const e_gdbus_cal_method_out_getRevision_arg_pointers[] =
+{
+  &e_gdbus_cal_method_out_getRevision_revision,
+  NULL
+};
+
+static const GDBusMethodInfo e_gdbus_cal_method_getRevision =
+{
+  -1,
+  (gchar *) "getRevision",
+  (GDBusArgInfo **) NULL,
+  (GDBusArgInfo **) &e_gdbus_cal_method_out_getRevision_arg_pointers,
+  (GDBusAnnotationInfo **) NULL,
+};
+
 static const GDBusArgInfo e_gdbus_cal_method_out_getAlarmEmailAddress_address =
 {
   -1,
@@ -5982,6 +6177,7 @@ static const GDBusMethodInfo * const e_gdbus_cal_method_info_pointers[] =
   &e_gdbus_cal_method_close,
   &e_gdbus_cal_method_remove,
   &e_gdbus_cal_method_isReadOnly,
+  &e_gdbus_cal_method_getRevision,
   &e_gdbus_cal_method_getCalAddress,
   &e_gdbus_cal_method_getAlarmEmailAddress,
   &e_gdbus_cal_method_getLdapAttribute,
@@ -6109,6 +6305,18 @@ handle_method_call (GDBusConnection       *connection,
       }
       break;
 
+    case __GET_REVISION_METHOD:
+      {
+        EGdbusCal *object = E_GDBUS_CAL (user_data);
+        gboolean handled;
+        g_signal_emit (object,
+                       signals[method_id],
+                       0, invocation, &handled);
+        if (!handled)
+          goto not_implemented;
+      }
+      break;
+
     case __IS_READ_ONLY_METHOD:
       {
         EGdbusCal *object = E_GDBUS_CAL (user_data);
diff --git a/calendar/libegdbus/e-gdbus-egdbuscal.h b/calendar/libegdbus/e-gdbus-egdbuscal.h
index e2420d2..c235421 100644
--- a/calendar/libegdbus/e-gdbus-egdbuscal.h
+++ b/calendar/libegdbus/e-gdbus-egdbuscal.h
@@ -38,6 +38,7 @@ typedef struct _EGdbusCal EGdbusCal; /* Dummy typedef */
  * @handle_refresh: Handler for the #EGdbusCal::handle-refresh signal.
  * @handle_close: Handler for the #EGdbusCal::handle-close signal.
  * @handle_remove: Handler for the #EGdbusCal::handle-remove signal.
+ * @handle_get_revision: Handler for the #EGdbusBook::handle-get-revision signal.
  * @handle_is_read_only: Handler for the #EGdbusCal::handle-is-read-only signal.
  * @handle_get_cal_address: Handler for the #EGdbusCal::handle-get-cal-address signal.
  * @handle_get_alarm_email_address: Handler for the #EGdbusCal::handle-get-alarm-email-address signal.
@@ -223,6 +224,9 @@ struct _EGdbusCalIface
   gboolean (*handle_remove) (
         EGdbusCal *object,
         GDBusMethodInvocation *invocation);
+  gboolean (*handle_get_revision) (
+        EGdbusCal *object,
+        GDBusMethodInvocation *invocation);
   gboolean (*handle_is_read_only) (
         EGdbusCal *object,
         GDBusMethodInvocation *invocation);
@@ -424,6 +428,24 @@ gboolean e_gdbus_cal_call_remove_sync (
         GCancellable *cancellable,
         GError **error);
 
+void e_gdbus_cal_call_get_revision (
+        EGdbusCal *proxy,
+        GCancellable *cancellable,
+        GAsyncReadyCallback callback,
+        gpointer user_data);
+
+gboolean e_gdbus_cal_call_get_revision_finish (
+        EGdbusCal *proxy,
+        gchar **out_revision,
+        GAsyncResult *res,
+        GError **error);
+
+gboolean e_gdbus_cal_call_get_revision_sync (
+        EGdbusCal *proxy,
+        gchar **out_revision,
+        GCancellable *cancellable,
+        GError **error);
+
 void e_gdbus_cal_call_is_read_only (
         EGdbusCal *proxy,
         GCancellable *cancellable,
@@ -885,6 +907,11 @@ void e_gdbus_cal_complete_remove (
         EGdbusCal *object,
         GDBusMethodInvocation *invocation);
 
+void e_gdbus_cal_complete_get_revision (
+        EGdbusCal *object,
+        GDBusMethodInvocation *invocation,
+        const gchar *out_revision);
+
 void e_gdbus_cal_complete_is_read_only (
         EGdbusCal *object,
         GDBusMethodInvocation *invocation);
