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