]> code.delx.au - pulseaudio/blob - src/pulsecore/dbus-util.c
Merge branch 'master' into dbus-work
[pulseaudio] / 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(
295 pa_mainloop_api *m,
296 pa_bool_t use_rtclock,
297 DBusConnection *conn) {
298 pa_dbus_wrap_connection *pconn;
299
300 pa_assert(m);
301 pa_assert(conn);
302
303 pconn = pa_xnew(pa_dbus_wrap_connection, 1);
304 pconn->mainloop = m;
305 pconn->connection = dbus_connection_ref(conn);
306 pconn->use_rtclock = use_rtclock;
307
308 dbus_connection_set_exit_on_disconnect(conn, FALSE);
309 dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
310 dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
311 dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
312 dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
313
314 pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
315
316 return pconn;
317 }
318
319 void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection* c) {
320 pa_assert(c);
321
322 if (dbus_connection_get_is_connected(c->connection)) {
323 dbus_connection_close(c->connection);
324 /* must process remaining messages, bit of a kludge to handle
325 * both unload and shutdown */
326 while (dbus_connection_read_write_dispatch(c->connection, -1))
327 ;
328 }
329
330 c->mainloop->defer_free(c->dispatch_event);
331 dbus_connection_unref(c->connection);
332 pa_xfree(c);
333 }
334
335 DBusConnection* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection *c) {
336 pa_assert(c);
337 pa_assert(c->connection);
338
339 return c->connection;
340 }
341
342 int pa_dbus_add_matches(DBusConnection *c, DBusError *error, ...) {
343 const char *t;
344 va_list ap;
345 unsigned k = 0;
346
347 pa_assert(c);
348 pa_assert(error);
349
350 va_start(ap, error);
351 while ((t = va_arg(ap, const char*))) {
352 dbus_bus_add_match(c, t, error);
353
354 if (dbus_error_is_set(error))
355 goto fail;
356
357 k++;
358 }
359 va_end(ap);
360 return 0;
361
362 fail:
363
364 va_end(ap);
365 va_start(ap, error);
366 for (; k > 0; k--) {
367 DBusError e;
368
369 pa_assert_se(t = va_arg(ap, const char*));
370
371 dbus_error_init(&e);
372 dbus_bus_remove_match(c, t, &e);
373 dbus_error_free(&e);
374 }
375 va_end(ap);
376
377 return -1;
378 }
379
380 void pa_dbus_remove_matches(DBusConnection *c, ...) {
381 const char *t;
382 va_list ap;
383 DBusError error;
384
385 pa_assert(c);
386
387 dbus_error_init(&error);
388
389 va_start(ap, c);
390 while ((t = va_arg(ap, const char*))) {
391 dbus_bus_remove_match(c, t, &error);
392 dbus_error_free(&error);
393 }
394 va_end(ap);
395 }
396
397 pa_dbus_pending *pa_dbus_pending_new(
398 DBusConnection *c,
399 DBusMessage *m,
400 DBusPendingCall *pending,
401 void *context_data,
402 void *call_data) {
403
404 pa_dbus_pending *p;
405
406 pa_assert(pending);
407
408 p = pa_xnew(pa_dbus_pending, 1);
409 p->connection = c;
410 p->message = m;
411 p->pending = pending;
412 p->context_data = context_data;
413 p->call_data = call_data;
414
415 PA_LLIST_INIT(pa_dbus_pending, p);
416
417 return p;
418 }
419
420 void pa_dbus_pending_free(pa_dbus_pending *p) {
421 pa_assert(p);
422
423 if (p->pending) {
424 dbus_pending_call_cancel(p->pending);
425 dbus_pending_call_unref(p->pending);
426 }
427
428 if (p->message)
429 dbus_message_unref(p->message);
430
431 pa_xfree(p);
432 }
433
434 void pa_dbus_sync_pending_list(pa_dbus_pending **p) {
435 pa_assert(p);
436
437 while (*p && dbus_connection_read_write_dispatch((*p)->connection, -1))
438 ;
439 }
440
441 void pa_dbus_free_pending_list(pa_dbus_pending **p) {
442 pa_dbus_pending *i;
443
444 pa_assert(p);
445
446 while ((i = *p)) {
447 PA_LLIST_REMOVE(pa_dbus_pending, *p, i);
448 pa_dbus_pending_free(i);
449 }
450 }
451
452 void pa_dbus_send_error(DBusConnection *c, DBusMessage *in_reply_to, const char *name, const char *format, ...) {
453 va_list ap;
454 char *message;
455 DBusMessage *reply = NULL;
456
457 pa_assert(c);
458 pa_assert(in_reply_to);
459 pa_assert(name);
460 pa_assert(format);
461
462 va_start(ap, format);
463 message = pa_vsprintf_malloc(format, ap);
464 va_end(ap);
465 pa_assert_se((reply = dbus_message_new_error(in_reply_to, name, message)));
466 pa_assert_se(dbus_connection_send(c, reply, NULL));
467
468 dbus_message_unref(reply);
469
470 pa_xfree(message);
471 }
472
473 void pa_dbus_send_empty_reply(DBusConnection *c, DBusMessage *in_reply_to) {
474 DBusMessage *reply = NULL;
475
476 pa_assert(c);
477 pa_assert(in_reply_to);
478
479 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
480 pa_assert_se(dbus_connection_send(c, reply, NULL));
481 dbus_message_unref(reply);
482 }
483
484 void pa_dbus_send_basic_value_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
485 DBusMessage *reply = NULL;
486
487 pa_assert(c);
488 pa_assert(in_reply_to);
489 pa_assert(dbus_type_is_basic(type));
490 pa_assert(data);
491
492 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
493 pa_assert_se(dbus_message_append_args(reply, type, data, DBUS_TYPE_INVALID));
494 pa_assert_se(dbus_connection_send(c, reply, NULL));
495 dbus_message_unref(reply);
496 }
497
498 static const char *signature_from_basic_type(int type) {
499 switch (type) {
500 case DBUS_TYPE_BOOLEAN: return DBUS_TYPE_BOOLEAN_AS_STRING;
501 case DBUS_TYPE_BYTE: return DBUS_TYPE_BYTE_AS_STRING;
502 case DBUS_TYPE_INT16: return DBUS_TYPE_INT16_AS_STRING;
503 case DBUS_TYPE_UINT16: return DBUS_TYPE_UINT16_AS_STRING;
504 case DBUS_TYPE_INT32: return DBUS_TYPE_INT32_AS_STRING;
505 case DBUS_TYPE_UINT32: return DBUS_TYPE_UINT32_AS_STRING;
506 case DBUS_TYPE_INT64: return DBUS_TYPE_INT64_AS_STRING;
507 case DBUS_TYPE_UINT64: return DBUS_TYPE_UINT64_AS_STRING;
508 case DBUS_TYPE_DOUBLE: return DBUS_TYPE_DOUBLE_AS_STRING;
509 case DBUS_TYPE_STRING: return DBUS_TYPE_STRING_AS_STRING;
510 case DBUS_TYPE_OBJECT_PATH: return DBUS_TYPE_OBJECT_PATH_AS_STRING;
511 case DBUS_TYPE_SIGNATURE: return DBUS_TYPE_SIGNATURE_AS_STRING;
512 default: pa_assert_not_reached();
513 }
514 }
515
516 void pa_dbus_send_basic_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
517 DBusMessage *reply = NULL;
518 DBusMessageIter msg_iter;
519 DBusMessageIter variant_iter;
520
521 pa_assert(c);
522 pa_assert(in_reply_to);
523 pa_assert(dbus_type_is_basic(type));
524 pa_assert(data);
525
526 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
527 dbus_message_iter_init_append(reply, &msg_iter);
528 pa_assert_se(dbus_message_iter_open_container(&msg_iter,
529 DBUS_TYPE_VARIANT,
530 signature_from_basic_type(type),
531 &variant_iter));
532 pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
533 pa_assert_se(dbus_message_iter_close_container(&msg_iter, &variant_iter));
534 pa_assert_se(dbus_connection_send(c, reply, NULL));
535 dbus_message_unref(reply);
536 }
537
538 /* Note: returns sizeof(char*) for strings, object paths and signatures. */
539 static unsigned basic_type_size(int type) {
540 switch (type) {
541 case DBUS_TYPE_BOOLEAN: return sizeof(dbus_bool_t);
542 case DBUS_TYPE_BYTE: return 1;
543 case DBUS_TYPE_INT16: return sizeof(dbus_int16_t);
544 case DBUS_TYPE_UINT16: return sizeof(dbus_uint16_t);
545 case DBUS_TYPE_INT32: return sizeof(dbus_int32_t);
546 case DBUS_TYPE_UINT32: return sizeof(dbus_uint32_t);
547 case DBUS_TYPE_INT64: return sizeof(dbus_int64_t);
548 case DBUS_TYPE_UINT64: return sizeof(dbus_uint64_t);
549 case DBUS_TYPE_DOUBLE: return sizeof(double);
550 case DBUS_TYPE_STRING:
551 case DBUS_TYPE_OBJECT_PATH:
552 case DBUS_TYPE_SIGNATURE: return sizeof(char*);
553 default: pa_assert_not_reached();
554 }
555 }
556
557 void pa_dbus_send_basic_array_variant_reply(
558 DBusConnection *c,
559 DBusMessage *in_reply_to,
560 int item_type,
561 void *array,
562 unsigned n) {
563 DBusMessage *reply = NULL;
564 DBusMessageIter msg_iter;
565
566 pa_assert(c);
567 pa_assert(in_reply_to);
568 pa_assert(dbus_type_is_basic(item_type));
569 pa_assert(array || n == 0);
570
571 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
572 dbus_message_iter_init_append(reply, &msg_iter);
573 pa_dbus_append_basic_array_variant(&msg_iter, item_type, array, n);
574 pa_assert_se(dbus_connection_send(c, reply, NULL));
575 dbus_message_unref(reply);
576 }
577
578 void pa_dbus_send_proplist_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, pa_proplist *proplist) {
579 DBusMessage *reply = NULL;
580 DBusMessageIter msg_iter;
581
582 pa_assert(c);
583 pa_assert(in_reply_to);
584 pa_assert(proplist);
585
586 pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
587 dbus_message_iter_init_append(reply, &msg_iter);
588 pa_dbus_append_proplist_variant(&msg_iter, proplist);
589 pa_assert_se(dbus_connection_send(c, reply, NULL));
590 dbus_message_unref(reply);
591 }
592
593 void pa_dbus_append_basic_array(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
594 DBusMessageIter array_iter;
595 unsigned i;
596 unsigned item_size;
597
598 pa_assert(iter);
599 pa_assert(dbus_type_is_basic(item_type));
600 pa_assert(array || n == 0);
601
602 item_size = basic_type_size(item_type);
603
604 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, signature_from_basic_type(item_type), &array_iter));
605
606 for (i = 0; i < n; ++i)
607 pa_assert_se(dbus_message_iter_append_basic(&array_iter, item_type, &((uint8_t*) array)[i * item_size]));
608
609 pa_assert_se(dbus_message_iter_close_container(iter, &array_iter));
610 };
611
612 void pa_dbus_append_basic_variant(DBusMessageIter *iter, int type, void *data) {
613 DBusMessageIter variant_iter;
614
615 pa_assert(iter);
616 pa_assert(dbus_type_is_basic(type));
617 pa_assert(data);
618
619 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, signature_from_basic_type(type), &variant_iter));
620 pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
621 pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
622 }
623
624 void pa_dbus_append_basic_array_variant(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
625 DBusMessageIter variant_iter;
626 char *array_signature;
627
628 pa_assert(iter);
629 pa_assert(dbus_type_is_basic(item_type));
630 pa_assert(array || n == 0);
631
632 array_signature = pa_sprintf_malloc("a%c", *signature_from_basic_type(item_type));
633
634 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, array_signature, &variant_iter));
635 pa_dbus_append_basic_array(&variant_iter, item_type, array, n);
636 pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
637
638 pa_xfree(array_signature);
639 }
640
641 void pa_dbus_append_basic_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, int type, void *data) {
642 DBusMessageIter dict_entry_iter;
643
644 pa_assert(dict_iter);
645 pa_assert(key);
646 pa_assert(dbus_type_is_basic(type));
647 pa_assert(data);
648
649 pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
650 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
651 pa_dbus_append_basic_variant(&dict_entry_iter, type, data);
652 pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
653 }
654
655 void pa_dbus_append_basic_array_variant_dict_entry(
656 DBusMessageIter *dict_iter,
657 const char *key,
658 int item_type,
659 const void *array,
660 unsigned n) {
661 DBusMessageIter dict_entry_iter;
662
663 pa_assert(dict_iter);
664 pa_assert(key);
665 pa_assert(dbus_type_is_basic(item_type));
666 pa_assert(array || n == 0);
667
668 pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
669 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
670 pa_dbus_append_basic_array_variant(&dict_entry_iter, item_type, array, n);
671 pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
672 }
673
674 void pa_dbus_append_proplist(DBusMessageIter *iter, pa_proplist *proplist) {
675 DBusMessageIter dict_iter;
676 DBusMessageIter dict_entry_iter;
677 DBusMessageIter array_iter;
678 void *state = NULL;
679 const char *key;
680
681 pa_assert(iter);
682 pa_assert(proplist);
683
684 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{say}", &dict_iter));
685
686 while ((key = pa_proplist_iterate(proplist, &state))) {
687 const void *value = NULL;
688 size_t nbytes;
689
690 pa_assert_se(pa_proplist_get(proplist, key, &value, &nbytes) >= 0);
691
692 pa_assert_se(dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
693
694 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
695
696 pa_assert_se(dbus_message_iter_open_container(&dict_entry_iter, DBUS_TYPE_ARRAY, "y", &array_iter));
697 pa_assert_se(dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, &value, nbytes));
698 pa_assert_se(dbus_message_iter_close_container(&dict_entry_iter, &array_iter));
699
700 pa_assert_se(dbus_message_iter_close_container(&dict_iter, &dict_entry_iter));
701 }
702
703 pa_assert_se(dbus_message_iter_close_container(iter, &dict_iter));
704 }
705
706 void pa_dbus_append_proplist_variant(DBusMessageIter *iter, pa_proplist *proplist) {
707 DBusMessageIter variant_iter;
708
709 pa_assert(iter);
710 pa_assert(proplist);
711
712 pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{say}", &variant_iter));
713 pa_dbus_append_proplist(&variant_iter, proplist);
714 pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
715 }
716
717 void pa_dbus_append_proplist_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, pa_proplist *proplist) {
718 DBusMessageIter dict_entry_iter;
719
720 pa_assert(dict_iter);
721 pa_assert(key);
722 pa_assert(proplist);
723
724 pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
725 pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
726 pa_dbus_append_proplist_variant(&dict_entry_iter, proplist);
727 pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
728 }
729
730 pa_proplist *pa_dbus_get_proplist_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter) {
731 DBusMessageIter dict_iter;
732 DBusMessageIter dict_entry_iter;
733 pa_proplist *proplist = NULL;
734 const char *key = NULL;
735 const uint8_t *value = NULL;
736 int value_length = 0;
737
738 pa_assert(c);
739 pa_assert(msg);
740 pa_assert(iter);
741 pa_assert(pa_streq(dbus_message_iter_get_signature(iter), "a{say}"));
742
743 proplist = pa_proplist_new();
744
745 dbus_message_iter_recurse(iter, &dict_iter);
746
747 while (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_INVALID) {
748 dbus_message_iter_recurse(&dict_iter, &dict_entry_iter);
749
750 dbus_message_iter_get_basic(&dict_entry_iter, &key);
751 dbus_message_iter_next(&dict_entry_iter);
752
753 if (strlen(key) <= 0 || !pa_ascii_valid(key)) {
754 pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Invalid property list key: '%s'.", key);
755 goto fail;
756 }
757
758 dbus_message_iter_get_fixed_array(&dict_entry_iter, &value, &value_length);
759
760 pa_assert(value_length >= 0);
761
762 pa_assert_se(pa_proplist_set(proplist, key, value, value_length) >= 0);
763
764 dbus_message_iter_next(&dict_iter);
765 }
766
767 dbus_message_iter_next(iter);
768
769 return proplist;
770
771 fail:
772 if (proplist)
773 pa_proplist_free(proplist);
774
775 return NULL;
776 }