[gconf/port-to-dbus: 13/23] build: Conditionally compile in the DBUS implementation files



commit eed7b085e64f425bac72ec5f9f0634fdb35176d3
Author: Rob Bradford <rob linux intel com>
Date:   Mon Jun 20 12:05:56 2011 +0100

    build: Conditionally compile in the DBUS implementation files

 gconf/Makefile.am           |   16 +
 gconf/gconf-database-dbus.c |  978 +++++++++++++++++
 gconf/gconf-database-dbus.h |   37 +
 gconf/gconf-dbus-utils.c    | 1133 ++++++++++++++++++++
 gconf/gconf-dbus-utils.h    |   99 ++
 gconf/gconf-dbus.c          | 2468 +++++++++++++++++++++++++++++++++++++++++++
 gconf/gconfd-dbus.c         |  392 +++++++
 gconf/gconfd-dbus.h         |   42 +
 8 files changed, 5165 insertions(+), 0 deletions(-)
---
diff --git a/gconf/Makefile.am b/gconf/Makefile.am
index 7558697..821e768 100644
--- a/gconf/Makefile.am
+++ b/gconf/Makefile.am
@@ -36,7 +36,9 @@ lib_LTLIBRARIES = libgconf-2.la
 bin_PROGRAMS = gconftool-2 
 libexec_PROGRAMS = gconfd-2 $(SANITY_CHECK)
 
+if HAVE_CORBA
 CORBA_SOURCECODE = GConfX-common.c GConfX-skels.c GConfX-stubs.c GConfX.h
+endif
 
 BUILT_SOURCES = 			\
 	$(CORBA_SOURCECODE)		\
@@ -76,6 +78,13 @@ gconfd_2_SOURCES = \
 	gconfd.h		\
 	gconfd.c
 
+if HAVE_DBUS
+gconfd_2_SOURCES += \
+	gconfd-dbus.c \
+	gconfd-dbus.h \
+	gconf-database-dbus.h \
+	gconf-database-dbus.c
+endif
 if OS_WIN32
 gconfd_2_LDFLAGS = -mwindows
 endif
@@ -121,6 +130,13 @@ libgconf_2_la_SOURCES = \
 	$(CORBA_SOURCECODE)	\
 	$(WIN32_SOURCECODE)
 
+if HAVE_DBUS
+libgconf_2_la_SOURCES += \
+	gconf-dbus.c \
+	gconf-dbus-utils.c \
+	gconf-dbus-utils.h
+endif
+
 libgconf_2_la_LDFLAGS = -version-info $(GCONF_CURRENT):$(GCONF_REVISION):$(GCONF_AGE) -no-undefined
 
 libgconf_2_la_LIBADD = $(INTLLIBS) $(DEPENDENT_LIBS) $(DEPENDENT_DBUS_LIBS) $(DEPENDENT_ORBIT_LIBS)
