summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Hult <rhult@src.gnome.org>2003-11-24 12:17:24 +0000
committerRichard Hult <rhult@src.gnome.org>2003-11-24 12:17:24 +0000
commit4b3c6b95ff9ddb3a7b60d4627d35915bbbdb8b55 (patch)
treecd0abe45f3e48333489742b3ab434758e342388c
parent8609bbd740c0d211b761a69011fb215986f60f0d (diff)
downloadgconf-4b3c6b95ff9ddb3a7b60d4627d35915bbbdb8b55.tar.gz
Split out more common stuff.
-rw-r--r--gconf/Makefile.am6
-rw-r--r--gconf/gconf-dbus-utils.h43
-rw-r--r--gconf/gconf-dbus.c2621
-rw-r--r--gconf/gconf.c810
-rw-r--r--gconf/gconf.h301
-rw-r--r--gconf/gconfd-dbus.c3
6 files changed, 3773 insertions, 11 deletions
diff --git a/gconf/Makefile.am b/gconf/Makefile.am
index 34ba00aa..90e1896f 100644
--- a/gconf/Makefile.am
+++ b/gconf/Makefile.am
@@ -76,9 +76,9 @@ gconfinclude_HEADERS = \
# Only one client is supported, if D-BUS is enable we use that. FIXME: remove corba files here
if HAVE_DBUS
-GCONF_IPC_SOURCE = gconf-dbus.c gconf-dbus.h gconf-dbus-utils.c gconf-dbus-utils.h gconf-corba-utils.c gconf-corba-utils.h
+GCONF_IPC_SOURCE = gconf-dbus.c gconf-dbus-utils.c gconf-dbus-utils.h gconf-corba-utils.c gconf-corba-utils.h
else
-GCONF_IPC_SOURCE = gconf-corba-utils.c gconf-corba-utils.h gconf-corba.c gconf-corba.h
+GCONF_IPC_SOURCE = gconf-corba-utils.c gconf-corba-utils.h gconf-corba.c
endif
if HAVE_ORBIT
@@ -150,7 +150,7 @@ libgconf_2_la_LDFLAGS = -version-info $(GCONF_CURRENT):$(GCONF_REVISION):$(GCONF
libgconf_2_la_LIBADD = $(INTLLIBS) $(DEPENDENT_LIBS) $(GCONF_IPC_LIBS)
-EXTRA_DIST=GConfX.idl default.path.in gconfmarshal.list regenerate-enum-header.sh regenerate-enum-footer.sh gconf-corba.c gconf-corba.h gconf-corba-utils.c gconf-corba.utils.h gconf-database-corba.c gconf-database-corba.h gconfd-corba.c gconfd-corba.h gconf-dbus.c gconf-dbus.h gconf-database-dbus.c gconf-database-dbus.h gconfd-dbus.c gconfd-dbus.h
+EXTRA_DIST=GConfX.idl default.path.in gconfmarshal.list regenerate-enum-header.sh regenerate-enum-footer.sh gconf-corba.c gconf-corba.h gconf-corba-utils.c gconf-corba.utils.h gconf-database-corba.c gconf-database-corba.h gconfd-corba.c gconf-dbus.c gconf-database-dbus.c gconf-database-dbus.h gconfd-dbus.c gconfd-dbus.h
install-data-local:
-mkdir -p $(DESTDIR)$(sysconfdir)/gconf/$(MAJOR_VERSION)
diff --git a/gconf/gconf-dbus-utils.h b/gconf/gconf-dbus-utils.h
index 5489cd69..2fd1fc27 100644
--- a/gconf/gconf-dbus-utils.h
+++ b/gconf/gconf-dbus-utils.h
@@ -25,6 +25,48 @@
#include <gconf/gconf.h>
#include <gconf/gconf-value.h>
+#define GCONF_DBUS_CONFIG_SERVER "org.gnome.GConf.Server"
+
+#define GCONF_DBUS_CONFIG_SERVER_SHUTDOWN "org.gnome.GConf.Server.Shutdown"
+#define GCONF_DBUS_CONFIG_SERVER_PING "org.gnome.GConf.Server.Ping"
+
+#define GCONF_DBUS_CONFIG_DATABASE_DIR_EXISTS "org.gnome.GConf.Database.DirExists"
+#define GCONF_DBUS_CONFIG_DATABASE_ALL_DIRS "org.gnome.GConf.Database.AllDirs"
+#define GCONF_DBUS_CONFIG_DATABASE_ALL_ENTRIES "org.gnome.GConf.Database.AllEntries"
+#define GCONF_DBUS_CONFIG_DATABASE_LOOKUP "org.gnome.GConf.Database.Lookup"
+#define GCONF_DBUS_CONFIG_DATABASE_SET "org.gnome.GConf.Database.Set"
+#define GCONF_DBUS_CONFIG_DATABASE_UNSET "org.gnome.GConf.Database.Unset"
+#define GCONF_DBUS_CONFIG_DATABASE_REMOVE_DIR "org.gnome.GConf.Database.RemoveDir"
+#define GCONF_DBUS_CONFIG_DATABASE_LOOKUP_DEFAULT_VALUE "org.gnome.GConf.Database.LookupDefaultValue"
+#define GCONF_DBUS_CONFIG_DATABASE_ADD_LISTENER "org.gnome.GConf.Database.AddListener"
+#define GCONF_DBUS_CONFIG_DATABASE_REMOVE_LISTENER "org.gnome.GConf.Database.RemoveListener"
+#define GCONF_DBUS_CONFIG_DATABASE_RECURSIVE_UNSET "org.gnome.GConf.Database.RecursiveUnset"
+#define GCONF_DBUS_CONFIG_DATABASE_SET_SCHEMA "org.gnome.GConf.Database.SetSchema"
+#define GCONF_DBUS_CONFIG_DATABASE_SYNC "org.gnome.GConf.Database.Sync"
+#define GCONF_DBUS_CONFIG_DATABASE_CLEAR_CACHE "org.gnome.GConf.Database.ClearCache"
+#define GCONF_DBUS_CONFIG_DATABASE_SYNCHRONOUS_SYNC "org.gnome.GConf.Database.Synchronous.Sync"
+
+#define GCONF_DBUS_CONFIG_LISTENER_NOTIFY "org.gnome.GConf.Listener.Notify"
+
+#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"
+
+
+#if 0
+
#define GCONF_SERVICE_NAME "org.gnome.GConf"
#define GCONF_SERVER_INTERFACE_NAME "org.gnome.GConf.Server"
#define GCONF_DATABASE_INTERFACE_NAME "org.gnome.GConf.Database"
@@ -55,6 +97,7 @@
#define GCONF_DBUS_ERROR_OVERRIDDEN "org.gnome.GConf.Error.Overriden"
#define GCONF_DBUS_ERROR_LOCK_FAILED "org.gnome.GConf.Error.LockFailed"
+#endif
void gconf_dbus_message_append_gconf_value (DBusMessage *message,
const GConfValue *value);
diff --git a/gconf/gconf-dbus.c b/gconf/gconf-dbus.c
new file mode 100644
index 00000000..0a282e6d
--- /dev/null
+++ b/gconf/gconf-dbus.c
@@ -0,0 +1,2621 @@
+/* -*- mode: C; c-file-style: "gnu" -*- */
+
+/* GConf
+ * Copyright (C) 1999, 2000 Red Hat Inc.
+ *
+ * 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 <popt.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/wait.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include <dbus/dbus.h>
+
+/* For now */
+#include <orbit/orbit-types.h>
+
+/* Returns TRUE if there was an error, frees dbus_error and sets err */
+static gboolean gconf_handle_dbus_exception (DBusMessage *message, GError** err);
+
+/* just returns TRUE if there's an exception indicating the server is
+ probably hosed; no side effects */
+/*static gboolean gconf_server_broken(DBusMessage *message);*/
+static gboolean gconf_server_broken(CORBA_Environment *ev);
+
+static void gconf_detach_config_server(void);
+
+/* Maximum number of times to try re-spawning the server if it's down. */
+#define MAX_RETRIES 1
+
+typedef struct _CnxnTable CnxnTable;
+
+struct _GConfEngine {
+ guint refcount;
+
+ gchar *database;
+
+ CnxnTable* ctable;
+
+ /* If non-NULL, this is a local engine;
+ local engines don't do notification! */
+ GConfSources* local_sources;
+
+ /* An address if this is not the default engine;
+ * NULL if it's the default
+ */
+ gchar *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 _GConfCnxn GConfCnxn;
+
+struct _GConfCnxn {
+ gchar* namespace_section;
+ guint client_id;
+
+ CORBA_unsigned_long server_id; /* id returned from server */
+
+ gchar* server_id2; /* XXX: use string or int id? */
+
+ GConfEngine* conf; /* engine we're associated with */
+ GConfNotifyFunc func;
+ gpointer user_data;
+};
+
+static GConfEngine *default_engine = NULL;
+
+static GConfCnxn* gconf_cnxn_new (GConfEngine *conf,
+ const gchar *namespace_section,
+ CORBA_unsigned_long server_id,
+ GConfNotifyFunc func,
+ gpointer user_data);
+static void gconf_cnxn_destroy (GConfCnxn *cnxn);
+static void gconf_cnxn_notify (GConfCnxn *cnxn,
+ GConfEntry *entry);
+
+
+static ConfigServer gconf_get_config_server (gboolean start_if_not_found,
+ GError **err);
+
+/* Forget our current server object reference, so the next call to
+ gconf_get_config_server will have to try to respawn the server */
+static ConfigListener gconf_get_config_listener (void);
+
+static void gconf_engine_detach (GConfEngine *conf);
+static gboolean gconf_engine_connect (GConfEngine *conf,
+ gboolean start_if_not_found,
+ GError **err);
+
+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);
+
+
+#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 void register_engine (GConfEngine *conf);
+static void unregister_engine (GConfEngine *conf);
+static GConfEngine *lookup_engine (const gchar *address);
+static GConfEngine *lookup_engine_by_database (const gchar *db);
+
+
+/* We'll use client-specific connection numbers to return to library
+ users, so if gconfd dies we can transparently re-register all our
+ listener functions. */
+
+struct _CnxnTable {
+ /* Hash from server-returned connection ID to GConfCnxn */
+ GHashTable* server_ids;
+ /* Hash from our connection ID to GConfCnxn */
+ GHashTable* client_ids;
+};
+
+static CnxnTable* ctable_new (void);
+static void ctable_destroy (CnxnTable *ct);
+static void ctable_insert (CnxnTable *ct,
+ GConfCnxn *cnxn);
+static void ctable_remove (CnxnTable *ct,
+ GConfCnxn *cnxn);
+static GSList* ctable_remove_by_conf (CnxnTable *ct,
+ GConfEngine *conf);
+static GConfCnxn* ctable_lookup_by_client_id (CnxnTable *ct,
+ guint client_id);
+static GConfCnxn* ctable_lookup_by_server_id (CnxnTable *ct,
+ CORBA_unsigned_long server_id);
+static void ctable_reinstall (CnxnTable *ct,
+ GConfCnxn *cnxn,
+ guint old_server_id,
+ guint new_server_id);
+
+
+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 0
+static gboolean
+gconf_server_broken(DBusMessage *message)
+{
+ const char *name;
+
+ /* A server that doesn't reply is a broken server. */
+ if (!message)
+ {
+ /* XXX: should listen to the signal instead, daemon_running = FALSE; */
+ return TRUE;
+ }
+
+ if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)
+ return FALSE;
+
+ name = dbus_message_get_member (message);
+
+ if (g_str_has_prefix (name, "org.freedesktop.DBus.Error"))
+ {
+ /* XXX: listen to signal... daemon_running = FALSE; */
+ return TRUE;
+ }
+ else if (strcmp (name, GCONF_DBUS_ERROR_IN_SHUTDOWN) != 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+#endif
+
+static gboolean
+gconf_handle_dbus_exception (DBusMessage *message, GError** err)
+{
+ char *error_string;
+ const char *name;
+
+ if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)
+ return FALSE;
+
+ name = dbus_message_get_member (message);
+
+ dbus_message_get_args (message, NULL,
+ DBUS_TYPE_STRING, &error_string,
+ 0);
+
+ if (g_str_has_prefix (name, "org.freedesktop.DBus.Error"))
+ {
+ if (err)
+ *err = gconf_error_new (GCONF_ERROR_NO_SERVER, _("D-BUS error: %s"),
+ error_string);
+ }
+ else if (g_str_has_prefix (name, "org.GConf.Error"))
+ {
+ if (err)
+ {
+ GConfError en;
+
+ en = dbus_error_name_to_gconf_errno (name);
+
+ *err = gconf_error_new (en, error_string);
+ }
+ }
+ else
+ {
+ if (err)
+ *err = gconf_error_new (GCONF_ERROR_FAILED, _("Unknown error %s: %s"),
+ name, error_string);
+ }
+
+ 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->ctable = ctable_new();
+ conf->local_sources = NULL;
+ conf->is_local = FALSE;
+ conf->is_default = TRUE;
+ }
+ else
+ {
+ conf->database = NULL;
+ conf->ctable = 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 GHashTable *engines_by_db = NULL;
+
+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;
+}
+
+/* This takes ownership of the ConfigDatabase */
+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
+gconf_engine_connect (GConfEngine *conf,
+ gboolean start_if_not_found,
+ GError **err)
+{
+ ConfigServer cs;
+ const gchar *db; /* XXX: const? */
+ int tries = 0;
+ CORBA_Environment ev;
+
+ g_return_val_if_fail (!conf->is_local, TRUE);
+
+ if (conf->database != NULL)
+ return TRUE;
+
+ RETRY:
+
+ cs = gconf_get_config_server (start_if_not_found, err);
+
+ if (cs == CORBA_OBJECT_NIL)
+ return FALSE; /* Error should already be set */
+
+ CORBA_exception_init (&ev);
+
+ if (conf->is_default)
+ db = NULL; /* XXX: ConfigServer_get_default_database (cs, &ev); */
+ else
+ db = NULL; /* XXX: ConfigServer_get_database (cs, conf->address, &ev); */
+
+ if (gconf_server_broken (&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_detach_config_server();
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception (NULL, err)) /* XXX: message */
+ return FALSE;
+
+ if (db == NULL)
+ {
+ if (err)
+ *err = gconf_error_new(GCONF_ERROR_BAD_ADDRESS,
+ _("Server couldn't resolve the address `%s'"),
+ conf->address ? conf->address : "default");
+
+ 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 (!gconf_engine_connect (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 GHashTable *engines_by_address = NULL;
+
+static void
+register_engine (GConfEngine *conf)
+{
+ g_return_if_fail (conf->address != NULL);
+
+ 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->address, conf);
+}
+
+static void
+unregister_engine (GConfEngine *conf)
+{
+ g_return_if_fail (conf->address != NULL);
+ g_return_if_fail (engines_by_address != NULL);
+
+ g_hash_table_remove (engines_by_address, conf->address);
+
+ if (g_hash_table_size (engines_by_address) == 0)
+ {
+ g_hash_table_destroy (engines_by_address);
+
+ engines_by_address = NULL;
+ }
+}
+
+static GConfEngine *
+lookup_engine (const gchar *address)
+{
+ if (engines_by_address)
+ return g_hash_table_lookup (engines_by_address, address);
+ else
+ return NULL;
+}
+
+
+/*
+ * 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_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;
+
+ /* Ignore errors, we never return a NULL default database, and
+ * since we aren't starting if it isn't found, we'll probably
+ * get errors half the time anyway.
+ */
+ gconf_engine_connect (conf, FALSE, NULL);
+ }
+ else
+ conf->refcount += 1;
+
+ return conf;
+}
+
+GConfEngine*
+gconf_engine_get_for_address (const gchar* address, GError** err)
+{
+ GConfEngine* conf;
+
+ conf = lookup_engine (address);
+
+ if (conf == NULL)
+ {
+ conf = gconf_engine_blank(TRUE);
+
+ conf->is_default = FALSE;
+ conf->address = g_strdup (address);
+
+ if (!gconf_engine_connect (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 */
+ GSList* removed;
+ GSList* tmp;
+ CORBA_Environment ev;
+
+ CORBA_exception_init(&ev);
+
+ /* FIXME CnxnTable only has entries for this GConfEngine now,
+ * it used to be global and shared among GConfEngine objects.
+ */
+ removed = ctable_remove_by_conf (conf->ctable, conf);
+
+ tmp = removed;
+ while (tmp != NULL)
+ {
+ GConfCnxn* gcnxn = tmp->data;
+
+ if (conf->database != NULL)
+ {
+ GError* err = NULL;
+ /*
+ ConfigDatabase_remove_listener(conf->database,
+ gcnxn->server_id,
+ &ev);
+ */
+ if (gconf_handle_dbus_exception (NULL, &err)) /* XXX: message */
+ {
+ /* Don't set error because realistically this
+ doesn't matter to clients */
+#ifdef GCONF_ENABLE_DEBUG
+ g_warning("Failure removing listener %u from the config server: %s",
+ (guint)gcnxn->server_id,
+ err->message);
+#endif
+ }
+ }
+
+ gconf_cnxn_destroy(gcnxn);
+
+ tmp = g_slist_next(tmp);
+ }
+
+ g_slist_free(removed);
+
+ if (conf->dnotify)
+ {
+ (* conf->dnotify) (conf->user_data);
+ }
+
+ /* do this after removing the notifications,
+ to avoid funky race conditions */
+ if (conf->address)
+ unregister_engine (conf);
+
+ /* Release the ConfigDatabase */
+ gconf_engine_detach (conf);
+
+ ctable_destroy (conf->ctable);
+ }
+
+ 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;
+}
+
+guint
+gconf_engine_notify_add(GConfEngine* conf,
+ const gchar* namespace_section,
+ GConfNotifyFunc func,
+ gpointer user_data,
+ GError** err)
+{
+ /* XXX: implement */
+#if 0
+ ConfigDatabase db;
+ ConfigListener cl;
+ gulong id;
+ CORBA_Environment ev;
+ GConfCnxn* cnxn;
+ gint tries = 0;
+ ConfigDatabase3_PropList properties;
+#define NUM_PROPERTIES 1
+ ConfigStringProperty properties_buffer[1];
+#endif
+ 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;
+ }
+#if 0
+ properties._buffer = properties_buffer;
+ properties._length = NUM_PROPERTIES;
+ properties._maximum = NUM_PROPERTIES;
+ properties._release = CORBA_FALSE; /* don't free static buffer */
+
+ properties._buffer[0].key = "name";
+ properties._buffer[0].value = g_get_prgname ();
+ if (properties._buffer[0].value == NULL)
+ properties._buffer[0].value = "unknown";
+
+ CORBA_exception_init(&ev);
+
+ RETRY:
+
+ db = gconf_engine_get_database (conf, TRUE, err);
+
+ if (db == CORBA_OBJECT_NIL)
+ return 0;
+
+ cl = gconf_get_config_listener ();
+
+ /* Should have aborted the program in this case probably */
+ g_return_val_if_fail(cl != CORBA_OBJECT_NIL, 0);
+
+ id = ConfigDatabase3_add_listener_with_properties (db,
+ (gchar*)namespace_section,
+ cl,
+ &properties,
+ &ev);
+
+ if (ev._major == CORBA_SYSTEM_EXCEPTION &&
+ CORBA_exception_id (&ev) &&
+ strcmp (CORBA_exception_id (&ev), "IDL:CORBA/BAD_OPERATION:1.0") == 0)
+ {
+ CORBA_exception_free (&ev);
+ CORBA_exception_init (&ev);
+
+ id = ConfigDatabase_add_listener(db,
+ (gchar*)namespace_section,
+ cl, &ev);
+ }
+
+ if (gconf_server_broken(&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_engine_detach (conf);
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception (NULL, err)) /* XXX: message */
+ return 0;
+
+ cnxn = gconf_cnxn_new(conf, namespace_section, id, func, user_data);
+
+ ctable_insert(conf->ctable, cnxn);
+
+ return cnxn->client_id;
+ #endif
+ return 0;
+}
+
+void
+gconf_engine_notify_remove(GConfEngine* conf,
+ guint client_id)
+{
+#if 0
+ GConfCnxn* gcnxn;
+ CORBA_Environment ev;
+ ConfigDatabase db;
+ gint tries = 0;
+
+ CHECK_OWNER_USE (conf);
+
+ if (gconf_engine_is_local(conf))
+ return;
+
+ CORBA_exception_init(&ev);
+
+ RETRY:
+
+ db = gconf_engine_get_database (conf, TRUE, NULL);
+
+ if (db == CORBA_OBJECT_NIL)
+ return;
+
+ gcnxn = ctable_lookup_by_client_id(conf->ctable, client_id);
+
+ g_return_if_fail(gcnxn != NULL);
+
+ ConfigDatabase_remove_listener(db,
+ gcnxn->server_id,
+ &ev);
+
+ if (gconf_server_broken(&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_engine_detach (conf);
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception (NULL, NULL)) /* XXX: message */
+ {
+ ; /* do nothing */
+ }
+
+
+ /* We want to do this even if the CORBA fails, so if we restart gconfd and
+ reinstall listeners we don't reinstall this one. */
+ ctable_remove(conf->ctable, gcnxn);
+
+ gconf_cnxn_destroy(gcnxn);
+#endif
+}
+
+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;
+ CORBA_Environment ev;
+ const gchar *db;
+ gint tries = 0;
+ gboolean is_default = FALSE;
+ gboolean is_writable = TRUE;
+ gchar *schema_name = NULL;
+
+ 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));
+
+ /* XXX: implement dbus version */
+
+ CORBA_exception_init(&ev);
+
+ RETRY:
+
+ db = gconf_engine_get_database (conf, TRUE, err);
+
+ if (db == CORBA_OBJECT_NIL)
+ {
+ g_return_val_if_fail(err == NULL || *err != NULL, NULL);
+
+ return NULL;
+ }
+
+ if (schema_name_p)
+ *schema_name_p = NULL;
+
+ /*
+ cv = ConfigDatabase2_lookup_with_schema_name (db,
+ (gchar*)key, (gchar*)
+ (locale ? locale : gconf_current_locale()),
+ use_schema_default,
+ &schema_name,
+ &is_default,
+ &is_writable,
+ &ev);
+ */
+ if (gconf_server_broken(&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_engine_detach (conf);
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception (NULL, err)) /* XXX: message */
+ {
+ /* NOTE: don't free cv since we got an exception! */
+ return NULL;
+ }
+ else
+ {
+ val = NULL;/* XXX: gconf_value_from_corba_value(cv); */
+
+ if (is_default_p)
+ *is_default_p = is_default;
+ if (is_writable_p)
+ *is_writable_p = is_writable;
+
+ /* we can't get a null pointer through corba
+ * so the server sent us an empty string
+ */
+ if (schema_name && schema_name[0] != '/')
+ {
+ /* XXX: CORBA_free (corba_schema_name); */
+ schema_name = NULL;
+ }
+
+ if (schema_name_p)
+ *schema_name_p = g_strdup (schema_name);
+
+ if (schema_name)
+ ;/* XXX: CORBA_free (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;
+ /* ConfigValue* cv; */
+ CORBA_Environment ev;
+ const gchar *db;
+ gint tries = 0;
+
+ 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));
+
+ CORBA_exception_init(&ev);
+
+ RETRY:
+
+ db = gconf_engine_get_database (conf, TRUE, err);
+
+ if (db == NULL)
+ {
+ g_return_val_if_fail(err == NULL || *err != NULL, NULL);
+
+ return NULL;
+ }
+
+ /*
+ cv = ConfigDatabase_lookup_default_value(db,
+ (gchar*)key,
+ (gchar*)gconf_current_locale(),
+ &ev);
+ */
+
+ if (gconf_server_broken(&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_engine_detach (conf);
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception (NULL, err)) /* XXX: message */
+ {
+ /* NOTE: don't free cv since we got an exception! */
+ return NULL;
+ }
+ else
+ {
+ val = NULL; /* XXX: gconf_value_from_corba_value(cv); */
+
+ return val;
+ }
+}
+
+gboolean
+gconf_engine_set (GConfEngine* conf, const gchar* key,
+ const GConfValue* value, GError** err)
+{
+ CORBA_Environment ev;
+ const gchar *db;
+ gint tries = 0;
+
+ 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, &error);
+
+ if (error != NULL)
+ {
+ if (err)
+ *err = error;
+ else
+ {
+ g_error_free(error);
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ g_assert(!gconf_engine_is_local(conf));
+
+ CORBA_exception_init(&ev);
+
+ RETRY:
+
+ db = gconf_engine_get_database (conf, TRUE, err);
+
+ if (db == NULL)
+ {
+ g_return_val_if_fail(err == NULL || *err != NULL, FALSE);
+
+ return FALSE;
+ }
+
+ /*cv = XXX: gconf_corba_value_from_gconf_value (value);
+
+ ConfigDatabase_set(db,
+ (gchar*)key, cv,
+ &ev);
+
+ CORBA_free(cv);
+ */
+ if (gconf_server_broken(&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_engine_detach (conf);
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception (NULL, err)) /* XXX: message */
+ return FALSE;
+
+ g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+
+ return TRUE;
+}
+
+gboolean
+gconf_engine_unset (GConfEngine* conf, const gchar* key, GError** err)
+{
+ CORBA_Environment ev;
+ const gchar *db;
+ gint tries = 0;
+
+ 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, &error);
+
+ if (error != NULL)
+ {
+ if (err)
+ *err = error;
+ else
+ {
+ g_error_free(error);
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ g_assert(!gconf_engine_is_local(conf));
+
+ CORBA_exception_init(&ev);
+
+ RETRY:
+
+ db = gconf_engine_get_database (conf, TRUE, err);
+
+ if (db == NULL)
+ {
+ g_return_val_if_fail(err == NULL || *err != NULL, FALSE);
+
+ return FALSE;
+ }
+
+ /* ConfigDatabase_unset (db,
+ (gchar*)key,
+ &ev);
+ */
+ if (gconf_server_broken (&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_engine_detach(conf);
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception (NULL, err)) /* XXX: message */
+ return FALSE;
+
+ g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+
+ 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)
+{
+ CORBA_Environment ev;
+ const gchar *db;
+ gint tries = 0;
+ /*ConfigDatabase3_UnsetFlags corba_flags;*/
+
+ 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));
+
+ CORBA_exception_init(&ev);
+
+ /*corba_flags = 0;
+ if (flags & GCONF_UNSET_INCLUDING_SCHEMA_NAMES)
+ corba_flags |= ConfigDatabase3_UNSET_INCLUDING_SCHEMA_NAMES;
+ */
+ RETRY:
+
+ db = gconf_engine_get_database (conf, TRUE, err);
+
+ if (db == NULL)
+ {
+ g_return_val_if_fail (err == NULL || *err != NULL, FALSE);
+
+ return FALSE;
+ }
+
+ /* XXX: ConfigDatabase3_recursive_unset (db, key, corba_flags, &ev);*/
+
+ if (gconf_server_broken (&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_engine_detach(conf);
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception (NULL, err)) /* XXX: message */
+ return FALSE;
+
+ g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+
+ return TRUE;
+}
+
+gboolean
+gconf_engine_associate_schema (GConfEngine* conf, const gchar* key,
+ const gchar* schema_key, GError** err)
+{
+ CORBA_Environment ev;
+ const gchar *db;
+ gint tries = 0;
+
+ 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));
+
+ CORBA_exception_init (&ev);
+
+ RETRY:
+
+ db = gconf_engine_get_database (conf, TRUE, err);
+
+ if (db == NULL)
+ {
+ g_return_val_if_fail (err == NULL || *err != NULL, FALSE);
+
+ return FALSE;
+ }
+
+#if 0
+ ConfigDatabase_set_schema (db,
+ key,
+ /* empty string means unset */
+ schema_key ? schema_key : "",
+ &ev);
+#endif
+
+ if (gconf_server_broken (&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free (&ev);
+ gconf_engine_detach (conf);
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception (NULL, err)) /* XXX: message */
+ return FALSE;
+
+ g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
+
+ 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* pairs = NULL;
+ /* ConfigDatabase_ValueList* values;
+ ConfigDatabase_KeyList* keys;
+ ConfigDatabase_IsDefaultList* is_defaults;
+ ConfigDatabase_IsWritableList* is_writables;
+ ConfigDatabase2_SchemaNameList *schema_names;
+ */
+ CORBA_Environment ev;
+ const gchar *db;
+ /* guint i;*/
+ gint tries = 0;
+
+ 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));
+
+ CORBA_exception_init(&ev);
+
+ RETRY:
+
+ db = gconf_engine_get_database (conf, TRUE, err);
+
+ if (db == NULL)
+ {
+ g_return_val_if_fail(err == NULL || *err != NULL, NULL);
+
+ return NULL;
+ }
+
+ /*
+ schema_names = NULL;
+
+ ConfigDatabase2_all_entries_with_schema_name (db,
+ (gchar*)dir,
+ (gchar*)gconf_current_locale(),
+ &keys, &values, &schema_names,
+ &is_defaults, &is_writables,
+ &ev);
+ */
+
+ if (gconf_server_broken(&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_engine_detach (conf);
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception (NULL, err)) /* XXX: message */
+ return NULL;
+
+#if 0
+
+ if (keys->_length != values->_length)
+ {
+ g_warning("Received unmatched key/value sequences in %s",
+ G_GNUC_FUNCTION);
+ return NULL;
+ }
+
+ i = 0;
+ while (i < keys->_length)
+ {
+ GConfEntry* pair;
+
+ pair =
+ gconf_entry_new_nocopy(gconf_concat_dir_and_key (dir, keys->_buffer[i]),
+ gconf_value_from_corba_value(&(values->_buffer[i])));
+
+ gconf_entry_set_is_default (pair, is_defaults->_buffer[i]);
+ gconf_entry_set_is_writable (pair, is_writables->_buffer[i]);
+ if (schema_names)
+ {
+ /* empty string means no schema name */
+ if (*(schema_names->_buffer[i]) != '\0')
+ gconf_entry_set_schema_name (pair, schema_names->_buffer[i]);
+ }
+
+ pairs = g_slist_prepend(pairs, pair);
+
+ ++i;
+ }
+
+ CORBA_free(keys);
+ CORBA_free(values);
+ CORBA_free(is_defaults);
+ CORBA_free(is_writables);
+ if (schema_names)
+ CORBA_free (schema_names);
+#endif
+
+ return pairs;
+}
+
+
+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;
+ /* ConfigDatabase_KeyList* keys;*/
+ CORBA_Environment ev;
+ const gchar *db;
+ guint i;
+ gint tries = 0;
+
+ 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));
+
+ CORBA_exception_init(&ev);
+
+ RETRY:
+
+ db = gconf_engine_get_database (conf, TRUE, err);
+
+ if (db == NULL)
+ {
+ g_return_val_if_fail(((err == NULL) || (*err && ((*err)->code == GCONF_ERROR_NO_SERVER))), NULL);
+
+ return NULL;
+ }
+
+ /* ConfigDatabase_all_dirs(db,
+ (gchar*)dir,
+ &keys,
+ &ev);
+ */
+ if (gconf_server_broken(&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_engine_detach (conf);
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception (NULL, err)) /* XXX: message */
+ return NULL;
+
+ i = 0;
+ /* while (i < keys->_length)
+ {
+ gchar* s;
+
+ s = gconf_concat_dir_and_key (dir, keys->_buffer[i]);
+
+ subdirs = g_slist_prepend(subdirs, s);
+
+ ++i;
+ }
+
+ CORBA_free(keys);
+ */
+ return subdirs;
+}
+
+/* annoyingly, this is REQUIRED for local sources */
+void
+gconf_engine_suggest_sync(GConfEngine* conf, GError** err)
+{
+ CORBA_Environment ev;
+ const gchar *db;
+ gint tries = 0;
+
+ 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));
+
+ CORBA_exception_init(&ev);
+
+ RETRY:
+
+ db = gconf_engine_get_database (conf, TRUE, err);
+
+ if (db == NULL)
+ {
+ g_return_if_fail(err == NULL || *err != NULL);
+
+ return;
+ }
+
+ /* XXX: ConfigDatabase_sync(db, &ev);*/
+
+ if (gconf_server_broken(&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_engine_detach (conf);
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception (NULL, err)) /* XXX: message */
+ ; /* nothing additional */
+}
+
+void
+gconf_clear_cache(GConfEngine* conf, GError** err)
+{
+ CORBA_Environment ev;
+ const gchar *db;
+ gint tries = 0;
+
+ 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;
+ }
+
+ g_assert(!gconf_engine_is_local(conf));
+
+ CORBA_exception_init(&ev);
+
+ RETRY:
+
+ db = gconf_engine_get_database (conf, TRUE, err);
+
+ if (db == NULL)
+ {
+ g_return_if_fail(err == NULL || *err != NULL);
+
+ return;
+ }
+
+ /* XXX: ConfigDatabase_clear_cache(db, &ev);*/
+
+ if (gconf_server_broken(&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_engine_detach (conf);
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception(NULL, err)) /* XXX: message */
+ ; /* nothing additional */
+}
+
+void
+gconf_synchronous_sync(GConfEngine* conf, GError** err)
+{
+ CORBA_Environment ev;
+ const gchar *db;
+ gint tries = 0;
+
+ 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;
+ }
+
+ g_assert(!gconf_engine_is_local(conf));
+
+ CORBA_exception_init(&ev);
+
+ RETRY:
+
+ db = gconf_engine_get_database (conf, TRUE, err);
+
+ if (db == NULL)
+ {
+ g_return_if_fail(err == NULL || *err != NULL);
+
+ return;
+ }
+
+ /* XXX: ConfigDatabase_synchronous_sync(db, &ev);*/
+
+ if (gconf_server_broken(&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_engine_detach (conf);
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception (NULL, err)) /* XXX: message */
+ ; /* nothing additional */
+}
+
+gboolean
+gconf_engine_dir_exists(GConfEngine *conf, const gchar *dir, GError** err)
+{
+ CORBA_Environment ev;
+ const gchar *db;
+ gboolean server_ret;
+ gint tries = 0;
+
+ 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));
+
+ CORBA_exception_init(&ev);
+
+ RETRY:
+
+ db = gconf_engine_get_database(conf, TRUE, err);
+
+ if (db == NULL)
+ {
+ g_return_val_if_fail(err == NULL || *err != NULL, FALSE);
+
+ return FALSE;
+ }
+
+ server_ret = TRUE; /* XXX: ConfigDatabase_dir_exists(db,
+ (gchar*)dir,
+ &ev);
+ */
+ if (gconf_server_broken(&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_engine_detach (conf);
+ goto RETRY;
+ }
+ }
+
+ if (gconf_handle_dbus_exception (NULL, err)) /* XXX: message */
+ ; /* nothing */
+
+ return (server_ret == TRUE);
+}
+
+void
+gconf_engine_remove_dir (GConfEngine* conf,
+ const gchar* dir,
+ GError** err)
+{
+ CORBA_Environment ev;
+ const gchar *db;
+ gint tries = 0;
+
+ 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;
+ }
+
+ CORBA_exception_init(&ev);
+
+ RETRY:
+
+ db = gconf_engine_get_database (conf, TRUE, err);
+
+ if (db == NULL)
+ {
+ g_return_if_fail(err == NULL || *err != NULL);
+ return;
+ }
+
+ /* XXX: ConfigDatabase_remove_dir(db, (gchar*)dir, &ev);*/
+
+ if (gconf_server_broken(&ev))
+ {
+ if (tries < MAX_RETRIES)
+ {
+ ++tries;
+ CORBA_exception_free(&ev);
+ gconf_engine_detach (conf);
+ goto RETRY;
+ }
+ }
+ gconf_handle_dbus_exception (NULL, err); /* XXX: message */
+
+ return;
+}
+
+gboolean
+gconf_engine_key_is_writable (GConfEngine *conf,
+ const gchar *key,
+ GError **err)
+{
+ gboolean is_writable = TRUE;
+ GConfValue *val;
+
+ CHECK_OWNER_USE (conf);
+
+ /* FIXME implement IDL to allow getting only writability
+ * (not that urgent since GConfClient caches this crap
+ * anyway)
+ */
+
+ val = gconf_engine_get_full(conf, key, NULL, TRUE,
+ NULL, &is_writable, err);
+
+ gconf_value_free (val);
+
+ return is_writable;
+}
+
+/*
+ * Connection maintenance
+ */
+
+static GConfCnxn*
+gconf_cnxn_new(GConfEngine* conf,
+ const gchar* namespace_section,
+ CORBA_unsigned_long server_id,
+ 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->server_id = server_id;
+ 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 ConfigServer server = CORBA_OBJECT_NIL;
+
+/* All errors set in here should be GCONF_ERROR_NO_SERVER; should
+ only set errors if start_if_not_found is TRUE */
+static ConfigServer
+gconf_get_config_server(gboolean start_if_not_found, GError** err)
+{
+ g_return_val_if_fail(err == NULL || *err == NULL, server);
+
+ if (server != CORBA_OBJECT_NIL)
+ return server;
+
+ server = NULL; /* XXX: activate the service here, add client if we need to do that */
+
+ return server; /* return what we have, NIL or not */
+}
+
+ConfigListener listener = CORBA_OBJECT_NIL;
+
+static void
+gconf_detach_config_server(void)
+{
+ /* XXX: remove listener and
+
+ 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; /* XXX: 0 is success... */
+}
+
+
+#if 0
+static void
+notify (...)
+{
+ GConfCnxn* cnxn;
+ GConfValue* gvalue;
+ GConfEngine* conf;
+ GConfEntry* entry;
+
+ conf = lookup_engine_by_database (db);
+
+ if (conf == NULL)
+ {
+#ifdef GCONF_ENABLE_DEBUG
+ g_warning ("Client received notify for unknown database object");
+#endif
+ return;
+ }
+
+ cnxn = ctable_lookup_by_server_id(conf->ctable, server_id);
+
+ if (cnxn == NULL)
+ {
+#ifdef GCONF_ENABLE_DEBUG
+ g_warning("Client received notify for unknown connection ID %u",
+ (guint)server_id);
+#endif
+ return;
+ }
+
+ gvalue = gconf_value_from_...;
+
+ entry = gconf_entry_new_nocopy (g_strdup (key), gvalue);
+ gconf_entry_set_is_default (entry, is_default);
+ gconf_entry_set_is_writable (entry, is_writable);
+
+ gconf_cnxn_notify(cnxn, entry);
+
+ gconf_entry_free (entry);
+}
+
+static void
+ping (...)
+{
+ /* This one is easy :-) */
+
+ return;
+}
+
+static void
+invalidate_cached_values (...)
+{
+#if 0
+ g_warning ("FIXME process %d received request to invalidate some cached GConf values from the server, but right now we don't know how to do that (not implemented).", (int) getpid());
+#endif
+}
+
+static void
+drop_all_caches (...)
+{
+#if 0
+ g_warning ("FIXME process %d received request to invalidate all cached GConf values from the server, but right now we don't know how to do that (not implemented).", (int) getpid());
+#endif
+}
+
+static ConfigListener
+gconf_get_config_listener(void)
+{
+ if (listener == CORBA_OBJECT_NIL)
+ {
+ CORBA_Environment ev;
+ PortableServer_POA poa;
+ PortableServer_POAManager poa_mgr;
+
+ CORBA_exception_init (&ev);
+ POA_ConfigListener__init (&poa_listener_servant, &ev);
+
+ g_assert (ev._major == CORBA_NO_EXCEPTION);
+
+ poa =
+ (PortableServer_POA) CORBA_ORB_resolve_initial_references (gconf_orb_get (),
+ "RootPOA", &ev);
+
+ g_assert (ev._major == CORBA_NO_EXCEPTION);
+
+ poa_mgr = PortableServer_POA__get_the_POAManager (poa, &ev);
+ PortableServer_POAManager_activate (poa_mgr, &ev);
+
+ g_assert (ev._major == CORBA_NO_EXCEPTION);
+
+ listener = PortableServer_POA_servant_to_reference(poa,
+ &poa_listener_servant,
+ &ev);
+
+ CORBA_Object_release ((CORBA_Object) poa_mgr, &ev);
+ CORBA_Object_release ((CORBA_Object) poa, &ev);
+
+ g_assert (listener != CORBA_OBJECT_NIL);
+ g_assert (ev._major == CORBA_NO_EXCEPTION);
+ }
+
+ return listener;
+}
+#endif
+
+/*
+ * Table of connections
+ */
+
+static gint
+corba_unsigned_long_equal (gconstpointer v1,
+ gconstpointer v2)
+{
+ return *((const CORBA_unsigned_long*) v1) == *((const CORBA_unsigned_long*) v2);
+}
+
+static guint
+corba_unsigned_long_hash (gconstpointer v)
+{
+ /* for our purposes we can just assume 32 bits are significant */
+ return (guint)(*(const CORBA_unsigned_long*) v);
+}
+
+static CnxnTable*
+ctable_new(void)
+{
+ CnxnTable* ct;
+
+ ct = g_new(CnxnTable, 1);
+
+ ct->server_ids = g_hash_table_new (corba_unsigned_long_hash,
+ corba_unsigned_long_equal);
+ ct->client_ids = g_hash_table_new (g_int_hash, g_int_equal);
+
+ return ct;
+}
+
+static void
+ctable_destroy(CnxnTable* ct)
+{
+ g_hash_table_destroy (ct->server_ids);
+ g_hash_table_destroy (ct->client_ids);
+ g_free(ct);
+}
+
+static void
+ctable_insert(CnxnTable* ct, GConfCnxn* cnxn)
+{
+ g_hash_table_insert (ct->server_ids, &cnxn->server_id, cnxn);
+ g_hash_table_insert (ct->client_ids, &cnxn->client_id, cnxn);
+}
+
+static void
+ctable_remove(CnxnTable* ct, GConfCnxn* cnxn)
+{
+ g_hash_table_remove (ct->server_ids, &cnxn->server_id);
+ g_hash_table_remove (ct->client_ids, &cnxn->client_id);
+}
+
+struct RemoveData {
+ GSList* removed;
+ GConfEngine* conf;
+ gboolean save_removed;
+};
+
+static gboolean
+remove_by_conf(gpointer key, gpointer value, gpointer user_data)
+{
+ struct RemoveData* rd = user_data;
+ GConfCnxn* cnxn = value;
+
+ if (cnxn->conf == rd->conf)
+ {
+ if (rd->save_removed)
+ rd->removed = g_slist_prepend(rd->removed, cnxn);
+
+ return TRUE; /* remove this one */
+ }
+ else
+ return FALSE; /* or not */
+}
+
+/* FIXME this no longer makes any sense, because a CnxnTable
+ belongs to a GConfEngine and all entries have the same
+ GConfEngine.
+*/
+
+/* We return a list of the removed GConfCnxn */
+static GSList*
+ctable_remove_by_conf(CnxnTable* ct, GConfEngine* conf)
+{
+ guint client_ids_removed;
+ guint server_ids_removed;
+ struct RemoveData rd;
+
+ rd.removed = NULL;
+ rd.conf = conf;
+ rd.save_removed = TRUE;
+
+ client_ids_removed = g_hash_table_foreach_remove (ct->server_ids,
+ remove_by_conf,
+ &rd);
+
+ rd.save_removed = FALSE;
+
+ server_ids_removed = g_hash_table_foreach_remove(ct->client_ids,
+ remove_by_conf,
+ &rd);
+
+ g_assert(client_ids_removed == server_ids_removed);
+ g_assert(client_ids_removed == g_slist_length(rd.removed));
+
+ return rd.removed;
+}
+
+static GConfCnxn*
+ctable_lookup_by_client_id(CnxnTable* ct, guint client_id)
+{
+ return g_hash_table_lookup(ct->client_ids, &client_id);
+}
+
+static GConfCnxn*
+ctable_lookup_by_server_id(CnxnTable* ct, CORBA_unsigned_long server_id)
+{
+ return g_hash_table_lookup (ct->server_ids, &server_id);
+}
+
+static void
+ctable_reinstall (CnxnTable* ct,
+ GConfCnxn *cnxn,
+ guint old_server_id,
+ guint new_server_id)
+{
+ g_return_if_fail (cnxn->server_id == old_server_id);
+
+ g_hash_table_remove (ct->server_ids, &old_server_id);
+
+ cnxn->server_id = new_server_id;
+
+ g_hash_table_insert (ct->server_ids, &cnxn->server_id, cnxn);
+}
+
+/*
+ * Daemon control
+ */
+
+void
+gconf_shutdown_daemon (GError** err)
+{
+ CORBA_Environment ev;
+ ConfigServer cs;
+
+ cs = gconf_get_config_server (FALSE, err); /* Don't want to spawn it if it's already down */
+
+ if (err && *err && (*err)->code == GCONF_ERROR_NO_SERVER)
+ {
+ /* No server is hardly an error here */
+ g_error_free (*err);
+ *err = NULL;
+ }
+
+ if (cs == CORBA_OBJECT_NIL)
+ {
+
+ return;
+ }
+
+ CORBA_exception_init (&ev);
+
+ ConfigServer_shutdown (cs, &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION)
+ {
+ if (err)
+ *err = gconf_error_new (GCONF_ERROR_FAILED, _("Failure shutting down config server: %s"),
+ CORBA_exception_id (&ev));
+
+ CORBA_exception_free(&ev);
+ }
+}
+
+gboolean
+gconf_ping_daemon(void)
+{
+ ConfigServer cs;
+
+ cs = gconf_get_config_server(FALSE, NULL); /* ignore error, since whole point is to see if server is reachable */
+
+ if (cs == CORBA_OBJECT_NIL)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+gboolean
+gconf_spawn_daemon(GError** err)
+{
+ ConfigServer cs;
+
+ cs = gconf_get_config_server(TRUE, err);
+
+ if (cs == CORBA_OBJECT_NIL)
+ {
+ g_return_val_if_fail(err == NULL || *err != NULL, FALSE);
+ return FALSE; /* Failed to spawn, error should be set */
+ }
+ else
+ return TRUE;
+}
+
+
+/* CORBA Util */
+
+/* Set GConfError from an exception, free exception, etc. */
+
+#if CORBA
+static GConfError
+corba_errno_to_gconf_errno(ConfigErrorType corba_err)
+{
+ switch (corba_err)
+ {
+ case ConfigFailed:
+ return GCONF_ERROR_FAILED;
+ break;
+ case ConfigNoPermission:
+ return GCONF_ERROR_NO_PERMISSION;
+ break;
+ case ConfigBadAddress:
+ return GCONF_ERROR_BAD_ADDRESS;
+ break;
+ case ConfigBadKey:
+ return GCONF_ERROR_BAD_KEY;
+ break;
+ case ConfigParseError:
+ return GCONF_ERROR_PARSE_ERROR;
+ break;
+ case ConfigCorrupt:
+ return GCONF_ERROR_CORRUPT;
+ break;
+ case ConfigTypeMismatch:
+ return GCONF_ERROR_TYPE_MISMATCH;
+ break;
+ case ConfigIsDir:
+ return GCONF_ERROR_IS_DIR;
+ break;
+ case ConfigIsKey:
+ return GCONF_ERROR_IS_KEY;
+ break;
+ case ConfigOverridden:
+ return GCONF_ERROR_OVERRIDDEN;
+ break;
+ case ConfigLockFailed:
+ return GCONF_ERROR_LOCK_FAILED;
+ break;
+ case ConfigNoWritableDatabase:
+ return GCONF_ERROR_NO_WRITABLE_DATABASE;
+ break;
+ case ConfigInShutdown:
+ return GCONF_ERROR_IN_SHUTDOWN;
+ break;
+ default:
+ g_assert_not_reached();
+ return GCONF_ERROR_SUCCESS; /* warnings */
+ break;
+ }
+}
+#endif
+
+static gboolean
+gconf_server_broken(CORBA_Environment* ev)
+{
+ switch (ev->_major)
+ {
+ case CORBA_SYSTEM_EXCEPTION:
+ return TRUE;
+ break;
+
+ case CORBA_USER_EXCEPTION:
+ {
+ ConfigException* ce;
+
+ ce = CORBA_exception_value(ev);
+
+ return ce->err_no == ConfigInShutdown;
+ }
+ break;
+
+ default:
+ return FALSE;
+ break;
+ }
+}
+
+/*
+ * Enumeration conversions
+ */
+
+gboolean
+gconf_string_to_enum (GConfEnumStringPair lookup_table[],
+ const gchar* str,
+ gint* enum_value_retloc)
+{
+ int i = 0;
+
+ while (lookup_table[i].str != NULL)
+ {
+ if (g_ascii_strcasecmp (lookup_table[i].str, str) == 0)
+ {
+ *enum_value_retloc = lookup_table[i].enum_value;
+ return TRUE;
+ }
+
+ ++i;
+ }
+
+ return FALSE;
+}
+
+const gchar*
+gconf_enum_to_string (GConfEnumStringPair lookup_table[],
+ gint enum_value)
+{
+ int i = 0;
+
+ while (lookup_table[i].str != NULL)
+ {
+ if (lookup_table[i].enum_value == enum_value)
+ return lookup_table[i].str;
+
+ ++i;
+ }
+
+ return NULL;
+}
diff --git a/gconf/gconf.c b/gconf/gconf.c
index db83b983..e9d9ab8d 100644
--- a/gconf/gconf.c
+++ b/gconf/gconf.c
@@ -1 +1,809 @@
-/* Add common things from gconf-dbus.c and gconf-corba.c here */
+/* -*- mode: C; c-file-style: "gnu" -*- */
+
+/* GConf
+ * Copyright (C) 1999, 2000 Red Hat Inc.
+ *
+ * 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 <popt.h>
+#include "gconf.h"
+#include "gconf-internals.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+
+gboolean
+gconf_key_check (const gchar* key, GError** err)
+{
+ gchar* why = NULL;
+
+ if (key == NULL)
+ {
+ if (err)
+ *err = gconf_error_new (GCONF_ERROR_BAD_KEY,
+ _("Key \"%s\" is NULL"),
+ key);
+ return FALSE;
+ }
+ else if (!gconf_valid_key (key, &why))
+ {
+ if (err)
+ *err = gconf_error_new (GCONF_ERROR_BAD_KEY, _("\"%s\": %s"),
+ key, why);
+ g_free(why);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void
+gconf_preinit (gpointer app, gpointer mod_info)
+{
+ /* Deprecated */
+}
+
+void
+gconf_postinit (gpointer app, gpointer mod_info)
+{
+ /* Deprecated */
+}
+
+/* All deprecated */
+const char gconf_version[] = VERSION;
+
+struct poptOption gconf_options[] = {
+ {NULL}
+};
+
+/* Also deprecated */
+gboolean
+gconf_init (int argc, char **argv, GError** err)
+{
+
+ return TRUE;
+}
+
+gboolean
+gconf_is_initialized (void)
+{
+ return TRUE;
+}
+
+/*
+ * Ampersand and <> are not allowed due to the XML backend; shell
+ * special characters aren't allowed; others are just in case we need
+ * some magic characters someday. hyphen, underscore, period, colon
+ * are allowed as separators. % disallowed to avoid printf confusion.
+ */
+
+/* Key/dir validity is exactly the same, except that '/' must be a dir,
+ but we are sort of ignoring that for now. */
+
+/* Also, keys can contain only ASCII */
+
+static const gchar invalid_chars[] = " \t\r\n\"$&<>,+=#!()'|{}[]?~`;%\\";
+
+gboolean
+gconf_valid_key (const gchar* key, gchar** why_invalid)
+{
+ const gchar* s = key;
+ gboolean just_saw_slash = FALSE;
+
+ /* Key must start with the root */
+ if (*key != '/')
+ {
+ if (why_invalid != NULL)
+ *why_invalid = g_strdup(_("Must begin with a slash (/)"));
+ return FALSE;
+ }
+
+ /* Root key is a valid dir */
+ if (*key == '/' && key[1] == '\0')
+ return TRUE;
+
+ while (*s)
+ {
+ if (just_saw_slash)
+ {
+ /* Can't have two slashes in a row, since it would mean
+ * an empty spot.
+ * Can't have a period right after a slash,
+ * because it would be a pain for filesystem-based backends.
+ */
+ if (*s == '/' || *s == '.')
+ {
+ if (why_invalid != NULL)
+ {
+ if (*s == '/')
+ *why_invalid = g_strdup(_("Can't have two slashes (/) in a row"));
+ else
+ *why_invalid = g_strdup(_("Can't have a period (.) right after a slash (/)"));
+ }
+ return FALSE;
+ }
+ }
+
+ if (*s == '/')
+ {
+ just_saw_slash = TRUE;
+ }
+ else
+ {
+ const gchar* inv = invalid_chars;
+
+ just_saw_slash = FALSE;
+
+ if (((unsigned char)*s) > 127)
+ {
+ if (why_invalid != NULL)
+ *why_invalid = g_strdup_printf (_("'%c' is not an ASCII character, so isn't allowed in key names"),
+ *s);
+ return FALSE;
+ }
+
+ while (*inv)
+ {
+ if (*inv == *s)
+ {
+ if (why_invalid != NULL)
+ *why_invalid = g_strdup_printf(_("`%c' is an invalid character in key/directory names"), *s);
+ return FALSE;
+ }
+ ++inv;
+ }
+ }
+
+ ++s;
+ }
+
+ /* Can't end with slash */
+ if (just_saw_slash)
+ {
+ if (why_invalid != NULL)
+ *why_invalid = g_strdup(_("Key/directory may not end with a slash (/)"));
+ return FALSE;
+ }
+ else
+ return TRUE;
+}
+
+/**
+ * gconf_escape_key:
+ * @arbitrary_text: some text in any encoding or format
+ * @len: length of @arbitrary_text in bytes, or -1 if @arbitrary_text is nul-terminated
+ *
+ * Escape @arbitrary_text such that it's a valid key element (i.e. one
+ * part of the key path). The escaped key won't pass gconf_valid_key()
+ * because it isn't a whole key (i.e. it doesn't have a preceding
+ * slash), but prepending a slash to the escaped text should always
+ * result in a valid key.
+ *
+ * Return value: a nul-terminated valid GConf key
+ **/
+char*
+gconf_escape_key (const char *arbitrary_text,
+ int len)
+{
+ const char *p;
+ const char *end;
+ GString *retval;
+
+ g_return_val_if_fail (arbitrary_text != NULL, NULL);
+
+ /* Nearly all characters we would normally use for escaping aren't allowed in key
+ * names, so we use @ for that.
+ *
+ * Invalid chars and @ itself are escaped as @xxx@ where xxx is the
+ * Latin-1 value in decimal
+ */
+
+ if (len < 0)
+ len = strlen (arbitrary_text);
+
+ retval = g_string_new (NULL);
+
+ p = arbitrary_text;
+ end = arbitrary_text + len;
+ while (p != end)
+ {
+ if (*p == '/' || *p == '.' || *p == '@' || ((guchar) *p) > 127 ||
+ strchr (invalid_chars, *p))
+ {
+ g_string_append_c (retval, '@');
+ g_string_append_printf (retval, "%u", (unsigned int) *p);
+ g_string_append_c (retval, '@');
+ }
+ else
+ g_string_append_c (retval, *p);
+
+ ++p;
+ }
+
+ return g_string_free (retval, FALSE);
+}
+
+/**
+ * gconf_unescape_key:
+ * @escaped_key: a key created with gconf_escape_key()
+ * @len: length of @escaped_key in bytes, or -1 if @escaped_key is nul-terminated
+ *
+ * Converts a string escaped with gconf_escape_key() back into its original
+ * form.
+ *
+ * Return value: the original string that was escaped to create @escaped_key
+ **/
+char*
+gconf_unescape_key (const char *escaped_key,
+ int len)
+{
+ const char *p;
+ const char *end;
+ const char *start_seq;
+ GString *retval;
+
+ g_return_val_if_fail (escaped_key != NULL, NULL);
+
+ if (len < 0)
+ len = strlen (escaped_key);
+
+ retval = g_string_new (NULL);
+
+ p = escaped_key;
+ end = escaped_key + len;
+ start_seq = NULL;
+ while (p != end)
+ {
+ if (start_seq)
+ {
+ if (*p == '@')
+ {
+ /* *p is the @ that ends a seq */
+ char *end;
+ guchar val;
+
+ val = strtoul (start_seq, &end, 10);
+ if (start_seq != end)
+ g_string_append_c (retval, val);
+
+ start_seq = NULL;
+ }
+ }
+ else
+ {
+ if (*p == '@')
+ start_seq = p + 1;
+ else
+ g_string_append_c (retval, *p);
+ }
+
+ ++p;
+ }
+
+ return g_string_free (retval, FALSE);
+}
+
+
+gboolean
+gconf_key_is_below (const gchar* above, const gchar* below)
+{
+ int len;
+
+ if (above[0] == '/' && above[1] == '\0')
+ return TRUE;
+
+ len = strlen (above);
+ if (strncmp (below, above, len) == 0)
+ {
+ /* only if this is a complete key component,
+ * so that /foo is not above /foofoo/bar */
+ if (below[len] == '\0' || below[len] == '/')
+ return TRUE;
+ else
+ return FALSE;
+ }
+ else
+ return FALSE;
+}
+
+gchar*
+gconf_unique_key (void)
+{
+ /* This function is hardly cryptographically random but should be
+ "good enough" */
+
+ static guint serial = 0;
+ gchar* key;
+ guint t, ut, p, u, r;
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ t = tv.tv_sec;
+ ut = tv.tv_usec;
+
+ p = getpid();
+
+ u = getuid();
+
+ /* don't bother to seed; if it's based on the time or any other
+ changing info we can get, we may as well just use that changing
+ info. since we don't seed we'll at least get a different number
+ on every call to this function in the same executable. */
+ r = rand();
+
+ /* The letters may increase uniqueness by preventing "melds"
+ i.e. 01t01k01 and 0101t0k1 are not the same */
+ key = g_strdup_printf("%ut%uut%uu%up%ur%uk%u",
+ /* Duplicate keys must be generated
+ by two different program instances */
+ serial,
+ /* Duplicate keys must be generated
+ in the same microsecond */
+ t,
+ ut,
+ /* Duplicate keys must be generated by
+ the same user */
+ u,
+ /* Duplicate keys must be generated by
+ two programs that got the same PID */
+ p,
+ /* Duplicate keys must be generated with the
+ same random seed and the same index into
+ the series of pseudorandom values */
+ r,
+ /* Duplicate keys must result from running
+ this function at the same stack location */
+ GPOINTER_TO_UINT(&key));
+
+ ++serial;
+
+ return key;
+}
+
+/*
+ * Sugar functions
+ */
+
+gdouble
+gconf_engine_get_float (GConfEngine* conf, const gchar* key,
+ GError** err)
+{
+ GConfValue* val;
+ static const gdouble deflt = 0.0;
+
+ g_return_val_if_fail(conf != NULL, 0.0);
+ g_return_val_if_fail(key != NULL, 0.0);
+
+ val = gconf_engine_get (conf, key, err);
+
+ if (val == NULL)
+ return deflt;
+ else
+ {
+ gdouble retval;
+
+ if (val->type != GCONF_VALUE_FLOAT)
+ {
+ if (err)
+ *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH, _("Expected float, got %s"),
+ gconf_value_type_to_string(val->type));
+ gconf_value_free(val);
+ return deflt;
+ }
+
+ retval = gconf_value_get_float(val);
+
+ gconf_value_free(val);
+
+ return retval;
+ }
+}
+
+gint
+gconf_engine_get_int (GConfEngine* conf, const gchar* key,
+ GError** err)
+{
+ GConfValue* val;
+ static const gint deflt = 0;
+
+ g_return_val_if_fail(conf != NULL, 0);
+ g_return_val_if_fail(key != NULL, 0);
+
+ val = gconf_engine_get (conf, key, err);
+
+ if (val == NULL)
+ return deflt;
+ else
+ {
+ gint retval;
+
+ if (val->type != GCONF_VALUE_INT)
+ {
+ if (err)
+ *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH, _("Expected int, got %s"),
+ gconf_value_type_to_string(val->type));
+ gconf_value_free(val);
+ return deflt;
+ }
+
+ retval = gconf_value_get_int(val);
+
+ gconf_value_free(val);
+
+ return retval;
+ }
+}
+
+gchar*
+gconf_engine_get_string(GConfEngine* conf, const gchar* key,
+ GError** err)
+{
+ GConfValue* val;
+ static const gchar* deflt = NULL;
+
+ g_return_val_if_fail(conf != NULL, NULL);
+ g_return_val_if_fail(key != NULL, NULL);
+
+ val = gconf_engine_get (conf, key, err);
+
+ if (val == NULL)
+ return deflt ? g_strdup(deflt) : NULL;
+ else
+ {
+ gchar* retval;
+
+ if (val->type != GCONF_VALUE_STRING)
+ {
+ if (err)
+ *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH, _("Expected string, got %s"),
+ gconf_value_type_to_string(val->type));
+ gconf_value_free(val);
+ return deflt ? g_strdup(deflt) : NULL;
+ }
+
+ retval = gconf_value_steal_string (val);
+ gconf_value_free (val);
+
+ return retval;
+ }
+}
+
+gboolean
+gconf_engine_get_bool (GConfEngine* conf, const gchar* key,
+ GError** err)
+{
+ GConfValue* val;
+ static const gboolean deflt = FALSE;
+
+ g_return_val_if_fail(conf != NULL, FALSE);
+ g_return_val_if_fail(key != NULL, FALSE);
+
+ val = gconf_engine_get (conf, key, err);
+
+ if (val == NULL)
+ return deflt;
+ else
+ {
+ gboolean retval;
+
+ if (val->type != GCONF_VALUE_BOOL)
+ {
+ if (err)
+ *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH, _("Expected bool, got %s"),
+ gconf_value_type_to_string(val->type));
+ gconf_value_free(val);
+ return deflt;
+ }
+
+ retval = gconf_value_get_bool(val);
+
+ gconf_value_free(val);
+
+ return retval;
+ }
+}
+
+GConfSchema*
+gconf_engine_get_schema (GConfEngine* conf, const gchar* key, GError** err)
+{
+ GConfValue* val;
+
+ g_return_val_if_fail(conf != NULL, NULL);
+ g_return_val_if_fail(key != NULL, NULL);
+
+ val = gconf_engine_get_with_locale(conf, key, gconf_current_locale(), err);
+
+ if (val == NULL)
+ return NULL;
+ else
+ {
+ GConfSchema* retval;
+
+ if (val->type != GCONF_VALUE_SCHEMA)
+ {
+ if (err)
+ *err = gconf_error_new(GCONF_ERROR_TYPE_MISMATCH, _("Expected schema, got %s"),
+ gconf_value_type_to_string(val->type));
+ gconf_value_free(val);
+ return NULL;
+ }
+
+ retval = gconf_value_steal_schema (val);
+ gconf_value_free (val);
+
+ return retval;
+ }
+}
+
+GSList*
+gconf_engine_get_list (GConfEngine* conf, const gchar* key,
+ GConfValueType list_type, GError** err)
+{
+ GConfValue* val;
+
+ g_return_val_if_fail(conf != NULL, NULL);
+ g_return_val_if_fail(key != NULL, NULL);
+ g_return_val_if_fail(list_type != GCONF_VALUE_INVALID, NULL);
+ g_return_val_if_fail(list_type != GCONF_VALUE_LIST, NULL);
+ g_return_val_if_fail(list_type != GCONF_VALUE_PAIR, NULL);
+ g_return_val_if_fail(err == NULL || *err == NULL, NULL);
+
+ val = gconf_engine_get_with_locale(conf, key, gconf_current_locale(), err);
+
+ if (val == NULL)
+ return NULL;
+ else
+ {
+ /* This type-checks the value */
+ return gconf_value_list_to_primitive_list_destructive(val, list_type, err);
+ }
+}
+
+gboolean
+gconf_engine_get_pair (GConfEngine* conf, const gchar* key,
+ GConfValueType car_type, GConfValueType cdr_type,
+ gpointer car_retloc, gpointer cdr_retloc,
+ GError** err)
+{
+ GConfValue* val;
+ GError* error = NULL;
+
+ g_return_val_if_fail(conf != NULL, FALSE);
+ g_return_val_if_fail(key != NULL, FALSE);
+ g_return_val_if_fail(car_type != GCONF_VALUE_INVALID, FALSE);
+ g_return_val_if_fail(car_type != GCONF_VALUE_LIST, FALSE);
+ g_return_val_if_fail(car_type != GCONF_VALUE_PAIR, FALSE);
+ g_return_val_if_fail(cdr_type != GCONF_VALUE_INVALID, FALSE);
+ g_return_val_if_fail(cdr_type != GCONF_VALUE_LIST, FALSE);
+ g_return_val_if_fail(cdr_type != GCONF_VALUE_PAIR, FALSE);
+ g_return_val_if_fail(car_retloc != NULL, FALSE);
+ g_return_val_if_fail(cdr_retloc != NULL, FALSE);
+ g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+
+ val = gconf_engine_get_with_locale(conf, key, gconf_current_locale(), &error);
+
+ if (error != NULL)
+ {
+ g_assert(val == NULL);
+
+ if (err)
+ *err = error;
+ else
+ g_error_free(error);
+
+ return FALSE;
+ }
+
+ if (val == NULL)
+ {
+ return TRUE;
+ }
+ else
+ {
+ /* Destroys val */
+ return gconf_value_pair_to_primitive_pair_destructive(val,
+ car_type, cdr_type,
+ car_retloc, cdr_retloc,
+ err);
+ }
+}
+
+/*
+ * Setters
+ */
+
+static gboolean
+error_checked_set(GConfEngine* conf, const gchar* key,
+ GConfValue* gval, GError** err)
+{
+ GError* my_err = NULL;
+
+ gconf_engine_set (conf, key, gval, &my_err);
+
+ gconf_value_free(gval);
+
+ if (my_err != NULL)
+ {
+ if (err)
+ *err = my_err;
+ else
+ g_error_free(my_err);
+ return FALSE;
+ }
+ else
+ return TRUE;
+}
+
+gboolean
+gconf_engine_set_float (GConfEngine* conf, const gchar* key,
+ gdouble val, GError** err)
+{
+ GConfValue* gval;
+
+ 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);
+
+ gval = gconf_value_new(GCONF_VALUE_FLOAT);
+
+ gconf_value_set_float(gval, val);
+
+ return error_checked_set(conf, key, gval, err);
+}
+
+gboolean
+gconf_engine_set_int (GConfEngine* conf, const gchar* key,
+ gint val, GError** err)
+{
+ GConfValue* gval;
+
+ 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);
+
+ gval = gconf_value_new(GCONF_VALUE_INT);
+
+ gconf_value_set_int(gval, val);
+
+ return error_checked_set(conf, key, gval, err);
+}
+
+gboolean
+gconf_engine_set_string (GConfEngine* conf, const gchar* key,
+ const gchar* val, GError** err)
+{
+ GConfValue* gval;
+
+ g_return_val_if_fail (val != NULL, FALSE);
+ 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);
+
+ g_return_val_if_fail (g_utf8_validate (val, -1, NULL), FALSE);
+
+ gval = gconf_value_new(GCONF_VALUE_STRING);
+
+ gconf_value_set_string(gval, val);
+
+ return error_checked_set(conf, key, gval, err);
+}
+
+gboolean
+gconf_engine_set_bool (GConfEngine* conf, const gchar* key,
+ gboolean val, GError** err)
+{
+ GConfValue* gval;
+
+ 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);
+
+ gval = gconf_value_new(GCONF_VALUE_BOOL);
+
+ gconf_value_set_bool(gval, !!val); /* canonicalize the bool */
+
+ return error_checked_set(conf, key, gval, err);
+}
+
+gboolean
+gconf_engine_set_schema (GConfEngine* conf, const gchar* key,
+ const GConfSchema* val, GError** err)
+{
+ GConfValue* gval;
+
+ g_return_val_if_fail(conf != NULL, FALSE);
+ g_return_val_if_fail(key != NULL, FALSE);
+ g_return_val_if_fail(val != NULL, FALSE);
+ g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+
+ gval = gconf_value_new(GCONF_VALUE_SCHEMA);
+
+ gconf_value_set_schema(gval, val);
+
+ return error_checked_set(conf, key, gval, err);
+}
+
+gboolean
+gconf_engine_set_list (GConfEngine* conf, const gchar* key,
+ GConfValueType list_type,
+ GSList* list,
+ GError** err)
+{
+ GConfValue* value_list;
+ GError *tmp_err = NULL;
+
+ g_return_val_if_fail(conf != NULL, FALSE);
+ g_return_val_if_fail(key != NULL, FALSE);
+ g_return_val_if_fail(list_type != GCONF_VALUE_INVALID, FALSE);
+ g_return_val_if_fail(list_type != GCONF_VALUE_LIST, FALSE);
+ g_return_val_if_fail(list_type != GCONF_VALUE_PAIR, FALSE);
+ g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+
+ value_list = gconf_value_list_from_primitive_list(list_type, list, &tmp_err);
+
+ if (tmp_err)
+ {
+ g_propagate_error (err, tmp_err);
+ return FALSE;
+ }
+
+ /* destroys the value_list */
+
+ return error_checked_set(conf, key, value_list, err);
+}
+
+gboolean
+gconf_engine_set_pair (GConfEngine* conf, const gchar* key,
+ GConfValueType car_type, GConfValueType cdr_type,
+ gconstpointer address_of_car,
+ gconstpointer address_of_cdr,
+ GError** err)
+{
+ GConfValue* pair;
+ GError *tmp_err = NULL;
+
+ g_return_val_if_fail(conf != NULL, FALSE);
+ g_return_val_if_fail(key != NULL, FALSE);
+ g_return_val_if_fail(car_type != GCONF_VALUE_INVALID, FALSE);
+ g_return_val_if_fail(car_type != GCONF_VALUE_LIST, FALSE);
+ g_return_val_if_fail(car_type != GCONF_VALUE_PAIR, FALSE);
+ g_return_val_if_fail(cdr_type != GCONF_VALUE_INVALID, FALSE);
+ g_return_val_if_fail(cdr_type != GCONF_VALUE_LIST, FALSE);
+ g_return_val_if_fail(cdr_type != GCONF_VALUE_PAIR, FALSE);
+ g_return_val_if_fail(address_of_car != NULL, FALSE);
+ g_return_val_if_fail(address_of_cdr != NULL, FALSE);
+ g_return_val_if_fail(err == NULL || *err == NULL, FALSE);
+
+
+ pair = gconf_value_pair_from_primitive_pair(car_type, cdr_type,
+ address_of_car, address_of_cdr,
+ &tmp_err);
+
+ if (tmp_err)
+ {
+ g_propagate_error (err, tmp_err);
+ return FALSE;
+ }
+
+ return error_checked_set(conf, key, pair, err);
+}
diff --git a/gconf/gconf.h b/gconf/gconf.h
index ee15dddd..41e2bce0 100644
--- a/gconf/gconf.h
+++ b/gconf/gconf.h
@@ -1,5 +1,5 @@
/* GConf
- * Copyright (C) 2003 Imendio HB
+ * Copyright (C) 1999, 2000 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,17 +21,306 @@
#define GCONF_GCONF_H
#include <glib.h>
-#include <dbus/dbus-glib.h>
-
-G_BEGIN_DECLS
-
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
#include <gconf/gconf-schema.h>
#include <gconf/gconf-engine.h>
#include <gconf/gconf-error.h>
#include <gconf/gconf-enum-types.h>
+typedef void (*GConfNotifyFunc) (GConfEngine* conf,
+ guint cnxn_id,
+ GConfEntry *entry,
+ gpointer user_data);
+
+/* Returns ID of the notification */
+/* returns 0 on error, 0 is an invalid ID */
+guint gconf_engine_notify_add (GConfEngine *conf,
+ /* dir or key to listen to */
+ const gchar *namespace_section,
+ GConfNotifyFunc func,
+ gpointer user_data,
+ GError **err);
+
+void gconf_engine_notify_remove (GConfEngine *conf,
+ guint cnxn);
+
+
+
+/* Low-level interfaces */
+GConfValue* gconf_engine_get (GConfEngine *conf,
+ const gchar *key,
+ GError **err);
+
+GConfValue* gconf_engine_get_without_default (GConfEngine *conf,
+ const gchar *key,
+ GError **err);
+
+GConfEntry* gconf_engine_get_entry (GConfEngine *conf,
+ const gchar *key,
+ const gchar *locale,
+ gboolean use_schema_default,
+ GError **err);
+
+
+/* Locale only matters if you are expecting to get a schema, or if you
+ don't know what you are expecting and it might be a schema. Note
+ that gconf_engine_get () automatically uses the current locale, which is
+ normally what you want. */
+GConfValue* gconf_engine_get_with_locale (GConfEngine *conf,
+ const gchar *key,
+ const gchar *locale,
+ GError **err);
+
+
+/* Get the default value stored in the schema associated with this key */
+GConfValue* gconf_engine_get_default_from_schema (GConfEngine *conf,
+ const gchar *key,
+ GError **err);
+gboolean gconf_engine_set (GConfEngine *conf,
+ const gchar *key,
+ const GConfValue *value,
+ GError **err);
+gboolean gconf_engine_unset (GConfEngine *conf,
+ const gchar *key,
+ GError **err);
+
+
+/*
+ * schema_key should have a schema (if key stores a value) or a dir
+ * full of schemas (if key stores a directory name)
+ */
+
+gboolean gconf_engine_associate_schema (GConfEngine *conf,
+ const gchar *key,
+ const gchar *schema_key,
+ GError **err);
+GSList* gconf_engine_all_entries (GConfEngine *conf,
+ const gchar *dir,
+ GError **err);
+GSList* gconf_engine_all_dirs (GConfEngine *conf,
+ const gchar *dir,
+ GError **err);
+void gconf_engine_suggest_sync (GConfEngine *conf,
+ GError **err);
+gboolean gconf_engine_dir_exists (GConfEngine *conf,
+ const gchar *dir,
+ GError **err);
+void gconf_engine_remove_dir (GConfEngine* conf,
+ const gchar* dir,
+ GError** err);
+
+gboolean gconf_engine_key_is_writable (GConfEngine *conf,
+ const gchar *key,
+ GError **err);
+
+/* if you pass non-NULL for why_invalid, it gives a user-readable
+ explanation of the problem in g_malloc()'d memory
+*/
+gboolean gconf_valid_key (const gchar *key,
+ gchar **why_invalid);
+
+
+/* return TRUE if the path "below" would be somewhere below the directory "above" */
+gboolean gconf_key_is_below (const gchar *above,
+ const gchar *below);
+
+
+/* Returns allocated concatenation of these two */
+gchar* gconf_concat_dir_and_key (const gchar *dir,
+ const gchar *key);
+
+
+/* Returns a different string every time (at least, the chances of
+ getting a duplicate are like one in a zillion). The key is a
+ legal gconf key name (a single element of one) */
+gchar* gconf_unique_key (void);
+
+/* Escape/unescape a string to create a valid key */
+char* gconf_escape_key (const char *arbitrary_text,
+ int len);
+char* gconf_unescape_key (const char *escaped_key,
+ int len);
+
+
+/*
+ * Higher-level stuff
+ */
+
+
+gdouble gconf_engine_get_float (GConfEngine *conf,
+ const gchar *key,
+ GError **err);
+gint gconf_engine_get_int (GConfEngine *conf,
+ const gchar *key,
+ GError **err);
+
+
+/* free the retval, retval can be NULL for "unset" */
+gchar* gconf_engine_get_string (GConfEngine *conf,
+ const gchar *key,
+ GError **err);
+gboolean gconf_engine_get_bool (GConfEngine *conf,
+ const gchar *key,
+ GError **err);
+
+
+/* this one has no default since it would be expensive and make little
+ sense; it returns NULL as a default, to indicate unset or error */
+/* free the retval */
+/* Note that this returns the schema stored at key, NOT
+ the schema associated with the key. */
+GConfSchema* gconf_engine_get_schema (GConfEngine *conf,
+ const gchar *key,
+ GError **err);
+
+
+/*
+ This automatically converts the list to the given list type;
+ a list of int or bool stores values in the list->data field
+ using GPOINTER_TO_INT(), a list of strings stores the gchar*
+ in list->data, a list of float contains pointers to allocated
+ gdouble (gotta love C!).
+*/
+GSList* gconf_engine_get_list (GConfEngine *conf,
+ const gchar *key,
+ GConfValueType list_type,
+ GError **err);
+
+/*
+ The car_retloc and cdr_retloc args should be the address of the appropriate
+ type:
+ bool gboolean*
+ int gint*
+ string gchar**
+ float gdouble*
+ schema GConfSchema**
+*/
+gboolean gconf_engine_get_pair (GConfEngine *conf,
+ const gchar *key,
+ GConfValueType car_type,
+ GConfValueType cdr_type,
+ gpointer car_retloc,
+ gpointer cdr_retloc,
+ GError **err);
+
+
+/* setters return TRUE on success; note that you still should suggest a sync */
+gboolean gconf_engine_set_float (GConfEngine *conf,
+ const gchar *key,
+ gdouble val,
+ GError **err);
+gboolean gconf_engine_set_int (GConfEngine *conf,
+ const gchar *key,
+ gint val,
+ GError **err);
+gboolean gconf_engine_set_string (GConfEngine *conf,
+ const gchar *key,
+ const gchar *val,
+ GError **err);
+gboolean gconf_engine_set_bool (GConfEngine *conf,
+ const gchar *key,
+ gboolean val,
+ GError **err);
+gboolean gconf_engine_set_schema (GConfEngine *conf,
+ const gchar *key,
+ const GConfSchema *val,
+ GError **err);
+
+
+/* List should be the same as the one gconf_engine_get_list() would return */
+gboolean gconf_engine_set_list (GConfEngine *conf,
+ const gchar *key,
+ GConfValueType list_type,
+ GSList *list,
+ GError **err);
+gboolean gconf_engine_set_pair (GConfEngine *conf,
+ const gchar *key,
+ GConfValueType car_type,
+ GConfValueType cdr_type,
+ gconstpointer address_of_car,
+ gconstpointer address_of_cdr,
+ GError **err);
+
+
+/* Utility function converts enumerations to and from strings */
+typedef struct _GConfEnumStringPair GConfEnumStringPair;
+
+struct _GConfEnumStringPair {
+ gint enum_value;
+ const gchar* str;
+};
+
+gboolean gconf_string_to_enum (GConfEnumStringPair lookup_table[],
+ const gchar *str,
+ gint *enum_value_retloc);
+const gchar* gconf_enum_to_string (GConfEnumStringPair lookup_table[],
+ gint enum_value);
+
+int gconf_debug_shutdown (void);
+
+#ifndef GCONF_DISABLE_DEPRECATED
+gboolean gconf_init (int argc, char **argv, GError** err);
+gboolean gconf_is_initialized (void);
+#endif /* GCONF_DISABLE_DEPRECATED */
+
+/* No, you can't use this stuff. Bad application developer. Bad. */
+#ifdef GCONF_ENABLE_INTERNALS
+
+/* This stuff is only useful in GNOME 2.0, so isn't in this GConf
+ * release.
+ */
+
+#ifndef GCONF_DISABLE_DEPRECATED
+/* For use by the Gnome module system */
+void gconf_preinit(gpointer app, gpointer mod_info);
+void gconf_postinit(gpointer app, gpointer mod_info);
+
+extern const char gconf_version[];
+
+#ifdef HAVE_POPT_H
+#include <popt.h>
+#endif
+
+#ifdef POPT_AUTOHELP
+/* If people are using popt, then make the table available to them */
+extern struct poptOption gconf_options[];
+#endif
+#endif /* GCONF_DISABLE_DEPRECATED */
+
+void gconf_clear_cache(GConfEngine* conf, GError** err);
+void gconf_synchronous_sync(GConfEngine* conf, GError** err);
+
+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);
+
+#endif /* GCONF_ENABLE_INTERNALS */
-/* Add common stuff here */
+#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"
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
G_END_DECLS
diff --git a/gconf/gconfd-dbus.c b/gconf/gconfd-dbus.c
index ab2d03fb..1412e6fa 100644
--- a/gconf/gconfd-dbus.c
+++ b/gconf/gconfd-dbus.c
@@ -21,7 +21,8 @@
#include "gconf-internals.h"
#include "gconf-locale.h"
#include "gconfd.h"
-#include "gconf-dbus.h"
+#include "gconf.h"
+#include "gconf-dbus-utils.h"
#include <time.h>
#include <string.h>
#include <sys/types.h>