[evolution-data-server] Bug 692361 - e_cal_client_get_free_busy() broken



commit 7ac978817654842ab6fea7d519ea92759cbcbbcc
Author: Milan Crha <mcrha redhat com>
Date:   Wed Jul 15 12:37:25 2015 +0200

    Bug 692361 - e_cal_client_get_free_busy() broken

 calendar/backends/gtasks/e-cal-backend-gtasks.c    |    2 +-
 calendar/libecal/e-cal-client.c                    |   48 ++++++++++++++++++--
 calendar/libecal/e-cal-client.h                    |    2 +
 calendar/libecal/e-cal.c                           |   18 ++++---
 calendar/libedata-cal/e-cal-backend-sync.c         |    2 +-
 calendar/libedata-cal/e-cal-backend.c              |   43 ++++++++++++++---
 calendar/libedata-cal/e-cal-backend.h              |    2 +
 calendar/libedata-cal/e-data-cal.c                 |   42 +++++++++++++++---
 calendar/libedata-cal/e-data-cal.h                 |    3 +-
 configure.ac                                       |    4 +-
 .../org.gnome.evolution.dataserver.Calendar.xml    |    1 +
 tests/libecal/client/Makefile.am                   |    6 ---
 .../libecal/client/test-cal-client-get-free-busy.c |   19 ++++----
 13 files changed, 146 insertions(+), 46 deletions(-)
---
diff --git a/calendar/backends/gtasks/e-cal-backend-gtasks.c b/calendar/backends/gtasks/e-cal-backend-gtasks.c
index 0735967..912d122 100644
--- a/calendar/backends/gtasks/e-cal-backend-gtasks.c
+++ b/calendar/backends/gtasks/e-cal-backend-gtasks.c
@@ -908,7 +908,7 @@ ecb_gtasks_get_free_busy (ECalBackend *backend,
        g_return_if_fail (E_IS_CAL_BACKEND_GTASKS (backend));
        g_return_if_fail (E_IS_DATA_CAL (cal));
 
-       e_data_cal_respond_get_free_busy (cal, opid, EDC_ERROR (NotSupported));
+       e_data_cal_respond_get_free_busy (cal, opid, EDC_ERROR (NotSupported), NULL);
 }
 
 static void
