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