diff libpurple/dbus-server.c @ 15374:5fe8042783c1

Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author Sean Egan <seanegan@gmail.com>
date Sat, 20 Jan 2007 02:32:10 +0000
parents
children 32c366eeeb99
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/dbus-server.c	Sat Jan 20 02:32:10 2007 +0000
@@ -0,0 +1,790 @@
+/*
+ * gaim
+ *
+ * Gaim is the legal property of its developers, whose names are too numerous
+ * to list here.  Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "account.h"
+#include "blist.h"
+#include "conversation.h"
+#include "dbus-gaim.h"
+#include "dbus-server.h"
+#include "dbus-useful.h"
+#include "dbus-bindings.h"
+#include "debug.h"
+#include "core.h"
+#include "internal.h"
+#include "savedstatuses.h"
+#include "util.h"
+#include "value.h"
+#include "xmlnode.h"
+
+
+/**************************************************************************/
+/** @name Gaim DBUS pointer registration mechanism                        */
+/**************************************************************************/
+
+/*
+ * Here we include the list of #GAIM_DBUS_DEFINE_TYPE statements for
+ * all structs defined in gaim.  This file has been generated by the
+ * #dbus-analyze-types.py script.
+ */
+
+#include "dbus-types.c"
+
+/*
+ * The following three hashtables map are used to translate between
+ * pointers (nodes) and the corresponding handles (ids).
+ */
+
+static GHashTable *map_node_id;
+static GHashTable *map_id_node;
+static GHashTable *map_id_type;
+
+static gchar *init_error;
+
+/**
+ * This function initializes the pointer-id traslation system.  It
+ * creates the three above hashtables and defines parents of some types.
+ */
+void
+gaim_dbus_init_ids(void)
+{
+	map_id_node = g_hash_table_new(g_direct_hash, g_direct_equal);
+	map_id_type = g_hash_table_new(g_direct_hash, g_direct_equal);
+	map_node_id = g_hash_table_new(g_direct_hash, g_direct_equal);
+
+	GAIM_DBUS_TYPE(GaimBuddy)->parent   = GAIM_DBUS_TYPE(GaimBlistNode);
+	GAIM_DBUS_TYPE(GaimContact)->parent = GAIM_DBUS_TYPE(GaimBlistNode);
+	GAIM_DBUS_TYPE(GaimChat)->parent    = GAIM_DBUS_TYPE(GaimBlistNode);
+	GAIM_DBUS_TYPE(GaimGroup)->parent   = GAIM_DBUS_TYPE(GaimBlistNode);
+}
+
+void
+gaim_dbus_register_pointer(gpointer node, GaimDBusType *type)
+{
+	static gint last_id = 0;
+
+	g_return_if_fail(map_node_id);
+	g_return_if_fail(g_hash_table_lookup(map_node_id, node) == NULL);
+
+	last_id++;
+	g_hash_table_insert(map_node_id, node, GINT_TO_POINTER(last_id));
+	g_hash_table_insert(map_id_node, GINT_TO_POINTER(last_id), node);
+	g_hash_table_insert(map_id_type, GINT_TO_POINTER(last_id), type);
+}
+
+void
+gaim_dbus_unregister_pointer(gpointer node)
+{
+	gpointer id = g_hash_table_lookup(map_node_id, node);
+
+	g_hash_table_remove(map_node_id, node);
+	g_hash_table_remove(map_id_node, GINT_TO_POINTER(id));
+	g_hash_table_remove(map_id_type, GINT_TO_POINTER(id));
+}
+
+gint
+gaim_dbus_pointer_to_id(gpointer node)
+{
+	gint id = GPOINTER_TO_INT(g_hash_table_lookup(map_node_id, node));
+	if ((id == 0) && (node != NULL))
+	{
+		gaim_debug_warning("dbus",
+				"Need to register an object with the dbus subsystem.\n");
+		g_return_val_if_reached(0);
+	}
+	return id;
+}
+
+gpointer
+gaim_dbus_id_to_pointer(gint id, GaimDBusType *type)
+{
+	GaimDBusType *objtype;
+
+	objtype = (GaimDBusType*)g_hash_table_lookup(map_id_type,
+			GINT_TO_POINTER(id));
+
+	while (objtype != type && objtype != NULL)
+		objtype = objtype->parent;
+
+	if (objtype == type)
+		return g_hash_table_lookup(map_id_node, GINT_TO_POINTER(id));
+	else
+		return NULL;
+}
+
+gint
+gaim_dbus_pointer_to_id_error(gpointer ptr, DBusError *error)
+{
+	gint id = gaim_dbus_pointer_to_id(ptr);
+
+	if (ptr != NULL && id == 0)
+		dbus_set_error(error, "net.sf.gaim.ObjectNotFound",
+				"The return object is not mapped (this is a Gaim error)");
+
+	return id;
+}
+
+gpointer
+gaim_dbus_id_to_pointer_error(gint id, GaimDBusType *type,
+		const char *typename, DBusError *error)
+{
+	gpointer ptr = gaim_dbus_id_to_pointer(id, type);
+
+	if (ptr == NULL && id != 0)
+		dbus_set_error(error, "net.sf.gaim.InvalidHandle",
+				"%s object with ID = %i not found", typename, id);
+
+	return ptr;
+}
+
+
+/**************************************************************************/
+/** @name Modified versions of some DBus functions                        */
+/**************************************************************************/
+
+dbus_bool_t
+gaim_dbus_message_get_args(DBusMessage *message,
+		DBusError *error, int first_arg_type, ...)
+{
+	dbus_bool_t retval;
+	va_list var_args;
+
+	va_start(var_args, first_arg_type);
+	retval = gaim_dbus_message_get_args_valist(message, error, first_arg_type, var_args);
+	va_end(var_args);
+
+	return retval;
+}
+
+dbus_bool_t
+gaim_dbus_message_get_args_valist(DBusMessage *message,
+		DBusError *error, int first_arg_type, va_list var_args)
+{
+	DBusMessageIter iter;
+
+	dbus_message_iter_init(message, &iter);
+	return gaim_dbus_message_iter_get_args_valist(&iter, error, first_arg_type, var_args);
+}
+
+dbus_bool_t
+gaim_dbus_message_iter_get_args(DBusMessageIter *iter,
+		DBusError *error, int first_arg_type, ...)
+{
+	dbus_bool_t retval;
+	va_list var_args;
+
+	va_start(var_args, first_arg_type);
+	retval = gaim_dbus_message_iter_get_args_valist(iter, error, first_arg_type, var_args);
+	va_end(var_args);
+
+	return retval;
+}
+
+#define TYPE_IS_CONTAINER(typecode)        \
+	((typecode) == DBUS_TYPE_STRUCT ||     \
+	 (typecode) == DBUS_TYPE_DICT_ENTRY || \
+	 (typecode) == DBUS_TYPE_VARIANT ||    \
+	 (typecode) == DBUS_TYPE_ARRAY)
+
+
+dbus_bool_t
+gaim_dbus_message_iter_get_args_valist(DBusMessageIter *iter,
+		DBusError *error, int first_arg_type, va_list var_args)
+{
+	int spec_type, msg_type, i;
+
+	spec_type = first_arg_type;
+
+	for (i = 0; spec_type != DBUS_TYPE_INVALID; i++)
+	{
+		msg_type = dbus_message_iter_get_arg_type(iter);
+
+		if (msg_type != spec_type)
+		{
+			dbus_set_error(error, DBUS_ERROR_INVALID_ARGS,
+					"Argument %d is specified to be of type \"%i\", but "
+					"is actually of type \"%i\"\n", i,
+					spec_type, msg_type);
+			return FALSE;
+		}
+
+		if (!TYPE_IS_CONTAINER(spec_type))
+		{
+			gpointer ptr;
+			ptr = va_arg (var_args, gpointer);
+			dbus_message_iter_get_basic(iter, ptr);
+		}
+		else
+		{
+			DBusMessageIter *sub;
+			sub = va_arg (var_args, DBusMessageIter*);
+			dbus_message_iter_recurse(iter, sub);
+			gaim_debug_info("dbus", "subiter %p:%p\n", sub, * (gpointer*) sub);
+			break; /* for testing only! */
+		}
+
+		spec_type = va_arg(var_args, int);
+		if (!dbus_message_iter_next(iter) && spec_type != DBUS_TYPE_INVALID)
+		{
+			dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
+					"Message has only %d arguments, but more were expected", i);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+
+
+/**************************************************************************/
+/** @name Useful functions                                                */
+/**************************************************************************/
+
+const char *empty_to_null(const char *str)
+{
+	if (str == NULL || str[0] == 0)
+		return NULL;
+	else
+		return str;
+}
+
+const char *
+null_to_empty(const char *s)
+{
+	if (s)
+		return s;
+	else
+		return "";
+}
+
+dbus_int32_t *
+gaim_dbusify_GList(GList *list, gboolean free_memory, dbus_int32_t *len)
+{
+	dbus_int32_t *array;
+	int i;
+	GList *elem;
+
+	*len = g_list_length(list);
+	array = g_new0(dbus_int32_t, g_list_length(list));
+	for (i = 0, elem = list; elem != NULL; elem = elem->next, i++)
+		array[i] = gaim_dbus_pointer_to_id(elem->data);
+
+	if (free_memory)
+		g_list_free(list);
+
+	return array;
+}
+
+dbus_int32_t *
+gaim_dbusify_GSList(GSList *list, gboolean free_memory, dbus_int32_t *len)
+{
+	dbus_int32_t *array;
+	int i;
+	GSList *elem;
+
+	*len = g_slist_length(list);
+	array = g_new0(dbus_int32_t, g_slist_length(list));
+	for (i = 0, elem = list; elem != NULL; elem = elem->next, i++)
+		array[i] = gaim_dbus_pointer_to_id(elem->data);
+
+	if (free_memory)
+		g_slist_free(list);
+
+	return array;
+}
+
+gpointer *
+gaim_GList_to_array(GList *list, gboolean free_memory, dbus_int32_t *len)
+{
+	gpointer *array;
+	int i;
+	GList *elem;
+
+	*len = g_list_length(list);
+	array = g_new0(gpointer, g_list_length(list));
+	for (i = 0, elem = list; elem != NULL; elem = elem->next, i++)
+		array[i] = elem->data;
+
+	if (free_memory)
+		g_list_free(list);
+
+	return array;
+}
+
+gpointer *
+gaim_GSList_to_array(GSList *list, gboolean free_memory, dbus_int32_t *len)
+{
+	gpointer *array;
+	int i;
+	GSList *elem;
+
+	*len = g_slist_length(list);
+	array = g_new0(gpointer, g_slist_length(list));
+	for (i = 0, elem = list; elem != NULL; elem = elem->next, i++)
+		array[i] = elem->data;
+
+	if (free_memory)
+		g_slist_free(list);
+
+	return array;
+}
+
+GHashTable *
+gaim_dbus_iter_hash_table(DBusMessageIter *iter, DBusError *error)
+{
+	GHashTable *hash;
+
+	/* we do not need to destroy strings because they are part of the message */
+	hash = g_hash_table_new(g_str_hash, g_str_equal);
+
+	do {
+		char *key, *value;
+		DBusMessageIter subiter;
+
+		if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
+			goto error;
+			/* With all due respect to Dijkstra,
+			 * this goto is for exception
+			 * handling, and it is ok because it
+			 * avoids duplication of the code
+			 * responsible for destroying the hash
+			 * table.  Exceptional instructions
+			 * for exceptional situations.
+			 */
+
+		dbus_message_iter_recurse(iter, &subiter);
+		if (!gaim_dbus_message_iter_get_args(&subiter, error,
+				DBUS_TYPE_STRING, &key,
+				DBUS_TYPE_STRING, &value,
+				DBUS_TYPE_INVALID))
+			goto error; /* same here */
+
+		g_hash_table_insert(hash, key, value);
+	} while (dbus_message_iter_next(iter));
+
+	return hash;
+
+error:
+	g_hash_table_destroy(hash);
+	return NULL;
+}
+
+/**************************************************************/
+/* DBus bindings ...                                          */
+/**************************************************************/
+
+static DBusConnection *gaim_dbus_connection;
+
+DBusConnection *
+gaim_dbus_get_connection(void)
+{
+	return gaim_dbus_connection;
+}
+
+#include "dbus-bindings.c"
+
+static gboolean
+gaim_dbus_dispatch_cb(DBusConnection *connection,
+		DBusMessage *message, void *user_data)
+{
+	const char *name;
+	GaimDBusBinding *bindings;
+	int i;
+
+	bindings = (GaimDBusBinding*) user_data;
+
+	if (!dbus_message_has_path(message, DBUS_PATH_GAIM))
+		return FALSE;
+
+	name = dbus_message_get_member(message);
+
+	if (name == NULL)
+		return FALSE;
+
+	if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+		return FALSE;
+
+	for (i = 0; bindings[i].name; i++)
+		if (!strcmp(name, bindings[i].name))
+		{
+			DBusMessage *reply;
+			DBusError error;
+
+			dbus_error_init(&error);
+
+			reply = bindings[i].handler(message, &error);
+
+			if (reply == NULL && dbus_error_is_set(&error))
+				reply = dbus_message_new_error (message,
+						error.name, error.message);
+
+			if (reply != NULL)
+			{
+				dbus_connection_send(connection, reply, NULL);
+				dbus_message_unref(reply);
+			}
+
+			return TRUE; /* return reply! */
+		}
+
+	return FALSE;
+}
+
+
+static const char *
+dbus_gettext(const char **ptr)
+{
+	const char *text = *ptr;
+	*ptr += strlen(text) + 1;
+	return text;
+}
+
+static void
+gaim_dbus_introspect_cb(GList **bindings_list, void *bindings)
+{
+	*bindings_list = g_list_prepend(*bindings_list, bindings);
+}
+
+static DBusMessage *gaim_dbus_introspect(DBusMessage *message)
+{
+	DBusMessage *reply;
+	GString *str;
+	GList *bindings_list, *node;
+
+	str = g_string_sized_new(0x1000); /* TODO: why this size? */
+
+	g_string_append(str, "<!DOCTYPE node PUBLIC '-//freedesktop//DTD D-BUS Object Introspection 1.0//EN' 'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>\n");
+	g_string_append_printf(str, "<node name='%s'>\n", DBUS_PATH_GAIM);
+	g_string_append_printf(str, "<interface name='%s'>\n", DBUS_INTERFACE_GAIM);
+
+	bindings_list = NULL;
+	gaim_signal_emit(gaim_dbus_get_handle(), "dbus-introspect", &bindings_list);
+
+	for (node = bindings_list; node; node = node->next)
+	{
+		GaimDBusBinding *bindings;
+		int i;
+
+		bindings = (GaimDBusBinding*)node->data;
+
+		for (i = 0; bindings[i].name; i++)
+		{
+			const char *text;
+
+			g_string_append_printf(str, "<method name='%s'>\n", bindings[i].name);
+
+			text = bindings[i].parameters;
+			while (*text)
+			{
+				const char *name, *direction, *type;
+
+				direction = dbus_gettext(&text);
+				type = dbus_gettext(&text);
+				name = dbus_gettext(&text);
+
+				g_string_append_printf(str,
+						"<arg name='%s' type='%s' direction='%s'/>\n",
+						name, type, direction);
+			}
+			g_string_append(str, "</method>\n");
+		}
+	}
+
+	g_string_append(str, "</interface>\n</node>\n");
+
+	reply = dbus_message_new_method_return(message);
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, &(str->str),
+			DBUS_TYPE_INVALID);
+	g_string_free(str, TRUE);
+	g_list_free(bindings_list);
+
+	return reply;
+}
+
+static DBusHandlerResult
+gaim_dbus_dispatch(DBusConnection *connection,
+		DBusMessage *message, void *user_data)
+{
+	if (gaim_signal_emit_return_1(gaim_dbus_get_handle(),
+			"dbus-method-called", connection, message))
+		return DBUS_HANDLER_RESULT_HANDLED;
+
+	if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL &&
+			dbus_message_has_path(message, DBUS_PATH_GAIM) &&
+			dbus_message_has_interface(message, DBUS_INTERFACE_INTROSPECTABLE) &&
+			dbus_message_has_member(message, "Introspect"))
+	{
+		DBusMessage *reply;
+		reply = gaim_dbus_introspect(message);
+		dbus_connection_send (connection, reply, NULL);
+		dbus_message_unref(reply);
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+void
+gaim_dbus_register_bindings(void *handle, GaimDBusBinding *bindings)
+{
+	gaim_signal_connect(gaim_dbus_get_handle(), "dbus-method-called",
+			handle,
+			GAIM_CALLBACK(gaim_dbus_dispatch_cb),
+			bindings);
+	gaim_signal_connect(gaim_dbus_get_handle(), "dbus-introspect",
+			handle,
+			GAIM_CALLBACK(gaim_dbus_introspect_cb),
+			bindings);
+}
+
+static void
+gaim_dbus_dispatch_init(void)
+{
+	static DBusObjectPathVTable vtable = {NULL, &gaim_dbus_dispatch, NULL, NULL, NULL, NULL};
+	DBusError error;
+	int result;
+
+	dbus_error_init(&error);
+	gaim_dbus_connection = dbus_bus_get(DBUS_BUS_STARTER, &error);
+
+	if (gaim_dbus_connection == NULL)
+	{
+		init_error = g_strdup_printf(N_("Failed to get connection: %s"), error.message);
+		dbus_error_free(&error);
+		return;
+	}
+
+	/* Do not allow libdbus to exit on connection failure (This may
+	   work around random exit(1) on SIGPIPE errors) */
+	dbus_connection_set_exit_on_disconnect (gaim_dbus_connection, FALSE);
+
+	if (!dbus_connection_register_object_path(gaim_dbus_connection,
+			DBUS_PATH_GAIM, &vtable, NULL))
+	{
+		init_error = g_strdup_printf(N_("Failed to get name: %s"), error.name);
+		dbus_error_free(&error);
+		return;
+	}
+
+	result = dbus_bus_request_name(gaim_dbus_connection,
+			DBUS_SERVICE_GAIM, 0, &error);
+
+	if (dbus_error_is_set(&error))
+	{
+		dbus_connection_unref(gaim_dbus_connection);
+		dbus_error_free(&error);
+		gaim_dbus_connection = NULL;
+		init_error = g_strdup_printf(N_("Failed to get serv name: %s"), error.name);
+		return;
+	}
+
+	dbus_connection_setup_with_g_main(gaim_dbus_connection, NULL);
+
+	gaim_debug_misc("dbus", "okkk\n");
+
+	gaim_signal_register(gaim_dbus_get_handle(), "dbus-method-called",
+			 gaim_marshal_BOOLEAN__POINTER_POINTER,
+			 gaim_value_new(GAIM_TYPE_BOOLEAN), 2,
+			 gaim_value_new(GAIM_TYPE_POINTER),
+			 gaim_value_new(GAIM_TYPE_POINTER));
+
+	gaim_signal_register(gaim_dbus_get_handle(), "dbus-introspect",
+			 gaim_marshal_VOID__POINTER, NULL, 1,
+			 gaim_value_new_outgoing(GAIM_TYPE_POINTER));
+
+	GAIM_DBUS_REGISTER_BINDINGS(gaim_dbus_get_handle());
+}
+
+
+
+/**************************************************************************/
+/** @name Signals                                                         */
+/**************************************************************************/
+
+
+
+static char *
+gaim_dbus_convert_signal_name(const char *gaim_name)
+{
+	int gaim_index, g_index;
+	char *g_name = g_new(char, strlen(gaim_name) + 1);
+	gboolean capitalize_next = TRUE;
+
+	for (gaim_index = g_index = 0; gaim_name[gaim_index]; gaim_index++)
+		if (gaim_name[gaim_index] != '-' && gaim_name[gaim_index] != '_')
+		{
+			if (capitalize_next)
+				g_name[g_index++] = g_ascii_toupper(gaim_name[gaim_index]);
+			else
+				g_name[g_index++] = gaim_name[gaim_index];
+			capitalize_next = FALSE;
+		} else
+			capitalize_next = TRUE;
+
+	g_name[g_index] = 0;
+
+	return g_name;
+}
+
+#define my_arg(type) (ptr != NULL ? * ((type *)ptr) : va_arg(data, type))
+
+static void
+gaim_dbus_message_append_gaim_values(DBusMessageIter *iter,
+		int number, GaimValue **gaim_values, va_list data)
+{
+	int i;
+
+	for (i = 0; i < number; i++)
+	{
+		const char *str;
+		int id;
+		gint xint;
+		guint xuint;
+		gboolean xboolean;
+		gpointer ptr = NULL;
+
+		if (gaim_value_is_outgoing(gaim_values[i]))
+		{
+			ptr = my_arg(gpointer);
+			g_return_if_fail(ptr);
+		}
+
+		switch (gaim_values[i]->type)
+		{
+		case GAIM_TYPE_INT:
+			xint = my_arg(gint);
+			dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &xint);
+			break;
+		case GAIM_TYPE_UINT:
+			xuint = my_arg(guint);
+			dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &xuint);
+			break;
+		case GAIM_TYPE_BOOLEAN:
+			xboolean = my_arg(gboolean);
+			dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &xboolean);
+			break;
+		case GAIM_TYPE_STRING:
+			str = null_to_empty(my_arg(char*));
+			if (!g_utf8_validate(str, -1, NULL)) {
+				gchar *tmp;
+				gaim_debug_error("dbus", "Invalid UTF-8 string passed to signal, emitting salvaged string!\n");
+				tmp = gaim_utf8_salvage(str);
+				dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &tmp);
+				g_free(tmp);
+			} else {
+				dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
+			}
+			break;
+		case GAIM_TYPE_SUBTYPE: /* registered pointers only! */
+		case GAIM_TYPE_POINTER:
+		case GAIM_TYPE_OBJECT:
+		case GAIM_TYPE_BOXED:
+			id = gaim_dbus_pointer_to_id(my_arg(gpointer));
+			dbus_message_iter_append_basic(iter,
+					(sizeof(void *) == 4) ? DBUS_TYPE_UINT32 : DBUS_TYPE_UINT64, &id);
+			break;
+		default: /* no conversion implemented */
+			g_return_if_reached();
+		}
+	}
+}
+
+#undef my_arg
+
+void
+gaim_dbus_signal_emit_gaim(const char *name, int num_values,
+		GaimValue **values, va_list vargs)
+{
+	DBusMessage *signal;
+	DBusMessageIter iter;
+	char *newname;
+
+#if 0 /* this is noisy with no dbus connection */
+	g_return_if_fail(gaim_dbus_connection);
+#else
+	if (gaim_dbus_connection == NULL)
+		return;
+#endif
+
+
+	/*
+	 * The test below is a hack that prevents our "dbus-method-called"
+	 * signal from being propagated to dbus.  What we really need is a
+	 * flag for each signal that states whether this signal is to be
+	 * dbus-propagated or not.
+	 */
+	if (!strcmp(name, "dbus-method-called"))
+		return;
+
+	newname = gaim_dbus_convert_signal_name(name);
+	signal = dbus_message_new_signal(DBUS_PATH_GAIM, DBUS_INTERFACE_GAIM, newname);
+	dbus_message_iter_init_append(signal, &iter);
+
+	gaim_dbus_message_append_gaim_values(&iter, num_values, values, vargs);
+
+	dbus_connection_send(gaim_dbus_connection, signal, NULL);
+
+	g_free(newname);
+	dbus_message_unref(signal);
+}
+
+const char *
+gaim_dbus_get_init_error(void)
+{
+	return init_error;
+}
+
+void *
+gaim_dbus_get_handle(void)
+{
+	static int handle;
+
+	return &handle;
+}
+
+void
+gaim_dbus_init(void)
+{
+	gaim_dbus_init_ids();
+
+	g_free(init_error);
+	init_error = NULL;
+	gaim_dbus_dispatch_init();
+	if (init_error != NULL)
+		gaim_debug_error("dbus", "%s\n", init_error);
+}
+
+void
+gaim_dbus_uninit(void)
+{
+	/* Surely we must do SOME kind of uninitialization? */
+
+	g_free(init_error);
+	init_error = NULL;
+}