From 93faf2d7f46bbeb8624183745c79488a5421d6a2 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 3 May 2008 03:23:20 +0000 Subject: [PATCH] Add a dbus service for setting default values --- GConf2.spec | 15 +- gconf-defaults.patch | 1201 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1215 insertions(+), 1 deletion(-) create mode 100644 gconf-defaults.patch diff --git a/GConf2.spec b/GConf2.spec index d2108ba..42c629e 100644 --- a/GConf2.spec +++ b/GConf2.spec @@ -5,7 +5,7 @@ Summary: A process-transparent configuration system Name: GConf2 Version: 2.22.0 -Release: 2%{?dist} +Release: 3%{?dist} License: LGPLv2+ Group: System Environment/Base Source: http://download.gnome.org/sources/GConf/2.22/GConf-%{version}.tar.bz2 @@ -23,6 +23,9 @@ BuildRequires: openldap-devel BuildRequires: perl(XML::Parser) BuildRequires: libtool, autoconf, automake BuildRequires: intltool +# for patch3 +BuildRequires: PolicyKit-devel >= 0.8 +Requires: dbus # for patch0 Requires: /usr/bin/killall @@ -31,6 +34,8 @@ Patch0: GConf-2.18.0.1-reload.patch Patch1: GConf2-2.14.0-timeout.patch # http://bugzilla.gnome.org/show_bug.cgi?id=531063 Patch2: gconf-timeouts.patch +# http://bugzilla.gnome.org/show_bug.cgi?id=531169 +Patch3: gconf-defaults.patch %description GConf is a process-transparent configuration database API used to @@ -68,6 +73,7 @@ which require GTK+. %patch0 -p1 -b .reload %patch1 -p1 -b .timers %patch2 -p1 -b .timeouts +%patch3 -p1 -b .defaults %build rm -f libtool @@ -122,6 +128,10 @@ fi %{_mandir}/man1/* %dir %{_libdir}/GConf %dir %{_libdir}/GConf/2 +%{_sysconfdir}/dbus-1/system.d/org.gnome.GConf.Defaults.conf +%{_libexecdir}/gconf-defaults-mechanism +%{_datadir}/PolicyKit/policy/org.gnome.gconf.defaults.policy +%{_datadir}/dbus-1/system-services/org.gnome.GConf.Defaults.service %files gtk %{_libexecdir}/gconf-sanity-check-2 @@ -135,6 +145,9 @@ fi %{_libdir}/pkgconfig/* %changelog +* Fri May 2 2008 Matthias Clasen - 2.22.0-3 +- Add a dbus service to set defaults + * Fri May 2 2008 Matthias Clasen - 2.22.0-2 - Use g_timeout_add_seconds for long timeouts diff --git a/gconf-defaults.patch b/gconf-defaults.patch new file mode 100644 index 0000000..bf5e31f --- /dev/null +++ b/gconf-defaults.patch @@ -0,0 +1,1201 @@ +diff -u -r GConf-2.22.0/configure.in hacked/configure.in +--- GConf-2.22.0/configure.in 2008-03-10 10:52:28.000000000 -0400 ++++ hacked/configure.in 2008-05-02 00:05:01.000000000 -0400 +@@ -166,6 +166,7 @@ + AC_SUBST(DEPENDENT_WITH_XML_AND_GTK_LIBS) + AC_SUBST(DEPENDENT_WITH_XML_AND_GTK_CFLAGS) + ++PKG_CHECK_MODULES(DEFAULTS, glib-2.0 gobject-2.0 gconf-2.0 dbus-1 dbus-glib-1 polkit-dbus) + + ORBIT_IDL="`$PKG_CONFIG --variable=orbit_idl ORBit-2.0`" + AC_SUBST(ORBIT_IDL) +@@ -261,6 +262,7 @@ + doc/gconf/Makefile + examples/Makefile + tests/Makefile ++defaults/Makefile + gconf-2.0.pc + ]) + +diff -u -r GConf-2.22.0/defaults/gconf-defaults.c hacked/defaults/gconf-defaults.c +--- GConf-2.22.0/defaults/gconf-defaults.c 2008-05-02 23:07:19.000000000 -0400 ++++ hacked/defaults/gconf-defaults.c 2008-05-02 22:12:17.000000000 -0400 +@@ -0,0 +1,704 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2008 Matthias Clasen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++#define GCONF_ENABLE_INTERNALS ++#include ++#include ++ ++#include "gconf-defaults.h" ++#include "gconf-defaults-glue.h" ++ ++static gboolean ++do_exit (gpointer user_data) ++{ ++ g_debug ("Exiting due to inactivity"); ++ exit (1); ++ return FALSE; ++} ++ ++static guint timer_id = 0; ++ ++static void ++stop_killtimer (void) ++{ ++ if (timer_id > 0) { ++ g_source_remove (timer_id); ++ timer_id = 0; ++ } ++} ++ ++static void ++start_killtimer (void) ++{ ++ g_debug ("Setting killtimer to 30 seconds..."); ++ timer_id = g_timeout_add_seconds (30, do_exit, NULL); ++} ++ ++struct GConfDefaultsPrivate ++{ ++ DBusGConnection *system_bus_connection; ++ DBusGProxy *system_bus_proxy; ++ PolKitContext *pol_ctx; ++}; ++ ++static void gconf_defaults_finalize (GObject *object); ++ ++G_DEFINE_TYPE (GConfDefaults, gconf_defaults, G_TYPE_OBJECT) ++ ++#define GCONF_DEFAULTS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCONF_TYPE_DEFAULTS, GConfDefaultsPrivate)) ++ ++GQuark ++gconf_defaults_error_quark (void) ++{ ++ static GQuark ret = 0; ++ ++ if (ret == 0) { ++ ret = g_quark_from_static_string ("gconf_defaults_error"); ++ } ++ ++ return ret; ++} ++ ++ ++#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC } ++ ++GType ++gconf_defaults_error_get_type (void) ++{ ++ static GType etype = 0; ++ ++ if (etype == 0) ++ { ++ static const GEnumValue values[] = ++ { ++ ENUM_ENTRY (GCONF_DEFAULTS_ERROR_GENERAL, "GeneralError"), ++ ENUM_ENTRY (GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED, "NotPrivileged"), ++ { 0, 0, 0 } ++ }; ++ ++ g_assert (GCONF_DEFAULTS_NUM_ERRORS == G_N_ELEMENTS (values) - 1); ++ ++ etype = g_enum_register_static ("GConfDefaultsError", values); ++ } ++ ++ return etype; ++} ++ ++ ++static GObject * ++gconf_defaults_constructor (GType type, ++ guint n_construct_properties, ++ GObjectConstructParam *construct_properties) ++{ ++ GConfDefaults *mechanism; ++ GConfDefaultsClass *klass; ++ ++ klass = GCONF_DEFAULTS_CLASS (g_type_class_peek (GCONF_TYPE_DEFAULTS)); ++ ++ mechanism = GCONF_DEFAULTS (G_OBJECT_CLASS (gconf_defaults_parent_class)->constructor ( ++ type, ++ n_construct_properties, ++ construct_properties)); ++ ++ return G_OBJECT (mechanism); ++} ++ ++static void ++gconf_defaults_class_init (GConfDefaultsClass *klass) ++{ ++ GObjectClass *object_class = G_OBJECT_CLASS (klass); ++ ++ object_class->constructor = gconf_defaults_constructor; ++ object_class->finalize = gconf_defaults_finalize; ++ ++ g_type_class_add_private (klass, sizeof (GConfDefaultsPrivate)); ++ ++ dbus_g_object_type_install_info (GCONF_TYPE_DEFAULTS, &dbus_glib_gconf_defaults_object_info); ++ ++ dbus_g_error_domain_register (GCONF_DEFAULTS_ERROR, NULL, GCONF_DEFAULTS_TYPE_ERROR); ++ ++} ++ ++static void ++gconf_defaults_init (GConfDefaults *mechanism) ++{ ++ mechanism->priv = GCONF_DEFAULTS_GET_PRIVATE (mechanism); ++} ++ ++static void ++gconf_defaults_finalize (GObject *object) ++{ ++ GConfDefaults *mechanism; ++ ++ g_return_if_fail (object != NULL); ++ g_return_if_fail (GCONF_IS_DEFAULTS (object)); ++ ++ mechanism = GCONF_DEFAULTS (object); ++ ++ g_return_if_fail (mechanism->priv != NULL); ++ ++ g_object_unref (mechanism->priv->system_bus_proxy); ++ ++ G_OBJECT_CLASS (gconf_defaults_parent_class)->finalize (object); ++} ++ ++static gboolean ++pk_io_watch_have_data (GIOChannel *channel, GIOCondition condition, gpointer user_data) ++{ ++ int fd; ++ PolKitContext *pk_context = user_data; ++ fd = g_io_channel_unix_get_fd (channel); ++ polkit_context_io_func (pk_context, fd); ++ return TRUE; ++} ++ ++static int ++pk_io_add_watch (PolKitContext *pk_context, int fd) ++{ ++ guint id = 0; ++ GIOChannel *channel; ++ channel = g_io_channel_unix_new (fd); ++ if (channel == NULL) ++ goto out; ++ id = g_io_add_watch (channel, G_IO_IN, pk_io_watch_have_data, pk_context); ++ if (id == 0) { ++ g_io_channel_unref (channel); ++ goto out; ++ } ++ g_io_channel_unref (channel); ++out: ++ return id; ++} ++ ++static void ++pk_io_remove_watch (PolKitContext *pk_context, int watch_id) ++{ ++ g_source_remove (watch_id); ++} ++ ++static gboolean ++register_mechanism (GConfDefaults *mechanism) ++{ ++ GError *error = NULL; ++ ++ mechanism->priv->pol_ctx = polkit_context_new (); ++ polkit_context_set_io_watch_functions (mechanism->priv->pol_ctx, pk_io_add_watch, pk_io_remove_watch); ++ if (!polkit_context_init (mechanism->priv->pol_ctx, NULL)) { ++ g_critical ("cannot initialize libpolkit"); ++ goto error; ++ } ++ ++ error = NULL; ++ mechanism->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); ++ if (mechanism->priv->system_bus_connection == NULL) { ++ if (error != NULL) { ++ g_critical ("error getting system bus: %s", error->message); ++ g_error_free (error); ++ } ++ goto error; ++ } ++ ++ dbus_g_connection_register_g_object (mechanism->priv->system_bus_connection, "/", ++ G_OBJECT (mechanism)); ++ ++ mechanism->priv->system_bus_proxy = dbus_g_proxy_new_for_name (mechanism->priv->system_bus_connection, ++ DBUS_SERVICE_DBUS, ++ DBUS_PATH_DBUS, ++ DBUS_INTERFACE_DBUS); ++ ++ start_killtimer (); ++ ++ return TRUE; ++ ++error: ++ return FALSE; ++} ++ ++ ++GConfDefaults * ++gconf_defaults_new (void) ++{ ++ GObject *object; ++ gboolean res; ++ ++ object = g_object_new (GCONF_TYPE_DEFAULTS, NULL); ++ ++ res = register_mechanism (GCONF_DEFAULTS (object)); ++ if (! res) { ++ g_object_unref (object); ++ return NULL; ++ } ++ ++ return GCONF_DEFAULTS (object); ++} ++ ++static const char * ++polkit_action_for_gconf_path (GConfDefaults *mechanism, ++ const char *annotation_key, ++ const char *path) ++{ ++ PolKitPolicyCache *cache; ++ PolKitPolicyFileEntry *entry; ++ char *prefix, *p; ++ const char *action; ++ ++ cache = polkit_context_get_policy_cache (mechanism->priv->pol_ctx); ++ prefix = g_strdup (path); ++ ++ while (1) { ++ entry = polkit_policy_cache_get_entry_by_annotation (cache, ++ annotation_key, ++ prefix); ++ if (entry) { ++ action = polkit_policy_file_entry_get_id (entry); ++ break; ++ } ++ ++ p = strrchr (prefix, '/'); ++ ++ if (p == NULL || p == prefix) { ++ action = NULL; ++ break; ++ } ++ ++ *p = 0; ++ } ++ ++ g_free (prefix); ++ ++ return action; ++} ++ ++static gboolean ++check_polkit_for_action (GConfDefaults *mechanism, ++ DBusGMethodInvocation *context, ++ const char *action) ++{ ++ const char *sender; ++ GError *error; ++ DBusError dbus_error; ++ PolKitCaller *pk_caller; ++ PolKitAction *pk_action; ++ PolKitResult pk_result; ++ ++ error = NULL; ++ ++ /* Check that caller is privileged */ ++ sender = dbus_g_method_get_sender (context); ++ dbus_error_init (&dbus_error); ++ pk_caller = polkit_caller_new_from_dbus_name ( ++ dbus_g_connection_get_connection (mechanism->priv->system_bus_connection), ++ sender, ++ &dbus_error); ++ if (pk_caller == NULL) { ++ error = g_error_new (GCONF_DEFAULTS_ERROR, ++ GCONF_DEFAULTS_ERROR_GENERAL, ++ "Error getting information about caller: %s: %s", ++ dbus_error.name, dbus_error.message); ++ dbus_error_free (&dbus_error); ++ dbus_g_method_return_error (context, error); ++ g_error_free (error); ++ return FALSE; ++ } ++ ++ pk_action = polkit_action_new (); ++ polkit_action_set_action_id (pk_action, action); ++ pk_result = polkit_context_is_caller_authorized (mechanism->priv->pol_ctx, pk_action, pk_caller, TRUE, NULL); ++ polkit_caller_unref (pk_caller); ++ ++ if (pk_result != POLKIT_RESULT_YES) { ++ dbus_error_init (&dbus_error); ++ polkit_dbus_error_generate (pk_action, pk_result, &dbus_error); ++ dbus_set_g_error (&error, &dbus_error); ++ dbus_g_method_return_error (context, error); ++ dbus_error_free (&dbus_error); ++ g_error_free (error); ++ polkit_action_unref (pk_action); ++ return FALSE; ++ } ++ ++ polkit_action_unref (pk_action); ++ return TRUE; ++} ++ ++static char * ++gconf_address_for_caller (GConfDefaults *mechanism, ++ DBusGMethodInvocation *context, ++ GError **gerror) ++{ ++ char *sender; ++ DBusConnection *conn; ++ uid_t uid; ++ struct passwd *pwd; ++ char *result; ++ DBusError error; ++ ++ conn = dbus_g_connection_get_connection (mechanism->priv->system_bus_connection); ++ sender = dbus_g_method_get_sender (context); ++ ++ dbus_error_init (&error); ++ uid = dbus_bus_get_unix_user (conn, sender, &error); ++ g_free (sender); ++ if (uid == (unsigned)-1) { ++ dbus_set_g_error (gerror, &error); ++ dbus_error_free (&error); ++ return NULL; ++ } ++ ++ pwd = getpwuid (uid); ++ if (pwd == NULL) { ++ g_set_error (gerror, ++ 0, 0, ++ "Failed to get passwd information for uid %d", uid); ++ return NULL; ++ } ++ ++ result = g_strconcat ("xml:merged:", pwd->pw_dir, "/.gconf", NULL); ++ return result; ++} ++ ++static gboolean ++path_is_excluded (const char *path, ++ const char **excludes) ++{ ++ int i; ++ ++ for (i = 0; excludes && excludes[i]; i++) { ++ if (g_str_has_prefix (path, excludes[i])) ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++static void ++copy_tree (GConfClient *src, ++ const char *path, ++ GConfChangeSet *changes, ++ const char **excludes) ++{ ++ GSList *list, *l; ++ GConfEntry *entry; ++ ++ if (path_is_excluded (path, excludes)) ++ return; ++ ++ list = gconf_client_all_entries (src, path, NULL); ++ for (l = list; l; l = l->next) { ++ entry = l->data; ++ if (!path_is_excluded (entry->key, excludes)) ++ gconf_change_set_set (changes, entry->key, entry->value); ++ } ++ g_slist_foreach (list, (GFunc)gconf_entry_free, NULL); ++ g_slist_free (list); ++ ++ list = gconf_client_all_dirs (src, path, NULL); ++ for (l = list; l; l = l->next) ++ copy_tree (src, (const char *)l->data, changes, excludes); ++ g_slist_foreach (list, (GFunc)g_free, NULL); ++ g_slist_free (list); ++} ++ ++static void ++copy_entry (GConfClient *src, ++ const char *path, ++ GConfChangeSet *changes, ++ const char **excludes) ++{ ++ GConfValue *value; ++ ++ if (path_is_excluded (path, excludes)) ++ return; ++ ++ value = gconf_client_get (src, path, NULL); ++ if (value) { ++ gconf_change_set_set (changes, path, value); ++ gconf_value_free (value); ++ } ++} ++ ++ ++void ++do_copy (GConfDefaults *mechanism, ++ gboolean mandatory, ++ const char **includes, ++ const char **excludes, ++ DBusGMethodInvocation *context) ++{ ++ char *address = NULL; ++ GConfClient *source = NULL; ++ GConfClient *dest = NULL; ++ GConfChangeSet *changes = NULL; ++ GConfEngine *engine; ++ GError *error; ++ GError *error2; ++ const char *action; ++ const char *annotation_key; ++ const char *default_action; ++ const char *dest_address; ++ int i; ++ ++ stop_killtimer (); ++ ++ /* check privileges for each include */ ++ if (mandatory) { ++ annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix"; ++ default_action = "org.gnome.gconf.defaults.set-mandatory"; ++ dest_address = "xml:merged:/etc/gconf/gconf.xml.mandatory"; ++ } ++ else { ++ annotation_key = "org.gnome.gconf.defaults.set-system.prefix"; ++ default_action = "org.gnome.gconf.defaults.set-system"; ++ dest_address = "xml:merged:/etc/gconf/gconf.xml.system"; ++ } ++ ++ for (i = 0; includes[i]; i++) { ++ action = polkit_action_for_gconf_path (mechanism, annotation_key, includes[i]); ++ if (action == NULL) ++ action = default_action; ++ ++ if (!check_polkit_for_action (mechanism, context, action)) ++ goto out; ++ } ++ ++ error = NULL; ++ engine = gconf_engine_get_local (dest_address, &error); ++ if (error) ++ goto cleanup; ++ ++ dest = gconf_client_get_for_engine (engine); ++ gconf_engine_unref (engine); ++ ++ /* find the address to from the caller id */ ++ address = gconf_address_for_caller (mechanism, context, &error); ++ if (error) ++ goto cleanup; ++ ++ engine = gconf_engine_get_local (address, &error); ++ if (error) ++ goto cleanup; ++ ++ source = gconf_client_get_for_engine (engine); ++ gconf_engine_unref (engine); ++ ++ changes = gconf_change_set_new (); ++ ++ /* recursively copy each include, leaving out the excludes */ ++ for (i = 0; includes[i]; i++) { ++ if (gconf_client_dir_exists (source, includes[i], NULL)) ++ copy_tree (source, includes[i], changes, excludes); ++ else ++ copy_entry (source, includes[i], changes, excludes); ++ } ++ ++ gconf_client_commit_change_set (dest, changes, TRUE, &error); ++ gconf_client_suggest_sync (dest, NULL); ++ ++cleanup: ++ g_free (address); ++ if (changes) ++ gconf_change_set_unref (changes); ++ if (dest) ++ g_object_unref (dest); ++ if (source) ++ g_object_unref (source); ++ ++ if (error) { ++ g_print ("failed to set GConf values: %s\n", error->message); ++ error2 = g_error_new (GCONF_DEFAULTS_ERROR, ++ GCONF_DEFAULTS_ERROR_GENERAL, ++ error->message); ++ g_error_free (error); ++ ++ dbus_g_method_return_error (context, error2); ++ g_error_free (error2); ++ } ++ else ++ dbus_g_method_return (context); ++ ++out: ++ start_killtimer (); ++} ++ ++void ++gconf_defaults_set_system (GConfDefaults *mechanism, ++ const char **includes, ++ const char **excludes, ++ DBusGMethodInvocation *context) ++{ ++ do_copy (mechanism, FALSE, includes, excludes, context); ++} ++ ++ ++void ++gconf_defaults_set_mandatory (GConfDefaults *mechanism, ++ const char **includes, ++ const char **excludes, ++ DBusGMethodInvocation *context) ++{ ++ do_copy (mechanism, TRUE, includes, excludes, context); ++} ++ ++static void ++unset_tree (GConfClient *dest, ++ const char *path, ++ GConfChangeSet *changes, ++ const char **excludes) ++{ ++ GSList *list, *l; ++ GConfEntry *entry; ++ ++ if (path_is_excluded (path, excludes)) ++ return; ++ ++ list = gconf_client_all_entries (dest, path, NULL); ++ for (l = list; l; l = l->next) { ++ entry = l->data; ++ if (!path_is_excluded (entry->key, excludes)) ++ gconf_change_set_unset (changes, entry->key); ++ } ++ g_slist_foreach (list, (GFunc)gconf_entry_free, NULL); ++ g_slist_free (list); ++ ++ list = gconf_client_all_dirs (dest, path, NULL); ++ for (l = list; l; l = l->next) ++ unset_tree (dest, (const char *)l->data, changes, excludes); ++ g_slist_foreach (list, (GFunc)g_free, NULL); ++ g_slist_free (list); ++} ++ ++static void ++unset_entry (GConfClient *dest, ++ const char *path, ++ GConfChangeSet *changes, ++ const char **excludes) ++{ ++ if (path_is_excluded (path, excludes)) ++ return; ++ ++ gconf_change_set_unset (changes, path); ++} ++ ++static void ++unset_in_db (GConfDefaults *mechanism, ++ const char *address, ++ const char **includes, ++ const char **excludes, ++ GError **error) ++{ ++ GConfEngine *engine; ++ GConfClient *dest = NULL; ++ GConfChangeSet *changes = NULL; ++ int i; ++ ++ engine = gconf_engine_get_local (address, error); ++ if (*error) ++ goto out; ++ ++ dest = gconf_client_get_for_engine (engine); ++ gconf_engine_unref (engine); ++ ++ changes = gconf_change_set_new (); ++ ++ /* recursively copy each include, leaving out the excludes */ ++ for (i = 0; includes[i]; i++) { ++ if (gconf_client_dir_exists (dest, includes[i], NULL)) ++ unset_tree (dest, includes[i], changes, excludes); ++ else ++ unset_entry (dest, includes[i], changes, excludes); ++ } ++ ++ gconf_client_commit_change_set (dest, changes, TRUE, error); ++ gconf_client_suggest_sync (dest, NULL); ++ ++out: ++ if (dest) ++ g_object_unref (dest); ++ if (changes) ++ gconf_change_set_unref (changes); ++} ++ ++void ++gconf_defaults_unset_mandatory (GConfDefaults *mechanism, ++ const char **includes, ++ const char **excludes, ++ DBusGMethodInvocation *context) ++{ ++ const char *annotation_key; ++ const char *default_action; ++ int i; ++ const char *action; ++ GError *error; ++ GError *error2; ++ ++ stop_killtimer (); ++ ++ annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix"; ++ default_action = "org.gnome.gconf.defaults.set-mandatory"; ++ ++ for (i = 0; includes[i]; i++) { ++ action = polkit_action_for_gconf_path (mechanism, annotation_key, includes[i]); ++ if (action == NULL) ++ action = default_action; ++ ++ if (!check_polkit_for_action (mechanism, context, action)) ++ goto out; ++ } ++ ++ error = NULL; ++ unset_in_db (mechanism,"xml:merged:/etc/gconf/gconf.xml.mandatory", ++ includes, excludes, &error); ++ ++ if (error) { ++ error2 = g_error_new (GCONF_DEFAULTS_ERROR, ++ GCONF_DEFAULTS_ERROR_GENERAL, ++ error->message); ++ g_error_free (error); ++ ++ dbus_g_method_return_error (context, error2); ++ g_error_free (error2); ++ } ++ else ++ dbus_g_method_return (context); ++out: ++ start_killtimer(); ++} +diff -u -r GConf-2.22.0/defaults/gconf-defaults.h hacked/defaults/gconf-defaults.h +--- GConf-2.22.0/defaults/gconf-defaults.h 2008-05-02 23:07:19.000000000 -0400 ++++ hacked/defaults/gconf-defaults.h 2008-05-02 14:08:18.000000000 -0400 +@@ -0,0 +1,84 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2008 Matthias Clasen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ */ ++ ++#ifndef GCONF_DEFAULTS_H ++#define GCONF_DEFAULTS_H ++ ++#include ++#include ++ ++G_BEGIN_DECLS ++ ++#define GCONF_TYPE_DEFAULTS (gconf_defaults_get_type ()) ++#define GCONF_DEFAULTS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GCONF_TYPE_DEFAULTS, GConfDefaults)) ++#define GCONF_DEFAULTS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GCONF_TYPE_DEFAULTS, GConfDefaultsClass)) ++#define GCONF_IS_DEFAULTS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GCONF_TYPE_DEFAULTS)) ++#define GCONF_IS_DEFAULTS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GCONF_TYPE_DEFAULTS)) ++#define GCONF_DEFAULTS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GCONF_TYPE_DEFAULTS, GConfDefaultsClass)) ++ ++typedef struct GConfDefaultsPrivate GConfDefaultsPrivate; ++ ++typedef struct ++{ ++ GObject parent; ++ GConfDefaultsPrivate *priv; ++} GConfDefaults; ++ ++typedef struct ++{ ++ GObjectClass parent_class; ++} GConfDefaultsClass; ++ ++typedef enum ++{ ++ GCONF_DEFAULTS_ERROR_GENERAL, ++ GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED, ++ GCONF_DEFAULTS_NUM_ERRORS ++} GConfDefaultsError; ++ ++#define GCONF_DEFAULTS_ERROR gconf_defaults_error_quark () ++ ++GType gconf_defaults_error_get_type (void); ++#define GCONF_DEFAULTS_TYPE_ERROR (gconf_defaults_error_get_type ()) ++ ++ ++GQuark gconf_defaults_error_quark (void); ++GType gconf_defaults_get_type (void); ++GConfDefaults *gconf_defaults_new (void); ++ ++/* exported methods */ ++void gconf_defaults_set_system (GConfDefaults *mechanism, ++ const char **includes, ++ const char **excludes, ++ DBusGMethodInvocation *context); ++ ++void gconf_defaults_set_mandatory (GConfDefaults *mechanism, ++ const char **includes, ++ const char **excludes, ++ DBusGMethodInvocation *context); ++ ++void gconf_defaults_unset_mandatory (GConfDefaults *mechanism, ++ const char **includes, ++ const char **excludes, ++ DBusGMethodInvocation *context); ++ ++G_END_DECLS ++ ++#endif /* GCONF_DEFAULTS_H */ +diff -u -r GConf-2.22.0/defaults/gconf-defaults-main.c hacked/defaults/gconf-defaults-main.c +--- GConf-2.22.0/defaults/gconf-defaults-main.c 2008-05-02 23:07:19.000000000 -0400 ++++ hacked/defaults/gconf-defaults-main.c 2008-05-01 14:41:50.000000000 -0400 +@@ -0,0 +1,174 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2008 Matthias Clasen ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++#include ++#include ++ ++ ++#include "gconf-defaults.h" ++ ++static DBusGProxy * ++get_bus_proxy (DBusGConnection *connection) ++{ ++ DBusGProxy *bus_proxy; ++ ++ bus_proxy = dbus_g_proxy_new_for_name (connection, ++ DBUS_SERVICE_DBUS, ++ DBUS_PATH_DBUS, ++ DBUS_INTERFACE_DBUS); ++ return bus_proxy; ++} ++ ++#define BUS_NAME "org.gnome.GConf.Defaults" ++ ++static gboolean ++acquire_name_on_proxy (DBusGProxy *bus_proxy) ++{ ++ GError *error; ++ guint result; ++ gboolean res; ++ gboolean ret; ++ ++ ret = FALSE; ++ ++ if (bus_proxy == NULL) { ++ goto out; ++ } ++ ++ error = NULL; ++ res = dbus_g_proxy_call (bus_proxy, ++ "RequestName", ++ &error, ++ G_TYPE_STRING, BUS_NAME, ++ G_TYPE_UINT, 0, ++ G_TYPE_INVALID, ++ G_TYPE_UINT, &result, ++ G_TYPE_INVALID); ++ if (! res) { ++ if (error != NULL) { ++ g_warning ("Failed to acquire %s: %s", BUS_NAME, error->message); ++ g_error_free (error); ++ } else { ++ g_warning ("Failed to acquire %s", BUS_NAME); ++ } ++ goto out; ++ } ++ ++ if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { ++ if (error != NULL) { ++ g_warning ("Failed to acquire %s: %s", BUS_NAME, error->message); ++ g_error_free (error); ++ } else { ++ g_warning ("Failed to acquire %s", BUS_NAME); ++ } ++ goto out; ++ } ++ ++ ret = TRUE; ++ ++ out: ++ return ret; ++} ++ ++static DBusGConnection * ++get_system_bus (void) ++{ ++ GError *error; ++ DBusGConnection *bus; ++ DBusConnection *connection; ++ ++ error = NULL; ++ bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); ++ if (bus == NULL) { ++ g_warning ("Couldn't connect to system bus: %s", error->message); ++ g_error_free (error); ++ goto out; ++ } ++ ++ connection = dbus_g_connection_get_connection (bus); ++ out: ++ return bus; ++} ++ ++int ++main (int argc, char **argv) ++{ ++ GMainLoop *loop; ++ GConfDefaults *mechanism; ++ DBusGProxy *bus_proxy; ++ DBusGConnection *connection; ++ int ret; ++ ++ ret = 1; ++ ++ if (! g_thread_supported ()) { ++ g_thread_init (NULL); ++ } ++ dbus_g_thread_init (); ++ g_type_init (); ++ ++ connection = get_system_bus (); ++ if (connection == NULL) { ++ goto out; ++ } ++ ++ bus_proxy = get_bus_proxy (connection); ++ if (bus_proxy == NULL) { ++ g_warning ("Could not construct bus_proxy object; bailing out"); ++ goto out; ++ } ++ ++ mechanism = gconf_defaults_new (); ++ ++ if (mechanism == NULL) { ++ goto out; ++ } ++ ++ if (!acquire_name_on_proxy (bus_proxy)) { ++ g_warning ("Could not acquire name; bailing out"); ++ goto out; ++ } ++ ++ loop = g_main_loop_new (NULL, FALSE); ++ ++ g_main_loop_run (loop); ++ ++ g_object_unref (mechanism); ++ g_main_loop_unref (loop); ++ ret = 0; ++ ++out: ++ return ret; ++} +diff -u -r GConf-2.22.0/defaults/gconf-defaults.xml hacked/defaults/gconf-defaults.xml +--- GConf-2.22.0/defaults/gconf-defaults.xml 2008-05-02 23:07:19.000000000 -0400 ++++ hacked/defaults/gconf-defaults.xml 2008-05-02 22:45:08.000000000 -0400 +@@ -0,0 +1,61 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff -u -r GConf-2.22.0/defaults/Makefile.am hacked/defaults/Makefile.am +--- GConf-2.22.0/defaults/Makefile.am 2008-05-02 23:07:19.000000000 -0400 ++++ hacked/defaults/Makefile.am 2008-04-30 23:35:38.000000000 -0400 +@@ -0,0 +1,51 @@ ++libexec_PROGRAMS = gconf-defaults-mechanism ++ ++gconf-defaults-glue.h: $(srcdir)/gconf-defaults.xml ++ dbus-binding-tool --prefix=gconf_defaults --mode=glib-server \ ++ --output=gconf-defaults-glue.h \ ++ $(srcdir)/gconf-defaults.xml ++ ++ ++gconf_defaults_mechanism_SOURCES = \ ++ gconf-defaults.h \ ++ gconf-defaults.c \ ++ gconf-defaults-glue.h \ ++ gconf-defaults-main.c ++ ++INCLUDES = $(DEFAULTS_CFLAGS) ++ ++gconf_defaults_mechanism_LDADD = $(DEFAULTS_LIBS) ++ ++BUILT_SOURCES = gconf-defaults-glue.h ++ ++dbus_servicesdir = $(datadir)/dbus-1/system-services ++dbus_confdir = $(sysconfdir)/dbus-1/system.d ++polkitdir = $(datadir)/PolicyKit/policy ++ ++dbus_services_in_files = org.gnome.GConf.Defaults.service.in ++polkit_in_files = org.gnome.gconf.defaults.policy.in ++ ++dbus_services_DATA = $(dbus_services_in_files:.service.in=.service) ++ ++$(dbus_services_DATA): $(dbus_services_in_files) ++ sed -e "s|\@LIBEXECDIR\@|$(libexecdir)|" $< > $@ ++ ++dbus_conf_DATA = org.gnome.GConf.Defaults.conf ++ ++@INTLTOOL_POLICY_RULE@ ++polkit_DATA = $(polkit_in_files:.policy.in=.policy) ++ ++check: ++ $(POLKIT_POLICY_FILE_VALIDATE) $(polkit_DATA) ++ ++EXTRA_DIST = \ ++ $(dbus_services_in_files) \ ++ org.gnome.GConf.Defaults.conf \ ++ $(polkit_in_files) \ ++ gconf-defaults.xml ++ ++CLEANFILES = \ ++ $(BUILT_SOURCES) \ ++ $(polkit_DATA) \ ++ $(dbus_services_DATA) ++ +diff -u -r GConf-2.22.0/defaults/org.gnome.GConf.Defaults.conf hacked/defaults/org.gnome.GConf.Defaults.conf +--- GConf-2.22.0/defaults/org.gnome.GConf.Defaults.conf 2008-05-02 23:07:19.000000000 -0400 ++++ hacked/defaults/org.gnome.GConf.Defaults.conf 2008-05-02 14:09:10.000000000 -0400 +@@ -0,0 +1,23 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff -u -r GConf-2.22.0/defaults/org.gnome.gconf.defaults.policy.in hacked/defaults/org.gnome.gconf.defaults.policy.in +--- GConf-2.22.0/defaults/org.gnome.gconf.defaults.policy.in 2008-05-02 23:07:19.000000000 -0400 ++++ hacked/defaults/org.gnome.gconf.defaults.policy.in 2008-05-02 14:09:28.000000000 -0400 +@@ -0,0 +1,28 @@ ++ ++ ++ ++ The GNOME Project ++ http://www.gnome.org/projects/gconf/ ++ gconf-editor ++ ++ ++ Change GConf system values ++ Privileges are required to change GConf system values ++ ++ no ++ auth_admin ++ ++ ++ ++ ++ Change GConf mandatory values ++ Privileges are required to change GConf mandatory values ++ ++ no ++ auth_admin ++ ++ ++ ++ +diff -u -r GConf-2.22.0/defaults/org.gnome.GConf.Defaults.service.in hacked/defaults/org.gnome.GConf.Defaults.service.in +--- GConf-2.22.0/defaults/org.gnome.GConf.Defaults.service.in 2008-05-02 23:07:19.000000000 -0400 ++++ hacked/defaults/org.gnome.GConf.Defaults.service.in 2008-05-01 14:39:59.000000000 -0400 +@@ -0,0 +1,4 @@ ++[D-BUS Service] ++Name=org.gnome.GConf.Defaults ++Exec=@LIBEXECDIR@/gconf-defaults-mechanism ++User=root +diff -u -r GConf-2.22.0/Makefile.am hacked/Makefile.am +--- GConf-2.22.0/Makefile.am 2007-06-25 07:11:31.000000000 -0400 ++++ hacked/Makefile.am 2008-04-30 23:32:45.000000000 -0400 +@@ -1,5 +1,5 @@ + +-SUBDIRS = gconf backends po doc examples ++SUBDIRS = gconf backends po doc examples defaults + DIST_SUBDIRS=tests $(SUBDIRS) + + EXTRA_DIST = \ +diff -u -r GConf-2.22.0/po/POTFILES.in hacked/po/POTFILES.in +--- GConf-2.22.0/po/POTFILES.in 2007-06-25 07:11:31.000000000 -0400 ++++ hacked/po/POTFILES.in 2008-05-01 22:14:31.000000000 -0400 +@@ -9,6 +9,7 @@ + backends/xml-cache.c + backends/xml-dir.c + backends/xml-entry.c ++defaults/org.gnome.gconf.defaults.policy.in + gconf/gconf-backend.c + gconf/gconf-client.c + gconf/gconf-database.c