diff --git a/calendar/libecal/e-cal-client.c b/calendar/libecal/e-cal-client.c
index 78731f6..f3d06e2 100644
--- a/calendar/libecal/e-cal-client.c
+++ b/calendar/libecal/e-cal-client.c
@@ -4533,6 +4533,7 @@ cal_client_get_free_busy_thread (GSimpleAsyncResult *simple,
                async_context->start,
                async_context->end,
                async_context->string_list,
+               &async_context->object_list,
                cancellable, &local_error)) {
 
                if (!local_error)
@@ -4606,10 +4607,13 @@ e_cal_client_get_free_busy (ECalClient *client,
  * e_cal_client_get_free_busy_finish:
  * @client: an #ECalClient
  * @result: a #GAsyncResult
+ * @out_freebusy: (element-type ECalComponent): a #GSList of #ECalComponent-s with overall returned 
Free/Busy data
  * @error: (out): a #GError to set an error, if any
  *
  * Finishes previous call of e_cal_client_get_free_busy().
- * All VFREEBUSY #ECalComponent-s were received by "free-busy-data" signal.
+ * The @out_freebusy contains all VFREEBUSY #ECalComponent-s, which could be also
+ * received by "free-busy-data" signal. The client is responsible to do a merge of
+ * the components between this complete list and those received through the signal.
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
  *
@@ -4618,6 +4622,7 @@ e_cal_client_get_free_busy (ECalClient *client,
 gboolean
 e_cal_client_get_free_busy_finish (ECalClient *client,
                                    GAsyncResult *result,
+                                  GSList **out_freebusy,
                                    GError **error)
 {
        GSimpleAsyncResult *simple;
@@ -4630,7 +4635,19 @@ e_cal_client_get_free_busy_finish (ECalClient *client,
        simple = G_SIMPLE_ASYNC_RESULT (result);
 
        /* Assume success unless a GError is set. */
-       return !g_simple_async_result_propagate_error (simple, error);
+       if (g_simple_async_result_propagate_error (simple, error))
+               return FALSE;
+
+       if (out_freebusy != NULL) {
+               AsyncContext *async_context;
+
+               async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+               *out_freebusy = async_context->object_list;
+               async_context->object_list = NULL;
+       }
+
+       return TRUE;
 }
 
 /**
@@ -4639,11 +4656,14 @@ e_cal_client_get_free_busy_finish (ECalClient *client,
  * @start: Start time for query
  * @end: End time for query
  * @users: (element-type utf8): List of users to retrieve free/busy information for
+ * @out_freebusy: (element-type ECalComponent): a #GSList of #ECalComponent-s with overall returned 
Free/Busy data
  * @cancellable: (allow-none): a #GCancellable; can be %NULL
  * @error: (out): a #GError to set an error, if any
  *
  * Gets free/busy information from the calendar server.
- * All VFREEBUSY #ECalComponent-s were received by "free-busy-data" signal.
+ * The @out_freebusy contains all VFREEBUSY #ECalComponent-s, which could be also
+ * received by "free-busy-data" signal. The client is responsible to do a merge of
+ * the components between this complete list and those received through the signal.
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
  *
@@ -4654,10 +4674,11 @@ e_cal_client_get_free_busy_sync (ECalClient *client,
                                  time_t start,
                                  time_t end,
                                  const GSList *users,
+                                GSList **out_freebusy,
                                  GCancellable *cancellable,
                                  GError **error)
 {
-       gchar **strv;
+       gchar **strv, **freebusy_strv = NULL;
        gint ii = 0;
        GError *local_error = NULL;
 
@@ -4675,6 +4696,7 @@ e_cal_client_get_free_busy_sync (ECalClient *client,
                client->priv->dbus_proxy,
                (gint64) start, (gint64) end,
                (const gchar * const *) strv,
+               &freebusy_strv,
                cancellable, &local_error);
 
        g_strfreev (strv);
@@ -4685,6 +4707,24 @@ e_cal_client_get_free_busy_sync (ECalClient *client,
                return FALSE;
        }
 
+       if (out_freebusy) {
+               *out_freebusy = NULL;
+
+               for (ii = 0; freebusy_strv && freebusy_strv[ii] != NULL; ii++) {
+                       ECalComponent *comp;
+
+                       comp = e_cal_component_new_from_string (freebusy_strv[ii]);
+                       if (!comp)
+                               continue;
+
+                       *out_freebusy = g_slist_prepend (*out_freebusy, comp);
+               }
+
+               *out_freebusy = g_slist_reverse (*out_freebusy);
+       }
+
+       g_strfreev (freebusy_strv);
+
        return TRUE;
 }
 
diff --git a/calendar/libecal/e-cal-client.h b/calendar/libecal/e-cal-client.h
index 17124a1..172861b 100644
--- a/calendar/libecal/e-cal-client.h
+++ b/calendar/libecal/e-cal-client.h
@@ -308,11 +308,13 @@ void              e_cal_client_get_free_busy      (ECalClient *client,
 gboolean       e_cal_client_get_free_busy_finish
                                                (ECalClient *client,
                                                 GAsyncResult *result,
+                                                GSList **out_freebusy,
                                                 GError **error);
 gboolean       e_cal_client_get_free_busy_sync (ECalClient *client,
                                                 time_t start,
                                                 time_t end,
                                                 const GSList *users,
+                                                GSList **out_freebusy,
                                                 GCancellable *cancellable,
                                                 GError **error);
 void           e_cal_client_create_object      (ECalClient *client,
diff --git a/calendar/libecal/e-cal.c b/calendar/libecal/e-cal.c
index db05e2c..da0df1b 100644
--- a/calendar/libecal/e-cal.c
+++ b/calendar/libecal/e-cal.c
@@ -1588,7 +1588,7 @@ e_cal_get_free_busy (ECal *ecal,
                      GList **freebusy,
                      GError **error)
 {
-       GSList *slist = NULL;
+       GSList *slist = NULL, *out_freebusy = NULL, *link;
        gboolean success;
 
        g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
@@ -1601,17 +1601,19 @@ e_cal_get_free_busy (ECal *ecal,
        for (; users != NULL; users = g_list_next (users))
                slist = g_slist_prepend (slist, users->data);
 
-       /* FIXME ECalClient's API for this is a giant W.T.F.
-        *       There's no way to populate the freebusy list
-        *       in a way that will avoid deadlocking for all
-        *       cases.  I guess leave the list empty and hope
-        *       no one notices until ECalClient grows a saner
-        *       free/busy API. */
        success = e_cal_client_get_free_busy_sync (
-               ecal->priv->client, start, end, slist, NULL, error);
+               ecal->priv->client, start, end, slist, &out_freebusy, NULL, error);
 
        g_slist_free (slist);
 
+       if (success) {
+               for (link = out_freebusy; link; link = g_slist_next (link)) {
+                       *freebusy = g_list_prepend (*freebusy, g_object_ref (link->data));
+               }
+       }
+
+       g_slist_free_full (out_freebusy, g_object_unref);
+
        return success;
 }
 
diff --git a/calendar/libedata-cal/e-cal-backend-sync.c b/calendar/libedata-cal/e-cal-backend-sync.c
index d415b8c..76d0e09 100644
--- a/calendar/libedata-cal/e-cal-backend-sync.c
+++ b/calendar/libedata-cal/e-cal-backend-sync.c
@@ -687,7 +687,7 @@ cal_backend_get_free_busy (ECalBackend *backend,
 
        if (freebusyobjs)
                e_data_cal_report_free_busy_data (cal, freebusyobjs);
-       e_data_cal_respond_get_free_busy (cal, opid, error);
+       e_data_cal_respond_get_free_busy (cal, opid, error, freebusyobjs);
 
        g_slist_foreach (freebusyobjs, (GFunc) g_free, NULL);
        g_slist_free (freebusyobjs);
diff --git a/calendar/libedata-cal/e-cal-backend.c b/calendar/libedata-cal/e-cal-backend.c
index 6179986..68febe7 100644
--- a/calendar/libedata-cal/e-cal-backend.c
+++ b/calendar/libedata-cal/e-cal-backend.c
@@ -2197,13 +2197,17 @@ e_cal_backend_get_object_list_finish (ECalBackend *backend,
  * @start: start time
  * @end: end time
  * @users: a %NULL-terminated array of user strings
+ * @out_freebusy: iCalendar strings with overall returned Free/Busy data
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
  * Obtains a free/busy object for the list of @users in the time interval
- * between @start and @end.  The free/busy results are returned through the
- * e_data_cal_report_free_busy_data() function rather than directly through
- * this function.
+ * between @start and @end.
+ *
+ * The free/busy results can be returned through the
+ * e_data_cal_report_free_busy_data() function asynchronously. The out_freebusy
+ * will contain all the returned data, possibly again, thus the client is
+ * responsible for the data merge, if needed.
  *
  * If an error occurs, the function will set @error and return %FALSE.
  *
@@ -2216,6 +2220,7 @@ e_cal_backend_get_free_busy_sync (ECalBackend *backend,
                                   time_t start,
                                   time_t end,
                                   const gchar * const *users,
+                                 GSList **out_freebusy,
                                   GCancellable *cancellable,
                                   GError **error)
 {
@@ -2235,7 +2240,7 @@ e_cal_backend_get_free_busy_sync (ECalBackend *backend,
        result = e_async_closure_wait (closure);
 
        success = e_cal_backend_get_free_busy_finish (
-               backend, result, error);
+               backend, result, out_freebusy, error);
 
        e_async_closure_free (closure);
 
@@ -2353,13 +2358,15 @@ e_cal_backend_get_free_busy (ECalBackend *backend,
  * e_cal_backend_get_free_busy_finish:
  * @backend: an #ECalBackend
  * @result: a #GAsyncResult
+ * @out_freebusy: iCalendar strings with overall returned Free/Busy data
  * @error: return location for a #GError, or %NULL
  *
  * Finishes the operation started with e_cal_backend_get_free_busy().
  *
- * The free/busy results are returned through the
- * e_data_cal_report_free_busy_data() function rather than directly through
- * this function.
+ * The free/busy results can be returned through the
+ * e_data_cal_report_free_busy_data() function asynchronously. The out_freebusy
+ * will contain all the returned data, possibly again, thus the client is
+ * responsible for the data merge, if needed.
  *
  * If an error occurred, the function will set @error and return %FALSE.
  *
@@ -2370,9 +2377,12 @@ e_cal_backend_get_free_busy (ECalBackend *backend,
 gboolean
 e_cal_backend_get_free_busy_finish (ECalBackend *backend,
                                     GAsyncResult *result,
+                                   GSList **out_freebusy,
                                     GError **error)
 {
        GSimpleAsyncResult *simple;
+       AsyncContext *async_context;
+       GSList *ical_strings = NULL;
 
        g_return_val_if_fail (
                g_simple_async_result_is_valid (
@@ -2380,11 +2390,28 @@ e_cal_backend_get_free_busy_finish (ECalBackend *backend,
                e_cal_backend_get_free_busy), FALSE);
 
        simple = G_SIMPLE_ASYNC_RESULT (result);
+       async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
        cal_backend_unblock_operations (backend, simple);
 
        /* Assume success unless a GError is set. */
-       return !g_simple_async_result_propagate_error (simple, error);
+       if (g_simple_async_result_propagate_error (simple, error))
+               return FALSE;
+
+       while (!g_queue_is_empty (&async_context->result_queue)) {
+               gchar *ical_freebusy;
+
+               ical_freebusy = g_queue_pop_head (&async_context->result_queue);
+               if (out_freebusy)
+                       ical_strings = g_slist_prepend (ical_strings, ical_freebusy);
+               else
+                       g_free (ical_freebusy);
+       }
+
+       if (out_freebusy)
+               *out_freebusy = g_slist_reverse (ical_strings);
+
+       return TRUE;
 }
 
 /**
diff --git a/calendar/libedata-cal/e-cal-backend.h b/calendar/libedata-cal/e-cal-backend.h
index 9ceb25d..e7bc505 100644
--- a/calendar/libedata-cal/e-cal-backend.h
+++ b/calendar/libedata-cal/e-cal-backend.h
@@ -340,6 +340,7 @@ gboolean    e_cal_backend_get_free_busy_sync
                                                 time_t start,
                                                 time_t end,
                                                 const gchar * const *users,
+                                                GSList **out_freebusy,
                                                 GCancellable *cancellable,
                                                 GError **error);
 void           e_cal_backend_get_free_busy     (ECalBackend *backend,
@@ -352,6 +353,7 @@ void                e_cal_backend_get_free_busy     (ECalBackend *backend,
 gboolean       e_cal_backend_get_free_busy_finish
                                                (ECalBackend *backend,
                                                 GAsyncResult *result,
+                                                GSList **out_freebusy,
                                                 GError **error);
 gboolean       e_cal_backend_create_objects_sync
                                                (ECalBackend *backend,
diff --git a/calendar/libedata-cal/e-data-cal.c b/calendar/libedata-cal/e-data-cal.c
index ec9e51e..99f234d 100644
--- a/calendar/libedata-cal/e-data-cal.c
+++ b/calendar/libedata-cal/e-data-cal.c
@@ -833,21 +833,38 @@ data_cal_complete_get_free_busy_cb (GObject *source_object,
                                     gpointer user_data)
 {
        AsyncContext *async_context = user_data;
+       GSList *out_freebusy = NULL;
        GError *error = NULL;
 
        e_cal_backend_get_free_busy_finish (
-               E_CAL_BACKEND (source_object), result, &error);
+               E_CAL_BACKEND (source_object), result, &out_freebusy, &error);
 
        if (error == NULL) {
+               gchar **strv;
+               gint ii = 0;
+               GSList *link;
+
+               strv = g_new0 (gchar *, g_slist_length (out_freebusy) + 1);
+
+               for (link = out_freebusy; link; link = g_slist_next (link)) {
+                       gchar *ical_freebusy = link->data;
+
+                       strv[ii++] = e_util_utf8_make_valid (ical_freebusy);
+               }
+
                e_dbus_calendar_complete_get_free_busy (
                        async_context->dbus_interface,
-                       async_context->invocation);
+                       async_context->invocation,
+                       (const gchar * const *) strv);
+
+               g_strfreev (strv);
        } else {
                data_cal_convert_to_client_error (error);
                g_dbus_method_invocation_take_error (
                        async_context->invocation, error);
        }
 
+       g_slist_free_full (out_freebusy, g_free);
        async_context_free (async_context);
 }
 
@@ -1783,33 +1800,46 @@ e_data_cal_respond_get_object_list (EDataCal *cal,
  * e_data_cal_respond_get_free_busy:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
+ * @freebusy: a #GSList of iCalendar strings with all gathered free/busy components.
  *
  * Notifies listeners of the completion of the get_free_busy method call.
- * To pass actual free/busy objects to the client use e_data_cal_report_free_busy_data().
+ * To pass actual free/busy objects to the client asynchronously
+ * use e_data_cal_report_free_busy_data(), but the @freebusy should contain
+ * all the objects being used in e_data_cal_report_free_busy_data().
  *
  * Since: 3.2
  */
 void
 e_data_cal_respond_get_free_busy (EDataCal *cal,
                                   guint32 opid,
-                                  GError *error)
+                                  GError *error,
+                                 const GSList *freebusy)
 {
        ECalBackend *backend;
        GSimpleAsyncResult *simple;
+       GQueue *queue = NULL;
+       const GSList *link;
 
        g_return_if_fail (E_IS_DATA_CAL (cal));
 
        backend = e_data_cal_ref_backend (cal);
        g_return_if_fail (backend != NULL);
 
-       simple = e_cal_backend_prepare_for_completion (backend, opid, NULL);
+       simple = e_cal_backend_prepare_for_completion (backend, opid, &queue);
        g_return_if_fail (simple != NULL);
 
        /* Translators: This is prefix to a detailed error message */
        g_prefix_error (&error, "%s", _("Cannot retrieve calendar free/busy list: "));
 
-       if (error != NULL)
+       if (error != NULL) {
                g_simple_async_result_take_error (simple, error);
+       } else {
+               for (link = freebusy; link; link = g_slist_next (link)) {
+                       const gchar *ical_freebusy = link->data;
+
+                       g_queue_push_tail (queue, g_strdup (ical_freebusy));
+               }
+       }
 
        g_simple_async_result_complete_in_idle (simple);
 
diff --git a/calendar/libedata-cal/e-data-cal.h b/calendar/libedata-cal/e-data-cal.h
index 4445c9a..97d4a11 100644
--- a/calendar/libedata-cal/e-data-cal.h
+++ b/calendar/libedata-cal/e-data-cal.h
@@ -148,7 +148,8 @@ void                e_data_cal_respond_get_object_list
 void           e_data_cal_respond_get_free_busy
                                                (EDataCal *cal,
                                                 guint32 opid,
-                                                GError *error);
+                                                GError *error,
+                                                const GSList *freebusy);
 void           e_data_cal_respond_create_objects
                                                (EDataCal *cal,
                                                 guint32 opid,
diff --git a/configure.ac b/configure.ac
index 625e3c5..6879e28 100644
--- a/configure.ac
+++ b/configure.ac
@@ -114,11 +114,11 @@ LIBEDATASERVERUI_CURRENT=1
 LIBEDATASERVERUI_REVISION=0
 LIBEDATASERVERUI_AGE=0
 
-LIBECAL_CURRENT=18
+LIBECAL_CURRENT=19
 LIBECAL_REVISION=0
 LIBECAL_AGE=0
 
-LIBEDATACAL_CURRENT=27
+LIBEDATACAL_CURRENT=28
 LIBEDATACAL_REVISION=0
 LIBEDATACAL_AGE=0
 
diff --git a/private/org.gnome.evolution.dataserver.Calendar.xml 
b/private/org.gnome.evolution.dataserver.Calendar.xml
index 5c21327..2d8949e 100644
--- a/private/org.gnome.evolution.dataserver.Calendar.xml
+++ b/private/org.gnome.evolution.dataserver.Calendar.xml
@@ -84,6 +84,7 @@
     <arg name="start" direction="in" type="x"/>
     <arg name="end" direction="in" type="x"/>
     <arg name="users" direction="in" type="as"/>
+    <arg name="freebusy" direction="out" type="as"/>
   </method>
 
   <method name="GetAttachmentUris">
diff --git a/tests/libecal/client/Makefile.am b/tests/libecal/client/Makefile.am
index 7d88b30..37af8f8 100644
--- a/tests/libecal/client/Makefile.am
+++ b/tests/libecal/client/Makefile.am
@@ -37,12 +37,6 @@ TESTS = \
        test-cal-client-get-view \
        test-cal-client-revision-view \
        test-cal-client-get-revision \
-       $(NULL)
-
-# test-cal-client-get-free-busy:
-#   broken by design, the API needs to be fixed.
-#
-BROKEN_TESTS = \
        test-cal-client-get-free-busy \
        $(NULL)
 
diff --git a/tests/libecal/client/test-cal-client-get-free-busy.c 
b/tests/libecal/client/test-cal-client-get-free-busy.c
index ac01a99..c368097 100644
--- a/tests/libecal/client/test-cal-client-get-free-busy.c
+++ b/tests/libecal/client/test-cal-client-get-free-busy.c
@@ -109,9 +109,8 @@ test_get_free_busy_sync (ETestServerFixture *fixture,
        ECalClient *cal_client;
        GError *error = NULL;
        icaltimezone *utc;
-       GSList *users = NULL;
+       GSList *users = NULL, *freebusy_data = NULL;
        time_t start, end;
-       gulong sig_id;
 
        cal_client = E_TEST_SERVER_UTILS_SERVICE (fixture, ECalClient);
 
@@ -123,16 +122,14 @@ test_get_free_busy_sync (ETestServerFixture *fixture,
        end = time_add_day_with_zone (start, 2, utc);
        users = g_slist_append (users, (gpointer) USER_EMAIL);
 
-       sig_id = g_signal_connect (cal_client, "free-busy-data", G_CALLBACK (free_busy_data_cb), (gpointer) 
G_STRFUNC);
-
-       if (!e_cal_client_get_free_busy_sync (cal_client, start, end, users, NULL, &error))
+       if (!e_cal_client_get_free_busy_sync (cal_client, start, end, users, &freebusy_data, NULL, &error))
                g_error ("get free busy sync: %s", error->message);
 
-       g_signal_handler_disconnect (cal_client, sig_id);
-
        g_slist_free (users);
 
-       g_assert (received_free_busy_data);
+       g_assert (freebusy_data);
+
+       g_slist_free_full (freebusy_data, g_object_unref);
 }
 
 static void
@@ -143,13 +140,17 @@ async_get_free_busy_result_ready (GObject *source_object,
        ECalClient *cal_client;
        GError *error = NULL;
        GMainLoop *loop = (GMainLoop *) user_data;
+       GSList *freebusy_data = NULL;
 
        cal_client = E_CAL_CLIENT (source_object);
 
-       if (!e_cal_client_get_free_busy_finish (cal_client, result, &error))
+       if (!e_cal_client_get_free_busy_finish (cal_client, result, &freebusy_data, &error))
                g_error ("create object finish: %s", error->message);
 
        g_assert (received_free_busy_data);
+       g_assert (freebusy_data);
+
+       g_slist_free_full (freebusy_data, g_object_unref);
 
        g_main_loop_quit (loop);
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]