153a5a1b3Sopenharmony_ci/***
253a5a1b3Sopenharmony_ci  This file is part of PulseAudio.
353a5a1b3Sopenharmony_ci
453a5a1b3Sopenharmony_ci  Copyright 2006 Lennart Poettering
553a5a1b3Sopenharmony_ci  Copyright 2006 Shams E. King
653a5a1b3Sopenharmony_ci
753a5a1b3Sopenharmony_ci  PulseAudio is free software; you can redistribute it and/or modify
853a5a1b3Sopenharmony_ci  it under the terms of the GNU Lesser General Public License as published
953a5a1b3Sopenharmony_ci  by the Free Software Foundation; either version 2.1 of the License,
1053a5a1b3Sopenharmony_ci  or (at your option) any later version.
1153a5a1b3Sopenharmony_ci
1253a5a1b3Sopenharmony_ci  PulseAudio is distributed in the hope that it will be useful, but
1353a5a1b3Sopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1453a5a1b3Sopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1553a5a1b3Sopenharmony_ci  General Public License for more details.
1653a5a1b3Sopenharmony_ci
1753a5a1b3Sopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1853a5a1b3Sopenharmony_ci  along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
1953a5a1b3Sopenharmony_ci***/
2053a5a1b3Sopenharmony_ci
2153a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H
2253a5a1b3Sopenharmony_ci#include <config.h>
2353a5a1b3Sopenharmony_ci#endif
2453a5a1b3Sopenharmony_ci
2553a5a1b3Sopenharmony_ci#include <stdarg.h>
2653a5a1b3Sopenharmony_ci
2753a5a1b3Sopenharmony_ci#include <pulse/rtclock.h>
2853a5a1b3Sopenharmony_ci#include <pulse/timeval.h>
2953a5a1b3Sopenharmony_ci#include <pulse/utf8.h>
3053a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h>
3153a5a1b3Sopenharmony_ci
3253a5a1b3Sopenharmony_ci#include <pulsecore/core-rtclock.h>
3353a5a1b3Sopenharmony_ci#include <pulsecore/core-util.h>
3453a5a1b3Sopenharmony_ci#include <pulsecore/log.h>
3553a5a1b3Sopenharmony_ci
3653a5a1b3Sopenharmony_ci#include "dbus-util.h"
3753a5a1b3Sopenharmony_ci
3853a5a1b3Sopenharmony_cistruct pa_dbus_wrap_connection {
3953a5a1b3Sopenharmony_ci    pa_mainloop_api *mainloop;
4053a5a1b3Sopenharmony_ci    DBusConnection *connection;
4153a5a1b3Sopenharmony_ci    pa_defer_event* dispatch_event;
4253a5a1b3Sopenharmony_ci    bool use_rtclock:1;
4353a5a1b3Sopenharmony_ci};
4453a5a1b3Sopenharmony_ci
4553a5a1b3Sopenharmony_cistruct timeout_data {
4653a5a1b3Sopenharmony_ci    pa_dbus_wrap_connection *connection;
4753a5a1b3Sopenharmony_ci    DBusTimeout *timeout;
4853a5a1b3Sopenharmony_ci};
4953a5a1b3Sopenharmony_ci
5053a5a1b3Sopenharmony_cistatic void dispatch_cb(pa_mainloop_api *ea, pa_defer_event *ev, void *userdata) {
5153a5a1b3Sopenharmony_ci    DBusConnection *conn = userdata;
5253a5a1b3Sopenharmony_ci
5353a5a1b3Sopenharmony_ci    if (dbus_connection_dispatch(conn) == DBUS_DISPATCH_COMPLETE)
5453a5a1b3Sopenharmony_ci        /* no more data to process, disable the deferred */
5553a5a1b3Sopenharmony_ci        ea->defer_enable(ev, 0);
5653a5a1b3Sopenharmony_ci}
5753a5a1b3Sopenharmony_ci
5853a5a1b3Sopenharmony_ci/* DBusDispatchStatusFunction callback for the pa mainloop */
5953a5a1b3Sopenharmony_cistatic void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata) {
6053a5a1b3Sopenharmony_ci    pa_dbus_wrap_connection *c = userdata;
6153a5a1b3Sopenharmony_ci
6253a5a1b3Sopenharmony_ci    pa_assert(c);
6353a5a1b3Sopenharmony_ci
6453a5a1b3Sopenharmony_ci    switch(status) {
6553a5a1b3Sopenharmony_ci
6653a5a1b3Sopenharmony_ci        case DBUS_DISPATCH_COMPLETE:
6753a5a1b3Sopenharmony_ci            c->mainloop->defer_enable(c->dispatch_event, 0);
6853a5a1b3Sopenharmony_ci            break;
6953a5a1b3Sopenharmony_ci
7053a5a1b3Sopenharmony_ci        case DBUS_DISPATCH_DATA_REMAINS:
7153a5a1b3Sopenharmony_ci        case DBUS_DISPATCH_NEED_MEMORY:
7253a5a1b3Sopenharmony_ci        default:
7353a5a1b3Sopenharmony_ci            c->mainloop->defer_enable(c->dispatch_event, 1);
7453a5a1b3Sopenharmony_ci            break;
7553a5a1b3Sopenharmony_ci    }
7653a5a1b3Sopenharmony_ci}
7753a5a1b3Sopenharmony_ci
7853a5a1b3Sopenharmony_cistatic pa_io_event_flags_t get_watch_flags(DBusWatch *watch) {
7953a5a1b3Sopenharmony_ci    unsigned int flags;
8053a5a1b3Sopenharmony_ci    pa_io_event_flags_t events = 0;
8153a5a1b3Sopenharmony_ci
8253a5a1b3Sopenharmony_ci    pa_assert(watch);
8353a5a1b3Sopenharmony_ci
8453a5a1b3Sopenharmony_ci    flags = dbus_watch_get_flags(watch);
8553a5a1b3Sopenharmony_ci
8653a5a1b3Sopenharmony_ci    /* no watch flags for disabled watches */
8753a5a1b3Sopenharmony_ci    if (!dbus_watch_get_enabled(watch))
8853a5a1b3Sopenharmony_ci        return PA_IO_EVENT_NULL;
8953a5a1b3Sopenharmony_ci
9053a5a1b3Sopenharmony_ci    if (flags & DBUS_WATCH_READABLE)
9153a5a1b3Sopenharmony_ci        events |= PA_IO_EVENT_INPUT;
9253a5a1b3Sopenharmony_ci    if (flags & DBUS_WATCH_WRITABLE)
9353a5a1b3Sopenharmony_ci        events |= PA_IO_EVENT_OUTPUT;
9453a5a1b3Sopenharmony_ci
9553a5a1b3Sopenharmony_ci    return events | PA_IO_EVENT_HANGUP | PA_IO_EVENT_ERROR;
9653a5a1b3Sopenharmony_ci}
9753a5a1b3Sopenharmony_ci
9853a5a1b3Sopenharmony_ci/* pa_io_event_cb_t IO event handler */
9953a5a1b3Sopenharmony_cistatic void handle_io_event(pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_event_flags_t events, void *userdata) {
10053a5a1b3Sopenharmony_ci    unsigned int flags = 0;
10153a5a1b3Sopenharmony_ci    DBusWatch *watch = userdata;
10253a5a1b3Sopenharmony_ci
10353a5a1b3Sopenharmony_ci    pa_assert(fd == dbus_watch_get_unix_fd(watch));
10453a5a1b3Sopenharmony_ci
10553a5a1b3Sopenharmony_ci    if (!dbus_watch_get_enabled(watch)) {
10653a5a1b3Sopenharmony_ci        pa_log_warn("Asked to handle disabled watch: %p %i", (void*) watch, fd);
10753a5a1b3Sopenharmony_ci        return;
10853a5a1b3Sopenharmony_ci    }
10953a5a1b3Sopenharmony_ci
11053a5a1b3Sopenharmony_ci    if (events & PA_IO_EVENT_INPUT)
11153a5a1b3Sopenharmony_ci        flags |= DBUS_WATCH_READABLE;
11253a5a1b3Sopenharmony_ci    if (events & PA_IO_EVENT_OUTPUT)
11353a5a1b3Sopenharmony_ci        flags |= DBUS_WATCH_WRITABLE;
11453a5a1b3Sopenharmony_ci    if (events & PA_IO_EVENT_HANGUP)
11553a5a1b3Sopenharmony_ci        flags |= DBUS_WATCH_HANGUP;
11653a5a1b3Sopenharmony_ci    if (events & PA_IO_EVENT_ERROR)
11753a5a1b3Sopenharmony_ci        flags |= DBUS_WATCH_ERROR;
11853a5a1b3Sopenharmony_ci
11953a5a1b3Sopenharmony_ci    dbus_watch_handle(watch, flags);
12053a5a1b3Sopenharmony_ci}
12153a5a1b3Sopenharmony_ci
12253a5a1b3Sopenharmony_ci/* pa_time_event_cb_t timer event handler */
12353a5a1b3Sopenharmony_cistatic void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, const struct timeval *t, void *userdata) {
12453a5a1b3Sopenharmony_ci    struct timeval tv;
12553a5a1b3Sopenharmony_ci    struct timeout_data *d = userdata;
12653a5a1b3Sopenharmony_ci
12753a5a1b3Sopenharmony_ci    pa_assert(d);
12853a5a1b3Sopenharmony_ci    pa_assert(d->connection);
12953a5a1b3Sopenharmony_ci
13053a5a1b3Sopenharmony_ci    if (dbus_timeout_get_enabled(d->timeout)) {
13153a5a1b3Sopenharmony_ci        /* Restart it for the next scheduled time. We do this before
13253a5a1b3Sopenharmony_ci         * calling dbus_timeout_handle() to make sure that the time
13353a5a1b3Sopenharmony_ci         * event is still around. */
13453a5a1b3Sopenharmony_ci        ea->time_restart(e, pa_timeval_rtstore(&tv,
13553a5a1b3Sopenharmony_ci                                               pa_timeval_load(t) + dbus_timeout_get_interval(d->timeout) * PA_USEC_PER_MSEC,
13653a5a1b3Sopenharmony_ci                                               d->connection->use_rtclock));
13753a5a1b3Sopenharmony_ci
13853a5a1b3Sopenharmony_ci        dbus_timeout_handle(d->timeout);
13953a5a1b3Sopenharmony_ci    }
14053a5a1b3Sopenharmony_ci}
14153a5a1b3Sopenharmony_ci
14253a5a1b3Sopenharmony_ci/* DBusAddWatchFunction callback for pa mainloop */
14353a5a1b3Sopenharmony_cistatic dbus_bool_t add_watch(DBusWatch *watch, void *data) {
14453a5a1b3Sopenharmony_ci    pa_dbus_wrap_connection *c = data;
14553a5a1b3Sopenharmony_ci    pa_io_event *ev;
14653a5a1b3Sopenharmony_ci
14753a5a1b3Sopenharmony_ci    pa_assert(watch);
14853a5a1b3Sopenharmony_ci    pa_assert(c);
14953a5a1b3Sopenharmony_ci
15053a5a1b3Sopenharmony_ci    ev = c->mainloop->io_new(
15153a5a1b3Sopenharmony_ci            c->mainloop,
15253a5a1b3Sopenharmony_ci            dbus_watch_get_unix_fd(watch),
15353a5a1b3Sopenharmony_ci            get_watch_flags(watch), handle_io_event, watch);
15453a5a1b3Sopenharmony_ci
15553a5a1b3Sopenharmony_ci    dbus_watch_set_data(watch, ev, NULL);
15653a5a1b3Sopenharmony_ci
15753a5a1b3Sopenharmony_ci    return TRUE;
15853a5a1b3Sopenharmony_ci}
15953a5a1b3Sopenharmony_ci
16053a5a1b3Sopenharmony_ci/* DBusRemoveWatchFunction callback for pa mainloop */
16153a5a1b3Sopenharmony_cistatic void remove_watch(DBusWatch *watch, void *data) {
16253a5a1b3Sopenharmony_ci    pa_dbus_wrap_connection *c = data;
16353a5a1b3Sopenharmony_ci    pa_io_event *ev;
16453a5a1b3Sopenharmony_ci
16553a5a1b3Sopenharmony_ci    pa_assert(watch);
16653a5a1b3Sopenharmony_ci    pa_assert(c);
16753a5a1b3Sopenharmony_ci
16853a5a1b3Sopenharmony_ci    if ((ev = dbus_watch_get_data(watch)))
16953a5a1b3Sopenharmony_ci        c->mainloop->io_free(ev);
17053a5a1b3Sopenharmony_ci}
17153a5a1b3Sopenharmony_ci
17253a5a1b3Sopenharmony_ci/* DBusWatchToggledFunction callback for pa mainloop */
17353a5a1b3Sopenharmony_cistatic void toggle_watch(DBusWatch *watch, void *data) {
17453a5a1b3Sopenharmony_ci    pa_dbus_wrap_connection *c = data;
17553a5a1b3Sopenharmony_ci    pa_io_event *ev;
17653a5a1b3Sopenharmony_ci
17753a5a1b3Sopenharmony_ci    pa_assert(watch);
17853a5a1b3Sopenharmony_ci    pa_assert(c);
17953a5a1b3Sopenharmony_ci
18053a5a1b3Sopenharmony_ci    pa_assert_se(ev = dbus_watch_get_data(watch));
18153a5a1b3Sopenharmony_ci
18253a5a1b3Sopenharmony_ci    /* get_watch_flags() checks if the watch is enabled */
18353a5a1b3Sopenharmony_ci    c->mainloop->io_enable(ev, get_watch_flags(watch));
18453a5a1b3Sopenharmony_ci}
18553a5a1b3Sopenharmony_ci
18653a5a1b3Sopenharmony_cistatic void time_event_destroy_cb(pa_mainloop_api *a, pa_time_event *e, void *userdata) {
18753a5a1b3Sopenharmony_ci    pa_xfree(userdata);
18853a5a1b3Sopenharmony_ci}
18953a5a1b3Sopenharmony_ci
19053a5a1b3Sopenharmony_ci/* DBusAddTimeoutFunction callback for pa mainloop */
19153a5a1b3Sopenharmony_cistatic dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) {
19253a5a1b3Sopenharmony_ci    pa_dbus_wrap_connection *c = data;
19353a5a1b3Sopenharmony_ci    pa_time_event *ev;
19453a5a1b3Sopenharmony_ci    struct timeval tv;
19553a5a1b3Sopenharmony_ci    struct timeout_data *d;
19653a5a1b3Sopenharmony_ci
19753a5a1b3Sopenharmony_ci    pa_assert(timeout);
19853a5a1b3Sopenharmony_ci    pa_assert(c);
19953a5a1b3Sopenharmony_ci
20053a5a1b3Sopenharmony_ci    if (!dbus_timeout_get_enabled(timeout))
20153a5a1b3Sopenharmony_ci        return FALSE;
20253a5a1b3Sopenharmony_ci
20353a5a1b3Sopenharmony_ci    d = pa_xnew(struct timeout_data, 1);
20453a5a1b3Sopenharmony_ci    d->connection = c;
20553a5a1b3Sopenharmony_ci    d->timeout = timeout;
20653a5a1b3Sopenharmony_ci    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);
20753a5a1b3Sopenharmony_ci    c->mainloop->time_set_destroy(ev, time_event_destroy_cb);
20853a5a1b3Sopenharmony_ci
20953a5a1b3Sopenharmony_ci    dbus_timeout_set_data(timeout, ev, NULL);
21053a5a1b3Sopenharmony_ci
21153a5a1b3Sopenharmony_ci    return TRUE;
21253a5a1b3Sopenharmony_ci}
21353a5a1b3Sopenharmony_ci
21453a5a1b3Sopenharmony_ci/* DBusRemoveTimeoutFunction callback for pa mainloop */
21553a5a1b3Sopenharmony_cistatic void remove_timeout(DBusTimeout *timeout, void *data) {
21653a5a1b3Sopenharmony_ci    pa_dbus_wrap_connection *c = data;
21753a5a1b3Sopenharmony_ci    pa_time_event *ev;
21853a5a1b3Sopenharmony_ci
21953a5a1b3Sopenharmony_ci    pa_assert(timeout);
22053a5a1b3Sopenharmony_ci    pa_assert(c);
22153a5a1b3Sopenharmony_ci
22253a5a1b3Sopenharmony_ci    if ((ev = dbus_timeout_get_data(timeout)))
22353a5a1b3Sopenharmony_ci        c->mainloop->time_free(ev);
22453a5a1b3Sopenharmony_ci}
22553a5a1b3Sopenharmony_ci
22653a5a1b3Sopenharmony_ci/* DBusTimeoutToggledFunction callback for pa mainloop */
22753a5a1b3Sopenharmony_cistatic void toggle_timeout(DBusTimeout *timeout, void *data) {
22853a5a1b3Sopenharmony_ci    struct timeout_data *d = data;
22953a5a1b3Sopenharmony_ci    pa_time_event *ev;
23053a5a1b3Sopenharmony_ci    struct timeval tv;
23153a5a1b3Sopenharmony_ci
23253a5a1b3Sopenharmony_ci    pa_assert(d);
23353a5a1b3Sopenharmony_ci    pa_assert(d->connection);
23453a5a1b3Sopenharmony_ci    pa_assert(timeout);
23553a5a1b3Sopenharmony_ci
23653a5a1b3Sopenharmony_ci    pa_assert_se(ev = dbus_timeout_get_data(timeout));
23753a5a1b3Sopenharmony_ci
23853a5a1b3Sopenharmony_ci    if (dbus_timeout_get_enabled(timeout))
23953a5a1b3Sopenharmony_ci        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));
24053a5a1b3Sopenharmony_ci    else
24153a5a1b3Sopenharmony_ci        d->connection->mainloop->time_restart(ev, pa_timeval_rtstore(&tv, PA_USEC_INVALID, d->connection->use_rtclock));
24253a5a1b3Sopenharmony_ci}
24353a5a1b3Sopenharmony_ci
24453a5a1b3Sopenharmony_cistatic void wakeup_main(void *userdata) {
24553a5a1b3Sopenharmony_ci    pa_dbus_wrap_connection *c = userdata;
24653a5a1b3Sopenharmony_ci
24753a5a1b3Sopenharmony_ci    pa_assert(c);
24853a5a1b3Sopenharmony_ci
24953a5a1b3Sopenharmony_ci    /* this will wakeup the mainloop and dispatch events, although
25053a5a1b3Sopenharmony_ci     * it may not be the cleanest way of accomplishing it */
25153a5a1b3Sopenharmony_ci    c->mainloop->defer_enable(c->dispatch_event, 1);
25253a5a1b3Sopenharmony_ci}
25353a5a1b3Sopenharmony_ci
25453a5a1b3Sopenharmony_cipa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, bool use_rtclock, DBusBusType type, DBusError *error) {
25553a5a1b3Sopenharmony_ci    DBusConnection *conn;
25653a5a1b3Sopenharmony_ci    pa_dbus_wrap_connection *pconn;
25753a5a1b3Sopenharmony_ci    char *id;
25853a5a1b3Sopenharmony_ci
25953a5a1b3Sopenharmony_ci    pa_assert(type == DBUS_BUS_SYSTEM || type == DBUS_BUS_SESSION || type == DBUS_BUS_STARTER);
26053a5a1b3Sopenharmony_ci
26153a5a1b3Sopenharmony_ci    if (!(conn = dbus_bus_get_private(type, error)))
26253a5a1b3Sopenharmony_ci        return NULL;
26353a5a1b3Sopenharmony_ci
26453a5a1b3Sopenharmony_ci    pconn = pa_xnew(pa_dbus_wrap_connection, 1);
26553a5a1b3Sopenharmony_ci    pconn->mainloop = m;
26653a5a1b3Sopenharmony_ci    pconn->connection = conn;
26753a5a1b3Sopenharmony_ci    pconn->use_rtclock = use_rtclock;
26853a5a1b3Sopenharmony_ci
26953a5a1b3Sopenharmony_ci    dbus_connection_set_exit_on_disconnect(conn, FALSE);
27053a5a1b3Sopenharmony_ci    dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
27153a5a1b3Sopenharmony_ci    dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
27253a5a1b3Sopenharmony_ci    dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
27353a5a1b3Sopenharmony_ci    dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
27453a5a1b3Sopenharmony_ci
27553a5a1b3Sopenharmony_ci    pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
27653a5a1b3Sopenharmony_ci
27753a5a1b3Sopenharmony_ci    pa_log_debug("Successfully connected to D-Bus %s bus %s as %s",
27853a5a1b3Sopenharmony_ci                 type == DBUS_BUS_SYSTEM ? "system" : (type == DBUS_BUS_SESSION ? "session" : "starter"),
27953a5a1b3Sopenharmony_ci                 pa_strnull((id = dbus_connection_get_server_id(conn))),
28053a5a1b3Sopenharmony_ci                 pa_strnull(dbus_bus_get_unique_name(conn)));
28153a5a1b3Sopenharmony_ci
28253a5a1b3Sopenharmony_ci    dbus_free(id);
28353a5a1b3Sopenharmony_ci
28453a5a1b3Sopenharmony_ci    return pconn;
28553a5a1b3Sopenharmony_ci}
28653a5a1b3Sopenharmony_ci
28753a5a1b3Sopenharmony_cipa_dbus_wrap_connection* pa_dbus_wrap_connection_new_from_existing(
28853a5a1b3Sopenharmony_ci        pa_mainloop_api *m,
28953a5a1b3Sopenharmony_ci        bool use_rtclock,
29053a5a1b3Sopenharmony_ci        DBusConnection *conn) {
29153a5a1b3Sopenharmony_ci    pa_dbus_wrap_connection *pconn;
29253a5a1b3Sopenharmony_ci
29353a5a1b3Sopenharmony_ci    pa_assert(m);
29453a5a1b3Sopenharmony_ci    pa_assert(conn);
29553a5a1b3Sopenharmony_ci
29653a5a1b3Sopenharmony_ci    pconn = pa_xnew(pa_dbus_wrap_connection, 1);
29753a5a1b3Sopenharmony_ci    pconn->mainloop = m;
29853a5a1b3Sopenharmony_ci    pconn->connection = dbus_connection_ref(conn);
29953a5a1b3Sopenharmony_ci    pconn->use_rtclock = use_rtclock;
30053a5a1b3Sopenharmony_ci
30153a5a1b3Sopenharmony_ci    dbus_connection_set_exit_on_disconnect(conn, FALSE);
30253a5a1b3Sopenharmony_ci    dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
30353a5a1b3Sopenharmony_ci    dbus_connection_set_watch_functions(conn, add_watch, remove_watch, toggle_watch, pconn, NULL);
30453a5a1b3Sopenharmony_ci    dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, toggle_timeout, pconn, NULL);
30553a5a1b3Sopenharmony_ci    dbus_connection_set_wakeup_main_function(conn, wakeup_main, pconn, NULL);
30653a5a1b3Sopenharmony_ci
30753a5a1b3Sopenharmony_ci    pconn->dispatch_event = pconn->mainloop->defer_new(pconn->mainloop, dispatch_cb, conn);
30853a5a1b3Sopenharmony_ci
30953a5a1b3Sopenharmony_ci    return pconn;
31053a5a1b3Sopenharmony_ci}
31153a5a1b3Sopenharmony_ci
31253a5a1b3Sopenharmony_civoid pa_dbus_wrap_connection_free(pa_dbus_wrap_connection* c) {
31353a5a1b3Sopenharmony_ci    pa_assert(c);
31453a5a1b3Sopenharmony_ci
31553a5a1b3Sopenharmony_ci    if (dbus_connection_get_is_connected(c->connection)) {
31653a5a1b3Sopenharmony_ci        dbus_connection_close(c->connection);
31753a5a1b3Sopenharmony_ci        /* must process remaining messages, bit of a kludge to handle
31853a5a1b3Sopenharmony_ci         * both unload and shutdown */
31953a5a1b3Sopenharmony_ci        while (dbus_connection_read_write_dispatch(c->connection, -1))
32053a5a1b3Sopenharmony_ci            ;
32153a5a1b3Sopenharmony_ci    }
32253a5a1b3Sopenharmony_ci
32353a5a1b3Sopenharmony_ci    c->mainloop->defer_free(c->dispatch_event);
32453a5a1b3Sopenharmony_ci    dbus_connection_unref(c->connection);
32553a5a1b3Sopenharmony_ci    pa_xfree(c);
32653a5a1b3Sopenharmony_ci}
32753a5a1b3Sopenharmony_ci
32853a5a1b3Sopenharmony_ciDBusConnection* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection *c) {
32953a5a1b3Sopenharmony_ci  pa_assert(c);
33053a5a1b3Sopenharmony_ci  pa_assert(c->connection);
33153a5a1b3Sopenharmony_ci
33253a5a1b3Sopenharmony_ci  return c->connection;
33353a5a1b3Sopenharmony_ci}
33453a5a1b3Sopenharmony_ci
33553a5a1b3Sopenharmony_ciint pa_dbus_add_matches(DBusConnection *c, DBusError *error, ...) {
33653a5a1b3Sopenharmony_ci    const char *t;
33753a5a1b3Sopenharmony_ci    va_list ap;
33853a5a1b3Sopenharmony_ci    unsigned k = 0;
33953a5a1b3Sopenharmony_ci
34053a5a1b3Sopenharmony_ci    pa_assert(c);
34153a5a1b3Sopenharmony_ci    pa_assert(error);
34253a5a1b3Sopenharmony_ci
34353a5a1b3Sopenharmony_ci    va_start(ap, error);
34453a5a1b3Sopenharmony_ci    while ((t = va_arg(ap, const char*))) {
34553a5a1b3Sopenharmony_ci        dbus_bus_add_match(c, t, error);
34653a5a1b3Sopenharmony_ci
34753a5a1b3Sopenharmony_ci        if (dbus_error_is_set(error))
34853a5a1b3Sopenharmony_ci            goto fail;
34953a5a1b3Sopenharmony_ci
35053a5a1b3Sopenharmony_ci        k++;
35153a5a1b3Sopenharmony_ci    }
35253a5a1b3Sopenharmony_ci    va_end(ap);
35353a5a1b3Sopenharmony_ci    return 0;
35453a5a1b3Sopenharmony_ci
35553a5a1b3Sopenharmony_cifail:
35653a5a1b3Sopenharmony_ci
35753a5a1b3Sopenharmony_ci    va_end(ap);
35853a5a1b3Sopenharmony_ci    va_start(ap, error);
35953a5a1b3Sopenharmony_ci    for (; k > 0; k--) {
36053a5a1b3Sopenharmony_ci        pa_assert_se(t = va_arg(ap, const char*));
36153a5a1b3Sopenharmony_ci        dbus_bus_remove_match(c, t, NULL);
36253a5a1b3Sopenharmony_ci    }
36353a5a1b3Sopenharmony_ci    va_end(ap);
36453a5a1b3Sopenharmony_ci
36553a5a1b3Sopenharmony_ci    return -1;
36653a5a1b3Sopenharmony_ci}
36753a5a1b3Sopenharmony_ci
36853a5a1b3Sopenharmony_civoid pa_dbus_remove_matches(DBusConnection *c, ...) {
36953a5a1b3Sopenharmony_ci    const char *t;
37053a5a1b3Sopenharmony_ci    va_list ap;
37153a5a1b3Sopenharmony_ci
37253a5a1b3Sopenharmony_ci    pa_assert(c);
37353a5a1b3Sopenharmony_ci
37453a5a1b3Sopenharmony_ci    va_start(ap, c);
37553a5a1b3Sopenharmony_ci    while ((t = va_arg(ap, const char*)))
37653a5a1b3Sopenharmony_ci        dbus_bus_remove_match(c, t, NULL);
37753a5a1b3Sopenharmony_ci    va_end(ap);
37853a5a1b3Sopenharmony_ci}
37953a5a1b3Sopenharmony_ci
38053a5a1b3Sopenharmony_cipa_dbus_pending *pa_dbus_pending_new(
38153a5a1b3Sopenharmony_ci        DBusConnection *c,
38253a5a1b3Sopenharmony_ci        DBusMessage *m,
38353a5a1b3Sopenharmony_ci        DBusPendingCall *pending,
38453a5a1b3Sopenharmony_ci        void *context_data,
38553a5a1b3Sopenharmony_ci        void *call_data) {
38653a5a1b3Sopenharmony_ci
38753a5a1b3Sopenharmony_ci    pa_dbus_pending *p;
38853a5a1b3Sopenharmony_ci
38953a5a1b3Sopenharmony_ci    pa_assert(pending);
39053a5a1b3Sopenharmony_ci
39153a5a1b3Sopenharmony_ci    p = pa_xnew(pa_dbus_pending, 1);
39253a5a1b3Sopenharmony_ci    p->connection = c;
39353a5a1b3Sopenharmony_ci    p->message = m;
39453a5a1b3Sopenharmony_ci    p->pending = pending;
39553a5a1b3Sopenharmony_ci    p->context_data = context_data;
39653a5a1b3Sopenharmony_ci    p->call_data = call_data;
39753a5a1b3Sopenharmony_ci
39853a5a1b3Sopenharmony_ci    PA_LLIST_INIT(pa_dbus_pending, p);
39953a5a1b3Sopenharmony_ci
40053a5a1b3Sopenharmony_ci    return p;
40153a5a1b3Sopenharmony_ci}
40253a5a1b3Sopenharmony_ci
40353a5a1b3Sopenharmony_civoid pa_dbus_pending_free(pa_dbus_pending *p) {
40453a5a1b3Sopenharmony_ci    pa_assert(p);
40553a5a1b3Sopenharmony_ci
40653a5a1b3Sopenharmony_ci    if (p->pending) {
40753a5a1b3Sopenharmony_ci        dbus_pending_call_cancel(p->pending);
40853a5a1b3Sopenharmony_ci        dbus_pending_call_unref(p->pending);
40953a5a1b3Sopenharmony_ci    }
41053a5a1b3Sopenharmony_ci
41153a5a1b3Sopenharmony_ci    if (p->message)
41253a5a1b3Sopenharmony_ci        dbus_message_unref(p->message);
41353a5a1b3Sopenharmony_ci
41453a5a1b3Sopenharmony_ci    pa_xfree(p);
41553a5a1b3Sopenharmony_ci}
41653a5a1b3Sopenharmony_ci
41753a5a1b3Sopenharmony_civoid pa_dbus_sync_pending_list(pa_dbus_pending **p) {
41853a5a1b3Sopenharmony_ci    pa_assert(p);
41953a5a1b3Sopenharmony_ci
42053a5a1b3Sopenharmony_ci    while (*p && dbus_connection_read_write_dispatch((*p)->connection, -1))
42153a5a1b3Sopenharmony_ci        ;
42253a5a1b3Sopenharmony_ci}
42353a5a1b3Sopenharmony_ci
42453a5a1b3Sopenharmony_civoid pa_dbus_free_pending_list(pa_dbus_pending **p) {
42553a5a1b3Sopenharmony_ci    pa_dbus_pending *i;
42653a5a1b3Sopenharmony_ci
42753a5a1b3Sopenharmony_ci    pa_assert(p);
42853a5a1b3Sopenharmony_ci
42953a5a1b3Sopenharmony_ci    while ((i = *p)) {
43053a5a1b3Sopenharmony_ci        PA_LLIST_REMOVE(pa_dbus_pending, *p, i);
43153a5a1b3Sopenharmony_ci        pa_dbus_pending_free(i);
43253a5a1b3Sopenharmony_ci    }
43353a5a1b3Sopenharmony_ci}
43453a5a1b3Sopenharmony_ci
43553a5a1b3Sopenharmony_ciconst char *pa_dbus_get_error_message(DBusMessage *m) {
43653a5a1b3Sopenharmony_ci    const char *message;
43753a5a1b3Sopenharmony_ci
43853a5a1b3Sopenharmony_ci    pa_assert(m);
43953a5a1b3Sopenharmony_ci    pa_assert(dbus_message_get_type(m) == DBUS_MESSAGE_TYPE_ERROR);
44053a5a1b3Sopenharmony_ci
44153a5a1b3Sopenharmony_ci    if (dbus_message_get_signature(m)[0] != 's')
44253a5a1b3Sopenharmony_ci        return "<no explanation>";
44353a5a1b3Sopenharmony_ci
44453a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_get_args(m, NULL, DBUS_TYPE_STRING, &message, DBUS_TYPE_INVALID));
44553a5a1b3Sopenharmony_ci
44653a5a1b3Sopenharmony_ci    return message;
44753a5a1b3Sopenharmony_ci}
44853a5a1b3Sopenharmony_ci
44953a5a1b3Sopenharmony_civoid pa_dbus_send_error(DBusConnection *c, DBusMessage *in_reply_to, const char *name, const char *format, ...) {
45053a5a1b3Sopenharmony_ci    va_list ap;
45153a5a1b3Sopenharmony_ci    char *message;
45253a5a1b3Sopenharmony_ci    DBusMessage *reply = NULL;
45353a5a1b3Sopenharmony_ci
45453a5a1b3Sopenharmony_ci    pa_assert(c);
45553a5a1b3Sopenharmony_ci    pa_assert(in_reply_to);
45653a5a1b3Sopenharmony_ci    pa_assert(name);
45753a5a1b3Sopenharmony_ci    pa_assert(format);
45853a5a1b3Sopenharmony_ci
45953a5a1b3Sopenharmony_ci    va_start(ap, format);
46053a5a1b3Sopenharmony_ci    message = pa_vsprintf_malloc(format, ap);
46153a5a1b3Sopenharmony_ci    va_end(ap);
46253a5a1b3Sopenharmony_ci    pa_assert_se((reply = dbus_message_new_error(in_reply_to, name, message)));
46353a5a1b3Sopenharmony_ci    pa_assert_se(dbus_connection_send(c, reply, NULL));
46453a5a1b3Sopenharmony_ci
46553a5a1b3Sopenharmony_ci    dbus_message_unref(reply);
46653a5a1b3Sopenharmony_ci
46753a5a1b3Sopenharmony_ci    pa_xfree(message);
46853a5a1b3Sopenharmony_ci}
46953a5a1b3Sopenharmony_ci
47053a5a1b3Sopenharmony_civoid pa_dbus_send_empty_reply(DBusConnection *c, DBusMessage *in_reply_to) {
47153a5a1b3Sopenharmony_ci    DBusMessage *reply = NULL;
47253a5a1b3Sopenharmony_ci
47353a5a1b3Sopenharmony_ci    pa_assert(c);
47453a5a1b3Sopenharmony_ci    pa_assert(in_reply_to);
47553a5a1b3Sopenharmony_ci
47653a5a1b3Sopenharmony_ci    pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
47753a5a1b3Sopenharmony_ci    pa_assert_se(dbus_connection_send(c, reply, NULL));
47853a5a1b3Sopenharmony_ci    dbus_message_unref(reply);
47953a5a1b3Sopenharmony_ci}
48053a5a1b3Sopenharmony_ci
48153a5a1b3Sopenharmony_civoid pa_dbus_send_basic_value_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
48253a5a1b3Sopenharmony_ci    DBusMessage *reply = NULL;
48353a5a1b3Sopenharmony_ci
48453a5a1b3Sopenharmony_ci    pa_assert(c);
48553a5a1b3Sopenharmony_ci    pa_assert(in_reply_to);
48653a5a1b3Sopenharmony_ci    pa_assert(dbus_type_is_basic(type));
48753a5a1b3Sopenharmony_ci    pa_assert(data);
48853a5a1b3Sopenharmony_ci
48953a5a1b3Sopenharmony_ci    pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
49053a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_append_args(reply, type, data, DBUS_TYPE_INVALID));
49153a5a1b3Sopenharmony_ci    pa_assert_se(dbus_connection_send(c, reply, NULL));
49253a5a1b3Sopenharmony_ci    dbus_message_unref(reply);
49353a5a1b3Sopenharmony_ci}
49453a5a1b3Sopenharmony_ci
49553a5a1b3Sopenharmony_cistatic const char *signature_from_basic_type(int type) {
49653a5a1b3Sopenharmony_ci    switch (type) {
49753a5a1b3Sopenharmony_ci        case DBUS_TYPE_BOOLEAN: return DBUS_TYPE_BOOLEAN_AS_STRING;
49853a5a1b3Sopenharmony_ci        case DBUS_TYPE_BYTE: return DBUS_TYPE_BYTE_AS_STRING;
49953a5a1b3Sopenharmony_ci        case DBUS_TYPE_INT16: return DBUS_TYPE_INT16_AS_STRING;
50053a5a1b3Sopenharmony_ci        case DBUS_TYPE_UINT16: return DBUS_TYPE_UINT16_AS_STRING;
50153a5a1b3Sopenharmony_ci        case DBUS_TYPE_INT32: return DBUS_TYPE_INT32_AS_STRING;
50253a5a1b3Sopenharmony_ci        case DBUS_TYPE_UINT32: return DBUS_TYPE_UINT32_AS_STRING;
50353a5a1b3Sopenharmony_ci        case DBUS_TYPE_INT64: return DBUS_TYPE_INT64_AS_STRING;
50453a5a1b3Sopenharmony_ci        case DBUS_TYPE_UINT64: return DBUS_TYPE_UINT64_AS_STRING;
50553a5a1b3Sopenharmony_ci        case DBUS_TYPE_DOUBLE: return DBUS_TYPE_DOUBLE_AS_STRING;
50653a5a1b3Sopenharmony_ci        case DBUS_TYPE_STRING: return DBUS_TYPE_STRING_AS_STRING;
50753a5a1b3Sopenharmony_ci        case DBUS_TYPE_OBJECT_PATH: return DBUS_TYPE_OBJECT_PATH_AS_STRING;
50853a5a1b3Sopenharmony_ci        case DBUS_TYPE_SIGNATURE: return DBUS_TYPE_SIGNATURE_AS_STRING;
50953a5a1b3Sopenharmony_ci        default: pa_assert_not_reached();
51053a5a1b3Sopenharmony_ci    }
51153a5a1b3Sopenharmony_ci}
51253a5a1b3Sopenharmony_ci
51353a5a1b3Sopenharmony_civoid pa_dbus_send_basic_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, int type, void *data) {
51453a5a1b3Sopenharmony_ci    DBusMessage *reply = NULL;
51553a5a1b3Sopenharmony_ci    DBusMessageIter msg_iter;
51653a5a1b3Sopenharmony_ci    DBusMessageIter variant_iter;
51753a5a1b3Sopenharmony_ci
51853a5a1b3Sopenharmony_ci    pa_assert(c);
51953a5a1b3Sopenharmony_ci    pa_assert(in_reply_to);
52053a5a1b3Sopenharmony_ci    pa_assert(dbus_type_is_basic(type));
52153a5a1b3Sopenharmony_ci    pa_assert(data);
52253a5a1b3Sopenharmony_ci
52353a5a1b3Sopenharmony_ci    pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
52453a5a1b3Sopenharmony_ci    dbus_message_iter_init_append(reply, &msg_iter);
52553a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_open_container(&msg_iter,
52653a5a1b3Sopenharmony_ci                                                  DBUS_TYPE_VARIANT,
52753a5a1b3Sopenharmony_ci                                                  signature_from_basic_type(type),
52853a5a1b3Sopenharmony_ci                                                  &variant_iter));
52953a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
53053a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_close_container(&msg_iter, &variant_iter));
53153a5a1b3Sopenharmony_ci    pa_assert_se(dbus_connection_send(c, reply, NULL));
53253a5a1b3Sopenharmony_ci    dbus_message_unref(reply);
53353a5a1b3Sopenharmony_ci}
53453a5a1b3Sopenharmony_ci
53553a5a1b3Sopenharmony_ci/* Note: returns sizeof(char*) for strings, object paths and signatures. */
53653a5a1b3Sopenharmony_cistatic unsigned basic_type_size(int type) {
53753a5a1b3Sopenharmony_ci    switch (type) {
53853a5a1b3Sopenharmony_ci        case DBUS_TYPE_BOOLEAN: return sizeof(dbus_bool_t);
53953a5a1b3Sopenharmony_ci        case DBUS_TYPE_BYTE: return 1;
54053a5a1b3Sopenharmony_ci        case DBUS_TYPE_INT16: return sizeof(dbus_int16_t);
54153a5a1b3Sopenharmony_ci        case DBUS_TYPE_UINT16: return sizeof(dbus_uint16_t);
54253a5a1b3Sopenharmony_ci        case DBUS_TYPE_INT32: return sizeof(dbus_int32_t);
54353a5a1b3Sopenharmony_ci        case DBUS_TYPE_UINT32: return sizeof(dbus_uint32_t);
54453a5a1b3Sopenharmony_ci        case DBUS_TYPE_INT64: return sizeof(dbus_int64_t);
54553a5a1b3Sopenharmony_ci        case DBUS_TYPE_UINT64: return sizeof(dbus_uint64_t);
54653a5a1b3Sopenharmony_ci        case DBUS_TYPE_DOUBLE: return sizeof(double);
54753a5a1b3Sopenharmony_ci        case DBUS_TYPE_STRING:
54853a5a1b3Sopenharmony_ci        case DBUS_TYPE_OBJECT_PATH:
54953a5a1b3Sopenharmony_ci        case DBUS_TYPE_SIGNATURE: return sizeof(char*);
55053a5a1b3Sopenharmony_ci        default: pa_assert_not_reached();
55153a5a1b3Sopenharmony_ci    }
55253a5a1b3Sopenharmony_ci}
55353a5a1b3Sopenharmony_ci
55453a5a1b3Sopenharmony_civoid pa_dbus_send_basic_array_variant_reply(
55553a5a1b3Sopenharmony_ci        DBusConnection *c,
55653a5a1b3Sopenharmony_ci        DBusMessage *in_reply_to,
55753a5a1b3Sopenharmony_ci        int item_type,
55853a5a1b3Sopenharmony_ci        void *array,
55953a5a1b3Sopenharmony_ci        unsigned n) {
56053a5a1b3Sopenharmony_ci    DBusMessage *reply = NULL;
56153a5a1b3Sopenharmony_ci    DBusMessageIter msg_iter;
56253a5a1b3Sopenharmony_ci
56353a5a1b3Sopenharmony_ci    pa_assert(c);
56453a5a1b3Sopenharmony_ci    pa_assert(in_reply_to);
56553a5a1b3Sopenharmony_ci    pa_assert(dbus_type_is_basic(item_type));
56653a5a1b3Sopenharmony_ci    pa_assert(array || n == 0);
56753a5a1b3Sopenharmony_ci
56853a5a1b3Sopenharmony_ci    pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
56953a5a1b3Sopenharmony_ci    dbus_message_iter_init_append(reply, &msg_iter);
57053a5a1b3Sopenharmony_ci    pa_dbus_append_basic_array_variant(&msg_iter, item_type, array, n);
57153a5a1b3Sopenharmony_ci    pa_assert_se(dbus_connection_send(c, reply, NULL));
57253a5a1b3Sopenharmony_ci    dbus_message_unref(reply);
57353a5a1b3Sopenharmony_ci}
57453a5a1b3Sopenharmony_ci
57553a5a1b3Sopenharmony_civoid pa_dbus_send_proplist_variant_reply(DBusConnection *c, DBusMessage *in_reply_to, pa_proplist *proplist) {
57653a5a1b3Sopenharmony_ci    DBusMessage *reply = NULL;
57753a5a1b3Sopenharmony_ci    DBusMessageIter msg_iter;
57853a5a1b3Sopenharmony_ci
57953a5a1b3Sopenharmony_ci    pa_assert(c);
58053a5a1b3Sopenharmony_ci    pa_assert(in_reply_to);
58153a5a1b3Sopenharmony_ci    pa_assert(proplist);
58253a5a1b3Sopenharmony_ci
58353a5a1b3Sopenharmony_ci    pa_assert_se((reply = dbus_message_new_method_return(in_reply_to)));
58453a5a1b3Sopenharmony_ci    dbus_message_iter_init_append(reply, &msg_iter);
58553a5a1b3Sopenharmony_ci    pa_dbus_append_proplist_variant(&msg_iter, proplist);
58653a5a1b3Sopenharmony_ci    pa_assert_se(dbus_connection_send(c, reply, NULL));
58753a5a1b3Sopenharmony_ci    dbus_message_unref(reply);
58853a5a1b3Sopenharmony_ci}
58953a5a1b3Sopenharmony_ci
59053a5a1b3Sopenharmony_civoid pa_dbus_append_basic_array(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
59153a5a1b3Sopenharmony_ci    DBusMessageIter array_iter;
59253a5a1b3Sopenharmony_ci    unsigned i;
59353a5a1b3Sopenharmony_ci    unsigned item_size;
59453a5a1b3Sopenharmony_ci
59553a5a1b3Sopenharmony_ci    pa_assert(iter);
59653a5a1b3Sopenharmony_ci    pa_assert(dbus_type_is_basic(item_type));
59753a5a1b3Sopenharmony_ci    pa_assert(array || n == 0);
59853a5a1b3Sopenharmony_ci
59953a5a1b3Sopenharmony_ci    item_size = basic_type_size(item_type);
60053a5a1b3Sopenharmony_ci
60153a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, signature_from_basic_type(item_type), &array_iter));
60253a5a1b3Sopenharmony_ci
60353a5a1b3Sopenharmony_ci    for (i = 0; i < n; ++i)
60453a5a1b3Sopenharmony_ci        pa_assert_se(dbus_message_iter_append_basic(&array_iter, item_type, &((uint8_t*) array)[i * item_size]));
60553a5a1b3Sopenharmony_ci
60653a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_close_container(iter, &array_iter));
60753a5a1b3Sopenharmony_ci}
60853a5a1b3Sopenharmony_ci
60953a5a1b3Sopenharmony_civoid pa_dbus_append_basic_variant(DBusMessageIter *iter, int type, void *data) {
61053a5a1b3Sopenharmony_ci    DBusMessageIter variant_iter;
61153a5a1b3Sopenharmony_ci
61253a5a1b3Sopenharmony_ci    pa_assert(iter);
61353a5a1b3Sopenharmony_ci    pa_assert(dbus_type_is_basic(type));
61453a5a1b3Sopenharmony_ci    pa_assert(data);
61553a5a1b3Sopenharmony_ci
61653a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, signature_from_basic_type(type), &variant_iter));
61753a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_append_basic(&variant_iter, type, data));
61853a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
61953a5a1b3Sopenharmony_ci}
62053a5a1b3Sopenharmony_ci
62153a5a1b3Sopenharmony_civoid pa_dbus_append_basic_array_variant(DBusMessageIter *iter, int item_type, const void *array, unsigned n) {
62253a5a1b3Sopenharmony_ci    DBusMessageIter variant_iter;
62353a5a1b3Sopenharmony_ci    char *array_signature;
62453a5a1b3Sopenharmony_ci
62553a5a1b3Sopenharmony_ci    pa_assert(iter);
62653a5a1b3Sopenharmony_ci    pa_assert(dbus_type_is_basic(item_type));
62753a5a1b3Sopenharmony_ci    pa_assert(array || n == 0);
62853a5a1b3Sopenharmony_ci
62953a5a1b3Sopenharmony_ci    array_signature = pa_sprintf_malloc("a%c", *signature_from_basic_type(item_type));
63053a5a1b3Sopenharmony_ci
63153a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, array_signature, &variant_iter));
63253a5a1b3Sopenharmony_ci    pa_dbus_append_basic_array(&variant_iter, item_type, array, n);
63353a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
63453a5a1b3Sopenharmony_ci
63553a5a1b3Sopenharmony_ci    pa_xfree(array_signature);
63653a5a1b3Sopenharmony_ci}
63753a5a1b3Sopenharmony_ci
63853a5a1b3Sopenharmony_civoid pa_dbus_append_basic_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, int type, void *data) {
63953a5a1b3Sopenharmony_ci    DBusMessageIter dict_entry_iter;
64053a5a1b3Sopenharmony_ci
64153a5a1b3Sopenharmony_ci    pa_assert(dict_iter);
64253a5a1b3Sopenharmony_ci    pa_assert(key);
64353a5a1b3Sopenharmony_ci    pa_assert(dbus_type_is_basic(type));
64453a5a1b3Sopenharmony_ci    pa_assert(data);
64553a5a1b3Sopenharmony_ci
64653a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
64753a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
64853a5a1b3Sopenharmony_ci    pa_dbus_append_basic_variant(&dict_entry_iter, type, data);
64953a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
65053a5a1b3Sopenharmony_ci}
65153a5a1b3Sopenharmony_ci
65253a5a1b3Sopenharmony_civoid pa_dbus_append_basic_array_variant_dict_entry(
65353a5a1b3Sopenharmony_ci        DBusMessageIter *dict_iter,
65453a5a1b3Sopenharmony_ci        const char *key,
65553a5a1b3Sopenharmony_ci        int item_type,
65653a5a1b3Sopenharmony_ci        const void *array,
65753a5a1b3Sopenharmony_ci        unsigned n) {
65853a5a1b3Sopenharmony_ci    DBusMessageIter dict_entry_iter;
65953a5a1b3Sopenharmony_ci
66053a5a1b3Sopenharmony_ci    pa_assert(dict_iter);
66153a5a1b3Sopenharmony_ci    pa_assert(key);
66253a5a1b3Sopenharmony_ci    pa_assert(dbus_type_is_basic(item_type));
66353a5a1b3Sopenharmony_ci    pa_assert(array || n == 0);
66453a5a1b3Sopenharmony_ci
66553a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
66653a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
66753a5a1b3Sopenharmony_ci    pa_dbus_append_basic_array_variant(&dict_entry_iter, item_type, array, n);
66853a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
66953a5a1b3Sopenharmony_ci}
67053a5a1b3Sopenharmony_ci
67153a5a1b3Sopenharmony_civoid pa_dbus_append_proplist(DBusMessageIter *iter, pa_proplist *proplist) {
67253a5a1b3Sopenharmony_ci    DBusMessageIter dict_iter;
67353a5a1b3Sopenharmony_ci    DBusMessageIter dict_entry_iter;
67453a5a1b3Sopenharmony_ci    DBusMessageIter array_iter;
67553a5a1b3Sopenharmony_ci    void *state = NULL;
67653a5a1b3Sopenharmony_ci    const char *key;
67753a5a1b3Sopenharmony_ci
67853a5a1b3Sopenharmony_ci    pa_assert(iter);
67953a5a1b3Sopenharmony_ci    pa_assert(proplist);
68053a5a1b3Sopenharmony_ci
68153a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "{say}", &dict_iter));
68253a5a1b3Sopenharmony_ci
68353a5a1b3Sopenharmony_ci    while ((key = pa_proplist_iterate(proplist, &state))) {
68453a5a1b3Sopenharmony_ci        const void *value = NULL;
68553a5a1b3Sopenharmony_ci        size_t nbytes;
68653a5a1b3Sopenharmony_ci
68753a5a1b3Sopenharmony_ci        pa_assert_se(pa_proplist_get(proplist, key, &value, &nbytes) >= 0);
68853a5a1b3Sopenharmony_ci
68953a5a1b3Sopenharmony_ci        pa_assert_se(dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
69053a5a1b3Sopenharmony_ci
69153a5a1b3Sopenharmony_ci        pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
69253a5a1b3Sopenharmony_ci
69353a5a1b3Sopenharmony_ci        pa_assert_se(dbus_message_iter_open_container(&dict_entry_iter, DBUS_TYPE_ARRAY, "y", &array_iter));
69453a5a1b3Sopenharmony_ci        pa_assert_se(dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE, &value, nbytes));
69553a5a1b3Sopenharmony_ci        pa_assert_se(dbus_message_iter_close_container(&dict_entry_iter, &array_iter));
69653a5a1b3Sopenharmony_ci
69753a5a1b3Sopenharmony_ci        pa_assert_se(dbus_message_iter_close_container(&dict_iter, &dict_entry_iter));
69853a5a1b3Sopenharmony_ci    }
69953a5a1b3Sopenharmony_ci
70053a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_close_container(iter, &dict_iter));
70153a5a1b3Sopenharmony_ci}
70253a5a1b3Sopenharmony_ci
70353a5a1b3Sopenharmony_civoid pa_dbus_append_proplist_variant(DBusMessageIter *iter, pa_proplist *proplist) {
70453a5a1b3Sopenharmony_ci    DBusMessageIter variant_iter;
70553a5a1b3Sopenharmony_ci
70653a5a1b3Sopenharmony_ci    pa_assert(iter);
70753a5a1b3Sopenharmony_ci    pa_assert(proplist);
70853a5a1b3Sopenharmony_ci
70953a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{say}", &variant_iter));
71053a5a1b3Sopenharmony_ci    pa_dbus_append_proplist(&variant_iter, proplist);
71153a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_close_container(iter, &variant_iter));
71253a5a1b3Sopenharmony_ci}
71353a5a1b3Sopenharmony_ci
71453a5a1b3Sopenharmony_civoid pa_dbus_append_proplist_variant_dict_entry(DBusMessageIter *dict_iter, const char *key, pa_proplist *proplist) {
71553a5a1b3Sopenharmony_ci    DBusMessageIter dict_entry_iter;
71653a5a1b3Sopenharmony_ci
71753a5a1b3Sopenharmony_ci    pa_assert(dict_iter);
71853a5a1b3Sopenharmony_ci    pa_assert(key);
71953a5a1b3Sopenharmony_ci    pa_assert(proplist);
72053a5a1b3Sopenharmony_ci
72153a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_open_container(dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter));
72253a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &key));
72353a5a1b3Sopenharmony_ci    pa_dbus_append_proplist_variant(&dict_entry_iter, proplist);
72453a5a1b3Sopenharmony_ci    pa_assert_se(dbus_message_iter_close_container(dict_iter, &dict_entry_iter));
72553a5a1b3Sopenharmony_ci}
72653a5a1b3Sopenharmony_ci
72753a5a1b3Sopenharmony_cipa_proplist *pa_dbus_get_proplist_arg(DBusConnection *c, DBusMessage *msg, DBusMessageIter *iter) {
72853a5a1b3Sopenharmony_ci    DBusMessageIter dict_iter;
72953a5a1b3Sopenharmony_ci    DBusMessageIter dict_entry_iter;
73053a5a1b3Sopenharmony_ci    char *signature;
73153a5a1b3Sopenharmony_ci    pa_proplist *proplist = NULL;
73253a5a1b3Sopenharmony_ci    const char *key = NULL;
73353a5a1b3Sopenharmony_ci    const uint8_t *value = NULL;
73453a5a1b3Sopenharmony_ci    int value_length = 0;
73553a5a1b3Sopenharmony_ci
73653a5a1b3Sopenharmony_ci    pa_assert(c);
73753a5a1b3Sopenharmony_ci    pa_assert(msg);
73853a5a1b3Sopenharmony_ci    pa_assert(iter);
73953a5a1b3Sopenharmony_ci
74053a5a1b3Sopenharmony_ci    pa_assert_se(signature = dbus_message_iter_get_signature(iter));
74153a5a1b3Sopenharmony_ci    pa_assert_se(pa_streq(signature, "a{say}"));
74253a5a1b3Sopenharmony_ci
74353a5a1b3Sopenharmony_ci    dbus_free(signature);
74453a5a1b3Sopenharmony_ci
74553a5a1b3Sopenharmony_ci    proplist = pa_proplist_new();
74653a5a1b3Sopenharmony_ci
74753a5a1b3Sopenharmony_ci    dbus_message_iter_recurse(iter, &dict_iter);
74853a5a1b3Sopenharmony_ci
74953a5a1b3Sopenharmony_ci    while (dbus_message_iter_get_arg_type(&dict_iter) != DBUS_TYPE_INVALID) {
75053a5a1b3Sopenharmony_ci        dbus_message_iter_recurse(&dict_iter, &dict_entry_iter);
75153a5a1b3Sopenharmony_ci
75253a5a1b3Sopenharmony_ci        dbus_message_iter_get_basic(&dict_entry_iter, &key);
75353a5a1b3Sopenharmony_ci        dbus_message_iter_next(&dict_entry_iter);
75453a5a1b3Sopenharmony_ci
75553a5a1b3Sopenharmony_ci        if (strlen(key) <= 0 || !pa_ascii_valid(key)) {
75653a5a1b3Sopenharmony_ci            pa_dbus_send_error(c, msg, DBUS_ERROR_INVALID_ARGS, "Invalid property list key: '%s'.", key);
75753a5a1b3Sopenharmony_ci            goto fail;
75853a5a1b3Sopenharmony_ci        }
75953a5a1b3Sopenharmony_ci
76053a5a1b3Sopenharmony_ci        dbus_message_iter_get_fixed_array(&dict_entry_iter, &value, &value_length);
76153a5a1b3Sopenharmony_ci
76253a5a1b3Sopenharmony_ci        pa_assert(value_length >= 0);
76353a5a1b3Sopenharmony_ci
76453a5a1b3Sopenharmony_ci        pa_assert_se(pa_proplist_set(proplist, key, value, value_length) >= 0);
76553a5a1b3Sopenharmony_ci
76653a5a1b3Sopenharmony_ci        dbus_message_iter_next(&dict_iter);
76753a5a1b3Sopenharmony_ci    }
76853a5a1b3Sopenharmony_ci
76953a5a1b3Sopenharmony_ci    dbus_message_iter_next(iter);
77053a5a1b3Sopenharmony_ci
77153a5a1b3Sopenharmony_ci    return proplist;
77253a5a1b3Sopenharmony_ci
77353a5a1b3Sopenharmony_cifail:
77453a5a1b3Sopenharmony_ci    if (proplist)
77553a5a1b3Sopenharmony_ci        pa_proplist_free(proplist);
77653a5a1b3Sopenharmony_ci
77753a5a1b3Sopenharmony_ci    return NULL;
77853a5a1b3Sopenharmony_ci}
779