goa: Add missing linker flag (for real).
[platform/upstream/evolution-data-server.git] / libedataserver / e-gdbus-templates.c
1 /*
2  * e-gdbus-templates.c
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) version 3.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
16  *
17  *
18  * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
19  *
20  */
21
22 #include <gio/gio.h>
23
24 #include <stdio.h>
25
26 #include "e-data-server-util.h"
27 #include "e-flag.h"
28 #include "e-gdbus-templates.h"
29
30 static GThread *main_thread = NULL;
31
32 void
33 e_gdbus_templates_init_main_thread (void)
34 {
35         if (!main_thread) {
36                 main_thread = g_thread_self ();
37         } else if (main_thread != g_thread_self ()) {
38                 g_warning ("%s: Called in different main thread, stored: %p would use: %p", G_STRFUNC, main_thread, g_thread_self ());
39         }
40 }
41
42 gboolean
43 e_gdbus_signal_emission_hook_void (GSignalInvocationHint *ihint,
44                                    guint n_param_values,
45                                    const GValue *param_values,
46                                    const gchar *signal_name,
47                                    const gchar *iface_name)
48 {
49         GObject *object;
50         GDBusConnection *connection;
51         const gchar *path;
52
53         if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
54                 return FALSE;
55
56         object = g_value_get_object (&param_values[0]);
57         path = g_object_get_data (object, "gdbus-codegen-path");
58         connection = g_object_get_data (object, "gdbus-codegen-connection");
59         if (connection == NULL || path == NULL)
60                 return FALSE;
61
62         g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, NULL, NULL);
63
64         return TRUE;
65 }
66
67 gboolean
68 e_gdbus_signal_emission_hook_boolean (GSignalInvocationHint *ihint,
69                                       guint n_param_values,
70                                       const GValue *param_values,
71                                       const gchar *signal_name,
72                                       const gchar *iface_name)
73 {
74         GObject *object;
75         GDBusConnection *connection;
76         const gchar *path;
77         GVariant *params;
78         GVariant *item;
79         GVariantBuilder *builder;
80
81         if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
82                 return FALSE;
83
84         object = g_value_get_object (&param_values[0]);
85         path = g_object_get_data (object, "gdbus-codegen-path");
86         connection = g_object_get_data (object, "gdbus-codegen-connection");
87         if (connection == NULL || path == NULL)
88                 return FALSE;
89
90         builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
91         g_assert_cmpint (n_param_values - 1, ==, 1);
92         param_values++;
93         item = g_variant_new_boolean (g_value_get_boolean (param_values));
94         g_variant_builder_add_value (builder, item);
95         param_values++;
96         params = g_variant_builder_end (builder);
97         g_variant_builder_unref (builder);
98
99         g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
100
101         return TRUE;
102 }
103
104 gboolean
105 e_gdbus_signal_emission_hook_string (GSignalInvocationHint *ihint,
106                                      guint n_param_values,
107                                      const GValue *param_values,
108                                      const gchar *signal_name,
109                                      const gchar *iface_name)
110 {
111         GObject *object;
112         GDBusConnection *connection;
113         const gchar *path;
114         GVariant *params;
115         GVariant *item;
116         GVariantBuilder *builder;
117
118         if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
119                 return FALSE;
120
121         object = g_value_get_object (&param_values[0]);
122         path = g_object_get_data (object, "gdbus-codegen-path");
123         connection = g_object_get_data (object, "gdbus-codegen-connection");
124         if (connection == NULL || path == NULL)
125                 return FALSE;
126
127         builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
128         g_assert_cmpint (n_param_values - 1, ==, 1);
129         param_values++;
130         item = g_variant_new_string (g_value_get_string (param_values));
131         g_variant_builder_add_value (builder, item);
132         param_values++;
133         params = g_variant_builder_end (builder);
134         g_variant_builder_unref (builder);
135
136         g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
137
138         return TRUE;
139 }
140
141 gboolean
142 e_gdbus_signal_emission_hook_strv (GSignalInvocationHint *ihint,
143                                    guint n_param_values,
144                                    const GValue *param_values,
145                                    const gchar *signal_name,
146                                    const gchar *iface_name)
147 {
148         GObject *object;
149         GDBusConnection *connection;
150         const gchar *path;
151         GVariant *params;
152         GVariant *item;
153         GVariantBuilder *builder;
154         const gchar * const *arg_strv;
155
156         if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
157                 return FALSE;
158
159         object = g_value_get_object (&param_values[0]);
160         path = g_object_get_data (object, "gdbus-codegen-path");
161         connection = g_object_get_data (object, "gdbus-codegen-connection");
162         if (connection == NULL || path == NULL)
163                 return FALSE;
164
165         builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
166         g_assert_cmpint (n_param_values - 1, ==, 1);
167         param_values++;
168         arg_strv = g_value_get_boxed (param_values);
169         item = g_variant_new_strv (arg_strv, -1);
170         g_variant_builder_add_value (builder, item);
171         param_values++;
172         params = g_variant_builder_end (builder);
173         g_variant_builder_unref (builder);
174
175         g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
176
177         return TRUE;
178 }
179
180 gboolean
181 e_gdbus_signal_emission_hook_uint (GSignalInvocationHint *ihint,
182                                    guint n_param_values,
183                                    const GValue *param_values,
184                                    const gchar *signal_name,
185                                    const gchar *iface_name)
186 {
187         GObject *object;
188         GDBusConnection *connection;
189         const gchar *path;
190         GVariant *params;
191         GVariant *item;
192         GVariantBuilder *builder;
193
194         if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
195                 return FALSE;
196
197         object = g_value_get_object (&param_values[0]);
198         path = g_object_get_data (object, "gdbus-codegen-path");
199         connection = g_object_get_data (object, "gdbus-codegen-connection");
200         if (connection == NULL || path == NULL)
201                 return FALSE;
202
203         builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
204         g_assert_cmpint (n_param_values - 1, ==, 1);
205         param_values++;
206         item = g_variant_new_uint32 (g_value_get_uint (param_values));
207         g_variant_builder_add_value (builder, item);
208         param_values++;
209         params = g_variant_builder_end (builder);
210         g_variant_builder_unref (builder);
211
212         g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
213
214         return TRUE;
215 }
216
217 gboolean
218 e_gdbus_signal_emission_hook_uint_string (GSignalInvocationHint *ihint,
219                                           guint n_param_values,
220                                           const GValue *param_values,
221                                           const gchar *signal_name,
222                                           const gchar *iface_name)
223 {
224         GObject *object;
225         GDBusConnection *connection;
226         const gchar *path;
227         GVariant *params;
228         GVariant *item;
229         GVariantBuilder *builder;
230
231         if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
232                 return FALSE;
233
234         object = g_value_get_object (&param_values[0]);
235         path = g_object_get_data (object, "gdbus-codegen-path");
236         connection = g_object_get_data (object, "gdbus-codegen-connection");
237         if (connection == NULL || path == NULL)
238                 return FALSE;
239
240         builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
241         g_assert_cmpint (n_param_values - 1, ==, 2);
242         param_values++;
243         item = g_variant_new_uint32 (g_value_get_uint (param_values));
244         g_variant_builder_add_value (builder, item);
245         param_values++;
246         item = g_variant_new_string (g_value_get_string (param_values));
247         g_variant_builder_add_value (builder, item);
248         param_values++;
249         params = g_variant_builder_end (builder);
250         g_variant_builder_unref (builder);
251
252         g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
253
254         return TRUE;
255 }
256
257 gboolean
258 e_gdbus_signal_emission_hook_async_void (GSignalInvocationHint *ihint,
259                                          guint n_param_values,
260                                          const GValue *param_values,
261                                          const gchar *signal_name,
262                                          const gchar *iface_name)
263 {
264         GObject *object;
265         GDBusConnection *connection;
266         const gchar *path;
267         GVariant *params;
268         GVariant *item;
269         GVariantBuilder *builder;
270         GError *arg_error;
271
272         if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
273                 return FALSE;
274
275         object = g_value_get_object (&param_values[0]);
276         path = g_object_get_data (object, "gdbus-codegen-path");
277         connection = g_object_get_data (object, "gdbus-codegen-connection");
278         if (connection == NULL || path == NULL)
279                 return FALSE;
280
281         builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
282         g_assert_cmpint (n_param_values - 1, ==, 2);
283         param_values++;
284         item = g_variant_new_uint32 (g_value_get_uint (param_values));
285         g_variant_builder_add_value (builder, item);
286         param_values++;
287         arg_error = g_value_get_boxed (param_values);
288         if (arg_error) {
289                 gchar *dbus_error_name = g_dbus_error_encode_gerror (arg_error);
290                 item = g_variant_new_string (dbus_error_name ? dbus_error_name : "");
291                 g_variant_builder_add_value (builder, item);
292                 item = g_variant_new_string (arg_error->message);
293                 g_variant_builder_add_value (builder, item);
294                 g_free (dbus_error_name);
295         } else {
296                 item = g_variant_new_string ("");
297                 g_variant_builder_add_value (builder, item);
298                 item = g_variant_new_string ("");
299                 g_variant_builder_add_value (builder, item);
300
301                 param_values++;
302         }
303         params = g_variant_builder_end (builder);
304         g_variant_builder_unref (builder);
305
306         g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
307
308         return TRUE;
309 }
310
311 gboolean
312 e_gdbus_signal_emission_hook_async_boolean (GSignalInvocationHint *ihint,
313                                             guint n_param_values,
314                                             const GValue *param_values,
315                                             const gchar *signal_name,
316                                             const gchar *iface_name)
317 {
318         GObject *object;
319         GDBusConnection *connection;
320         const gchar *path;
321         GVariant *params;
322         GVariant *item;
323         GVariantBuilder *builder;
324         GError *arg_error;
325
326         if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
327                 return FALSE;
328
329         object = g_value_get_object (&param_values[0]);
330         path = g_object_get_data (object, "gdbus-codegen-path");
331         connection = g_object_get_data (object, "gdbus-codegen-connection");
332         if (connection == NULL || path == NULL)
333                 return FALSE;
334
335         builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
336         g_assert_cmpint (n_param_values - 1, ==, 3);
337         param_values++;
338         item = g_variant_new_uint32 (g_value_get_uint (param_values));
339         g_variant_builder_add_value (builder, item);
340         param_values++;
341         arg_error = g_value_get_boxed (param_values);
342         if (arg_error) {
343                 gchar *dbus_error_name = g_dbus_error_encode_gerror (arg_error);
344                 item = g_variant_new_string (dbus_error_name ? dbus_error_name : "");
345                 g_variant_builder_add_value (builder, item);
346                 item = g_variant_new_string (arg_error->message);
347                 g_variant_builder_add_value (builder, item);
348                 g_free (dbus_error_name);
349
350                 /* fake value for easier processing in e_gdbus_proxy_emit_signal() */
351                 item = g_variant_new_boolean (FALSE);
352                 g_variant_builder_add_value (builder, item);
353         } else {
354                 item = g_variant_new_string ("");
355                 g_variant_builder_add_value (builder, item);
356                 item = g_variant_new_string ("");
357                 g_variant_builder_add_value (builder, item);
358
359                 param_values++;
360                 item = g_variant_new_boolean (g_value_get_boolean (param_values));
361                 g_variant_builder_add_value (builder, item);
362                 param_values++;
363         }
364         params = g_variant_builder_end (builder);
365         g_variant_builder_unref (builder);
366
367         g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
368
369         return TRUE;
370 }
371
372 gboolean
373 e_gdbus_signal_emission_hook_async_string (GSignalInvocationHint *ihint,
374                                            guint n_param_values,
375                                            const GValue *param_values,
376                                            const gchar *signal_name,
377                                            const gchar *iface_name)
378 {
379         GObject *object;
380         GDBusConnection *connection;
381         const gchar *path;
382         GVariant *params;
383         GVariant *item;
384         GVariantBuilder *builder;
385         GError *arg_error;
386
387         if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
388                 return FALSE;
389
390         object = g_value_get_object (&param_values[0]);
391         path = g_object_get_data (object, "gdbus-codegen-path");
392         connection = g_object_get_data (object, "gdbus-codegen-connection");
393         if (connection == NULL || path == NULL)
394                 return FALSE;
395
396         builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
397         g_assert_cmpint (n_param_values - 1, ==, 3);
398         param_values++;
399         item = g_variant_new_uint32 (g_value_get_uint (param_values));
400         g_variant_builder_add_value (builder, item);
401         param_values++;
402         arg_error = g_value_get_boxed (param_values);
403         if (arg_error) {
404                 gchar *dbus_error_name = g_dbus_error_encode_gerror (arg_error);
405                 item = g_variant_new_string (dbus_error_name ? dbus_error_name : "");
406                 g_variant_builder_add_value (builder, item);
407                 item = g_variant_new_string (arg_error->message);
408                 g_variant_builder_add_value (builder, item);
409                 g_free (dbus_error_name);
410
411                 /* fake value for easier processing in e_gdbus_proxy_emit_signal() */
412                 item = g_variant_new_string ("");
413                 g_variant_builder_add_value (builder, item);
414         } else {
415                 item = g_variant_new_string ("");
416                 g_variant_builder_add_value (builder, item);
417                 item = g_variant_new_string ("");
418                 g_variant_builder_add_value (builder, item);
419
420                 param_values++;
421                 item = g_variant_new_string (g_value_get_string (param_values));
422                 g_variant_builder_add_value (builder, item);
423                 param_values++;
424         }
425         params = g_variant_builder_end (builder);
426         g_variant_builder_unref (builder);
427
428         g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
429
430         return TRUE;
431 }
432
433 gboolean
434 e_gdbus_signal_emission_hook_async_strv (GSignalInvocationHint *ihint,
435                                          guint n_param_values,
436                                          const GValue *param_values,
437                                          const gchar *signal_name,
438                                          const gchar *iface_name)
439 {
440         GObject *object;
441         GDBusConnection *connection;
442         const gchar *path;
443         GVariant *params;
444         GVariant *item;
445         GVariantBuilder *builder;
446         const GError *arg_error;
447         const gchar * const *arg_strv;
448
449         if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
450                 return FALSE;
451
452         object = g_value_get_object (&param_values[0]);
453         path = g_object_get_data (object, "gdbus-codegen-path");
454         connection = g_object_get_data (object, "gdbus-codegen-connection");
455         if (connection == NULL || path == NULL)
456                 return FALSE;
457
458         builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
459         g_assert_cmpint (n_param_values - 1, ==, 3);
460         param_values++;
461         item = g_variant_new_uint32 (g_value_get_uint (param_values));
462         g_variant_builder_add_value (builder, item);
463         param_values++;
464         arg_error = g_value_get_boxed (param_values);
465         if (arg_error) {
466                 const gchar *fake_strv;
467                 gchar *dbus_error_name = g_dbus_error_encode_gerror (arg_error);
468                 item = g_variant_new_string (dbus_error_name ? dbus_error_name : "");
469                 g_variant_builder_add_value (builder, item);
470                 item = g_variant_new_string (arg_error->message);
471                 g_variant_builder_add_value (builder, item);
472                 g_free (dbus_error_name);
473
474                 /* fake value for easier processing in e_gdbus_proxy_emit_signal() */
475                 fake_strv = NULL;
476                 item = g_variant_new_strv (&fake_strv, -1);
477                 g_variant_builder_add_value (builder, item);
478         } else {
479                 item = g_variant_new_string ("");
480                 g_variant_builder_add_value (builder, item);
481                 item = g_variant_new_string ("");
482                 g_variant_builder_add_value (builder, item);
483
484                 param_values++;
485                 arg_strv = g_value_get_boxed (param_values);
486                 item = g_variant_new_strv (arg_strv, -1);
487                 g_variant_builder_add_value (builder, item);
488                 param_values++;
489         }
490         params = g_variant_builder_end (builder);
491         g_variant_builder_unref (builder);
492
493         g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
494
495         return TRUE;
496 }
497
498 gboolean
499 e_gdbus_signal_emission_hook_async_uint (GSignalInvocationHint *ihint,
500                                          guint n_param_values,
501                                          const GValue *param_values,
502                                          const gchar *signal_name,
503                                          const gchar *iface_name)
504 {
505         GObject *object;
506         GDBusConnection *connection;
507         const gchar *path;
508         GVariant *params;
509         GVariant *item;
510         GVariantBuilder *builder;
511         GError *arg_error;
512
513         if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
514                 return FALSE;
515
516         object = g_value_get_object (&param_values[0]);
517         path = g_object_get_data (object, "gdbus-codegen-path");
518         connection = g_object_get_data (object, "gdbus-codegen-connection");
519         if (connection == NULL || path == NULL)
520                 return FALSE;
521
522         builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
523         g_assert_cmpint (n_param_values - 1, ==, 3);
524         param_values++;
525         item = g_variant_new_uint32 (g_value_get_uint (param_values));
526         g_variant_builder_add_value (builder, item);
527         param_values++;
528         arg_error = g_value_get_boxed (param_values);
529         if (arg_error) {
530                 gchar *dbus_error_name = g_dbus_error_encode_gerror (arg_error);
531                 item = g_variant_new_string (dbus_error_name ? dbus_error_name : "");
532                 g_variant_builder_add_value (builder, item);
533                 item = g_variant_new_string (arg_error->message);
534                 g_variant_builder_add_value (builder, item);
535                 g_free (dbus_error_name);
536
537                 /* fake value for easier processing in e_gdbus_proxy_emit_signal() */
538                 item = g_variant_new_uint32 (g_value_get_uint (0));
539                 g_variant_builder_add_value (builder, item);
540         } else {
541                 item = g_variant_new_string ("");
542                 g_variant_builder_add_value (builder, item);
543                 item = g_variant_new_string ("");
544                 g_variant_builder_add_value (builder, item);
545
546                 param_values++;
547                 item = g_variant_new_uint32 (g_value_get_uint (param_values));
548                 g_variant_builder_add_value (builder, item);
549                 param_values++;
550         }
551         params = g_variant_builder_end (builder);
552         g_variant_builder_unref (builder);
553
554         g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
555
556         return TRUE;
557 }
558
559 void
560 e_gdbus_proxy_emit_signal (GDBusProxy *proxy,
561                            GVariant *parameters,
562                            guint signal_id,
563                            guint signal_type)
564 {
565         gboolean arg_boolean = FALSE;
566         const gchar *arg_const_string = NULL;
567         const gchar **arg_const_strv = NULL;
568         guint arg_uint = 0;
569
570         g_return_if_fail (proxy != NULL);
571
572         if ((signal_type & E_GDBUS_TYPE_IS_ASYNC) != 0) {
573                 /* the signal is a done signal, thus opid and error name with error message are first two parameters */
574                 guint arg_opid = 0;
575                 const gchar *dbus_error_name = NULL, *dbus_error_message = NULL;
576                 GError *arg_error = NULL;
577
578                 signal_type = signal_type & (~E_GDBUS_TYPE_IS_ASYNC);
579                 switch (signal_type) {
580                 case E_GDBUS_TYPE_VOID:
581                         g_variant_get (parameters, "(u&s&s)", &arg_opid, &dbus_error_name, &dbus_error_message);
582                         break;
583                 case E_GDBUS_TYPE_BOOLEAN:
584                         g_variant_get (parameters, "(u&s&sb)", &arg_opid, &dbus_error_name, &dbus_error_message, &arg_boolean);
585                         break;
586                 case E_GDBUS_TYPE_STRING:
587                         g_variant_get (parameters, "(u&s&s&s)", &arg_opid, &dbus_error_name, &dbus_error_message, &arg_const_string);
588                         break;
589                 case E_GDBUS_TYPE_STRV:
590                         /* array is newly allocated, but items are gvariant's */
591                         g_variant_get (parameters, "(u&s&s^a&s)", &arg_opid, &dbus_error_name, &dbus_error_message, &arg_const_strv);
592                         break;
593                 case E_GDBUS_TYPE_UINT:
594                         g_variant_get (parameters, "(u&s&su)", &arg_opid, &dbus_error_name, &dbus_error_message, &arg_uint);
595                         break;
596                 default:
597                         /* fix below too, if this is reached */
598                         g_warning ("%s: Unknown E_GDBUS_TYPE %x", G_STRFUNC, signal_type);
599                         return;
600                 }
601
602                 if (dbus_error_name && *dbus_error_name && dbus_error_message)
603                         arg_error = g_dbus_error_new_for_dbus_error (dbus_error_name, dbus_error_message);
604
605                 switch (signal_type) {
606                 case E_GDBUS_TYPE_VOID:
607                         g_signal_emit (proxy, signal_id, 0, arg_opid, arg_error);
608                         break;
609                 case E_GDBUS_TYPE_BOOLEAN:
610                         g_signal_emit (proxy, signal_id, 0, arg_opid, arg_error, arg_boolean);
611                         break;
612                 case E_GDBUS_TYPE_STRING:
613                         g_signal_emit (proxy, signal_id, 0, arg_opid, arg_error, arg_const_string);
614                         break;
615                 case E_GDBUS_TYPE_STRV:
616                         g_signal_emit (proxy, signal_id, 0, arg_opid, arg_error, arg_const_strv);
617                         g_free (arg_const_strv);
618                         break;
619                 case E_GDBUS_TYPE_UINT:
620                         g_signal_emit (proxy, signal_id, 0, arg_opid, arg_error, arg_uint);
621                         break;
622                 }
623
624                 if (arg_error)
625                         g_error_free (arg_error);
626         } else {
627                 switch (signal_type) {
628                 case E_GDBUS_TYPE_VOID:
629                         g_signal_emit (proxy, signal_id, 0);
630                         break;
631                 case E_GDBUS_TYPE_BOOLEAN:
632                         g_variant_get (parameters, "(b)", &arg_boolean);
633                         g_signal_emit (proxy, signal_id, 0, arg_boolean);
634                         break;
635                 case E_GDBUS_TYPE_STRING:
636                         g_variant_get (parameters, "(&s)", &arg_const_string);
637                         g_signal_emit (proxy, signal_id, 0, arg_const_string);
638                         break;
639                 case E_GDBUS_TYPE_STRV:
640                         /* array is newly allocated, but items are gvariant's */
641                         g_variant_get (parameters, "(^a&s)", &arg_const_strv);
642                         g_signal_emit (proxy, signal_id, 0, arg_const_strv);
643                         g_free (arg_const_strv);
644                         break;
645                 case E_GDBUS_TYPE_UINT:
646                         g_variant_get (parameters, "(u)", &arg_uint);
647                         g_signal_emit (proxy, signal_id, 0, arg_uint);
648                         break;
649                 case E_GDBUS_TYPE_UINT | E_GDBUS_TYPE_STRING:
650                         g_variant_get (parameters, "(u&s)", &arg_uint, &arg_const_string);
651                         g_signal_emit (proxy, signal_id, 0, arg_uint, arg_const_string);
652                         break;
653                 default:
654                         g_warning ("%s: Unknown E_GDBUS_TYPE %x", G_STRFUNC, signal_type);
655                         break;
656                 }
657         }
658 }
659
660 void
661 e_gdbus_stub_handle_method_call (GObject *stub_object,
662                                  GDBusMethodInvocation *invocation,
663                                  GVariant *parameters,
664                                  const gchar *method_name,
665                                  guint method_id,
666                                  guint method_type)
667 {
668         gboolean handled = FALSE;
669         gboolean arg_boolean = FALSE;
670         const gchar *arg_const_string = NULL;
671         const gchar ** arg_const_strv = NULL;
672         guint arg_uint = 0;
673
674         g_return_if_fail (stub_object != NULL);
675         g_return_if_fail (method_name != NULL);
676
677         switch (method_type & (~E_GDBUS_TYPE_IS_ASYNC)) {
678         case E_GDBUS_TYPE_VOID:
679                 g_signal_emit (stub_object, method_id, 0, invocation, &handled);
680                 break;
681         case E_GDBUS_TYPE_BOOLEAN:
682                 g_variant_get (parameters, "(b)", &arg_boolean);
683                 g_signal_emit (stub_object, method_id, 0, invocation, arg_boolean, &handled);
684                 break;
685         case E_GDBUS_TYPE_STRING:
686                 g_variant_get (parameters, "(&s)", &arg_const_string);
687                 g_signal_emit (stub_object, method_id, 0, invocation, arg_const_string, &handled);
688                 break;
689         case E_GDBUS_TYPE_STRV:
690                 /* array is newly allocated, but items are gvariant's */
691                 g_variant_get (parameters, "(^a&s)", &arg_const_strv);
692                 g_signal_emit (stub_object, method_id, 0, invocation, arg_const_strv, &handled);
693                 g_free (arg_const_strv);
694                 break;
695         case E_GDBUS_TYPE_UINT:
696                 g_variant_get (parameters, "(u)", &arg_uint);
697                 g_signal_emit (stub_object, method_id, 0, invocation, arg_uint, &handled);
698                 break;
699         default:
700                 g_warning ("%s: Unknown E_GDBUS_TYPE %x", G_STRFUNC, method_type);
701                 break;
702         }
703
704         if (!handled)
705               g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "Method `%s' is not implemented", method_name);
706 }
707
708 G_DEFINE_INTERFACE (EGdbusAsyncOpKeeper, e_gdbus_async_op_keeper, G_TYPE_OBJECT)
709
710 static void
711 e_gdbus_async_op_keeper_default_init (EGdbusAsyncOpKeeperInterface *iface)
712 {
713 }
714
715 /**
716  * e_gdbus_async_op_keeper_create_pending_ops:
717  * @object: a #EGdbusAsyncOpKeeper
718  *
719  * Create a hash table of pending async operations. This can be freed
720  * with g_hash_table_unref() in dispose. The interface asks for this
721  * pointer by calling e_gdbus_async_op_keeper_create_pending_ops().
722  *
723  * Returns: (transfer full) (element-type gpointer gpointer): hash table of
724  * pending async operations; free with g_hash_table_unref()
725  */
726 GHashTable *
727 e_gdbus_async_op_keeper_create_pending_ops (EGdbusAsyncOpKeeper *object)
728 {
729         g_return_val_if_fail (object != NULL, NULL);
730         g_return_val_if_fail (E_IS_GDBUS_ASYNC_OP_KEEPER (object), NULL);
731
732         return g_hash_table_new (g_direct_hash, g_direct_equal);
733 }
734
735 /**
736  * e_gdbus_async_op_keeper_get_pending_ops:
737  * @object: a #EGdbusAsyncOpKeeper
738  *
739  * Get the hash table of pending async operations previously created
740  * by e_gdbus_async_op_keeper_create_pending_ops().
741  *
742  * Returns: (transfer none): hash table of pending async operations
743  */
744 GHashTable *
745 e_gdbus_async_op_keeper_get_pending_ops (EGdbusAsyncOpKeeper *object)
746 {
747         EGdbusAsyncOpKeeperInterface *iface;
748
749         g_return_val_if_fail (E_IS_GDBUS_ASYNC_OP_KEEPER (object), NULL);
750
751         iface = E_GDBUS_ASYNC_OP_KEEPER_GET_IFACE (object);
752         g_return_val_if_fail (iface->get_pending_ops != NULL, NULL);
753
754         return iface->get_pending_ops (object);
755 }
756
757 /* synchronously cancels one operation - sends a request from client to the server */
758 gboolean
759 e_gdbus_async_op_keeper_cancel_op_sync (EGdbusAsyncOpKeeper *object,
760                                         guint in_opid,
761                                         GCancellable *cancellable,
762                                         GError **error)
763 {
764         EGdbusAsyncOpKeeperInterface *iface;
765
766         g_return_val_if_fail (E_IS_GDBUS_ASYNC_OP_KEEPER (object), FALSE);
767
768         iface = E_GDBUS_ASYNC_OP_KEEPER_GET_IFACE (object);
769         g_return_val_if_fail (iface->cancel_op_sync != NULL, FALSE);
770
771         return iface->cancel_op_sync (object, in_opid, cancellable, error);
772 }
773
774 /* Used to finish asynchronous GDBus call - this might be done in the callback
775  * as soon as possible; method returns to a caller operation ID which was started */
776 void
777 e_gdbus_complete_async_method (gpointer object,
778                                GDBusMethodInvocation *invocation,
779                                guint opid)
780 {
781         g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", opid));
782 }
783
784 /* Used to finish synchronous GDBus call - this might be done in the callback
785  * as soon as possible */
786 void
787 e_gdbus_complete_sync_method_void (gpointer object,
788                                    GDBusMethodInvocation *invocation,
789                                    const GError *error)
790 {
791         if (error)
792                 g_dbus_method_invocation_return_gerror (invocation, error);
793         else
794                 g_dbus_method_invocation_return_value (invocation, NULL);
795 }
796
797 void
798 e_gdbus_complete_sync_method_boolean (gpointer object,
799                                       GDBusMethodInvocation *invocation,
800                                       gboolean out_boolean,
801                                       const GError *error)
802 {
803         if (error)
804                 g_dbus_method_invocation_return_gerror (invocation, error);
805         else
806                 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", out_boolean));
807 }
808
809 void
810 e_gdbus_complete_sync_method_string (gpointer object,
811                                      GDBusMethodInvocation *invocation,
812                                      const gchar *out_string,
813                                      const GError *error)
814 {
815         if (error)
816                 g_dbus_method_invocation_return_gerror (invocation, error);
817         else
818                 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", out_string));
819 }
820
821 void
822 e_gdbus_complete_sync_method_strv (gpointer object,
823                                    GDBusMethodInvocation *invocation,
824                                    const gchar * const *out_strv,
825                                    const GError *error)
826 {
827         if (error)
828                 g_dbus_method_invocation_return_gerror (invocation, error);
829         else
830                 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(^as)", out_strv));
831 }
832
833 void
834 e_gdbus_complete_sync_method_uint (gpointer object,
835                                    GDBusMethodInvocation *invocation,
836                                    guint out_uint,
837                                    const GError *error)
838 {
839         if (error)
840                 g_dbus_method_invocation_return_gerror (invocation, error);
841         else
842                 g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", out_uint));
843 }
844
845 typedef struct _AsyncOpData
846 {
847         gint ref_count;
848         EGdbusAsyncOpKeeper *proxy;
849         guint opid;
850
851         GCancellable *cancellable;
852         gulong cancel_id;
853         guint cancel_idle_id;
854
855         gpointer async_source_tag;
856         GAsyncReadyCallback async_callback;
857         gpointer async_user_data;
858
859         guint result_type; /* any of E_GDBUS_TYPE_... except of E_GDBUS_TYPE_IS_ASYNC */
860         union {
861                 gboolean out_boolean;
862                 gchar *out_string;
863                 gchar ** out_strv;
864                 guint out_uint;
865         } result;
866 } AsyncOpData;
867
868 static void
869 async_op_data_free (AsyncOpData *op_data)
870 {
871         GHashTable *pending_ops;
872
873         g_return_if_fail (op_data != NULL);
874
875         pending_ops = e_gdbus_async_op_keeper_get_pending_ops (op_data->proxy);
876
877         if (op_data->cancel_idle_id) {
878                 GError *error = NULL;
879
880                 g_source_remove (op_data->cancel_idle_id);
881                 op_data->cancel_idle_id = 0;
882
883                 if (pending_ops)
884                         g_hash_table_remove (pending_ops, GUINT_TO_POINTER (op_data->opid));
885
886                 if (!e_gdbus_async_op_keeper_cancel_op_sync (op_data->proxy, op_data->opid, NULL, &error)) {
887                         g_debug ("%s: Failed to cancel operation: %s\n", G_STRFUNC, error ? error->message : "Unknown error");
888                         g_clear_error (&error);
889                 }
890         } else if (pending_ops) {
891                 g_hash_table_remove (pending_ops, GUINT_TO_POINTER (op_data->opid));
892         }
893
894         if (op_data->cancellable) {
895                 if (op_data->cancel_id) {
896                         g_cancellable_disconnect (op_data->cancellable, op_data->cancel_id);
897                         op_data->cancel_id = 0;
898                 }
899                 g_object_unref (op_data->cancellable);
900                 op_data->cancellable = NULL;
901         }
902
903         if (!g_atomic_int_dec_and_test (&op_data->ref_count))
904                 return;
905
906         g_object_unref (op_data->proxy);
907
908         switch (op_data->result_type) {
909         case E_GDBUS_TYPE_STRING:
910                 if (op_data->result.out_string)
911                         g_free (op_data->result.out_string);
912                 break;
913         case E_GDBUS_TYPE_STRV:
914                 if (op_data->result.out_strv)
915                         g_strfreev (op_data->result.out_strv);
916                 break;
917         }
918
919         g_free (op_data);
920
921         g_return_if_fail (pending_ops != NULL);
922 }
923
924 static void
925 async_op_complete (AsyncOpData *op_data,
926                    const GError *error,
927                    gboolean in_idle)
928 {
929         GSimpleAsyncResult *simple;
930
931         g_return_if_fail (op_data != NULL);
932
933         g_atomic_int_inc (&op_data->ref_count);
934         simple = g_simple_async_result_new (G_OBJECT (op_data->proxy), op_data->async_callback, op_data->async_user_data, op_data->async_source_tag);
935         g_simple_async_result_set_op_res_gpointer (simple, op_data, (GDestroyNotify) async_op_data_free);
936         if (error)
937                 g_simple_async_result_set_from_error (simple, error);
938
939         if (in_idle)
940                 g_simple_async_result_complete_in_idle (simple);
941         else
942                 g_simple_async_result_complete (simple);
943
944         g_object_unref (simple);
945 }
946
947 typedef struct _CancelData
948 {
949         EGdbusAsyncOpKeeper *proxy;
950         guint opid;
951         AsyncOpData *op_data;
952 } CancelData;
953
954 static void
955 cancel_data_free (gpointer ptr)
956 {
957         CancelData *cd = ptr;
958
959         if (!cd)
960                 return;
961
962         g_object_unref (cd->proxy);
963         g_free (cd);
964 }
965
966 static gboolean
967 e_gdbus_op_cancelled_idle_cb (gpointer user_data)
968 {
969         CancelData *cd = user_data;
970         AsyncOpData *op_data;
971         GHashTable *pending_ops;
972         GCancellable *cancellable;
973         GError *error = NULL;
974
975         g_return_val_if_fail (cd != NULL, FALSE);
976
977         pending_ops = e_gdbus_async_op_keeper_get_pending_ops (cd->proxy);
978         if (pending_ops && !g_hash_table_lookup (pending_ops, GUINT_TO_POINTER (cd->opid))) {
979                 /* got served already */
980                 return FALSE;
981         }
982
983         op_data = cd->op_data;
984         g_return_val_if_fail (op_data != NULL, FALSE);
985
986         cancellable = op_data->cancellable;
987         op_data->cancel_idle_id = 0;
988
989         if (!e_gdbus_async_op_keeper_cancel_op_sync (op_data->proxy, op_data->opid, NULL, &error)) {
990                 g_debug ("%s: Failed to cancel operation: %s\n", G_STRFUNC, error ? error->message : "Unknown error");
991                 g_clear_error (&error);
992         }
993
994         g_return_val_if_fail (g_cancellable_set_error_if_cancelled (cancellable, &error), FALSE);
995
996         async_op_complete (op_data, error, TRUE);
997         g_clear_error (&error);
998
999         return FALSE;
1000 }
1001
1002 static void
1003 e_gdbus_op_cancelled_cb (GCancellable *cancellable,
1004                          AsyncOpData *op_data)
1005 {
1006         CancelData *cd;
1007
1008         g_return_if_fail (op_data != NULL);
1009         g_return_if_fail (op_data->cancellable == cancellable);
1010
1011         cd = g_new0 (CancelData, 1);
1012         cd->proxy = g_object_ref (op_data->proxy);
1013         cd->opid = op_data->opid;
1014         cd->op_data = op_data;
1015
1016         /* do this on idle, because this callback should be left
1017          * as soon as possible, with no sync calls being done;
1018          * also schedule with priority higher than gtk+ uses
1019          * for animations (check docs for G_PRIORITY_HIGH_IDLE) */
1020         op_data->cancel_idle_id = g_idle_add_full (G_PRIORITY_DEFAULT, e_gdbus_op_cancelled_idle_cb, cd, cancel_data_free);
1021 }
1022
1023 static void
1024 e_gdbus_async_call_opid_ready_cb (GObject *source_proxy,
1025                                   GAsyncResult *result,
1026                                   gpointer user_data)
1027 {
1028         GVariant *_result;
1029         GError *error = NULL;
1030         AsyncOpData *op_data = user_data;
1031
1032         _result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_proxy), result, &error);
1033
1034         if (_result != NULL && !error) {
1035                 EGdbusAsyncOpKeeper *op_keeper = E_GDBUS_ASYNC_OP_KEEPER (source_proxy);
1036                 GHashTable *pending_ops;
1037                 gboolean add_pending = TRUE;
1038
1039                 g_return_if_fail (op_keeper != NULL);
1040
1041                 pending_ops = e_gdbus_async_op_keeper_get_pending_ops (op_keeper);
1042                 g_return_if_fail (pending_ops != NULL);
1043
1044                 g_variant_get (_result, "(u)", &op_data->opid);
1045                 g_variant_unref (_result);
1046
1047                 if (op_data->cancellable && !g_cancellable_set_error_if_cancelled (op_data->cancellable, &error))
1048                         op_data->cancel_id = g_cancellable_connect (op_data->cancellable, G_CALLBACK (e_gdbus_op_cancelled_cb), op_data, NULL);
1049                 else
1050                         add_pending = op_data->cancellable == NULL;
1051
1052                 /* add to pending ops, waiting for associated 'done' signal */
1053                 if (add_pending)
1054                         g_hash_table_insert (pending_ops, GUINT_TO_POINTER (op_data->opid), op_data);
1055         } else if (_result) {
1056                 g_variant_unref (_result);
1057         }
1058
1059         if (error) {
1060                 async_op_complete (op_data, error, FALSE);
1061                 g_error_free (error);
1062         }
1063 }
1064
1065 static gchar **
1066 copy_strv (const gchar * const *strv)
1067 {
1068         GPtrArray *array;
1069         gint ii;
1070
1071         array = g_ptr_array_sized_new (g_strv_length ((gchar **) strv) + 1);
1072
1073         for (ii = 0; strv[ii]; ii++) {
1074                 g_ptr_array_add (array, g_strdup (strv[ii]));
1075         }
1076
1077         /* NULL-terminated */
1078         g_ptr_array_add (array, NULL);
1079
1080         return (gchar **) g_ptr_array_free (array, FALSE);
1081 }
1082
1083 static void
1084 e_gdbus_proxy_async_method_done (guint e_gdbus_type,
1085                                  gconstpointer out_value,
1086                                  EGdbusAsyncOpKeeper *object,
1087                                  guint arg_opid,
1088                                  const GError *error)
1089 {
1090         AsyncOpData *op_data;
1091         GHashTable *pending_ops;
1092
1093         g_return_if_fail (object != NULL);
1094         g_return_if_fail (E_IS_GDBUS_ASYNC_OP_KEEPER (object));
1095
1096         pending_ops = e_gdbus_async_op_keeper_get_pending_ops (object);
1097         g_return_if_fail (pending_ops != NULL);
1098
1099         op_data = g_hash_table_lookup (pending_ops, GUINT_TO_POINTER (arg_opid));
1100         if (!op_data) {
1101                 /* it happens for cancelled operations, thus rather than track cancelled ops disable the debug warning */
1102                 /* g_debug ("%s: Operation %d gone before got done signal for it", G_STRFUNC, arg_opid); */
1103                 return;
1104         }
1105
1106         if (out_value) {
1107                 op_data->result_type = e_gdbus_type;
1108
1109                 switch (e_gdbus_type) {
1110                 case E_GDBUS_TYPE_VOID:
1111                         break;
1112                 case E_GDBUS_TYPE_BOOLEAN:
1113                         op_data->result.out_boolean = * ((const gboolean *) out_value);
1114                         break;
1115                 case E_GDBUS_TYPE_STRING:
1116                         op_data->result.out_string = g_strdup ((const gchar *) out_value);
1117                         break;
1118                 case E_GDBUS_TYPE_STRV:
1119                         op_data->result.out_strv = copy_strv ((const gchar * const *) out_value);
1120                         break;
1121                 case E_GDBUS_TYPE_UINT:
1122                         op_data->result.out_uint = * ((const guint *) out_value);
1123                         break;
1124                 default:
1125                         g_warning ("%s: Unknown E_GDBUS_TYPE %x", G_STRFUNC, e_gdbus_type);
1126                         break;
1127                 }
1128         }
1129
1130         async_op_complete (op_data, error, TRUE);
1131 }
1132
1133 void
1134 e_gdbus_proxy_async_method_done_void (EGdbusAsyncOpKeeper *proxy,
1135                                       guint arg_opid,
1136                                       const GError *error)
1137 {
1138         e_gdbus_proxy_async_method_done (E_GDBUS_TYPE_VOID, NULL, proxy, arg_opid, error);
1139 }
1140
1141 void
1142 e_gdbus_proxy_async_method_done_boolean (EGdbusAsyncOpKeeper *proxy,
1143                                          guint arg_opid,
1144                                          const GError *error,
1145                                          gboolean out_boolean)
1146 {
1147         e_gdbus_proxy_async_method_done (E_GDBUS_TYPE_BOOLEAN, &out_boolean, proxy, arg_opid, error);
1148 }
1149
1150 /* takes ownership of the out parameter */
1151 void
1152 e_gdbus_proxy_async_method_done_string (EGdbusAsyncOpKeeper *proxy,
1153                                         guint arg_opid,
1154                                         const GError *error,
1155                                         const gchar *out_string)
1156 {
1157         e_gdbus_proxy_async_method_done (E_GDBUS_TYPE_STRING, out_string, proxy, arg_opid, error);
1158 }
1159
1160 /* takes ownership of the out parameter */
1161 void
1162 e_gdbus_proxy_async_method_done_strv (EGdbusAsyncOpKeeper *proxy,
1163                                       guint arg_opid,
1164                                       const GError *error,
1165                                       const gchar * const *out_strv)
1166 {
1167         e_gdbus_proxy_async_method_done (E_GDBUS_TYPE_STRV, out_strv, proxy, arg_opid, error);
1168 }
1169
1170 void
1171 e_gdbus_proxy_async_method_done_uint (EGdbusAsyncOpKeeper *proxy,
1172                                       guint arg_opid,
1173                                       const GError *error,
1174                                       guint out_uint)
1175 {
1176         e_gdbus_proxy_async_method_done (E_GDBUS_TYPE_UINT, &out_uint, proxy, arg_opid, error);
1177 }
1178
1179 /* takes ownership of _params */
1180 static void
1181 e_gdbus_proxy_call_with_params (GVariant *_params,
1182                                 const gchar *method_name,
1183                                 gpointer source_tag,
1184                                 EGdbusAsyncOpKeeper *proxy,
1185                                 GCancellable *cancellable,
1186                                 GAsyncReadyCallback callback,
1187                                 gpointer user_data)
1188 {
1189         AsyncOpData *op_data;
1190
1191         op_data = g_new0 (AsyncOpData, 1);
1192         op_data->proxy = g_object_ref (proxy);
1193         op_data->opid = 0;
1194         op_data->async_source_tag = source_tag;
1195         op_data->async_callback = callback;
1196         op_data->async_user_data = user_data;
1197         op_data->cancellable = cancellable;
1198         if (op_data->cancellable)
1199                 g_object_ref (op_data->cancellable);
1200
1201         g_dbus_proxy_call (G_DBUS_PROXY (proxy), method_name, _params, G_DBUS_CALL_FLAGS_NONE, e_data_server_util_get_dbus_call_timeout (), cancellable, e_gdbus_async_call_opid_ready_cb, op_data);
1202 }
1203
1204 void
1205 e_gdbus_proxy_call_void (const gchar *method_name,
1206                          gpointer source_tag,
1207                          EGdbusAsyncOpKeeper *proxy,
1208                          GCancellable *cancellable,
1209                          GAsyncReadyCallback callback,
1210                          gpointer user_data)
1211 {
1212         e_gdbus_proxy_call_with_params (NULL, method_name, source_tag, proxy, cancellable, callback, user_data);
1213 }
1214
1215 void
1216 e_gdbus_proxy_call_boolean (const gchar *method_name,
1217                             gpointer source_tag,
1218                             EGdbusAsyncOpKeeper *proxy,
1219                             gboolean in_boolean,
1220                             GCancellable *cancellable,
1221                             GAsyncReadyCallback callback,
1222                             gpointer user_data)
1223 {
1224         GVariant *_params;
1225
1226         _params = g_variant_new ("(b)", in_boolean);
1227
1228         e_gdbus_proxy_call_with_params (_params, method_name, source_tag, proxy, cancellable, callback, user_data);
1229 }
1230
1231 void
1232 e_gdbus_proxy_call_string (const gchar *method_name,
1233                            gpointer source_tag,
1234                            EGdbusAsyncOpKeeper *proxy,
1235                            const gchar *in_string,
1236                            GCancellable *cancellable,
1237                            GAsyncReadyCallback callback,
1238                            gpointer user_data)
1239 {
1240         GVariant *_params;
1241
1242         _params = g_variant_new ("(s)", in_string);
1243
1244         e_gdbus_proxy_call_with_params (_params, method_name, source_tag, proxy, cancellable, callback, user_data);
1245 }
1246
1247 void
1248 e_gdbus_proxy_call_strv (const gchar *method_name,
1249                          gpointer source_tag,
1250                          EGdbusAsyncOpKeeper *proxy,
1251                          const gchar * const *in_strv,
1252                          GCancellable *cancellable,
1253                          GAsyncReadyCallback callback,
1254                          gpointer user_data)
1255 {
1256         GVariant *_params;
1257
1258         _params = g_variant_new ("(^as)", in_strv);
1259
1260         e_gdbus_proxy_call_with_params (_params, method_name, source_tag, proxy, cancellable, callback, user_data);
1261 }
1262
1263 void
1264 e_gdbus_proxy_call_uint (const gchar *method_name,
1265                          gpointer source_tag,
1266                          EGdbusAsyncOpKeeper *proxy,
1267                          guint in_uint,
1268                          GCancellable *cancellable,
1269                          GAsyncReadyCallback callback,
1270                          gpointer user_data)
1271 {
1272         GVariant *_params;
1273
1274         _params = g_variant_new ("(u)", in_uint);
1275
1276         e_gdbus_proxy_call_with_params (_params, method_name, source_tag, proxy, cancellable, callback, user_data);
1277 }
1278
1279 gboolean
1280 e_gdbus_proxy_finish_call_void (EGdbusAsyncOpKeeper *proxy,
1281                                 GAsyncResult *result,
1282                                 GError **error,
1283                                 gpointer source_tag)
1284 {
1285         g_return_val_if_fail (proxy != NULL, FALSE);
1286         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (proxy), source_tag), FALSE);
1287
1288         return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
1289 }
1290
1291 gboolean
1292 e_gdbus_proxy_finish_call_boolean (EGdbusAsyncOpKeeper *proxy,
1293                                    GAsyncResult *result,
1294                                    gboolean *out_boolean,
1295                                    GError **error,
1296                                    gpointer source_tag)
1297 {
1298         AsyncOpData *op_data;
1299
1300         g_return_val_if_fail (proxy != NULL, FALSE);
1301         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (proxy), source_tag), FALSE);
1302         g_return_val_if_fail (out_boolean != NULL, FALSE);
1303
1304         if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1305                 return FALSE;
1306
1307         op_data = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
1308         g_return_val_if_fail (op_data != NULL, FALSE);
1309         g_return_val_if_fail (op_data->result_type == E_GDBUS_TYPE_BOOLEAN, FALSE);
1310
1311         *out_boolean = op_data->result.out_boolean;
1312
1313         return TRUE;
1314 }
1315
1316 /* caller takes ownership and responsibility for freeing the out parameter */
1317 gboolean
1318 e_gdbus_proxy_finish_call_string (EGdbusAsyncOpKeeper *proxy,
1319                                   GAsyncResult *result,
1320                                   gchar **out_string,
1321                                   GError **error,
1322                                   gpointer source_tag)
1323 {
1324         AsyncOpData *op_data;
1325
1326         g_return_val_if_fail (proxy != NULL, FALSE);
1327         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (proxy), source_tag), FALSE);
1328         g_return_val_if_fail (out_string != NULL, FALSE);
1329
1330         if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1331                 return FALSE;
1332
1333         op_data = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
1334         g_return_val_if_fail (op_data != NULL, FALSE);
1335         g_return_val_if_fail (op_data->result_type == E_GDBUS_TYPE_STRING, FALSE);
1336
1337         *out_string = op_data->result.out_string;
1338         op_data->result.out_string = NULL;
1339
1340         return TRUE;
1341 }
1342
1343 /* caller takes ownership and responsibility for freeing the out parameter */
1344 gboolean
1345 e_gdbus_proxy_finish_call_strv (EGdbusAsyncOpKeeper *proxy,
1346                                 GAsyncResult *result,
1347                                 gchar ***out_strv,
1348                                 GError **error,
1349                                 gpointer source_tag)
1350 {
1351         AsyncOpData *op_data;
1352
1353         g_return_val_if_fail (proxy != NULL, FALSE);
1354         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (proxy), source_tag), FALSE);
1355         g_return_val_if_fail (out_strv != NULL, FALSE);
1356
1357         if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1358                 return FALSE;
1359
1360         op_data = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
1361         g_return_val_if_fail (op_data != NULL, FALSE);
1362         g_return_val_if_fail (op_data->result_type == E_GDBUS_TYPE_STRV, FALSE);
1363
1364         *out_strv = op_data->result.out_strv;
1365         op_data->result.out_strv = NULL;
1366
1367         return TRUE;
1368 }
1369
1370 gboolean
1371 e_gdbus_proxy_finish_call_uint (EGdbusAsyncOpKeeper *proxy,
1372                                 GAsyncResult *result,
1373                                 guint *out_uint,
1374                                 GError **error,
1375                                 gpointer source_tag)
1376 {
1377         AsyncOpData *op_data;
1378
1379         g_return_val_if_fail (proxy != NULL, FALSE);
1380         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (proxy), source_tag), FALSE);
1381         g_return_val_if_fail (out_uint != NULL, FALSE);
1382
1383         if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
1384                 return FALSE;
1385
1386         op_data = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
1387         g_return_val_if_fail (op_data != NULL, FALSE);
1388         g_return_val_if_fail (op_data->result_type == E_GDBUS_TYPE_UINT, FALSE);
1389
1390         *out_uint = op_data->result.out_uint;
1391
1392         return TRUE;
1393 }
1394
1395 typedef struct _SyncOpData
1396 {
1397         EFlag *flag;
1398         GError **error;
1399
1400         guint out_type; /* one of E_GDBUS_TYPE_... except of E_GDBUS_TYPE_IS_ASYNC */
1401         union {
1402                 gboolean *out_boolean;
1403                 gchar **out_string;
1404                 gchar ***out_strv;
1405                 guint *out_uint;
1406         } out_arg;
1407
1408         union {
1409                 EGdbusCallFinishVoid finish_void;
1410                 EGdbusCallFinishBoolean finish_boolean;
1411                 EGdbusCallFinishString finish_string;
1412                 EGdbusCallFinishStrv finish_strv;
1413                 EGdbusCallFinishUint finish_uint;
1414         } finish_func;
1415
1416         gboolean finish_result;
1417 } SyncOpData;
1418
1419 static void
1420 e_gdbus_proxy_sync_ready_cb (GObject *proxy,
1421                              GAsyncResult *result,
1422                              gpointer user_data)
1423 {
1424         gint sync_opid = GPOINTER_TO_INT (user_data);
1425         gchar *sync_opid_ident;
1426         SyncOpData *sync_data;
1427
1428         sync_opid_ident = g_strdup_printf ("EGdbusTemplates-SyncOp-%d", sync_opid);
1429         sync_data = g_object_get_data (proxy, sync_opid_ident);
1430         g_free (sync_opid_ident);
1431
1432         if (!sync_data) {
1433                 /* already finished operation; it can happen when the operation is cancelled,
1434                  * but the result is already waiting in an idle queue.
1435                 */
1436                 return;
1437         }
1438
1439         g_return_if_fail (sync_data->flag != NULL);
1440
1441         switch (sync_data->out_type) {
1442         case E_GDBUS_TYPE_VOID:
1443                 g_return_if_fail (sync_data->finish_func.finish_void != NULL);
1444                 sync_data->finish_result = sync_data->finish_func.finish_void (G_DBUS_PROXY (proxy), result, sync_data->error);
1445                 break;
1446         case E_GDBUS_TYPE_BOOLEAN:
1447                 g_return_if_fail (sync_data->finish_func.finish_boolean != NULL);
1448                 sync_data->finish_result = sync_data->finish_func.finish_boolean (G_DBUS_PROXY (proxy), result, sync_data->out_arg.out_boolean, sync_data->error);
1449                 break;
1450         case E_GDBUS_TYPE_STRING:
1451                 g_return_if_fail (sync_data->finish_func.finish_string != NULL);
1452                 sync_data->finish_result = sync_data->finish_func.finish_string (G_DBUS_PROXY (proxy), result, sync_data->out_arg.out_string, sync_data->error);
1453                 break;
1454         case E_GDBUS_TYPE_STRV:
1455                 g_return_if_fail (sync_data->finish_func.finish_strv != NULL);
1456                 sync_data->finish_result = sync_data->finish_func.finish_strv (G_DBUS_PROXY (proxy), result, sync_data->out_arg.out_strv, sync_data->error);
1457                 break;
1458         case E_GDBUS_TYPE_UINT:
1459                 g_return_if_fail (sync_data->finish_func.finish_uint != NULL);
1460                 sync_data->finish_result = sync_data->finish_func.finish_uint (G_DBUS_PROXY (proxy), result, sync_data->out_arg.out_uint, sync_data->error);
1461                 break;
1462         default:
1463                 g_warning ("%s: Unknown 'out' E_GDBUS_TYPE %x", G_STRFUNC, sync_data->out_type);
1464                 sync_data->finish_result = FALSE;
1465         }
1466
1467         e_flag_set (sync_data->flag);
1468 }
1469
1470 static gboolean
1471 e_gdbus_proxy_call_sync (GDBusProxy *proxy,
1472                          GCancellable *cancellable,
1473                          GError **error,
1474                          gpointer start_func,
1475                          gpointer finish_func,
1476                          guint in_type,
1477                          gconstpointer in_value,
1478                          guint out_type,
1479                          gpointer out_value)
1480 {
1481         static volatile gint sync_op_counter = 0;
1482         gint sync_opid;
1483         gchar *sync_opid_ident;
1484         SyncOpData sync_data = { 0 };
1485
1486         g_return_val_if_fail (proxy != NULL, FALSE);
1487         g_return_val_if_fail (start_func != NULL, FALSE);
1488         g_return_val_if_fail (finish_func != NULL, FALSE);
1489
1490         g_object_ref (proxy);
1491
1492         switch (out_type) {
1493         case E_GDBUS_TYPE_VOID:
1494                 sync_data.finish_func.finish_void = finish_func;
1495                 break;
1496         case E_GDBUS_TYPE_BOOLEAN:
1497                 sync_data.out_arg.out_boolean = out_value;
1498                 sync_data.finish_func.finish_boolean = finish_func;
1499                 break;
1500         case E_GDBUS_TYPE_STRING:
1501                 sync_data.out_arg.out_string = out_value;
1502                 sync_data.finish_func.finish_string = finish_func;
1503                 break;
1504         case E_GDBUS_TYPE_STRV:
1505                 sync_data.out_arg.out_strv = out_value;
1506                 sync_data.finish_func.finish_strv = finish_func;
1507                 break;
1508         case E_GDBUS_TYPE_UINT:
1509                 sync_data.out_arg.out_uint = out_value;
1510                 sync_data.finish_func.finish_uint = finish_func;
1511                 break;
1512         default:
1513                 g_warning ("%s: Unknown 'out' E_GDBUS_TYPE %x", G_STRFUNC, out_type);
1514                 g_object_unref (proxy);
1515                 return FALSE;
1516         }
1517
1518         sync_data.flag = e_flag_new ();
1519         sync_data.error = error;
1520         sync_data.out_type = out_type;
1521
1522         sync_opid = g_atomic_int_add (&sync_op_counter, 1);
1523         sync_opid_ident = g_strdup_printf ("EGdbusTemplates-SyncOp-%d", sync_opid);
1524         g_object_set_data (G_OBJECT (proxy), sync_opid_ident, &sync_data);
1525
1526         switch (in_type) {
1527         case E_GDBUS_TYPE_VOID: {
1528                 EGdbusCallStartVoid start = start_func;
1529                 start (proxy, cancellable, e_gdbus_proxy_sync_ready_cb, GINT_TO_POINTER (sync_opid));
1530         } break;
1531         case E_GDBUS_TYPE_BOOLEAN: {
1532                 EGdbusCallStartBoolean start = start_func;
1533                 start (proxy, * ((gboolean *) in_value), cancellable, e_gdbus_proxy_sync_ready_cb, GINT_TO_POINTER (sync_opid));
1534         } break;
1535         case E_GDBUS_TYPE_STRING: {
1536                 EGdbusCallStartString start = start_func;
1537                 start (proxy, (const gchar *) in_value, cancellable, e_gdbus_proxy_sync_ready_cb, GINT_TO_POINTER (sync_opid));
1538         } break;
1539         case E_GDBUS_TYPE_STRV: {
1540                 EGdbusCallStartStrv start = start_func;
1541                 start (proxy, (const gchar * const *) in_value, cancellable, e_gdbus_proxy_sync_ready_cb, GINT_TO_POINTER (sync_opid));
1542         } break;
1543         case E_GDBUS_TYPE_UINT: {
1544                 EGdbusCallStartUint start = start_func;
1545                 start (proxy, * ((guint *) in_value), cancellable, e_gdbus_proxy_sync_ready_cb, GINT_TO_POINTER (sync_opid));
1546         } break;
1547         default:
1548                 g_warning ("%s: Unknown 'in' E_GDBUS_TYPE %x", G_STRFUNC, in_type);
1549                 e_flag_free (sync_data.flag);
1550                 g_object_set_data (G_OBJECT (proxy), sync_opid_ident, NULL);
1551                 g_free (sync_opid_ident);
1552                 g_object_unref (proxy);
1553                 return FALSE;
1554         }
1555
1556         /* check if called from the main thread */
1557         if ((main_thread && main_thread == g_thread_self ()) ||
1558             (!main_thread && (g_main_context_is_owner (g_main_context_default ())
1559             || g_main_context_default () == g_main_context_get_thread_default ()
1560             || !g_main_context_get_thread_default ()))) {
1561                 /* the call to e_gdbus_templates_init_main_thread() wasn't done, but no problem,
1562                  * check if the call was done in the main thread with main loop running,
1563                  * and if so, then remember it
1564                 */
1565                 if (!main_thread && g_main_context_is_owner (g_main_context_default ()))
1566                         e_gdbus_templates_init_main_thread ();
1567
1568                 /* Might not be the best thing here, but as the async operation
1569                  * is divided into two-step process, invoking the method and
1570                  * waiting for its "done" signal, then if the sync method is called
1571                  * from the main thread, then there is probably no other option.
1572                 */
1573                 while (!e_flag_is_set (sync_data.flag)) {
1574                         g_usleep (1000);
1575                         g_main_context_iteration (NULL, FALSE);
1576                 }
1577         } else {
1578                 /* is called in a dedicated thread */
1579                 e_flag_wait (sync_data.flag);
1580         }
1581         g_object_set_data (G_OBJECT (proxy), sync_opid_ident, NULL);
1582         e_flag_free (sync_data.flag);
1583
1584         g_free (sync_opid_ident);
1585         g_object_unref (proxy);
1586
1587         return sync_data.finish_result;
1588 }
1589
1590 gboolean
1591 e_gdbus_proxy_call_sync_void__void (GDBusProxy *proxy,
1592                                     GCancellable *cancellable,
1593                                     GError **error,
1594                                     EGdbusCallStartVoid start_func,
1595                                     EGdbusCallFinishVoid finish_func)
1596 {
1597         g_return_val_if_fail (proxy != NULL, FALSE);
1598         g_return_val_if_fail (start_func != NULL, FALSE);
1599         g_return_val_if_fail (finish_func != NULL, FALSE);
1600
1601         return e_gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_VOID, NULL, E_GDBUS_TYPE_VOID, NULL);
1602 }
1603
1604 /**
1605  * e_gdbus_proxy_call_sync_void__boolean:
1606  * @proxy:
1607  * @out_boolean:
1608  * @cancellable: (allow-none):
1609  * @error:
1610  * @start_func: (scope call):
1611  * @finish_func: (scope call):
1612  *
1613  * Returns:
1614  */
1615 gboolean
1616 e_gdbus_proxy_call_sync_void__boolean (GDBusProxy *proxy,
1617                                        gboolean *out_boolean,
1618                                        GCancellable *cancellable,
1619                                        GError **error,
1620                                        EGdbusCallStartVoid start_func,
1621                                        EGdbusCallFinishBoolean finish_func)
1622 {
1623         g_return_val_if_fail (proxy != NULL, FALSE);
1624         g_return_val_if_fail (start_func != NULL, FALSE);
1625         g_return_val_if_fail (finish_func != NULL, FALSE);
1626         g_return_val_if_fail (out_boolean != NULL, FALSE);
1627
1628         return e_gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_VOID, NULL, E_GDBUS_TYPE_BOOLEAN, out_boolean);
1629 }
1630
1631 /**
1632  * e_gdbus_proxy_call_sync_void__string:
1633  * @proxy:
1634  * @out_string:
1635  * @cancellable: (allow-none):
1636  * @error:
1637  * @start_func: (scope call):
1638  * @finish_func: (scope call):
1639  *
1640  * Returns:
1641  */
1642 gboolean
1643 e_gdbus_proxy_call_sync_void__string (GDBusProxy *proxy,
1644                                       gchar **out_string,
1645                                       GCancellable *cancellable,
1646                                       GError **error,
1647                                       EGdbusCallStartVoid start_func,
1648                                       EGdbusCallFinishString finish_func)
1649 {
1650         g_return_val_if_fail (proxy != NULL, FALSE);
1651         g_return_val_if_fail (start_func != NULL, FALSE);
1652         g_return_val_if_fail (finish_func != NULL, FALSE);
1653         g_return_val_if_fail (out_string != NULL, FALSE);
1654
1655         return e_gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_VOID, NULL, E_GDBUS_TYPE_STRING, out_string);
1656 }
1657
1658 /**
1659  * e_gdbus_proxy_call_sync_void__strv:
1660  * @proxy:
1661  * @out_strv:
1662  * @cancellable: (allow-none):
1663  * @error:
1664  * @start_func: (scope call):
1665  * @finish_func: (scope call):
1666  *
1667  * Returns:
1668  */
1669 gboolean
1670 e_gdbus_proxy_call_sync_void__strv (GDBusProxy *proxy,
1671                                     gchar ***out_strv,
1672                                     GCancellable *cancellable,
1673                                     GError **error,
1674                                     EGdbusCallStartVoid start_func,
1675                                     EGdbusCallFinishStrv finish_func)
1676 {
1677         g_return_val_if_fail (proxy != NULL, FALSE);
1678         g_return_val_if_fail (start_func != NULL, FALSE);
1679         g_return_val_if_fail (finish_func != NULL, FALSE);
1680         g_return_val_if_fail (out_strv != NULL, FALSE);
1681
1682         return e_gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_VOID, NULL, E_GDBUS_TYPE_STRV, out_strv);
1683 }
1684
1685 /**
1686  * e_gdbus_proxy_call_sync_void__uint:
1687  * @proxy:
1688  * @out_uint:
1689  * @cancellable: (allow-none):
1690  * @error:
1691  * @start_func: (scope call):
1692  * @finish_func: (scope call):
1693  *
1694  * Returns:
1695  */
1696 gboolean
1697 e_gdbus_proxy_call_sync_void__uint (GDBusProxy *proxy,
1698                                     guint *out_uint,
1699                                     GCancellable *cancellable,
1700                                     GError **error,
1701                                     EGdbusCallStartVoid start_func,
1702                                     EGdbusCallFinishUint finish_func)
1703 {
1704         g_return_val_if_fail (proxy != NULL, FALSE);
1705         g_return_val_if_fail (start_func != NULL, FALSE);
1706         g_return_val_if_fail (finish_func != NULL, FALSE);
1707         g_return_val_if_fail (out_uint != NULL, FALSE);
1708
1709         return e_gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_VOID, NULL, E_GDBUS_TYPE_UINT, out_uint);
1710 }
1711
1712 gboolean
1713 e_gdbus_proxy_call_sync_boolean__void (GDBusProxy *proxy,
1714                                        gboolean in_boolean,
1715                                        GCancellable *cancellable,
1716                                        GError **error,
1717                                        EGdbusCallStartBoolean start_func,
1718                                        EGdbusCallFinishVoid finish_func)
1719 {
1720         g_return_val_if_fail (proxy != NULL, FALSE);
1721         g_return_val_if_fail (start_func != NULL, FALSE);
1722         g_return_val_if_fail (finish_func != NULL, FALSE);
1723
1724         return e_gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_BOOLEAN, &in_boolean, E_GDBUS_TYPE_VOID, NULL);
1725 }
1726
1727 /**
1728  * e_gdbus_proxy_call_sync_string__void:
1729  * @proxy:
1730  * @in_string:
1731  * @cancellable: (allow-none):
1732  * @error:
1733  * @start_func: (scope call):
1734  * @finish_func: (scope call):
1735  *
1736  * Returns:
1737  */
1738 gboolean
1739 e_gdbus_proxy_call_sync_string__void (GDBusProxy *proxy,
1740                                       const gchar *in_string,
1741                                       GCancellable *cancellable,
1742                                       GError **error,
1743                                       EGdbusCallStartString start_func,
1744                                       EGdbusCallFinishVoid finish_func)
1745 {
1746         g_return_val_if_fail (proxy != NULL, FALSE);
1747         g_return_val_if_fail (start_func != NULL, FALSE);
1748         g_return_val_if_fail (finish_func != NULL, FALSE);
1749         g_return_val_if_fail (in_string != NULL, FALSE);
1750
1751         return e_gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_STRING, in_string, E_GDBUS_TYPE_VOID, NULL);
1752 }
1753
1754 gboolean
1755 e_gdbus_proxy_call_sync_strv__void (GDBusProxy *proxy,
1756                                     const gchar * const *in_strv,
1757                                     GCancellable *cancellable,
1758                                     GError **error,
1759                                     EGdbusCallStartStrv start_func,
1760                                     EGdbusCallFinishVoid finish_func)
1761 {
1762         g_return_val_if_fail (proxy != NULL, FALSE);
1763         g_return_val_if_fail (start_func != NULL, FALSE);
1764         g_return_val_if_fail (finish_func != NULL, FALSE);
1765         g_return_val_if_fail (in_strv != NULL, FALSE);
1766
1767         return e_gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_STRV, in_strv, E_GDBUS_TYPE_VOID, NULL);
1768 }
1769
1770 /**
1771  * e_gdbus_proxy_call_sync_uint__void:
1772  * @proxy:
1773  * @in_uint:
1774  * @cancellable: (allow-none):
1775  * @error:
1776  * @start_func: (scope call):
1777  * @finish_func: (scope call):
1778  *
1779  * Returns:
1780  */
1781 gboolean
1782 e_gdbus_proxy_call_sync_uint__void (GDBusProxy *proxy,
1783                                     guint in_uint,
1784                                     GCancellable *cancellable,
1785                                     GError **error,
1786                                     EGdbusCallStartUint start_func,
1787                                     EGdbusCallFinishVoid finish_func)
1788 {
1789         g_return_val_if_fail (proxy != NULL, FALSE);
1790         g_return_val_if_fail (start_func != NULL, FALSE);
1791         g_return_val_if_fail (finish_func != NULL, FALSE);
1792
1793         return e_gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_UINT, &in_uint, E_GDBUS_TYPE_VOID, NULL);
1794 }
1795
1796 gboolean
1797 e_gdbus_proxy_call_sync_string__string (GDBusProxy *proxy,
1798                                         const gchar *in_string,
1799                                         gchar **out_string,
1800                                         GCancellable *cancellable,
1801                                         GError **error,
1802                                         EGdbusCallStartString start_func,
1803                                         EGdbusCallFinishString finish_func)
1804 {
1805         g_return_val_if_fail (proxy != NULL, FALSE);
1806         g_return_val_if_fail (start_func != NULL, FALSE);
1807         g_return_val_if_fail (finish_func != NULL, FALSE);
1808         g_return_val_if_fail (in_string != NULL, FALSE);
1809         g_return_val_if_fail (out_string != NULL, FALSE);
1810
1811         return e_gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_STRING, in_string, E_GDBUS_TYPE_STRING, out_string);
1812 }
1813
1814 /**
1815  * e_gdbus_proxy_call_sync_string__strv:
1816  * @proxy:
1817  * @cancellable: (allow-none):
1818  * @error:
1819  * @start_func: (scope call):
1820  * @finish_func: (scope call):
1821  *
1822  * Returns:
1823  */
1824 gboolean
1825 e_gdbus_proxy_call_sync_string__strv (GDBusProxy *proxy,
1826                                       const gchar *in_string,
1827                                       gchar ***out_strv,
1828                                       GCancellable *cancellable,
1829                                       GError **error,
1830                                       EGdbusCallStartString start_func,
1831                                       EGdbusCallFinishStrv finish_func)
1832 {
1833         g_return_val_if_fail (proxy != NULL, FALSE);
1834         g_return_val_if_fail (start_func != NULL, FALSE);
1835         g_return_val_if_fail (finish_func != NULL, FALSE);
1836         g_return_val_if_fail (in_string != NULL, FALSE);
1837         g_return_val_if_fail (out_strv != NULL, FALSE);
1838
1839         return e_gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_STRING, in_string, E_GDBUS_TYPE_STRV, out_strv);
1840 }
1841
1842 gboolean
1843 e_gdbus_proxy_call_sync_strv__string (GDBusProxy *proxy,
1844                                       const gchar * const *in_strv,
1845                                       gchar **out_string,
1846                                       GCancellable *cancellable,
1847                                       GError **error,
1848                                       EGdbusCallStartStrv start_func,
1849                                       EGdbusCallFinishString finish_func)
1850 {
1851         g_return_val_if_fail (proxy != NULL, FALSE);
1852         g_return_val_if_fail (start_func != NULL, FALSE);
1853         g_return_val_if_fail (finish_func != NULL, FALSE);
1854         g_return_val_if_fail (in_strv != NULL, FALSE);
1855         g_return_val_if_fail (out_string != NULL, FALSE);
1856
1857         return e_gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_STRV, in_strv, E_GDBUS_TYPE_STRING, out_string);
1858 }
1859
1860 /**
1861  * e_gdbus_proxy_call_sync_strv__strv:
1862  * @proxy:
1863  * @in_strv:
1864  * @out_strv:
1865  * @cancellable: (allow-none):
1866  * @error:
1867  * @start_func: (scope call):
1868  * @finish_func: (scope call):
1869  *
1870  * Returns:
1871  */
1872 gboolean
1873 e_gdbus_proxy_call_sync_strv__strv (GDBusProxy *proxy,
1874                                     const gchar * const *in_strv,
1875                                     gchar ***out_strv,
1876                                     GCancellable *cancellable,
1877                                     GError **error,
1878                                     EGdbusCallStartStrv start_func,
1879                                     EGdbusCallFinishStrv finish_func)
1880 {
1881         g_return_val_if_fail (proxy != NULL, FALSE);
1882         g_return_val_if_fail (start_func != NULL, FALSE);
1883         g_return_val_if_fail (finish_func != NULL, FALSE);
1884         g_return_val_if_fail (in_strv != NULL, FALSE);
1885         g_return_val_if_fail (out_strv != NULL, FALSE);
1886
1887         return e_gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_STRV, in_strv, E_GDBUS_TYPE_STRV, out_strv);
1888 }
1889
1890 static void
1891 proxy_method_call (const gchar *method_name,
1892                    guint param_type,
1893                    gconstpointer param_value,
1894                    GDBusProxy *proxy,
1895                    GCancellable *cancellable,
1896                    GAsyncReadyCallback callback,
1897                    gpointer user_data)
1898 {
1899         GVariant *params = NULL;
1900         GVariant *item;
1901         GVariantBuilder *builder = NULL;
1902
1903         g_return_if_fail (method_name != NULL);
1904         g_return_if_fail (proxy != NULL);
1905         g_return_if_fail (G_IS_DBUS_PROXY (proxy));
1906         if (param_type != E_GDBUS_TYPE_VOID)
1907                 g_return_if_fail (param_value != NULL);
1908
1909         switch (param_type) {
1910         case E_GDBUS_TYPE_VOID:
1911                 break;
1912         case E_GDBUS_TYPE_BOOLEAN:
1913                 builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
1914                 item = g_variant_new_boolean (* ((const gboolean *) param_value));
1915                 g_variant_builder_add_value (builder, item);
1916                 break;
1917         case E_GDBUS_TYPE_STRING:
1918                 builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
1919                 item = g_variant_new_string ((const gchar *) param_value);
1920                 g_variant_builder_add_value (builder, item);
1921                 break;
1922         case E_GDBUS_TYPE_STRV:
1923                 builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
1924                 item = g_variant_new_strv ((const gchar * const *) param_value, -1);
1925                 g_variant_builder_add_value (builder, item);
1926                 break;
1927         case E_GDBUS_TYPE_UINT:
1928                 builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
1929                 item = g_variant_new_uint32 (* ((const guint *) param_value));
1930                 g_variant_builder_add_value (builder, item);
1931                 break;
1932         default:
1933                 g_warning ("%s: Unknown 'param' E_GDBUS_TYPE %x", G_STRFUNC, param_type);
1934                 return;
1935         }
1936
1937         if (builder != NULL) {
1938                 params = g_variant_builder_end (builder);
1939                 g_variant_builder_unref (builder);
1940         }
1941
1942         g_dbus_proxy_call (G_DBUS_PROXY (proxy), method_name, params, G_DBUS_CALL_FLAGS_NONE, e_data_server_util_get_dbus_call_timeout (), cancellable, callback, user_data);
1943 }
1944
1945 void
1946 e_gdbus_proxy_method_call_void (const gchar *method_name,
1947                                 GDBusProxy *proxy,
1948                                 GCancellable *cancellable,
1949                                 GAsyncReadyCallback callback,
1950                                 gpointer user_data)
1951 {
1952         proxy_method_call (method_name, E_GDBUS_TYPE_VOID, NULL, proxy, cancellable, callback, user_data);
1953 }
1954
1955 void
1956 e_gdbus_proxy_method_call_boolean (const gchar *method_name,
1957                                    GDBusProxy *proxy,
1958                                    gboolean in_boolean,
1959                                    GCancellable *cancellable,
1960                                    GAsyncReadyCallback callback,
1961                                    gpointer user_data)
1962 {
1963         proxy_method_call (method_name, E_GDBUS_TYPE_BOOLEAN, &in_boolean, proxy, cancellable, callback, user_data);
1964 }
1965
1966 void
1967 e_gdbus_proxy_method_call_string (const gchar *method_name,
1968                                   GDBusProxy *proxy,
1969                                   const gchar *in_string,
1970                                   GCancellable *cancellable,
1971                                   GAsyncReadyCallback callback,
1972                                   gpointer user_data)
1973 {
1974         proxy_method_call (method_name, E_GDBUS_TYPE_STRING, in_string, proxy, cancellable, callback, user_data);
1975 }
1976
1977 void
1978 e_gdbus_proxy_method_call_strv (const gchar *method_name,
1979                                 GDBusProxy *proxy,
1980                                 const gchar * const *in_strv,
1981                                 GCancellable *cancellable,
1982                                 GAsyncReadyCallback callback,
1983                                 gpointer user_data)
1984 {
1985         proxy_method_call (method_name, E_GDBUS_TYPE_STRV, in_strv, proxy, cancellable, callback, user_data);
1986 }
1987
1988 void
1989 e_gdbus_proxy_method_call_uint (const gchar *method_name,
1990                                 GDBusProxy *proxy,
1991                                 guint in_uint,
1992                                 GCancellable *cancellable,
1993                                 GAsyncReadyCallback callback,
1994                                 gpointer user_data)
1995 {
1996         proxy_method_call (method_name, E_GDBUS_TYPE_VOID, &in_uint, proxy, cancellable, callback, user_data);
1997 }
1998
1999 static gboolean
2000 process_result (const gchar *caller_func_name,
2001                 guint out_type,
2002                 gpointer out_value,
2003                 GVariant *_result)
2004 {
2005         if (out_type != E_GDBUS_TYPE_VOID)
2006                 g_return_val_if_fail (out_value != NULL, FALSE);
2007
2008         if (_result == NULL)
2009                 return FALSE;
2010
2011         switch (out_type) {
2012         case E_GDBUS_TYPE_VOID:
2013                 break;
2014         case E_GDBUS_TYPE_BOOLEAN:
2015                 g_variant_get (_result, "(b)", (gboolean *) out_value);
2016                 break;
2017         case E_GDBUS_TYPE_STRING:
2018                 g_variant_get (_result, "(s)", (gchar **) out_value);
2019                 break;
2020         case E_GDBUS_TYPE_STRV:
2021                 g_variant_get (_result, "(^as)", (gchar ***) out_value);
2022                 break;
2023         case E_GDBUS_TYPE_UINT:
2024                 g_variant_get (_result, "(u)", (guint *) out_value);
2025                 break;
2026         default:
2027                 g_warning ("%s: Unknown 'out' E_GDBUS_TYPE %x", caller_func_name ? caller_func_name : G_STRFUNC, out_type);
2028                 break;
2029         }
2030
2031         g_variant_unref (_result);
2032
2033         return TRUE;
2034 }
2035
2036 static gboolean
2037 proxy_method_call_finish (guint out_type,
2038                           gpointer out_param,
2039                           GDBusProxy *proxy,
2040                           GAsyncResult *result,
2041                           GError **error)
2042 {
2043         g_return_val_if_fail (proxy != NULL, FALSE);
2044         g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), FALSE);
2045         if (out_type != E_GDBUS_TYPE_VOID)
2046                 g_return_val_if_fail (out_param != NULL, FALSE);
2047
2048         return process_result (G_STRFUNC, out_type, out_param, g_dbus_proxy_call_finish (proxy, result, error));
2049 }
2050
2051 gboolean
2052 e_gdbus_proxy_method_call_finish_void (GDBusProxy *proxy,
2053                                        GAsyncResult *result,
2054                                        GError **error)
2055 {
2056         return proxy_method_call_finish (E_GDBUS_TYPE_VOID, NULL, proxy, result, error);
2057 }
2058
2059 gboolean
2060 e_gdbus_proxy_method_call_finish_boolean (GDBusProxy *proxy,
2061                                           GAsyncResult *result,
2062                                           gboolean *out_boolean,
2063                                           GError **error)
2064 {
2065         return proxy_method_call_finish (E_GDBUS_TYPE_BOOLEAN, out_boolean, proxy, result, error);
2066 }
2067
2068 gboolean
2069 e_gdbus_proxy_method_call_finish_string (GDBusProxy *proxy,
2070                                          GAsyncResult *result,
2071                                          gchar **out_string,
2072                                          GError **error)
2073 {
2074         return proxy_method_call_finish (E_GDBUS_TYPE_STRING, out_string, proxy, result, error);
2075 }
2076
2077 gboolean
2078 e_gdbus_proxy_method_call_finish_strv (GDBusProxy *proxy,
2079                                        GAsyncResult *result,
2080                                        gchar ***out_strv,
2081                                        GError **error)
2082 {
2083         return proxy_method_call_finish (E_GDBUS_TYPE_STRV, out_strv, proxy, result, error);
2084 }
2085
2086 gboolean
2087 e_gdbus_proxy_method_call_finish_uint (GDBusProxy *proxy,
2088                                        GAsyncResult *result,
2089                                        guint *out_uint,
2090                                        GError **error)
2091 {
2092         return proxy_method_call_finish (E_GDBUS_TYPE_UINT, out_uint, proxy, result, error);
2093 }
2094
2095 static gboolean
2096 proxy_method_call_sync (const gchar *method_name,
2097                         guint in_type,
2098                         gconstpointer in_value,
2099                         guint out_type,
2100                         gpointer out_value,
2101                         GDBusProxy *proxy,
2102                         GCancellable *cancellable,
2103                         GError **error)
2104 {
2105         GVariant *params = NULL;
2106         GVariant *item;
2107         GVariantBuilder *builder = NULL;
2108
2109         g_return_val_if_fail (method_name != NULL, FALSE);
2110         g_return_val_if_fail (proxy != NULL, FALSE);
2111         g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), FALSE);
2112         if (in_type != E_GDBUS_TYPE_VOID)
2113                 g_return_val_if_fail (in_value != NULL, FALSE);
2114         if (out_type != E_GDBUS_TYPE_VOID)
2115                 g_return_val_if_fail (out_value != NULL, FALSE);
2116
2117         switch (in_type) {
2118         case E_GDBUS_TYPE_VOID:
2119                 break;
2120         case E_GDBUS_TYPE_BOOLEAN:
2121                 builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
2122                 item = g_variant_new_boolean (* ((const gboolean *) in_value));
2123                 g_variant_builder_add_value (builder, item);
2124                 break;
2125         case E_GDBUS_TYPE_STRING:
2126                 builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
2127                 item = g_variant_new_string ((const gchar *) in_value);
2128                 g_variant_builder_add_value (builder, item);
2129                 break;
2130         case E_GDBUS_TYPE_STRV:
2131                 builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
2132                 item = g_variant_new_strv ((const gchar * const *) in_value, -1);
2133                 g_variant_builder_add_value (builder, item);
2134                 break;
2135         case E_GDBUS_TYPE_UINT:
2136                 builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
2137                 item = g_variant_new_uint32 (* ((const guint *) in_value));
2138                 g_variant_builder_add_value (builder, item);
2139                 break;
2140         default:
2141                 g_warning ("%s: Unknown 'in' E_GDBUS_TYPE %x", G_STRFUNC, in_type);
2142                 return FALSE;
2143         }
2144
2145         if (builder != NULL) {
2146                 params = g_variant_builder_end (builder);
2147                 g_variant_builder_unref (builder);
2148         }
2149
2150         return process_result (G_STRFUNC, out_type, out_value, g_dbus_proxy_call_sync (G_DBUS_PROXY (proxy), method_name, params, G_DBUS_CALL_FLAGS_NONE, e_data_server_util_get_dbus_call_timeout (), cancellable, error));
2151 }
2152
2153 /**
2154  * e_gdbus_proxy_call_sync_void__void:
2155  * @proxy:
2156  * @cancellable: (allow-none):
2157  * @error:
2158  * @start_func: (scope call):
2159  * @finish_func: (scope call):
2160  *
2161  * Returns:
2162  */
2163 gboolean
2164 e_gdbus_proxy_method_call_sync_void__void (const gchar *method_name,
2165                                            GDBusProxy *proxy,
2166                                            GCancellable *cancellable,
2167                                            GError **error)
2168 {
2169         return proxy_method_call_sync (method_name, E_GDBUS_TYPE_VOID, NULL, E_GDBUS_TYPE_VOID, NULL, proxy, cancellable, error);
2170 }
2171
2172 /**
2173  * e_gdbus_proxy_call_sync_boolean__void:
2174  * @proxy:
2175  * @in_boolean:
2176  * @cancellable: (allow-none):
2177  * @error:
2178  * @start_func: (scope call):
2179  * @finish_func: (scope call):
2180  *
2181  * Returns:
2182  */
2183 gboolean
2184 e_gdbus_proxy_method_call_sync_boolean__void (const gchar *method_name,
2185                                               GDBusProxy *proxy,
2186                                               gboolean in_boolean,
2187                                               GCancellable *cancellable,
2188                                               GError **error)
2189 {
2190         return proxy_method_call_sync (method_name, E_GDBUS_TYPE_BOOLEAN, &in_boolean, E_GDBUS_TYPE_VOID, NULL, proxy, cancellable, error);
2191 }
2192
2193 gboolean
2194 e_gdbus_proxy_method_call_sync_string__void (const gchar *method_name,
2195                                              GDBusProxy *proxy,
2196                                              const gchar *in_string,
2197                                              GCancellable *cancellable,
2198                                              GError **error)
2199 {
2200         return proxy_method_call_sync (method_name, E_GDBUS_TYPE_STRING, in_string, E_GDBUS_TYPE_VOID, NULL, proxy, cancellable, error);
2201 }
2202
2203 /**
2204  * e_gdbus_proxy_call_sync_strv__void:
2205  * @proxy:
2206  * @in_strv:
2207  * @cancellable: (allow-none):
2208  * @error:
2209  * @start_func: (scope call):
2210  * @finish_func: (scope call):
2211  *
2212  * Returns:
2213  */
2214 gboolean
2215 e_gdbus_proxy_method_call_sync_strv__void (const gchar *method_name,
2216                                            GDBusProxy *proxy,
2217                                            const gchar * const *in_strv,
2218                                            GCancellable *cancellable,
2219                                            GError **error)
2220 {
2221         return proxy_method_call_sync (method_name, E_GDBUS_TYPE_STRV, in_strv, E_GDBUS_TYPE_VOID, NULL, proxy, cancellable, error);
2222 }
2223
2224 gboolean
2225 e_gdbus_proxy_method_call_sync_uint__void (const gchar *method_name,
2226                                            GDBusProxy *proxy,
2227                                            guint in_uint,
2228                                            GCancellable *cancellable,
2229                                            GError **error)
2230 {
2231         return proxy_method_call_sync (method_name, E_GDBUS_TYPE_UINT, &in_uint, E_GDBUS_TYPE_VOID, NULL, proxy, cancellable, error);
2232 }
2233
2234 /**
2235  * e_gdbus_proxy_call_sync_string__string:
2236  * @proxy:
2237  * @in_string:
2238  * @out_string:
2239  * @cancellable: (allow-none):
2240  * @error:
2241  * @start_func: (scope call):
2242  * @finish_func: (scope call):
2243  *
2244  * Returns:
2245  */
2246 gboolean
2247 e_gdbus_proxy_method_call_sync_string__string (const gchar *method_name,
2248                                                GDBusProxy *proxy,
2249                                                const gchar *in_string,
2250                                                gchar **out_string,
2251                                                GCancellable *cancellable,
2252                                                GError **error)
2253 {
2254         return proxy_method_call_sync (method_name, E_GDBUS_TYPE_STRING, in_string, E_GDBUS_TYPE_STRING, out_string, proxy, cancellable, error);
2255 }
2256
2257 /**
2258  * e_gdbus_proxy_call_sync_strv__string:
2259  * @proxy:
2260  * @in_strv:
2261  * @out_string:
2262  * @cancellable: (allow-none):
2263  * @error:
2264  * @start_func: (scope call):
2265  * @finish_func: (scope call):
2266  *
2267  * Returns:
2268  */
2269 gboolean
2270 e_gdbus_proxy_method_call_sync_strv__string (const gchar *method_name,
2271                                              GDBusProxy *proxy,
2272                                              const gchar * const *in_strv,
2273                                              gchar **out_string,
2274                                              GCancellable *cancellable,
2275                                              GError **error)
2276 {
2277         return proxy_method_call_sync (method_name, E_GDBUS_TYPE_STRV, in_strv, E_GDBUS_TYPE_STRING, out_string, proxy, cancellable, error);
2278 }
2279
2280 /**
2281  * e_gdbus_templates_encode_error:
2282  * @in_error: (allow-none):
2283  *
2284  * Returns: (transfer full): a %NULL-terminated array of strings; free with
2285  * g_strfreev()
2286  */
2287 gchar **
2288 e_gdbus_templates_encode_error (const GError *in_error)
2289 {
2290         gchar **strv;
2291
2292         strv = g_new0 (gchar *, 3);
2293
2294         if (!in_error) {
2295                 strv[0] = g_strdup ("");
2296                 strv[1] = g_strdup ("");
2297         } else {
2298                 gchar *dbus_error_name = g_dbus_error_encode_gerror (in_error);
2299
2300                 strv[0] = e_util_utf8_make_valid (dbus_error_name ? dbus_error_name : "");
2301                 strv[1] = e_util_utf8_make_valid (in_error->message);
2302
2303                 g_free (dbus_error_name);
2304         }
2305
2306         return strv;
2307 }
2308
2309 /* free *out_error with g_error_free(), if not NULL */
2310 gboolean
2311 e_gdbus_templates_decode_error (const gchar * const *in_strv,
2312                                 GError **out_error)
2313 {
2314         const gchar *error_name, *error_message;
2315
2316         g_return_val_if_fail (out_error != NULL, FALSE);
2317
2318         *out_error = NULL;
2319
2320         g_return_val_if_fail (in_strv != NULL, FALSE);
2321         g_return_val_if_fail (in_strv[0] != NULL, FALSE);
2322         g_return_val_if_fail (in_strv[1] != NULL, FALSE);
2323         g_return_val_if_fail (in_strv[2] == NULL, FALSE);
2324
2325         error_name = in_strv[0];
2326         error_message = in_strv[1];
2327
2328         if (error_name && *error_name && error_message)
2329                 *out_error = g_dbus_error_new_for_dbus_error (error_name, error_message);
2330
2331         return TRUE;
2332 }
2333
2334 /**
2335  * e_gdbus_templates_encode_two_strings:
2336  * @in_str1: (allow-none):
2337  * @in_str2: (allow-none):
2338  *
2339  * Returns: (transfer full): a %NULL-terminated array of strings; free with
2340  * g_strfreev()
2341  */
2342 gchar **
2343 e_gdbus_templates_encode_two_strings (const gchar *in_str1,
2344                                       const gchar *in_str2)
2345 {
2346         gchar **strv;
2347
2348         strv = g_new0 (gchar *, 3);
2349         strv[0] = e_util_utf8_make_valid (in_str1 ? in_str1 : "");
2350         strv[1] = e_util_utf8_make_valid (in_str2 ? in_str2 : "");
2351         strv[2] = NULL;
2352
2353         return strv;
2354 }
2355
2356 /* free *out_str1 and *out_str2 with g_free() */
2357 gboolean
2358 e_gdbus_templates_decode_two_strings (const gchar * const *in_strv,
2359                                       gchar **out_str1,
2360                                       gchar **out_str2)
2361 {
2362         g_return_val_if_fail (in_strv != NULL, FALSE);
2363         g_return_val_if_fail (in_strv[0] != NULL, FALSE);
2364         g_return_val_if_fail (in_strv[1] != NULL, FALSE);
2365         g_return_val_if_fail (in_strv[2] == NULL, FALSE);
2366         g_return_val_if_fail (out_str1 != NULL, FALSE);
2367         g_return_val_if_fail (out_str2 != NULL, FALSE);
2368
2369         *out_str1 = g_strdup (in_strv[0]);
2370         *out_str2 = g_strdup (in_strv[1]);
2371
2372         return TRUE;
2373 }