release: added packaging for gerrit.
[profile/ivi/pulseaudio-panda.git] / src / pulsecore / dbus-util.c
1 /***
2   This file is part of PulseAudio.
3
4   Copyright 2006 Lennart Poettering
5   Copyright 2006 Shams E. King
6
7   PulseAudio is free software; you can redistribute it and/or modify
8   it under the terms of the GNU Lesser General Public License as published
9   by the Free Software Foundation; either version 2.1 of the License,
10   or (at your option) any later version.
11
12   PulseAudio is distributed in the hope that it will be useful, but
13   WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15   General Public License for more details.
16
17   You should have received a copy of the GNU Lesser General Public License
18   along with PulseAudio; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20   USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdarg.h>
28
29 #include <pulse/rtclock.h>
30 #include <pulse/timeval.h>
31 #include <pulse/utf8.h>
32 #include <pulse/xmalloc.h>
33
34 #include <pulsecore/core-rtclock.h>
35 #include <pulsecore/core-util.h>
36 #include <pulsecore/log.h>
37
38 #include "dbus-util.h"
39
40 struct pa_dbus_wrap_connection {
41     pa_mainloop_api *mainloop;
42     DBusConnection *connection;
43     pa_defer_event* dispatch_event;
44     pa_bool_t use_rtclock:1;
45 };
46
47 struct timeout_data {
48     pa_dbus_wrap_connection *connection;
49     DBusTimeout *timeout;
50 };
51
52 static void dispatch_cb(pa_mainloop_api *ea, pa_defer_event *ev, void *userdata) {
53     DBusConnection *conn = userdata;
54
55     if (dbus_connection_dispatch(conn) == DBUS_DISPATCH_COMPLETE)
56         /* no more data to process, disable the deferred */
57         ea->defer_enable(ev, 0);
58 }
59
60 /* DBusDispatchStatusFunction callback for the pa mainloop */
61 static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata) {
62     pa_dbus_wrap_connection *c = userdata;
63
64     pa_assert(c);
65
66     switch(status) {
67
68         case DBUS_DISPATCH_COMPLETE:
69             c->mainloop->defer_enable(c->dispatch_event, 0);
70             break;
71
72         case DBUS_DISPATCH_DATA_REMAINS:
73         case DBUS_DISPATCH_NEED_MEMORY:
74         default:
75             c->mainloop->defer_enable(c->dispatch_event, 1);
76             break;
77     }
78 }
79
80 static pa_io_event_flags_t get_watch_flags(DBusWatch *watch) {
81     unsigned int flags;
82     pa_io_event_flags_t events = 0;
83
84     pa_assert(watch);
85
86     flags = dbus_watch_get_flags(watch);
87
88     /* no watch flags for disabled watches */
89     if (!dbus_watch_get_enabled(watch))
90         return PA_IO_EVENT_NULL;
91
92     if (flags & DBUS_WATCH_READABLE)
93         events |= PA_IO_EVENT_INPUT;
94     if (flags & DBUS_WATCH_WRITABLE)
95         events |= PA_IO_EVENT_OUTPUT;
96
97     return events | PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR;
98 }
99
100 /* pa_io_event_cb_t IO event handler */
101 static void handle_io_event(pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
102     unsigned int flags = 0;
103     DBusWatch *watch = userdata;
104
105 #if HAVE_DBUS_WATCH_GET_UNIX_FD
106     pa_assert(fd == dbus_watch_get_unix_fd(watch));
107 #else
108     pa_assert(fd == dbus_watch_get_fd(watch));
109 #endif
110
111     if (!dbus_watch_get_enabled(watch)) {
112         pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd);
113         return;
114     }
115
116     if (events & PA_IO_EVENT_INPUT)
117         flags |= DBUS_WATCH_READABLE;
118     if (events & PA_IO_EVENT_OUTPUT)
119         flags |= DBUS_WATCH_WRITABLE;
120     if (events & PA_IO_EVENT_HANGUP)
121         flags |= DBUS_WATCH_HANGUP;
122     if (events & PA_IO_EVENT_ERROR)
123         flags |= DBUS_WATCH_ERROR;
124
125     dbus_watch_handle(watch, flags);
126 }
127
128 /* pa_time_event_cb_t timer event handler */
129 static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, const struct timeval *t, void *userdata) {
130     struct timeval tv;
131     struct timeout_data *d = userdata;
132
133     pa_assert(d);
134     pa_assert(d->connection);
135
136     if (dbus_timeout_get_enabled(d->timeout)) {
137         /* Restart it for the next scheduled time. We do this before
138          * calling dbus_timeout_handle() to make sure that the time
139          * event is still around. */
140         ea->time_restart(e, pa_timeval_rtstore(&tv,
141                                                pa_timeval_load(t) + dbus_timeout_get_interval(d->timeout) * PA_USEC_PER_MSEC,
142                                                d->connection->use_rtclock));
143
144         dbus_timeout_handle(d->timeout);
145     }
146 }
147
148 /* DBusAddWatchFunction callback for pa mainloop */
149 static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
150     pa_dbus_wrap_connection *c = data;
151     pa_io_event *ev;
152
153     pa_assert(watch);
154     pa_assert(c);
155
156     ev = c->mainloop->io_new(
157             c->mainloop,
158 #if HAVE_DBUS_WATCH_GET_UNIX_FD
159             dbus_watch_get_unix_fd(watch),
160 #else
161             dbus_watch_get_fd(watch),
162 #endif
163             get_watch_flags(watch), handle_io_event, watch);
164
165     dbus_watch_set_data(watch, ev, NULL);
166
167     return TRUE;
168 }
169
170 /* DBusRemoveWatchFunction callback for pa mainloop */
171 static void remove_watch(DBusWatch *watch, void *data) {
172     pa_dbus_wrap_connection *c = data;
173     pa_io_event *ev;
174
175     pa_assert(watch);
176     pa_assert(c);
177
178     if ((ev = dbus_watch_get_data(watch)))
179         c->mainloop->io_free(ev);
180 }
181
182 /* DBusWatchToggledFunction callback for pa mainloop */
183 static void toggle_watch(DBusWatch *watch, void *data) {
184     pa_dbus_wrap_connection *c = data;
185     pa_io_event *ev;
186
187     pa_assert(watch);
188     pa_assert(c);
189
190     pa_assert_se(ev = dbus_watch_get_data(watch));
191
192     /* get_watch_flags() checks if the watch is enabled */
193     c->mainloop->io_enable(ev, get_watch_flags(watch));
194 }
195
196 static void time_event_destroy_cb(pa_mainloop_api *a, pa_time_event *e, void *userdata) {
197     pa_xfree(userdata);
198 }
199
200 /* DBusAddTimeoutFunction callback for pa mainloop */
201 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) {
202     pa_dbus_wrap_connection *c = data;
203     pa_time_event *ev;
204     struct timeval tv;
205     struct timeout_data *d;
206
207     pa_assert(timeout);
208     pa_assert(c);
209
210     if (!dbus_timeout_get_enabled(timeout))
211         return FALSE;
212
213     d = pa_xnew(struct timeout_data, 1);
214     d->connection = c;
215     d->timeout = timeout;
216     ev = c->mainloop->time_new(c->mainloop, pa_timeval_rtstore(&tv, pa_rtclock_now() + dbus_timeout_get_interval(timeout) * PA_USEC_PER_MSEC, c->use_rtclock), handle_time_event, d);
217     c->mainloop->time_set_destroy(ev, time_event_destroy_cb);
218
219     dbus_timeout_set_data(timeout, ev, NULL);
220
221     return TRUE;
222 }
223
224 /* DBusRemoveTimeoutFunction callback for pa mainloop */
225 static void remove_timeout(DBusTimeout *timeout, void *data) {
226     pa_dbus_wrap_connection *c = data;
227     pa_time_event *ev;
228
229     pa_assert(timeout);
230     pa_assert(c);
231
232     if ((ev = dbus_timeout_get_data(timeout)))
233         c->mainloop->time_free(ev);
234 }
235
236 /* DBusTimeoutToggledFunction callback for pa mainloop */
237 static void toggle_timeout(DBusTimeout *timeout, void *data) {
238     struct timeout_data *d = data;
239     pa_time_event *ev;
240     struct timeval tv;
241
242     pa_assert(d);
243     pa_assert(d->connection);
244     pa_assert(timeout);
245
246     pa_assert_se(ev = dbus_timeout_get_data(timeout));
247
248     if (dbus_timeout_get_enabled(timeout))
249         d->connection->mainloop->time_restart(ev, pa_timeval_rtstore(&tv, pa_rtclock_now() + dbus_timeout_get_interval(timeout) * PA_USEC_PER_MSEC, d->connection->use_rtclock));
250     else
251         d->connection->mainloop->time_restart(ev, pa_timeval_rtstore(&tv, PA_USEC_INVALID, d->connection->use_rtclock));
252 }
253
254 static void wakeup_main(void *userdata) {
255     pa_dbus_wrap_connection *c = userdata;
256
257     pa_assert(c);
258
259     /* this will wakeup the mainloop and dispatch events, although
260      * it may not be the cleanest way of accomplishing it */
261     c->mainloop->defer_enable(c->dispatch_event, 1);
262 }
263
264 pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, pa_bool_t use_rtclock, DBusBusType type, DBusError *error) {
265     DBusConnection *conn;
266     pa_dbus_wrap_connection *pconn;
267     char *id;
268
269     pa_assert(type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION || type == DBUS_BUS_STARTER);
270
271     if (!(conn = dbus_bus_get_private(type, error)))
272         return NULL;
273
274     pconn = pa_xnew(pa_dbus_wrap_connection, 1);
275     pconn->mainloop = m;
276     pconn->connection = conn;
277     pconn->use_rtclock = use_rtclock;
278
279     dbus_connection_set_exit_on_disconnect(conn, FALSE);
280     dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
281     dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
282     dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
283     dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
284
285     pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
286
287     pa_log_debug("Successfully connected to D-Bus %s bus %s as %s",
288                  type == DBUS_BUS_SYSTEM ? "system" : (type == DBUS_BUS_SESSION ? "session" : "starter"),
289                  pa_strnull((id = dbus_connection_get_server_id(conn))),
290                  pa_strnull(dbus_bus_get_unique_name(conn)));
291
292     dbus_free(id);
293
294     return pconn;
295 }
296
297 pa_dbus_wrap_connection* pa_dbus_wrap_connection_new_from_existing(
298         pa_mainloop_api *m,
299         pa_bool_t use_rtclock,
300         DBusConnection *conn) {
301     pa_dbus_wrap_connection *pconn;
302
303     pa_assert(m);
304     pa_assert(conn);
305
306     pconn = pa_xnew(pa_dbus_wrap_connection, 1);
307     pconn->mainloop = m;
308     pconn->connection = dbus_connection_ref(conn);
309     pconn->use_rtclock = use_rtclock;
310
311     dbus_connection_set_exit_on_disconnect(conn, FALSE);
312     dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
313     dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
314     dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
315     dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
316
317     pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
318
319     return pconn;
320 }
321
322 void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection* c) {
323     pa_assert(c);
324
325     if (dbus_connection_get_is_connected(c->connection)) {
326         dbus_connection_close(c->connection);
327         /* must process remaining messages, bit of a kludge to handle
328          * both unload and shutdown */
329         while (dbus_connection_read_write_dispatch(c->connection, -1))
330             ;
331     }
332
333     c->mainloop->defer_free(c->dispatch_event);
334     dbus_connection_unref(c->connection);
335     pa_xfree(c);
336 }
337
338 DBusConnection* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection *c) {
339   pa_assert(c);
340   pa_assert(c->connection);
341
342   return c->connection;
343 }
344
345 int pa_dbus_add_matches(DBusConnection *c, DBusError *error, ...) {
346     const char *t;
347     va_list ap;
348     unsigned k = 0;
349
350     pa_assert(c);
351     pa_assert(error);
352
353     va_start(ap, error);
354     while ((t = va_arg(ap, const char*))) {
355         dbus_bus_add_match(c, t, error);
356
357         if (dbus_error_is_set(error))
358             goto fail;
359
360         k++;
361     }
362     va_end(ap);
363     return 0;
364
365 fail:
366
367     va_end(ap);
368     va_start(ap, error);
369     for (; k > 0; k--) {
370         pa_assert_se(t = va_arg(ap, const char*));
371         dbus_bus_remove_match(c, t, NULL);
372     }
373     va_end(ap);
374
375     return -1;
376 }
377
378 void pa_dbus_remove_matches(DBusConnection *c, ...) {
379     const char *t;
380     va_list ap;
381
382     pa_assert(c);
383
384     va_start(ap, c);
385     while ((t = va_arg(ap, const char*)))
386         dbus_bus_remove_match(c, t, NULL);
387     va_end(ap);
388 }
389
390 pa_dbus_pending *pa_dbus_pending_new(
391         DBusConnection *c,
392         DBusMessage *m,
393         DBusPendingCall *pending,
394         void *context_data,
395         void *call_data) {
396
397     pa_dbus_pending *p;
398
399     pa_assert(pending);
400
401     p = pa_xnew(pa_dbus_pending, 1);
402     p->connection = c;
403     p->message = m;
404     p->pending = pending;
405     p->context_data = context_data;
406     p->call_data = call_data;
407
408     PA_LLIST_INIT(pa_dbus_pending, p);
409
410     return p;
411 }
412
413 void pa_dbus_pending_free(pa_dbus_pending *p) {
414     pa_assert(p);
415
416     if (p->pending) {
417         dbus_pending_call_cancel(p->pending);
418         dbus_pending_call_unref(p->pending);
419     }
420
421     if (p->message)
422         dbus_message_unref(p->message);
423
424     pa_xfree(p);
425 }
426
427 void pa_dbus_sync_pending_list(pa_dbus_pending **p) {
428     pa_assert(p);
429
430     while (*p && dbus_connection_read_write_dispatch((*p)->connection, -1))
431         ;
432 }
433
434 void pa_dbus_free_pending_list(pa_dbus_pending **p) {
435     pa_dbus_pending *i;
436
437     pa_assert(p);
438
439     while ((i = *p)) {
440         PA_LLIST_REMOVE(pa_dbus_pending, *p, i);
441         pa_dbus_pending_free(i);
442     }
443 }
444
445 const char *pa_dbus_get_error_message(DBusMessage *m) {
446     const char *message;
447
448     pa_assert(m);
449     pa_assert(dbus_message_get_type(m) == DBUS_MESSAGE_TYPE_ERROR);
450
451     if (dbus_message_get_signature(m)[0] != 's')
452         return "<no explanation>";
453
454     pa_assert_se(dbus_message_get_args(m, NULL, DBUS_TYPE_STRING, &message, DBUS_TYPE_INVALID));
455
456     return message;
457 }
458
459 void pa_dbus_send_error(DBusConnection *c, DBusMessage *in_reply_to, const char *name, const char *format, ...) {
460     va_list ap;
461     char *message;
462     DBusMessage *reply = NULL;
463
464     pa_assert(c);
465     pa_assert(in_reply_to);
466     pa_assert(name);
467     pa_assert(format);
468
469     va_start(ap, format);
470     message = pa_vsprintf_malloc(format, ap);
471     va_end(ap);
472     pa_assert_se((reply = dbus_message_new_error(in_reply_to, name, message)));
473     pa_assert_se(dbus_connection_send(c, reply, NULL));
474
475     dbus_message_unref(reply);
476
477     pa_xfree(message);
478 }
479
480 void pa_dbus_send_empty_reply(DBusConnection *c, DBusMessage *in_reply_to) {
481     DBusMessage *reply = NULL;
482
483     pa_assert(c);
484     pa_assert(in_reply_to);
485
486     pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
487     pa_assert_se(dbus_connection_send(c, reply, NULL));
488     dbus_message_unref(reply);
489 }
490
491 void pa_dbus_send_basic_value_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
492     DBusMessage *reply = NULL;
493
494     pa_assert(c);
495     pa_assert(in_reply_to);
496     pa_assert(dbus_type_is_basic(type));
497     pa_assert(data);
498
499     pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
500     pa_assert_se(dbus_message_append_args(reply, type, data, DBUS_TYPE_INVALID));
501     pa_assert_se(dbus_connection_send(c, reply, NULL));
502     dbus_message_unref(reply);
503 }
504
505 static const char *signature_from_basic_type(int type) {
506     switch (type) {
507         case DBUS_TYPE_BOOLEAN: return DBUS_TYPE_BOOLEAN_AS_STRING;
508         case DBUS_TYPE_BYTE: return DBUS_TYPE_BYTE_AS_STRING;
509         case DBUS_TYPE_INT16: return DBUS_TYPE_INT16_AS_STRING;
510         case DBUS_TYPE_UINT16: return DBUS_TYPE_UINT16_AS_STRING;
511         case DBUS_TYPE_INT32: return DBUS_TYPE_INT32_AS_STRING;
512         case DBUS_TYPE_UINT32: return DBUS_TYPE_UINT32_AS_STRING;
513         case DBUS_TYPE_INT64: return DBUS_TYPE_INT64_AS_STRING;
514         case DBUS_TYPE_UINT64: return DBUS_TYPE_UINT64_AS_STRING;
515         case DBUS_TYPE_DOUBLE: return DBUS_TYPE_DOUBLE_AS_STRING;
516         case DBUS_TYPE_STRING: return DBUS_TYPE_STRING_AS_STRING;
517         case DBUS_TYPE_OBJECT_PATH: return DBUS_TYPE_OBJECT_PATH_AS_STRING;
518         case DBUS_TYPE_SIGNATURE: return DBUS_TYPE_SIGNATURE_AS_STRING;
519         default: pa_assert_not_reached();
520     }
521 }
522
523 void pa_dbus_send_basic_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
524     DBusMessage *reply = NULL;
525     DBusMessageIter msg_iter;
526     DBusMessageIter variant_iter;
527
528     pa_assert(c);
529     pa_assert(in_reply_to);
530     pa_assert(dbus_type_is_basic(type));
531     pa_assert(data);
532
533     pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
534     dbus_message_iter_init_append(reply, &msg_iter);
535     pa_assert_se(dbus_message_iter_open_container(&msg_iter,
536                                                   DBUS_TYPE_VARIANT,
537                                                   signature_from_basic_type(type),
538                                                   &variant_iter));
539     pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
540     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &variant_iter));
541     pa_assert_se(dbus_connection_send(c, reply, NULL));
542     dbus_message_unref(reply);
543 }
544
545 /* Note: returns sizeof(char*) for strings, object paths and signatures. */
546 static unsigned basic_type_size(int type) {
547     switch (type) {
548         case DBUS_TYPE_BOOLEAN: return sizeof(dbus_bool_t);
549         case DBUS_TYPE_BYTE: return 1;
550         case DBUS_TYPE_INT16: return sizeof(dbus_int16_t);
551         case DBUS_TYPE_UINT16: return sizeof(dbus_uint16_t);
552         case DBUS_TYPE_INT32: return sizeof(dbus_int32_t);
553         case DBUS_TYPE_UINT32: return sizeof(dbus_uint32_t);
554         case DBUS_TYPE_INT64: return sizeof(dbus_int64_t);
555         case DBUS_TYPE_UINT64: return sizeof(dbus_uint64_t);
556         case DBUS_TYPE_DOUBLE: return sizeof(double);
557         case DBUS_TYPE_STRING:
558         case DBUS_TYPE_OBJECT_PATH:
559         case DBUS_TYPE_SIGNATURE: return sizeof(char*);
560         default: pa_assert_not_reached();
561     }
562 }
563
564 void pa_dbus_send_basic_array_variant_reply(
565         DBusConnection *c,
566         DBusMessage *in_reply_to,
567         int item_type,
568         void *array,
569         unsigned n) {
570     DBusMessage *reply = NULL;
571     DBusMessageIter msg_iter;
572
573     pa_assert(c);
574     pa_assert(in_reply_to);
575     pa_assert(dbus_type_is_basic(item_type));
576     pa_assert(array || n == 0);
577
578     pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
579     dbus_message_iter_init_append(reply, &msg_iter);
580     pa_dbus_append_basic_array_variant(&msg_iter, item_type, array, n);
581     pa_assert_se(dbus_connection_send(c, reply, NULL));
582     dbus_message_unref(reply);
583 }
584
585 void pa_dbus_send_proplist_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, pa_proplist *proplist) {
586     DBusMessage *reply = NULL;
587     DBusMessageIter msg_iter;
588
589     pa_assert(c);
590     pa_assert(in_reply_to);
591     pa_assert(proplist);
592
593     pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
594     dbus_message_iter_init_append(reply, &msg_iter);
595     pa_dbus_append_proplist_variant(&msg_iter, proplist);
596     pa_assert_se(dbus_connection_send(c, reply, NULL));
597     dbus_message_unref(reply);
598 }
599
600 void pa_dbus_append_basic_array(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
601     DBusMessageIter array_iter;
602     unsigned i;
603     unsigned item_size;
604
605     pa_assert(iter);
606     pa_assert(dbus_type_is_basic(item_type));
607     pa_assert(array || n == 0);
608
609     item_size = basic_type_size(item_type);
610
611     pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, signature_from_basic_type(item_type), &array_iter));
612
613     for (i = 0; i < n; ++i)
614         pa_assert_se(dbus_message_iter_append_basic(&array_iter, item_type, &((uint8_t*) array)[i * item_size]));
615
616     pa_assert_se(dbus_message_iter_close_container(iter, &array_iter));
617 }
618
619 void pa_dbus_append_basic_variant(DBusMessageIter *iter, int type, void *data) {
620     DBusMessageIter variant_iter;
621
622     pa_assert(iter);
623     pa_assert(dbus_type_is_basic(type));
624     pa_assert(data);
625
626     pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, signature_from_basic_type(type), &variant_iter));
627     pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
628     pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
629 }
630
631 void pa_dbus_append_basic_array_variant(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
632     DBusMessageIter variant_iter;
633     char *array_signature;
634
635     pa_assert(iter);
636     pa_assert(dbus_type_is_basic(item_type));
637     pa_assert(array || n == 0);
638
639     array_signature = pa_sprintf_malloc("a%c", *signature_from_basic_type(item_type));
640
641     pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, array_signature, &variant_iter));
642     pa_dbus_append_basic_array(&variant_iter, item_type, array, n);
643     pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
644
645     pa_xfree(array_signature);
646 }
647
648 void pa_dbus_append_basic_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, int type, void *data) {
649     DBusMessageIter dict_entry_iter;
650
651     pa_assert(dict_iter);
652     pa_assert(key);
653     pa_assert(dbus_type_is_basic(type));
654     pa_assert(data);
655
656     pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
657     pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
658     pa_dbus_append_basic_variant(&dict_entry_iter, type, data);
659     pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
660 }
661
662 void pa_dbus_append_basic_array_variant_dict_entry(
663         DBusMessageIter *dict_iter,
664         const char *key,
665         int item_type,
666         const void *array,
667         unsigned n) {
668     DBusMessageIter dict_entry_iter;
669
670     pa_assert(dict_iter);
671     pa_assert(key);
672     pa_assert(dbus_type_is_basic(item_type));
673     pa_assert(array || n == 0);
674
675     pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
676     pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
677     pa_dbus_append_basic_array_variant(&dict_entry_iter, item_type, array, n);
678     pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
679 }
680
681 void pa_dbus_append_proplist(DBusMessageIter *iter, pa_proplist *proplist) {
682     DBusMessageIter dict_iter;
683     DBusMessageIter dict_entry_iter;
684     DBusMessageIter array_iter;
685     void *state = NULL;
686     const char *key;
687
688     pa_assert(iter);
689     pa_assert(proplist);
690
691     pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{say}", &dict_iter));
692
693     while ((key = pa_proplist_iterate(proplist, &state))) {
694         const void *value = NULL;
695         size_t nbytes;
696
697         pa_assert_se(pa_proplist_get(proplist, key, &value, &nbytes) >= 0);
698
699         pa_assert_se(dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
700
701         pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
702
703         pa_assert_se(dbus_message_iter_open_container(&dict_entry_iter, DBUS_TYPE_ARRAY, "y", &array_iter));
704         pa_assert_se(dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, &value, nbytes));
705         pa_assert_se(dbus_message_iter_close_container(&dict_entry_iter, &array_iter));
706
707         pa_assert_se(dbus_message_iter_close_container(&dict_iter, &dict_entry_iter));
708     }
709
710     pa_assert_se(dbus_message_iter_close_container(iter, &dict_iter));
711 }
712
713 void pa_dbus_append_proplist_variant(DBusMessageIter *iter, pa_proplist *proplist) {
714     DBusMessageIter variant_iter;
715
716     pa_assert(iter);
717     pa_assert(proplist);
718
719     pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{say}", &variant_iter));
720     pa_dbus_append_proplist(&variant_iter, proplist);
721     pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
722 }
723
724 void pa_dbus_append_proplist_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, pa_proplist *proplist) {
725     DBusMessageIter dict_entry_iter;
726
727     pa_assert(dict_iter);
728     pa_assert(key);
729     pa_assert(proplist);
730
731     pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
732     pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
733     pa_dbus_append_proplist_variant(&dict_entry_iter, proplist);
734     pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
735 }
736
737 pa_proplist *pa_dbus_get_proplist_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter) {
738     DBusMessageIter dict_iter;
739     DBusMessageIter dict_entry_iter;
740     pa_proplist *proplist = NULL;
741     const char *key = NULL;
742     const uint8_t *value = NULL;
743     int value_length = 0;
744
745     pa_assert(c);
746     pa_assert(msg);
747     pa_assert(iter);
748     pa_assert(pa_streq(dbus_message_iter_get_signature(iter), "a{say}"));
749
750     proplist = pa_proplist_new();
751
752     dbus_message_iter_recurse(iter, &dict_iter);
753
754     while (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_INVALID) {
755         dbus_message_iter_recurse(&dict_iter, &dict_entry_iter);
756
757         dbus_message_iter_get_basic(&dict_entry_iter, &key);
758         dbus_message_iter_next(&dict_entry_iter);
759
760         if (strlen(key) <= 0 || !pa_ascii_valid(key)) {
761             pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Invalid property list key: '%s'.", key);
762             goto fail;
763         }
764
765         dbus_message_iter_get_fixed_array(&dict_entry_iter, &value, &value_length);
766
767         pa_assert(value_length >= 0);
768
769         pa_assert_se(pa_proplist_set(proplist, key, value, value_length) >= 0);
770
771         dbus_message_iter_next(&dict_iter);
772     }
773
774     dbus_message_iter_next(iter);
775
776     return proplist;
777
778 fail:
779     if (proplist)
780         pa_proplist_free(proplist);
781
782     return NULL;
783 }