gdbus: add Method.NoReply annotation in introspection
[framework/connectivity/connman.git] / gdbus / object.c
1 /*
2  *
3  *  D-Bus helper library
4  *
5  *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <stdio.h>
29 #include <string.h>
30
31 #include <glib.h>
32 #include <dbus/dbus.h>
33
34 #include "gdbus.h"
35
36 #define info(fmt...)
37 #define error(fmt...)
38 #define debug(fmt...)
39
40 struct generic_data {
41         unsigned int refcount;
42         GSList *interfaces;
43         char *introspect;
44 };
45
46 struct interface_data {
47         char *name;
48         const GDBusMethodTable *methods;
49         const GDBusSignalTable *signals;
50         const GDBusPropertyTable *properties;
51         void *user_data;
52         GDBusDestroyFunction destroy;
53 };
54
55 struct security_data {
56         GDBusPendingReply pending;
57         DBusMessage *message;
58         const GDBusMethodTable *method;
59         void *iface_user_data;
60 };
61
62 static void print_arguments(GString *gstr, const GDBusArgInfo *args,
63                                                 const char *direction)
64 {
65         for (; args && args->name; args++) {
66                 g_string_append_printf(gstr,
67                                         "\t\t\t<arg name=\"%s\" type=\"%s\"",
68                                         args->name, args->signature);
69
70                 if (direction)
71                         g_string_append_printf(gstr,
72                                         " direction=\"%s\"/>\n", direction);
73                 else
74                         g_string_append_printf(gstr, "/>\n");
75
76         }
77 }
78
79 static void generate_interface_xml(GString *gstr, struct interface_data *iface)
80 {
81         const GDBusMethodTable *method;
82         const GDBusSignalTable *signal;
83
84         for (method = iface->methods; method && method->name; method++) {
85                 gboolean deprecated = method->flags &
86                                                 G_DBUS_METHOD_FLAG_DEPRECATED;
87                 gboolean noreply = method->flags &
88                                                 G_DBUS_METHOD_FLAG_NOREPLY;
89
90                 if (!deprecated && !noreply &&
91                                 !(method->in_args && method->in_args->name) &&
92                                 !(method->out_args && method->out_args->name))
93                         g_string_append_printf(gstr, "\t\t<method name=\"%s\"/>\n",
94                                                                 method->name);
95                 else {
96                         g_string_append_printf(gstr, "\t\t<method name=\"%s\">\n",
97                                                                 method->name);
98                         print_arguments(gstr, method->in_args, "in");
99                         print_arguments(gstr, method->out_args, "out");
100
101                         if (deprecated)
102                                 g_string_append_printf(gstr, "\t\t\t<annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n");
103
104                         if (noreply)
105                                 g_string_append_printf(gstr, "\t\t\t<annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n");
106
107                         g_string_append_printf(gstr, "\t\t</method>\n");
108                 }
109         }
110
111         for (signal = iface->signals; signal && signal->name; signal++) {
112                 gboolean deprecated = signal->flags &
113                                                 G_DBUS_SIGNAL_FLAG_DEPRECATED;
114
115                 if (!deprecated && !(signal->args && signal->args->name))
116                         g_string_append_printf(gstr, "\t\t<signal name=\"%s\"/>\n",
117                                                                 signal->name);
118                 else {
119                         g_string_append_printf(gstr, "\t\t<signal name=\"%s\">\n",
120                                                                 signal->name);
121                         print_arguments(gstr, signal->args, NULL);
122
123                         if (deprecated)
124                                 g_string_append_printf(gstr, "\t\t\t<annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n");
125
126                         g_string_append_printf(gstr, "\t\t</signal>\n");
127                 }
128         }
129 }
130
131 static void generate_introspection_xml(DBusConnection *conn,
132                                 struct generic_data *data, const char *path)
133 {
134         GSList *list;
135         GString *gstr;
136         char **children;
137         int i;
138
139         g_free(data->introspect);
140
141         gstr = g_string_new(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
142
143         g_string_append_printf(gstr, "<node>\n");
144
145         for (list = data->interfaces; list; list = list->next) {
146                 struct interface_data *iface = list->data;
147
148                 g_string_append_printf(gstr, "\t<interface name=\"%s\">\n",
149                                                                 iface->name);
150
151                 generate_interface_xml(gstr, iface);
152
153                 g_string_append_printf(gstr, "\t</interface>\n");
154         }
155
156         if (!dbus_connection_list_registered(conn, path, &children))
157                 goto done;
158
159         for (i = 0; children[i]; i++)
160                 g_string_append_printf(gstr, "\t<node name=\"%s\"/>\n",
161                                                                 children[i]);
162
163         dbus_free_string_array(children);
164
165 done:
166         g_string_append_printf(gstr, "</node>\n");
167
168         data->introspect = g_string_free(gstr, FALSE);
169 }
170
171 static DBusMessage *introspect(DBusConnection *connection,
172                                 DBusMessage *message, void *user_data)
173 {
174         struct generic_data *data = user_data;
175         DBusMessage *reply;
176
177         if (!dbus_message_has_signature(message, DBUS_TYPE_INVALID_AS_STRING)) {
178                 error("Unexpected signature to introspect call");
179                 return NULL;
180         }
181
182         if (data->introspect == NULL)
183                 generate_introspection_xml(connection, data,
184                                                 dbus_message_get_path(message));
185
186         reply = dbus_message_new_method_return(message);
187         if (reply == NULL)
188                 return NULL;
189
190         dbus_message_append_args(reply, DBUS_TYPE_STRING, &data->introspect,
191                                         DBUS_TYPE_INVALID);
192
193         return reply;
194 }
195
196 static DBusHandlerResult process_message(DBusConnection *connection,
197                         DBusMessage *message, const GDBusMethodTable *method,
198                                                         void *iface_user_data)
199 {
200         DBusMessage *reply;
201
202         reply = method->function(connection, message, iface_user_data);
203
204         if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY) {
205                 if (reply != NULL)
206                         dbus_message_unref(reply);
207                 return DBUS_HANDLER_RESULT_HANDLED;
208         }
209
210         if (method->flags & G_DBUS_METHOD_FLAG_ASYNC) {
211                 if (reply == NULL)
212                         return DBUS_HANDLER_RESULT_HANDLED;
213         }
214
215         if (reply == NULL)
216                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
217
218         dbus_connection_send(connection, reply, NULL);
219         dbus_message_unref(reply);
220
221         return DBUS_HANDLER_RESULT_HANDLED;
222 }
223
224 static GDBusPendingReply next_pending = 1;
225 static GSList *pending_security = NULL;
226
227 static const GDBusSecurityTable *security_table = NULL;
228
229 void g_dbus_pending_success(DBusConnection *connection,
230                                         GDBusPendingReply pending)
231 {
232         GSList *list;
233
234         for (list = pending_security; list; list = list->next) {
235                 struct security_data *secdata = list->data;
236
237                 if (secdata->pending != pending)
238                         continue;
239
240                 pending_security = g_slist_remove(pending_security, secdata);
241
242                 process_message(connection, secdata->message,
243                                 secdata->method, secdata->iface_user_data);
244
245                 dbus_message_unref(secdata->message);
246                 g_free(secdata);
247                 return;
248         }
249 }
250
251 void g_dbus_pending_error_valist(DBusConnection *connection,
252                                 GDBusPendingReply pending, const char *name,
253                                         const char *format, va_list args)
254 {
255         GSList *list;
256
257         for (list = pending_security; list; list = list->next) {
258                 struct security_data *secdata = list->data;
259                 DBusMessage *reply;
260
261                 if (secdata->pending != pending)
262                         continue;
263
264                 pending_security = g_slist_remove(pending_security, secdata);
265
266                 reply = g_dbus_create_error_valist(secdata->message,
267                                                         name, format, args);
268                 if (reply != NULL) {
269                         dbus_connection_send(connection, reply, NULL);
270                         dbus_message_unref(reply);
271                 }
272
273                 dbus_message_unref(secdata->message);
274                 g_free(secdata);
275                 return;
276         }
277 }
278
279 void g_dbus_pending_error(DBusConnection *connection,
280                                 GDBusPendingReply pending,
281                                 const char *name, const char *format, ...)
282 {
283         va_list args;
284
285         va_start(args, format);
286
287         g_dbus_pending_error_valist(connection, pending, name, format, args);
288
289         va_end(args);
290 }
291
292 int polkit_check_authorization(DBusConnection *conn,
293                                 const char *action, gboolean interaction,
294                                 void (*function) (dbus_bool_t authorized,
295                                                         void *user_data),
296                                                 void *user_data, int timeout);
297
298 struct builtin_security_data {
299         DBusConnection *conn;
300         GDBusPendingReply pending;
301 };
302
303 static void builtin_security_result(dbus_bool_t authorized, void *user_data)
304 {
305         struct builtin_security_data *data = user_data;
306
307         if (authorized == TRUE)
308                 g_dbus_pending_success(data->conn, data->pending);
309         else
310                 g_dbus_pending_error(data->conn, data->pending,
311                                                 DBUS_ERROR_AUTH_FAILED, NULL);
312
313         g_free(data);
314 }
315
316 static void builtin_security_function(DBusConnection *conn,
317                                                 const char *action,
318                                                 gboolean interaction,
319                                                 GDBusPendingReply pending)
320 {
321         struct builtin_security_data *data;
322
323         data = g_new0(struct builtin_security_data, 1);
324         data->conn = conn;
325         data->pending = pending;
326
327         if (polkit_check_authorization(conn, action, interaction,
328                                 builtin_security_result, data, 30000) < 0)
329                 g_dbus_pending_error(conn, pending, NULL, NULL);
330 }
331
332 static gboolean check_privilege(DBusConnection *conn, DBusMessage *msg,
333                         const GDBusMethodTable *method, void *iface_user_data)
334 {
335         const GDBusSecurityTable *security;
336
337         for (security = security_table; security && security->privilege;
338                                                                 security++) {
339                 struct security_data *secdata;
340                 gboolean interaction;
341
342                 if (security->privilege != method->privilege)
343                         continue;
344
345                 secdata = g_new(struct security_data, 1);
346                 secdata->pending = next_pending++;
347                 secdata->message = dbus_message_ref(msg);
348                 secdata->method = method;
349                 secdata->iface_user_data = iface_user_data;
350
351                 pending_security = g_slist_prepend(pending_security, secdata);
352
353                 if (security->flags & G_DBUS_SECURITY_FLAG_ALLOW_INTERACTION)
354                         interaction = TRUE;
355                 else
356                         interaction = FALSE;
357
358                 if (!(security->flags & G_DBUS_SECURITY_FLAG_BUILTIN) &&
359                                                         security->function)
360                         security->function(conn, security->action,
361                                                 interaction, secdata->pending);
362                 else
363                         builtin_security_function(conn, security->action,
364                                                 interaction, secdata->pending);
365
366                 return TRUE;
367         }
368
369         return FALSE;
370 }
371
372 static void generic_unregister(DBusConnection *connection, void *user_data)
373 {
374         struct generic_data *data = user_data;
375
376         g_free(data->introspect);
377         g_free(data);
378 }
379
380 static struct interface_data *find_interface(GSList *interfaces,
381                                                 const char *name)
382 {
383         GSList *list;
384
385         if (name == NULL)
386                 return NULL;
387
388         for (list = interfaces; list; list = list->next) {
389                 struct interface_data *iface = list->data;
390                 if (!strcmp(name, iface->name))
391                         return iface;
392         }
393
394         return NULL;
395 }
396
397 static gboolean g_dbus_args_have_signature(const GDBusArgInfo *args,
398                                                         DBusMessage *message)
399 {
400         const char *sig = dbus_message_get_signature(message);
401         const char *p = NULL;
402
403         for (; args && args->signature && *sig; args++) {
404                 p = args->signature;
405
406                 for (; *sig && *p; sig++, p++) {
407                         if (*p != *sig)
408                                 return FALSE;
409                 }
410         }
411
412         if (*sig || (p && *p) || (args && args->signature))
413                 return FALSE;
414
415         return TRUE;
416 }
417
418 static DBusHandlerResult generic_message(DBusConnection *connection,
419                                         DBusMessage *message, void *user_data)
420 {
421         struct generic_data *data = user_data;
422         struct interface_data *iface;
423         const GDBusMethodTable *method;
424         const char *interface;
425
426         interface = dbus_message_get_interface(message);
427
428         iface = find_interface(data->interfaces, interface);
429         if (iface == NULL)
430                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
431
432         for (method = iface->methods; method &&
433                         method->name && method->function; method++) {
434                 if (dbus_message_is_method_call(message, iface->name,
435                                                         method->name) == FALSE)
436                         continue;
437
438                 if (g_dbus_args_have_signature(method->in_args,
439                                                         message) == FALSE)
440                         continue;
441
442                 if (check_privilege(connection, message, method,
443                                                 iface->user_data) == TRUE)
444                         return DBUS_HANDLER_RESULT_HANDLED;
445
446                 return process_message(connection, message, method,
447                                                         iface->user_data);
448         }
449
450         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
451 }
452
453 static DBusObjectPathVTable generic_table = {
454         .unregister_function    = generic_unregister,
455         .message_function       = generic_message,
456 };
457
458 static void invalidate_parent_data(DBusConnection *conn, const char *child_path)
459 {
460         struct generic_data *data = NULL;
461         char *parent_path, *slash;
462
463         parent_path = g_strdup(child_path);
464         slash = strrchr(parent_path, '/');
465         if (slash == NULL)
466                 goto done;
467
468         if (slash == parent_path && parent_path[1] != '\0')
469                 parent_path[1] = '\0';
470         else
471                 *slash = '\0';
472
473         if (!strlen(parent_path))
474                 goto done;
475
476         if (dbus_connection_get_object_path_data(conn, parent_path,
477                                                         (void *) &data) == FALSE) {
478                 goto done;
479         }
480
481         invalidate_parent_data(conn, parent_path);
482
483         if (data == NULL)
484                 goto done;
485
486         g_free(data->introspect);
487         data->introspect = NULL;
488
489 done:
490         g_free(parent_path);
491 }
492
493 static const GDBusMethodTable introspect_methods[] = {
494         { GDBUS_METHOD("Introspect", NULL,
495                         GDBUS_ARGS({ "xml", "s" }), introspect) },
496         { }
497 };
498
499 static void add_interface(struct generic_data *data, const char *name,
500                                 const GDBusMethodTable *methods,
501                                 const GDBusSignalTable *signals,
502                                 const GDBusPropertyTable *properties,
503                                 void *user_data,
504                                 GDBusDestroyFunction destroy)
505 {
506         struct interface_data *iface;
507
508         iface = g_new0(struct interface_data, 1);
509         iface->name = g_strdup(name);
510         iface->methods = methods;
511         iface->signals = signals;
512         iface->properties = properties;
513         iface->user_data = user_data;
514         iface->destroy = destroy;
515
516         data->interfaces = g_slist_append(data->interfaces, iface);
517 }
518
519 static struct generic_data *object_path_ref(DBusConnection *connection,
520                                                         const char *path)
521 {
522         struct generic_data *data;
523
524         if (dbus_connection_get_object_path_data(connection, path,
525                                                 (void *) &data) == TRUE) {
526                 if (data != NULL) {
527                         data->refcount++;
528                         return data;
529                 }
530         }
531
532         data = g_new0(struct generic_data, 1);
533         data->refcount = 1;
534
535         data->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<node></node>");
536
537         if (!dbus_connection_register_object_path(connection, path,
538                                                 &generic_table, data)) {
539                 g_free(data->introspect);
540                 g_free(data);
541                 return NULL;
542         }
543
544         invalidate_parent_data(connection, path);
545
546         add_interface(data, DBUS_INTERFACE_INTROSPECTABLE,
547                         introspect_methods, NULL, NULL, data, NULL);
548
549         return data;
550 }
551
552 static gboolean remove_interface(struct generic_data *data, const char *name)
553 {
554         struct interface_data *iface;
555
556         iface = find_interface(data->interfaces, name);
557         if (iface == NULL)
558                 return FALSE;
559
560         data->interfaces = g_slist_remove(data->interfaces, iface);
561
562         if (iface->destroy)
563                 iface->destroy(iface->user_data);
564
565         g_free(iface->name);
566         g_free(iface);
567
568         return TRUE;
569 }
570
571 static void object_path_unref(DBusConnection *connection, const char *path)
572 {
573         struct generic_data *data = NULL;
574
575         if (dbus_connection_get_object_path_data(connection, path,
576                                                 (void *) &data) == FALSE)
577                 return;
578
579         if (data == NULL)
580                 return;
581
582         data->refcount--;
583
584         if (data->refcount > 0)
585                 return;
586
587         remove_interface(data, DBUS_INTERFACE_INTROSPECTABLE);
588
589         invalidate_parent_data(connection, path);
590
591         dbus_connection_unregister_object_path(connection, path);
592 }
593
594 static gboolean check_signal(DBusConnection *conn, const char *path,
595                                 const char *interface, const char *name,
596                                 const GDBusArgInfo **args)
597 {
598         struct generic_data *data = NULL;
599         struct interface_data *iface;
600         const GDBusSignalTable *signal;
601
602         *args = NULL;
603         if (!dbus_connection_get_object_path_data(conn, path,
604                                         (void *) &data) || data == NULL) {
605                 error("dbus_connection_emit_signal: path %s isn't registered",
606                                 path);
607                 return FALSE;
608         }
609
610         iface = find_interface(data->interfaces, interface);
611         if (iface == NULL) {
612                 error("dbus_connection_emit_signal: %s does not implement %s",
613                                 path, interface);
614                 return FALSE;
615         }
616
617         for (signal = iface->signals; signal && signal->name; signal++) {
618                 if (!strcmp(signal->name, name)) {
619                         *args = signal->args;
620                         break;
621                 }
622         }
623
624         if (*args == NULL) {
625                 error("No signal named %s on interface %s", name, interface);
626                 return FALSE;
627         }
628
629         return TRUE;
630 }
631
632 static dbus_bool_t emit_signal_valist(DBusConnection *conn,
633                                                 const char *path,
634                                                 const char *interface,
635                                                 const char *name,
636                                                 int first,
637                                                 va_list var_args)
638 {
639         DBusMessage *signal;
640         dbus_bool_t ret;
641         const GDBusArgInfo *args;
642
643         if (!check_signal(conn, path, interface, name, &args))
644                 return FALSE;
645
646         signal = dbus_message_new_signal(path, interface, name);
647         if (signal == NULL) {
648                 error("Unable to allocate new %s.%s signal", interface,  name);
649                 return FALSE;
650         }
651
652         ret = dbus_message_append_args_valist(signal, first, var_args);
653         if (!ret)
654                 goto fail;
655
656         if (g_dbus_args_have_signature(args, signal) == FALSE) {
657                 error("%s.%s: expected signature'%s' but got '%s'",
658                                 interface, name, args, signature);
659                 ret = FALSE;
660                 goto fail;
661         }
662
663         ret = dbus_connection_send(conn, signal, NULL);
664
665 fail:
666         dbus_message_unref(signal);
667
668         return ret;
669 }
670
671 gboolean g_dbus_register_interface(DBusConnection *connection,
672                                         const char *path, const char *name,
673                                         const GDBusMethodTable *methods,
674                                         const GDBusSignalTable *signals,
675                                         const GDBusPropertyTable *properties,
676                                         void *user_data,
677                                         GDBusDestroyFunction destroy)
678 {
679         struct generic_data *data;
680
681         data = object_path_ref(connection, path);
682         if (data == NULL)
683                 return FALSE;
684
685         if (find_interface(data->interfaces, name)) {
686                 object_path_unref(connection, path);
687                 return FALSE;
688         }
689
690         add_interface(data, name, methods, signals,
691                         properties, user_data, destroy);
692
693         g_free(data->introspect);
694         data->introspect = NULL;
695
696         return TRUE;
697 }
698
699 gboolean g_dbus_unregister_interface(DBusConnection *connection,
700                                         const char *path, const char *name)
701 {
702         struct generic_data *data = NULL;
703
704         if (path == NULL)
705                 return FALSE;
706
707         if (dbus_connection_get_object_path_data(connection, path,
708                                                 (void *) &data) == FALSE)
709                 return FALSE;
710
711         if (data == NULL)
712                 return FALSE;
713
714         if (remove_interface(data, name) == FALSE)
715                 return FALSE;
716
717         g_free(data->introspect);
718         data->introspect = NULL;
719
720         object_path_unref(connection, path);
721
722         return TRUE;
723 }
724
725 gboolean g_dbus_register_security(const GDBusSecurityTable *security)
726 {
727         if (security_table != NULL)
728                 return FALSE;
729
730         security_table = security;
731
732         return TRUE;
733 }
734
735 gboolean g_dbus_unregister_security(const GDBusSecurityTable *security)
736 {
737         security_table = NULL;
738
739         return TRUE;
740 }
741
742 DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name,
743                                         const char *format, va_list args)
744 {
745         char str[1024];
746
747         vsnprintf(str, sizeof(str), format, args);
748
749         return dbus_message_new_error(message, name, str);
750 }
751
752 DBusMessage *g_dbus_create_error(DBusMessage *message, const char *name,
753                                                 const char *format, ...)
754 {
755         va_list args;
756         DBusMessage *reply;
757
758         va_start(args, format);
759
760         reply = g_dbus_create_error_valist(message, name, format, args);
761
762         va_end(args);
763
764         return reply;
765 }
766
767 DBusMessage *g_dbus_create_reply_valist(DBusMessage *message,
768                                                 int type, va_list args)
769 {
770         DBusMessage *reply;
771
772         reply = dbus_message_new_method_return(message);
773         if (reply == NULL)
774                 return NULL;
775
776         if (dbus_message_append_args_valist(reply, type, args) == FALSE) {
777                 dbus_message_unref(reply);
778                 return NULL;
779         }
780
781         return reply;
782 }
783
784 DBusMessage *g_dbus_create_reply(DBusMessage *message, int type, ...)
785 {
786         va_list args;
787         DBusMessage *reply;
788
789         va_start(args, type);
790
791         reply = g_dbus_create_reply_valist(message, type, args);
792
793         va_end(args);
794
795         return reply;
796 }
797
798 gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message)
799 {
800         dbus_bool_t result;
801
802         if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
803                 dbus_message_set_no_reply(message, TRUE);
804
805         result = dbus_connection_send(connection, message, NULL);
806
807         dbus_message_unref(message);
808
809         return result;
810 }
811
812 gboolean g_dbus_send_reply_valist(DBusConnection *connection,
813                                 DBusMessage *message, int type, va_list args)
814 {
815         DBusMessage *reply;
816
817         reply = dbus_message_new_method_return(message);
818         if (reply == NULL)
819                 return FALSE;
820
821         if (dbus_message_append_args_valist(reply, type, args) == FALSE) {
822                 dbus_message_unref(reply);
823                 return FALSE;
824         }
825
826         return g_dbus_send_message(connection, reply);
827 }
828
829 gboolean g_dbus_send_reply(DBusConnection *connection,
830                                 DBusMessage *message, int type, ...)
831 {
832         va_list args;
833         gboolean result;
834
835         va_start(args, type);
836
837         result = g_dbus_send_reply_valist(connection, message, type, args);
838
839         va_end(args);
840
841         return result;
842 }
843
844 gboolean g_dbus_emit_signal(DBusConnection *connection,
845                                 const char *path, const char *interface,
846                                 const char *name, int type, ...)
847 {
848         va_list args;
849         gboolean result;
850
851         va_start(args, type);
852
853         result = emit_signal_valist(connection, path, interface,
854                                                         name, type, args);
855
856         va_end(args);
857
858         return result;
859 }
860
861 gboolean g_dbus_emit_signal_valist(DBusConnection *connection,
862                                 const char *path, const char *interface,
863                                 const char *name, int type, va_list args)
864 {
865         return emit_signal_valist(connection, path, interface,
866                                                         name, type, args);
867 }