diff options
author | Richard Hult <rhult@src.gnome.org> | 2003-11-24 12:17:24 +0000 |
---|---|---|
committer | Richard Hult <rhult@src.gnome.org> | 2003-11-24 12:17:24 +0000 |
commit | 4b3c6b95ff9ddb3a7b60d4627d35915bbbdb8b55 (patch) | |
tree | cd0abe45f3e48333489742b3ab434758e342388c | |
parent | 8609bbd740c0d211b761a69011fb215986f60f0d (diff) | |
download | gconf-4b3c6b95ff9ddb3a7b60d4627d35915bbbdb8b55.tar.gz |
Split out more common stuff.
-rw-r--r-- | gconf/Makefile.am | 6 | ||||
-rw-r--r-- | gconf/gconf-dbus-utils.h | 43 | ||||
-rw-r--r-- | gconf/gconf-dbus.c | 2621 | ||||
-rw-r--r-- | gconf/gconf.c | 810 | ||||
-rw-r--r-- | gconf/gconf.h | 301 | ||||
-rw-r--r-- | gconf/gconfd-dbus.c | 3 |
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> |