diff --git a/gconf/gconf-database-dbus.c b/gconf/gconf-database-dbus.c
new file mode 100644
index 0000000..ce42382
--- /dev/null
+++ b/gconf/gconf-database-dbus.c
@@ -0,0 +1,978 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+/* GConf
+ * Copyright (C) 2003, 2004 Imendio HB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+#include "gconfd.h"
+#include "gconf-dbus-utils.h"
+#include "gconfd-dbus.h"
+#include "gconf-database-dbus.h"
+
+#define DATABASE_OBJECT_PATH "/org/gnome/GConf/Database"
+
+static gint object_nr = 0;
+
+typedef struct {
+  char  *namespace_section;
+  GList *clients;
+} NotificationData;
+
+typedef struct {
+  gchar *service;
+  gint nr_of_notifications;
+} ListeningClientData;
+
+static void              database_unregistered_func         (DBusConnection   *connection,
+							     GConfDatabase    *db);
+static DBusHandlerResult database_message_func              (DBusConnection   *connection,
+							     DBusMessage      *message,
+							     GConfDatabase    *db);
+static DBusHandlerResult database_filter_func               (DBusConnection   *connection,
+							     DBusMessage      *message,
+							     GConfDatabase    *db);
+static DBusHandlerResult database_handle_name_owner_changed (DBusConnection   *connection,
+							     DBusMessage      *message,
+							     GConfDatabase    *db);
+
+static void     database_handle_lookup            (DBusConnection   *conn,
+						   DBusMessage      *message,
+						   GConfDatabase    *db);
+static void     database_handle_lookup_ext        (DBusConnection   *conn,
+						   DBusMessage      *message,
+						   GConfDatabase    *db);
+static void     database_handle_lookup_default    (DBusConnection   *conn,
+						   DBusMessage      *message,
+						   GConfDatabase    *db);
+static void     database_handle_set               (DBusConnection   *conn,
+						   DBusMessage      *message,
+						   GConfDatabase    *db);
+static void     database_handle_unset             (DBusConnection   *conn,
+						   DBusMessage      *message,
+						   GConfDatabase    *db);
+static void     database_handle_recursive_unset   (DBusConnection   *conn,
+						   DBusMessage      *message,
+						   GConfDatabase    *db);
+static void     database_handle_dir_exists        (DBusConnection   *conn,
+						   DBusMessage      *message,
+						   GConfDatabase    *db);
+static void     database_handle_get_all_entries   (DBusConnection   *conn,
+						   DBusMessage      *message,
+						   GConfDatabase    *db);
+static void     database_handle_get_all_dirs      (DBusConnection   *conn,
+						   DBusMessage      *message,
+						   GConfDatabase    *db);
+static void     database_handle_set_schema        (DBusConnection   *conn,
+						   DBusMessage      *message,
+						   GConfDatabase    *db);
+static void     database_handle_suggest_sync      (DBusConnection   *conn,
+						   DBusMessage      *message,
+						   GConfDatabase    *db);
+static void     database_handle_add_notify        (DBusConnection   *conn,
+						   DBusMessage      *message,
+						   GConfDatabase    *db);
+static gboolean database_remove_notification_data (GConfDatabase    *db,
+						   NotificationData *notification,
+						   const char       *client);
+static void     database_handle_remove_notify     (DBusConnection   *conn,
+						   DBusMessage      *message,
+						   GConfDatabase    *db);
+
+static ListeningClientData *database_add_listening_client      (GConfDatabase       *db,
+								const gchar         *service);
+static void                 database_remove_listening_client   (GConfDatabase       *db,
+								ListeningClientData *client);
+
+
+static DBusObjectPathVTable database_vtable = {
+  (DBusObjectPathUnregisterFunction) database_unregistered_func,
+  (DBusObjectPathMessageFunction)    database_message_func,
+  NULL,
+};
+ 
+static void
+database_unregistered_func (DBusConnection *connection, GConfDatabase *db)
+{
+}
+
+static DBusHandlerResult
+database_message_func (DBusConnection *connection,
+                       DBusMessage    *message,
+                       GConfDatabase  *db)
+{
+  if (gconfd_dbus_check_in_shutdown (connection, message))
+    return DBUS_HANDLER_RESULT_HANDLED;
+
+  if (dbus_message_is_method_call (message,
+				   GCONF_DBUS_DATABASE_INTERFACE,
+				   GCONF_DBUS_DATABASE_LOOKUP)) {
+    database_handle_lookup (connection, message, db);
+  }
+  else if (dbus_message_is_method_call (message,
+					GCONF_DBUS_DATABASE_INTERFACE,
+					GCONF_DBUS_DATABASE_LOOKUP_EXTENDED)) {
+    database_handle_lookup_ext (connection, message, db);
+  }
+  else if (dbus_message_is_method_call (message,
+					GCONF_DBUS_DATABASE_INTERFACE,
+					GCONF_DBUS_DATABASE_LOOKUP_DEFAULT)) {
+    database_handle_lookup_default (connection, message, db);
+  }
+  else if (dbus_message_is_method_call (message,
+					GCONF_DBUS_DATABASE_INTERFACE,
+					GCONF_DBUS_DATABASE_SET)) {
+    database_handle_set (connection, message, db);
+  }
+  else if (dbus_message_is_method_call (message,
+					GCONF_DBUS_DATABASE_INTERFACE,
+					GCONF_DBUS_DATABASE_UNSET)) {
+    database_handle_unset (connection, message, db);
+  }
+  else if (dbus_message_is_method_call (message,
+					GCONF_DBUS_DATABASE_INTERFACE,
+					GCONF_DBUS_DATABASE_RECURSIVE_UNSET)) {
+    database_handle_recursive_unset (connection, message, db);
+  }
+  else if (dbus_message_is_method_call (message,
+					GCONF_DBUS_DATABASE_INTERFACE,
+					GCONF_DBUS_DATABASE_DIR_EXISTS)) {
+    database_handle_dir_exists (connection, message, db);
+  }
+  else if (dbus_message_is_method_call (message,
+					GCONF_DBUS_DATABASE_INTERFACE,
+					GCONF_DBUS_DATABASE_GET_ALL_ENTRIES)) {
+    database_handle_get_all_entries (connection, message, db);
+  }
+  else if (dbus_message_is_method_call (message,
+					GCONF_DBUS_DATABASE_INTERFACE,
+					GCONF_DBUS_DATABASE_GET_ALL_DIRS)) {
+    database_handle_get_all_dirs (connection, message, db);
+  }
+  else if (dbus_message_is_method_call (message,
+					GCONF_DBUS_DATABASE_INTERFACE,
+					GCONF_DBUS_DATABASE_SET_SCHEMA)) {
+    database_handle_set_schema (connection, message, db);
+  }
+  else if (dbus_message_is_method_call (message,
+					GCONF_DBUS_DATABASE_INTERFACE,
+					GCONF_DBUS_DATABASE_SUGGEST_SYNC)) {
+    database_handle_suggest_sync (connection, message, db);
+  }
+  else if (dbus_message_is_method_call (message,
+					GCONF_DBUS_DATABASE_INTERFACE,
+					GCONF_DBUS_DATABASE_ADD_NOTIFY)) {
+	  database_handle_add_notify (connection, message, db);
+  }
+  else if (dbus_message_is_method_call (message,
+					GCONF_DBUS_DATABASE_INTERFACE,
+					GCONF_DBUS_DATABASE_REMOVE_NOTIFY)) {
+	  database_handle_remove_notify (connection, message, db);
+  } else {
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  }
+
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static void
+get_all_notifications_func (gpointer key,
+			    gpointer value,
+			    gpointer user_data)
+{
+  GList **list = user_data;
+  
+  *list = g_list_prepend (*list, value);
+}
+
+static DBusHandlerResult
+database_filter_func (DBusConnection *connection,
+		      DBusMessage    *message,
+		      GConfDatabase  *db)
+{
+#if 0
+  /* Debug output. */
+  if (dbus_message_get_member (message)) {
+    g_print ("Message: %s\n", dbus_message_get_member (message));
+  }
+#endif
+  
+  if (dbus_message_is_signal (message,
+			      DBUS_INTERFACE_DBUS,
+                              "NameOwnerChanged"))
+    return database_handle_name_owner_changed (connection, message, db);
+
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusHandlerResult
+database_handle_name_owner_changed (DBusConnection *connection,
+				    DBusMessage    *message,
+				    GConfDatabase  *db)
+{  
+  gchar               *service;
+  gchar               *old_owner;
+  gchar               *new_owner;
+  GList               *notifications = NULL, *l;
+  NotificationData    *notification;
+  ListeningClientData *client;
+  
+  dbus_message_get_args (message,
+			 NULL,
+			 DBUS_TYPE_STRING, &service,
+			 DBUS_TYPE_STRING, &old_owner,
+			 DBUS_TYPE_STRING, &new_owner,
+			 DBUS_TYPE_INVALID);
+  
+  if (strcmp (new_owner, "") != 0) 
+    {
+      /* Service still exist, don't remove notifications */
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+  g_hash_table_foreach (db->notifications, get_all_notifications_func,
+			&notifications);
+  
+  /* Note: This might be a bit too slow to do like this. We could add a hash
+   * table that maps client base service names to notification data, instead of
+   * going through the entire list of notifications and clients.
+   */
+  for (l = notifications; l; l = l->next)
+    {
+      notification = l->data;
+      
+      database_remove_notification_data (db, notification, service);
+    }
+ 
+  client = g_hash_table_lookup (db->listening_clients, service);
+  if (client)
+    database_remove_listening_client (db, client);
+
+  g_list_free (notifications);
+
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+    
+static void
+database_handle_lookup (DBusConnection *conn,
+                        DBusMessage    *message,
+                        GConfDatabase  *db)
+{
+  GConfValue *value;
+  DBusMessage *reply;
+  gchar *key;
+  gchar *locale;
+  GConfLocaleList *locales;
+  gboolean use_schema_default;
+  GError *gerror = NULL;
+  DBusMessageIter iter;
+  
+  if (!gconfd_dbus_get_message_args (conn, message,
+				     DBUS_TYPE_STRING, &key,
+				     DBUS_TYPE_STRING, &locale,
+				     DBUS_TYPE_BOOLEAN, &use_schema_default,
+				     DBUS_TYPE_INVALID))
+    return;
+  
+  locales = gconfd_locale_cache_lookup (locale);
+  
+  value = gconf_database_query_value (db, key, locales->list, 
+				      use_schema_default,
+				      NULL, NULL, NULL, &gerror);
+
+  if (gconfd_dbus_set_exception (conn, message, &gerror))
+    goto fail;
+
+  reply = dbus_message_new_method_return (message);
+
+  dbus_message_iter_init_append (reply, &iter);
+  gconf_dbus_utils_append_value (&iter, value);
+
+  dbus_connection_send (conn, reply, NULL);
+  dbus_message_unref (reply);
+  
+ fail:
+  if (value)
+    gconf_value_free (value);
+}
+
+static void 
+database_handle_lookup_ext (DBusConnection *conn,
+			    DBusMessage    *message,
+			    GConfDatabase  *db)
+{
+  GConfValue *value;
+  gchar *schema_name = NULL;
+  gboolean value_is_default;
+  gboolean value_is_writable;
+  DBusMessage *reply;
+  gchar *key;
+  gchar *locale;
+  GConfLocaleList *locales;
+  gboolean use_schema_default;
+  GError *gerror = NULL;
+  DBusMessageIter iter;
+  
+  if (!gconfd_dbus_get_message_args (conn, message,
+				     DBUS_TYPE_STRING, &key,
+				     DBUS_TYPE_STRING, &locale,
+				     DBUS_TYPE_BOOLEAN, &use_schema_default,
+				     DBUS_TYPE_INVALID))
+    return;
+  
+  locales = gconfd_locale_cache_lookup (locale);
+  
+  value = gconf_database_query_value (db, key, locales->list,
+				      use_schema_default,
+				      &schema_name, &value_is_default, 
+				      &value_is_writable, &gerror);
+  
+  if (gconfd_dbus_set_exception (conn, message, &gerror))
+    goto fail;
+  
+  reply = dbus_message_new_method_return (message);
+
+  dbus_message_iter_init_append (reply, &iter);
+
+  if (value)
+    gconf_dbus_utils_append_entry_values (&iter,
+					  key,
+					  value,
+					  value_is_default,
+					  value_is_writable,
+					  schema_name);
+  
+  dbus_connection_send (conn, reply, NULL);
+  dbus_message_unref (reply);
+
+ fail:
+  g_free (schema_name);
+
+  if (value)
+    gconf_value_free (value);
+}
+
+static void 
+database_handle_lookup_default (DBusConnection *conn,
+				DBusMessage    *message,
+				GConfDatabase  *db)
+{
+  GConfValue *value;
+  DBusMessage *reply;
+  gchar *key;
+  gchar *locale;
+  GConfLocaleList *locales;
+  GError *gerror = NULL;
+  DBusMessageIter iter;
+  
+  if (!gconfd_dbus_get_message_args (conn, message,
+				     DBUS_TYPE_STRING, &key,
+				     DBUS_TYPE_STRING, &locale,
+				     DBUS_TYPE_INVALID))
+    return;
+
+  locales = gconfd_locale_cache_lookup (locale);
+
+  value = gconf_database_query_default_value (db, key, locales->list,
+					      NULL,
+					      &gerror);
+
+  if (gconfd_dbus_set_exception (conn, message, &gerror))
+    goto fail;
+  
+  reply = dbus_message_new_method_return (message);
+
+  dbus_message_iter_init_append (reply, &iter);
+
+  if (value)
+    gconf_dbus_utils_append_value (&iter, value);
+  
+  dbus_connection_send (conn, reply, NULL);
+  dbus_message_unref (reply);
+
+ fail:
+  if (value)
+    gconf_value_free (value);
+}
+
+static void
+database_handle_set (DBusConnection *conn,
+                     DBusMessage    *message,
+                     GConfDatabase  *db)
+{
+  gchar *key;
+  GConfValue *value = NULL; 
+  GError *gerror = NULL;
+  DBusMessage *reply;
+  DBusMessageIter iter;
+
+  dbus_message_iter_init (message, &iter);
+  dbus_message_iter_get_basic (&iter, &key);
+
+  dbus_message_iter_next (&iter);
+  value = gconf_dbus_utils_get_value (&iter);
+
+  gconf_database_set (db, key, value, &gerror);
+  gconf_value_free (value);
+
+  if (gconfd_dbus_set_exception (conn, message, &gerror))
+    return;
+
+  reply = dbus_message_new_method_return (message);
+  dbus_connection_send (conn, reply, NULL);
+  dbus_message_unref (reply);
+}
+
+static void
+database_handle_unset (DBusConnection *conn,
+		       DBusMessage    *message,
+		       GConfDatabase  *db)
+{
+  gchar *key;
+  gchar *locale;
+  GError *gerror = NULL;
+  DBusMessage *reply;
+
+  if (!gconfd_dbus_get_message_args (conn, message,
+				     DBUS_TYPE_STRING, &key,
+				     DBUS_TYPE_STRING, &locale,
+				     DBUS_TYPE_INVALID))
+    return;
+
+  if (locale[0] == '\0')
+    {
+      locale = NULL;
+    }
+  
+  gconf_database_unset (db, key, locale, &gerror);
+  
+  gconf_database_sync (db, NULL);
+  
+  if (gconfd_dbus_set_exception (conn, message, &gerror))
+    return;
+ 
+  reply = dbus_message_new_method_return (message);
+  dbus_connection_send (conn, reply, NULL);
+  dbus_message_unref (reply);
+
+}
+                                                                               
+static void
+database_handle_recursive_unset  (DBusConnection *conn,
+                                  DBusMessage    *message,
+                                  GConfDatabase  *db)
+{
+  gchar       *key;
+  gchar       *locale;
+  GError      *gerror = NULL;
+  guint32      unset_flags;
+  DBusMessage *reply;
+  
+  if (!gconfd_dbus_get_message_args (conn, message, 
+				     DBUS_TYPE_STRING, &key,
+				     DBUS_TYPE_STRING, &locale,
+				     DBUS_TYPE_UINT32, &unset_flags,
+				     DBUS_TYPE_INVALID))
+    return;
+
+  if (locale[0] == '\0')
+    {
+      locale = NULL;
+    }
+  
+  gconf_database_recursive_unset (db, key, locale, unset_flags, &gerror);
+  
+  gconf_database_sync (db, NULL);
+  
+  if (gconfd_dbus_set_exception (conn, message, &gerror))
+    return;
+
+  reply = dbus_message_new_method_return (message);
+  dbus_connection_send (conn, reply, NULL);
+  dbus_message_unref (reply);
+}
+                                                                                
+static void
+database_handle_dir_exists (DBusConnection *conn,
+                            DBusMessage    *message,
+                            GConfDatabase  *db)
+{
+  gboolean     exists;
+  gchar       *dir;
+  GError      *gerror = NULL;
+  DBusMessage *reply;
+ 
+  if (!gconfd_dbus_get_message_args (conn, message, 
+				     DBUS_TYPE_STRING, &dir,
+				     DBUS_TYPE_INVALID))
+    return;
+
+  exists = gconf_database_dir_exists (db, dir, &gerror);
+
+  if (gconfd_dbus_set_exception (conn, message, &gerror))
+    return;
+
+  reply = dbus_message_new_method_return (message);
+  dbus_message_append_args (reply,
+			    DBUS_TYPE_BOOLEAN, &exists,
+			    DBUS_TYPE_INVALID);
+  dbus_connection_send (conn, reply, NULL);
+  dbus_message_unref (reply);
+}
+                                                                                
+static void
+database_handle_get_all_entries (DBusConnection *conn,
+                                 DBusMessage    *message,
+                                 GConfDatabase  *db)
+{
+  GSList *entries, *l;
+  gchar  *dir;
+  gchar  *locale;
+  GError *gerror = NULL;
+  GConfLocaleList* locales;
+  DBusMessage *reply;
+  DBusMessageIter iter;
+
+  if (!gconfd_dbus_get_message_args (conn, message, 
+				     DBUS_TYPE_STRING, &dir,
+				     DBUS_TYPE_STRING, &locale,
+				     DBUS_TYPE_INVALID)) 
+    return;
+
+  locales = gconfd_locale_cache_lookup (locale);
+
+  entries = gconf_database_all_entries (db, dir, 
+					locales->list, &gerror);
+
+  if (gconfd_dbus_set_exception (conn, message, &gerror))
+    return;
+
+  reply = dbus_message_new_method_return (message);
+
+  dbus_message_iter_init_append (reply, &iter);
+
+  gconf_dbus_utils_append_entries (&iter, entries);
+
+  for (l = entries; l; l = l->next)
+    {
+      GConfEntry *entry = l->data;
+      
+      gconf_entry_free (entry);
+    }
+  
+  dbus_connection_send (conn, reply, NULL);
+  dbus_message_unref (reply);
+
+  g_slist_free (entries);
+}
+                                                                                
+static void
+database_handle_get_all_dirs (DBusConnection *conn,
+                              DBusMessage    *message,
+                              GConfDatabase  *db)
+{
+  GSList          *dirs, *l;
+  gchar           *dir;
+  GError          *gerror = NULL;
+  DBusMessage     *reply;
+  DBusMessageIter  iter;
+  DBusMessageIter  array_iter;
+
+  if (!gconfd_dbus_get_message_args (conn, message,
+				     DBUS_TYPE_STRING, &dir,
+				     DBUS_TYPE_INVALID)) 
+    return;
+
+  dirs = gconf_database_all_dirs (db, dir, &gerror);
+
+  if (gconfd_dbus_set_exception (conn, message, &gerror))
+    return;
+  
+  reply = dbus_message_new_method_return (message);
+
+  dbus_message_iter_init_append (reply, &iter);
+
+  dbus_message_iter_open_container (&iter,
+				    DBUS_TYPE_ARRAY,
+				    DBUS_TYPE_STRING_AS_STRING,
+				    &array_iter);
+  
+  for (l = dirs; l; l = l->next) 
+    {
+      gchar *str = (gchar *) l->data;
+
+      dbus_message_iter_append_basic (&array_iter,
+				      DBUS_TYPE_STRING,
+				      &str);
+      
+      g_free (l->data);
+    }
+
+  dbus_message_iter_close_container (&iter, &array_iter);
+ 
+  g_slist_free (dirs);
+  
+  dbus_connection_send (conn, reply, NULL);
+  dbus_message_unref (reply);
+}
+                                                                                
+static void
+database_handle_set_schema (DBusConnection *conn,
+                            DBusMessage    *message,
+                            GConfDatabase  *db)
+{
+  gchar       *key;
+  gchar       *schema_key;
+  GError      *gerror = NULL;
+  DBusMessage *reply;
+
+  if (!gconfd_dbus_get_message_args (conn, message,
+				     DBUS_TYPE_STRING, &key,
+				     DBUS_TYPE_STRING, &schema_key,
+				     DBUS_TYPE_INVALID)) 
+    return;
+
+  /* Empty schema key name means unset. */ 
+  if (schema_key[0] == '\0')
+    schema_key = NULL;
+  
+  gconf_database_set_schema (db, key, schema_key, &gerror);
+
+  if (gconfd_dbus_set_exception (conn, message, &gerror))
+    return;
+
+  reply = dbus_message_new_method_return (message);
+  dbus_connection_send (conn, reply, NULL);
+  dbus_message_unref (reply);
+}
+
+static void
+database_handle_suggest_sync (DBusConnection *conn,
+		              DBusMessage    *message,
+		              GConfDatabase  *db)
+{
+  GError *gerror = NULL;
+  DBusMessage *reply;
+  
+  gconf_database_sync (db, &gerror);
+  
+  if (gconfd_dbus_set_exception (conn, message, &gerror))
+    return;
+
+  reply = dbus_message_new_method_return (message);
+  dbus_connection_send (conn, reply, NULL);
+  dbus_message_unref (reply);
+}
+
+static void
+database_handle_add_notify (DBusConnection    *conn,
+                            DBusMessage       *message,
+                            GConfDatabase *db)
+{
+  gchar *namespace_section;
+  DBusMessage *reply;
+  const char *sender;
+  NotificationData *notification;
+  ListeningClientData *client;
+
+  if (!gconfd_dbus_get_message_args (conn, message,
+				     DBUS_TYPE_STRING, &namespace_section,
+				     DBUS_TYPE_INVALID)) 
+    return;
+
+  sender = dbus_message_get_sender (message);
+  
+  client = g_hash_table_lookup (db->listening_clients, sender);
+  if (!client)
+    {
+      client = database_add_listening_client (db, sender);
+    }
+  else
+    {
+      client->nr_of_notifications++;
+    }
+  
+  notification = g_hash_table_lookup (db->notifications, namespace_section);
+  
+  if (notification == NULL)
+    {
+      notification = g_new0 (NotificationData, 1);
+      notification->namespace_section = g_strdup (namespace_section);
+
+      g_hash_table_insert (db->notifications,
+			   notification->namespace_section, notification);
+    }
+  
+  notification->clients = g_list_prepend (notification->clients,
+					  g_strdup (sender));
+  
+  reply = dbus_message_new_method_return (message);
+  dbus_connection_send (conn, reply, NULL);
+  dbus_message_unref (reply);
+}
+
+static gboolean
+database_remove_notification_data (GConfDatabase *db,
+				   NotificationData *notification,
+				   const char *client)
+{
+  GList *element;
+  
+  element = g_list_find_custom (notification->clients, client,
+			     (GCompareFunc)strcmp);
+  if (element == NULL)
+    return FALSE;
+  
+  notification->clients = g_list_remove_link (notification->clients, element);
+  if (notification->clients == NULL)
+    {
+      g_hash_table_remove (db->notifications,
+			   notification->namespace_section);
+
+      g_free (notification->namespace_section);
+      g_free (notification);
+    }
+  
+  g_free (element->data);
+  g_list_free_1 (element);
+
+  return TRUE;
+}
+
+static void
+database_handle_remove_notify (DBusConnection    *conn,
+			       DBusMessage       *message,
+			       GConfDatabase *db)
+{
+  gchar *namespace_section;
+  DBusMessage *reply;
+  const char *sender;
+  NotificationData *notification;
+  ListeningClientData *client;
+  
+  if (!gconfd_dbus_get_message_args (conn, message,
+				     DBUS_TYPE_STRING, &namespace_section,
+				     DBUS_TYPE_INVALID)) 
+    return;
+
+  sender = dbus_message_get_sender (message);
+  
+  notification = g_hash_table_lookup (db->notifications, namespace_section);
+
+  client = g_hash_table_lookup (db->listening_clients, sender);
+  if (client) {
+    client->nr_of_notifications--;
+    
+    if (client->nr_of_notifications == 0) {
+      database_remove_listening_client (db, client);
+    }
+  }
+    
+  /* Notification can be NULL if the client and server get out of sync. */
+  if (notification == NULL || !database_remove_notification_data (db, notification, sender))
+    {
+      gconf_log (GCL_DEBUG, _("Notification on %s doesn't exist"),
+                 namespace_section);
+    }
+  
+  reply = dbus_message_new_method_return (message);
+  dbus_connection_send (conn, reply, NULL);
+  dbus_message_unref (reply);
+}
+
+static gchar *
+get_rule_for_service (const gchar *service)
+{
+  gchar *rule;
+  
+  rule = g_strdup_printf ("type='signal',member='NameOwnerChanged',arg0='%s'", service);
+
+  return rule;
+}
+
+static ListeningClientData *
+database_add_listening_client (GConfDatabase *db, 
+			       const gchar   *service)
+{
+  ListeningClientData *client;
+  gchar               *rule;
+
+  client = g_new0 (ListeningClientData, 1);
+  client->service = g_strdup (service);
+  client->nr_of_notifications = 1;
+
+  g_hash_table_insert (db->listening_clients, client->service, client);
+  
+  rule = get_rule_for_service (service);
+  dbus_bus_add_match (gconfd_dbus_get_connection (), rule, NULL);
+  g_free (rule);
+
+  return client;
+}
+
+static void
+database_remove_listening_client (GConfDatabase       *db,
+				  ListeningClientData *client)
+{
+  gchar *rule;
+
+  rule = get_rule_for_service (client->service);
+  dbus_bus_remove_match (gconfd_dbus_get_connection (), rule, NULL);
+  g_free (rule);
+
+  g_hash_table_remove (db->listening_clients, client->service);
+  g_free (client->service);
+  g_free (client);
+}
+
+void
+gconf_database_dbus_setup (GConfDatabase *db)
+{
+  DBusConnection *conn;
+  
+  g_assert (db->object_path == NULL);
+  
+  db->object_path = g_strdup_printf ("%s/%d", 
+				     DATABASE_OBJECT_PATH, 
+				     object_nr++);
+
+  conn = gconfd_dbus_get_connection ();
+  
+  dbus_connection_register_object_path (conn,
+					db->object_path,
+					&database_vtable,
+					db);
+
+  db->notifications = g_hash_table_new (g_str_hash, g_str_equal);
+  db->listening_clients = g_hash_table_new (g_str_hash, g_str_equal);
+ 
+  dbus_connection_add_filter (conn,
+			      (DBusHandleMessageFunction)database_filter_func,
+			      db,
+			      NULL);
+}
+
+void
+gconf_database_dbus_teardown (GConfDatabase *db)
+{
+  DBusConnection *conn;
+
+  conn = gconfd_dbus_get_connection ();
+
+  dbus_connection_unregister_object_path (conn, db->object_path);
+  
+  dbus_connection_remove_filter (conn,
+				 (DBusHandleMessageFunction)database_filter_func,
+				 db);
+  g_free (db->object_path);
+  db->object_path = NULL;
+}
+
+const char *
+gconf_database_dbus_get_path (GConfDatabase *db)
+{
+  return db->object_path;
+}
+
+void
+gconf_database_dbus_notify_listeners (GConfDatabase    *db,
+				      GConfSources     *modified_sources,
+				      const gchar      *key,
+				      const GConfValue *value,
+				      gboolean          is_default,
+				      gboolean          is_writable,
+				      gboolean          notify_others)
+{
+  char             *dir, *sep;
+  GList            *l;
+  NotificationData *notification;
+  DBusMessage      *message;
+  gboolean          last;
+  
+  dir = g_strdup (key);
+
+  /* Lookup the key in the namespace hierarchy, start with the full key and then
+   * remove the leaf, lookup again, remove the leaf, and so on until a match is
+   * found. Notify the clients (identified by their base service) that
+   * correspond to the found namespace.
+   */
+  last = FALSE;
+  while (1)
+    {
+      notification = g_hash_table_lookup (db->notifications, dir);
+
+      if (notification)
+	{
+	  for (l = notification->clients; l; l = l->next)
+	    {
+	      const char *base_service = l->data;
+	      DBusMessageIter iter;
+	      
+	      message = dbus_message_new_method_call (base_service,
+						      GCONF_DBUS_CLIENT_OBJECT,
+						      GCONF_DBUS_CLIENT_INTERFACE,
+						      "Notify");
+
+	      dbus_message_append_args (message,
+					DBUS_TYPE_STRING, &db->object_path,
+					DBUS_TYPE_STRING, &dir,
+					DBUS_TYPE_INVALID);
+
+	      dbus_message_iter_init_append (message, &iter);
+	      
+	      gconf_dbus_utils_append_entry_values (&iter,
+						    key,
+						    value,
+						    is_default,
+						    is_writable,
+						    NULL);
+	      
+	      dbus_message_set_no_reply (message, TRUE);
+	      
+	      dbus_connection_send (gconfd_dbus_get_connection (), message, NULL);
+	      dbus_message_unref (message);
+	    }
+	}
+
+      if (last)
+	break;
+      
+      sep = strrchr (dir, '/');
+
+      /* Special case to catch notifications on the root. */
+      if (sep == dir)
+	{
+	  last = TRUE;
+	  sep[1] = '\0';
+	}
+      else
+	*sep = '\0';
+    }
+
+    
+  g_free (dir);
+
+  if (modified_sources)
+    {
+      if (notify_others)
+        gconfd_notify_other_listeners (db, modified_sources, key);
+
+      g_list_free (modified_sources->sources);
+      g_free (modified_sources);
+    }
+}
diff --git a/gconf/gconf-database-dbus.h b/gconf/gconf-database-dbus.h
new file mode 100644
index 0000000..8794b1f
--- /dev/null
+++ b/gconf/gconf-database-dbus.h
@@ -0,0 +1,37 @@
+/* GConf
+ * Copyright (C) 2003 Imendio HB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GCONF_GCONF_DATABASE_DBUS_H
+#define GCONF_GCONF_DATABASE_DBUS_H
+
+#include <dbus/dbus.h>
+#include "gconf-database.h"
+
+void         gconf_database_dbus_setup            (GConfDatabase    *db);
+void         gconf_database_dbus_teardown         (GConfDatabase *db);
+const gchar *gconf_database_dbus_get_path         (GConfDatabase    *db);
+void         gconf_database_dbus_notify_listeners (GConfDatabase    *db,
+						   GConfSources     *modified_sources,
+						   const gchar      *key,
+						   const GConfValue *value,
+						   gboolean          is_default,
+						   gboolean          is_writable,
+						   gboolean          notify_others);
+
+#endif
diff --git a/gconf/gconf-dbus-utils.c b/gconf/gconf-dbus-utils.c
new file mode 100644
index 0000000..6fd5bfa
--- /dev/null
+++ b/gconf/gconf-dbus-utils.c
@@ -0,0 +1,1133 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+
+#include <config.h>
+#include <string.h>
+#include <dbus/dbus.h>
+
+#include "gconf/gconf.h"
+#include "gconf-internals.h"
+#include "gconf-dbus-utils.h"
+
+#define d(x)
+
+/* Entry:
+ *
+ * struct {
+ *   string  key;
+ *   struct  value;
+ *
+ *   boolean schema_name_set;
+ *   string  schema_name;
+ *
+ *   boolean is_default;
+ *   boolean is_writable;
+ * };
+ *
+ */
+
+/* Pair:
+ *
+ * struct {
+ *   int32 car_type;
+ *   <fundamental> car_value;
+
+ *   int32 cdr_type;
+ *   <fundamental> cdr_value;
+ * };
+ *
+ */
+
+/* List:
+ *
+ * struct {
+ *   int32 list_type;
+ *   array<fundamental> values;
+ * };
+ *
+ */
+
+/* Value:
+ *
+ * struct {
+ *   int32 type;
+ *   <int, string, float, bool, list, pair, schema> value;
+ * };
+ *
+ */
+
+/* Schema:
+ *
+ * struct {
+ *   int32  type;
+ *   int32  list_type;
+ *   int32  car_type;
+ *   int32  cdr_type;
+
+ *   boolean locale_set;
+ *   string  locale;
+
+ *   boolean short_desc_set;
+ *   string  short_desc;
+
+ *   boolean long_desc_set;
+ *   string  long_desc;
+
+ *   boolean owner_set;
+ *   string  owner;
+
+ *   boolean gettext_domain_set;
+ *   string  gettext_domain;
+
+ *   string  default_value;
+ * };
+ *
+ */
+
+static void         utils_append_value_helper_fundamental (DBusMessageIter   *iter,
+							   const GConfValue  *value);
+static void         utils_append_value_helper_pair        (DBusMessageIter   *main_iter,
+							   const GConfValue  *value);
+static void         utils_append_value_helper_list        (DBusMessageIter   *main_iter,
+							   const GConfValue  *value);
+static void         utils_append_schema                   (DBusMessageIter   *main_iter,
+							   const GConfSchema *schema);
+static void         utils_append_value                    (DBusMessageIter   *main_iter,
+							   const GConfValue  *value);
+
+static GConfValue * utils_get_value_helper_fundamental    (DBusMessageIter   *iter,
+							   GConfValueType     value_type);
+static GConfValue * utils_get_value_helper_pair           (DBusMessageIter   *iter);
+static GConfValue * utils_get_value_helper_list           (DBusMessageIter   *iter);
+static GConfValue * utils_get_value                       (DBusMessageIter   *main_iter);
+static GConfSchema *utils_get_schema                      (DBusMessageIter   *main_iter);
+static GConfValue * utils_get_schema_value                (DBusMessageIter   *iter);
+
+
+/*
+ * Utilities
+ */
+
+/* A boolean followed by a string. */
+static void
+utils_append_optional_string (DBusMessageIter *iter,
+			      const gchar     *str)
+{
+  gboolean is_set;
+  
+  if (str)
+    is_set = TRUE;
+  else
+    {
+      is_set = FALSE;
+      str = "";
+    }
+
+  dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &is_set);
+  dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &str);
+}
+
+/* A boolean followed by a string. */
+static const gchar *
+utils_get_optional_string (DBusMessageIter *iter)
+{
+  gboolean     is_set;
+  const gchar *str;
+  
+  dbus_message_iter_get_basic (iter, &is_set);
+  dbus_message_iter_next (iter);
+  dbus_message_iter_get_basic (iter, &str);
+
+  if (is_set)
+    return str;
+  else
+    return NULL;
+}
+
+
+/*
+ * Setters
+ */
+
+
+/* Helper for utils_append_value, writes a int/string/float/bool/schema.
+ */
+static void
+utils_append_value_helper_fundamental (DBusMessageIter  *iter,
+				       const GConfValue *value)
+{
+  gint32       i;
+  gboolean     b;
+  const gchar *s;
+  gdouble      d;
+
+  d(g_print ("Append value (fundamental)\n"));
+  
+  switch (value->type)
+    {
+    case GCONF_VALUE_INT:
+      i = gconf_value_get_int (value);
+      dbus_message_iter_append_basic (iter, DBUS_TYPE_INT32, &i);
+      break;
+
+    case GCONF_VALUE_STRING:
+      s = gconf_value_get_string (value);
+      dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &s);
+      break;
+
+    case GCONF_VALUE_FLOAT:
+      d = gconf_value_get_float (value);
+      dbus_message_iter_append_basic (iter, DBUS_TYPE_DOUBLE, &d);
+      break;
+
+    case GCONF_VALUE_BOOL:
+      b = gconf_value_get_bool (value);
+      dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &b);
+      break;
+
+    case GCONF_VALUE_SCHEMA:
+      utils_append_schema (iter, gconf_value_get_schema (value));
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+/* Helper for utils_append_value, writes a pair. The pair is a struct with the
+ * two values and two fundamental values (type, value, type value).
+ */
+static void
+utils_append_value_helper_pair (DBusMessageIter  *main_iter,
+				const GConfValue *value)
+{
+  DBusMessageIter  struct_iter;
+  GConfValue      *car, *cdr;
+  gint32           type;
+
+  d(g_print ("Append value (pair)\n"));
+
+  g_assert (value->type == GCONF_VALUE_PAIR);
+    
+  dbus_message_iter_open_container (main_iter,
+				    DBUS_TYPE_STRUCT,
+				    NULL, /* for struct */
+				    &struct_iter);
+
+  car = gconf_value_get_car (value);
+  cdr = gconf_value_get_cdr (value);
+  
+  /* The pair types. */
+  if (car)
+    type = car->type;
+  else
+    type = GCONF_VALUE_INVALID;
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_INT32, &type);
+  
+  if (cdr)
+    type = cdr->type;
+  else
+    type = GCONF_VALUE_INVALID;
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_INT32, &type);
+
+  /* The values. */
+  if (car)
+    utils_append_value_helper_fundamental (&struct_iter, car);
+
+  if (cdr)
+    utils_append_value_helper_fundamental (&struct_iter, cdr);
+
+  dbus_message_iter_close_container (main_iter, &struct_iter);
+}
+
+/* Helper for utils_append_value, writes a list. The "list" is a struct with the
+ * list type and an array with the values directly in it.
+ */
+static void
+utils_append_value_helper_list (DBusMessageIter  *main_iter,
+				const GConfValue *value)
+{
+  DBusMessageIter  struct_iter;
+  DBusMessageIter  array_iter;
+  GConfValueType   list_type;
+  const gchar     *array_type;
+  GSList          *list;
+  
+  d(g_print ("Append value (list)\n"));
+
+  g_assert (value->type == GCONF_VALUE_LIST);
+  
+  dbus_message_iter_open_container (main_iter,
+				    DBUS_TYPE_STRUCT,
+				    NULL, /* for struct */
+				    &struct_iter);
+  
+  /* Write the list type. */
+  list_type = gconf_value_get_list_type (value);
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_INT32, &list_type);
+
+  /* And the value. */
+  switch (list_type)
+    {
+    case GCONF_VALUE_INT:
+      array_type = DBUS_TYPE_INT32_AS_STRING;
+      break;
+      
+    case GCONF_VALUE_STRING:
+      array_type = DBUS_TYPE_STRING_AS_STRING;
+      break;
+      
+    case GCONF_VALUE_FLOAT:
+      array_type = DBUS_TYPE_DOUBLE_AS_STRING;
+      break;
+      
+    case GCONF_VALUE_BOOL:
+      array_type = DBUS_TYPE_BOOLEAN_AS_STRING;
+      break;
+      
+    case GCONF_VALUE_SCHEMA:
+      array_type = DBUS_TYPE_STRUCT_AS_STRING;
+      break;
+
+    default:
+      array_type = NULL;
+      g_assert_not_reached ();
+    }
+  
+  dbus_message_iter_open_container (&struct_iter,
+				    DBUS_TYPE_ARRAY,
+				    array_type,
+				    &array_iter);
+  
+  list = gconf_value_get_list (value);
+  
+  switch (list_type)
+    {
+    case GCONF_VALUE_STRING:
+      while (list)
+	{
+	  const gchar *s;
+
+	  s = gconf_value_get_string (list->data);
+	  dbus_message_iter_append_basic (&array_iter,
+					  DBUS_TYPE_STRING,
+					  &s);
+	  
+	  list = list->next;
+	}
+      break;
+
+    case GCONF_VALUE_INT:
+      while (list)
+	{
+	  gint32 i;
+
+	  i = gconf_value_get_int (list->data);
+	  dbus_message_iter_append_basic (&array_iter,
+					  DBUS_TYPE_INT32,
+					  &i);
+	  
+	  list = list->next;
+	}
+      break;
+      
+    case GCONF_VALUE_FLOAT:
+      while (list)
+	{
+	  gdouble d;
+
+	  d = gconf_value_get_float (list->data);
+	  dbus_message_iter_append_basic (&array_iter,
+					  DBUS_TYPE_DOUBLE,
+					  &d);
+
+	  list = list->next;
+	}
+      break;
+
+    case GCONF_VALUE_BOOL:
+      while (list)
+	{
+	  gboolean b;
+
+	  b = gconf_value_get_bool (list->data);
+	  dbus_message_iter_append_basic (&array_iter,
+					  DBUS_TYPE_BOOLEAN,
+					  &b);
+	  
+	  list = list->next;
+	}
+      break;
+      
+    case GCONF_VALUE_SCHEMA:
+      while (list)
+	{
+	  GConfSchema *schema;
+
+	  schema = gconf_value_get_schema (list->data);
+	  utils_append_schema (&array_iter, schema);
+	  
+	  list = list->next;
+	}
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+  
+  dbus_message_iter_close_container (&struct_iter, &array_iter);
+  dbus_message_iter_close_container (main_iter, &struct_iter);
+}
+
+/* Writes a schema, which is a struct. */
+static void
+utils_append_schema (DBusMessageIter   *main_iter,
+		     const GConfSchema *schema)
+{
+  DBusMessageIter  struct_iter;
+  gint32           i;
+  const gchar     *s;
+  GConfValue      *default_value;
+
+  dbus_message_iter_open_container (main_iter,
+				    DBUS_TYPE_STRUCT,
+				    NULL, /* for structs */
+				    &struct_iter);
+  
+  i = gconf_schema_get_type (schema);
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_INT32, &i);
+
+  i = gconf_schema_get_list_type (schema);
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_INT32, &i);
+
+  i = gconf_schema_get_car_type (schema);
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_INT32, &i);
+  
+  i = gconf_schema_get_cdr_type (schema);
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_INT32, &i);
+
+  s = gconf_schema_get_locale (schema);
+  utils_append_optional_string (&struct_iter, s);
+  
+  s = gconf_schema_get_short_desc (schema);
+  utils_append_optional_string (&struct_iter, s);
+
+  s = gconf_schema_get_long_desc (schema);
+  utils_append_optional_string (&struct_iter, s);
+
+  s = gconf_schema_get_owner (schema);
+  utils_append_optional_string (&struct_iter, s);
+
+  default_value = gconf_schema_get_default_value (schema);
+
+  /* We don't need to do this, but it's much simpler */
+  if (default_value)
+    {
+      gchar *encoded;
+      
+      encoded = gconf_value_encode (default_value);
+      g_assert (encoded != NULL);
+
+      dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &encoded);
+      g_free (encoded);
+    }
+  else
+    {
+      s = "";
+      dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &s);
+    }
+  
+  if (!dbus_message_iter_close_container (main_iter, &struct_iter))
+    g_error ("Out of memory");
+}
+
+static void
+utils_append_value (DBusMessageIter  *main_iter,
+		    const GConfValue *value)
+{
+  DBusMessageIter struct_iter;
+  gint32          type;
+
+  /* A value is stored as a struct with the type and the actual value. */
+  dbus_message_iter_open_container (main_iter,
+				    DBUS_TYPE_STRUCT,
+				    NULL, /* for structs */
+				    &struct_iter);
+
+  if (!value)
+    type = GCONF_VALUE_INVALID;
+  else
+    type = value->type;
+
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_INT32, &type);
+  
+  switch (type)
+    {
+    case GCONF_VALUE_INT:
+    case GCONF_VALUE_STRING:
+    case GCONF_VALUE_FLOAT:
+    case GCONF_VALUE_BOOL:
+    case GCONF_VALUE_SCHEMA:
+      utils_append_value_helper_fundamental (&struct_iter, value);
+      break;
+      
+    case GCONF_VALUE_LIST:
+      utils_append_value_helper_list (&struct_iter, value);
+      break;
+
+    case GCONF_VALUE_PAIR:
+      utils_append_value_helper_pair (&struct_iter, value);
+      break;
+
+    case GCONF_VALUE_INVALID:
+      break;
+      
+    default:
+      g_assert_not_reached ();
+    }
+
+  dbus_message_iter_close_container (main_iter, &struct_iter);
+}
+
+/* Writes an entry, which is a struct. */
+static void
+utils_append_entry_values (DBusMessageIter  *main_iter,
+			   const gchar      *key,
+			   const GConfValue *value,
+			   gboolean          is_default,
+			   gboolean          is_writable,
+			   const gchar      *schema_name)   
+{
+  DBusMessageIter struct_iter;
+
+  d(g_print ("Appending entry %s\n", key));
+  
+  dbus_message_iter_open_container (main_iter,
+				    DBUS_TYPE_STRUCT,
+				    NULL, /* for structs */
+				    &struct_iter);
+
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &key);
+
+  utils_append_value (&struct_iter, value);
+
+  utils_append_optional_string (&struct_iter, schema_name);
+
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_BOOLEAN, &is_default);
+
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_BOOLEAN, &is_writable);
+  
+  dbus_message_iter_close_container (main_iter, &struct_iter);
+}
+
+/* Writes an entry, which is a struct. */
+static void
+utils_append_entry_values_stringified (DBusMessageIter  *main_iter,
+				       const gchar      *key,
+				       const GConfValue *value,
+				       gboolean          is_default,
+				       gboolean          is_writable,
+				       const gchar      *schema_name)   
+{
+  DBusMessageIter  struct_iter;
+  gchar           *value_str;
+
+  d(g_print ("Appending entry %s\n", key));
+  
+  dbus_message_iter_open_container (main_iter,
+				    DBUS_TYPE_STRUCT,
+				    NULL, /* for structs */
+				    &struct_iter);
+
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &key);
+
+  value_str = NULL;
+  if (value)
+    value_str = gconf_value_encode ((GConfValue *) value);
+
+  if (!value_str)
+    value_str = g_strdup ("");
+
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_STRING, &value_str);
+  g_free (value_str);
+
+  utils_append_optional_string (&struct_iter, schema_name);
+
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_BOOLEAN, &is_default);
+
+  dbus_message_iter_append_basic (&struct_iter, DBUS_TYPE_BOOLEAN, &is_writable);
+  
+  if (!dbus_message_iter_close_container (main_iter, &struct_iter))
+    g_error ("Out of memory");
+}
+
+gboolean
+gconf_dbus_utils_get_entry_values (DBusMessageIter  *main_iter,
+				   gchar           **key_p,
+				   GConfValue      **value_p,
+				   gboolean         *is_default_p,
+				   gboolean         *is_writable_p,
+				   gchar           **schema_name_p)
+{
+  DBusMessageIter  struct_iter;
+  gchar           *key;
+  GConfValue      *value;
+  gboolean         is_default;
+  gboolean         is_writable;
+  gchar           *schema_name;
+
+  g_return_val_if_fail (dbus_message_iter_get_arg_type (main_iter) == DBUS_TYPE_STRUCT,
+			FALSE);
+
+  dbus_message_iter_recurse (main_iter, &struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &key);
+
+  d(g_print ("Getting entry %s\n", key));
+    
+  dbus_message_iter_next (&struct_iter);
+  value = utils_get_value (&struct_iter);
+
+  dbus_message_iter_next (&struct_iter);
+  schema_name = (gchar *) utils_get_optional_string (&struct_iter);
+
+  dbus_message_iter_next (&struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &is_default);
+
+  dbus_message_iter_next (&struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &is_writable);
+
+  if (key_p)
+    *key_p = key;
+
+  if (value_p)
+    *value_p = value;
+  else if (value)
+    gconf_value_free (value);
+
+  if (schema_name_p)
+    *schema_name_p = schema_name;
+  
+  if (is_default_p)
+    *is_default_p = is_default;
+
+  if (is_writable_p)
+    *is_writable_p = is_writable;
+
+  return TRUE;
+}
+
+static gboolean
+utils_get_entry_values_stringified (DBusMessageIter  *main_iter,
+				    gchar           **key_p,
+				    GConfValue      **value_p,
+				    gboolean         *is_default_p,
+				    gboolean         *is_writable_p,
+				    gchar           **schema_name_p)
+{
+  DBusMessageIter  struct_iter;
+  gchar           *key;
+  gchar           *value_str;
+  GConfValue      *value;
+  gboolean         is_default;
+  gboolean         is_writable;
+  gchar           *schema_name;
+
+  dbus_message_iter_recurse (main_iter, &struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &key);
+
+  d(g_print ("Getting entry %s\n", key));
+    
+  dbus_message_iter_next (&struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &value_str);
+  if (value_str[0] != '\0')
+    value = gconf_value_decode (value_str);
+  else
+    value = NULL;
+
+  dbus_message_iter_next (&struct_iter);
+  schema_name = (gchar *) utils_get_optional_string (&struct_iter);
+
+  dbus_message_iter_next (&struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &is_default);
+
+  dbus_message_iter_next (&struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &is_writable);
+
+  if (key_p)
+    *key_p = key;
+
+  if (value_p)
+    *value_p = value;
+  else
+    gconf_value_free (value);
+
+  if (schema_name_p)
+    *schema_name_p = schema_name;
+  
+  if (is_default_p)
+    *is_default_p = is_default;
+
+  if (is_writable_p)
+    *is_writable_p = is_writable;
+
+  return TRUE;
+}
+
+
+/*
+ * Getters
+ */
+
+/* Helper for utils_get_value, reads int/string/float/bool/schema. */
+static GConfValue *
+utils_get_value_helper_fundamental (DBusMessageIter *iter,
+				    GConfValueType   value_type)
+{
+  GConfValue  *value;
+  GConfSchema *schema;
+  gint32       i;
+  const gchar *s;
+  gdouble      d;
+  gboolean     b;
+
+  d(g_print ("Get value (fundamental)\n"));
+
+  if (value_type == GCONF_VALUE_INVALID)
+    return NULL;
+    
+  value = gconf_value_new (value_type);
+  
+  switch (value_type)
+    {
+    case GCONF_VALUE_INT:
+      dbus_message_iter_get_basic (iter, &i);
+      gconf_value_set_int (value, i);
+      break;
+
+    case GCONF_VALUE_STRING:
+      dbus_message_iter_get_basic (iter, &s);
+      gconf_value_set_string (value, s);
+      break;
+
+    case GCONF_VALUE_FLOAT:
+      dbus_message_iter_get_basic (iter, &d);
+      gconf_value_set_float (value, d);
+      break;
+
+    case GCONF_VALUE_BOOL:
+      dbus_message_iter_get_basic (iter, &b);
+      gconf_value_set_bool (value, b);
+      break;
+
+    case GCONF_VALUE_SCHEMA:
+      schema = utils_get_schema (iter);
+      gconf_value_set_schema_nocopy (value, schema);
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+
+  return value;
+}
+
+/* Helper for utils_get_value, reads a pair. The pair is a struct with the two
+ * values and two fundamental values (type, value, type, value).
+ */
+static GConfValue *
+utils_get_value_helper_pair (DBusMessageIter *iter)
+{
+  GConfValue      *value;
+  DBusMessageIter  struct_iter;
+  gint32           car_type, cdr_type;
+  GConfValue      *car_value = NULL, *cdr_value = NULL;
+
+  d(g_print ("Get value (pair)\n"));
+
+  value = gconf_value_new (GCONF_VALUE_PAIR);
+
+  /* Get the pair types. */
+  dbus_message_iter_recurse (iter, &struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &car_type);
+  dbus_message_iter_next (&struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &cdr_type);
+
+  /* Get the values. */
+  dbus_message_iter_next (&struct_iter);
+  if (car_type == GCONF_VALUE_SCHEMA) 
+    car_value = utils_get_schema_value (&struct_iter);
+  else if (car_type != GCONF_VALUE_INVALID)
+    car_value = utils_get_value_helper_fundamental (&struct_iter, car_type);
+
+  dbus_message_iter_next (&struct_iter);
+  if (cdr_type == GCONF_VALUE_SCHEMA) 
+    cdr_value = utils_get_schema_value (&struct_iter);
+  else if (cdr_type != GCONF_VALUE_INVALID)
+    cdr_value = utils_get_value_helper_fundamental (&struct_iter, cdr_type);
+
+  if (car_value)
+    gconf_value_set_car_nocopy (value, car_value);
+
+  if (cdr_value)
+    gconf_value_set_cdr_nocopy (value, cdr_value);
+
+  return value;
+}
+
+/* Helper for utils_get_value, reads a list. The "list" is a struct with the
+ * list type and an array with the values directly in it.
+ */
+static GConfValue *
+utils_get_value_helper_list (DBusMessageIter *iter)
+{
+  DBusMessageIter  struct_iter;
+  DBusMessageIter  array_iter;
+  GConfValue      *value;
+  gint32           list_type;
+  GSList          *list;
+  GConfValue      *child_value;
+  
+  d(g_print ("Get value (list)\n"));
+
+  value = gconf_value_new (GCONF_VALUE_LIST);
+
+  dbus_message_iter_recurse (iter, &struct_iter);
+
+  /* Get the list type. */
+  dbus_message_iter_get_basic (&struct_iter, &list_type);
+  gconf_value_set_list_type (value, list_type);
+
+  /* Get the array. */
+  dbus_message_iter_next (&struct_iter);
+  dbus_message_iter_recurse (&struct_iter, &array_iter);
+
+  /* And the values from the array. */
+  list = NULL;
+  switch (list_type)
+    {
+    case GCONF_VALUE_STRING:
+      while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_STRING)
+	{
+	  const gchar *str;
+	  
+	  dbus_message_iter_get_basic (&array_iter, &str);
+
+	  child_value = gconf_value_new (GCONF_VALUE_STRING);
+	  gconf_value_set_string (child_value, str);
+	  list = g_slist_prepend (list, child_value);
+
+	  dbus_message_iter_next (&array_iter);
+	}
+      break;
+
+    case GCONF_VALUE_INT:
+      while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_INT32)
+	{
+	  gint32 i;
+	  
+	  dbus_message_iter_get_basic (&array_iter, &i);
+
+	  child_value = gconf_value_new (GCONF_VALUE_INT);
+	  gconf_value_set_int (child_value, i);
+	  list = g_slist_prepend (list, child_value);
+
+	  dbus_message_iter_next (&array_iter);
+	}
+      break;
+
+    case GCONF_VALUE_FLOAT:
+      while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_DOUBLE)
+	{
+	  gdouble d;
+	  
+	  dbus_message_iter_get_basic (&array_iter, &d);
+
+	  child_value = gconf_value_new (GCONF_VALUE_FLOAT);
+	  gconf_value_set_float (child_value, d);
+	  list = g_slist_prepend (list, child_value);
+
+	  dbus_message_iter_next (&array_iter);
+	}
+      break;
+
+    case GCONF_VALUE_BOOL:
+      while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_BOOLEAN)
+	{
+	  gboolean b;
+	  
+	  dbus_message_iter_get_basic (&array_iter, &b);
+
+	  child_value = gconf_value_new (GCONF_VALUE_BOOL);
+	  gconf_value_set_bool (child_value, b);
+	  list = g_slist_prepend (list, child_value);
+
+	  dbus_message_iter_next (&array_iter);
+	}
+      break;
+
+    case GCONF_VALUE_SCHEMA:
+      while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_STRUCT)
+	{
+	  child_value = utils_get_schema_value (&array_iter);
+	  list = g_slist_prepend (list, child_value);
+
+	  dbus_message_iter_next (&array_iter);
+	}
+      break;
+      
+    default:
+      g_assert_not_reached ();
+    }
+
+  list = g_slist_reverse (list);
+  gconf_value_set_list_nocopy (value, list);
+  
+  return value;
+}
+
+static GConfValue *
+utils_get_value (DBusMessageIter *main_iter)
+{
+  DBusMessageIter  struct_iter;
+  gint32           type;
+  GConfValue      *value;
+  
+  g_assert (dbus_message_iter_get_arg_type (main_iter) == DBUS_TYPE_STRUCT);
+  
+  /* A value is stored as a struct with the type and a variant with the actual
+   * value.
+   */
+
+  dbus_message_iter_recurse (main_iter, &struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &type);
+
+  dbus_message_iter_next (&struct_iter);
+
+  switch (type)
+    {
+    case GCONF_VALUE_INT:
+    case GCONF_VALUE_STRING:
+    case GCONF_VALUE_BOOL:
+    case GCONF_VALUE_FLOAT:
+      value = utils_get_value_helper_fundamental (&struct_iter, type);
+      break;
+      
+    case GCONF_VALUE_PAIR:
+      value = utils_get_value_helper_pair (&struct_iter);
+      break;
+      
+    case GCONF_VALUE_LIST:
+      value = utils_get_value_helper_list (&struct_iter);
+      break;
+      
+    case GCONF_VALUE_SCHEMA:
+      value = utils_get_schema_value (&struct_iter);
+      break;
+
+    case GCONF_VALUE_INVALID:
+      value = NULL;
+      break;
+      
+    default:
+      value = NULL;
+      g_assert_not_reached ();
+    }
+  
+  return value;
+}
+
+static GConfSchema *
+utils_get_schema (DBusMessageIter *main_iter)
+{
+  DBusMessageIter  struct_iter;
+  gint32           type, list_type, car_type, cdr_type;
+  const gchar     *locale, *short_desc, *long_desc, *owner;
+  const gchar     *encoded;
+  GConfSchema     *schema;
+  GConfValue      *default_value;
+  
+  g_assert (dbus_message_iter_get_arg_type (main_iter) == DBUS_TYPE_STRUCT);
+  
+  dbus_message_iter_recurse (main_iter, &struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &type);
+  
+  dbus_message_iter_next (&struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &list_type);
+
+  dbus_message_iter_next (&struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &car_type);
+
+  dbus_message_iter_next (&struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &cdr_type);
+
+  dbus_message_iter_next (&struct_iter);
+  locale = utils_get_optional_string (&struct_iter);
+
+  dbus_message_iter_next (&struct_iter);
+  short_desc = utils_get_optional_string (&struct_iter);
+
+  dbus_message_iter_next (&struct_iter);
+  long_desc = utils_get_optional_string (&struct_iter);
+
+  dbus_message_iter_next (&struct_iter);
+  owner = utils_get_optional_string (&struct_iter);
+
+  dbus_message_iter_next (&struct_iter);
+  dbus_message_iter_get_basic (&struct_iter, &encoded);
+
+  schema = gconf_schema_new ();
+  
+  gconf_schema_set_type (schema, type);
+  gconf_schema_set_list_type (schema, list_type);
+  gconf_schema_set_car_type (schema, car_type);
+  gconf_schema_set_cdr_type (schema, cdr_type);
+
+  if (locale)
+    gconf_schema_set_locale (schema, locale);
+  
+  if (short_desc)
+    gconf_schema_set_short_desc (schema, short_desc);
+  
+  if (long_desc)
+    gconf_schema_set_long_desc (schema, long_desc);
+  
+  if (owner)
+    gconf_schema_set_owner (schema, owner);
+
+  if (*encoded != '\0')
+    {
+      default_value = gconf_value_decode (encoded);
+      if (default_value)
+	gconf_schema_set_default_value_nocopy (schema, default_value);
+    }
+
+  return schema;
+}
+
+static GConfValue *
+utils_get_schema_value (DBusMessageIter *iter)
+{
+  GConfSchema *schema;
+  GConfValue  *value;
+
+  schema = utils_get_schema (iter);
+
+  value = gconf_value_new (GCONF_VALUE_SCHEMA);
+  gconf_value_set_schema_nocopy (value, schema);
+
+  return value;
+}
+
+
+/*
+ * Public API
+ */
+
+void
+gconf_dbus_utils_append_value (DBusMessageIter  *iter,
+			       const GConfValue *value)
+{
+  utils_append_value (iter, value);
+}
+
+GConfValue *
+gconf_dbus_utils_get_value (DBusMessageIter  *iter)
+{
+  return utils_get_value (iter);
+}
+
+void
+gconf_dbus_utils_append_entry_values (DBusMessageIter  *iter,
+				      const gchar      *key,
+				      const GConfValue *value,
+				      gboolean          is_default,
+				      gboolean          is_writable,
+				      const gchar      *schema_name)
+{
+  utils_append_entry_values (iter,
+			     key,
+			     value,
+			     is_default,
+			     is_writable,
+			     schema_name);
+}
+
+/* Append the list of entries as an array. */
+void
+gconf_dbus_utils_append_entries (DBusMessageIter *iter,
+				 GSList          *entries)
+{
+  DBusMessageIter array_iter;
+  GSList *l;
+
+  dbus_message_iter_open_container (iter,
+				    DBUS_TYPE_ARRAY,
+				    DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+				    DBUS_TYPE_STRING_AS_STRING
+				    DBUS_TYPE_STRING_AS_STRING
+				    DBUS_TYPE_BOOLEAN_AS_STRING
+				    DBUS_TYPE_STRING_AS_STRING
+				    DBUS_TYPE_BOOLEAN_AS_STRING
+				    DBUS_TYPE_BOOLEAN_AS_STRING
+				    DBUS_STRUCT_END_CHAR_AS_STRING,
+				    &array_iter);
+
+  for (l = entries; l; l = l->next)
+    {
+      GConfEntry *entry = l->data;
+
+      utils_append_entry_values_stringified (&array_iter,
+					     entry->key,
+					     gconf_entry_get_value (entry),
+					     gconf_entry_get_is_default (entry),
+					     gconf_entry_get_is_writable (entry),
+					     gconf_entry_get_schema_name (entry));
+    }
+
+  dbus_message_iter_close_container (iter, &array_iter);
+}
+
+/* Get a list of entries from an array. */
+GSList *
+gconf_dbus_utils_get_entries (DBusMessageIter *iter, const gchar *dir)
+{
+  GSList *entries;
+  DBusMessageIter array_iter;
+
+  entries = NULL;
+
+  dbus_message_iter_recurse (iter, &array_iter);
+
+  /* Loop through while there are structs (entries). */
+  while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_STRUCT)
+    {
+      gchar      *key;
+      GConfValue *value;
+      gboolean    is_default;
+      gboolean    is_writable;
+      gchar      *schema_name;
+      GConfEntry *entry;
+
+      if (!utils_get_entry_values_stringified (&array_iter,
+					       &key,
+					       &value,
+					       &is_default,
+					       &is_writable,
+					       &schema_name))
+	break;
+
+      entry = gconf_entry_new_nocopy (gconf_concat_dir_and_key (dir, key), value);
+
+      gconf_entry_set_is_default (entry, is_default);
+      gconf_entry_set_is_writable (entry, is_writable);
+      
+      if (schema_name)
+	gconf_entry_set_schema_name (entry, schema_name);
+      
+      entries = g_slist_prepend (entries, entry);
+      
+      dbus_message_iter_next (&array_iter);
+    }
+
+  return entries;
+}
+
diff --git a/gconf/gconf-dbus-utils.h b/gconf/gconf-dbus-utils.h
new file mode 100644
index 0000000..deeab87
--- /dev/null
+++ b/gconf/gconf-dbus-utils.h
@@ -0,0 +1,99 @@
+/* GConf
+ * Copyright (C) 2003 Imendio HB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GCONF_DBUS_UTILS_H
+#define GCONF_DBUS_UTILS_H
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gconf/gconf.h>
+#include <gconf/gconf-value.h>
+
+#define GCONF_DBUS_SERVICE                  "org.gnome.GConf"
+
+#define GCONF_DBUS_SERVER_INTERFACE         "org.gnome.GConf.Server"
+#define GCONF_DBUS_DATABASE_INTERFACE       "org.gnome.GConf.Database"
+
+#define GCONF_DBUS_SERVER_OBJECT            "/org/gnome/GConf/Server"
+
+#define GCONF_DBUS_SERVER_GET_DEFAULT_DB    "GetDefaultDatabase"
+#define GCONF_DBUS_SERVER_GET_DB            "GetDatabase"
+#define GCONF_DBUS_SERVER_SHUTDOWN          "Shutdown"
+
+#define GCONF_DBUS_DATABASE_LOOKUP          "Lookup"
+#define GCONF_DBUS_DATABASE_LOOKUP_EXTENDED "LookupExtended" 
+#define GCONF_DBUS_DATABASE_LOOKUP_DEFAULT  "LookupDefault" 
+#define GCONF_DBUS_DATABASE_SET             "Set"
+#define GCONF_DBUS_DATABASE_UNSET           "UnSet"
+#define GCONF_DBUS_DATABASE_RECURSIVE_UNSET "RecursiveUnset"
+#define GCONF_DBUS_DATABASE_DIR_EXISTS      "DirExists"
+#define GCONF_DBUS_DATABASE_GET_ALL_ENTRIES "AllEntries"
+#define GCONF_DBUS_DATABASE_GET_ALL_DIRS    "AllDirs"
+#define GCONF_DBUS_DATABASE_SET_SCHEMA      "SetSchema"
+#define GCONF_DBUS_DATABASE_SUGGEST_SYNC    "SuggestSync"
+
+#define GCONF_DBUS_DATABASE_ADD_NOTIFY      "AddNotify"
+#define GCONF_DBUS_DATABASE_REMOVE_NOTIFY   "RemoveNotify"
+ 
+#define GCONF_DBUS_LISTENER_NOTIFY          "Notify"
+
+#define GCONF_DBUS_CLIENT_SERVICE           "org.gnome.GConf.ClientService"
+#define GCONF_DBUS_CLIENT_OBJECT            "/org/gnome/GConf/Client"
+#define GCONF_DBUS_CLIENT_INTERFACE         "org.gnome.GConf.Client"
+
+#define GCONF_DBUS_UNSET_INCLUDING_SCHEMA_NAMES 0x1
+ 
+#define GCONF_DBUS_ERROR_FAILED               "org.gnome.GConf.Error.Failed"
+#define GCONF_DBUS_ERROR_NO_PERMISSION        "org.gnome.GConf.Error.NoPermission"
+#define GCONF_DBUS_ERROR_BAD_ADDRESS          "org.gnome.GConf.Error.BadAddress"
+#define GCONF_DBUS_ERROR_BAD_KEY              "org.gnome.GConf.Error.BadKey"
+#define GCONF_DBUS_ERROR_PARSE_ERROR          "org.gnome.GConf.Error.ParseError"
+#define GCONF_DBUS_ERROR_CORRUPT              "org.gnome.GConf.Error.Corrupt"
+#define GCONF_DBUS_ERROR_TYPE_MISMATCH        "org.gnome.GConf.Error.TypeMismatch"
+#define GCONF_DBUS_ERROR_IS_DIR               "org.gnome.GConf.Error.IsDir"
+#define GCONF_DBUS_ERROR_IS_KEY               "org.gnome.GConf.Error.IsKey"
+#define GCONF_DBUS_ERROR_NO_WRITABLE_DATABASE "org.gnome.GConf.Error.NoWritableDatabase"
+#define GCONF_DBUS_ERROR_IN_SHUTDOWN          "org.gnome.GConf.Error.InShutdown"
+#define GCONF_DBUS_ERROR_OVERRIDDEN           "org.gnome.GConf.Error.Overriden"
+#define GCONF_DBUS_ERROR_LOCK_FAILED          "org.gnome.GConf.Error.LockFailed"
+
+void        gconf_dbus_utils_append_value     (DBusMessageIter   *iter,
+					       const GConfValue  *value);
+GConfValue *gconf_dbus_utils_get_value        (DBusMessageIter   *iter);
+
+void        gconf_dbus_utils_append_entry_values (DBusMessageIter   *iter,
+						 const gchar       *key,
+						 const GConfValue  *value,
+						 gboolean           is_default,
+						 gboolean           is_writable,
+						 const gchar       *schema_name);
+gboolean    gconf_dbus_utils_get_entry_values   (DBusMessageIter   *iter,
+						 gchar            **key,
+						 GConfValue       **value,
+						 gboolean          *is_default,
+						 gboolean          *is_writable,
+						 gchar            **schema_name);
+
+void gconf_dbus_utils_append_entries (DBusMessageIter *iter,
+				      GSList          *entries);
+
+GSList *gconf_dbus_utils_get_entries (DBusMessageIter *iter, const gchar *dir);
+
+
+#endif/* GCONF_DBUS_UTILS_H */
diff --git a/gconf/gconf-dbus.c b/gconf/gconf-dbus.c
new file mode 100644
index 0000000..8071e94
--- /dev/null
+++ b/gconf/gconf-dbus.c
@@ -0,0 +1,2468 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+
+/* GConf
+ * Copyright (C) 1999, 2000 Red Hat Inc.
+ * Copyright (C) 2003 Imendio AB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include "gconf.h"
+#include "gconf-dbus-utils.h"
+#include "gconf-internals.h"
+#include "gconf-sources.h"
+#include "gconf-locale.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#define d(x) 
+
+#define DAEMON_NAME_OWNER_CHANGED_RULE \
+    "type='signal',member='NameOwnerChanged',arg0='org.gnome.GConf'"
+#define NOTIFY_RULE \
+    "type='method_call',interface='org.gnome.GConf.Database',member='Notify'"
+#define DAEMON_DISCONNECTED_RULE \
+    "type='signal',member='Disconnected'"
+
+struct _GConfEngine {
+  guint refcount;
+
+  gchar *database;
+
+  GHashTable *notify_dirs;
+  GHashTable *notify_ids;
+
+  /* If non-NULL, this is a local engine;
+     local engines don't do notification! */
+  GConfSources* local_sources;
+
+  /* A list of addresses that make up this db
+   * if this is not the default engine;
+   * NULL if it's the default
+   */
+  GSList *addresses;
+
+  /* A concatentation of the addresses above.
+   */
+  char *persistent_address;
+
+  gpointer user_data;
+  GDestroyNotify dnotify;
+
+  gpointer owner;
+  int owner_use_count;
+  
+  guint is_default : 1;
+
+  /* If TRUE, this is a local engine (and therefore
+   * has no ctable and no notifications)
+   */
+  guint is_local : 1;
+};
+
+typedef struct {
+  gchar* namespace_section;
+  guint client_id;
+
+  GConfEngine* conf;             /* Engine we're associated with */
+  GConfNotifyFunc func;
+  gpointer user_data;
+} GConfCnxn;
+
+typedef struct {
+  GList *cnxns;     /* List of connections to be notified below the dir */
+} CnxnsData;
+
+
+static DBusConnection *global_conn = NULL;
+static gboolean        service_running = FALSE;
+static gboolean        needs_reconnect = FALSE;
+static GConfEngine    *default_engine = NULL;
+static GHashTable     *engines_by_db = NULL;
+static GHashTable     *engines_by_address = NULL;
+static gboolean        dbus_disconnected = FALSE;
+
+static gboolean     ensure_dbus_connection      (void);
+static gboolean     ensure_service              (gboolean          start_if_not_found,
+						 GError          **err);
+static gboolean     ensure_database             (GConfEngine      *conf,
+						 gboolean          start_if_not_found,
+						 GError          **err);
+
+static void         gconf_engine_detach         (GConfEngine      *conf);
+static void         gconf_engine_set_database   (GConfEngine      *conf,
+						 const gchar      *db);
+static const gchar *gconf_engine_get_database   (GConfEngine      *conf,
+						 gboolean          start_if_not_found,
+						 GError          **err);
+
+static void         register_engine             (GConfEngine      *conf);
+static void         unregister_engine           (GConfEngine      *conf);
+static GConfCnxn *  gconf_cnxn_new              (GConfEngine      *conf,
+						 const gchar      *namespace_section,
+						 GConfNotifyFunc   func,
+						 gpointer          user_data);
+static void         gconf_cnxn_destroy          (GConfCnxn        *cnxn);
+static void         gconf_cnxn_notify           (GConfCnxn        *cnxn,
+						 GConfEntry       *entry);
+static GConfCnxn *  gconf_cnxn_lookup_id        (GConfEngine      *conf,
+						 guint             client_id);
+static GList *      gconf_cnxn_lookup_dir       (GConfEngine      *conf,
+						 const gchar      *dir);
+static void         gconf_cnxn_insert           (GConfEngine      *conf,
+						 const gchar      *dir,
+						 guint              client_id,
+						 GConfCnxn        *cnxn);
+static void         gconf_cnxn_remove           (GConfEngine      *conf,
+						 GConfCnxn        *cnxn);
+static gboolean     send_notify_add             (GConfEngine      *conf,
+						 GConfCnxn        *cnxn,
+						 GError          **err);
+static void         reinitialize_databases      (void);
+static DBusHandlerResult
+                    gconf_dbus_message_filter   (DBusConnection   *dbus_conn,
+						 DBusMessage      *message,
+						 gpointer          user_data);
+static GConfEngine *lookup_engine_by_addresses  (GSList           *addresses);
+static GConfEngine *lookup_engine_by_database   (const gchar      *db);
+static gboolean     gconf_handle_dbus_exception (DBusMessage      *message,
+						 DBusError        *derr,
+						 GError          **gerr);
+static void         gconf_detach_config_server  (void);
+static DBusHandlerResult
+                    handle_notify               (DBusConnection   *connection,
+						 DBusMessage      *message,
+						 GConfEngine      *conf);
+
+
+#define CHECK_OWNER_USE(engine) \
+  do { if ((engine)->owner && (engine)->owner_use_count == 0) \
+      g_warning ("%s: You can't use a GConfEngine that has an active " \
+		 "GConfClient wrapper object. Use GConfClient API instead.", \
+		 G_GNUC_FUNCTION); \
+  } while (0)
+
+
+static GConfError
+dbus_error_name_to_gconf_errno (const char *name)
+{
+  int i;
+  struct
+  {
+    const char *name;
+    GConfError error;
+  } errors [] = {
+    { GCONF_DBUS_ERROR_FAILED, GCONF_ERROR_FAILED },
+    { GCONF_DBUS_ERROR_NO_PERMISSION, GCONF_ERROR_NO_PERMISSION },
+    { GCONF_DBUS_ERROR_BAD_ADDRESS, GCONF_ERROR_BAD_ADDRESS },
+    { GCONF_DBUS_ERROR_BAD_KEY, GCONF_ERROR_BAD_KEY },
+    { GCONF_DBUS_ERROR_PARSE_ERROR, GCONF_ERROR_PARSE_ERROR },
+    { GCONF_DBUS_ERROR_CORRUPT, GCONF_ERROR_CORRUPT },
+    { GCONF_DBUS_ERROR_TYPE_MISMATCH, GCONF_ERROR_TYPE_MISMATCH },
+    { GCONF_DBUS_ERROR_IS_DIR, GCONF_ERROR_IS_DIR },
+    { GCONF_DBUS_ERROR_IS_KEY, GCONF_ERROR_IS_KEY },
+    { GCONF_DBUS_ERROR_OVERRIDDEN, GCONF_ERROR_OVERRIDDEN },
+    { GCONF_DBUS_ERROR_LOCK_FAILED, GCONF_ERROR_LOCK_FAILED },
+    { GCONF_DBUS_ERROR_NO_WRITABLE_DATABASE, GCONF_ERROR_NO_WRITABLE_DATABASE },
+    { GCONF_DBUS_ERROR_IN_SHUTDOWN, GCONF_ERROR_IN_SHUTDOWN },
+  };
+
+  for (i = 0; i < G_N_ELEMENTS (errors); i++)
+    {
+      if (strcmp (name, errors[i].name) == 0)
+	return errors[i].error;
+    }
+
+  g_assert_not_reached ();
+  
+  return GCONF_ERROR_SUCCESS;
+}
+
+/* If no error is detected, return FALSE with no side-effects. If an error is
+ * detected, return TRUE, set gerr, unref message and free derr.
+ */
+static gboolean
+gconf_handle_dbus_exception (DBusMessage *message, DBusError *derr, GError **gerr)
+{
+  char *error_string;
+  const char *name;
+
+  if (message == NULL)
+    {
+      if (derr && dbus_error_is_set (derr))
+	{
+	  if (gerr)
+	    {
+	      *gerr = gconf_error_new (GCONF_ERROR_NO_SERVER, _("D-BUS error: %s"),
+				       derr->message);
+	    }
+	}
+      else 
+	{
+	  if (gerr)
+	    *gerr = gconf_error_new (GCONF_ERROR_FAILED, _("Unknown error"));
+	}
+
+      if (derr)
+	dbus_error_free (derr);
+
+      return TRUE;
+    }
+    
+  if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)
+    return FALSE;
+
+  if (derr)
+    dbus_error_free (derr);
+
+  name = dbus_message_get_member (message);
+
+  dbus_message_get_args (message, NULL,
+			 DBUS_TYPE_STRING, &error_string,
+			 DBUS_TYPE_INVALID);
+  
+  if (g_str_has_prefix (name, "org.freedesktop.DBus.Error"))
+    {
+      if (gerr)
+	*gerr = gconf_error_new (GCONF_ERROR_NO_SERVER, _("D-BUS error: %s"),
+				error_string);
+    }
+  else if (g_str_has_prefix (name, "org.gnome.GConf.Error"))
+    {
+      if (gerr)
+	{
+	  GConfError en;
+	  
+	  en = dbus_error_name_to_gconf_errno (name);
+	  *gerr = gconf_error_new (en, error_string);
+	}
+    }
+  else
+    {
+      if (gerr)
+	*gerr = gconf_error_new (GCONF_ERROR_FAILED, _("Unknown error %s: %s"),
+				 name, error_string);
+    }
+
+  dbus_message_unref (message);
+  
+  return TRUE;
+}
+
+static GConfEngine*
+gconf_engine_blank (gboolean remote)
+{
+  GConfEngine* conf;
+
+  _gconf_init_i18n ();
+  
+  conf = g_new0 (GConfEngine, 1);
+
+  conf->refcount = 1;
+  
+  conf->owner = NULL;
+  conf->owner_use_count = 0;
+  
+  if (remote)
+    {
+      conf->database = NULL;
+
+      conf->notify_dirs = g_hash_table_new_full (g_str_hash, g_str_equal,
+						 g_free, NULL);
+
+      conf->notify_ids = g_hash_table_new (NULL, NULL);
+      
+      conf->local_sources = NULL;
+      conf->is_local = FALSE;
+      conf->is_default = TRUE;
+    }
+  else
+    {
+      conf->database = NULL;
+      conf->notify_ids = NULL;
+      conf->notify_dirs = NULL;
+      conf->local_sources = NULL;
+      conf->is_local = TRUE;
+      conf->is_default = FALSE;
+    }
+  
+  return conf;
+}
+
+void
+gconf_engine_set_owner (GConfEngine *engine,
+                        gpointer     client)
+{
+  g_return_if_fail (engine->owner_use_count == 0);
+  
+  engine->owner = client;
+}
+
+void
+gconf_engine_push_owner_usage (GConfEngine *engine,
+                               gpointer     client)
+{
+  g_return_if_fail (engine->owner == client);
+
+  engine->owner_use_count += 1;
+}
+
+void
+gconf_engine_pop_owner_usage  (GConfEngine *engine,
+                               gpointer     client)
+{
+  g_return_if_fail (engine->owner == client);
+  g_return_if_fail (engine->owner_use_count > 0);
+
+  engine->owner_use_count -= 1;
+}
+
+static GConfEngine *
+lookup_engine_by_database (const gchar *db)
+{
+  if (engines_by_db)
+    return g_hash_table_lookup (engines_by_db, db);
+  else
+    return NULL;
+}
+
+static void
+database_hash_value_destroy (gpointer value)
+{
+  GConfEngine *conf = value;
+
+  g_free (conf->database);
+  conf->database = NULL;
+}
+
+static void
+gconf_engine_set_database (GConfEngine *conf,
+                           const gchar *db)
+{
+  gconf_engine_detach (conf);
+
+  conf->database = g_strdup (db);
+
+  if (engines_by_db == NULL)
+    engines_by_db = g_hash_table_new_full (g_str_hash,
+					   g_str_equal,
+					   NULL,
+					   database_hash_value_destroy);
+  
+  g_hash_table_insert (engines_by_db, conf->database, conf);  
+}
+
+static void
+gconf_engine_detach (GConfEngine *conf)
+{
+  if (conf->database != NULL)
+    {
+      g_hash_table_remove (engines_by_db, conf->database);
+    }
+}
+
+static gboolean
+ensure_dbus_connection (void)
+{
+  DBusError error;
+
+  if (global_conn != NULL)
+    return TRUE;
+
+  if (dbus_disconnected)
+    {
+      g_warning ("The connection to DBus was broken. Can't reinitialize it.");
+      return FALSE;
+    }
+
+  dbus_error_init (&error);
+
+  global_conn = dbus_bus_get_private (DBUS_BUS_SESSION, &error);
+  
+  if (!global_conn) 
+    {
+      g_warning ("Client failed to connect to the D-BUS daemon:\n%s", error.message);
+      
+      dbus_error_free (&error);
+      return FALSE;
+    }
+	
+  dbus_connection_setup_with_g_main (global_conn, NULL);
+
+  dbus_connection_set_exit_on_disconnect (global_conn, FALSE);
+
+  dbus_bus_add_match (global_conn, DAEMON_NAME_OWNER_CHANGED_RULE, NULL);
+  dbus_bus_add_match (global_conn, NOTIFY_RULE, NULL);
+  dbus_bus_add_match (global_conn, DAEMON_DISCONNECTED_RULE, NULL);
+
+  dbus_connection_add_filter (global_conn, gconf_dbus_message_filter,
+			      NULL, NULL);
+  
+  return TRUE;
+}
+
+static gboolean
+ensure_service (gboolean  start_if_not_found,
+		GError   **err)
+{
+  DBusError error;
+
+  if (global_conn == NULL)
+    {
+      if (!ensure_dbus_connection ())
+	{
+	  g_set_error (err, GCONF_ERROR,
+		       GCONF_ERROR_NO_SERVER,
+		       _("No D-BUS daemon running\n"));
+	  return FALSE;
+	}
+
+      g_assert (global_conn != NULL);
+    }
+
+  if (service_running)
+    return TRUE;
+  
+  if (start_if_not_found)
+    {
+      d(g_print ("* activate_service, activating\n"));
+
+      dbus_error_init (&error);
+      
+      if (!dbus_bus_start_service_by_name (global_conn,
+					   GCONF_DBUS_SERVICE,
+					   0,
+					   NULL,
+					   &error))
+	{
+	  const gchar *msg;
+	  
+	  if (dbus_error_is_set (&error))
+	    msg = error.message;
+	  else
+	    msg = _("Unknown error");
+	  
+	  g_set_error (err, GCONF_ERROR,
+		       GCONF_ERROR_NO_SERVER,
+		       _("Failed to activate configuration server: %s\n"),
+		       msg);
+	  
+	  if (dbus_error_is_set (&error))
+	    dbus_error_free (&error);
+	  
+	  return FALSE;
+	}
+      
+      service_running = TRUE;
+      
+      return TRUE;
+    }
+  
+  return FALSE;
+}
+
+static gboolean
+ensure_database (GConfEngine  *conf,
+		 gboolean      start_if_not_found,
+		 GError      **err)
+{
+  DBusMessage *message, *reply;
+  DBusError error;
+  gchar *db;
+
+  g_return_val_if_fail (!conf->is_local, TRUE);
+
+  if (!ensure_service (start_if_not_found, err))
+    return FALSE;
+
+  if (needs_reconnect)
+    {
+      /* Re-connect notifications and re-get database names from the previous
+       * (if any) instance of the GConf service.
+       */
+      needs_reconnect = FALSE;
+      reinitialize_databases ();
+    }
+  
+  if (conf->database != NULL)
+    return TRUE;
+  
+  if (conf->is_default)
+    {
+      message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					      GCONF_DBUS_SERVER_OBJECT,
+					      GCONF_DBUS_SERVER_INTERFACE,
+					      GCONF_DBUS_SERVER_GET_DEFAULT_DB);
+    }
+  else
+    {
+      gchar *addresses;
+
+      addresses = gconf_address_list_get_persistent_name (conf->addresses);
+      
+      message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					      GCONF_DBUS_SERVER_OBJECT,
+					      GCONF_DBUS_SERVER_INTERFACE,
+					      GCONF_DBUS_SERVER_GET_DB);
+      dbus_message_append_args (message,
+				DBUS_TYPE_STRING, &addresses,
+				DBUS_TYPE_INVALID);
+      
+      g_free (addresses);
+    }
+
+  dbus_error_init (&error);
+  reply = dbus_connection_send_with_reply_and_block (global_conn,
+						     message, -1, &error);
+  
+  dbus_message_unref (message);
+  
+  if (gconf_handle_dbus_exception (reply, &error, err))
+    return FALSE;
+
+  dbus_message_get_args (reply,
+			 NULL,
+			 DBUS_TYPE_STRING, &db,
+			 DBUS_TYPE_INVALID);
+
+  dbus_message_unref (reply);
+
+  if (db == NULL)
+    {
+      if (err)
+        *err = gconf_error_new (GCONF_ERROR_BAD_ADDRESS,
+				_("Server couldn't resolve the address `%s'"),
+				conf->persistent_address);
+      
+      return FALSE;
+    }
+
+  gconf_engine_set_database (conf, db);
+
+  return TRUE;
+}
+
+static const gchar *
+gconf_engine_get_database (GConfEngine *conf,
+                           gboolean start_if_not_found,
+                           GError **err)
+{
+  if (!ensure_database (conf, start_if_not_found, err))
+    return NULL;
+  else
+    return conf->database;
+}
+
+static gboolean
+gconf_engine_is_local (GConfEngine* conf)
+{
+  return conf->is_local;
+}
+
+static void
+register_engine (GConfEngine *conf)
+{
+  g_return_if_fail (conf->addresses != NULL);
+
+  g_assert (conf->persistent_address == NULL);
+
+  conf->persistent_address = 
+          gconf_address_list_get_persistent_name (conf->addresses);
+
+  if (engines_by_address == NULL)
+    engines_by_address = g_hash_table_new (g_str_hash, g_str_equal);
+
+  g_hash_table_insert (engines_by_address, conf->persistent_address, conf);
+}
+
+static void
+unregister_engine (GConfEngine *conf)
+{
+  g_return_if_fail (engines_by_address != NULL);
+
+  g_assert (conf->persistent_address != NULL);
+
+  g_hash_table_remove (engines_by_address, conf->persistent_address);
+  g_free (conf->persistent_address);
+  conf->persistent_address = NULL;
+
+  if (g_hash_table_size (engines_by_address) == 0)
+    {
+      g_hash_table_destroy (engines_by_address);
+      
+      engines_by_address = NULL;
+    }
+}
+
+static GConfEngine *
+lookup_engine_by_addresses (GSList *addresses)
+{
+  if (engines_by_address != NULL)
+    {
+      GConfEngine *retval;
+      char        *key;
+
+      key = gconf_address_list_get_persistent_name (addresses);
+
+      retval = g_hash_table_lookup (engines_by_address, key);
+
+      g_free (key);
+
+      return retval;
+    }
+
+  return NULL;
+}
+
+
+/*
+ * Connection maintenance
+ */
+
+static GConfCnxn *
+gconf_cnxn_new (GConfEngine *conf,
+		const gchar *namespace_section,
+		GConfNotifyFunc func,
+		gpointer user_data)
+{
+  GConfCnxn *cnxn;
+  static guint next_id = 1;
+  
+  cnxn = g_new0 (GConfCnxn, 1);
+
+  cnxn->namespace_section = g_strdup (namespace_section);
+  cnxn->conf = conf;
+  cnxn->client_id = next_id;
+  cnxn->func = func;
+  cnxn->user_data = user_data;
+
+  ++next_id;
+
+  return cnxn;
+}
+
+static void      
+gconf_cnxn_destroy (GConfCnxn* cnxn)
+{
+  g_free (cnxn->namespace_section);
+  g_free (cnxn);
+}
+
+static void       
+gconf_cnxn_notify (GConfCnxn* cnxn,
+		   GConfEntry *entry)
+{
+  (*cnxn->func) (cnxn->conf, cnxn->client_id,
+		 entry,
+		 cnxn->user_data);
+}
+
+static GList *
+gconf_cnxn_lookup_dir (GConfEngine *conf, const gchar *dir)
+{
+  CnxnsData *data;
+
+  data = g_hash_table_lookup (conf->notify_dirs, dir);
+
+  if (data == NULL)
+    return NULL;
+
+  return data->cnxns;
+}
+
+static GConfCnxn *
+gconf_cnxn_lookup_id (GConfEngine *conf, guint client_id)
+{
+  gint id = client_id;
+
+  return g_hash_table_lookup (conf->notify_ids, GINT_TO_POINTER (id));
+}
+
+static void
+gconf_cnxn_insert (GConfEngine *conf, const gchar *dir, guint client_id, GConfCnxn *cnxn)
+{
+  CnxnsData *data;
+  gint id = client_id;
+
+  data = g_hash_table_lookup (conf->notify_dirs, dir);
+
+  if (data == NULL)
+    {
+      data = g_new (CnxnsData, 1);
+      data->cnxns = NULL;
+      g_hash_table_insert (conf->notify_dirs, g_strdup (dir), data);
+    }
+  
+  data->cnxns = g_list_prepend (data->cnxns, cnxn);
+
+  g_hash_table_insert (conf->notify_ids, GINT_TO_POINTER (id), cnxn);
+}
+
+static void
+gconf_cnxn_remove (GConfEngine *conf, GConfCnxn *cnxn)
+{
+  CnxnsData *data;
+  gint id = cnxn->client_id;
+
+  g_hash_table_remove (conf->notify_ids, GINT_TO_POINTER (id));
+
+  data = g_hash_table_lookup (conf->notify_dirs, cnxn->namespace_section);
+  if (data)
+    {
+      data->cnxns = g_list_remove (data->cnxns, cnxn);
+
+      if (data->cnxns == NULL)
+	{
+	  g_hash_table_remove (conf->notify_dirs, cnxn->namespace_section);
+	  g_free (data);
+
+	  gconf_cnxn_destroy (cnxn);
+	}
+    }
+}
+  
+
+/*
+ *  Public Interface
+ */
+
+GConfEngine*
+gconf_engine_get_local      (const gchar* address,
+                             GError** err)
+{
+  GConfEngine *conf;
+  GConfSource *source;
+
+  g_return_val_if_fail (address != NULL, NULL);
+  g_return_val_if_fail (err == NULL || *err == NULL, NULL);
+  
+  source = gconf_resolve_address (address, err);
+
+  if (source == NULL)
+    return NULL;
+  
+  conf = gconf_engine_blank (FALSE);
+
+  conf->local_sources = gconf_sources_new_from_source (source);
+
+  g_assert (gconf_engine_is_local (conf));
+  
+  return conf;
+}
+
+GConfEngine *
+gconf_engine_get_local_for_addresses (GSList  *addresses,
+				      GError **err)
+{
+  GConfEngine *conf;
+
+  g_return_val_if_fail (addresses != NULL, NULL);
+  g_return_val_if_fail (err == NULL || *err == NULL, NULL);
+  
+  conf = gconf_engine_blank (FALSE);
+
+  conf->local_sources = gconf_sources_new_from_addresses (addresses, err);
+
+  g_assert (gconf_engine_is_local (conf));
+  
+  return conf;
+}
+
+GConfEngine*
+gconf_engine_get_default (void)
+{
+  GConfEngine* conf = NULL;
+  
+  if (default_engine)
+    conf = default_engine;
+  
+  if (conf == NULL)
+    {
+      conf = gconf_engine_blank (TRUE);
+
+      conf->is_default = TRUE;
+
+      default_engine = conf;
+    }
+  else
+    conf->refcount += 1;
+  
+  return conf;
+}
+
+GConfEngine*
+gconf_engine_get_for_address (const gchar* address, GError** err)
+{
+  GConfEngine *conf;
+  GSList      *addresses;
+  
+  addresses = g_slist_append (NULL, g_strdup (address));
+
+  conf = lookup_engine_by_addresses (addresses);
+
+  if (conf == NULL)
+    {
+      conf = gconf_engine_blank (TRUE);
+
+      conf->is_default = FALSE;
+      conf->addresses = addresses;
+
+      if (!ensure_database (conf, TRUE, err))
+        {
+          gconf_engine_unref (conf);
+          return NULL;
+        }
+      
+      register_engine (conf);
+    }
+  else
+    {
+      g_free (addresses->data);
+      g_slist_free (addresses);
+      conf->refcount += 1;
+    }
+  
+  return conf;
+}
+
+GConfEngine*
+gconf_engine_get_for_addresses (GSList *addresses, GError** err)
+{
+  GConfEngine* conf;
+
+  conf = lookup_engine_by_addresses (addresses);
+
+  if (conf == NULL)
+    {
+      GSList *tmp;
+
+      conf = gconf_engine_blank (TRUE);
+
+      conf->is_default = FALSE;
+      conf->addresses = NULL;
+
+      tmp = addresses;
+      while (tmp != NULL)
+        {
+          conf->addresses = g_slist_append (conf->addresses,
+                                            g_strdup (tmp->data));
+          tmp = tmp->next;
+        }
+
+      if (!ensure_database (conf, TRUE, err))
+        {
+          gconf_engine_unref (conf);
+          return NULL;
+        }
+
+      register_engine (conf);
+    }
+  else
+    conf->refcount += 1;
+  
+  return conf;
+}
+
+void
+gconf_engine_ref (GConfEngine* conf)
+{
+  g_return_if_fail (conf != NULL);
+  g_return_if_fail (conf->refcount > 0);
+
+  conf->refcount += 1;
+}
+
+void         
+gconf_engine_unref (GConfEngine* conf)
+{
+  g_return_if_fail (conf != NULL);
+  g_return_if_fail (conf->refcount > 0);
+
+  conf->refcount -= 1;
+  
+  if (conf->refcount == 0)
+    {
+      if (gconf_engine_is_local (conf))
+        {
+          if (conf->local_sources != NULL)
+            gconf_sources_free (conf->local_sources);
+        }
+      else
+        {
+          /* Remove all connections associated with this GConf */
+
+	  /* FIXME: remove notify_ids from hash when we have
+	     add/remove_notify. */
+
+          if (conf->dnotify)
+            {
+              (* conf->dnotify) (conf->user_data);
+            }
+          
+          /* do this after removing the notifications,
+             to avoid funky race conditions */
+          if (conf->addresses)
+	    {
+	      gconf_address_list_free (conf->addresses);
+	      conf->addresses = NULL;
+	    }
+
+	  if (conf->persistent_address)
+	    {
+	      unregister_engine (conf);
+	    }
+	  
+          /* Release the ConfigDatabase */
+          gconf_engine_detach (conf);
+
+          if (conf->notify_ids)
+	    g_hash_table_destroy (conf->notify_ids);
+          if (conf->notify_dirs)
+	    g_hash_table_destroy (conf->notify_dirs);
+        }
+      
+      if (conf == default_engine)
+        default_engine = NULL;
+      
+      g_free(conf);
+    }
+}
+
+void
+gconf_engine_set_user_data  (GConfEngine   *engine,
+                             gpointer       data,
+                             GDestroyNotify dnotify)
+{
+  if (engine->dnotify)
+    {
+      (* engine->dnotify) (engine->user_data);
+    }
+
+  engine->dnotify = dnotify;
+  engine->user_data = data;
+}
+
+gpointer
+gconf_engine_get_user_data (GConfEngine   *engine)
+{
+  return engine->user_data;
+}
+
+static gboolean
+send_notify_add (GConfEngine *conf,
+		 GConfCnxn *cnxn,
+		 GError **err)
+{
+  const gchar *db;
+  DBusMessage *message, *reply;
+  DBusError error;
+    
+  db = gconf_engine_get_database (conf, TRUE, err);
+  
+  if (db == NULL)
+    {
+      g_return_val_if_fail(err == NULL || *err != NULL, 0);
+      
+      return FALSE;
+    }
+
+  message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					  db,
+					  GCONF_DBUS_DATABASE_INTERFACE,
+					  GCONF_DBUS_DATABASE_ADD_NOTIFY);
+  
+  dbus_message_append_args (message,
+			    DBUS_TYPE_STRING, &cnxn->namespace_section,
+			    DBUS_TYPE_INVALID);
+
+  dbus_error_init (&error);
+  reply = dbus_connection_send_with_reply_and_block (global_conn,
+						     message, -1, &error);
+  dbus_message_unref (message);
+  
+  if (gconf_handle_dbus_exception (reply, &error, err))
+    return FALSE;
+  
+  dbus_message_unref (reply);
+
+  return TRUE;
+}
+
+guint
+gconf_engine_notify_add (GConfEngine* conf,
+			 const gchar* namespace_section,
+			 GConfNotifyFunc func,
+			 gpointer user_data,
+			 GError** err)
+{
+  GConfCnxn *cnxn;
+  
+  g_return_val_if_fail (!gconf_engine_is_local (conf), 0);
+
+  CHECK_OWNER_USE (conf);
+  
+  if (gconf_engine_is_local (conf))
+    {
+      if (err)
+        *err = gconf_error_new (GCONF_ERROR_LOCAL_ENGINE,
+				_("Can't add notifications to a local configuration source"));
+
+      return 0;
+    }
+
+  cnxn = gconf_cnxn_new (conf, namespace_section, func, user_data);
+  gconf_cnxn_insert (conf, namespace_section, cnxn->client_id, cnxn);
+  
+  if (!send_notify_add (conf, cnxn, err))
+    {
+      gconf_cnxn_remove (conf, cnxn);
+      return 0;
+    }
+
+  return cnxn->client_id;
+}
+
+void         
+gconf_engine_notify_remove (GConfEngine* conf,
+			    guint client_id)
+{
+  GConfCnxn *cnxn;
+  const gchar *db;
+  gchar *namespace_section = NULL;
+  DBusMessage *message, *reply;
+  DBusError error;
+  
+  CHECK_OWNER_USE (conf);
+  
+  if (gconf_engine_is_local(conf))
+    return;
+
+  cnxn = gconf_cnxn_lookup_id (conf, client_id);
+  if (cnxn != NULL)
+    {
+      namespace_section = g_strdup (cnxn->namespace_section);
+      gconf_cnxn_remove (conf, cnxn);
+    }
+  
+  g_return_if_fail (cnxn != NULL); 
+  
+  db = gconf_engine_get_database (conf, TRUE, NULL);
+  
+  if (db == NULL)
+    return;
+
+  d(g_print ("notify_remove, id = %d\n", client_id));
+  
+  message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					  db,
+					  GCONF_DBUS_DATABASE_INTERFACE,
+					  GCONF_DBUS_DATABASE_REMOVE_NOTIFY);
+  
+  dbus_message_append_args (message,
+			    DBUS_TYPE_STRING, &namespace_section,
+			    DBUS_TYPE_INVALID);
+
+  dbus_error_init (&error);
+  reply = dbus_connection_send_with_reply_and_block (global_conn, message, -1, &error);
+  dbus_message_unref (message);
+  
+  if (dbus_error_is_set (&error))
+    dbus_error_free (&error);
+  
+  g_free (namespace_section);
+  
+  dbus_message_unref (reply);
+}
+
+GConfValue *
+gconf_engine_get_fuller (GConfEngine *conf,
+                         const gchar *key,
+                         const gchar *locale,
+                         gboolean use_schema_default,
+                         gboolean *is_default_p,
+                         gboolean *is_writable_p,
+                         gchar   **schema_name_p,
+                         GError **err)
+{
+  GConfValue* val;
+  const gchar *db;
+  gboolean is_default = FALSE;
+  gboolean is_writable = TRUE;
+  gchar *schema_name = NULL;
+  DBusMessage *message, *reply;
+  DBusError error;
+  DBusMessageIter iter;
+  gboolean success;
+  
+  g_return_val_if_fail(conf != NULL, NULL);
+  g_return_val_if_fail(key != NULL, NULL);
+  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
+
+  CHECK_OWNER_USE (conf);
+  
+  if (!gconf_key_check (key, err))
+    return NULL;
+
+  if (gconf_engine_is_local (conf))
+    {
+      gchar **locale_list;
+      
+      locale_list = gconf_split_locale (locale);
+      
+      val = gconf_sources_query_value (conf->local_sources,
+				       key,
+				       (const gchar**)locale_list,
+				       use_schema_default,
+				       &is_default,
+				       &is_writable,
+				       schema_name_p ? &schema_name : NULL,
+				       err);
+
+      if (locale_list != NULL)
+        g_strfreev(locale_list);
+      
+      if (is_default_p)
+        *is_default_p = is_default;
+
+      if (is_writable_p)
+        *is_writable_p = is_writable;
+
+      if (schema_name_p)
+        *schema_name_p = schema_name;
+      else
+        g_free (schema_name);
+      
+      return val;
+    }
+
+  g_assert (!gconf_engine_is_local (conf));
+
+  db = gconf_engine_get_database (conf, TRUE, err);
+
+  if (db == NULL)
+    {
+      g_return_val_if_fail(err == NULL || *err != NULL, NULL);
+      return NULL;
+    }
+
+  if (schema_name_p)
+    *schema_name_p = NULL;
+
+  message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					  db,
+					  GCONF_DBUS_DATABASE_INTERFACE,
+					  GCONF_DBUS_DATABASE_LOOKUP_EXTENDED);
+
+  locale = locale ? locale : gconf_current_locale();
+  
+  dbus_message_append_args (message,
+			    DBUS_TYPE_STRING, &key,
+			    DBUS_TYPE_STRING, &locale,
+			    DBUS_TYPE_BOOLEAN, &use_schema_default,
+			    DBUS_TYPE_INVALID);
+
+  dbus_error_init (&error);
+  reply = dbus_connection_send_with_reply_and_block (global_conn, message, -1, &error);
+  dbus_message_unref (message);
+
+  if (gconf_handle_dbus_exception (reply, &error, err))
+    return NULL;
+
+  dbus_message_iter_init (reply, &iter);
+
+  /* If there is no struct (entry) here, there is no value. */
+  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRUCT)
+    {
+      dbus_message_unref (reply);
+      return NULL;
+    }
+  
+  success = gconf_dbus_utils_get_entry_values (&iter,
+					       NULL,
+					       &val,
+					       &is_default,
+					       &is_writable,
+					       &schema_name);
+  
+  dbus_message_unref (reply);
+  
+  if (!success)
+    {
+      if (err)
+	g_set_error (err, GCONF_ERROR,
+		     GCONF_ERROR_FAILED,
+		     _("Couldn't get value"));
+      
+      return NULL;
+    }
+  
+  if (is_default_p)
+    *is_default_p = !!is_default;
+  
+  if (is_writable_p)
+    *is_writable_p = !!is_writable;
+  
+  if (schema_name && schema_name[0] != '/')
+    {
+      schema_name = NULL;
+    }
+  
+  if (schema_name_p)
+    *schema_name_p = g_strdup (schema_name);
+  
+  return val;
+}
+
+GConfValue *
+gconf_engine_get_full (GConfEngine *conf,
+                       const gchar *key,
+                       const gchar *locale,
+                       gboolean use_schema_default,
+                       gboolean *is_default_p,
+                       gboolean *is_writable_p,
+                       GError **err)
+{
+  return gconf_engine_get_fuller (conf, key, locale, use_schema_default,
+                                  is_default_p, is_writable_p,
+                                  NULL, err);
+}
+
+GConfEntry*
+gconf_engine_get_entry (GConfEngine* conf,
+			const gchar* key,
+			const gchar* locale,
+			gboolean use_schema_default,
+			GError** err)
+{
+  gboolean is_writable = TRUE;
+  gboolean is_default = FALSE;
+  GConfValue *val;
+  GError *error;
+  GConfEntry *entry;
+  gchar *schema_name;
+
+  CHECK_OWNER_USE (conf);
+  
+  schema_name = NULL;
+  error = NULL;
+  val = gconf_engine_get_fuller (conf, key, locale, use_schema_default,
+                                 &is_default, &is_writable,
+                                 &schema_name, &error);
+  if (error != NULL)
+    {
+      g_propagate_error (err, error);
+      return NULL;
+    }
+
+  entry = gconf_entry_new_nocopy (g_strdup (key), val);
+
+  gconf_entry_set_is_default (entry, is_default);
+  gconf_entry_set_is_writable (entry, is_writable);
+  gconf_entry_set_schema_name (entry, schema_name);
+
+  g_free (schema_name);
+
+  return entry;
+}
+     
+GConfValue*  
+gconf_engine_get (GConfEngine* conf, const gchar* key, GError** err)
+{
+  return gconf_engine_get_with_locale (conf, key, NULL, err);
+}
+
+GConfValue*
+gconf_engine_get_with_locale (GConfEngine* conf, const gchar* key,
+			      const gchar* locale,
+			      GError** err)
+{
+  return gconf_engine_get_full (conf, key, locale, TRUE,
+				NULL, NULL, err);
+}
+
+GConfValue*
+gconf_engine_get_without_default (GConfEngine* conf, const gchar* key,
+				  GError** err)
+{
+  return gconf_engine_get_full (conf, key, NULL, FALSE, NULL, NULL, err);
+}
+
+GConfValue*
+gconf_engine_get_default_from_schema (GConfEngine* conf,
+                                      const gchar* key,
+                                      GError** err)
+{
+  GConfValue* val;
+  const gchar *db;
+  const gchar *locale;
+  DBusMessage *message, *reply;
+  DBusError error;
+  DBusMessageIter iter;
+  
+  g_return_val_if_fail(conf != NULL, NULL);
+  g_return_val_if_fail(key != NULL, NULL);
+  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
+
+  CHECK_OWNER_USE (conf);
+  
+  if (!gconf_key_check (key, err))
+    return NULL;
+
+  if (gconf_engine_is_local(conf))
+    {
+      gchar** locale_list;
+
+      locale_list = gconf_split_locale(gconf_current_locale());
+      
+      val = gconf_sources_query_default_value(conf->local_sources,
+                                              key,
+                                              (const gchar**)locale_list,
+                                              NULL,
+                                              err);
+
+      if (locale_list != NULL)
+        g_strfreev(locale_list);
+      
+      return val;
+    }
+
+  g_assert (!gconf_engine_is_local (conf));
+
+  db = gconf_engine_get_database (conf, TRUE, err);
+
+  if (db == NULL)
+    {
+      g_return_val_if_fail(err == NULL || *err != NULL, NULL);
+      return NULL;
+    }
+
+  message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					  db,
+					  GCONF_DBUS_DATABASE_INTERFACE,
+					  GCONF_DBUS_DATABASE_LOOKUP_DEFAULT);
+
+  locale = gconf_current_locale();
+  
+  dbus_message_append_args (message,
+			    DBUS_TYPE_STRING, &key,
+			    DBUS_TYPE_STRING, &locale,
+			    DBUS_TYPE_INVALID);
+
+  dbus_error_init (&error);
+  reply = dbus_connection_send_with_reply_and_block (global_conn, message, -1, &error);
+  dbus_message_unref (message);
+
+  if (gconf_handle_dbus_exception (reply, &error, err))
+    return NULL;
+
+  dbus_message_iter_init (reply, &iter);
+
+  /* If there is no struct (entry) here, there is no value. */
+  if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRUCT)
+    {
+      dbus_message_unref (reply);
+      return NULL;
+    }
+  
+  val = gconf_dbus_utils_get_value (&iter);
+  
+  dbus_message_unref (reply);
+  
+  if (!val)
+    {
+      if (err)
+	g_set_error (err, GCONF_ERROR,
+		     GCONF_ERROR_FAILED,
+		     _("Couldn't get value"));
+      
+      return NULL;
+    }
+  
+  return val;
+}
+
+gboolean
+gconf_engine_set (GConfEngine* conf, const gchar* key,
+                  const GConfValue* value, GError** err)
+{
+  const gchar *db;
+  DBusMessage *message, *reply;
+  DBusError error;
+  DBusMessageIter iter;
+
+  g_return_val_if_fail(conf != NULL, FALSE);
+  g_return_val_if_fail(key != NULL, FALSE);
+  g_return_val_if_fail(value != NULL, FALSE);
+  g_return_val_if_fail(value->type != GCONF_VALUE_INVALID, FALSE);
+  g_return_val_if_fail( (value->type != GCONF_VALUE_STRING) ||
+                        (gconf_value_get_string(value) != NULL) , FALSE );
+  g_return_val_if_fail( (value->type != GCONF_VALUE_LIST) ||
+                        (gconf_value_get_list_type(value) != GCONF_VALUE_INVALID), FALSE);
+  g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+
+  CHECK_OWNER_USE (conf);
+
+  if (!gconf_key_check (key, err))
+    return FALSE;
+
+  if (!gconf_value_validate (value, err))
+    return FALSE;
+  
+  if (gconf_engine_is_local (conf))
+    {
+      GError* error = NULL;
+      
+      gconf_sources_set_value (conf->local_sources, key, value, NULL, &error);
+
+      if (error != NULL)
+        {
+          if (err)
+            *err = error;
+          else
+            {
+              g_error_free (error);
+            }
+          return FALSE;
+        }
+      
+      return TRUE;
+    }
+
+  g_assert (!gconf_engine_is_local (conf));
+  
+  db = gconf_engine_get_database (conf, TRUE, err);
+
+  if (db == NULL)
+    {
+      g_return_val_if_fail(err == NULL || *err != NULL, FALSE);
+      
+      return FALSE;
+    }
+
+  message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					  db,
+					  GCONF_DBUS_DATABASE_INTERFACE,
+					  GCONF_DBUS_DATABASE_SET);
+  
+  dbus_message_append_args (message,
+			    DBUS_TYPE_STRING, &key,
+			    DBUS_TYPE_INVALID);
+
+  dbus_message_iter_init_append (message, &iter);
+  gconf_dbus_utils_append_value (&iter, value);
+
+  dbus_error_init (&error);
+  reply = dbus_connection_send_with_reply_and_block (global_conn, message, -1, &error);
+  dbus_message_unref (message);
+
+  if (gconf_handle_dbus_exception (reply, &error, err))
+    return FALSE;
+
+  g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+
+  dbus_message_unref (reply);
+
+  return TRUE;
+}
+
+gboolean
+gconf_engine_unset (GConfEngine* conf, const gchar* key, GError** err)
+{
+  const gchar *db;
+  DBusMessage *message, *reply;
+  DBusError error;
+  const gchar *empty;
+
+  g_return_val_if_fail (conf != NULL, FALSE);
+  g_return_val_if_fail (key != NULL, FALSE);
+  g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+
+  CHECK_OWNER_USE (conf);
+  
+  if (!gconf_key_check (key, err))
+    return FALSE;
+
+  if (gconf_engine_is_local (conf))
+    {
+      GError* error = NULL;
+      
+      gconf_sources_unset_value (conf->local_sources, key, NULL, NULL, &error);
+
+      if (error != NULL)
+        {
+          if (err)
+            *err = error;
+          else
+            {
+              g_error_free (error);
+            }
+          return FALSE;
+        }
+      
+      return TRUE;
+    }
+
+  g_assert(!gconf_engine_is_local(conf));
+  
+  db = gconf_engine_get_database (conf, TRUE, err);
+
+  if (db == NULL)
+    {
+      g_return_val_if_fail(err == NULL || *err != NULL, FALSE);
+
+      return FALSE;
+    }
+
+  message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					  db,
+					  GCONF_DBUS_DATABASE_INTERFACE,
+					  GCONF_DBUS_DATABASE_UNSET);
+
+  empty = "";
+  dbus_message_append_args (message,
+			    DBUS_TYPE_STRING, &key,
+			    DBUS_TYPE_STRING, &empty,
+			    DBUS_TYPE_INVALID);
+
+  dbus_error_init (&error);
+  reply = dbus_connection_send_with_reply_and_block (global_conn, message, -1, &error);
+  dbus_message_unref (message);
+  
+  if (gconf_handle_dbus_exception (reply, &error, err))
+    return FALSE;
+
+  g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+
+  dbus_message_unref (reply);
+
+  return TRUE;
+}
+
+/**
+ * gconf_engine_recursive_unset:
+ * @engine: a #GConfEngine
+ * @key: a key or directory name
+ * @flags: change how the unset is done
+ * @err: return location for a #GError, or %NULL to ignore errors
+ * 
+ * Unsets all keys below @key, including @key itself.  If any unset
+ * fails, continues on to unset as much as it can. The first
+ * failure is returned in @err.
+ *
+ * Returns: %FALSE if error is set
+ **/
+gboolean
+gconf_engine_recursive_unset (GConfEngine    *conf,
+                              const char     *key,
+                              GConfUnsetFlags flags,
+                              GError        **err)
+{
+  const gchar *db;
+  DBusMessage *message, *reply;
+  DBusError error;
+  guint dbus_flags;
+  const gchar *empty;
+  
+  g_return_val_if_fail (conf != NULL, FALSE);
+  g_return_val_if_fail (key != NULL, FALSE);
+  g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+
+  CHECK_OWNER_USE (conf);
+  
+  if (!gconf_key_check (key, err))
+    return FALSE;
+
+  if (gconf_engine_is_local (conf))
+    {
+      GError* error = NULL;
+      
+      gconf_sources_recursive_unset (conf->local_sources, key, NULL,
+                                     flags, NULL, &error);
+
+      if (error != NULL)
+        {
+          if (err)
+            *err = error;
+          else
+            {
+              g_error_free (error);
+            }
+          return FALSE;
+        }
+      
+      return TRUE;
+    }
+
+  g_assert (!gconf_engine_is_local (conf));
+  
+  dbus_flags = 0;
+  if (flags & GCONF_UNSET_INCLUDING_SCHEMA_NAMES)
+    dbus_flags |= GCONF_DBUS_UNSET_INCLUDING_SCHEMA_NAMES;
+
+  db = gconf_engine_get_database (conf, TRUE, err);
+
+  if (db == NULL)
+    {
+      g_return_val_if_fail (err == NULL || *err != NULL, FALSE);
+
+      return FALSE;
+    }
+
+  message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					  db,
+					  GCONF_DBUS_DATABASE_INTERFACE,
+					  GCONF_DBUS_DATABASE_RECURSIVE_UNSET);
+
+  empty = "";
+  dbus_message_append_args (message,
+			    DBUS_TYPE_STRING, &key,
+			    DBUS_TYPE_STRING, &empty,
+			    DBUS_TYPE_UINT32, &dbus_flags,
+			    DBUS_TYPE_INVALID);
+
+  dbus_error_init (&error);
+  reply = dbus_connection_send_with_reply_and_block (global_conn, message, -1, &error);
+  dbus_message_unref (message);
+  
+  if (gconf_handle_dbus_exception (reply, &error, err))
+    return FALSE;
+
+  g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+
+  dbus_message_unref (reply);
+
+  return TRUE;
+}
+
+gboolean
+gconf_engine_associate_schema  (GConfEngine* conf, const gchar* key,
+                                const gchar* schema_key, GError** err)
+{
+  const gchar *db;
+  DBusMessage *message, *reply;
+  DBusError error;
+  
+  g_return_val_if_fail (conf != NULL, FALSE);
+  g_return_val_if_fail (key != NULL, FALSE);
+  g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+  
+  if (!gconf_key_check (key, err))
+    return FALSE;
+
+  if (schema_key && !gconf_key_check (schema_key, err))
+    return FALSE;
+
+  if (gconf_engine_is_local(conf))
+    {
+      GError* error = NULL;
+      
+      gconf_sources_set_schema (conf->local_sources, key, schema_key, &error);
+
+      if (error != NULL)
+        {
+          if (err)
+            *err = error;
+          else
+            {
+              g_error_free(error);
+            }
+          return FALSE;
+        }
+      
+      return TRUE;
+    }
+
+  g_assert (!gconf_engine_is_local (conf));
+  
+  db = gconf_engine_get_database (conf, TRUE, err);
+
+  if (db == NULL)
+    {
+      g_return_val_if_fail (err == NULL || *err != NULL, FALSE);
+
+      return FALSE;
+    }
+
+  message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					  db,
+					  GCONF_DBUS_DATABASE_INTERFACE,
+					  GCONF_DBUS_DATABASE_SET_SCHEMA);
+
+   /* Empty schema string means unset. */
+  schema_key = schema_key ? schema_key : "";
+  
+  dbus_message_append_args (message,
+			    DBUS_TYPE_STRING, &key,
+			    DBUS_TYPE_STRING, &schema_key,
+			    DBUS_TYPE_INVALID);
+
+  dbus_error_init (&error);
+  reply = dbus_connection_send_with_reply_and_block (global_conn, message, -1, &error);
+  dbus_message_unref (message);
+  
+  if (gconf_handle_dbus_exception (reply, &error, err))
+    return FALSE;
+  
+  g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+
+  dbus_message_unref (reply);
+
+  return TRUE;
+}
+
+static void
+qualify_entries (GSList *entries, const char *dir)
+{
+  GSList *tmp = entries;
+  
+  while (tmp != NULL)
+    {
+      GConfEntry *entry = tmp->data;
+      gchar *full;
+
+      full = gconf_concat_dir_and_key (dir, entry->key);
+
+      g_free (entry->key);
+      entry->key = full;
+
+      tmp = g_slist_next (tmp);
+    }
+}
+
+GSList*      
+gconf_engine_all_entries (GConfEngine* conf, const gchar* dir, GError** err)
+{
+  GSList* entries = NULL;
+  const gchar *db;
+  DBusMessage *message, *reply;
+  DBusError error;
+  DBusMessageIter iter;
+  const gchar *locale;
+
+  g_return_val_if_fail(conf != NULL, NULL);
+  g_return_val_if_fail(dir != NULL, NULL);
+  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
+
+  CHECK_OWNER_USE (conf);
+  
+  if (!gconf_key_check(dir, err))
+    return NULL;
+
+  if (gconf_engine_is_local(conf))
+    {
+      GError* error = NULL;
+      gchar** locale_list;
+      GSList* retval;
+      
+      locale_list = gconf_split_locale(gconf_current_locale());
+      
+      retval = gconf_sources_all_entries(conf->local_sources,
+                                         dir,
+                                         (const gchar**)locale_list,
+                                         &error);
+
+      if (locale_list)
+        g_strfreev(locale_list);
+      
+      if (error != NULL)
+        {
+          if (err)
+            *err = error;
+          else
+            {
+              g_error_free(error);
+            }
+
+          g_assert(retval == NULL);
+          
+          return NULL;
+        }
+
+      qualify_entries (retval, dir);
+      
+      return retval;
+    }
+
+  g_assert(!gconf_engine_is_local(conf));
+  
+  db = gconf_engine_get_database (conf, TRUE, err);
+
+  if (db == NULL)
+    {
+      g_return_val_if_fail(err == NULL || *err != NULL, NULL);
+
+      return NULL;
+    }
+
+  message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					  db,
+					  GCONF_DBUS_DATABASE_INTERFACE,
+					  GCONF_DBUS_DATABASE_GET_ALL_ENTRIES);
+
+  locale = gconf_current_locale ();
+  dbus_message_append_args (message,
+			    DBUS_TYPE_STRING, &dir,
+			    DBUS_TYPE_STRING, &locale,
+			    DBUS_TYPE_INVALID);
+  
+  dbus_error_init (&error);
+  reply = dbus_connection_send_with_reply_and_block (global_conn, message, -1, &error);
+  dbus_message_unref (message);
+  
+  if (gconf_handle_dbus_exception (reply, &error, err))
+    return NULL;
+  
+  g_return_val_if_fail (err == NULL || *err == NULL, NULL);
+
+  dbus_message_iter_init (reply, &iter);
+  
+  entries = gconf_dbus_utils_get_entries (&iter, dir);
+  
+  dbus_message_unref (reply);
+
+  return entries;
+}
+
+static void
+qualify_keys (GSList *keys, const char *dir)
+{
+  GSList *tmp = keys;
+  while (tmp != NULL)
+    {
+      char *key = tmp->data;
+      gchar *full;
+
+      full = gconf_concat_dir_and_key (dir, key);
+
+      g_free (tmp->data);
+      tmp->data = full;
+
+      tmp = g_slist_next (tmp);
+    }
+}
+
+GSList*      
+gconf_engine_all_dirs(GConfEngine* conf, const gchar* dir, GError** err)
+{
+  GSList* subdirs = NULL;
+  const gchar *db;
+  DBusMessage *message, *reply;
+  DBusError error;
+  DBusMessageIter iter;
+  DBusMessageIter array_iter;
+  
+  g_return_val_if_fail(conf != NULL, NULL);
+  g_return_val_if_fail(dir != NULL, NULL);
+  g_return_val_if_fail(err == NULL || *err == NULL, NULL);
+  
+  CHECK_OWNER_USE (conf);
+  
+  if (!gconf_key_check(dir, err))
+    return NULL;
+  
+  if (gconf_engine_is_local(conf))
+    {
+      GError* error = NULL;
+      GSList* retval;
+      
+      retval = gconf_sources_all_dirs(conf->local_sources,
+                                      dir,
+                                      &error);
+      
+      if (error != NULL)
+        {
+          if (err)
+            *err = error;
+          else
+            {
+              g_error_free(error);
+            }
+
+          g_assert(retval == NULL);
+          
+          return NULL;
+        }
+      
+      qualify_keys (retval, dir);
+      
+      return retval;
+    }
+  
+  g_assert(!gconf_engine_is_local(conf));
+
+  db = gconf_engine_get_database (conf, TRUE, err);
+
+  if (db == NULL)
+    {
+      g_return_val_if_fail (err == NULL || *err != NULL, NULL);
+      
+      return NULL;
+    }
+  
+  message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					  db,
+					  GCONF_DBUS_DATABASE_INTERFACE,
+					  GCONF_DBUS_DATABASE_GET_ALL_DIRS);
+
+  dbus_message_append_args (message,
+			    DBUS_TYPE_STRING, &dir,
+			    DBUS_TYPE_INVALID);
+  
+  dbus_error_init (&error);
+  reply = dbus_connection_send_with_reply_and_block (global_conn, message, -1, &error);
+  dbus_message_unref (message);
+  
+  if (gconf_handle_dbus_exception (reply, &error, err))
+    return NULL;
+
+  g_return_val_if_fail (err == NULL || *err == NULL, NULL);
+
+  dbus_message_iter_init (reply, &iter);
+
+  dbus_message_iter_recurse (&iter, &array_iter);
+  while (dbus_message_iter_get_arg_type (&array_iter) == DBUS_TYPE_STRING)
+    {
+      const gchar *key;
+      gchar       *s;
+      
+      dbus_message_iter_get_basic (&array_iter, &key);
+      
+      s = gconf_concat_dir_and_key (dir, key);
+      subdirs = g_slist_prepend (subdirs, s);
+      
+      if (!dbus_message_iter_next (&array_iter))
+	break;
+    }
+  
+  dbus_message_unref (reply);
+
+  return subdirs;
+}
+
+/* annoyingly, this is REQUIRED for local sources */
+void 
+gconf_engine_suggest_sync(GConfEngine* conf, GError** err)
+{
+  const gchar *db;
+  DBusMessage *message;
+  DBusMessage *reply;
+  DBusError error;
+  
+  g_return_if_fail(conf != NULL);
+  g_return_if_fail(err == NULL || *err == NULL);
+
+  CHECK_OWNER_USE (conf);
+  
+  if (gconf_engine_is_local(conf))
+    {
+      GError* error = NULL;
+      
+      gconf_sources_sync_all(conf->local_sources,
+                             &error);
+      
+      if (error != NULL)
+        {
+          if (err)
+            *err = error;
+          else
+            {
+              g_error_free(error);
+            }
+          return;
+        }
+      
+      return;
+    }
+
+  g_assert(!gconf_engine_is_local(conf));
+
+  db = gconf_engine_get_database (conf, TRUE, err);
+
+  if (db == NULL)
+    {
+      g_return_if_fail (err == NULL || *err != NULL);
+    }
+  
+  message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					  db,
+					  GCONF_DBUS_DATABASE_INTERFACE,
+					  GCONF_DBUS_DATABASE_SUGGEST_SYNC);
+
+  dbus_error_init (&error);
+  reply = dbus_connection_send_with_reply_and_block (global_conn, message, -1, &error);
+  dbus_message_unref (message);
+
+  if (!gconf_handle_dbus_exception (reply, &error, err))
+    dbus_message_unref (reply);
+}
+
+void 
+gconf_clear_cache(GConfEngine* conf, GError** err)
+{
+  g_return_if_fail(conf != NULL);
+  g_return_if_fail(err == NULL || *err == NULL);
+
+  /* don't disallow non-owner use here since you can't do this
+   * via GConfClient API and calling this function won't break
+   * GConfClient anyway
+   */
+  
+  if (gconf_engine_is_local(conf))
+    {
+      GError* error = NULL;
+      
+      gconf_sources_clear_cache(conf->local_sources);
+      
+      if (error != NULL)
+        {
+          if (err)
+            *err = error;
+          else
+            {
+              g_error_free(error);
+            }
+          return;
+        }
+      
+      return;
+    }
+
+  /* Do nothing for non-local case. */
+}
+
+void 
+gconf_synchronous_sync(GConfEngine* conf, GError** err)
+{
+  g_return_if_fail(conf != NULL);
+  g_return_if_fail(err == NULL || *err == NULL);
+
+  if (gconf_engine_is_local(conf))
+    {
+      GError* error = NULL;
+      
+      gconf_sources_sync_all(conf->local_sources, &error);
+      
+      if (error != NULL)
+        {
+          if (err)
+            *err = error;
+          else
+            {
+              g_error_free(error);
+            }
+          return;
+        }
+      
+      return;
+    }
+
+  /* Do nothing for non-local case. */
+}
+
+gboolean
+gconf_engine_dir_exists (GConfEngine *conf, const gchar *dir, GError** err)
+{
+  const gchar *db;
+  dbus_bool_t exists;
+  DBusMessage *message, *reply;
+  DBusError error;
+  
+  g_return_val_if_fail(conf != NULL, FALSE);
+  g_return_val_if_fail(dir != NULL, FALSE);
+  g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+
+  CHECK_OWNER_USE (conf);
+  
+  if (!gconf_key_check(dir, err))
+    return FALSE;
+  
+  if (gconf_engine_is_local(conf))
+    {
+      return gconf_sources_dir_exists(conf->local_sources,
+                                      dir,
+                                      err);
+    }
+
+  g_assert(!gconf_engine_is_local(conf));
+  
+  db = gconf_engine_get_database(conf, TRUE, err);
+  
+  if (db == NULL)
+    {
+      g_return_val_if_fail(err == NULL || *err != NULL, FALSE);
+
+      return FALSE;
+    }
+
+  message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					  db,
+					  GCONF_DBUS_DATABASE_INTERFACE,
+					  GCONF_DBUS_DATABASE_DIR_EXISTS);
+  
+  dbus_message_append_args (message,
+			    DBUS_TYPE_STRING, &dir,
+			    DBUS_TYPE_INVALID);
+  
+  dbus_error_init (&error);
+  reply = dbus_connection_send_with_reply_and_block (global_conn, message, -1, &error);
+  dbus_message_unref (message);
+ 
+  if (gconf_handle_dbus_exception (reply, &error, err))
+    return FALSE;
+
+  g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+
+  exists = FALSE;
+  dbus_message_get_args (reply,
+			 NULL,
+			 DBUS_TYPE_BOOLEAN, &exists,
+			 DBUS_TYPE_INVALID);
+
+  dbus_message_unref (reply);
+
+  return !!exists;
+}
+
+void
+gconf_engine_remove_dir (GConfEngine* conf,
+                         const gchar* dir,
+                         GError** err)
+{
+  g_return_if_fail(conf != NULL);
+  g_return_if_fail(dir != NULL);
+  g_return_if_fail(err == NULL || *err == NULL);
+
+  /* FIXME we have no GConfClient method for doing this */
+  /*   CHECK_OWNER_USE (conf); */
+  
+  if (!gconf_key_check(dir, err))
+    return;
+
+  if (gconf_engine_is_local(conf))
+    {
+      gconf_sources_remove_dir(conf->local_sources, dir, err);
+      return;
+    }
+}
+
+static void
+cnxn_get_all_func (gpointer key,
+		   gpointer value,
+		   gpointer user_data)
+{
+  GList **list = user_data;
+  
+  *list = g_list_prepend (*list, value);
+}
+
+static void
+engines_by_db_get_all_func (gpointer key,
+			    gpointer value,
+			    gpointer user_data)
+{
+  GList **list = user_data;
+
+  *list = g_list_prepend (*list, value);
+}
+
+static void
+reinitialize_databases (void)
+{
+  GList *engines = NULL, *engine;
+  GList *cnxns, *l;
+  GConfEngine *conf;
+  
+  if (engines_by_db)
+    g_hash_table_foreach (engines_by_db,
+			  engines_by_db_get_all_func,
+			  &engines);
+
+  /* Reset databases. */
+  for (engine = engines; engine; engine = engine->next)
+    {
+      conf = engine->data;
+
+      g_hash_table_remove (engines_by_db, conf->database);  
+      ensure_database (conf, FALSE, NULL);
+    }
+  
+  /* Re-add notifications. */
+  for (engine = engines; engine; engine = engine->next)
+    {
+      conf = engine->data;
+      
+      cnxns = NULL;
+      g_hash_table_foreach (conf->notify_ids,
+			    cnxn_get_all_func,
+			    &cnxns);
+      
+      for (l = cnxns; l; l = l->next)
+	{
+	  GConfCnxn *cnxn = l->data;
+	  
+	  send_notify_add (conf, cnxn, NULL);
+	}
+      
+      g_list_free (cnxns);
+    }
+  
+  g_list_free (engines);
+}
+
+static DBusHandlerResult
+gconf_dbus_message_filter (DBusConnection    *dbus_conn,
+			   DBusMessage       *message,
+			   gpointer           user_data)
+{
+  if (dbus_message_is_method_call (message,
+				   GCONF_DBUS_CLIENT_INTERFACE,
+				   "Notify"))
+    {
+      return handle_notify (dbus_conn, message, NULL);
+    }
+  else if (dbus_message_is_signal (message,
+				   DBUS_INTERFACE_LOCAL,
+				   "Disconnected"))
+    {
+      dbus_connection_unref (global_conn);
+      global_conn = NULL;
+      service_running = FALSE;
+      dbus_disconnected = TRUE;
+
+      g_warning ("Got Disconnected from DBus.\n");
+
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+  else if (dbus_message_is_signal (message,
+				   DBUS_INTERFACE_DBUS,
+				   "NameOwnerChanged"))
+    {
+      char *service;
+      char *old_owner;
+      char *new_owner;
+
+      dbus_message_get_args (message,
+			     NULL,
+			     DBUS_TYPE_STRING, &service,
+			     DBUS_TYPE_STRING, &old_owner,
+			     DBUS_TYPE_STRING, &new_owner,
+			     DBUS_TYPE_INVALID);
+      
+      if (strcmp (service, GCONF_DBUS_SERVICE) != 0)
+	{
+	  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	}
+      
+      if (strcmp (old_owner, "") == 0) 
+	{
+	  /* GConfd is back. */
+	  service_running = TRUE;
+	  
+	  if (needs_reconnect)
+	    {
+	      needs_reconnect = FALSE;
+	      reinitialize_databases ();
+	    }
+	  
+	  d(g_print ("*** Gconf Service created\n"));
+	}
+
+      if (strcmp (new_owner, "") == 0) 
+	{
+	  /* GConfd is gone, set the state so we can detect that we're down. */
+	  service_running = FALSE;
+	  needs_reconnect = TRUE;
+  
+	  d(g_print ("*** GConf Service deleted\n"));
+	}
+      
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;      
+    }
+
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+} 
+
+/* FIXME: What should this do in the D-BUS case? */
+static void
+gconf_detach_config_server(void)
+{  
+  if (engines_by_db != NULL)
+    {
+      g_hash_table_destroy (engines_by_db);
+      engines_by_db = NULL;
+    }
+}
+
+/**
+ * gconf_debug_shutdown:
+ * @void: 
+ * 
+ * Detach from the config server and release
+ * all related resources
+ **/
+int
+gconf_debug_shutdown (void)
+{
+  gconf_detach_config_server ();
+
+  return 0;
+}
+
+static DBusHandlerResult
+handle_notify (DBusConnection *connection,
+	       DBusMessage *message,
+	       GConfEngine *conf2)
+{
+  GConfEngine *conf;
+  gchar *key, *schema_name;
+  gboolean is_default, is_writable;
+  DBusMessageIter iter;
+  GConfValue *value;
+  GConfEntry* entry;
+  GList *list, *l;
+  gboolean match = FALSE;
+  gchar *namespace_section, *db;
+
+  dbus_message_iter_init (message, &iter);
+
+  dbus_message_iter_get_basic (&iter, &db);
+
+  if (!dbus_message_iter_next (&iter))
+    {
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+  
+  dbus_message_iter_get_basic (&iter, &namespace_section);
+
+  if (!dbus_message_iter_next (&iter))
+    {
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+
+  conf = lookup_engine_by_database (db);
+
+  g_return_val_if_fail (conf != NULL, DBUS_HANDLER_RESULT_NOT_YET_HANDLED);
+  if (conf == NULL)
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  
+  if (!gconf_dbus_utils_get_entry_values (&iter,
+					  &key,
+					  &value,
+					  &is_default,
+					  &is_writable,
+					  &schema_name))
+    {
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+  
+  d(g_print ("Got notify on %s (%s)\n", key, namespace_section));
+
+  list = gconf_cnxn_lookup_dir (conf, namespace_section);
+  for (l = list; l; l = l->next)
+    {
+      GConfCnxn *cnxn = l->data;
+
+      d(g_print ("match? %s\n", cnxn->namespace_section));
+      
+      if (strcmp (cnxn->namespace_section, namespace_section) == 0)
+	{
+	  d(g_print ("yes: %s\n", key));
+	  
+	  entry = gconf_entry_new (key, value);
+	  gconf_cnxn_notify (cnxn, entry);
+	  gconf_entry_free (entry);
+	  
+	  match = TRUE;
+	}
+    }
+
+  if (value)
+    gconf_value_free (value);
+
+  if (!match)
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+
+/*
+ * Daemon control
+ */
+
+void          
+gconf_shutdown_daemon (GError** err)
+{
+  DBusMessage *message;
+
+  /* Don't want to spawn it if it's already down */
+  if (global_conn == NULL || !service_running)
+    return;
+  
+  message = dbus_message_new_method_call (GCONF_DBUS_SERVICE,
+					  GCONF_DBUS_SERVER_OBJECT,
+					  GCONF_DBUS_SERVER_INTERFACE,
+					  GCONF_DBUS_SERVER_SHUTDOWN);
+
+  dbus_connection_send (global_conn, message, 0);
+  dbus_connection_flush (global_conn);
+
+  dbus_message_unref (message);
+}
+
+gboolean
+gconf_ping_daemon (void)
+{
+  if (global_conn == NULL)
+  {
+    if (!ensure_dbus_connection ())
+    {
+      return FALSE;
+    }
+    g_assert (global_conn != NULL);
+  }
+
+  if (!dbus_bus_name_has_owner(global_conn,
+                               GCONF_DBUS_SERVICE,
+                               NULL))
+  {
+    service_running = FALSE;
+  }
+  else
+  {
+    service_running = TRUE;
+  }
+
+  return service_running;
+}
+
+gboolean
+gconf_spawn_daemon (GError **err)
+{
+  return ensure_service (TRUE, err);
+}
+
+
diff --git a/gconf/gconf-dbus.h b/gconf/gconf-dbus.h
new file mode 100644
index 0000000..e69de29
diff --git a/gconf/gconfd-dbus.c b/gconf/gconfd-dbus.c
new file mode 100644
index 0000000..cb0ecac
--- /dev/null
+++ b/gconf/gconfd-dbus.c
@@ -0,0 +1,392 @@
+/* GConf
+ * Copyright (C) 2003 Imendio HB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <string.h>
+#include "gconf-database-dbus.h"
+#include "gconf-dbus-utils.h"
+#include "gconfd.h"
+#include "gconfd-dbus.h"
+
+static DBusConnection *bus_conn;
+static const char *server_path = "/org/gnome/GConf/Server";
+static gint nr_of_connections = 0;
+
+static void              server_unregistered_func (DBusConnection *connection,
+						   void           *user_data);
+static DBusHandlerResult server_message_func      (DBusConnection  *connection,
+                                                   DBusMessage     *message,
+						   void            *user_data);
+static DBusHandlerResult server_filter_func       (DBusConnection  *connection,
+						   DBusMessage     *message,
+						   void            *user_data);
+static void              server_handle_get_db     (DBusConnection  *connection,
+                                                   DBusMessage     *message);
+static void              server_handle_shutdown   (DBusConnection  *connection,
+                                                   DBusMessage     *message);
+static void          server_handle_get_default_db (DBusConnection  *connection,
+                                                   DBusMessage     *message);
+
+
+static DBusObjectPathVTable
+server_vtable = {
+  server_unregistered_func,
+  server_message_func,
+  NULL,
+};
+
+static void
+server_unregistered_func (DBusConnection *connection, void *user_data)
+{
+  g_print ("Server object unregistered\n");
+  nr_of_connections = 0;
+}
+
+static DBusHandlerResult
+server_message_func (DBusConnection *connection,
+		     DBusMessage    *message,
+		     void           *user_data)
+{
+  if (gconfd_dbus_check_in_shutdown (connection, message))
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+  if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL) 
+    {
+      g_print ("Not a method call\n");
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+                                                                                
+  if (strcmp (dbus_message_get_interface (message),
+	      GCONF_DBUS_SERVER_INTERFACE) != 0) 
+    {
+      g_print ("Not correct interface: \"%s\"\n",
+	       dbus_message_get_interface (message));
+      return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+    }
+                                                                                
+  if (dbus_message_is_method_call (message,
+				   GCONF_DBUS_SERVER_INTERFACE,
+				   GCONF_DBUS_SERVER_GET_DEFAULT_DB))
+    server_handle_get_default_db (connection, message);
+  else if (dbus_message_is_method_call (message,
+					GCONF_DBUS_SERVER_INTERFACE,
+					GCONF_DBUS_SERVER_GET_DB))
+    server_handle_get_db (connection, message);
+  else if (dbus_message_is_method_call (message,
+					GCONF_DBUS_SERVER_INTERFACE,
+					GCONF_DBUS_SERVER_SHUTDOWN)) 
+    server_handle_shutdown (connection, message);
+  else 
+    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+  
+  return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+static DBusHandlerResult
+server_filter_func (DBusConnection  *connection,
+		    DBusMessage     *message,
+		    void            *user_data)
+{
+  if (dbus_message_is_signal (message,
+			      DBUS_INTERFACE_LOCAL,
+			      "Disconnected")) {
+	  /* Exit cleanly. */
+	  gconfd_main_quit ();
+  }
+  
+  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void
+server_real_handle_get_db (DBusConnection *connection,
+			   DBusMessage    *message,
+			   GSList         *addresses)
+{
+  GConfDatabase *db;
+  DBusMessage   *reply;
+  GError        *gerror = NULL;
+  const gchar   *str;
+ 
+  if (gconfd_dbus_check_in_shutdown (connection, message))
+    return;
+
+  db = gconfd_obtain_database (addresses, &gerror);
+
+  if (gconfd_dbus_set_exception (connection, message, &gerror))
+    return;
+  
+  reply = dbus_message_new_method_return (message);
+  if (reply == NULL) 
+      g_error ("No memory");
+
+  str = gconf_database_dbus_get_path (db);
+  dbus_message_append_args (reply,
+			    DBUS_TYPE_STRING, &str,
+			    DBUS_TYPE_INVALID);
+  
+  if (!dbus_connection_send (connection, reply, NULL)) 
+    g_error ("No memory");
+
+  dbus_message_unref (reply);
+}
+
+static void
+server_handle_get_default_db (DBusConnection *connection, 
+			      DBusMessage *message)
+{
+  server_real_handle_get_db (connection, message, NULL);
+}
+
+static void
+server_handle_get_db (DBusConnection *connection, DBusMessage *message)
+{
+  char   *addresses;
+  GSList *list;
+
+  if (!gconfd_dbus_get_message_args (connection, message, 
+				     DBUS_TYPE_STRING, &addresses,
+				     DBUS_TYPE_INVALID))
+    return;
+
+  list = gconf_persistent_name_get_address_list (addresses);
+
+  server_real_handle_get_db (connection, message, list);
+
+  g_slist_foreach (list, (GFunc) g_free, NULL);
+  g_slist_free (list);
+}
+
+static void
+server_handle_shutdown (DBusConnection *connection, DBusMessage *message)
+{
+  DBusMessage *reply;
+
+  if (gconfd_dbus_check_in_shutdown (connection, message))
+    return;
+
+  gconf_log(GCL_DEBUG, _("Shutdown request received"));
+
+  reply = dbus_message_new_method_return (message);
+  dbus_connection_send (connection, reply, NULL);
+  dbus_message_unref (reply);
+  
+  dbus_connection_unregister_object_path (connection, server_path);
+
+  gconfd_main_quit();
+}
+
+gboolean
+gconfd_dbus_init (void)
+{
+  DBusError error;
+  gint      ret;
+
+  dbus_error_init (&error);
+
+  bus_conn = dbus_bus_get (DBUS_BUS_SESSION, &error);
+
+  if (!bus_conn) 
+   {
+     gconf_log (GCL_ERR, _("Daemon failed to connect to the D-BUS daemon:\n%s"),
+		error.message);
+     dbus_error_free (&error);
+     return FALSE;
+   }
+
+  /* We handle exiting ourselves on disconnect. */
+  dbus_connection_set_exit_on_disconnect (bus_conn, FALSE);
+
+  /* Add message filter to handle Disconnected. */
+  dbus_connection_add_filter (bus_conn,
+			      (DBusHandleMessageFunction) server_filter_func,
+			      NULL, NULL);
+  
+  ret = dbus_bus_request_name (bus_conn,
+			       GCONF_DBUS_SERVICE,
+			       0,
+			       &error);
+
+  if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+    {
+      gconf_log (GCL_ERR, "Daemon could not become primary owner");
+      return FALSE;
+    }
+  
+  if (dbus_error_is_set (&error)) 
+    {
+      gconf_log (GCL_ERR, _("Daemon failed to acquire gconf service:\n%s"),
+		 error.message);
+      dbus_error_free (&error);
+      return FALSE;
+    }
+
+  if (!dbus_connection_register_object_path (bus_conn,
+					     server_path,
+					     &server_vtable,
+					     NULL))
+    {
+      gconf_log (GCL_ERR, _("Failed to register server object with the D-BUS bus daemon"));
+      return FALSE;
+    }
+  
+  
+  nr_of_connections = 1;
+  dbus_connection_setup_with_g_main (bus_conn, NULL);
+  
+  return TRUE;
+}
+
+guint
+gconfd_dbus_client_count (void)
+{
+  return nr_of_connections;
+}
+
+gboolean
+gconfd_dbus_get_message_args (DBusConnection *connection,
+			      DBusMessage    *message,
+			      int             first_arg_type,
+			      ...)
+{
+  gboolean retval;
+  va_list var_args;
+                                                                                
+  va_start (var_args, first_arg_type);
+  retval = dbus_message_get_args_valist (message, NULL, first_arg_type, var_args);
+  va_end (var_args);
+ 
+  if (!retval)
+    {
+      DBusMessage *reply;
+       
+      reply = dbus_message_new_error (message, GCONF_DBUS_ERROR_FAILED,
+				      _("Got a malformed message."));
+      dbus_connection_send (connection, reply, NULL);
+      dbus_message_unref (reply);
+       
+      return FALSE;
+    }
+ 
+  return TRUE;
+}
+
+gboolean 
+gconfd_dbus_set_exception (DBusConnection  *connection,
+			   DBusMessage     *message,
+			   GError         **error)
+{
+  GConfError en;
+  const char *name = NULL;
+  DBusMessage *reply;
+                                                                                
+  if (error == NULL || *error == NULL)
+    return FALSE;
+                                                                                
+  en = (*error)->code;
+                                                                                
+  /* success is not supposed to get set */
+  g_return_val_if_fail(en != GCONF_ERROR_SUCCESS, FALSE);
+
+  switch (en)
+    {
+    case GCONF_ERROR_FAILED:
+      name = GCONF_DBUS_ERROR_FAILED;
+      break;
+    case GCONF_ERROR_NO_PERMISSION:
+      name = GCONF_DBUS_ERROR_NO_PERMISSION;
+      break;
+    case GCONF_ERROR_BAD_ADDRESS:
+      name = GCONF_DBUS_ERROR_BAD_ADDRESS;
+      break;
+    case GCONF_ERROR_BAD_KEY:
+      name = GCONF_DBUS_ERROR_BAD_KEY;
+      break;
+    case GCONF_ERROR_PARSE_ERROR:
+      name = GCONF_DBUS_ERROR_PARSE_ERROR;
+      break;
+    case GCONF_ERROR_CORRUPT:
+      name = GCONF_DBUS_ERROR_CORRUPT;
+      break;
+    case GCONF_ERROR_TYPE_MISMATCH:
+      name = GCONF_DBUS_ERROR_TYPE_MISMATCH;
+      break;
+    case GCONF_ERROR_IS_DIR:
+      name = GCONF_DBUS_ERROR_IS_DIR;
+      break;
+    case GCONF_ERROR_IS_KEY:
+      name = GCONF_DBUS_ERROR_IS_KEY;
+      break;
+    case GCONF_ERROR_NO_WRITABLE_DATABASE:
+      name = GCONF_DBUS_ERROR_NO_WRITABLE_DATABASE;
+      break;
+    case GCONF_ERROR_IN_SHUTDOWN:
+      name = GCONF_DBUS_ERROR_IN_SHUTDOWN;
+      break;
+    case GCONF_ERROR_OVERRIDDEN:
+      name = GCONF_DBUS_ERROR_OVERRIDDEN;
+      break;
+    case GCONF_ERROR_LOCK_FAILED:
+      name = GCONF_DBUS_ERROR_LOCK_FAILED;
+      break;
+    case GCONF_ERROR_OAF_ERROR:
+    case GCONF_ERROR_LOCAL_ENGINE:
+    case GCONF_ERROR_NO_SERVER:
+    case GCONF_ERROR_SUCCESS:
+    default:
+      gconf_log (GCL_ERR, "Unhandled error code %d", en);
+      g_assert_not_reached();
+      break;
+    }
+                                                                                
+  reply = dbus_message_new_error (message, name, (*error)->message);
+  dbus_connection_send (connection, reply, NULL);
+  dbus_message_unref (reply);
+                                                                                
+  return TRUE;
+}
+
+gboolean
+gconfd_dbus_check_in_shutdown (DBusConnection *connection,
+                               DBusMessage    *message)
+{
+  if (gconfd_in_shutdown ())
+    {
+      DBusMessage *reply;
+       
+      reply = dbus_message_new_error (message,
+				      GCONF_DBUS_ERROR_IN_SHUTDOWN,
+				      _("The GConf daemon is currently shutting down."));
+      dbus_connection_send (connection, reply, NULL);
+      dbus_message_unref (reply);
+       
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+DBusConnection *
+gconfd_dbus_get_connection (void)
+{
+  return bus_conn;
+}
+
diff --git a/gconf/gconfd-dbus.h b/gconf/gconfd-dbus.h
new file mode 100644
index 0000000..40695ab
--- /dev/null
+++ b/gconf/gconfd-dbus.h
@@ -0,0 +1,42 @@
+/* GConf
+ * Copyright (C) 2003  CodeFactory AB
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef GCONF_GCONFD_DBUS_H
+#define GCONF_GCONFD_DBUS_H
+
+#include <dbus/dbus.h>
+
+gboolean gconfd_dbus_init                     (void);
+gboolean gconfd_dbus_check_in_shutdown        (DBusConnection   *connection,
+					       DBusMessage      *message);
+guint    gconfd_dbus_client_count             (void);
+
+/* Convenience function copied from andercas old code */
+gboolean gconfd_dbus_get_message_args         (DBusConnection *connection,
+					       DBusMessage    *message,
+					       int             first_arg_type,
+					       ...);
+gboolean gconfd_dbus_set_exception            (DBusConnection  *connection,
+					       DBusMessage     *message,
+					       GError         **error);
+gboolean gconfd_dbus_check_in_shutdown        (DBusConnection *connection,
+					       DBusMessage    *message);
+DBusConnection *gconfd_dbus_get_connection    (void);
+
+#endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]