gdbus: Introduce G_DBUS_PROPERTY_FLAG_EXPERIMENTAL
[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 #define DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager"
41
42 #ifndef DBUS_ERROR_UNKNOWN_PROPERTY
43 #define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty"
44 #endif
45
46 #ifndef DBUS_ERROR_PROPERTY_READ_ONLY
47 #define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly"
48 #endif
49
50 struct generic_data {
51         unsigned int refcount;
52         DBusConnection *conn;
53         char *path;
54         GSList *interfaces;
55         GSList *objects;
56         GSList *added;
57         GSList *removed;
58         guint process_id;
59         gboolean pending_prop;
60         char *introspect;
61         struct generic_data *parent;
62 };
63
64 struct interface_data {
65         char *name;
66         const GDBusMethodTable *methods;
67         const GDBusSignalTable *signals;
68         const GDBusPropertyTable *properties;
69         GSList *pending_prop;
70         void *user_data;
71         GDBusDestroyFunction destroy;
72 };
73
74 struct security_data {
75         GDBusPendingReply pending;
76         DBusMessage *message;
77         const GDBusMethodTable *method;
78         void *iface_user_data;
79 };
80
81 struct property_data {
82         DBusConnection *conn;
83         GDBusPendingPropertySet id;
84         DBusMessage *message;
85 };
86
87 static int global_flags = 0;
88 static struct generic_data *root;
89
90 static gboolean process_changes(gpointer user_data);
91 static void process_properties_from_interface(struct generic_data *data,
92                                                 struct interface_data *iface);
93 static void process_property_changes(struct generic_data *data);
94
95 static void print_arguments(GString *gstr, const GDBusArgInfo *args,
96                                                 const char *direction)
97 {
98         for (; args && args->name; args++) {
99                 g_string_append_printf(gstr,
100                                         "\t\t\t<arg name=\"%s\" type=\"%s\"",
101                                         args->name, args->signature);
102
103                 if (direction)
104                         g_string_append_printf(gstr,
105                                         " direction=\"%s\"/>\n", direction);
106                 else
107                         g_string_append_printf(gstr, "/>\n");
108
109         }
110 }
111
112 #define G_DBUS_ANNOTATE(prefix_, name_, value_)                         \
113         prefix_ "<annotation name=\"org.freedesktop.DBus." name_ "\" "  \
114         "value=\"" value_ "\"/>\n"
115
116 #define G_DBUS_ANNOTATE_DEPRECATED(prefix_) \
117         G_DBUS_ANNOTATE(prefix_, "Deprecated", "true")
118
119 #define G_DBUS_ANNOTATE_NOREPLY(prefix_) \
120         G_DBUS_ANNOTATE(prefix_, "Method.NoReply", "true")
121
122 static gboolean check_experimental(int flags, int flag)
123 {
124         if (!(flags & flag))
125                 return FALSE;
126
127         return !(global_flags & G_DBUS_FLAG_ENABLE_EXPERIMENTAL);
128 }
129
130 static void generate_interface_xml(GString *gstr, struct interface_data *iface)
131 {
132         const GDBusMethodTable *method;
133         const GDBusSignalTable *signal;
134         const GDBusPropertyTable *property;
135
136         for (method = iface->methods; method && method->name; method++) {
137                 gboolean deprecated = method->flags &
138                                                 G_DBUS_METHOD_FLAG_DEPRECATED;
139                 gboolean noreply = method->flags &
140                                                 G_DBUS_METHOD_FLAG_NOREPLY;
141
142                 if (check_experimental(method->flags,
143                                         G_DBUS_METHOD_FLAG_EXPERIMENTAL))
144                         continue;
145
146                 if (!deprecated && !noreply &&
147                                 !(method->in_args && method->in_args->name) &&
148                                 !(method->out_args && method->out_args->name))
149                         g_string_append_printf(gstr,
150                                                 "\t\t<method name=\"%s\"/>\n",
151                                                 method->name);
152                 else {
153                         g_string_append_printf(gstr,
154                                                 "\t\t<method name=\"%s\">\n",
155                                                 method->name);
156                         print_arguments(gstr, method->in_args, "in");
157                         print_arguments(gstr, method->out_args, "out");
158
159                         if (deprecated)
160                                 g_string_append_printf(gstr,
161                                         G_DBUS_ANNOTATE_DEPRECATED("\t\t\t"));
162                         if (noreply)
163                                 g_string_append_printf(gstr,
164                                         G_DBUS_ANNOTATE_NOREPLY("\t\t\t"));
165
166                         g_string_append_printf(gstr, "\t\t</method>\n");
167                 }
168         }
169
170         for (signal = iface->signals; signal && signal->name; signal++) {
171                 gboolean deprecated = signal->flags &
172                                                 G_DBUS_SIGNAL_FLAG_DEPRECATED;
173
174                 if (check_experimental(signal->flags,
175                                         G_DBUS_SIGNAL_FLAG_EXPERIMENTAL))
176                         continue;
177
178                 if (!deprecated && !(signal->args && signal->args->name))
179                         g_string_append_printf(gstr,
180                                                 "\t\t<signal name=\"%s\"/>\n",
181                                                 signal->name);
182                 else {
183                         g_string_append_printf(gstr,
184                                                 "\t\t<signal name=\"%s\">\n",
185                                                 signal->name);
186                         print_arguments(gstr, signal->args, NULL);
187
188                         if (deprecated)
189                                 g_string_append_printf(gstr,
190                                         G_DBUS_ANNOTATE_DEPRECATED("\t\t\t"));
191
192                         g_string_append_printf(gstr, "\t\t</signal>\n");
193                 }
194         }
195
196         for (property = iface->properties; property && property->name;
197                                                                 property++) {
198                 gboolean deprecated = property->flags &
199                                         G_DBUS_PROPERTY_FLAG_DEPRECATED;
200
201                 if (check_experimental(property->flags,
202                                         G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
203                         continue;
204
205                 g_string_append_printf(gstr, "\t\t<property name=\"%s\""
206                                         " type=\"%s\" access=\"%s%s\"",
207                                         property->name, property->type,
208                                         property->get ? "read" : "",
209                                         property->set ? "write" : "");
210
211                 if (!deprecated)
212                         g_string_append_printf(gstr, "/>\n");
213                 else
214                         g_string_append_printf(gstr,
215                                 G_DBUS_ANNOTATE_DEPRECATED(">\n\t\t\t"));
216         }
217 }
218
219 static void generate_introspection_xml(DBusConnection *conn,
220                                 struct generic_data *data, const char *path)
221 {
222         GSList *list;
223         GString *gstr;
224         char **children;
225         int i;
226
227         g_free(data->introspect);
228
229         gstr = g_string_new(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
230
231         g_string_append_printf(gstr, "<node>\n");
232
233         for (list = data->interfaces; list; list = list->next) {
234                 struct interface_data *iface = list->data;
235
236                 g_string_append_printf(gstr, "\t<interface name=\"%s\">\n",
237                                                                 iface->name);
238
239                 generate_interface_xml(gstr, iface);
240
241                 g_string_append_printf(gstr, "\t</interface>\n");
242         }
243
244         if (!dbus_connection_list_registered(conn, path, &children))
245                 goto done;
246
247         for (i = 0; children[i]; i++)
248                 g_string_append_printf(gstr, "\t<node name=\"%s\"/>\n",
249                                                                 children[i]);
250
251         dbus_free_string_array(children);
252
253 done:
254         g_string_append_printf(gstr, "</node>\n");
255
256         data->introspect = g_string_free(gstr, FALSE);
257 }
258
259 static DBusMessage *introspect(DBusConnection *connection,
260                                 DBusMessage *message, void *user_data)
261 {
262         struct generic_data *data = user_data;
263         DBusMessage *reply;
264
265         if (data->introspect == NULL)
266                 generate_introspection_xml(connection, data,
267                                                 dbus_message_get_path(message));
268
269         reply = dbus_message_new_method_return(message);
270         if (reply == NULL)
271                 return NULL;
272
273         dbus_message_append_args(reply, DBUS_TYPE_STRING, &data->introspect,
274                                         DBUS_TYPE_INVALID);
275
276         return reply;
277 }
278
279 static DBusHandlerResult process_message(DBusConnection *connection,
280                         DBusMessage *message, const GDBusMethodTable *method,
281                                                         void *iface_user_data)
282 {
283         DBusMessage *reply;
284
285         reply = method->function(connection, message, iface_user_data);
286
287         if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY) {
288                 if (reply != NULL)
289                         dbus_message_unref(reply);
290                 return DBUS_HANDLER_RESULT_HANDLED;
291         }
292
293         if (method->flags & G_DBUS_METHOD_FLAG_ASYNC) {
294                 if (reply == NULL)
295                         return DBUS_HANDLER_RESULT_HANDLED;
296         }
297
298         if (reply == NULL)
299                 return DBUS_HANDLER_RESULT_NEED_MEMORY;
300
301         dbus_connection_send(connection, reply, NULL);
302         dbus_message_unref(reply);
303
304         return DBUS_HANDLER_RESULT_HANDLED;
305 }
306
307 static GDBusPendingReply next_pending = 1;
308 static GSList *pending_security = NULL;
309
310 static const GDBusSecurityTable *security_table = NULL;
311
312 void g_dbus_pending_success(DBusConnection *connection,
313                                         GDBusPendingReply pending)
314 {
315         GSList *list;
316
317         for (list = pending_security; list; list = list->next) {
318                 struct security_data *secdata = list->data;
319
320                 if (secdata->pending != pending)
321                         continue;
322
323                 pending_security = g_slist_remove(pending_security, secdata);
324
325                 process_message(connection, secdata->message,
326                                 secdata->method, secdata->iface_user_data);
327
328                 dbus_message_unref(secdata->message);
329                 g_free(secdata);
330                 return;
331         }
332 }
333
334 void g_dbus_pending_error_valist(DBusConnection *connection,
335                                 GDBusPendingReply pending, const char *name,
336                                         const char *format, va_list args)
337 {
338         GSList *list;
339
340         for (list = pending_security; list; list = list->next) {
341                 struct security_data *secdata = list->data;
342                 DBusMessage *reply;
343
344                 if (secdata->pending != pending)
345                         continue;
346
347                 pending_security = g_slist_remove(pending_security, secdata);
348
349                 reply = g_dbus_create_error_valist(secdata->message,
350                                                         name, format, args);
351                 if (reply != NULL) {
352                         dbus_connection_send(connection, reply, NULL);
353                         dbus_message_unref(reply);
354                 }
355
356                 dbus_message_unref(secdata->message);
357                 g_free(secdata);
358                 return;
359         }
360 }
361
362 void g_dbus_pending_error(DBusConnection *connection,
363                                 GDBusPendingReply pending,
364                                 const char *name, const char *format, ...)
365 {
366         va_list args;
367
368         va_start(args, format);
369
370         g_dbus_pending_error_valist(connection, pending, name, format, args);
371
372         va_end(args);
373 }
374
375 int polkit_check_authorization(DBusConnection *conn,
376                                 const char *action, gboolean interaction,
377                                 void (*function) (dbus_bool_t authorized,
378                                                         void *user_data),
379                                                 void *user_data, int timeout);
380
381 struct builtin_security_data {
382         DBusConnection *conn;
383         GDBusPendingReply pending;
384 };
385
386 static void builtin_security_result(dbus_bool_t authorized, void *user_data)
387 {
388         struct builtin_security_data *data = user_data;
389
390         if (authorized == TRUE)
391                 g_dbus_pending_success(data->conn, data->pending);
392         else
393                 g_dbus_pending_error(data->conn, data->pending,
394                                                 DBUS_ERROR_AUTH_FAILED, NULL);
395
396         g_free(data);
397 }
398
399 static void builtin_security_function(DBusConnection *conn,
400                                                 const char *action,
401                                                 gboolean interaction,
402                                                 GDBusPendingReply pending)
403 {
404         struct builtin_security_data *data;
405
406         data = g_new0(struct builtin_security_data, 1);
407         data->conn = conn;
408         data->pending = pending;
409
410         if (polkit_check_authorization(conn, action, interaction,
411                                 builtin_security_result, data, 30000) < 0)
412                 g_dbus_pending_error(conn, pending, NULL, NULL);
413 }
414
415 static gboolean check_privilege(DBusConnection *conn, DBusMessage *msg,
416                         const GDBusMethodTable *method, void *iface_user_data)
417 {
418         const GDBusSecurityTable *security;
419
420         for (security = security_table; security && security->privilege;
421                                                                 security++) {
422                 struct security_data *secdata;
423                 gboolean interaction;
424
425                 if (security->privilege != method->privilege)
426                         continue;
427
428                 secdata = g_new(struct security_data, 1);
429                 secdata->pending = next_pending++;
430                 secdata->message = dbus_message_ref(msg);
431                 secdata->method = method;
432                 secdata->iface_user_data = iface_user_data;
433
434                 pending_security = g_slist_prepend(pending_security, secdata);
435
436                 if (security->flags & G_DBUS_SECURITY_FLAG_ALLOW_INTERACTION)
437                         interaction = TRUE;
438                 else
439                         interaction = FALSE;
440
441                 if (!(security->flags & G_DBUS_SECURITY_FLAG_BUILTIN) &&
442                                                         security->function)
443                         security->function(conn, security->action,
444                                                 interaction, secdata->pending);
445                 else
446                         builtin_security_function(conn, security->action,
447                                                 interaction, secdata->pending);
448
449                 return TRUE;
450         }
451
452         return FALSE;
453 }
454
455 static GDBusPendingPropertySet next_pending_property = 1;
456 static GSList *pending_property_set;
457
458 static struct property_data *remove_pending_property_data(
459                                                 GDBusPendingPropertySet id)
460 {
461         struct property_data *propdata;
462         GSList *l;
463
464         for (l = pending_property_set; l != NULL; l = l->next) {
465                 propdata = l->data;
466                 if (propdata->id != id)
467                         continue;
468
469                 break;
470         }
471
472         if (l == NULL)
473                 return NULL;
474
475         pending_property_set = g_slist_delete_link(pending_property_set, l);
476
477         return propdata;
478 }
479
480 void g_dbus_pending_property_success(GDBusPendingPropertySet id)
481 {
482         struct property_data *propdata;
483
484         propdata = remove_pending_property_data(id);
485         if (propdata == NULL)
486                 return;
487
488         g_dbus_send_reply(propdata->conn, propdata->message,
489                                                         DBUS_TYPE_INVALID);
490         dbus_message_unref(propdata->message);
491         g_free(propdata);
492 }
493
494 void g_dbus_pending_property_error_valist(GDBusPendingReply id,
495                                         const char *name, const char *format,
496                                         va_list args)
497 {
498         struct property_data *propdata;
499         DBusMessage *reply;
500
501         propdata = remove_pending_property_data(id);
502         if (propdata == NULL)
503                 return;
504
505         reply = g_dbus_create_error_valist(propdata->message, name, format,
506                                                                         args);
507         if (reply != NULL) {
508                 dbus_connection_send(propdata->conn, reply, NULL);
509                 dbus_message_unref(reply);
510         }
511
512         dbus_message_unref(propdata->message);
513         g_free(propdata);
514 }
515
516 void g_dbus_pending_property_error(GDBusPendingReply id, const char *name,
517                                                 const char *format, ...)
518 {
519         va_list args;
520
521         va_start(args, format);
522
523         g_dbus_pending_property_error_valist(id, name, format, args);
524
525         va_end(args);
526 }
527
528 static void reset_parent(gpointer data, gpointer user_data)
529 {
530         struct generic_data *child = data;
531         struct generic_data *parent = user_data;
532
533         child->parent = parent;
534 }
535
536 static void append_property(struct interface_data *iface,
537                         const GDBusPropertyTable *p, DBusMessageIter *dict)
538 {
539         DBusMessageIter entry, value;
540
541         dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
542                                                                 &entry);
543         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &p->name);
544         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, p->type,
545                                                                 &value);
546
547         p->get(p, &value, iface->user_data);
548
549         dbus_message_iter_close_container(&entry, &value);
550         dbus_message_iter_close_container(dict, &entry);
551 }
552
553 static void append_properties(struct interface_data *data,
554                                                         DBusMessageIter *iter)
555 {
556         DBusMessageIter dict;
557         const GDBusPropertyTable *p;
558
559         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
560                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
561                                 DBUS_TYPE_STRING_AS_STRING
562                                 DBUS_TYPE_VARIANT_AS_STRING
563                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
564
565         for (p = data->properties; p && p->name; p++) {
566                 if (check_experimental(p->flags,
567                                         G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
568                         continue;
569
570                 if (p->get == NULL)
571                         continue;
572
573                 if (p->exists != NULL && !p->exists(p, data->user_data))
574                         continue;
575
576                 append_property(data, p, &dict);
577         }
578
579         dbus_message_iter_close_container(iter, &dict);
580 }
581
582 static void append_interface(gpointer data, gpointer user_data)
583 {
584         struct interface_data *iface = data;
585         DBusMessageIter *array = user_data;
586         DBusMessageIter entry;
587
588         dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
589                                                                 &entry);
590         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &iface->name);
591         append_properties(data, &entry);
592         dbus_message_iter_close_container(array, &entry);
593 }
594
595 static void emit_interfaces_added(struct generic_data *data)
596 {
597         DBusMessage *signal;
598         DBusMessageIter iter, array;
599
600         if (root == NULL || data == root)
601                 return;
602
603         signal = dbus_message_new_signal(root->path,
604                                         DBUS_INTERFACE_OBJECT_MANAGER,
605                                         "InterfacesAdded");
606         if (signal == NULL)
607                 return;
608
609         dbus_message_iter_init_append(signal, &iter);
610         dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
611                                                                 &data->path);
612
613         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
614                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
615                                 DBUS_TYPE_STRING_AS_STRING
616                                 DBUS_TYPE_ARRAY_AS_STRING
617                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
618                                 DBUS_TYPE_STRING_AS_STRING
619                                 DBUS_TYPE_VARIANT_AS_STRING
620                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING
621                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
622
623         g_slist_foreach(data->added, append_interface, &array);
624         g_slist_free(data->added);
625         data->added = NULL;
626
627         dbus_message_iter_close_container(&iter, &array);
628
629         g_dbus_send_message(data->conn, signal);
630 }
631
632 static struct interface_data *find_interface(GSList *interfaces,
633                                                 const char *name)
634 {
635         GSList *list;
636
637         if (name == NULL)
638                 return NULL;
639
640         for (list = interfaces; list; list = list->next) {
641                 struct interface_data *iface = list->data;
642                 if (!strcmp(name, iface->name))
643                         return iface;
644         }
645
646         return NULL;
647 }
648
649 static gboolean g_dbus_args_have_signature(const GDBusArgInfo *args,
650                                                         DBusMessage *message)
651 {
652         const char *sig = dbus_message_get_signature(message);
653         const char *p = NULL;
654
655         for (; args && args->signature && *sig; args++) {
656                 p = args->signature;
657
658                 for (; *sig && *p; sig++, p++) {
659                         if (*p != *sig)
660                                 return FALSE;
661                 }
662         }
663
664         if (*sig || (p && *p) || (args && args->signature))
665                 return FALSE;
666
667         return TRUE;
668 }
669
670 static gboolean remove_interface(struct generic_data *data, const char *name)
671 {
672         struct interface_data *iface;
673
674         iface = find_interface(data->interfaces, name);
675         if (iface == NULL)
676                 return FALSE;
677
678         process_properties_from_interface(data, iface);
679
680         data->interfaces = g_slist_remove(data->interfaces, iface);
681
682         if (iface->destroy) {
683                 iface->destroy(iface->user_data);
684                 iface->user_data = NULL;
685         }
686
687         /*
688          * Interface being removed was just added, on the same mainloop
689          * iteration? Don't send any signal
690          */
691         if (g_slist_find(data->added, iface)) {
692                 data->added = g_slist_remove(data->added, iface);
693                 g_free(iface->name);
694                 g_free(iface);
695                 return TRUE;
696         }
697
698         if (data->parent == NULL) {
699                 g_free(iface->name);
700                 g_free(iface);
701                 return TRUE;
702         }
703
704         data->removed = g_slist_prepend(data->removed, iface->name);
705         g_free(iface);
706
707         if (data->process_id > 0)
708                 return TRUE;
709
710         data->process_id = g_idle_add(process_changes, data);
711
712         return TRUE;
713 }
714
715 static struct generic_data *invalidate_parent_data(DBusConnection *conn,
716                                                 const char *child_path)
717 {
718         struct generic_data *data = NULL, *child = NULL, *parent = NULL;
719         char *parent_path, *slash;
720
721         parent_path = g_strdup(child_path);
722         slash = strrchr(parent_path, '/');
723         if (slash == NULL)
724                 goto done;
725
726         if (slash == parent_path && parent_path[1] != '\0')
727                 parent_path[1] = '\0';
728         else
729                 *slash = '\0';
730
731         if (!strlen(parent_path))
732                 goto done;
733
734         if (dbus_connection_get_object_path_data(conn, parent_path,
735                                                         (void *) &data) == FALSE) {
736                 goto done;
737         }
738
739         parent = invalidate_parent_data(conn, parent_path);
740
741         if (data == NULL) {
742                 data = parent;
743                 if (data == NULL)
744                         goto done;
745         }
746
747         g_free(data->introspect);
748         data->introspect = NULL;
749
750         if (!dbus_connection_get_object_path_data(conn, child_path,
751                                                         (void *) &child))
752                 goto done;
753
754         if (child == NULL || g_slist_find(data->objects, child) != NULL)
755                 goto done;
756
757         data->objects = g_slist_prepend(data->objects, child);
758         child->parent = data;
759
760 done:
761         g_free(parent_path);
762         return data;
763 }
764
765 static inline const GDBusPropertyTable *find_property(const GDBusPropertyTable *properties,
766                                                         const char *name)
767 {
768         const GDBusPropertyTable *p;
769
770         for (p = properties; p && p->name; p++) {
771                 if (strcmp(name, p->name) != 0)
772                         continue;
773
774                 if (check_experimental(p->flags,
775                                         G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
776                         break;
777
778                 return p;
779         }
780
781         return NULL;
782 }
783
784 static DBusMessage *properties_get(DBusConnection *connection,
785                                         DBusMessage *message, void *user_data)
786 {
787         struct generic_data *data = user_data;
788         struct interface_data *iface;
789         const GDBusPropertyTable *property;
790         const char *interface, *name;
791         DBusMessageIter iter, value;
792         DBusMessage *reply;
793
794         if (!dbus_message_get_args(message, NULL,
795                                         DBUS_TYPE_STRING, &interface,
796                                         DBUS_TYPE_STRING, &name,
797                                         DBUS_TYPE_INVALID))
798                 return NULL;
799
800         iface = find_interface(data->interfaces, interface);
801         if (iface == NULL)
802                 return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
803                                 "No such interface '%s'", interface);
804
805         property = find_property(iface->properties, name);
806         if (property == NULL)
807                 return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
808                                 "No such property '%s'", name);
809
810         if (property->exists != NULL &&
811                         !property->exists(property, iface->user_data))
812                 return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
813                                         "No such property '%s'", name);
814
815         if (property->get == NULL)
816                 return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
817                                 "Property '%s' is not readable", name);
818
819         reply = dbus_message_new_method_return(message);
820         if (reply == NULL)
821                 return NULL;
822
823         dbus_message_iter_init_append(reply, &iter);
824         dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
825                                                 property->type, &value);
826
827         if (!property->get(property, &value, iface->user_data)) {
828                 dbus_message_unref(reply);
829                 return NULL;
830         }
831
832         dbus_message_iter_close_container(&iter, &value);
833
834         return reply;
835 }
836
837 static DBusMessage *properties_get_all(DBusConnection *connection,
838                                         DBusMessage *message, void *user_data)
839 {
840         struct generic_data *data = user_data;
841         struct interface_data *iface;
842         const char *interface;
843         DBusMessageIter iter;
844         DBusMessage *reply;
845
846         if (!dbus_message_get_args(message, NULL,
847                                         DBUS_TYPE_STRING, &interface,
848                                         DBUS_TYPE_INVALID))
849                 return NULL;
850
851         iface = find_interface(data->interfaces, interface);
852         if (iface == NULL)
853                 return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
854                                         "No such interface '%s'", interface);
855
856         reply = dbus_message_new_method_return(message);
857         if (reply == NULL)
858                 return NULL;
859
860         dbus_message_iter_init_append(reply, &iter);
861
862         append_properties(iface, &iter);
863
864         return reply;
865 }
866
867 static DBusMessage *properties_set(DBusConnection *connection,
868                                         DBusMessage *message, void *user_data)
869 {
870         struct generic_data *data = user_data;
871         DBusMessageIter iter, sub;
872         struct interface_data *iface;
873         const GDBusPropertyTable *property;
874         const char *name, *interface;
875         struct property_data *propdata;
876
877         if (!dbus_message_iter_init(message, &iter))
878                 return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
879                                                         "No arguments given");
880
881         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
882                 return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
883                                         "Invalid argument type: '%c'",
884                                         dbus_message_iter_get_arg_type(&iter));
885
886         dbus_message_iter_get_basic(&iter, &interface);
887         dbus_message_iter_next(&iter);
888
889         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
890                 return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
891                                         "Invalid argument type: '%c'",
892                                         dbus_message_iter_get_arg_type(&iter));
893
894         dbus_message_iter_get_basic(&iter, &name);
895         dbus_message_iter_next(&iter);
896
897         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
898                 return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
899                                         "Invalid argument type: '%c'",
900                                         dbus_message_iter_get_arg_type(&iter));
901
902         dbus_message_iter_recurse(&iter, &sub);
903
904         iface = find_interface(data->interfaces, interface);
905         if (iface == NULL)
906                 return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
907                                         "No such interface '%s'", interface);
908
909         property = find_property(iface->properties, name);
910         if (property == NULL)
911                 return g_dbus_create_error(message,
912                                                 DBUS_ERROR_UNKNOWN_PROPERTY,
913                                                 "No such property '%s'", name);
914
915         if (property->set == NULL)
916                 return g_dbus_create_error(message,
917                                         DBUS_ERROR_PROPERTY_READ_ONLY,
918                                         "Property '%s' is not writable", name);
919
920         if (property->exists != NULL &&
921                         !property->exists(property, iface->user_data))
922                 return g_dbus_create_error(message,
923                                                 DBUS_ERROR_UNKNOWN_PROPERTY,
924                                                 "No such property '%s'", name);
925
926         propdata = g_new(struct property_data, 1);
927         propdata->id = next_pending_property++;
928         propdata->message = dbus_message_ref(message);
929         propdata->conn = connection;
930         pending_property_set = g_slist_prepend(pending_property_set, propdata);
931
932         property->set(property, &sub, propdata->id, iface->user_data);
933
934         return NULL;
935 }
936
937 static const GDBusMethodTable properties_methods[] = {
938         { GDBUS_METHOD("Get",
939                         GDBUS_ARGS({ "interface", "s" }, { "name", "s" }),
940                         GDBUS_ARGS({ "value", "v" }),
941                         properties_get) },
942         { GDBUS_ASYNC_METHOD("Set",
943                         GDBUS_ARGS({ "interface", "s" }, { "name", "s" },
944                                                         { "value", "v" }),
945                         NULL,
946                         properties_set) },
947         { GDBUS_METHOD("GetAll",
948                         GDBUS_ARGS({ "interface", "s" }),
949                         GDBUS_ARGS({ "properties", "a{sv}" }),
950                         properties_get_all) },
951         { }
952 };
953
954 static const GDBusSignalTable properties_signals[] = {
955         { GDBUS_SIGNAL("PropertiesChanged",
956                         GDBUS_ARGS({ "interface", "s" },
957                                         { "changed_properties", "a{sv}" },
958                                         { "invalidated_properties", "as"})) },
959         { }
960 };
961
962 static void append_name(gpointer data, gpointer user_data)
963 {
964         char *name = data;
965         DBusMessageIter *iter = user_data;
966
967         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &name);
968 }
969
970 static void emit_interfaces_removed(struct generic_data *data)
971 {
972         DBusMessage *signal;
973         DBusMessageIter iter, array;
974
975         if (root == NULL || data == root)
976                 return;
977
978         signal = dbus_message_new_signal(root->path,
979                                         DBUS_INTERFACE_OBJECT_MANAGER,
980                                         "InterfacesRemoved");
981         if (signal == NULL)
982                 return;
983
984         dbus_message_iter_init_append(signal, &iter);
985         dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
986                                                                 &data->path);
987         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
988                                         DBUS_TYPE_STRING_AS_STRING, &array);
989
990         g_slist_foreach(data->removed, append_name, &array);
991         g_slist_free_full(data->removed, g_free);
992         data->removed = NULL;
993
994         dbus_message_iter_close_container(&iter, &array);
995
996         g_dbus_send_message(data->conn, signal);
997 }
998
999 static gboolean process_changes(gpointer user_data)
1000 {
1001         struct generic_data *data = user_data;
1002
1003         data->process_id = 0;
1004
1005         if (data->added != NULL)
1006                 emit_interfaces_added(data);
1007
1008         /* Flush pending properties */
1009         if (data->pending_prop == TRUE)
1010                 process_property_changes(data);
1011
1012         if (data->removed != NULL)
1013                 emit_interfaces_removed(data);
1014
1015         return FALSE;
1016 }
1017
1018 static void generic_unregister(DBusConnection *connection, void *user_data)
1019 {
1020         struct generic_data *data = user_data;
1021         struct generic_data *parent = data->parent;
1022
1023         if (parent != NULL)
1024                 parent->objects = g_slist_remove(parent->objects, data);
1025
1026         if (data->process_id > 0) {
1027                 g_source_remove(data->process_id);
1028                 process_changes(data);
1029         }
1030
1031         g_slist_foreach(data->objects, reset_parent, data->parent);
1032         g_slist_free(data->objects);
1033
1034         dbus_connection_unref(data->conn);
1035         g_free(data->introspect);
1036         g_free(data->path);
1037         g_free(data);
1038 }
1039
1040 static DBusHandlerResult generic_message(DBusConnection *connection,
1041                                         DBusMessage *message, void *user_data)
1042 {
1043         struct generic_data *data = user_data;
1044         struct interface_data *iface;
1045         const GDBusMethodTable *method;
1046         const char *interface;
1047
1048         interface = dbus_message_get_interface(message);
1049
1050         iface = find_interface(data->interfaces, interface);
1051         if (iface == NULL)
1052                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1053
1054         for (method = iface->methods; method &&
1055                         method->name && method->function; method++) {
1056
1057                 if (dbus_message_is_method_call(message, iface->name,
1058                                                         method->name) == FALSE)
1059                         continue;
1060
1061                 if (check_experimental(method->flags,
1062                                         G_DBUS_METHOD_FLAG_EXPERIMENTAL))
1063                         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1064
1065                 if (g_dbus_args_have_signature(method->in_args,
1066                                                         message) == FALSE)
1067                         continue;
1068
1069                 if (check_privilege(connection, message, method,
1070                                                 iface->user_data) == TRUE)
1071                         return DBUS_HANDLER_RESULT_HANDLED;
1072
1073                 return process_message(connection, message, method,
1074                                                         iface->user_data);
1075         }
1076
1077         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
1078 }
1079
1080 static DBusObjectPathVTable generic_table = {
1081         .unregister_function    = generic_unregister,
1082         .message_function       = generic_message,
1083 };
1084
1085 static const GDBusMethodTable introspect_methods[] = {
1086         { GDBUS_METHOD("Introspect", NULL,
1087                         GDBUS_ARGS({ "xml", "s" }), introspect) },
1088         { }
1089 };
1090
1091 static void append_interfaces(struct generic_data *data, DBusMessageIter *iter)
1092 {
1093         DBusMessageIter array;
1094
1095         dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
1096                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1097                                 DBUS_TYPE_STRING_AS_STRING
1098                                 DBUS_TYPE_ARRAY_AS_STRING
1099                                 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1100                                 DBUS_TYPE_STRING_AS_STRING
1101                                 DBUS_TYPE_VARIANT_AS_STRING
1102                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING
1103                                 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
1104
1105         g_slist_foreach(data->interfaces, append_interface, &array);
1106
1107         dbus_message_iter_close_container(iter, &array);
1108 }
1109
1110 static void append_object(gpointer data, gpointer user_data)
1111 {
1112         struct generic_data *child = data;
1113         DBusMessageIter *array = user_data;
1114         DBusMessageIter entry;
1115
1116         dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
1117                                                                 &entry);
1118         dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
1119                                                                 &child->path);
1120         append_interfaces(child, &entry);
1121         dbus_message_iter_close_container(array, &entry);
1122
1123         g_slist_foreach(child->objects, append_object, user_data);
1124 }
1125
1126 static DBusMessage *get_objects(DBusConnection *connection,
1127                                 DBusMessage *message, void *user_data)
1128 {
1129         struct generic_data *data = user_data;
1130         DBusMessage *reply;
1131         DBusMessageIter iter;
1132         DBusMessageIter array;
1133
1134         reply = dbus_message_new_method_return(message);
1135         if (reply == NULL)
1136                 return NULL;
1137
1138         dbus_message_iter_init_append(reply, &iter);
1139
1140         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
1141                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1142                                         DBUS_TYPE_OBJECT_PATH_AS_STRING
1143                                         DBUS_TYPE_ARRAY_AS_STRING
1144                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1145                                         DBUS_TYPE_STRING_AS_STRING
1146                                         DBUS_TYPE_ARRAY_AS_STRING
1147                                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1148                                         DBUS_TYPE_STRING_AS_STRING
1149                                         DBUS_TYPE_VARIANT_AS_STRING
1150                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING
1151                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING
1152                                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
1153                                         &array);
1154
1155         g_slist_foreach(data->objects, append_object, &array);
1156
1157         dbus_message_iter_close_container(&iter, &array);
1158
1159         return reply;
1160 }
1161
1162 static const GDBusMethodTable manager_methods[] = {
1163         { GDBUS_METHOD("GetManagedObjects", NULL,
1164                 GDBUS_ARGS({ "objects", "a{oa{sa{sv}}}" }), get_objects) },
1165         { }
1166 };
1167
1168 static const GDBusSignalTable manager_signals[] = {
1169         { GDBUS_SIGNAL("InterfacesAdded",
1170                 GDBUS_ARGS({ "object", "o" },
1171                                 { "interfaces", "a{sa{sv}}" })) },
1172         { GDBUS_SIGNAL("InterfacesRemoved",
1173                 GDBUS_ARGS({ "object", "o" }, { "interfaces", "as" })) },
1174         { }
1175 };
1176
1177 static void add_interface(struct generic_data *data,
1178                                 const char *name,
1179                                 const GDBusMethodTable *methods,
1180                                 const GDBusSignalTable *signals,
1181                                 const GDBusPropertyTable *properties,
1182                                 void *user_data,
1183                                 GDBusDestroyFunction destroy)
1184 {
1185         struct interface_data *iface;
1186
1187         iface = g_new0(struct interface_data, 1);
1188         iface->name = g_strdup(name);
1189         iface->methods = methods;
1190         iface->signals = signals;
1191         iface->properties = properties;
1192         iface->user_data = user_data;
1193         iface->destroy = destroy;
1194
1195         data->interfaces = g_slist_append(data->interfaces, iface);
1196         if (data->parent == NULL)
1197                 return;
1198
1199         data->added = g_slist_append(data->added, iface);
1200         if (data->process_id > 0)
1201                 return;
1202
1203         data->process_id = g_idle_add(process_changes, data);
1204 }
1205
1206 static struct generic_data *object_path_ref(DBusConnection *connection,
1207                                                         const char *path)
1208 {
1209         struct generic_data *data;
1210
1211         if (dbus_connection_get_object_path_data(connection, path,
1212                                                 (void *) &data) == TRUE) {
1213                 if (data != NULL) {
1214                         data->refcount++;
1215                         return data;
1216                 }
1217         }
1218
1219         data = g_new0(struct generic_data, 1);
1220         data->conn = dbus_connection_ref(connection);
1221         data->path = g_strdup(path);
1222         data->refcount = 1;
1223
1224         data->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<node></node>");
1225
1226         if (!dbus_connection_register_object_path(connection, path,
1227                                                 &generic_table, data)) {
1228                 g_free(data->introspect);
1229                 g_free(data);
1230                 return NULL;
1231         }
1232
1233         invalidate_parent_data(connection, path);
1234
1235         add_interface(data, DBUS_INTERFACE_INTROSPECTABLE, introspect_methods,
1236                                                 NULL, NULL, data, NULL);
1237
1238         return data;
1239 }
1240
1241 static void object_path_unref(DBusConnection *connection, const char *path)
1242 {
1243         struct generic_data *data = NULL;
1244
1245         if (dbus_connection_get_object_path_data(connection, path,
1246                                                 (void *) &data) == FALSE)
1247                 return;
1248
1249         if (data == NULL)
1250                 return;
1251
1252         data->refcount--;
1253
1254         if (data->refcount > 0)
1255                 return;
1256
1257         remove_interface(data, DBUS_INTERFACE_INTROSPECTABLE);
1258         remove_interface(data, DBUS_INTERFACE_PROPERTIES);
1259
1260         invalidate_parent_data(data->conn, data->path);
1261
1262         dbus_connection_unregister_object_path(data->conn, data->path);
1263 }
1264
1265 static gboolean check_signal(DBusConnection *conn, const char *path,
1266                                 const char *interface, const char *name,
1267                                 const GDBusArgInfo **args)
1268 {
1269         struct generic_data *data = NULL;
1270         struct interface_data *iface;
1271         const GDBusSignalTable *signal;
1272
1273         *args = NULL;
1274         if (!dbus_connection_get_object_path_data(conn, path,
1275                                         (void *) &data) || data == NULL) {
1276                 error("dbus_connection_emit_signal: path %s isn't registered",
1277                                 path);
1278                 return FALSE;
1279         }
1280
1281         iface = find_interface(data->interfaces, interface);
1282         if (iface == NULL) {
1283                 error("dbus_connection_emit_signal: %s does not implement %s",
1284                                 path, interface);
1285                 return FALSE;
1286         }
1287
1288         for (signal = iface->signals; signal && signal->name; signal++) {
1289                 if (strcmp(signal->name, name) != 0)
1290                         continue;
1291
1292                 if (signal->flags & G_DBUS_SIGNAL_FLAG_EXPERIMENTAL) {
1293                         const char *env = g_getenv("GDBUS_EXPERIMENTAL");
1294                         if (g_strcmp0(env, "1") != 0)
1295                                 break;
1296                 }
1297
1298                 *args = signal->args;
1299                 return TRUE;
1300         }
1301
1302         error("No signal named %s on interface %s", name, interface);
1303         return FALSE;
1304 }
1305
1306 static dbus_bool_t emit_signal_valist(DBusConnection *conn,
1307                                                 const char *path,
1308                                                 const char *interface,
1309                                                 const char *name,
1310                                                 int first,
1311                                                 va_list var_args)
1312 {
1313         DBusMessage *signal;
1314         dbus_bool_t ret;
1315         const GDBusArgInfo *args;
1316
1317         if (!check_signal(conn, path, interface, name, &args))
1318                 return FALSE;
1319
1320         signal = dbus_message_new_signal(path, interface, name);
1321         if (signal == NULL) {
1322                 error("Unable to allocate new %s.%s signal", interface,  name);
1323                 return FALSE;
1324         }
1325
1326         ret = dbus_message_append_args_valist(signal, first, var_args);
1327         if (!ret)
1328                 goto fail;
1329
1330         if (g_dbus_args_have_signature(args, signal) == FALSE) {
1331                 error("%s.%s: got unexpected signature '%s'", interface, name,
1332                                         dbus_message_get_signature(signal));
1333                 ret = FALSE;
1334                 goto fail;
1335         }
1336
1337         ret = dbus_connection_send(conn, signal, NULL);
1338
1339 fail:
1340         dbus_message_unref(signal);
1341
1342         return ret;
1343 }
1344
1345 gboolean g_dbus_register_interface(DBusConnection *connection,
1346                                         const char *path, const char *name,
1347                                         const GDBusMethodTable *methods,
1348                                         const GDBusSignalTable *signals,
1349                                         const GDBusPropertyTable *properties,
1350                                         void *user_data,
1351                                         GDBusDestroyFunction destroy)
1352 {
1353         struct generic_data *data;
1354
1355         data = object_path_ref(connection, path);
1356         if (data == NULL)
1357                 return FALSE;
1358
1359         if (find_interface(data->interfaces, name)) {
1360                 object_path_unref(connection, path);
1361                 return FALSE;
1362         }
1363
1364         if (properties != NULL && !find_interface(data->interfaces,
1365                                                 DBUS_INTERFACE_PROPERTIES))
1366                 add_interface(data, DBUS_INTERFACE_PROPERTIES,
1367                                 properties_methods, properties_signals, NULL,
1368                                 data, NULL);
1369
1370         add_interface(data, name, methods, signals, properties, user_data,
1371                                                                 destroy);
1372
1373         g_free(data->introspect);
1374         data->introspect = NULL;
1375
1376         return TRUE;
1377 }
1378
1379 gboolean g_dbus_unregister_interface(DBusConnection *connection,
1380                                         const char *path, const char *name)
1381 {
1382         struct generic_data *data = NULL;
1383
1384         if (path == NULL)
1385                 return FALSE;
1386
1387         if (dbus_connection_get_object_path_data(connection, path,
1388                                                 (void *) &data) == FALSE)
1389                 return FALSE;
1390
1391         if (data == NULL)
1392                 return FALSE;
1393
1394         if (remove_interface(data, name) == FALSE)
1395                 return FALSE;
1396
1397         g_free(data->introspect);
1398         data->introspect = NULL;
1399
1400         object_path_unref(connection, data->path);
1401
1402         return TRUE;
1403 }
1404
1405 gboolean g_dbus_register_security(const GDBusSecurityTable *security)
1406 {
1407         if (security_table != NULL)
1408                 return FALSE;
1409
1410         security_table = security;
1411
1412         return TRUE;
1413 }
1414
1415 gboolean g_dbus_unregister_security(const GDBusSecurityTable *security)
1416 {
1417         security_table = NULL;
1418
1419         return TRUE;
1420 }
1421
1422 DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name,
1423                                         const char *format, va_list args)
1424 {
1425         char str[1024];
1426
1427         vsnprintf(str, sizeof(str), format, args);
1428
1429         return dbus_message_new_error(message, name, str);
1430 }
1431
1432 DBusMessage *g_dbus_create_error(DBusMessage *message, const char *name,
1433                                                 const char *format, ...)
1434 {
1435         va_list args;
1436         DBusMessage *reply;
1437
1438         va_start(args, format);
1439
1440         reply = g_dbus_create_error_valist(message, name, format, args);
1441
1442         va_end(args);
1443
1444         return reply;
1445 }
1446
1447 DBusMessage *g_dbus_create_reply_valist(DBusMessage *message,
1448                                                 int type, va_list args)
1449 {
1450         DBusMessage *reply;
1451
1452         reply = dbus_message_new_method_return(message);
1453         if (reply == NULL)
1454                 return NULL;
1455
1456         if (dbus_message_append_args_valist(reply, type, args) == FALSE) {
1457                 dbus_message_unref(reply);
1458                 return NULL;
1459         }
1460
1461         return reply;
1462 }
1463
1464 DBusMessage *g_dbus_create_reply(DBusMessage *message, int type, ...)
1465 {
1466         va_list args;
1467         DBusMessage *reply;
1468
1469         va_start(args, type);
1470
1471         reply = g_dbus_create_reply_valist(message, type, args);
1472
1473         va_end(args);
1474
1475         return reply;
1476 }
1477
1478 gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message)
1479 {
1480         dbus_bool_t result;
1481
1482         if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
1483                 dbus_message_set_no_reply(message, TRUE);
1484
1485         result = dbus_connection_send(connection, message, NULL);
1486
1487         dbus_message_unref(message);
1488
1489         return result;
1490 }
1491
1492 gboolean g_dbus_send_error_valist(DBusConnection *connection,
1493                                         DBusMessage *message, const char *name,
1494                                         const char *format, va_list args)
1495 {
1496         DBusMessage *error;
1497         char str[1024];
1498
1499         vsnprintf(str, sizeof(str), format, args);
1500
1501         error = dbus_message_new_error(message, name, str);
1502         if (error == NULL)
1503                 return FALSE;
1504
1505         return g_dbus_send_message(connection, error);
1506 }
1507
1508 gboolean g_dbus_send_error(DBusConnection *connection, DBusMessage *message,
1509                                 const char *name, const char *format, ...)
1510 {
1511         va_list args;
1512         gboolean result;
1513
1514         va_start(args, format);
1515
1516         result = g_dbus_send_error_valist(connection, message, name,
1517                                                         format, args);
1518
1519         va_end(args);
1520
1521         return result;
1522 }
1523
1524 gboolean g_dbus_send_reply_valist(DBusConnection *connection,
1525                                 DBusMessage *message, int type, va_list args)
1526 {
1527         DBusMessage *reply;
1528
1529         reply = dbus_message_new_method_return(message);
1530         if (reply == NULL)
1531                 return FALSE;
1532
1533         if (dbus_message_append_args_valist(reply, type, args) == FALSE) {
1534                 dbus_message_unref(reply);
1535                 return FALSE;
1536         }
1537
1538         return g_dbus_send_message(connection, reply);
1539 }
1540
1541 gboolean g_dbus_send_reply(DBusConnection *connection,
1542                                 DBusMessage *message, int type, ...)
1543 {
1544         va_list args;
1545         gboolean result;
1546
1547         va_start(args, type);
1548
1549         result = g_dbus_send_reply_valist(connection, message, type, args);
1550
1551         va_end(args);
1552
1553         return result;
1554 }
1555
1556 gboolean g_dbus_emit_signal(DBusConnection *connection,
1557                                 const char *path, const char *interface,
1558                                 const char *name, int type, ...)
1559 {
1560         va_list args;
1561         gboolean result;
1562
1563         va_start(args, type);
1564
1565         result = emit_signal_valist(connection, path, interface,
1566                                                         name, type, args);
1567
1568         va_end(args);
1569
1570         return result;
1571 }
1572
1573 gboolean g_dbus_emit_signal_valist(DBusConnection *connection,
1574                                 const char *path, const char *interface,
1575                                 const char *name, int type, va_list args)
1576 {
1577         return emit_signal_valist(connection, path, interface,
1578                                                         name, type, args);
1579 }
1580
1581 static void process_properties_from_interface(struct generic_data *data,
1582                                                 struct interface_data *iface)
1583 {
1584         GSList *l;
1585         DBusMessage *signal;
1586         DBusMessageIter iter, dict, array;
1587         GSList *invalidated;
1588
1589         if (iface->pending_prop == NULL)
1590                 return;
1591
1592         signal = dbus_message_new_signal(data->path,
1593                         DBUS_INTERFACE_PROPERTIES, "PropertiesChanged");
1594         if (signal == NULL) {
1595                 error("Unable to allocate new " DBUS_INTERFACE_PROPERTIES
1596                                                 ".PropertiesChanged signal");
1597                 return;
1598         }
1599
1600         iface->pending_prop = g_slist_reverse(iface->pending_prop);
1601
1602         dbus_message_iter_init_append(signal, &iter);
1603         dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &iface->name);
1604         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
1605                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
1606                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
1607                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
1608
1609         invalidated = NULL;
1610
1611         for (l = iface->pending_prop; l != NULL; l = l->next) {
1612                 GDBusPropertyTable *p = l->data;
1613
1614                 if (p->get == NULL)
1615                         continue;
1616
1617                 if (p->exists != NULL && !p->exists(p, iface->user_data)) {
1618                         invalidated = g_slist_prepend(invalidated, p);
1619                         continue;
1620                 }
1621
1622                 append_property(iface, p, &dict);
1623         }
1624
1625         dbus_message_iter_close_container(&iter, &dict);
1626
1627         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
1628                                 DBUS_TYPE_STRING_AS_STRING, &array);
1629         for (l = invalidated; l != NULL; l = g_slist_next(l)) {
1630                 GDBusPropertyTable *p = l->data;
1631
1632                 dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
1633                                                                 &p->name);
1634         }
1635         g_slist_free(invalidated);
1636         dbus_message_iter_close_container(&iter, &array);
1637
1638         g_dbus_send_message(data->conn, signal);
1639
1640         g_slist_free(iface->pending_prop);
1641         iface->pending_prop = NULL;
1642 }
1643
1644 static void process_property_changes(struct generic_data *data)
1645 {
1646         GSList *l;
1647
1648         for (l = data->interfaces; l != NULL; l = l->next) {
1649                 struct interface_data *iface = l->data;
1650
1651                 process_properties_from_interface(data, iface);
1652         }
1653
1654         data->pending_prop = FALSE;
1655 }
1656
1657 void g_dbus_emit_property_changed(DBusConnection *connection,
1658                                 const char *path, const char *interface,
1659                                 const char *name)
1660 {
1661         const GDBusPropertyTable *property;
1662         struct generic_data *data;
1663         struct interface_data *iface;
1664
1665         if (!dbus_connection_get_object_path_data(connection, path,
1666                                         (void **) &data) || data == NULL)
1667                 return;
1668
1669         iface = find_interface(data->interfaces, interface);
1670         if (iface == NULL)
1671                 return;
1672
1673         property = find_property(iface->properties, name);
1674         if (property == NULL) {
1675                 error("Could not find property %s in %p", name,
1676                                                         iface->properties);
1677                 return;
1678         }
1679
1680         if (g_slist_find(iface->pending_prop, (void *) property) != NULL)
1681                 return;
1682
1683         data->pending_prop = TRUE;
1684         iface->pending_prop = g_slist_prepend(iface->pending_prop,
1685                                                 (void *) property);
1686
1687         if (!data->process_id) {
1688                 data->process_id = g_idle_add(process_changes, data);
1689                 return;
1690         }
1691 }
1692
1693 gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
1694                                 const char *interface, DBusMessageIter *iter)
1695 {
1696         struct generic_data *data;
1697         struct interface_data *iface;
1698
1699         if (!dbus_connection_get_object_path_data(connection, path,
1700                                         (void **) &data) || data == NULL)
1701                 return FALSE;
1702
1703         iface = find_interface(data->interfaces, interface);
1704         if (iface == NULL)
1705                 return FALSE;
1706
1707         append_properties(iface, iter);
1708
1709         return TRUE;
1710 }
1711
1712 gboolean g_dbus_attach_object_manager(DBusConnection *connection)
1713 {
1714         struct generic_data *data;
1715
1716         data = object_path_ref(connection, "/");
1717         if (data == NULL)
1718                 return FALSE;
1719
1720         add_interface(data, DBUS_INTERFACE_OBJECT_MANAGER,
1721                                         manager_methods, manager_signals,
1722                                         NULL, data, NULL);
1723         root = data;
1724
1725         return TRUE;
1726 }
1727
1728 gboolean g_dbus_detach_object_manager(DBusConnection *connection)
1729 {
1730         if (!g_dbus_unregister_interface(connection, "/",
1731                                         DBUS_INTERFACE_OBJECT_MANAGER))
1732                 return FALSE;
1733
1734         root = NULL;
1735
1736         return TRUE;
1737 }
1738
1739 void g_dbus_set_flags(int flags)
1740 {
1741         global_flags = flags;
1742 }