* Copyright (C) 2003 CodeFactory AB
* Copyright (C) 2003 Red Hat, Inc.
*
- * Licensed under the Academic Free License version 1.2
+ * Licensed under the Academic Free License version 2.0
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "dbus-bus.h"
#include "dbus-protocol.h"
#include "dbus-internals.h"
+#include "dbus-message.h"
+#include <string.h>
/**
* @defgroup DBusBus Message bus APIs
* @ingroup DBus
* @brief Functions for communicating with the message bus
*
+ * @todo right now the default address of the system bus is hardcoded,
+ * so if you change it in the global config file suddenly you have to
+ * set DBUS_SYSTEM_BUS_ADDRESS env variable. Might be nice if the
+ * client lib somehow read the config file, or if the bus on startup
+ * somehow wrote out its address to a well-known spot, but might also
+ * not be worth it.
*/
-
/**
* @defgroup DBusBusInternals Message bus APIs internals
* @ingroup DBusInternals
* Block of message-bus-related data we attach to each
* #DBusConnection used with these convenience functions.
*
+ *
+ * @todo get rid of most of these; they should be done
+ * with DBusGProxy and the Qt equivalent, i.e. the same
+ * way any other interface would be used.
*/
typedef struct
{
+ DBusConnection *connection; /**< Connection we're associated with */
char *base_service; /**< Base service name of this connection */
+ unsigned int is_well_known : 1; /**< Is one of the well-known connections in our global array */
} BusData;
-/** The slot we have reserved to store BusData
+/** The slot we have reserved to store BusData.
*/
-static int bus_data_slot = -1;
-/** Number of connections using the slot
- */
-static int bus_data_slot_refcount = 0;
+static dbus_int32_t bus_data_slot = -1;
-/**
- * Lock for bus_data_slot and bus_data_slot_refcount
- */
-static DBusMutex *slot_lock;
+/** Number of bus types */
+#define N_BUS_TYPES 3
+
+static DBusConnection *bus_connections[N_BUS_TYPES];
+static char *bus_connection_addresses[N_BUS_TYPES] = { NULL, NULL, NULL };
+
+static DBusBusType activation_bus_type = DBUS_BUS_ACTIVATION;
+
+static dbus_bool_t initialized = FALSE;
/**
- * Initialize the mutex used for bus_data_slot
- *
- * @returns the mutex
+ * Lock for globals in this file
*/
-DBusMutex *
-_dbus_bus_init_lock (void)
+_DBUS_DEFINE_GLOBAL_LOCK (bus);
+
+static void
+addresses_shutdown_func (void *data)
{
- slot_lock = dbus_mutex_new ();
- return slot_lock;
+ int i;
+
+ i = 0;
+ while (i < N_BUS_TYPES)
+ {
+ if (bus_connections[i] != NULL)
+ _dbus_warn ("dbus_shutdown() called but connections were still live!");
+
+ dbus_free (bus_connection_addresses[i]);
+ bus_connection_addresses[i] = NULL;
+ ++i;
+ }
+
+ activation_bus_type = DBUS_BUS_ACTIVATION;
}
static dbus_bool_t
-data_slot_ref (void)
+get_from_env (char **connection_p,
+ const char *env_var)
{
- dbus_mutex_lock (slot_lock);
-
- if (bus_data_slot < 0)
- bus_data_slot = dbus_connection_allocate_data_slot ();
-
- if (bus_data_slot < 0)
+ const char *s;
+
+ _dbus_assert (*connection_p == NULL);
+
+ s = _dbus_getenv (env_var);
+ if (s == NULL || *s == '\0')
+ return TRUE; /* successfully didn't use the env var */
+ else
{
- dbus_mutex_unlock (slot_lock);
- return FALSE;
+ *connection_p = _dbus_strdup (s);
+ return *connection_p != NULL;
}
+}
- bus_data_slot_refcount += 1;
+static dbus_bool_t
+init_connections_unlocked (void)
+{
+ if (!initialized)
+ {
+ const char *s;
+ int i;
- dbus_mutex_unlock (slot_lock);
+ i = 0;
+ while (i < N_BUS_TYPES)
+ {
+ bus_connections[i] = NULL;
+ ++i;
+ }
- return TRUE;
-}
+ /* Don't init these twice, we may run this code twice if
+ * init_connections_unlocked() fails midway through.
+ * In practice, each block below should contain only one
+ * "return FALSE" or running through twice may not
+ * work right.
+ */
+
+ if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
+ {
+ _dbus_verbose ("Filling in system bus address...\n");
+
+ if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SYSTEM],
+ "DBUS_SYSTEM_BUS_ADDRESS"))
+ return FALSE;
+ }
+
+
+ if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
+ {
+ /* Use default system bus address if none set in environment */
+ bus_connection_addresses[DBUS_BUS_SYSTEM] =
+ _dbus_strdup (DBUS_SYSTEM_BUS_DEFAULT_ADDRESS);
+ if (bus_connection_addresses[DBUS_BUS_SYSTEM] == NULL)
+ return FALSE;
+
+ _dbus_verbose (" used default system bus \"%s\"\n",
+ bus_connection_addresses[DBUS_BUS_SYSTEM]);
+ }
+ else
+ _dbus_verbose (" used env var system bus \"%s\"\n",
+ bus_connection_addresses[DBUS_BUS_SYSTEM]);
+
+ if (bus_connection_addresses[DBUS_BUS_SESSION] == NULL)
+ {
+ _dbus_verbose ("Filling in session bus address...\n");
+
+ if (!get_from_env (&bus_connection_addresses[DBUS_BUS_SESSION],
+ "DBUS_SESSION_BUS_ADDRESS"))
+ return FALSE;
+ _dbus_verbose (" \"%s\"\n", bus_connection_addresses[DBUS_BUS_SESSION] ?
+ bus_connection_addresses[DBUS_BUS_SESSION] : "none set");
+ }
-static void
-data_slot_unref (void)
-{
- dbus_mutex_lock (slot_lock);
+ if (bus_connection_addresses[DBUS_BUS_ACTIVATION] == NULL)
+ {
+ _dbus_verbose ("Filling in activation bus address...\n");
+
+ if (!get_from_env (&bus_connection_addresses[DBUS_BUS_ACTIVATION],
+ "DBUS_ACTIVATION_ADDRESS"))
+ return FALSE;
+
+ _dbus_verbose (" \"%s\"\n", bus_connection_addresses[DBUS_BUS_ACTIVATION] ?
+ bus_connection_addresses[DBUS_BUS_ACTIVATION] : "none set");
+ }
- _dbus_assert (bus_data_slot >= 0);
- _dbus_assert (bus_data_slot_refcount > 0);
- bus_data_slot_refcount -= 1;
+ if (bus_connection_addresses[DBUS_BUS_ACTIVATION] != NULL)
+ {
+ s = _dbus_getenv ("DBUS_ACTIVATION_BUS_TYPE");
+
+ if (s != NULL)
+ {
+ _dbus_verbose ("Bus activation type was set to \"%s\"\n", s);
+
+ if (strcmp (s, "system") == 0)
+ activation_bus_type = DBUS_BUS_SYSTEM;
+ else if (strcmp (s, "session") == 0)
+ activation_bus_type = DBUS_BUS_SESSION;
+ }
+ }
+ else
+ {
+ /* Default to the session bus instead if available */
+ if (bus_connection_addresses[DBUS_BUS_SESSION] != NULL)
+ {
+ bus_connection_addresses[DBUS_BUS_ACTIVATION] =
+ _dbus_strdup (bus_connection_addresses[DBUS_BUS_SESSION]);
+ if (bus_connection_addresses[DBUS_BUS_ACTIVATION] == NULL)
+ return FALSE;
+ }
+ }
+
+ /* If we return FALSE we have to be sure that restarting
+ * the above code will work right
+ */
+
+ if (!_dbus_setenv ("DBUS_ACTIVATION_ADDRESS", NULL))
+ return FALSE;
- if (bus_data_slot_refcount == 0)
- {
- dbus_connection_free_data_slot (bus_data_slot);
- bus_data_slot = -1;
+ if (!_dbus_setenv ("DBUS_ACTIVATION_BUS_TYPE", NULL))
+ return FALSE;
+
+ if (!_dbus_register_shutdown_func (addresses_shutdown_func,
+ NULL))
+ return FALSE;
+
+ initialized = TRUE;
}
- dbus_mutex_unlock (slot_lock);
+ return initialized;
}
static void
bus_data_free (void *data)
{
BusData *bd = data;
-
+
+ if (bd->is_well_known)
+ {
+ int i;
+ _DBUS_LOCK (bus);
+ /* We may be stored in more than one slot */
+ i = 0;
+ while (i < N_BUS_TYPES)
+ {
+ if (bus_connections[i] == bd->connection)
+ bus_connections[i] = NULL;
+
+ ++i;
+ }
+ _DBUS_UNLOCK (bus);
+ }
+
dbus_free (bd->base_service);
dbus_free (bd);
- data_slot_unref ();
+ dbus_connection_free_data_slot (&bus_data_slot);
}
static BusData*
{
BusData *bd;
- if (!data_slot_ref ())
+ if (!dbus_connection_allocate_data_slot (&bus_data_slot))
return NULL;
bd = dbus_connection_get_data (connection, bus_data_slot);
bd = dbus_new0 (BusData, 1);
if (bd == NULL)
{
- data_slot_unref ();
+ dbus_connection_free_data_slot (&bus_data_slot);
return NULL;
}
+
+ bd->connection = connection;
- dbus_connection_set_data (connection, bus_data_slot, bd,
- bus_data_free);
+ if (!dbus_connection_set_data (connection, bus_data_slot, bd,
+ bus_data_free))
+ {
+ dbus_free (bd);
+ dbus_connection_free_data_slot (&bus_data_slot);
+ return NULL;
+ }
/* Data slot refcount now held by the BusData */
}
else
{
- data_slot_unref ();
+ dbus_connection_free_data_slot (&bus_data_slot);
}
return bd;
*/
/**
+ * Connects to a bus daemon and registers the client with it.
+ * If a connection to the bus already exists, then that connection is returned.
+ *
+ * @todo alex thinks we should nullify the connection when we get a disconnect-message.
+ *
+ * @param type bus type
+ * @param error address where an error can be returned.
+ * @returns a DBusConnection
+ */
+DBusConnection *
+dbus_bus_get (DBusBusType type,
+ DBusError *error)
+{
+ const char *address;
+ DBusConnection *connection;
+ BusData *bd;
+ DBusBusType address_type;
+
+ _dbus_return_val_if_fail (type >= 0 && type < N_BUS_TYPES, NULL);
+ _dbus_return_val_if_error_is_set (error, NULL);
+
+ _DBUS_LOCK (bus);
+
+ if (!init_connections_unlocked ())
+ {
+ _DBUS_UNLOCK (bus);
+ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
+ return NULL;
+ }
+
+ /* We want to use the activation address even if the
+ * activating bus is the session or system bus,
+ * per the spec.
+ */
+ address_type = type;
+
+ /* Use the real type of the activation bus for getting its
+ * connection, but only if the real type's address is available. (If
+ * the activating bus isn't a well-known bus then
+ * activation_bus_type == DBUS_BUS_ACTIVATION)
+ */
+ if (type == DBUS_BUS_ACTIVATION &&
+ bus_connection_addresses[activation_bus_type] != NULL)
+ type = activation_bus_type;
+
+ if (bus_connections[type] != NULL)
+ {
+ connection = bus_connections[type];
+ dbus_connection_ref (connection);
+
+ _DBUS_UNLOCK (bus);
+ return connection;
+ }
+
+ address = bus_connection_addresses[address_type];
+ if (address == NULL)
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Unable to determine the address of the message bus");
+ _DBUS_UNLOCK (bus);
+ return NULL;
+ }
+
+ connection = dbus_connection_open (address, error);
+
+ if (!connection)
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ _DBUS_UNLOCK (bus);
+ return NULL;
+ }
+
+ /* By default we're bound to the lifecycle of
+ * the message bus.
+ */
+ dbus_connection_set_exit_on_disconnect (connection,
+ TRUE);
+
+ if (!dbus_bus_register (connection, error))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ dbus_connection_disconnect (connection);
+ dbus_connection_unref (connection);
+
+ _DBUS_UNLOCK (bus);
+ return NULL;
+ }
+
+ bus_connections[type] = connection;
+ bd = ensure_bus_data (connection);
+ _dbus_assert (bd != NULL);
+
+ bd->is_well_known = TRUE;
+
+ _DBUS_UNLOCK (bus);
+ return connection;
+}
+
+
+/**
* Registers a connection with the bus. This must be the first
* thing an application does when connecting to the message bus.
* If registration succeeds, the base service name will be set,
DBusMessage *message, *reply;
char *name;
BusData *bd;
+ dbus_bool_t retval;
+
+ _dbus_return_val_if_fail (connection != NULL, FALSE);
+ _dbus_return_val_if_error_is_set (error, FALSE);
+ retval = FALSE;
+
bd = ensure_bus_data (connection);
if (bd == NULL)
{
return TRUE;
}
- message = dbus_message_new (DBUS_SERVICE_DBUS,
- DBUS_MESSAGE_HELLO);
+ message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+ DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "Hello");
if (!message)
{
dbus_message_unref (message);
if (reply == NULL)
- {
- _DBUS_ASSERT_ERROR_IS_SET (error);
- return FALSE;
- }
+ goto out;
+ else if (dbus_set_error_from_message (error, reply))
+ goto out;
+ else if (!dbus_message_get_args (reply, error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ goto out;
+
+ bd->base_service = name;
- if (!dbus_message_get_args (reply, error,
- DBUS_TYPE_STRING, &name,
- 0))
- {
- _DBUS_ASSERT_ERROR_IS_SET (error);
- return FALSE;
- }
+ retval = TRUE;
+
+ out:
+ if (reply)
+ dbus_message_unref (reply);
- bd->base_service = name;
+ if (!retval)
+ _DBUS_ASSERT_ERROR_IS_SET (error);
- return TRUE;
+ return retval;
}
{
BusData *bd;
+ _dbus_return_val_if_fail (connection != NULL, FALSE);
+ _dbus_return_val_if_fail (base_service != NULL, FALSE);
+
bd = ensure_bus_data (connection);
if (bd == NULL)
return FALSE;
_dbus_assert (bd->base_service == NULL);
- _dbus_assert (base_service != NULL);
bd->base_service = _dbus_strdup (base_service);
return bd->base_service != NULL;
{
BusData *bd;
+ _dbus_return_val_if_fail (connection != NULL, NULL);
+
bd = ensure_bus_data (connection);
if (bd == NULL)
return NULL;
}
/**
+ * Asks the bus to return the uid of a service.
+ *
+ * @param connection the connection
+ * @param service_name the service name
+ * @param error location to store the error
+ * @returns a result code, -1 if error is set
+ */
+unsigned long
+dbus_bus_get_unix_user (DBusConnection *connection,
+ const char *service,
+ DBusError *error)
+{
+ DBusMessage *message, *reply;
+ dbus_uint32_t uid;
+
+ _dbus_return_val_if_fail (connection != NULL, DBUS_UID_UNSET);
+ _dbus_return_val_if_fail (service != NULL, DBUS_UID_UNSET);
+ _dbus_return_val_if_error_is_set (error, DBUS_UID_UNSET);
+
+ message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+ DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "GetConnectionUnixUser");
+
+ if (message == NULL)
+ {
+ _DBUS_SET_OOM (error);
+ return DBUS_UID_UNSET;
+ }
+
+ if (!dbus_message_append_args (message,
+ DBUS_TYPE_STRING, service,
+ DBUS_TYPE_INVALID))
+ {
+ dbus_message_unref (message);
+ _DBUS_SET_OOM (error);
+ return DBUS_UID_UNSET;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
+ error);
+
+ dbus_message_unref (message);
+
+ if (reply == NULL)
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ return DBUS_UID_UNSET;
+ }
+
+ if (dbus_set_error_from_message (error, reply))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ dbus_message_unref (reply);
+ return DBUS_UID_UNSET;
+ }
+
+ if (!dbus_message_get_args (reply, error,
+ DBUS_TYPE_UINT32, &uid,
+ DBUS_TYPE_INVALID))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ dbus_message_unref (reply);
+ return DBUS_UID_UNSET;
+ }
+
+ dbus_message_unref (reply);
+
+ return (unsigned long) uid;
+}
+
+
+/**
* Asks the bus to try to acquire a certain service.
*
* @todo these docs are not complete, need to document the
DBusError *error)
{
DBusMessage *message, *reply;
- int service_result;
+ dbus_uint32_t service_result;
+
+ _dbus_return_val_if_fail (connection != NULL, 0);
+ _dbus_return_val_if_fail (service_name != NULL, 0);
+ _dbus_return_val_if_error_is_set (error, 0);
- message = dbus_message_new (DBUS_SERVICE_DBUS,
- DBUS_MESSAGE_ACQUIRE_SERVICE);
+ message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+ DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "AcquireService");
if (message == NULL)
{
if (!dbus_message_append_args (message,
DBUS_TYPE_STRING, service_name,
DBUS_TYPE_UINT32, flags,
- 0))
+ DBUS_TYPE_INVALID))
{
dbus_message_unref (message);
_DBUS_SET_OOM (error);
{
_DBUS_ASSERT_ERROR_IS_SET (error);
return -1;
- }
+ }
+ if (dbus_set_error_from_message (error, reply))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ dbus_message_unref (reply);
+ return -1;
+ }
+
if (!dbus_message_get_args (reply, error,
DBUS_TYPE_UINT32, &service_result,
- 0))
+ DBUS_TYPE_INVALID))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
+ dbus_message_unref (reply);
return -1;
}
+ dbus_message_unref (reply);
+
return service_result;
}
/**
* Checks whether a certain service exists.
*
- * @todo the SERVICE_EXISTS message should use BOOLEAN not UINT32
- *
* @param connection the connection
* @param service_name the service name
* @param error location to store any errors
DBusError *error)
{
DBusMessage *message, *reply;
- unsigned int exists;
+ dbus_bool_t exists;
+
+ _dbus_return_val_if_fail (connection != NULL, FALSE);
+ _dbus_return_val_if_fail (service_name != NULL, FALSE);
+ _dbus_return_val_if_error_is_set (error, FALSE);
- message = dbus_message_new (DBUS_SERVICE_DBUS,
- DBUS_MESSAGE_SERVICE_EXISTS);
+ message = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+ DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "ServiceExists");
if (message == NULL)
{
_DBUS_SET_OOM (error);
if (!dbus_message_append_args (message,
DBUS_TYPE_STRING, service_name,
- 0))
+ DBUS_TYPE_INVALID))
{
dbus_message_unref (message);
_DBUS_SET_OOM (error);
}
if (!dbus_message_get_args (reply, error,
- DBUS_TYPE_UINT32, &exists,
- 0))
+ DBUS_TYPE_BOOLEAN, &exists,
+ DBUS_TYPE_INVALID))
{
_DBUS_ASSERT_ERROR_IS_SET (error);
+ dbus_message_unref (reply);
return FALSE;
}
- return (exists != FALSE);
+ dbus_message_unref (reply);
+ return exists;
+}
+
+/**
+ * Activates a given service
+ *
+ * @param connection the connection
+ * @param service_name the service name
+ * @param flags the flags
+ * @param result a place to store the result of the activation, which will
+ * be one of DBUS_ACTIVATION_REPLY_ACTIVATED or
+ * DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE if successful. Pass NULL if you
+ * don't care about the result.
+ * @param error location to store any errors
+ * @returns #TRUE if the activation succeeded, #FALSE if not
+ *
+ * @todo document what the flags do
+ */
+dbus_bool_t
+dbus_bus_activate_service (DBusConnection *connection,
+ const char *service_name,
+ dbus_uint32_t flags,
+ dbus_uint32_t *result,
+ DBusError *error)
+{
+ DBusMessage *msg;
+ DBusMessage *reply;
+
+ msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+ DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "ActivateService");
+
+ if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, service_name,
+ DBUS_TYPE_UINT32, flags, DBUS_TYPE_INVALID))
+ {
+ dbus_message_unref (msg);
+ _DBUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ reply = dbus_connection_send_with_reply_and_block (connection, msg,
+ -1, error);
+ dbus_message_unref (msg);
+
+ if (reply == NULL)
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ return FALSE;
+ }
+
+ if (dbus_set_error_from_message (error, reply))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ dbus_message_unref (reply);
+ return FALSE;
+ }
+
+ if (result != NULL &&
+ !dbus_message_get_args (reply, error, DBUS_TYPE_UINT32,
+ result, DBUS_TYPE_INVALID))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ dbus_message_unref (reply);
+ return FALSE;
+ }
+
+ dbus_message_unref (reply);
+ return TRUE;
+}
+
+static void
+send_no_return_values (DBusConnection *connection,
+ DBusMessage *msg,
+ DBusError *error)
+{
+ if (error)
+ {
+ /* Block to check success codepath */
+ DBusMessage *reply;
+
+ reply = dbus_connection_send_with_reply_and_block (connection, msg,
+ -1, error);
+
+ if (reply == NULL)
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ return;
+ }
+
+ if (dbus_set_error_from_message (error, reply))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ dbus_message_unref (reply);
+ return;
+ }
+
+ dbus_message_unref (reply);
+ }
+ else
+ {
+ /* Silently-fail nonblocking codepath */
+ if (!dbus_connection_send (connection, msg, NULL))
+ return;
+ }
+}
+
+/**
+ * Adds a match rule to match messages going through the message bus.
+ * The "rule" argument is the string form of a match rule.
+ *
+ * If you pass #NULL for the error, this function will not
+ * block; the match thus won't be added until you flush the
+ * connection, and if there's an error adding the match
+ * (only possible error is lack of resources in the bus),
+ * you won't find out about it.
+ *
+ * If you pass non-#NULL for the error this function will
+ * block until it gets a reply.
+ *
+ * Normal API conventions would have the function return
+ * a boolean value indicating whether the error was set,
+ * but that would require blocking always to determine
+ * the return value.
+ *
+ * @param connection connection to the message bus
+ * @param rule textual form of match rule
+ * @param error location to store any errors
+ */
+void
+dbus_bus_add_match (DBusConnection *connection,
+ const char *rule,
+ DBusError *error)
+{
+ DBusMessage *msg;
+
+ msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+ DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "AddMatch");
+
+ if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, rule,
+ DBUS_TYPE_INVALID))
+ {
+ dbus_message_unref (msg);
+ _DBUS_SET_OOM (error);
+ return;
+ }
+
+ send_no_return_values (connection, msg, error);
+
+ dbus_message_unref (msg);
+}
+
+/**
+ * Removes a previously-added match rule "by value" (the most
+ * recently-added identical rule gets removed). The "rule" argument
+ * is the string form of a match rule.
+ *
+ * If you pass #NULL for the error, this function will not
+ * block; otherwise it will. See detailed explanation in
+ * docs for dbus_bus_add_match().
+ *
+ * @param connection connection to the message bus
+ * @param rule textual form of match rule
+ * @param error location to store any errors
+ */
+void
+dbus_bus_remove_match (DBusConnection *connection,
+ const char *rule,
+ DBusError *error)
+{
+ DBusMessage *msg;
+
+ msg = dbus_message_new_method_call (DBUS_SERVICE_ORG_FREEDESKTOP_DBUS,
+ DBUS_PATH_ORG_FREEDESKTOP_DBUS,
+ DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS,
+ "RemoveMatch");
+
+ if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, rule,
+ DBUS_TYPE_INVALID))
+ {
+ dbus_message_unref (msg);
+ _DBUS_SET_OOM (error);
+ return;
+ }
+
+ send_no_return_values (connection, msg, error);
+
+ dbus_message_unref (msg);
}
/** @} */