mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	dbus: Implement the Name property of the core object.
This commit is contained in:
		
							parent
							
								
									6e2fec05dd
								
							
						
					
					
						commit
						5c7952e4fa
					
				
					 5 changed files with 942 additions and 151 deletions
				
			
		| 
						 | 
				
			
			@ -943,7 +943,7 @@ int main(int argc, char *argv[]) {
 | 
			
		|||
    if (!conf->system_instance) {
 | 
			
		||||
        if (!(server_lookup = pa_dbusobj_server_lookup_new(c)))
 | 
			
		||||
            goto finish;
 | 
			
		||||
        if (!(lookup_service_bus = register_dbus_name(c, DBUS_BUS_SESSION, "org.pulseaudio.PulseAudio1")))
 | 
			
		||||
        if (!(lookup_service_bus = register_dbus_name(c, DBUS_BUS_SESSION, "org.PulseAudio1")))
 | 
			
		||||
            goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,7 +37,7 @@
 | 
			
		|||
#include "server-lookup.h"
 | 
			
		||||
 | 
			
		||||
#define OBJECT_PATH "/org/pulseaudio1/server_lookup"
 | 
			
		||||
#define INTERFACE "org.pulseaudio.ServerLookup1"
 | 
			
		||||
#define INTERFACE "org.PulseAudio.ServerLookup1"
 | 
			
		||||
 | 
			
		||||
struct pa_dbusobj_server_lookup {
 | 
			
		||||
    pa_core *core;
 | 
			
		||||
| 
						 | 
				
			
			@ -50,17 +50,31 @@ static const char introspection[] =
 | 
			
		|||
    "<node>"
 | 
			
		||||
    " <!-- If you are looking for documentation make sure to check out\n"
 | 
			
		||||
    "      http://pulseaudio.org/wiki/DBusInterface -->\n"
 | 
			
		||||
    " <interface name=\"" INTERFACE "\">"
 | 
			
		||||
    "  <method name=\"GetAddress\">"
 | 
			
		||||
    "   <arg name=\"result\" type=\"s\" direction=\"out\"/>"
 | 
			
		||||
    "  </method>"
 | 
			
		||||
    " </interface>"
 | 
			
		||||
    " <interface name=\"org.freedesktop.DBus.Introspectable\">"
 | 
			
		||||
    "  <method name=\"Introspect\">"
 | 
			
		||||
    "   <arg name=\"data\" type=\"s\" direction=\"out\"/>"
 | 
			
		||||
    "  </method>"
 | 
			
		||||
    " </interface>"
 | 
			
		||||
    "</node>";
 | 
			
		||||
    " <interface name=\"" INTERFACE "\">\n"
 | 
			
		||||
    "  <property name=\"Address\" type=\"s\" access=\"read\"/>\n"
 | 
			
		||||
    " </interface>\n"
 | 
			
		||||
    " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n"
 | 
			
		||||
    "  <method name=\"Introspect\">\n"
 | 
			
		||||
    "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    " </interface>\n"
 | 
			
		||||
    " <interface name=\"" DBUS_INTERFACE_PROPERTIES "\">\n"
 | 
			
		||||
    "  <method name=\"Get\">\n"
 | 
			
		||||
    "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"value\" type=\"v\" direction=\"out\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    "  <method name=\"Set\">\n"
 | 
			
		||||
    "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"value\" type=\"v\" direction=\"in\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    "  <method name=\"GetAll\">\n"
 | 
			
		||||
    "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"props\" type=\"a{sv}\" direction=\"out\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    " </interface>\n"
 | 
			
		||||
    "</node>\n";
 | 
			
		||||
 | 
			
		||||
static void unregister_cb(DBusConnection *conn, void *user_data) {
 | 
			
		||||
    pa_dbusobj_server_lookup *sl = user_data;
 | 
			
		||||
| 
						 | 
				
			
			@ -72,105 +86,352 @@ static void unregister_cb(DBusConnection *conn, void *user_data) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) {
 | 
			
		||||
    DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    const char *i = introspection;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
 | 
			
		||||
    if (!(reply = dbus_message_new_method_return(msg)))
 | 
			
		||||
        goto fail;
 | 
			
		||||
    if (!(reply = dbus_message_new_method_return(msg))) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &i, DBUS_TYPE_INVALID)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &i, DBUS_TYPE_INVALID))
 | 
			
		||||
        goto fail;
 | 
			
		||||
 | 
			
		||||
    if (!dbus_connection_send(conn, reply, NULL))
 | 
			
		||||
        goto oom;
 | 
			
		||||
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
finish:
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
oom:
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
enum get_address_result_t {
 | 
			
		||||
    SUCCESS,
 | 
			
		||||
    FAILED_TO_LOAD_CLIENT_CONF,
 | 
			
		||||
    SERVER_FROM_TYPE_FAILED
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
    return DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
/* Caller frees the returned address. */
 | 
			
		||||
static enum get_address_result_t get_address(pa_server_type_t server_type, char **address) {
 | 
			
		||||
    enum get_address_result_t r = SUCCESS;
 | 
			
		||||
    pa_client_conf *conf = pa_client_conf_new();
 | 
			
		||||
 | 
			
		||||
    *address = NULL;
 | 
			
		||||
 | 
			
		||||
    if (pa_client_conf_load(conf, NULL) < 0) {
 | 
			
		||||
        r = FAILED_TO_LOAD_CLIENT_CONF;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (conf->default_dbus_server)
 | 
			
		||||
        *address = pa_xstrdup(conf->default_dbus_server);
 | 
			
		||||
    else if (!(*address = pa_get_dbus_address_from_server_type(server_type))) {
 | 
			
		||||
        r = SERVER_FROM_TYPE_FAILED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    pa_client_conf_free(conf);
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult handle_get_address(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) {
 | 
			
		||||
    DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    pa_client_conf *conf = NULL;
 | 
			
		||||
    char *address = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter variant_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(sl);
 | 
			
		||||
 | 
			
		||||
    conf = pa_client_conf_new();
 | 
			
		||||
    switch (get_address(sl->core->server_type, &address)) {
 | 
			
		||||
        case SUCCESS:
 | 
			
		||||
            if (!(reply = dbus_message_new_method_return(msg))) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
            if (!dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_VARIANT, "s", &variant_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_STRING, &address)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_close_container(&msg_iter, &variant_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
 | 
			
		||||
    if (pa_client_conf_load(conf, NULL) < 0) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error(msg, "org.pulseaudio.ClientConfLoadError", "Failed to load client.conf.")))
 | 
			
		||||
            goto fail;
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL))
 | 
			
		||||
            goto oom;
 | 
			
		||||
        return DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        case FAILED_TO_LOAD_CLIENT_CONF:
 | 
			
		||||
            if (!(reply = dbus_message_new_error(msg, "org.pulseaudio.ClientConfLoadError", "Failed to load client.conf."))) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
 | 
			
		||||
        case SERVER_FROM_TYPE_FAILED:
 | 
			
		||||
            if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, "PulseAudio internal error: get_dbus_server_from_type() failed."))) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            pa_assert_not_reached();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (conf->default_dbus_server) {
 | 
			
		||||
        address = pa_xstrdup(conf->default_dbus_server);
 | 
			
		||||
    } else {
 | 
			
		||||
        if (!(address = pa_get_dbus_address_from_server_type(sl->core->server_type))) {
 | 
			
		||||
            if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, "PulseAudio internal error: get_dbus_server_from_type() failed.")))
 | 
			
		||||
                goto fail;
 | 
			
		||||
            if (!dbus_connection_send(conn, reply, NULL))
 | 
			
		||||
                goto oom;
 | 
			
		||||
            return DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
