Merge branch 'master' of git://0pointer.de/pulseaudio into dbus-work
[profile/ivi/pulseaudio.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 *c;
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
61 /* DBusDispatchStatusFunction callback for the pa mainloop */
62 static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata) {
63     pa_dbus_wrap_connection *c = userdata;
64
65     pa_assert(c);
66
67     switch(status) {
68
69         case DBUS_DISPATCH_COMPLETE:
70             c->mainloop->defer_enable(c->dispatch_event, 0);
71             break;
72
73         case DBUS_DISPATCH_DATA_REMAINS:
74         case DBUS_DISPATCH_NEED_MEMORY:
75         default:
76             c->mainloop->defer_enable(c->dispatch_event, 1);
77             break;
78     }
79 }
80
81 static pa_io_event_flags_t get_watch_flags(DBusWatch *watch) {
82     unsigned int flags;
83     pa_io_event_flags_t events = 0;
84
85     pa_assert(watch);
86
87     flags = dbus_watch_get_flags(watch);
88
89     /* no watch flags for disabled watches */
90     if (!dbus_watch_get_enabled(watch))
91         return PA_IO_EVENT_NULL;
92
93     if (flags & DBUS_WATCH_READABLE)
94         events |= PA_IO_EVENT_INPUT;
95     if (flags & DBUS_WATCH_WRITABLE)
96         events |= PA_IO_EVENT_OUTPUT;
97
98     return events | PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR;
99 }
100
101 /* pa_io_event_cb_t IO event handler */
102 static void handle_io_event(pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
103     unsigned int flags = 0;
104     DBusWatch *watch = userdata;
105
106 #if HAVE_DBUS_WATCH_GET_UNIX_FD
107     pa_assert(fd == dbus_watch_get_unix_fd(watch));
108 #else
109     pa_assert(fd == dbus_watch_get_fd(watch));
110 #endif
111
112     if (!dbus_watch_get_enabled(watch)) {
113         pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd);
114         return;
115     }
116
117     if (events & PA_IO_EVENT_INPUT)
118         flags |= DBUS_WATCH_READABLE;
119     if (events & PA_IO_EVENT_OUTPUT)
120         flags |= DBUS_WATCH_WRITABLE;
121     if (events & PA_IO_EVENT_HANGUP)
122         flags |= DBUS_WATCH_HANGUP;
123     if (events & PA_IO_EVENT_ERROR)
124         flags |= DBUS_WATCH_ERROR;
125
126     dbus_watch_handle(watch, flags);
127 }
128
129 /* pa_time_event_cb_t timer event handler */
130 static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, const struct timeval *t, void *userdata) {
131     struct timeval tv;
132     struct timeout_data *d = userdata;
133
134     pa_assert(d);
135     pa_assert(d->c);
136
137     if (dbus_timeout_get_enabled(d->timeout)) {
138         dbus_timeout_handle(d->timeout);
139
140         /* restart it for the next scheduled time */
141         ea->time_restart(e, pa_timeval_rtstore(&tv, pa_timeval_load(t) + dbus_timeout_get_interval(d->timeout) * PA_USEC_PER_MSEC, d->c->use_rtclock));
142     }
143 }
144
145 /* DBusAddWatchFunction callback for pa mainloop */
146 static dbus_bool_t add_watch(DBusWatch *watch, void *data) {
147     pa_dbus_wrap_connection *c = data;
148     pa_io_event *ev;
149
150     pa_assert(watch);
151     pa_assert(c);
152
153     ev = c->mainloop->io_new(
154             c->mainloop,
155 #if HAVE_DBUS_WATCH_GET_UNIX_FD
156             dbus_watch_get_unix_fd(watch),
157 #else
158             dbus_watch_get_fd(watch),
159 #endif
160             get_watch_flags(watch), handle_io_event, watch);
161
162     dbus_watch_set_data(watch, ev, NULL);
163
164     return TRUE;
165 }
166
167 /* DBusRemoveWatchFunction callback for pa mainloop */
168 static void remove_watch(DBusWatch *watch, void *data) {
169     pa_dbus_wrap_connection *c = data;
170     pa_io_event *ev;
171
172     pa_assert(watch);
173     pa_assert(c);
174
175     if ((ev = dbus_watch_get_data(watch)))
176         c->mainloop->io_free(ev);
177 }
178
179 /* DBusWatchToggledFunction callback for pa mainloop */
180 static void toggle_watch(DBusWatch *watch, void *data) {
181     pa_dbus_wrap_connection *c = data;
182     pa_io_event *ev;
183
184     pa_assert(watch);
185     pa_assert(c);
186
187     pa_assert_se(ev = dbus_watch_get_data(watch));
188
189     /* get_watch_flags() checks if the watch is enabled */
190     c->mainloop->io_enable(ev, get_watch_flags(watch));
191 }
192
193 static void time_event_destroy_cb(pa_mainloop_api *a, pa_time_event *e, void *userdata) {
194     pa_xfree(userdata);
195 }
196
197 /* DBusAddTimeoutFunction callback for pa mainloop */
198 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) {
199     pa_dbus_wrap_connection *c = data;
200     pa_time_event *ev;
201     struct timeval tv;
202     struct timeout_data *d;
203
204     pa_assert(timeout);
205     pa_assert(c);
206
207     if (!dbus_timeout_get_enabled(timeout))
208         return FALSE;
209
210     d = pa_xnew(struct timeout_data, 1);
211     d->c = c;
212     d->timeout = timeout;
213     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);
214     c->mainloop->time_set_destroy(ev, time_event_destroy_cb);
215
216     dbus_timeout_set_data(timeout, ev, NULL);
217
218     return TRUE;
219 }
220
221 /* DBusRemoveTimeoutFunction callback for pa mainloop */
222 static void remove_timeout(DBusTimeout *timeout, void *data) {
223     pa_dbus_wrap_connection *c = data;
224     pa_time_event *ev;
225
226     pa_assert(timeout);
227     pa_assert(c);
228
229     if ((ev = dbus_timeout_get_data(timeout)))
230         c->mainloop->time_free(ev);
231 }
232
233 /* DBusTimeoutToggledFunction callback for pa mainloop */
234 static void toggle_timeout(DBusTimeout *timeout, void *data) {
235     struct timeout_data *d = data;
236     pa_time_event *ev;
237     struct timeval tv;
238
239     pa_assert(d);
240     pa_assert(d->c);
241     pa_assert(timeout);
242
243     pa_assert_se(ev = dbus_timeout_get_data(timeout));
244
245     if (dbus_timeout_get_enabled(timeout)) {
246         d->c->mainloop->time_restart(ev, pa_timeval_rtstore(&tv, pa_rtclock_now() + dbus_timeout_get_interval(timeout) * PA_USEC_PER_MSEC, d->c->use_rtclock));
247     } else
248         d->c->mainloop->time_restart(ev, pa_timeval_rtstore(&tv, PA_USEC_INVALID, d->c->use_rtclock));
249 }
250
251 static void wakeup_main(void *userdata) {
252     pa_dbus_wrap_connection *c = userdata;
253
254     pa_assert(c);
255
256     /* this will wakeup the mainloop and dispatch events, although
257      * it may not be the cleanest way of accomplishing it */
258     c->mainloop->defer_enable(c->dispatch_event, 1);
259 }
260
261 pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, pa_bool_t use_rtclock, DBusBusType type, DBusError *error) {
262     DBusConnection *conn;
263     pa_dbus_wrap_connection *pconn;
264     char *id;
265
266     pa_assert(type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION || type == DBUS_BUS_STARTER);
267
268     if (!(conn = dbus_bus_get_private(type, error)))
269         return NULL;
270
271     pconn = pa_xnew(pa_dbus_wrap_connection, 1);
272     pconn->mainloop = m;
273     pconn->connection = conn;
274     pconn->use_rtclock = use_rtclock;
275
276     dbus_connection_set_exit_on_disconnect(conn, FALSE);
277     dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
278     dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
279     dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
280     dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
281
282     pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
283
284     pa_log_debug("Successfully connected to D-Bus %s bus %s as %s",
285                  type == DBUS_BUS_SYSTEM ? "system" : (type == DBUS_BUS_SESSION ? "session" : "starter"),
286                  pa_strnull((id = dbus_connection_get_server_id(conn))),
287                  pa_strnull(dbus_bus_get_unique_name(conn)));
288
289     dbus_free(id);
290
291     return pconn;
292 }
293
294 pa_dbus_wrap_connection* pa_dbus_wrap_connection_new_from_existing(pa_mainloop_api *m, pa_bool_t use_rtclock, DBusConnection *conn) {
295     pa_dbus_wrap_connection *pconn;
296
297     pa_assert(m);
298     pa_assert(conn);
299
300     pconn = pa_xnew(pa_dbus_wrap_connection, 1);
301     pconn->mainloop = m;
302     pconn->connection = dbus_connection_ref(conn);
303     pconn->use_rtclock = use_rtclock;
304
305     dbus_connection_set_exit_on_disconnect(conn, FALSE);
306     dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
307     dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
308     dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
309     dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
310
311     pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
312
313     return pconn;
314 }
315
316 void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection* c) {
317     pa_assert(c);
318
319     if (dbus_connection_get_is_connected(c->connection)) {
320         dbus_connection_close(c->connection);
321         /* must process remaining messages, bit of a kludge to handle
322          * both unload and shutdown */
323         while (dbus_connection_read_write_dispatch(c->connection, -1))
324             ;
325     }
326
327     c->mainloop->defer_free(c->dispatch_event);
328     dbus_connection_unref(c->connection);
329     pa_xfree(c);
330 }
331
332 DBusConnection* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection *c) {
333   pa_assert(c);
334   pa_assert(c->connection);
335
336   return c->connection;
337 }
338
339 int pa_dbus_add_matches(DBusConnection *c, DBusError *error, ...) {
340     const char *t;
341     va_list ap;
342     unsigned k = 0;
343
344     pa_assert(c);
345     pa_assert(error);
346
347     va_start(ap, error);
348     while ((t = va_arg(ap, const char*))) {
349         dbus_bus_add_match(c, t, error);
350
351         if (dbus_error_is_set(error))
352             goto fail;
353
354         k++;
355     }
356     va_end(ap);
357     return 0;
358
359 fail:
360
361     va_end(ap);
362     va_start(ap, error);
363     for (; k > 0; k--) {
364         DBusError e;
365
366         pa_assert_se(t = va_arg(ap, const char*));
367
368         dbus_error_init(&e);
369         dbus_bus_remove_match(c, t, &e);
370         dbus_error_free(&e);
371     }
372     va_end(ap);
373
374     return -1;
375 }
376
377 void pa_dbus_remove_matches(DBusConnection *c, ...) {
378     const char *t;
379     va_list ap;
380     DBusError error;
381
382     pa_assert(c);
383
384     dbus_error_init(&error);
385
386     va_start(ap, c);
387     while ((t = va_arg(ap, const char*))) {
388         dbus_bus_remove_match(c, t, &error);
389         dbus_error_free(&error);
390     }
391     va_end(ap);
392 }
393
394 pa_dbus_pending *pa_dbus_pending_new(
395         DBusConnection *c,
396         DBusMessage *m,
397         DBusPendingCall *pending,
398         void *context_data,
399         void *call_data) {
400
401     pa_dbus_pending *p;
402
403     pa_assert(pending);
404
405     p = pa_xnew(pa_dbus_pending, 1);
406     p->connection = c;
407     p->message = m;
408     p->pending = pending;
409     p->context_data = context_data;
410     p->call_data = call_data;
411
412     PA_LLIST_INIT(pa_dbus_pending, p);
413
414     return p;
415 }
416
417 void pa_dbus_pending_free(pa_dbus_pending *p) {
418     pa_assert(p);
419
420     if (p->pending) {
421         dbus_pending_call_cancel(p->pending);
422         dbus_pending_call_unref(p->pending);
423     }
424
425     if (p->message)
426         dbus_message_unref(p->message);
427
428     pa_xfree(p);
429 }
430
431 void pa_dbus_sync_pending_list(pa_dbus_pending **p) {
432     pa_assert(p);
433
434     while (*p && dbus_connection_read_write_dispatch((*p)->connection, -1))
435         ;
436 }
437
438 void pa_dbus_free_pending_list(pa_dbus_pending **p) {
439     pa_dbus_pending *i;
440
441     pa_assert(p);
442
443     while ((i = *p)) {
444         PA_LLIST_REMOVE(pa_dbus_pending, *p, i);
445         pa_dbus_pending_free(i);
446     }
447 }
448
449 void pa_dbus_send_error(DBusConnection *c, DBusMessage *in_reply_to, const char *name, const char *format, ...) {
450     va_list ap;
451     char *message;
452     DBusMessage *reply = NULL;
453
454     pa_assert(c);
455     pa_assert(in_reply_to);
456     pa_assert(name);
457     pa_assert(format);
458
459     va_start(ap, format);
460     message = pa_vsprintf_malloc(format, ap);
461     va_end(ap);
462     pa_assert_se((reply = dbus_message_new_error(in_reply_to, name, message)));
463     pa_assert_se(dbus_connection_send(c, reply, NULL));
464
465     dbus_message_unref(reply);
466
467     pa_xfree(message);
468 }
469
470 void pa_dbus_send_empty_reply(DBusConnection *c, DBusMessage *in_reply_to) {
471     DBusMessage *reply = NULL;
472
473     pa_assert(c);
474     pa_assert(in_reply_to);
475
476     pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
477     pa_assert_se(dbus_connection_send(c, reply, NULL));
478     dbus_message_unref(reply);
479 }
480
481 void pa_dbus_send_basic_value_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
482     DBusMessage *reply = NULL;
483
484     pa_assert(c);
485     pa_assert(in_reply_to);
486     pa_assert(dbus_type_is_basic(type));
487     pa_assert(data);
488
489     pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
490     pa_assert_se(dbus_message_append_args(reply, type, data, DBUS_TYPE_INVALID));
491     pa_assert_se(dbus_connection_send(c, reply, NULL));
492     dbus_message_unref(reply);
493 }
494
495 static const char *signature_from_basic_type(int type) {
496     switch (type) {
497         case DBUS_TYPE_BOOLEAN: return DBUS_TYPE_BOOLEAN_AS_STRING;
498         case DBUS_TYPE_BYTE: return DBUS_TYPE_BYTE_AS_STRING;
499         case DBUS_TYPE_INT16: return DBUS_TYPE_INT16_AS_STRING;
500         case DBUS_TYPE_UINT16: return DBUS_TYPE_UINT16_AS_STRING;
501         case DBUS_TYPE_INT32: return DBUS_TYPE_INT32_AS_STRING;
502         case DBUS_TYPE_UINT32: return DBUS_TYPE_UINT32_AS_STRING;
503         case DBUS_TYPE_INT64: return DBUS_TYPE_INT64_AS_STRING;
504         case DBUS_TYPE_UINT64: return DBUS_TYPE_UINT64_AS_STRING;
505         case DBUS_TYPE_DOUBLE: return DBUS_TYPE_DOUBLE_AS_STRING;
506         case DBUS_TYPE_STRING: return DBUS_TYPE_STRING_AS_STRING;
507         case DBUS_TYPE_OBJECT_PATH: return DBUS_TYPE_OBJECT_PATH_AS_STRING;
508         case DBUS_TYPE_SIGNATURE: return DBUS_TYPE_SIGNATURE_AS_STRING;
509         default: pa_assert_not_reached();
510     }
511 }
512
513 void pa_dbus_send_basic_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
514     DBusMessage *reply = NULL;
515     DBusMessageIter msg_iter;
516     DBusMessageIter variant_iter;
517
518     pa_assert(c);
519     pa_assert(in_reply_to);
520     pa_assert(dbus_type_is_basic(type));
521     pa_assert(data);
522
523     pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
524     dbus_message_iter_init_append(reply, &msg_iter);
525     pa_assert_se(dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_VARIANT, signature_from_basic_type(type), &variant_iter));
526     pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
527     pa_assert_se(dbus_message_iter_close_container(&msg_iter, &variant_iter));
528     pa_assert_se(dbus_connection_send(c, reply, NULL));
529     dbus_message_unref(reply);
530 }
531
532 /* Note: returns sizeof(char*) for strings, object paths and signatures. */
533 static unsigned basic_type_size(int type) {
534     switch (type) {
535         case DBUS_TYPE_BOOLEAN: return sizeof(dbus_bool_t);
536         case DBUS_TYPE_BYTE: return 1;
537         case DBUS_TYPE_INT16: return sizeof(dbus_int16_t);
538         case DBUS_TYPE_UINT16: return sizeof(dbus_uint16_t);
539         case DBUS_TYPE_INT32: return sizeof(dbus_int32_t);
540         case DBUS_TYPE_UINT32: return sizeof(dbus_uint32_t);
541         case DBUS_TYPE_INT64: return sizeof(dbus_int64_t);
542         case DBUS_TYPE_UINT64: return sizeof(dbus_uint64_t);
543         case DBUS_TYPE_DOUBLE: return sizeof(double);
544         case DBUS_TYPE_STRING:
545         case DBUS_TYPE_OBJECT_PATH:
546         case DBUS_TYPE_SIGNATURE: return sizeof(char*);
547         default: pa_assert_not_reached();
548     }
549 }
550
551 void pa_dbus_send_basic_array_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, int item_type, void *array, unsigned n) {
552     DBusMessage *reply = NULL;
553     DBusMessageIter msg_iter;
554
555     pa_assert(c);
556     pa_assert(in_reply_to);
557     pa_assert(dbus_type_is_basic(item_type));
558     pa_assert(array || n == 0);
559
560     pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
561     dbus_message_iter_init_append(reply, &msg_iter);
562     pa_dbus_append_basic_array_variant(&msg_iter, item_type, array, n);
563     pa_assert_se(dbus_connection_send(c, reply, NULL));
564     dbus_message_unref(reply);
565 }
566
567 void pa_dbus_send_proplist_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, pa_proplist *proplist) {
568     DBusMessage *reply = NULL;
569     DBusMessageIter msg_iter;
570
571     pa_assert(c);
572     pa_assert(in_reply_to);
573     pa_assert(proplist);
574
575     pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
576     dbus_message_iter_init_append(reply, &msg_iter);
577     pa_dbus_append_proplist_variant(&msg_iter, proplist);
578     pa_assert_se(dbus_connection_send(c, reply, NULL));
579     dbus_message_unref(reply);
580 }
581
582 void pa_dbus_append_basic_array(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
583     DBusMessageIter array_iter;
584     unsigned i;
585     unsigned item_size;
586
587     pa_assert(iter);
588     pa_assert(dbus_type_is_basic(item_type));
589     pa_assert(array || n == 0);
590
591     item_size = basic_type_size(item_type);
592
593     pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, signature_from_basic_type(item_type), &array_iter));
594
595     for (i = 0; i < n; ++i)
596         pa_assert_se(dbus_message_iter_append_basic(&array_iter, item_type, &((uint8_t*) array)[i * item_size]));
597
598     pa_assert_se(dbus_message_iter_close_container(iter, &array_iter));
599 };
600
601 void pa_dbus_append_basic_variant(DBusMessageIter *iter, int type, void *data) {
602     DBusMessageIter variant_iter;
603
604     pa_assert(iter);
605     pa_assert(dbus_type_is_basic(type));
606     pa_assert(data);
607
608     pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, signature_from_basic_type(type), &variant_iter));
609     pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
610     pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
611 }
612
613 void pa_dbus_append_basic_array_variant(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
614     DBusMessageIter variant_iter;
615     char *array_signature;
616
617     pa_assert(iter);
618     pa_assert(dbus_type_is_basic(item_type));
619     pa_assert(array || n == 0);
620
621     array_signature = pa_sprintf_malloc("a%c", *signature_from_basic_type(item_type));
622
623     pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, array_signature, &variant_iter));
624     pa_dbus_append_basic_array(&variant_iter, item_type, array, n);
625     pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
626
627     pa_xfree(array_signature);
628 }
629
630 void pa_dbus_append_basic_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, int type, void *data) {
631     DBusMessageIter dict_entry_iter;
632
633     pa_assert(dict_iter);
634     pa_assert(key);
635     pa_assert(dbus_type_is_basic(type));
636     pa_assert(data);
637
638     pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
639     pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
640     pa_dbus_append_basic_variant(&dict_entry_iter, type, data);
641     pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
642 }
643
644 void pa_dbus_append_basic_array_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, int item_type, const void *array, unsigned n) {
645     DBusMessageIter dict_entry_iter;
646
647     pa_assert(dict_iter);
648     pa_assert(key);
649     pa_assert(dbus_type_is_basic(item_type));
650     pa_assert(array || n == 0);
651
652     pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
653     pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
654     pa_dbus_append_basic_array_variant(&dict_entry_iter, item_type, array, n);
655     pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
656 }
657
658 void pa_dbus_append_proplist(DBusMessageIter *iter, pa_proplist *proplist) {
659     DBusMessageIter dict_iter;
660     DBusMessageIter dict_entry_iter;
661     DBusMessageIter array_iter;
662     void *state = NULL;
663     const char *key;
664
665     pa_assert(iter);
666     pa_assert(proplist);
667
668     pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{say}", &dict_iter));
669
670     while ((key = pa_proplist_iterate(proplist, &state))) {
671         const void *value = NULL;
672         size_t nbytes;
673
674         pa_assert_se(pa_proplist_get(proplist, key, &value, &nbytes) >= 0);
675
676         pa_assert_se(dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
677
678         pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
679
680         pa_assert_se(dbus_message_iter_open_container(&dict_entry_iter, DBUS_TYPE_ARRAY, "y", &array_iter));
681         pa_assert_se(dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, &value, nbytes));
682         pa_assert_se(dbus_message_iter_close_container(&dict_entry_iter, &array_iter));
683
684         pa_assert_se(dbus_message_iter_close_container(&dict_iter, &dict_entry_iter));
685     }
686
687     pa_assert_se(dbus_message_iter_close_container(iter, &dict_iter));
688 }
689
690 void pa_dbus_append_proplist_variant(DBusMessageIter *iter, pa_proplist *proplist) {
691     DBusMessageIter variant_iter;
692
693     pa_assert(iter);
694     pa_assert(proplist);
695
696     pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{say}", &variant_iter));
697     pa_dbus_append_proplist(&variant_iter, proplist);
698     pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
699 }
700
701 void pa_dbus_append_proplist_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, pa_proplist *proplist) {
702     DBusMessageIter dict_entry_iter;
703
704     pa_assert(dict_iter);
705     pa_assert(key);
706     pa_assert(proplist);
707
708     pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
709     pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
710     pa_dbus_append_proplist_variant(&dict_entry_iter, proplist);
711     pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
712 }
713
714 int pa_dbus_get_basic_set_property_arg(DBusConnection *c, DBusMessage *msg, int type, void *data) {
715     DBusMessageIter msg_iter;
716     DBusMessageIter variant_iter;
717
718     pa_assert(c);
719     pa_assert(msg);
720     pa_assert(dbus_type_is_basic(type));
721     pa_assert(data);
722
723     /* Skip the interface and property name arguments. */
724     if (!dbus_message_iter_init(msg, &msg_iter) || !dbus_message_iter_next(&msg_iter) || !dbus_message_iter_next(&msg_iter)) {
725         pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Too few arguments.");
726         return -1;
727     }
728
729     if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_VARIANT) {
730         pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Message argument isn't a variant.");
731         return -1;
732     }
733
734     dbus_message_iter_recurse(&msg_iter, &variant_iter);
735
736     if (pa_dbus_get_basic_arg(c, msg, &variant_iter, type, data) < 0)
737         return -1;
738
739     return 0;
740 }
741
742 int pa_dbus_get_fixed_array_set_property_arg(DBusConnection *c, DBusMessage *msg, int item_type, void *data, unsigned *n) {
743     DBusMessageIter msg_iter;
744     DBusMessageIter variant_iter;
745
746     pa_assert(c);
747     pa_assert(msg);
748     pa_assert(dbus_type_is_fixed(item_type));
749     pa_assert(data);
750     pa_assert(n);
751
752     /* Skip the interface and property name arguments. */
753     if (!dbus_message_iter_init(msg, &msg_iter) || !dbus_message_iter_next(&msg_iter) || !dbus_message_iter_next(&msg_iter)) {
754         pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Too few arguments.");
755         return -1;
756     }
757
758     if (dbus_message_iter_get_arg_type(&msg_iter) != DBUS_TYPE_VARIANT) {
759         pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Message argument isn't a variant.");
760         return -1;
761     }
762
763     dbus_message_iter_recurse(&msg_iter, &variant_iter);
764
765     if (pa_dbus_get_fixed_array_arg(c, msg, &variant_iter, item_type, data, n) < 0)
766         return -1;
767
768     return 0;
769 }
770
771 int pa_dbus_get_basic_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter, int type, void *data) {
772     int arg_type;
773
774     pa_assert(c);
775     pa_assert(msg);
776     pa_assert(iter);
777     pa_assert(dbus_type_is_basic(type));
778     pa_assert(data);
779
780     arg_type = dbus_message_iter_get_arg_type(iter);
781     if (arg_type != type) {
782         if (arg_type == DBUS_TYPE_INVALID)
783             pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Too few arguments. D-Bus type '%c' expected.", (char) type);
784         else
785             pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong argument type: '%c'. Expected type '%c'.", (char) arg_type, (char) type);
786         return -1;
787     }
788
789     dbus_message_iter_get_basic(iter, data);
790
791     dbus_message_iter_next(iter);
792
793     return 0;
794 }
795
796 int pa_dbus_get_fixed_array_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter, int item_type, void *array, unsigned *n) {
797     DBusMessageIter array_iter;
798     int signed_n;
799     int arg_type;
800     int element_type;
801
802     pa_assert(c);
803     pa_assert(msg);
804     pa_assert(iter);
805     pa_assert(dbus_type_is_fixed(item_type));
806     pa_assert(array);
807     pa_assert(n);
808
809     arg_type = dbus_message_iter_get_arg_type(iter);
810     if (arg_type != DBUS_TYPE_ARRAY) {
811         if (arg_type == DBUS_TYPE_INVALID)
812             pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Too few arguments. An array of type '%c' was expected.", (char) item_type);
813         else
814             pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong argument type: '%c'. An array of type '%c' was expected.", (char) arg_type, (char) item_type);
815         return -1;
816     }
817
818     element_type = dbus_message_iter_get_element_type(iter);
819     if (element_type != item_type) {
820         pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong array element type: '%c'. Element type '%c' was expected.", (char) element_type, (char) item_type);
821         return -1;
822     }
823
824     dbus_message_iter_recurse(iter, &array_iter);
825
826     dbus_message_iter_get_fixed_array(&array_iter, array, &signed_n);
827
828     dbus_message_iter_next(iter);
829
830     pa_assert(signed_n >= 0);
831
832     *n = signed_n;
833
834     return 0;
835 }
836
837 pa_proplist *pa_dbus_get_proplist_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter) {
838     DBusMessageIter dict_iter;
839     DBusMessageIter dict_entry_iter;
840     int arg_type;
841     pa_proplist *proplist = NULL;
842     const char *key;
843     const uint8_t *value;
844     int value_length;
845
846     pa_assert(c);
847     pa_assert(msg);
848     pa_assert(iter);
849
850     arg_type = dbus_message_iter_get_arg_type(iter);
851     if (arg_type != DBUS_TYPE_ARRAY) {
852         if (arg_type == DBUS_TYPE_INVALID)
853             pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Too few arguments. An array was expected.");
854         else
855             pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong argument type: '%c'. An array was expected.", (char) arg_type);
856         return NULL;
857     }
858
859     arg_type = dbus_message_iter_get_element_type(iter);
860     if (arg_type != DBUS_TYPE_DICT_ENTRY) {
861         pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong array element type: '%c'. A dictionary entry was expected.", (char) arg_type);
862         return NULL;
863     }
864
865     proplist = pa_proplist_new();
866
867     dbus_message_iter_recurse(iter, &dict_iter);
868
869     while (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_INVALID) {
870         dbus_message_iter_recurse(&dict_iter, &dict_entry_iter);
871
872         arg_type = dbus_message_iter_get_arg_type(&dict_entry_iter);
873         if (arg_type != DBUS_TYPE_STRING) {
874             pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong dict key type: '%c'. A string was expected.", (char) arg_type);
875             goto fail;
876         }
877
878         dbus_message_iter_get_basic(&dict_entry_iter, &key);
879         dbus_message_iter_next(&dict_entry_iter);
880
881         if (strlen(key) <= 0 || !pa_ascii_valid(key)) {
882             pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Invalid property list key.");
883             goto fail;
884         }
885
886         arg_type = dbus_message_iter_get_arg_type(&dict_entry_iter);
887         if (arg_type != DBUS_TYPE_ARRAY) {
888             if (arg_type == DBUS_TYPE_INVALID)
889                 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Dict value missing.");
890             else
891                 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong dict value type: '%c'. An array was expected.", (char) arg_type);
892             goto fail;
893         }
894
895         arg_type = dbus_message_iter_get_element_type(&dict_entry_iter);
896         if (arg_type != DBUS_TYPE_BYTE) {
897             pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Wrong dict value item type: '%c'. A byte was expected.", (char) arg_type);
898             goto fail;
899         }
900
901         dbus_message_iter_get_fixed_array(&dict_entry_iter, &value, &value_length);
902
903         pa_assert(value_length >= 0);
904
905         pa_assert_se(pa_proplist_set(proplist, key, value, value_length) >= 0);
906
907         dbus_message_iter_next(&dict_iter);
908     }
909
910     dbus_message_iter_next(iter);
911
912     return proplist;
913
914 fail:
915     if (proplist)
916         pa_proplist_free(proplist);
917
918     return NULL;
919 }