wifi: Add support for autoscan request
[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 (data->introspect == NULL)
178                 generate_introspection_xml(connection, data,
179                                                 dbus_message_get_path(message));
180
181         reply = dbus_message_new_method_return(message);
182         if (reply == NULL)
183                 return NULL;
184
185         dbus_message_append_args(reply, DBUS_TYPE_STRING, &data->introspect,
186                                         DBUS_TYPE_INVALID);
187
188         return reply;
189 }
190
191 static DBusHandlerResult process_message(DBusConnection *connection,
192                         DBusMessage *message, const GDBusMethodTable *method,
193                                                         void *iface_user_data)
194 {
195         DBusMessage *reply;
196
197         reply = method->function(connection, message, iface_user_data);
198
199         if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY) {
200                 if (reply != NULL)
201                         dbus_message_unref(reply);
202                 return DBUS_HANDLER_RESULT_HANDLED;
203         }
204
205         if (method->flags & G_DBUS_METHOD_FLAG_ASYNC) {
206                 if (reply == NULL)
207                         return DBUS_HANDLER_RESULT_HANDLED;
208         }
209
210         if (reply == NULL)
211                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
212
213         dbus_connection_send(connection, reply, NULL);
214         dbus_message_unref(reply);
215
216         return DBUS_HANDLER_RESULT_HANDLED;
217 }
218
219 static GDBusPendingReply next_pending = 1;
220 static GSList *pending_security = NULL;
221
222 static const GDBusSecurityTable *security_table = NULL;
223
224 void g_dbus_pending_success(DBusConnection *connection,
225                                         GDBusPendingReply pending)
226 {
227         GSList *list;
228
229         for (list = pending_security; list; list = list->next) {
230                 struct security_data *secdata = list->data;
231
232                 if (secdata->pending != pending)
233                         continue;
234
235                 pending_security = g_slist_remove(pending_security, secdata);
236
237                 process_message(connection, secdata->message,
238                                 secdata->method, secdata->iface_user_data);
239
240                 dbus_message_unref(secdata->message);
241                 g_free(secdata);
242                 return;
243         }
244 }
245
246 void g_dbus_pending_error_valist(DBusConnection *connection,
247                                 GDBusPendingReply pending, const char *name,
248                                         const char *format, va_list args)
249 {
250         GSList *list;
251
252         for (list = pending_security; list; list = list->next) {
253                 struct security_data *secdata = list->data;
254                 DBusMessage *reply;
255
256                 if (secdata->pending != pending)
257                         continue;
258
259                 pending_security = g_slist_remove(pending_security, secdata);
260
261                 reply = g_dbus_create_error_valist(secdata->message,
262                                                         name, format, args);
263                 if (reply != NULL) {
264                         dbus_connection_send(connection, reply, NULL);
265                         dbus_message_unref(reply);
266                 }
267
268                 dbus_message_unref(secdata->message);
269                 g_free(secdata);
270                 return;
271         }
272 }
273
274 void g_dbus_pending_error(DBusConnection *connection,
275                                 GDBusPendingReply pending,
276                                 const char *name, const char *format, ...)
277 {
278         va_list args;
279
280         va_start(args, format);
281
282         g_dbus_pending_error_valist(connection, pending, name, format, args);
283
284         va_end(args);
285 }
286
287 int polkit_check_authorization(DBusConnection *conn,
288                                 const char *action, gboolean interaction,
289                                 void (*function) (dbus_bool_t authorized,
290                                                         void *user_data),
291                                                 void *user_data, int timeout);
292
293 struct builtin_security_data {
294         DBusConnection *conn;
295         GDBusPendingReply pending;
296 };
297
298 static void builtin_security_result(dbus_bool_t authorized, void *user_data)
299 {
300         struct builtin_security_data *data = user_data;
301
302         if (authorized == TRUE)
303                 g_dbus_pending_success(data->conn, data->pending);
304         else
305                 g_dbus_pending_error(data->conn, data->pending,
306                                                 DBUS_ERROR_AUTH_FAILED, NULL);
307
308         g_free(data);
309 }
310
311 static void builtin_security_function(DBusConnection *conn,
312                                                 const char *action,
313                                                 gboolean interaction,
314                                                 GDBusPendingReply pending)
315 {
316         struct builtin_security_data *data;
317
318         data = g_new0(struct builtin_security_data, 1);
319         data->conn = conn;
320         data->pending = pending;
321
322         if (polkit_check_authorization(conn, action, interaction,
323                                 builtin_security_result, data, 30000) < 0)
324                 g_dbus_pending_error(conn, pending, NULL, NULL);
325 }
326
327 static gboolean check_privilege(DBusConnection *conn, DBusMessage *msg,
328                         const GDBusMethodTable *method, void *iface_user_data)
329 {
330         const GDBusSecurityTable *security;
331
332         for (security = security_table; security && security->privilege;
333                                                                 security++) {
334                 struct security_data *secdata;
335                 gboolean interaction;
336
337                 if (security->privilege != method->privilege)
338                         continue;
339
340                 secdata = g_new(struct security_data, 1);
341                 secdata->pending = next_pending++;
342                 secdata->message = dbus_message_ref(msg);
343                 secdata->method = method;
344                 secdata->iface_user_data = iface_user_data;
345
346                 pending_security = g_slist_prepend(pending_security, secdata);
347
348                 if (security->flags & G_DBUS_SECURITY_FLAG_ALLOW_INTERACTION)
349                         interaction = TRUE;
350                 else
351                         interaction = FALSE;
352
353                 if (!(security->flags & G_DBUS_SECURITY_FLAG_BUILTIN) &&
354                                                         security->function)
355                         security->function(conn, security->action,
356                                                 interaction, secdata->pending);
357                 else
358                         builtin_security_function(conn, security->action,
359                                                 interaction, secdata->pending);
360
361                 return TRUE;
362         }
363
364         return FALSE;
365 }
366
367 static void generic_unregister(DBusConnection *connection, void *user_data)
368 {
369         struct generic_data *data = user_data;
370
371         g_free(data->introspect);
372         g_free(data);
373 }
374
375 static struct interface_data *find_interface(GSList *interfaces,
376                                                 const char *name)
377 {
378         GSList *list;
379
380         if (name == NULL)
381                 return NULL;
382
383         for (list = interfaces; list; list = list->next) {
384                 struct interface_data *iface = list->data;
385                 if (!strcmp(name, iface->name))
386                         return iface;
387         }
388
389         return NULL;
390 }
391
392 static gboolean g_dbus_args_have_signature(const GDBusArgInfo *args,
393                                                         DBusMessage *message)
394 {
395         const char *sig = dbus_message_get_signature(message);
396         const char *p = NULL;
397
398         for (; args && args->signature && *sig; args++) {
399                 p = args->signature;
400
401                 for (; *sig && *p; sig++, p++) {
402                         if (*p != *sig)
403                                 return FALSE;
404                 }
405         }
406
407         if (*sig || (p && *p) || (args && args->signature))
408                 return FALSE;
409
410         return TRUE;
411 }
412
413 static DBusHandlerResult generic_message(DBusConnection *connection,
414                                         DBusMessage *message, void *user_data)
415 {
416         struct generic_data *data = user_data;
417         struct interface_data *iface;
418         const GDBusMethodTable *method;
419         const char *interface;
420
421         interface = dbus_message_get_interface(message);
422
423         iface = find_interface(data->interfaces, interface);
424         if (iface == NULL)
425                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
426
427         for (method = iface->methods; method &&
428                         method->name && method->function; method++) {
429                 if (dbus_message_is_method_call(message, iface->name,
430                                                         method->name) == FALSE)
431                         continue;
432
433                 if (g_dbus_args_have_signature(method->in_args,
434                                                         message) == FALSE)
435                         continue;
436
437                 if (check_privilege(connection, message, method,
438                                                 iface->user_data) == TRUE)
439                         return DBUS_HANDLER_RESULT_HANDLED;
440
441                 return process_message(connection, message, method,
442                                                         iface->user_data);
443         }
444
445         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
446 }
447
448 static DBusObjectPathVTable generic_table = {
449         .unregister_function    = generic_unregister,
450         .message_function       = generic_message,
451 };
452
453 static void invalidate_parent_data(DBusConnection *conn, const char *child_path)
454 {
455         struct generic_data *data = NULL;
456         char *parent_path, *slash;
457
458         parent_path = g_strdup(child_path);
459         slash = strrchr(parent_path, '/');
460         if (slash == NULL)
461                 goto done;
462
463         if (slash == parent_path && parent_path[1] != '\0')
464                 parent_path[1] = '\0';
465         else
466                 *slash = '\0';
467
468         if (!strlen(parent_path))
469                 goto done;
470
471         if (dbus_connection_get_object_path_data(conn, parent_path,
472                                                         (void *) &data) == FALSE) {
473                 goto done;
474         }
475
476         invalidate_parent_data(conn, parent_path);
477
478         if (data == NULL)
479                 goto done;
480
481         g_free(data->introspect);
482         data->introspect = NULL;
483
484 done:
485         g_free(parent_path);
486 }
487
488 static const GDBusMethodTable introspect_methods[] = {
489         { GDBUS_METHOD("Introspect", NULL,
490                         GDBUS_ARGS({ "xml", "s" }), introspect) },
491         { }
492 };
493
494 static void add_interface(struct generic_data *data, const char *name,
495                                 const GDBusMethodTable *methods,
496                                 const GDBusSignalTable *signals,
497                                 const GDBusPropertyTable *properties,
498                                 void *user_data,
499                                 GDBusDestroyFunction destroy)
500 {
501         struct interface_data *iface;
502
503         iface = g_new0(struct interface_data, 1);
504         iface->name = g_strdup(name);
505         iface->methods = methods;
506         iface->signals = signals;
507         iface->properties = properties;
508         iface->user_data = user_data;
509         iface->destroy = destroy;
510
511         data->interfaces = g_slist_append(data->interfaces, iface);
512 }
513
514 static struct generic_data *object_path_ref(DBusConnection *connection,
515                                                         const char *path)
516 {
517         struct generic_data *data;
518
519         if (dbus_connection_get_object_path_data(connection, path,
520                                                 (void *) &data) == TRUE) {
521                 if (data != NULL) {
522                         data->refcount++;
523                         return data;
524                 }
525         }
526
527         data = g_new0(struct generic_data, 1);
528         data->refcount = 1;
529
530         data->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<node></node>");
531
532         if (!dbus_connection_register_object_path(connection, path,
533                                                 &generic_table, data)) {
534                 g_free(data->introspect);
535                 g_free(data);
536                 return NULL;
537         }
538
539         invalidate_parent_data(connection, path);
540
541         add_interface(data, DBUS_INTERFACE_INTROSPECTABLE,
542                         introspect_methods, NULL, NULL, data, NULL);
543
544         return data;
545 }
546
547 static gboolean remove_interface(struct generic_data *data, const char *name)
548 {
549         struct interface_data *iface;
550
551         iface = find_interface(data->interfaces, name);
552         if (iface == NULL)
553                 return FALSE;
554
555         data->interfaces = g_slist_remove(data->interfaces, iface);
556
557         if (iface->destroy)
558                 iface->destroy(iface->user_data);
559
560         g_free(iface->name);
561         g_free(iface);
562
563         return TRUE;
564 }
565
566 static void object_path_unref(DBusConnection *connection, const char *path)
567 {
568         struct generic_data *data = NULL;
569
570         if (dbus_connection_get_object_path_data(connection, path,
571                                                 (void *) &data) == FALSE)
572                 return;
573
574         if (data == NULL)
575                 return;
576
577         data->refcount--;
578
579         if (data->refcount > 0)
580                 return;
581
582         remove_interface(data, DBUS_INTERFACE_INTROSPECTABLE);
583
584         invalidate_parent_data(connection, path);
585
586         dbus_connection_unregister_object_path(connection, path);
587 }
588
589 static gboolean check_signal(DBusConnection *conn, const char *path,
590                                 const char *interface, const char *name,
591                                 const GDBusArgInfo **args)
592 {
593         struct generic_data *data = NULL;
594         struct interface_data *iface;
595         const GDBusSignalTable *signal;
596
597         *args = NULL;
598         if (!dbus_connection_get_object_path_data(conn, path,
599                                         (void *) &data) || data == NULL) {
600                 error("dbus_connection_emit_signal: path %s isn't registered",
601                                 path);
602                 return FALSE;
603         }
604
605         iface = find_interface(data->interfaces, interface);
606         if (iface == NULL) {
607                 error("dbus_connection_emit_signal: %s does not implement %s",
608                                 path, interface);
609                 return FALSE;
610         }
611
612         for (signal = iface->signals; signal && signal->name; signal++) {
613                 if (!strcmp(signal->name, name)) {
614                         *args = signal->args;
615                         return TRUE;
616                 }
617         }
618
619         error("No signal named %s on interface %s", name, interface);
620         return FALSE;
621 }
622
623 static dbus_bool_t emit_signal_valist(DBusConnection *conn,
624                                                 const char *path,
625                                                 const char *interface,
626                                                 const char *name,
627                                                 int first,
628                                                 va_list var_args)
629 {
630         DBusMessage *signal;
631         dbus_bool_t ret;
632         const GDBusArgInfo *args;
633
634         if (!check_signal(conn, path, interface, name, &args))
635                 return FALSE;
636
637         signal = dbus_message_new_signal(path, interface, name);
638         if (signal == NULL) {
639                 error("Unable to allocate new %s.%s signal", interface,  name);
640                 return FALSE;
641         }
642
643         ret = dbus_message_append_args_valist(signal, first, var_args);
644         if (!ret)
645                 goto fail;
646
647         if (g_dbus_args_have_signature(args, signal) == FALSE) {
648                 error("%s.%s: expected signature'%s' but got '%s'",
649                                 interface, name, args, signature);
650                 ret = FALSE;
651                 goto fail;
652         }
653
654         ret = dbus_connection_send(conn, signal, NULL);
655
656 fail:
657         dbus_message_unref(signal);
658
659         return ret;
660 }
661
662 gboolean g_dbus_register_interface(DBusConnection *connection,
663                                         const char *path, const char *name,
664                                         const GDBusMethodTable *methods,
665                                         const GDBusSignalTable *signals,
666                                         const GDBusPropertyTable *properties,
667                                         void *user_data,
668                                         GDBusDestroyFunction destroy)
669 {
670         struct generic_data *data;
671
672         data = object_path_ref(connection, path);
673         if (data == NULL)
674                 return FALSE;
675
676         if (find_interface(data->interfaces, name)) {
677                 object_path_unref(connection, path);
678                 return FALSE;
679         }
680
681         add_interface(data, name, methods, signals,
682                         properties, user_data, destroy);
683
684         g_free(data->introspect);
685         data->introspect = NULL;
686
687         return TRUE;
688 }
689
690 gboolean g_dbus_unregister_interface(DBusConnection *connection,
691                                         const char *path, const char *name)
692 {
693         struct generic_data *data = NULL;
694
695         if (path == NULL)
696                 return FALSE;
697
698         if (dbus_connection_get_object_path_data(connection, path,
699                                                 (void *) &data) == FALSE)
700                 return FALSE;
701
702         if (data == NULL)
703                 return FALSE;
704
705         if (remove_interface(data, name) == FALSE)
706                 return FALSE;
707
708         g_free(data->introspect);
709         data->introspect = NULL;
710
711         object_path_unref(connection, path);
712
713         return TRUE;
714 }
715
716 gboolean g_dbus_register_security(const GDBusSecurityTable *security)
717 {
718         if (security_table != NULL)
719                 return FALSE;
720
721         security_table = security;
722
723         return TRUE;
724 }
725
726 gboolean g_dbus_unregister_security(const GDBusSecurityTable *security)
727 {
728         security_table = NULL;
729
730         return TRUE;
731 }
732
733 DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name,
734                                         const char *format, va_list args)
735 {
736         char str[1024];
737
738         vsnprintf(str, sizeof(str), format, args);
739
740         return dbus_message_new_error(message, name, str);
741 }
742
743 DBusMessage *g_dbus_create_error(DBusMessage *message, const char *name,
744                                                 const char *format, ...)
745 {
746         va_list args;
747         DBusMessage *reply;
748
749         va_start(args, format);
750
751         reply = g_dbus_create_error_valist(message, name, format, args);
752
753         va_end(args);
754
755         return reply;
756 }
757
758 DBusMessage *g_dbus_create_reply_valist(DBusMessage *message,
759                                                 int type, va_list args)
760 {
761         DBusMessage *reply;
762
763         reply = dbus_message_new_method_return(message);
764         if (reply == NULL)
765                 return NULL;
766
767         if (dbus_message_append_args_valist(reply, type, args) == FALSE) {
768                 dbus_message_unref(reply);
769                 return NULL;
770         }
771
772         return reply;
773 }
774
775 DBusMessage *g_dbus_create_reply(DBusMessage *message, int type, ...)
776 {
777         va_list args;
778         DBusMessage *reply;
779
780         va_start(args, type);
781
782         reply = g_dbus_create_reply_valist(message, type, args);
783
784         va_end(args);
785
786         return reply;
787 }
788
789 gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message)
790 {
791         dbus_bool_t result;
792
793         if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
794                 dbus_message_set_no_reply(message, TRUE);
795
796         result = dbus_connection_send(connection, message, NULL);
797
798         dbus_message_unref(message);
799
800         return result;
801 }
802
803 gboolean g_dbus_send_reply_valist(DBusConnection *connection,
804                                 DBusMessage *message, int type, va_list args)
805 {
806         DBusMessage *reply;
807
808         reply = dbus_message_new_method_return(message);
809         if (reply == NULL)
810                 return FALSE;
811
812         if (dbus_message_append_args_valist(reply, type, args) == FALSE) {
813                 dbus_message_unref(reply);
814                 return FALSE;
815         }
816
817         return g_dbus_send_message(connection, reply);
818 }
819
820 gboolean g_dbus_send_reply(DBusConnection *connection,
821                                 DBusMessage *message, int type, ...)
822 {
823         va_list args;
824         gboolean result;
825
826         va_start(args, type);
827
828         result = g_dbus_send_reply_valist(connection, message, type, args);
829
830         va_end(args);
831
832         return result;
833 }
834
835 gboolean g_dbus_emit_signal(DBusConnection *connection,
836                                 const char *path, const char *interface,
837                                 const char *name, int type, ...)
838 {
839         va_list args;
840         gboolean result;
841
842         va_start(args, type);
843
844         result = emit_signal_valist(connection, path, interface,
845                                                         name, type, args);
846
847         va_end(args);
848
849         return result;
850 }
851
852 gboolean g_dbus_emit_signal_valist(DBusConnection *connection,
853                                 const char *path, const char *interface,
854                                 const char *name, int type, va_list args)
855 {
856         return emit_signal_valist(connection, path, interface,
857                                                         name, type, args);
858 }