finish:
 | 
			
		||||
    pa_xfree(address);
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult handle_get(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) {
 | 
			
		||||
    DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    const char* interface;
 | 
			
		||||
    const char* property;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(sl);
 | 
			
		||||
 | 
			
		||||
    if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, "Invalid arguments"))) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!(reply = dbus_message_new_method_return(msg)))
 | 
			
		||||
        goto oom;
 | 
			
		||||
    if (*interface && !pa_streq(interface, INTERFACE)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID))
 | 
			
		||||
        goto fail;
 | 
			
		||||
    if (!pa_streq(property, "Address")) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error_printf(msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s: No such property", property))) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!dbus_connection_send(conn, reply, NULL))
 | 
			
		||||
        goto oom;
 | 
			
		||||
 | 
			
		||||
    pa_client_conf_free(conf);
 | 
			
		||||
    pa_xfree(address);
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    if (conf)
 | 
			
		||||
        pa_client_conf_free(conf);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(address);
 | 
			
		||||
    r = handle_get_address(conn, msg, sl);
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
oom:
 | 
			
		||||
    if (conf)
 | 
			
		||||
        pa_client_conf_free(conf);
 | 
			
		||||
static DBusHandlerResult handle_set(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) {
 | 
			
		||||
    DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    const char* interface;
 | 
			
		||||
    const char* property;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_xfree(address);
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(sl);
 | 
			
		||||
 | 
			
		||||
    if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, "Invalid arguments"))) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (*interface && !pa_streq(interface, INTERFACE)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!pa_streq(property, "Address")) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error_printf(msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s: No such property", property))) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!(reply = dbus_message_new_error_printf(msg, DBUS_ERROR_ACCESS_DENIED, "%s: Property not settable", property))) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult handle_get_all(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_server_lookup *sl) {
 | 
			
		||||
    DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    const char *property = "Address";
 | 
			
		||||
    char *interface = NULL;
 | 
			
		||||
    char *address = NULL;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter dict_iter;
 | 
			
		||||
    DBusMessageIter dict_entry_iter;
 | 
			
		||||
    DBusMessageIter variant_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(sl);
 | 
			
		||||
 | 
			
		||||
    if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID)) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, "Invalid arguments"))) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    switch (get_address(sl->core->server_type, &address)) {
 | 
			
		||||
        case SUCCESS:
 | 
			
		||||
            if (!(reply = dbus_message_new_method_return(msg))) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
            if (!dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &property)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_open_container(&dict_entry_iter, DBUS_TYPE_VARIANT, "s", &variant_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_STRING, &address)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_close_container(&dict_entry_iter, &variant_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_close_container(&dict_iter, &dict_entry_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_message_iter_close_container(&msg_iter, &dict_iter)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
 | 
			
		||||
        case FAILED_TO_LOAD_CLIENT_CONF:
 | 
			
		||||
            if (!(reply = dbus_message_new_error(msg, "org.pulseaudio.ClientConfLoadError", "Failed to load client.conf."))) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
 | 
			
		||||
        case SERVER_FROM_TYPE_FAILED:
 | 
			
		||||
            if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_FAILED, "PulseAudio internal error: get_dbus_server_from_type() failed."))) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
                r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
                goto finish;
 | 
			
		||||
            }
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            pa_assert_not_reached();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    pa_xfree(address);
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult message_cb(DBusConnection *conn, DBusMessage *msg, void *user_data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -182,11 +443,24 @@ static DBusHandlerResult message_cb(DBusConnection *conn, DBusMessage *msg, void
 | 
			
		|||
 | 
			
		||||
    /* pa_log("Got message! type = %s   path = %s   iface = %s   member = %s   dest = %s", dbus_message_type_to_string(dbus_message_get_type(msg)), dbus_message_get_path(msg), dbus_message_get_interface(msg), dbus_message_get_member(msg), dbus_message_get_destination(msg)); */
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_is_method_call(msg, "org.freedesktop.DBus.Introspectable", "Introspect"))
 | 
			
		||||
    if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_METHOD_CALL)
 | 
			
		||||
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_is_method_call(msg, DBUS_INTERFACE_INTROSPECTABLE, "Introspect") ||
 | 
			
		||||
        (!dbus_message_get_interface(msg) && dbus_message_has_member(msg, "Introspect")))
 | 
			
		||||
        return handle_introspect(conn, msg, sl);
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_is_method_call(msg, INTERFACE, "GetAddress"))
 | 
			
		||||
        return handle_get_address(conn, msg, sl);
 | 
			
		||||
    if (dbus_message_is_method_call(msg, DBUS_INTERFACE_PROPERTIES, "Get") ||
 | 
			
		||||
        (!dbus_message_get_interface(msg) && dbus_message_has_member(msg, "Get")))
 | 
			
		||||
        return handle_get(conn, msg, sl);
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_is_method_call(msg, DBUS_INTERFACE_PROPERTIES, "Set") ||
 | 
			
		||||
        (!dbus_message_get_interface(msg) && dbus_message_has_member(msg, "Set")))
 | 
			
		||||
        return handle_set(conn, msg, sl);
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_is_method_call(msg, DBUS_INTERFACE_PROPERTIES, "GetAll") ||
 | 
			
		||||
        (!dbus_message_get_interface(msg) && dbus_message_has_member(msg, "GetAll")))
 | 
			
		||||
        return handle_get_all(conn, msg, sl);
 | 
			
		||||
 | 
			
		||||
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,6 +48,7 @@ struct object_entry {
 | 
			
		|||
 | 
			
		||||
struct interface_entry {
 | 
			
		||||
    char *name;
 | 
			
		||||
    char **properties;
 | 
			
		||||
    char **methods;
 | 
			
		||||
    char *introspection_snippet;
 | 
			
		||||
    DBusObjectPathMessageFunction receive;
 | 
			
		||||
| 
						 | 
				
			
			@ -106,48 +107,152 @@ static void update_introspection(struct object_entry *oe) {
 | 
			
		|||
 | 
			
		||||
    buf = pa_strbuf_new();
 | 
			
		||||
    pa_strbuf_puts(buf, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
 | 
			
		||||
    pa_strbuf_puts(buf, "<node>");
 | 
			
		||||
    pa_strbuf_puts(buf, "<node>\n");
 | 
			
		||||
 | 
			
		||||
    while ((iface_entry = pa_hashmap_iterate(oe->interfaces, &state, NULL)))
 | 
			
		||||
        pa_strbuf_puts(buf, iface_entry->introspection_snippet);
 | 
			
		||||
 | 
			
		||||
    pa_strbuf_puts(buf, " <interface name=\"org.freedesktop.DBus.Introspectable\">"
 | 
			
		||||
                        "  <method name=\"Introspect\">"
 | 
			
		||||
                        "   <arg name=\"data\" type=\"s\" direction=\"out\"/>"
 | 
			
		||||
                        "  </method>"
 | 
			
		||||
                        " </interface>");
 | 
			
		||||
    pa_strbuf_puts(buf, " <interface name=\"" DBUS_INTERFACE_INTROSPECTABLE "\">\n"
 | 
			
		||||
                        "  <method name=\"Introspect\">\n"
 | 
			
		||||
                        "   <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
 | 
			
		||||
                        "  </method>\n"
 | 
			
		||||
                        " </interface>\n"
 | 
			
		||||
                        " <interface name=\"" DBUS_INTERFACE_PROPERTIES "\">\n"
 | 
			
		||||
                        "  <method name=\"Get\">\n"
 | 
			
		||||
                        "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
                        "   <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
                        "   <arg name=\"value\" type=\"v\" direction=\"out\"/>\n"
 | 
			
		||||
                        "  </method>\n"
 | 
			
		||||
                        "  <method name=\"Set\">\n"
 | 
			
		||||
                        "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
                        "   <arg name=\"property_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
                        "   <arg name=\"value\" type=\"v\" direction=\"in\"/>\n"
 | 
			
		||||
                        "  </method>\n"
 | 
			
		||||
                        "  <method name=\"GetAll\">\n"
 | 
			
		||||
                        "   <arg name=\"interface_name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
                        "   <arg name=\"props\" type=\"a{sv}\" direction=\"out\"/>\n"
 | 
			
		||||
                        "  </method>\n"
 | 
			
		||||
                        " </interface>\n");
 | 
			
		||||
 | 
			
		||||
    pa_strbuf_puts(buf, "</node>");
 | 
			
		||||
    pa_strbuf_puts(buf, "</node>\n");
 | 
			
		||||
 | 
			
		||||
    pa_xfree(oe->introspection);
 | 
			
		||||
    oe->introspection = pa_strbuf_tostring_free(buf);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct interface_entry *find_interface(struct object_entry *obj_entry, DBusMessage *msg) {
 | 
			
		||||
    const char *interface;
 | 
			
		||||
    struct interface_entry *iface_entry;
 | 
			
		||||
enum find_result_t {
 | 
			
		||||
    SUCCESS,
 | 
			
		||||
    NO_SUCH_PROPERTY,
 | 
			
		||||
    NO_SUCH_METHOD,
 | 
			
		||||
    INVALID_MESSAGE_ARGUMENTS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static enum find_result_t find_interface_by_property(struct object_entry *obj_entry, const char *property, struct interface_entry **entry) {
 | 
			
		||||
    void *state = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(obj_entry);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(property);
 | 
			
		||||
    pa_assert(entry);
 | 
			
		||||
 | 
			
		||||
    if ((interface = dbus_message_get_interface(msg)))
 | 
			
		||||
        return pa_hashmap_get(obj_entry->interfaces, interface);
 | 
			
		||||
    while ((*entry = pa_hashmap_iterate(obj_entry->interfaces, &state, NULL))) {
 | 
			
		||||
        char *iface_property;
 | 
			
		||||
        char **pos = (*entry)->properties;
 | 
			
		||||
 | 
			
		||||
    /* NULL interface, we'll have to search for an interface that contains the
 | 
			
		||||
     * method. */
 | 
			
		||||
 | 
			
		||||
    while ((iface_entry = pa_hashmap_iterate(obj_entry->interfaces, &state, NULL))) {
 | 
			
		||||
        char *method;
 | 
			
		||||
        char **pos = iface_entry->methods;
 | 
			
		||||
 | 
			
		||||
        while ((method = *pos++)) {
 | 
			
		||||
            if (!strcmp(dbus_message_get_member(msg), method))
 | 
			
		||||
                return iface_entry;
 | 
			
		||||
        while ((iface_property = *pos++)) {
 | 
			
		||||
            if (pa_streq(iface_property, property))
 | 
			
		||||
                return SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return NULL;
 | 
			
		||||
    return NO_SUCH_PROPERTY;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum find_result_t find_interface_by_method(struct object_entry *obj_entry, const char *method, struct interface_entry **entry) {
 | 
			
		||||
    void *state = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(obj_entry);
 | 
			
		||||
    pa_assert(method);
 | 
			
		||||
    pa_assert(entry);
 | 
			
		||||
 | 
			
		||||
    while ((*entry = pa_hashmap_iterate(obj_entry->interfaces, &state, NULL))) {
 | 
			
		||||
        char *iface_method;
 | 
			
		||||
        char **pos = (*entry)->methods;
 | 
			
		||||
 | 
			
		||||
        while ((iface_method = *pos++)) {
 | 
			
		||||
            if (pa_streq(iface_method, method))
 | 
			
		||||
                return SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return NO_SUCH_METHOD;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum find_result_t find_interface_from_properties_call(struct object_entry *obj_entry, DBusMessage *msg, struct interface_entry **entry) {
 | 
			
		||||
    const char *interface;
 | 
			
		||||
    const char *property;
 | 
			
		||||
 | 
			
		||||
    pa_assert(obj_entry);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(entry);
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_has_member(msg, "GetAll")) {
 | 
			
		||||
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID))
 | 
			
		||||
            return INVALID_MESSAGE_ARGUMENTS;
 | 
			
		||||
 | 
			
		||||
        if (*interface) {
 | 
			
		||||
            if ((*entry = pa_hashmap_get(obj_entry->interfaces, interface)))
 | 
			
		||||
                return SUCCESS;
 | 
			
		||||
            else
 | 
			
		||||
                return NO_SUCH_METHOD;
 | 
			
		||||
        } else {
 | 
			
		||||
            pa_assert_se((*entry = pa_hashmap_first(obj_entry->interfaces)));
 | 
			
		||||
            return SUCCESS;
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        pa_assert(dbus_message_has_member(msg, "Get") || dbus_message_has_member(msg, "Set"));
 | 
			
		||||
 | 
			
		||||
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID))
 | 
			
		||||
            return INVALID_MESSAGE_ARGUMENTS;
 | 
			
		||||
 | 
			
		||||
        if (*interface) {
 | 
			
		||||
            if ((*entry = pa_hashmap_get(obj_entry->interfaces, interface)))
 | 
			
		||||
                return SUCCESS;
 | 
			
		||||
            else
 | 
			
		||||
                return NO_SUCH_METHOD;
 | 
			
		||||
        } else
 | 
			
		||||
            return find_interface_by_property(obj_entry, property, entry);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static enum find_result_t find_interface(struct object_entry *obj_entry, DBusMessage *msg, struct interface_entry **entry) {
 | 
			
		||||
    const char *interface;
 | 
			
		||||
 | 
			
		||||
    pa_assert(obj_entry);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(entry);
 | 
			
		||||
 | 
			
		||||
    *entry = NULL;
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_has_interface(msg, DBUS_INTERFACE_PROPERTIES))
 | 
			
		||||
        return find_interface_from_properties_call(obj_entry, msg, entry);
 | 
			
		||||
 | 
			
		||||
    else if ((interface = dbus_message_get_interface(msg))) {
 | 
			
		||||
        if ((*entry = pa_hashmap_get(obj_entry->interfaces, interface)))
 | 
			
		||||
            return SUCCESS;
 | 
			
		||||
        else
 | 
			
		||||
            return NO_SUCH_METHOD;
 | 
			
		||||
 | 
			
		||||
    } else { /* The method call doesn't contain an interface. */
 | 
			
		||||
        if (dbus_message_has_member(msg, "Get") || dbus_message_has_member(msg, "Set") || dbus_message_has_member(msg, "GetAll")) {
 | 
			
		||||
            if (find_interface_by_method(obj_entry, dbus_message_get_member(msg), entry) == SUCCESS)
 | 
			
		||||
                return SUCCESS; /* The object has a method named Get, Set or GetAll in some other interface than .Properties. */
 | 
			
		||||
            else
 | 
			
		||||
                /* Assume this is a .Properties call. */
 | 
			
		||||
                return find_interface_from_properties_call(obj_entry, msg, entry);
 | 
			
		||||
 | 
			
		||||
        } else /* This is not a .Properties call. */
 | 
			
		||||
            return find_interface_by_method(obj_entry, dbus_message_get_member(msg), entry);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult handle_message_cb(DBusConnection *connection, DBusMessage *message, void *user_data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +271,8 @@ static DBusHandlerResult handle_message_cb(DBusConnection *connection, DBusMessa
 | 
			
		|||
 | 
			
		||||
    pa_assert_se((obj_entry = pa_hashmap_get(dbus_state->objects, dbus_message_get_path(message))));
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
 | 
			
		||||
    if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect") ||
 | 
			
		||||
        (!dbus_message_get_interface(message) && dbus_message_has_member(message, "Introspect"))) {
 | 
			
		||||
        if (!(reply = dbus_message_new_method_return(message)))
 | 
			
		||||
            goto oom;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -183,10 +289,38 @@ static DBusHandlerResult handle_message_cb(DBusConnection *connection, DBusMessa
 | 
			
		|||
        return DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!(iface_entry = find_interface(obj_entry, message)))
 | 
			
		||||
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
    switch (find_interface(obj_entry, message, &iface_entry)) {
 | 
			
		||||
        case SUCCESS:
 | 
			
		||||
            return iface_entry->receive(connection, message, iface_entry->userdata);
 | 
			
		||||
 | 
			
		||||
    return iface_entry->receive(connection, message, iface_entry->userdata);
 | 
			
		||||
        case NO_SUCH_PROPERTY:
 | 
			
		||||
            if (!(reply = dbus_message_new_error(message, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "No such property")))
 | 
			
		||||
                goto fail;
 | 
			
		||||
 | 
			
		||||
            if (!dbus_connection_send(connection, reply, NULL))
 | 
			
		||||
                goto oom;
 | 
			
		||||
 | 
			
		||||
            dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
            return DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
 | 
			
		||||
        case NO_SUCH_METHOD:
 | 
			
		||||
            return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
 | 
			
		||||
        case INVALID_MESSAGE_ARGUMENTS:
 | 
			
		||||
            if (!(reply = dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS, "Invalid arguments")))
 | 
			
		||||
                goto fail;
 | 
			
		||||
 | 
			
		||||
            if (!dbus_connection_send(connection, reply, NULL))
 | 
			
		||||
                goto oom;
 | 
			
		||||
 | 
			
		||||
            dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
            return DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            pa_assert_not_reached();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
    if (reply)
 | 
			
		||||
| 
						 | 
				
			
			@ -226,23 +360,30 @@ static void register_object(struct dbus_state *dbus_state, struct object_entry *
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static char **copy_methods(const char * const *methods) {
 | 
			
		||||
static char **copy_strarray(const char * const *array) {
 | 
			
		||||
    unsigned n = 0;
 | 
			
		||||
    char **copy;
 | 
			
		||||
    unsigned i;
 | 
			
		||||
 | 
			
		||||
    while (methods[n++])
 | 
			
		||||
    while (array[n++])
 | 
			
		||||
        ;
 | 
			
		||||
 | 
			
		||||
    copy = pa_xnew0(char *, n);
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < n - 1; ++i)
 | 
			
		||||
        copy[i] = pa_xstrdup(methods[i]);
 | 
			
		||||
        copy[i] = pa_xstrdup(array[i]);
 | 
			
		||||
 | 
			
		||||
    return copy;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int pa_dbus_add_interface(pa_core *c, const char* path, const char* interface, const char * const *methods, const char* introspection_snippet, DBusObjectPathMessageFunction receive_cb, void *userdata) {
 | 
			
		||||
int pa_dbus_add_interface(pa_core *c,
 | 
			
		||||
                          const char* path,
 | 
			
		||||
                          const char* interface,
 | 
			
		||||
                          const char * const *properties,
 | 
			
		||||
                          const char * const *methods,
 | 
			
		||||
                          const char* introspection_snippet,
 | 
			
		||||
                          DBusObjectPathMessageFunction receive_cb,
 | 
			
		||||
                          void *userdata) {
 | 
			
		||||
    struct dbus_state *dbus_state;
 | 
			
		||||
    pa_hashmap *objects;
 | 
			
		||||
    struct object_entry *obj_entry;
 | 
			
		||||
| 
						 | 
				
			
			@ -283,7 +424,8 @@ int pa_dbus_add_interface(pa_core *c, const char* path, const char* interface, c
 | 
			
		|||
 | 
			
		||||
    iface_entry = pa_xnew(struct interface_entry, 1);
 | 
			
		||||
    iface_entry->name = pa_xstrdup(interface);
 | 
			
		||||
    iface_entry->methods = copy_methods(methods);
 | 
			
		||||
    iface_entry->properties = copy_strarray(properties);
 | 
			
		||||
    iface_entry->methods = copy_strarray(methods);
 | 
			
		||||
    iface_entry->introspection_snippet = pa_xstrdup(introspection_snippet);
 | 
			
		||||
    iface_entry->receive = receive_cb;
 | 
			
		||||
    iface_entry->userdata = userdata;
 | 
			
		||||
| 
						 | 
				
			
			@ -331,13 +473,13 @@ static void unregister_object(struct dbus_state *dbus_state, struct object_entry
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void free_methods(char **methods) {
 | 
			
		||||
    char **pos = methods;
 | 
			
		||||
static void free_strarray(char **array) {
 | 
			
		||||
    char **pos = array;
 | 
			
		||||
 | 
			
		||||
    while (*pos++)
 | 
			
		||||
        pa_xfree(*pos);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(methods);
 | 
			
		||||
    pa_xfree(array);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int pa_dbus_remove_interface(pa_core *c, const char* path, const char* interface) {
 | 
			
		||||
| 
						 | 
				
			
			@ -365,7 +507,8 @@ int pa_dbus_remove_interface(pa_core *c, const char* path, const char* interface
 | 
			
		|||
    update_introspection(obj_entry);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(iface_entry->name);
 | 
			
		||||
    free_methods(iface_entry->methods);
 | 
			
		||||
    free_strarray(iface_entry->properties);
 | 
			
		||||
    free_strarray(iface_entry->methods);
 | 
			
		||||
    pa_xfree(iface_entry->introspection_snippet);
 | 
			
		||||
    pa_xfree(iface_entry);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,10 +28,12 @@
 | 
			
		|||
#include <pulsecore/macro.h>
 | 
			
		||||
 | 
			
		||||
#define PA_DBUS_DEFAULT_PORT 24883
 | 
			
		||||
#define PA_DBUS_SOCKET_NAME "dbus_socket"
 | 
			
		||||
#define PA_DBUS_SOCKET_NAME "dbus-socket"
 | 
			
		||||
 | 
			
		||||
#define PA_DBUS_SYSTEM_SOCKET_PATH PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_DBUS_SOCKET_NAME
 | 
			
		||||
 | 
			
		||||
#define PA_DBUS_ERROR_NO_SUCH_PROPERTY "org.PulseAudio.Core1.NoSuchPropertyError"
 | 
			
		||||
 | 
			
		||||
/* NOTE: These functions may only be called from the main thread. */
 | 
			
		||||
 | 
			
		||||
/* Returns the default address of the server type in the escaped form. For
 | 
			
		||||
| 
						 | 
				
			
			@ -47,17 +49,27 @@ char *pa_get_dbus_address_from_server_type(pa_server_type_t server_type);
 | 
			
		|||
 * Introspection requests are handled automatically. For that to work, the
 | 
			
		||||
 * caller gives an XML snippet containing the interface introspection element.
 | 
			
		||||
 * All interface snippets are automatically combined to provide the final
 | 
			
		||||
 * introspection string.
 | 
			
		||||
 * introspection string for the object.
 | 
			
		||||
 *
 | 
			
		||||
 * The introspection snippet contains the interface name and the methods, but
 | 
			
		||||
 * since this function doesn't do XML parsing, the interface name and the set
 | 
			
		||||
 * of method names have to be supplied separately. If the interface doesn't
 | 
			
		||||
 * contain any methods, NULL may be given as the methods parameter, otherwise
 | 
			
		||||
 * the methods parameter must be a NULL-terminated array of strings.
 | 
			
		||||
 * The introspection snippet contains the interface name, the property names
 | 
			
		||||
 * and the method namess, but since this function doesn't do XML parsing, the
 | 
			
		||||
 * information needs to be given separately. Property and method names are
 | 
			
		||||
 * given as a NULL-terminated array of strings. The interface name is used for
 | 
			
		||||
 * message routing, and so are the property and method names too in case the
 | 
			
		||||
 * client doesn't tell which interface he's trying to access; in absence of
 | 
			
		||||
 * interface information from the client, the correct interface is searched
 | 
			
		||||
 * based on the property or method name.
 | 
			
		||||
 *
 | 
			
		||||
 * Fails and returns a negative number if the object already has the interface
 | 
			
		||||
 * registered. */
 | 
			
		||||
int pa_dbus_add_interface(pa_core *c, const char* path, const char* interface, const char * const *methods, const char* introspection_snippet, DBusObjectPathMessageFunction receive_cb, void *userdata);
 | 
			
		||||
int pa_dbus_add_interface(pa_core *c,
 | 
			
		||||
                          const char* path,
 | 
			
		||||
                          const char* interface,
 | 
			
		||||
                          const char * const *properties,
 | 
			
		||||
                          const char * const *methods,
 | 
			
		||||
                          const char* introspection_snippet,
 | 
			
		||||
                          DBusObjectPathMessageFunction receive_cb,
 | 
			
		||||
                          void *userdata);
 | 
			
		||||
 | 
			
		||||
/* Returns a negative number if the given object doesn't have the given
 | 
			
		||||
 * interface registered. */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,62 +27,414 @@
 | 
			
		|||
 | 
			
		||||
#include <pulse/xmalloc.h>
 | 
			
		||||
 | 
			
		||||
#include <pulsecore/core-util.h>
 | 
			
		||||
#include <pulsecore/dbus-common.h>
 | 
			
		||||
#include <pulsecore/macro.h>
 | 
			
		||||
 | 
			
		||||
#include "core.h"
 | 
			
		||||
 | 
			
		||||
#define OBJECT_NAME "/org/pulseaudio/core"
 | 
			
		||||
#define INTERFACE_NAME "org.pulseaudio.Core"
 | 
			
		||||
#define OBJECT_PATH "/org/pulseaudio1"
 | 
			
		||||
#define INTERFACE_CORE "org.PulseAudio.Core1"
 | 
			
		||||
 | 
			
		||||
struct pa_dbusobj_core {
 | 
			
		||||
    pa_core *core;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const char *introspection_snippet =
 | 
			
		||||
    " <interface name=\""INTERFACE_NAME"\">"
 | 
			
		||||
    "  <method name=\"Test\">"
 | 
			
		||||
    "   <arg name=\"result\" type=\"s\" direction=\"out\"/>"
 | 
			
		||||
    "  </method>"
 | 
			
		||||
    " </interface>";
 | 
			
		||||
    " <interface name=\"" INTERFACE_CORE "\">\n"
 | 
			
		||||
    "  <method name=\"GetCardByName\">\n"
 | 
			
		||||
    "   <arg name=\"Name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"Card\" type=\"o\" direction=\"out\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    "  <method name=\"GetSinkByName\">\n"
 | 
			
		||||
    "   <arg name=\"Name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"Sink\" type=\"o\" direction=\"out\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    "  <method name=\"GetSourceByName\">\n"
 | 
			
		||||
    "   <arg name=\"Name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"Source\" type=\"o\" direction=\"out\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    "  <method name=\"GetSampleByName\">\n"
 | 
			
		||||
    "   <arg name=\"Name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"Sample\" type=\"o\" direction=\"out\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    "  <method name=\"UploadSample\">\n"
 | 
			
		||||
    "   <arg name=\"Name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"SampleFormat\" type=\"y\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"SampleRate\" type=\"u\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"Channels\" type=\"ay\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"DefaultVolume\" type=\"au\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"Proplist\" type=\"a{say}\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"Data\" type=\"ay\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"Sample\" type=\"o\" direction=\"out\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    "  <method name=\"LoadSampleFromFile\">\n"
 | 
			
		||||
    "   <arg name=\"Name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"Filepath\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"Sample\" type=\"o\" direction=\"out\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    "  <method name=\"AddLazySample\">\n"
 | 
			
		||||
    "   <arg name=\"Name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"Filepath\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"Sample\" type=\"o\" direction=\"out\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    "  <method name=\"AddLazySamplesFromDirectory\">\n"
 | 
			
		||||
    "   <arg name=\"Dirpath\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    "  <method name=\"LoadModule\">\n"
 | 
			
		||||
    "   <arg name=\"Name\" type=\"s\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"Arguments\" type=\"a{ss}\" direction=\"in\"/>\n"
 | 
			
		||||
    "   <arg name=\"Module\" type=\"o\" direction=\"out\"/>\n"
 | 
			
		||||
    "  </method>\n"
 | 
			
		||||
    "  <method name=\"Exit\"/>\n"
 | 
			
		||||
    "  <signal name=\"NewCard\">\n"
 | 
			
		||||
    "   <arg name=\"Card\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"CardRemoved\">\n"
 | 
			
		||||
    "   <arg name=\"Card\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"NewSink\">\n"
 | 
			
		||||
    "   <arg name=\"Sink\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"SinkRemoved\">\n"
 | 
			
		||||
    "   <arg name=\"Sink\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"FallbackSinkUpdated\">\n"
 | 
			
		||||
    "   <arg name=\"Sink\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"NewSource\">\n"
 | 
			
		||||
    "   <arg name=\"Source\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"SourceRemoved\">\n"
 | 
			
		||||
    "   <arg name=\"Source\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"FallbackSourceUpdated\">\n"
 | 
			
		||||
    "   <arg name=\"Source\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"NewPlaybackStream\">\n"
 | 
			
		||||
    "   <arg name=\"PlaybackStream\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"PlaybackStreamRemoved\">\n"
 | 
			
		||||
    "   <arg name=\"PlaybackStream\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"NewRecordStream\">\n"
 | 
			
		||||
    "   <arg name=\"RecordStream\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"RecordStreamRemoved\">\n"
 | 
			
		||||
    "   <arg name=\"RecordStream\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"NewSample\">\n"
 | 
			
		||||
    "   <arg name=\"Sample\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"SampleRemoved\">\n"
 | 
			
		||||
    "   <arg name=\"Sample\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"NewModule\">\n"
 | 
			
		||||
    "   <arg name=\"Module\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"ModuleRemoved\">\n"
 | 
			
		||||
    "   <arg name=\"Module\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"NewClient\">\n"
 | 
			
		||||
    "   <arg name=\"Client\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <signal name=\"ClientRemoved\">\n"
 | 
			
		||||
    "   <arg name=\"Client\" type=\"o\"/>\n"
 | 
			
		||||
    "  </signal>\n"
 | 
			
		||||
    "  <property name=\"InterfaceRevision\" type=\"u\" access=\"read\"/>\n"
 | 
			
		||||
    "  <property name=\"Name\" type=\"s\" access=\"read\"/>\n"
 | 
			
		||||
    "  <property name=\"Version\" type=\"s\" access=\"read\"/>\n"
 | 
			
		||||
    "  <property name=\"Username\" type=\"s\" access=\"read\"/>\n"
 | 
			
		||||
    "  <property name=\"Hostname\" type=\"s\" access=\"read\"/>\n"
 | 
			
		||||
    "  <property name=\"DefaultChannels\" type=\"ay\" access=\"readwrite\"/>\n"
 | 
			
		||||
    "  <property name=\"DefaultSampleFormat\" type=\"y\" access=\"readwrite\"/>\n"
 | 
			
		||||
    "  <property name=\"DefaultSampleRate\" type=\"u\" access=\"readwrite\"/>\n"
 | 
			
		||||
    "  <property name=\"Sinks\" type=\"ao\" access=\"read\"/>\n"
 | 
			
		||||
    "  <property name=\"FallbackSink\" type=\"s\" access=\"readwrite\"/>\n"
 | 
			
		||||
    "  <property name=\"Sources\" type=\"ao\" access=\"read\"/>\n"
 | 
			
		||||
    "  <property name=\"FallbackSource\" type=\"o\" access=\"readwrite\"/>\n"
 | 
			
		||||
    "  <property name=\"PlaybackStreams\" type=\"ao\" access=\"read\"/>\n"
 | 
			
		||||
    "  <property name=\"RecordStreams\" type=\"ao\" access=\"read\"/>\n"
 | 
			
		||||
    "  <property name=\"Samples\" type=\"ao\" access=\"read\"/>\n"
 | 
			
		||||
    "  <property name=\"Modules\" type=\"ao\" access=\"read\"/>\n"
 | 
			
		||||
    "  <property name=\"Clients\" type=\"ao\" access=\"read\"/>\n"
 | 
			
		||||
    "  <property name=\"Extensions\" type=\"as\" access=\"read\"/>\n"
 | 
			
		||||
    " </interface>\n";
 | 
			
		||||
 | 
			
		||||
static const char *methods[] = {
 | 
			
		||||
    "Test",
 | 
			
		||||
/* If you need to modify this list, note that handle_get_all() uses hard-coded
 | 
			
		||||
 * indexes to point to these strings, so make sure the indexes don't go wrong
 | 
			
		||||
 * there. */
 | 
			
		||||
static const char *properties[] = {
 | 
			
		||||
    "InterfaceRevision",
 | 
			
		||||
    "Name",
 | 
			
		||||
    "Version",
 | 
			
		||||
    "Username",
 | 
			
		||||
    "Hostname",
 | 
			
		||||
    "DefaultChannels",
 | 
			
		||||
    "DefaultSampleFormat",
 | 
			
		||||
    "DefaultSampleRate",
 | 
			
		||||
    "Sinks",
 | 
			
		||||
    "FallbackSink",
 | 
			
		||||
    "Sources",
 | 
			
		||||
    "FallbackSource",
 | 
			
		||||
    "PlaybackStreams",
 | 
			
		||||
    "RecordStreams",
 | 
			
		||||
    "Samples",
 | 
			
		||||
    "Modules",
 | 
			
		||||
    "Clients",
 | 
			
		||||
    "Extensions",
 | 
			
		||||
    NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult handle_test(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_core *c) {
 | 
			
		||||
static const char *methods[] = {
 | 
			
		||||
    "GetCardByName",
 | 
			
		||||
    "GetSinkByName",
 | 
			
		||||
    "GetSourceByName",
 | 
			
		||||
    "GetSampleByName",
 | 
			
		||||
    "UploadSample",
 | 
			
		||||
    "LoadSampleFromFile",
 | 
			
		||||
    "AddLazySample",
 | 
			
		||||
    "AddLazySamplesFromDirectory",
 | 
			
		||||
    "LoadModule",
 | 
			
		||||
    "Exit",
 | 
			
		||||
    NULL
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult handle_get_name(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_core *c) {
 | 
			
		||||
    DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    const char *reply_message = "Hello!";
 | 
			
		||||
    const char *server_name = PACKAGE_NAME;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter variant_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    if (!(reply = dbus_message_new_method_return(msg)))
 | 
			
		||||
        goto oom;
 | 
			
		||||
    if (!(reply = dbus_message_new_method_return(msg))) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
    if (!dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_VARIANT, "s", &variant_iter)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_STRING, &server_name)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_message_iter_close_container(&msg_iter, &variant_iter)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
 | 
			
		||||
    if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &reply_message, DBUS_TYPE_INVALID))
 | 
			
		||||
        goto fail;
 | 
			
		||||
 | 
			
		||||
    if (!dbus_connection_send(conn, reply, NULL))
 | 
			
		||||
        goto oom;
 | 
			
		||||
 | 
			
		||||
    dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
 | 
			
		||||
fail:
 | 
			
		||||
finish:
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
oom:
 | 
			
		||||
static DBusHandlerResult handle_get(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_core *c) {
 | 
			
		||||
    DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    const char* interface;
 | 
			
		||||
    const char* property;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, "Invalid arguments"))) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (*interface && !pa_streq(interface, INTERFACE_CORE)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (pa_streq(property, "Name")) {
 | 
			
		||||
        r = handle_get_name(conn, msg, c);
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!(reply = dbus_message_new_error_printf(msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s: No such property", property))) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult handle_set(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_core *c) {
 | 
			
		||||
    DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    const char* interface;
 | 
			
		||||
    const char* property;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_STRING, &property, DBUS_TYPE_INVALID)) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, "Invalid arguments"))) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (*interface && !pa_streq(interface, INTERFACE_CORE)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (pa_streq(property, "Name")) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error_printf(msg, DBUS_ERROR_ACCESS_DENIED, "%s: Property not settable", property))) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!(reply = dbus_message_new_error_printf(msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s: No such property", property))) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    goto finish;
 | 
			
		||||
 | 
			
		||||
    if (!(reply = dbus_message_new_error_printf(msg, DBUS_ERROR_ACCESS_DENIED, "%s: Property not settable", property))) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult handle_get_all(DBusConnection *conn, DBusMessage *msg, pa_dbusobj_core *c) {
 | 
			
		||||
    DBusHandlerResult r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
    DBusMessage *reply = NULL;
 | 
			
		||||
    char *interface = NULL;
 | 
			
		||||
    char const *server_name = PACKAGE_NAME;
 | 
			
		||||
    DBusMessageIter msg_iter;
 | 
			
		||||
    DBusMessageIter dict_iter;
 | 
			
		||||
    DBusMessageIter dict_entry_iter;
 | 
			
		||||
    DBusMessageIter variant_iter;
 | 
			
		||||
 | 
			
		||||
    pa_assert(conn);
 | 
			
		||||
    pa_assert(msg);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &interface, DBUS_TYPE_INVALID)) {
 | 
			
		||||
        if (!(reply = dbus_message_new_error(msg, DBUS_ERROR_INVALID_ARGS, "Invalid arguments"))) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
            r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
            goto finish;
 | 
			
		||||
        }
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!(reply = dbus_message_new_method_return(msg))) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    dbus_message_iter_init_append(reply, &msg_iter);
 | 
			
		||||
    if (!dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_message_iter_open_container(&dict_iter, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry_iter)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_message_iter_append_basic(&dict_entry_iter, DBUS_TYPE_STRING, &properties[1])) { /* Name */
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_message_iter_open_container(&dict_entry_iter, DBUS_TYPE_VARIANT, "s", &variant_iter)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_message_iter_append_basic(&variant_iter, DBUS_TYPE_STRING, &server_name)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_message_iter_close_container(&dict_entry_iter, &variant_iter)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_message_iter_close_container(&dict_iter, &dict_entry_iter)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_message_iter_close_container(&msg_iter, &dict_iter)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if (!dbus_connection_send(conn, reply, NULL)) {
 | 
			
		||||
        r = DBUS_HANDLER_RESULT_NEED_MEMORY;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    r = DBUS_HANDLER_RESULT_HANDLED;
 | 
			
		||||
 | 
			
		||||
finish:
 | 
			
		||||
    if (reply)
 | 
			
		||||
        dbus_message_unref(reply);
 | 
			
		||||
 | 
			
		||||
    return r;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static DBusHandlerResult receive_cb(DBusConnection *connection, DBusMessage *message, void *user_data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -92,8 +444,17 @@ static DBusHandlerResult receive_cb(DBusConnection *connection, DBusMessage *mes
 | 
			
		|||
    pa_assert(message);
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_is_method_call(message, INTERFACE_NAME, "Test"))
 | 
			
		||||
        return handle_test(connection, message, c);
 | 
			
		||||
    if (dbus_message_is_method_call(message, DBUS_INTERFACE_PROPERTIES, "Get") ||
 | 
			
		||||
        (!dbus_message_get_interface(message) && dbus_message_has_member(message, "Get")))
 | 
			
		||||
        return handle_get(connection, message, c);
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_is_method_call(message, DBUS_INTERFACE_PROPERTIES, "Set") ||
 | 
			
		||||
        (!dbus_message_get_interface(message) && dbus_message_has_member(message, "Set")))
 | 
			
		||||
        return handle_set(connection, message, c);
 | 
			
		||||
 | 
			
		||||
    if (dbus_message_is_method_call(message, DBUS_INTERFACE_PROPERTIES, "GetAll") ||
 | 
			
		||||
        (!dbus_message_get_interface(message) && dbus_message_has_member(message, "GetAll")))
 | 
			
		||||
        return handle_get_all(connection, message, c);
 | 
			
		||||
 | 
			
		||||
    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +467,8 @@ pa_dbusobj_core *pa_dbusobj_core_new(pa_core *core) {
 | 
			
		|||
    c = pa_xnew(pa_dbusobj_core, 1);
 | 
			
		||||
    c->core = core;
 | 
			
		||||
 | 
			
		||||
    pa_dbus_add_interface(core, OBJECT_NAME, INTERFACE_NAME, methods, introspection_snippet, receive_cb, c);
 | 
			
		||||
    pa_dbus_add_interface(core, OBJECT_PATH, INTERFACE_CORE, properties, methods, introspection_snippet, receive_cb, c);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return c;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -114,7 +476,7 @@ pa_dbusobj_core *pa_dbusobj_core_new(pa_core *core) {
 | 
			
		|||
void pa_dbusobj_core_free(pa_dbusobj_core *c) {
 | 
			
		||||
    pa_assert(c);
 | 
			
		||||
 | 
			
		||||
    pa_dbus_remove_interface(c->core, OBJECT_NAME, INTERFACE_NAME);
 | 
			
		||||
    pa_dbus_remove_interface(c->core, OBJECT_PATH, INTERFACE_CORE);
 | 
			
		||||
 | 
			
		||||
    pa_xfree(c);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue