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