summaryrefslogtreecommitdiff
path: root/telepathy-glib/dbus-daemon.c
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2009-08-17 15:30:16 +0100
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2009-08-17 16:20:52 +0100
commit48b48dca4a73d3bee4d1311163001e1cac26adb8 (patch)
treea00266e9760c84730fd530e8c0a30954c9a8eded /telepathy-glib/dbus-daemon.c
parentf6d4e669ec944cb9da603f4ded8732f65ddd26a4 (diff)
downloadtelepathy-glib-48b48dca4a73d3bee4d1311163001e1cac26adb8.tar.gz
Add tp_dbus_daemon_list_names, tp_dbus_daemon_list_activatable_names
These use libdbus directly, to avoid DBusGProxy's undesirable signal-binding (which causes us to wake up on every NameOwnerChanged).
Diffstat (limited to 'telepathy-glib/dbus-daemon.c')
-rw-r--r--telepathy-glib/dbus-daemon.c272
1 files changed, 272 insertions, 0 deletions
diff --git a/telepathy-glib/dbus-daemon.c b/telepathy-glib/dbus-daemon.c
index 1a34af1ac..928a3a281 100644
--- a/telepathy-glib/dbus-daemon.c
+++ b/telepathy-glib/dbus-daemon.c
@@ -931,6 +931,278 @@ tp_dbus_daemon_get_unique_name (TpDBusDaemon *self)
return dbus_bus_get_unique_name (self->priv->libdbus);
}
+typedef struct {
+ TpDBusDaemon *self;
+ DBusMessage *reply;
+ TpDBusDaemonListNamesCb callback;
+ gpointer user_data;
+ GDestroyNotify destroy;
+ gpointer weak_object;
+ gsize refs;
+} ListNamesContext;
+
+static ListNamesContext *
+list_names_context_new (TpDBusDaemon *self,
+ TpDBusDaemonListNamesCb callback,
+ gpointer user_data,
+ GDestroyNotify destroy,
+ GObject *weak_object)
+{
+ ListNamesContext *context = g_slice_new (ListNamesContext);
+
+ context->self = g_object_ref (self);
+ context->reply = NULL;
+ context->callback = callback;
+ context->user_data = user_data;
+ context->destroy = destroy;
+ context->weak_object = weak_object;
+
+ if (context->weak_object != NULL)
+ g_object_add_weak_pointer (weak_object, &context->weak_object);
+
+ context->refs = 1;
+ return context;
+}
+
+static void
+list_names_context_unref (gpointer data)
+{
+ ListNamesContext *context = data;
+
+ if (--context->refs == 0)
+ {
+ g_object_unref (context->self);
+
+ if (context->reply != NULL)
+ dbus_message_unref (context->reply);
+
+ if (context->destroy != NULL)
+ context->destroy (context->user_data);
+
+ context->destroy = NULL;
+
+ if (context->weak_object != NULL)
+ g_object_remove_weak_pointer (context->weak_object,
+ &context->weak_object);
+
+ g_slice_free (ListNamesContext, context);
+ }
+}
+
+static gboolean
+_tp_dbus_daemon_list_names_idle (gpointer data)
+{
+ ListNamesContext *context = data;
+ char **array = NULL;
+ const gchar * const *result = NULL;
+ GError *error = NULL;
+
+ if (context->callback == NULL)
+ {
+ DEBUG ("Caller no longer cares (weak object vanished), ignoring");
+ return FALSE;
+ }
+
+ if (context->reply == NULL)
+ {
+ g_set_error_literal (&error, DBUS_GERROR, DBUS_GERROR_DISCONNECTED,
+ "DBusConnection disconnected");
+ }
+ else if (dbus_message_get_type (context->reply) ==
+ DBUS_MESSAGE_TYPE_METHOD_RETURN)
+ {
+ int n_elements;
+
+ if (dbus_message_get_args (context->reply, NULL,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &array, &n_elements,
+ DBUS_TYPE_INVALID))
+ {
+ result = (const gchar * const *) array;
+ g_assert (result[n_elements] == NULL);
+ }
+ else
+ {
+ g_set_error_literal (&error, DBUS_GERROR, DBUS_GERROR_INVALID_ARGS,
+ "Malformed reply from List*Names()");
+ }
+ }
+ else
+ {
+ DBusError dbus_error = DBUS_ERROR_INIT;
+
+ if (dbus_set_error_from_message (&dbus_error, context->reply))
+ {
+ /* FIXME: ideally we'd use dbus-glib's error mapping here, but we
+ * don't have access to it */
+ g_set_error (&error, DBUS_GERROR, DBUS_GERROR_FAILED,
+ "List*Names() raised %s: %s", dbus_error.name,
+ dbus_error.message);
+ dbus_error_free (&dbus_error);
+ }
+ else
+ {
+ g_set_error_literal (&error, DBUS_GERROR, DBUS_GERROR_INVALID_ARGS,
+ "Unexpected message type from List*Names()");
+ }
+ }
+
+ if (error != NULL)
+ DEBUG ("%s", error->message);
+
+ context->callback (context->self, result, error, context->user_data,
+ context->weak_object);
+ dbus_free_string_array (array); /* NULL-safe */
+ return FALSE;
+}
+
+static void
+_tp_dbus_daemon_list_names_notify (DBusPendingCall *pc,
+ gpointer data)
+{
+ ListNamesContext *context = data;
+
+ /* we recycle this function for the case where the connection is already
+ * disconnected: in that case we use pc = NULL */
+ if (pc != NULL)
+ context->reply = dbus_pending_call_steal_reply (pc);
+
+ /* We have to do the real work in an idle, so we don't break re-entrant
+ * calls (the dbus-glib event source isn't re-entrant) */
+ context->refs++;
+ g_idle_add_full (G_PRIORITY_HIGH, _tp_dbus_daemon_list_names_idle,
+ context, list_names_context_unref);
+
+ if (pc != NULL)
+ dbus_pending_call_unref (pc);
+}
+
+/**
+ * TpDBusDaemonListNamesCb:
+ * @bus_daemon: object representing a connection to a bus
+ * @names: constant %NULL-terminated array of constant strings representing
+ * bus names, or %NULL on error
+ * @error: the error that occurred, or %NULL on success
+ * @user_data: the same user data that was passed to
+ * tp_dbus_daemon_list_names or tp_dbus_daemon_list_activatable_names
+ * @weak_object: the same object that was passed to
+ * tp_dbus_daemon_list_names or tp_dbus_daemon_list_activatable_names
+ *
+ * Signature of a callback for functions that list bus names.
+ *
+ * Since: 0.7.UNRELEASED
+ */
+
+static void
+_tp_dbus_daemon_list_names_common (TpDBusDaemon *self,
+ const gchar *method,
+ gint timeout_ms,
+ TpDBusDaemonListNamesCb callback,
+ gpointer user_data,
+ GDestroyNotify destroy,
+ GObject *weak_object)
+{
+ DBusMessage *message;
+ DBusPendingCall *pc = NULL;
+ ListNamesContext *context;
+
+ g_return_if_fail (TP_IS_DBUS_DAEMON (self));
+ g_return_if_fail (callback != NULL);
+ g_return_if_fail (weak_object == NULL || G_IS_OBJECT (weak_object));
+
+ message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, method);
+
+ if (message == NULL)
+ g_error ("Out of memory");
+
+ if (!dbus_connection_send_with_reply (self->priv->libdbus,
+ message, &pc, timeout_ms))
+ g_error ("Out of memory");
+ /* pc is unreffed by _tp_dbus_daemon_list_names_notify */
+
+ context = list_names_context_new (self, callback, user_data, destroy,
+ weak_object);
+
+ if (pc == NULL || dbus_pending_call_get_completed (pc))
+ {
+ /* pc can be NULL when the connection is already disconnected */
+ _tp_dbus_daemon_list_names_notify (pc, context);
+ list_names_context_unref (context);
+ }
+ else if (!dbus_pending_call_set_notify (pc,
+ _tp_dbus_daemon_list_names_notify, context,
+ list_names_context_unref))
+ {
+ g_error ("Out of memory");
+ }
+}
+
+/**
+ * tp_dbus_daemon_list_names:
+ * @self: object representing a connection to a bus
+ * @timeout_ms: timeout for the call
+ * @callback: callback to be called on success or failure; must not be %NULL
+ * @user_data: opaque user-supplied data to pass to the callback
+ * @destroy: if not %NULL, called with @user_data as argument after the call
+ * has succeeded or failed, or after @weak_object has been destroyed
+ * @weak_object: if not %NULL, a GObject which will be weakly referenced; if
+ * it is destroyed, @callback will not be called at all
+ *
+ * Call the ListNames method on the bus daemon, asynchronously. The @callback
+ * will be called from the main loop with a list of all the names (either
+ * unique or well-known) that exist on the bus.
+ *
+ * In versions of telepathy-glib that have it, this should be preferred
+ * instead of calling tp_cli_dbus_daemon_call_list_names(), since that
+ * function will result in wakeups for every NameOwnerChanged signal.
+ *
+ * Since: 0.7.UNRELEASED
+ */
+void
+tp_dbus_daemon_list_names (TpDBusDaemon *self,
+ gint timeout_ms,
+ TpDBusDaemonListNamesCb callback,
+ gpointer user_data,
+ GDestroyNotify destroy,
+ GObject *weak_object)
+{
+ _tp_dbus_daemon_list_names_common (self, "ListNames", timeout_ms,
+ callback, user_data, destroy, weak_object);
+}
+
+/**
+ * tp_dbus_daemon_list_activatable_names:
+ * @self: object representing a connection to a bus daemon
+ * @timeout_ms: timeout for the call
+ * @callback: callback to be called on success or failure; must not be %NULL
+ * @user_data: opaque user-supplied data to pass to the callback
+ * @destroy: if not %NULL, called with @user_data as argument after the call
+ * has succeeded or failed, or after @weak_object has been destroyed
+ * @weak_object: if not %NULL, a GObject which will be weakly referenced; if
+ * it is destroyed, @callback will not be called at all
+ *
+ * Call the ListActivatableNames method on the bus daemon, asynchronously.
+ * The @callback will be called from the main loop with a list of all the
+ * well-known names that are available for service-activation on the bus.
+ *
+ * In versions of telepathy-glib that have it, this should be preferred
+ * instead of calling tp_cli_dbus_daemon_call_list_activatable_names(), since
+ * that function will result in wakeups for every NameOwnerChanged signal.
+ *
+ * Since: 0.7.UNRELEASED
+ */
+void
+tp_dbus_daemon_list_activatable_names (TpDBusDaemon *self,
+ gint timeout_ms,
+ TpDBusDaemonListNamesCb callback,
+ gpointer user_data,
+ GDestroyNotify destroy,
+ GObject *weak_object)
+{
+ _tp_dbus_daemon_list_names_common (self, "ListActivatableNames", timeout_ms,
+ callback, user_data, destroy, weak_object);
+}
+
static void
free_daemon_list (gpointer p)
{