~ubuntu-branches/ubuntu/quantal/gconf/quantal

« back to all changes in this revision

Viewing changes to .pc/01_defaults_path.patch/defaults/gconf-defaults.c

  • Committer: Bazaar Package Importer
  • Author(s): Emilio Pozuelo Monfort, Josselin Mouette, Sjoerd Simons, Emilio Pozuelo Monfort
  • Date: 2010-12-06 00:53:14 UTC
  • mfrom: (1.1.25 upstream)
  • mto: (7.3.4 sid)
  • mto: This revision was merged to the branch mainline in revision 58.
  • Revision ID: james.westby@ubuntu.com-20101206005314-uz89yke6r1xfw504
Tags: 2.32.1-1
[ Josselin Mouette ]
* Include patch-translations.mk, bump build-depends accordingly.
* Include 03_error_message.patch in POTFILES.in.
* pt_BR.po: Brazilian Portuguese translation. Closes: #599032.
* fr.po: French translation by Christian Perrier. Closes: #599049.
* da.po: Danish translation by Joe Hansen. Closes: #599125.
* cs.po: Czech translation by Michal Simunek. Closes: #599198.
* update-gconf-defaults: patch from Ubuntu to deal with broken 
  symlinks. Closes: #599393. Thanks Michael Vogt.
* de.po: German translation by Helge Kreutzmann. Closes: #599683.
* sv.po: Swedish translation by Martin Bagge. Closes: #599854.
* 04_manpage.patch: patch from A. Costa. Fixes typos in the manual 
  page. Closes: #600899.

[ Sjoerd Simons ]
* New upstream release
* Bump gobject-introspection to the lastest version to generate the most
  recent .gir version
* debian/patches/03_error_message.patch
  + Removed, merged upstream
* debian/rules:
  + Specify compilation with gtk2

[ Emilio Pozuelo Monfort ]
* Switch to source format 3.0 (quilt).
* debian/patches/*:
  - Updated to apply cleanly.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright (C) 2008, 2009 Matthias Clasen <mclasen@redhat.com>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU General Public License as published by
 
7
 * the Free Software Foundation; either version 2 of the License, or
 
8
 * (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
18
 *
 
19
 */
 
20
 
 
21
#include <config.h>
 
22
 
 
23
#include <stdlib.h>
 
24
#include <stdio.h>
 
25
#include <fcntl.h>
 
26
#include <unistd.h>
 
27
#include <string.h>
 
28
#include <sys/wait.h>
 
29
#include <errno.h>
 
30
#include <sys/time.h>
 
31
#include <sys/types.h>
 
32
#include <pwd.h>
 
33
 
 
34
#include <glib.h>
 
35
#include <glib-object.h>
 
36
 
 
37
#include <dbus/dbus-glib.h>
 
38
#include <dbus/dbus-glib-lowlevel.h>
 
39
 
 
40
#include <polkit/polkit.h>
 
41
 
 
42
#define GCONF_ENABLE_INTERNALS
 
43
#include <gconf/gconf-client.h>
 
44
#include <gconf/gconf-engine.h>
 
45
 
 
46
#include "gconf-defaults.h"
 
47
#include "gconf-defaults-glue.h"
 
48
 
 
49
static gboolean
 
50
do_exit (gpointer user_data)
 
51
{
 
52
        g_debug ("Exiting due to inactivity");
 
53
        exit (1);
 
54
        return FALSE;
 
55
}
 
56
 
 
57
static guint timer_id = 0;
 
58
gboolean disable_killtimer = FALSE;
 
59
 
 
60
static void
 
61
stop_killtimer (void)
 
62
{
 
63
        if (disable_killtimer)
 
64
                return;
 
65
 
 
66
        if (timer_id > 0) {
 
67
                g_source_remove (timer_id);
 
68
                timer_id = 0;
 
69
        }
 
70
}
 
71
 
 
72
static void
 
73
start_killtimer (void)
 
74
{
 
75
        if (disable_killtimer)
 
76
                return;
 
77
 
 
78
        if (timer_id == 0) {
 
79
                g_debug ("Setting killtimer to 30 seconds...");
 
80
                timer_id = g_timeout_add_seconds (30, do_exit, NULL);
 
81
        }
 
82
}
 
83
 
 
84
static gint operations = 0;
 
85
 
 
86
static void
 
87
start_operation (void)
 
88
{
 
89
        if (operations == 0)
 
90
                stop_killtimer ();
 
91
        operations++;
 
92
}
 
93
 
 
94
static void
 
95
stop_operation (void)
 
96
{
 
97
        if (operations == 1)
 
98
                start_killtimer ();
 
99
        operations --;
 
100
}
 
101
 
 
102
struct GConfDefaultsPrivate
 
103
{
 
104
        DBusGConnection *system_bus_connection;
 
105
        DBusGProxy      *system_bus_proxy;
 
106
        PolkitAuthority *auth;
 
107
};
 
108
 
 
109
static void gconf_defaults_finalize (GObject *object);
 
110
 
 
111
G_DEFINE_TYPE (GConfDefaults, gconf_defaults, G_TYPE_OBJECT)
 
112
 
 
113
#define GCONF_DEFAULTS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GCONF_TYPE_DEFAULTS, GConfDefaultsPrivate))
 
114
 
 
115
GQuark
 
116
gconf_defaults_error_quark (void)
 
117
{
 
118
        static GQuark ret = 0;
 
119
 
 
120
        if (ret == 0) {
 
121
                ret = g_quark_from_static_string ("gconf_defaults_error");
 
122
        }
 
123
 
 
124
        return ret;
 
125
}
 
126
 
 
127
 
 
128
#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
 
129
 
 
130
GType
 
131
gconf_defaults_error_get_type (void)
 
132
{
 
133
        static GType etype = 0;
 
134
 
 
135
        if (etype == 0)
 
136
        {
 
137
                static const GEnumValue values[] =
 
138
                        {
 
139
                                ENUM_ENTRY (GCONF_DEFAULTS_ERROR_GENERAL, "GeneralError"),
 
140
                                ENUM_ENTRY (GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED, "NotPrivileged"),
 
141
                                { 0, 0, 0 }
 
142
                        };
 
143
 
 
144
                g_assert (GCONF_DEFAULTS_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
 
145
 
 
146
                etype = g_enum_register_static ("GConfDefaultsError", values);
 
147
        }
 
148
 
 
149
        return etype;
 
150
}
 
151
 
 
152
 
 
153
static GObject *
 
154
gconf_defaults_constructor (GType                  type,
 
155
                            guint                  n_construct_properties,
 
156
                            GObjectConstructParam *construct_properties)
 
157
{
 
158
        GConfDefaults      *mechanism;
 
159
        GConfDefaultsClass *klass;
 
160
 
 
161
        klass = GCONF_DEFAULTS_CLASS (g_type_class_peek (GCONF_TYPE_DEFAULTS));
 
162
 
 
163
        mechanism = GCONF_DEFAULTS (G_OBJECT_CLASS (gconf_defaults_parent_class)->constructor (
 
164
                                                type,
 
165
                                                n_construct_properties,
 
166
                                                construct_properties));
 
167
 
 
168
        return G_OBJECT (mechanism);
 
169
}
 
170
 
 
171
enum {
 
172
        SYSTEM_SET,
 
173
        LAST_SIGNAL
 
174
};
 
175
 
 
176
static guint signals[LAST_SIGNAL] = { 0 };
 
177
 
 
178
static void
 
179
gconf_defaults_class_init (GConfDefaultsClass *klass)
 
180
{
 
181
        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
 
182
 
 
183
        object_class->constructor = gconf_defaults_constructor;
 
184
        object_class->finalize = gconf_defaults_finalize;
 
185
 
 
186
        signals[SYSTEM_SET] = g_signal_new ("system-set",
 
187
                                            G_OBJECT_CLASS_TYPE (object_class),
 
188
                                            G_SIGNAL_RUN_FIRST,
 
189
                                            G_STRUCT_OFFSET (GConfDefaultsClass, system_set),
 
190
                                            NULL, NULL,
 
191
                                            g_cclosure_marshal_VOID__BOXED,
 
192
                                            G_TYPE_NONE, 1, G_TYPE_STRV);
 
193
 
 
194
        g_type_class_add_private (klass, sizeof (GConfDefaultsPrivate));
 
195
 
 
196
        dbus_g_object_type_install_info (GCONF_TYPE_DEFAULTS, &dbus_glib_gconf_defaults_object_info);
 
197
 
 
198
        dbus_g_error_domain_register (GCONF_DEFAULTS_ERROR, NULL, GCONF_DEFAULTS_TYPE_ERROR);
 
199
 
 
200
}
 
201
 
 
202
static void
 
203
gconf_defaults_init (GConfDefaults *mechanism)
 
204
{
 
205
        mechanism->priv = GCONF_DEFAULTS_GET_PRIVATE (mechanism);
 
206
}
 
207
 
 
208
static void
 
209
gconf_defaults_finalize (GObject *object)
 
210
{
 
211
        GConfDefaults *mechanism;
 
212
 
 
213
        g_return_if_fail (object != NULL);
 
214
        g_return_if_fail (GCONF_IS_DEFAULTS (object));
 
215
 
 
216
        mechanism = GCONF_DEFAULTS (object);
 
217
 
 
218
        g_return_if_fail (mechanism->priv != NULL);
 
219
 
 
220
        g_object_unref (mechanism->priv->auth);
 
221
        g_object_unref (mechanism->priv->system_bus_proxy);
 
222
 
 
223
        G_OBJECT_CLASS (gconf_defaults_parent_class)->finalize (object);
 
224
}
 
225
 
 
226
static gboolean
 
227
register_mechanism (GConfDefaults *mechanism)
 
228
{
 
229
        GError *error = NULL;
 
230
 
 
231
        mechanism->priv->auth = polkit_authority_get ();
 
232
 
 
233
        error = NULL;
 
234
        mechanism->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
 
235
        if (mechanism->priv->system_bus_connection == NULL) {
 
236
                if (error != NULL) {
 
237
                        g_critical ("error getting system bus: %s", error->message);
 
238
                        g_error_free (error);
 
239
                }
 
240
                goto error;
 
241
        }
 
242
 
 
243
        dbus_g_connection_register_g_object (mechanism->priv->system_bus_connection, "/",
 
244
                                             G_OBJECT (mechanism));
 
245
 
 
246
        mechanism->priv->system_bus_proxy = dbus_g_proxy_new_for_name (mechanism->priv->system_bus_connection,
 
247
                                                                      DBUS_SERVICE_DBUS,
 
248
                                                                      DBUS_PATH_DBUS,
 
249
                                                                      DBUS_INTERFACE_DBUS);
 
250
 
 
251
        start_killtimer ();
 
252
 
 
253
        return TRUE;
 
254
 
 
255
error:
 
256
        return FALSE;
 
257
}
 
258
 
 
259
 
 
260
GConfDefaults *
 
261
gconf_defaults_new (void)
 
262
{
 
263
        GObject *object;
 
264
        gboolean res;
 
265
 
 
266
        object = g_object_new (GCONF_TYPE_DEFAULTS, NULL);
 
267
 
 
268
        res = register_mechanism (GCONF_DEFAULTS (object));
 
269
        if (! res) {
 
270
                g_object_unref (object);
 
271
                return NULL;
 
272
        }
 
273
 
 
274
        return GCONF_DEFAULTS (object);
 
275
}
 
276
 
 
277
static const char *
 
278
polkit_action_for_gconf_path (GConfDefaults *mechanism,
 
279
                              GList         *action_descriptions,
 
280
                              const char    *annotation_key,
 
281
                              const char    *path)
 
282
{
 
283
        char *prefix, *p;
 
284
        const char *action;
 
285
        GList *l;
 
286
        PolkitActionDescription *action_description;
 
287
        const gchar *annotation;
 
288
 
 
289
        g_debug ("finding action for path '%s'", path);
 
290
        prefix = g_strdup (path);
 
291
        while (1) {
 
292
                for (l = action_descriptions; l; l = l->next) {
 
293
                        action_description = l->data;
 
294
 
 
295
                        annotation = polkit_action_description_get_annotation (action_description, annotation_key);
 
296
                        if (g_strcmp0 (prefix, annotation) == 0) {
 
297
                                action = polkit_action_description_get_action_id (action_description);
 
298
                                g_debug ("action for prefix '%s': '%s'\n", prefix, action);
 
299
                                goto found;
 
300
                        }
 
301
                }
 
302
 
 
303
                p = strrchr (prefix, '/');
 
304
 
 
305
                if (p == NULL || p == prefix) {
 
306
                        action = NULL;
 
307
                        break;
 
308
                }
 
309
 
 
310
                *p = 0;
 
311
        }
 
312
 
 
313
 found:
 
314
        g_free (prefix);
 
315
 
 
316
        return action;
 
317
}
 
318
 
 
319
static void
 
320
throw_error (DBusGMethodInvocation *context,
 
321
             gint                   error_code,
 
322
             const gchar           *format,
 
323
             ...)
 
324
{
 
325
        GError *error;
 
326
        va_list args;
 
327
        gchar *message;
 
328
 
 
329
        va_start (args, format);
 
330
        message = g_strdup_vprintf (format, args);
 
331
        va_end (args);
 
332
 
 
333
        error = g_error_new (GCONF_DEFAULTS_ERROR,
 
334
                             error_code,
 
335
                             "%s", message);
 
336
        dbus_g_method_return_error (context, error);
 
337
        g_error_free (error);
 
338
        g_free (message);
 
339
}
 
340
 
 
341
typedef void (*AuthObtainedCallback) (GConfDefaults          *mechanism,
 
342
                                      DBusGMethodInvocation  *context,
 
343
                                      gpointer                user_data);
 
344
 
 
345
typedef struct
 
346
{
 
347
        GConfDefaults                   *mechanism;
 
348
        DBusGMethodInvocation           *context;
 
349
        gchar                          **actions;
 
350
        gint                             id;
 
351
        gint                             flags;
 
352
        AuthObtainedCallback             auth_obtained_callback;
 
353
        GAsyncReadyCallback              check_auth_callback;
 
354
        gpointer                         user_data;
 
355
        GDestroyNotify                   destroy;
 
356
        PolkitSubject                   *subject;
 
357
        gboolean                         challenge;
 
358
} CheckAuthData;
 
359
 
 
360
static void
 
361
check_auth_data_free (CheckAuthData *data)
 
362
{
 
363
        g_object_unref (data->mechanism);
 
364
        g_strfreev (data->actions);
 
365
        if (data->destroy)
 
366
                data->destroy (data->user_data);
 
367
        g_object_unref (data->subject);
 
368
        g_free (data);
 
369
}
 
370
 
 
371
static void check_next_action (CheckAuthData *data);
 
372
 
 
373
static void
 
374
check_authorization_callback (PolkitAuthority *authority,
 
375
                              GAsyncResult    *res,
 
376
                              gpointer         user_data)
 
377
{
 
378
        CheckAuthData *data = user_data;
 
379
        PolkitAuthorizationResult *result;
 
380
        GError *error;
 
381
        gboolean is_authorized;
 
382
 
 
383
        is_authorized = FALSE;
 
384
 
 
385
        error = NULL;
 
386
        result = polkit_authority_check_authorization_finish (authority,
 
387
                                                              res,
 
388
                                                              &error);
 
389
        if (error != NULL) {
 
390
                g_debug ("error checking action '%s'\n", error->message);
 
391
                throw_error (data->context,
 
392
                             GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
 
393
                             "Not Authorized: %s", error->message);
 
394
                g_error_free (error);
 
395
        }
 
396
        else {
 
397
                if (polkit_authorization_result_get_is_authorized (result)) {
 
398
                        g_debug ("result for '%s': authorized\n",
 
399
                                 data->actions[data->id]);
 
400
                        is_authorized = TRUE;
 
401
                }
 
402
                else if (polkit_authorization_result_get_is_challenge (result)) {
 
403
                        g_debug ("result for '%s': challenge\n",
 
404
                                 data->actions[data->id]);
 
405
                        throw_error (data->context,
 
406
                                     GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
 
407
                                     "Authorization is required");
 
408
                }
 
409
                else {
 
410
                        g_debug ("result for '%s': not authorized\n",
 
411
                                 data->actions[data->id]);
 
412
                        throw_error (data->context,
 
413
                                     GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
 
414
                                     "Not Authorized");
 
415
                }
 
416
        }
 
417
 
 
418
        if (is_authorized) {
 
419
                data->id++;
 
420
                if (data->actions[data->id] == NULL)
 
421
                        data->auth_obtained_callback (data->mechanism,
 
422
                                                      data->context,
 
423
                                                      data->user_data);
 
424
                else {
 
425
                        check_next_action (data);
 
426
                        return; /* continue operation */
 
427
                }
 
428
        }
 
429
 
 
430
        check_auth_data_free (data);
 
431
        g_object_unref (result);
 
432
        stop_operation ();
 
433
}
 
434
 
 
435
static void
 
436
check_next_action (CheckAuthData *data)
 
437
{
 
438
        g_debug ("checking action '%s'\n", data->actions[data->id]);
 
439
        polkit_authority_check_authorization (data->mechanism->priv->auth,
 
440
                                              data->subject,
 
441
                                              data->actions[data->id],
 
442
                                              NULL,
 
443
                                              data->flags,
 
444
                                              NULL,
 
445
                                              data->check_auth_callback,
 
446
                                              data);
 
447
}
 
448
 
 
449
static void
 
450
check_polkit_for_actions (GConfDefaults                   *mechanism,
 
451
                          DBusGMethodInvocation           *context,
 
452
                          gchar                          **actions,
 
453
                          AuthObtainedCallback             auth_obtained_callback,
 
454
                          gpointer                         user_data,
 
455
                          GDestroyNotify                   destroy)
 
456
{
 
457
        CheckAuthData *data;
 
458
 
 
459
        data = g_new0 (CheckAuthData, 1);
 
460
        data->mechanism = g_object_ref (mechanism);
 
461
        data->context = context;
 
462
        data->actions = actions;
 
463
        data->flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION;
 
464
        data->id = 0;
 
465
        data->auth_obtained_callback = auth_obtained_callback;
 
466
        data->check_auth_callback = (GAsyncReadyCallback)check_authorization_callback;
 
467
        data->user_data = user_data;
 
468
        data->destroy = destroy;
 
469
        data->subject = polkit_system_bus_name_new (dbus_g_method_get_sender (context));
 
470
        data->challenge = FALSE;
 
471
 
 
472
        check_next_action (data);
 
473
}
 
474
 
 
475
static char *
 
476
gconf_address_for_caller (GConfDefaults          *mechanism,
 
477
                          DBusGMethodInvocation  *context,
 
478
                          GError                **gerror)
 
479
{
 
480
        char *sender;
 
481
        DBusConnection *conn;
 
482
        uid_t uid;
 
483
        struct passwd *pwd;
 
484
        char *result;
 
485
        DBusError error;
 
486
 
 
487
        conn = dbus_g_connection_get_connection (mechanism->priv->system_bus_connection);
 
488
        sender = dbus_g_method_get_sender (context);
 
489
 
 
490
        dbus_error_init (&error);
 
491
        uid = dbus_bus_get_unix_user (conn, sender, &error);
 
492
        g_free (sender);
 
493
        if (uid == (unsigned)-1) {
 
494
                dbus_set_g_error (gerror, &error);
 
495
                dbus_error_free (&error);
 
496
                return NULL;
 
497
        }
 
498
 
 
499
        pwd = getpwuid (uid);
 
500
        if (pwd == NULL) {
 
501
                g_set_error (gerror,
 
502
                             0, 0,
 
503
                             "Failed to get passwd information for uid %d", uid);
 
504
                return NULL;
 
505
        }
 
506
 
 
507
        result = g_strconcat ("xml:merged:", pwd->pw_dir, "/.gconf", NULL);
 
508
        return result;
 
509
}
 
510
 
 
511
static gboolean
 
512
path_is_excluded (const char  *path,
 
513
                  const char **excludes)
 
514
{
 
515
        int i;
 
516
 
 
517
        for (i = 0; excludes && excludes[i]; i++) {
 
518
                if (g_str_has_prefix (path, excludes[i]))
 
519
                        return TRUE;
 
520
        }
 
521
 
 
522
        return FALSE;
 
523
}
 
524
 
 
525
static void
 
526
copy_tree (GConfClient     *src,
 
527
           const char      *path,
 
528
           GConfChangeSet  *changes,
 
529
           const char     **excludes)
 
530
{
 
531
        GSList *list, *l;
 
532
        GConfEntry *entry;
 
533
 
 
534
        if (path_is_excluded (path, excludes))
 
535
                return;
 
536
 
 
537
        list = gconf_client_all_entries (src, path, NULL);
 
538
        for (l = list; l; l = l->next) {
 
539
                entry = l->data;
 
540
                if (!path_is_excluded (entry->key, excludes))
 
541
                        gconf_change_set_set (changes, entry->key, entry->value);
 
542
        }
 
543
        g_slist_foreach (list, (GFunc)gconf_entry_free, NULL);
 
544
        g_slist_free (list);
 
545
 
 
546
        list = gconf_client_all_dirs (src, path, NULL);
 
547
        for (l = list; l; l = l->next)
 
548
                copy_tree (src, (const char *)l->data, changes, excludes);
 
549
        g_slist_foreach (list, (GFunc)g_free, NULL);
 
550
        g_slist_free (list);
 
551
}
 
552
 
 
553
static void
 
554
copy_entry (GConfClient     *src,
 
555
            const char      *path,
 
556
            GConfChangeSet  *changes,
 
557
            const char     **excludes)
 
558
{
 
559
        GConfValue *value;
 
560
 
 
561
        if (path_is_excluded (path, excludes))
 
562
                return;
 
563
 
 
564
        value = gconf_client_get (src, path, NULL);
 
565
        if (value) {
 
566
                gconf_change_set_set (changes, path, value);
 
567
                gconf_value_free (value);
 
568
        }
 
569
}
 
570
 
 
571
typedef void (*ChangeSetCallback) (GConfDefaults  *mechanism,
 
572
                                   GConfChangeSet *changes,
 
573
                                   gpointer        data);
 
574
 
 
575
typedef struct
 
576
{
 
577
        GConfDefaults                   *mechanism;
 
578
        DBusGMethodInvocation           *context;
 
579
        const char                      *dest_address;
 
580
        char                           **actions;
 
581
        char                           **includes;
 
582
        char                           **excludes;
 
583
        GConfValue                      *value;
 
584
        ChangeSetCallback                changeset_callback;
 
585
        gpointer                         user_data;
 
586
        GDestroyNotify                   destroy;
 
587
} CopyData;
 
588
 
 
589
static void
 
590
copy_data_free (gpointer user_data)
 
591
{
 
592
        CopyData *data = user_data;
 
593
 
 
594
        g_object_unref (data->mechanism);
 
595
        g_strfreev (data->includes);
 
596
        g_strfreev (data->excludes);
 
597
        g_strfreev (data->actions);
 
598
        if (data->value)
 
599
                gconf_value_free (data->value);
 
600
        if (data->destroy)
 
601
                data->destroy (data->user_data);
 
602
        g_free (data);
 
603
}
 
604
 
 
605
static void
 
606
do_copy_authorized (GConfDefaults          *mechanism,
 
607
                    DBusGMethodInvocation  *context,
 
608
                    gpointer                user_data)
 
609
{
 
610
        CopyData    *data = user_data;
 
611
        GConfClient *source = NULL;
 
612
        GConfClient *dest = NULL;
 
613
        GConfChangeSet *changes = NULL;
 
614
        GConfEngine *engine;
 
615
        char *address = NULL;
 
616
        gint i;
 
617
        GError *error;
 
618
 
 
619
        error = NULL;
 
620
        engine = gconf_engine_get_local (data->dest_address, &error);
 
621
        if (error)
 
622
                goto cleanup;
 
623
 
 
624
        dest = gconf_client_get_for_engine (engine);
 
625
        gconf_engine_unref (engine);
 
626
 
 
627
        /* find the address to from the caller id */
 
628
        address = gconf_address_for_caller (data->mechanism, data->context, &error);
 
629
        if (error)
 
630
                goto cleanup;
 
631
 
 
632
        engine = gconf_engine_get_local (address, &error);
 
633
        if (error)
 
634
                goto cleanup;
 
635
 
 
636
        source = gconf_client_get_for_engine (engine);
 
637
        gconf_engine_unref (engine);
 
638
 
 
639
        changes = gconf_change_set_new ();
 
640
 
 
641
        if (data->value) {
 
642
                g_assert (data->includes[1] == NULL);
 
643
                g_assert (data->excludes == NULL);
 
644
 
 
645
                gconf_change_set_set (changes, data->includes[0], data->value);
 
646
        }
 
647
        else {
 
648
                /* recursively copy each include, leaving out the excludes */
 
649
                for (i = 0; data->includes[i]; i++) {
 
650
                        if (gconf_client_dir_exists (source, data->includes[i], NULL))
 
651
                                copy_tree (source, data->includes[i], changes, (const char **)data->excludes);
 
652
                        else
 
653
                                copy_entry (source, data->includes[i], changes, (const char **)data->excludes);
 
654
                }
 
655
        }
 
656
 
 
657
        gconf_client_commit_change_set (dest, changes, FALSE, &error);
 
658
        gconf_client_suggest_sync (dest, NULL);
 
659
 
 
660
        if (data->changeset_callback) {
 
661
                data->changeset_callback (data->mechanism, changes, data->user_data);
 
662
        }
 
663
 
 
664
cleanup:
 
665
        g_free (address);
 
666
        if (changes)
 
667
                gconf_change_set_unref (changes);
 
668
        if (dest)
 
669
                g_object_unref (dest);
 
670
        if (source)
 
671
                g_object_unref (source);
 
672
 
 
673
        if (error) {
 
674
                throw_error (data->context,
 
675
                             GCONF_DEFAULTS_ERROR_GENERAL,
 
676
                             "%s", error->message);
 
677
                g_error_free (error);
 
678
        }
 
679
        else
 
680
                dbus_g_method_return (data->context);
 
681
}
 
682
 
 
683
typedef void (*ActionsReadyCallback) (GConfDefaults          *mechanism,
 
684
                                      DBusGMethodInvocation  *context,
 
685
                                      gchar                 **actions,
 
686
                                      AuthObtainedCallback    auth_obtained_callback,
 
687
                                      gpointer                data,
 
688
                                      GDestroyNotify          destroy);
 
689
 
 
690
typedef struct
 
691
{
 
692
        GConfDefaults                   *mechanism;
 
693
        DBusGMethodInvocation           *context;
 
694
        char                           **includes;
 
695
        const char                      *default_action;
 
696
        const char                      *annotation_key;
 
697
        ActionsReadyCallback             actions_ready_callback;
 
698
        AuthObtainedCallback             auth_obtained_callback;
 
699
        gpointer                         data;
 
700
        GDestroyNotify                   destroy;
 
701
} ActionData;
 
702
 
 
703
static void
 
704
action_data_free (ActionData *data)
 
705
{
 
706
        g_object_unref (data->mechanism);
 
707
        g_strfreev (data->includes);
 
708
        if (data->destroy)
 
709
                data->destroy (data->data);
 
710
        g_free (data);
 
711
}
 
712
 
 
713
static void
 
714
actions_ready_cb (GObject      *source,
 
715
                  GAsyncResult *res,
 
716
                  gpointer      user_data)
 
717
{
 
718
        ActionData *data = user_data;
 
719
        GList *action_descriptions;
 
720
        GError *error = NULL;
 
721
        int i;
 
722
        GHashTable *obtained;
 
723
        GHashTableIter iter;
 
724
        const gchar *action;
 
725
        gchar **actions;
 
726
        gpointer key, value;
 
727
 
 
728
        action_descriptions = polkit_authority_enumerate_actions_finish (data->mechanism->priv->auth, res, &error);
 
729
 
 
730
        if (error) {
 
731
                throw_error (data->context,
 
732
                             GCONF_DEFAULTS_ERROR_GENERAL,
 
733
                             "Failed to get action descriptions: %s", error->message);
 
734
                g_error_free (error);
 
735
                action_data_free (data);
 
736
                stop_operation ();
 
737
                return;
 
738
        }
 
739
 
 
740
        obtained = g_hash_table_new (g_str_hash, g_str_equal);
 
741
 
 
742
        for (i = 0; data->includes[i]; i++) {
 
743
                action = polkit_action_for_gconf_path (data->mechanism, action_descriptions, data->annotation_key, data->includes[i]);
 
744
                if (action == NULL) {
 
745
                        g_debug ("using default action '%s' for path '%s'",
 
746
                                 data->default_action, data->includes[i]);
 
747
                        action = data->default_action;
 
748
                }
 
749
 
 
750
                g_hash_table_insert (obtained, (gpointer)action, (gpointer)action);
 
751
        }
 
752
        actions = g_new0 (char *, g_hash_table_size (obtained) + 1);
 
753
        g_hash_table_iter_init (&iter, obtained);
 
754
        i = 0;
 
755
        while (g_hash_table_iter_next (&iter, &key, &value)) {
 
756
                actions[i] = g_strdup ((char *)key);
 
757
                i++;
 
758
        }
 
759
        g_hash_table_destroy (obtained);
 
760
        g_list_foreach (action_descriptions, (GFunc)g_object_unref, NULL);
 
761
        g_list_free (action_descriptions);
 
762
 
 
763
        data->actions_ready_callback (data->mechanism, data->context, actions, data->auth_obtained_callback, data->data, data->destroy);
 
764
 
 
765
        data->destroy = NULL;
 
766
        action_data_free (data);
 
767
}
 
768
 
 
769
static void
 
770
do_copy (GConfDefaults          *mechanism,
 
771
         gboolean                mandatory,
 
772
         const gchar           **includes,
 
773
         const gchar           **excludes,
 
774
         GConfValue             *value,
 
775
         DBusGMethodInvocation  *context,
 
776
         ChangeSetCallback       changeset_callback,
 
777
         gpointer                user_data,
 
778
         GDestroyNotify          destroy)
 
779
{
 
780
        CopyData *cdata;
 
781
        ActionData *adata;
 
782
 
 
783
        start_operation ();
 
784
 
 
785
        cdata = g_new0 (CopyData, 1);
 
786
        cdata->mechanism = g_object_ref (mechanism);
 
787
        cdata->context = context;
 
788
        cdata->includes = g_strdupv ((gchar **)includes);
 
789
        cdata->excludes = g_strdupv ((gchar **)excludes);
 
790
        cdata->value = value;
 
791
        cdata->actions = NULL;
 
792
        cdata->changeset_callback = changeset_callback;
 
793
        cdata->user_data = user_data;
 
794
        cdata->destroy = destroy;
 
795
 
 
796
        adata = g_new0 (ActionData, 1);
 
797
        adata->mechanism = g_object_ref (mechanism);
 
798
        adata->context = context;
 
799
        adata->includes = g_strdupv ((gchar **)includes);
 
800
        adata->actions_ready_callback = check_polkit_for_actions;
 
801
        adata->auth_obtained_callback = do_copy_authorized;
 
802
        adata->data = cdata;
 
803
        adata->destroy = copy_data_free;
 
804
 
 
805
        /* check privileges for each include */
 
806
        if (mandatory) {
 
807
                adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
 
808
                adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
 
809
                cdata->dest_address = "xml:merged:" SYSGCONFDIR "/gconf.xml.mandatory";
 
810
        }
 
811
        else {
 
812
                adata->annotation_key = "org.gnome.gconf.defaults.set-system.prefix";
 
813
                adata->default_action = "org.gnome.gconf.defaults.set-system";
 
814
                cdata->dest_address = "xml:merged:" SYSGCONFDIR "/gconf.xml.system";
 
815
        }
 
816
 
 
817
        polkit_authority_enumerate_actions (mechanism->priv->auth,
 
818
                                            NULL,
 
819
                                            actions_ready_cb,
 
820
                                            adata);
 
821
}
 
822
 
 
823
static void
 
824
append_key (GConfChangeSet *cs,
 
825
            const gchar *key,
 
826
            GConfValue *value,
 
827
            gpointer user_data)
 
828
{
 
829
        GPtrArray *keys = (GPtrArray *) user_data;
 
830
 
 
831
        g_ptr_array_add (keys, (gpointer) key);
 
832
}
 
833
 
 
834
static void
 
835
set_system_changes (GConfDefaults  *mechanism,
 
836
                    GConfChangeSet *changes,
 
837
                    gpointer        data)
 
838
{
 
839
        GPtrArray *keys;
 
840
 
 
841
        keys = g_ptr_array_new ();
 
842
        gconf_change_set_foreach (changes, append_key, keys);
 
843
        g_ptr_array_add (keys, NULL);
 
844
 
 
845
        g_signal_emit (mechanism, signals[SYSTEM_SET], 0, keys->pdata);
 
846
 
 
847
        g_ptr_array_free (keys, TRUE);
 
848
}
 
849
 
 
850
void
 
851
gconf_defaults_set_system (GConfDefaults          *mechanism,
 
852
                           const char            **includes,
 
853
                           const char            **excludes,
 
854
                           DBusGMethodInvocation  *context)
 
855
{
 
856
        do_copy (mechanism, FALSE, includes, excludes, NULL, context, set_system_changes, NULL, NULL);
 
857
}
 
858
 
 
859
void
 
860
gconf_defaults_set_mandatory (GConfDefaults          *mechanism,
 
861
                              const char            **includes,
 
862
                              const char            **excludes,
 
863
                              DBusGMethodInvocation  *context)
 
864
{
 
865
        do_copy (mechanism, TRUE, includes, excludes, NULL, context, NULL, NULL, NULL);
 
866
}
 
867
 
 
868
static void
 
869
unset_tree (GConfClient     *dest,
 
870
            const char      *path,
 
871
            GConfChangeSet  *changes,
 
872
            const char     **excludes)
 
873
{
 
874
        GSList *list, *l;
 
875
        GConfEntry *entry;
 
876
 
 
877
        if (path_is_excluded (path, excludes))
 
878
                return;
 
879
 
 
880
        list = gconf_client_all_entries (dest, path, NULL);
 
881
        for (l = list; l; l = l->next) {
 
882
                entry = l->data;
 
883
                if (!path_is_excluded (entry->key, excludes))
 
884
                        gconf_change_set_unset (changes, entry->key);
 
885
        }
 
886
        g_slist_foreach (list, (GFunc)gconf_entry_free, NULL);
 
887
        g_slist_free (list);
 
888
 
 
889
        list = gconf_client_all_dirs (dest, path, NULL);
 
890
        for (l = list; l; l = l->next)
 
891
                unset_tree (dest, (const char *)l->data, changes, excludes);
 
892
        g_slist_foreach (list, (GFunc)g_free, NULL);
 
893
        g_slist_free (list);
 
894
}
 
895
 
 
896
static void
 
897
unset_entry (GConfClient     *dest,
 
898
             const char      *path,
 
899
             GConfChangeSet  *changes,
 
900
             const char     **excludes)
 
901
{
 
902
        if (path_is_excluded (path, excludes))
 
903
                return;
 
904
 
 
905
        gconf_change_set_unset (changes, path);
 
906
}
 
907
 
 
908
static void
 
909
unset_in_db (GConfDefaults   *mechanism,
 
910
             const gchar     *address,
 
911
             const gchar    **includes,
 
912
             const gchar    **excludes,
 
913
             GError         **error)
 
914
{
 
915
        GConfEngine *engine;
 
916
        GConfClient *dest = NULL;
 
917
        GConfChangeSet *changes = NULL;
 
918
        int i;
 
919
 
 
920
        engine = gconf_engine_get_local (address, error);
 
921
        if (*error)
 
922
                goto out;
 
923
 
 
924
        dest = gconf_client_get_for_engine (engine);
 
925
        gconf_engine_unref (engine);
 
926
 
 
927
        changes = gconf_change_set_new ();
 
928
 
 
929
        /* recursively copy each include, leaving out the excludes */
 
930
        for (i = 0; includes[i]; i++) {
 
931
                if (gconf_client_dir_exists (dest, includes[i], NULL))
 
932
                        unset_tree (dest, includes[i], changes, excludes);
 
933
                else
 
934
                        unset_entry (dest, includes[i], changes, excludes);
 
935
        }
 
936
 
 
937
        gconf_client_commit_change_set (dest, changes, TRUE, error);
 
938
        gconf_client_suggest_sync (dest, NULL);
 
939
 
 
940
out:
 
941
        if (dest)
 
942
                g_object_unref (dest);
 
943
        if (changes)
 
944
                gconf_change_set_unref (changes);
 
945
}
 
946
 
 
947
typedef struct
 
948
{
 
949
        GConfDefaults          *mechanism;
 
950
        DBusGMethodInvocation  *context;
 
951
        char                  **includes;
 
952
        char                  **excludes;
 
953
} UnsetData;
 
954
 
 
955
static void
 
956
unset_data_free (gpointer user_data)
 
957
{
 
958
        UnsetData *data = user_data;
 
959
 
 
960
        g_object_unref (data->mechanism);
 
961
        g_strfreev (data->includes);
 
962
        g_strfreev (data->excludes);
 
963
        g_free (data);
 
964
}
 
965
 
 
966
static void
 
967
do_unset_authorized (GConfDefaults          *mechanism,
 
968
                     DBusGMethodInvocation  *context,
 
969
                     gpointer                user_data)
 
970
{
 
971
        UnsetData *data = user_data;
 
972
        GError *error;
 
973
 
 
974
        error = NULL;
 
975
        unset_in_db (mechanism, "xml:merged:" SYSGCONFDIR "/gconf.xml.mandatory", 
 
976
                     (const gchar **)data->includes,
 
977
                     (const gchar **)data->excludes, &error);
 
978
 
 
979
        if (error) {
 
980
                throw_error (data->context,
 
981
                             GCONF_DEFAULTS_ERROR,
 
982
                             GCONF_DEFAULTS_ERROR_GENERAL,
 
983
                             "%s", error->message);
 
984
                g_error_free (error);
 
985
        }
 
986
        else
 
987
                dbus_g_method_return (data->context);
 
988
}
 
989
 
 
990
void
 
991
gconf_defaults_unset_mandatory (GConfDefaults          *mechanism,
 
992
                                const char            **includes,
 
993
                                const char            **excludes,
 
994
                                DBusGMethodInvocation  *context)
 
995
{
 
996
        UnsetData *udata;
 
997
        ActionData *adata;
 
998
 
 
999
        start_operation ();
 
1000
 
 
1001
        udata = g_new0 (UnsetData, 1);
 
1002
        udata->mechanism = g_object_ref (mechanism);
 
1003
        udata->context = context;
 
1004
        udata->includes = g_strdupv ((gchar **)includes);
 
1005
        udata->excludes = g_strdupv ((gchar **)excludes);
 
1006
 
 
1007
        adata = g_new0 (ActionData, 1);
 
1008
        adata->mechanism = g_object_ref (mechanism);
 
1009
        adata->context = context;
 
1010
        adata->includes = g_strdupv ((gchar **)includes);
 
1011
        adata->auth_obtained_callback = do_unset_authorized;
 
1012
        adata->data = udata;
 
1013
        adata->destroy = unset_data_free;
 
1014
 
 
1015
        adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
 
1016
        adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
 
1017
 
 
1018
        polkit_authority_enumerate_actions (mechanism->priv->auth,
 
1019
                                            NULL,
 
1020
                                            actions_ready_cb,
 
1021
                                            adata);
 
1022
}
 
1023
 
 
1024
static void
 
1025
check_authorization_only_callback (PolkitAuthority *authority,
 
1026
                                   GAsyncResult    *res,
 
1027
                                   gpointer         user_data)
 
1028
{
 
1029
        CheckAuthData *data = user_data;
 
1030
        PolkitAuthorizationResult *result;
 
1031
        GError *error;
 
1032
        gboolean is_authorized;
 
1033
 
 
1034
        is_authorized = FALSE;
 
1035
 
 
1036
        error = NULL;
 
1037
        result = polkit_authority_check_authorization_finish (authority,
 
1038
                                                              res,
 
1039
                                                              &error);
 
1040
        if (error != NULL) {
 
1041
                g_debug ("error checking action '%s'\n", error->message);
 
1042
                throw_error (data->context,
 
1043
                             GCONF_DEFAULTS_ERROR_NOT_PRIVILEGED,
 
1044
                             "Not Authorized: %s", error->message);
 
1045
                g_error_free (error);
 
1046
                goto out;
 
1047
        }
 
1048
        else {
 
1049
                if (polkit_authorization_result_get_is_authorized (result)) {
 
1050
                        g_debug ("result for '%s': authorized\n",
 
1051
                                 data->actions[data->id]);
 
1052
                        is_authorized = TRUE;
 
1053
                }
 
1054
                else if (polkit_authorization_result_get_is_challenge (result)) {
 
1055
                        g_debug ("result for '%s': challenge\n",
 
1056
                                 data->actions[data->id]);
 
1057
                        is_authorized = TRUE;
 
1058
                        data->challenge = TRUE;
 
1059
                }
 
1060
                else {
 
1061
                        g_debug ("result for '%s': not authorized\n",
 
1062
                                 data->actions[data->id]);
 
1063
                        is_authorized = FALSE;
 
1064
                }
 
1065
        }
 
1066
 
 
1067
        if (is_authorized) {
 
1068
                data->id++;
 
1069
                if (data->actions[data->id] == NULL) {
 
1070
                        gint result;
 
1071
 
 
1072
                        result = data->challenge ? 1 : 2;
 
1073
                        g_debug ("return %d\n", result);
 
1074
                        dbus_g_method_return (data->context, result);
 
1075
                }
 
1076
                else {
 
1077
                        check_next_action (data);
 
1078
                        return; /* continue operation */
 
1079
                }
 
1080
        }
 
1081
        else {
 
1082
                g_debug ("return 0\n");
 
1083
                dbus_g_method_return (data->context, 0);
 
1084
        }
 
1085
 
 
1086
out:
 
1087
        check_auth_data_free (data);
 
1088
        g_object_unref (result);
 
1089
        stop_operation ();
 
1090
}
 
1091
 
 
1092
static void
 
1093
check_permissions_only (GConfDefaults                   *mechanism,
 
1094
                        DBusGMethodInvocation           *context,
 
1095
                        gchar                          **actions,
 
1096
                        AuthObtainedCallback             auth_obtained_callback,
 
1097
                        gpointer                         user_data,
 
1098
                        GDestroyNotify                   destroy)
 
1099
{
 
1100
        CheckAuthData *data;
 
1101
 
 
1102
        data = g_new0 (CheckAuthData, 1);
 
1103
        data->mechanism = g_object_ref (mechanism);
 
1104
        data->context = context;
 
1105
        data->actions = actions;
 
1106
        data->flags = 0;
 
1107
        data->id = 0;
 
1108
        data->check_auth_callback = (GAsyncReadyCallback)check_authorization_only_callback;
 
1109
        data->auth_obtained_callback = NULL;
 
1110
        data->user_data = NULL;
 
1111
        data->destroy = NULL;
 
1112
        data->subject = polkit_system_bus_name_new (dbus_g_method_get_sender (context));
 
1113
        data->challenge = FALSE;
 
1114
 
 
1115
        check_next_action (data);
 
1116
}
 
1117
 
 
1118
static void
 
1119
do_check (GConfDefaults          *mechanism,
 
1120
          gboolean                mandatory,
 
1121
          const gchar           **includes,
 
1122
          DBusGMethodInvocation  *context)
 
1123
{
 
1124
        ActionData *adata;
 
1125
 
 
1126
        start_operation ();
 
1127
 
 
1128
        adata = g_new0 (ActionData, 1);
 
1129
        adata->mechanism = g_object_ref (mechanism);
 
1130
        adata->context = context;
 
1131
        adata->includes = g_strdupv ((gchar **)includes);
 
1132
        adata->actions_ready_callback = check_permissions_only;
 
1133
        adata->auth_obtained_callback = NULL;
 
1134
        adata->data = NULL;
 
1135
        adata->destroy = NULL;
 
1136
 
 
1137
        if (mandatory) {
 
1138
                adata->annotation_key = "org.gnome.gconf.defaults.set-mandatory.prefix";
 
1139
                adata->default_action = "org.gnome.gconf.defaults.set-mandatory";
 
1140
        }
 
1141
        else {
 
1142
                adata->annotation_key = "org.gnome.gconf.defaults.set-system.prefix";
 
1143
                adata->default_action = "org.gnome.gconf.defaults.set-system";
 
1144
        }
 
1145
 
 
1146
        polkit_authority_enumerate_actions (mechanism->priv->auth,
 
1147
                                            NULL,
 
1148
                                            actions_ready_cb,
 
1149
                                            adata);
 
1150
}
 
1151
 
 
1152
void
 
1153
gconf_defaults_can_set_system (GConfDefaults          *mechanism,
 
1154
                               const char            **includes,
 
1155
                               DBusGMethodInvocation  *context)
 
1156
{
 
1157
        do_check (mechanism, FALSE, includes, context);
 
1158
}
 
1159
 
 
1160
void
 
1161
gconf_defaults_can_set_mandatory (GConfDefaults          *mechanism,
 
1162
                                  const char            **includes,
 
1163
                                  DBusGMethodInvocation  *context)
 
1164
{
 
1165
        do_check (mechanism, TRUE, includes, context);
 
1166
}
 
1167
 
 
1168
void
 
1169
gconf_defaults_set_system_value (GConfDefaults         *mechanism,
 
1170
                                 const char            *path,
 
1171
                                 const char            *value,
 
1172
                                 DBusGMethodInvocation *context)
 
1173
{
 
1174
        GConfValue *gvalue;
 
1175
        const char *includes[] = { NULL, NULL };
 
1176
 
 
1177
        gvalue = gconf_value_decode (value);
 
1178
        if (gvalue) {
 
1179
                includes[0] = path;
 
1180
                do_copy (mechanism, FALSE, includes, NULL, gvalue, context, set_system_changes, NULL, NULL);
 
1181
        }
 
1182
}
 
1183
 
 
1184
void
 
1185
gconf_defaults_set_mandatory_value (GConfDefaults         *mechanism,
 
1186
                                    const char            *path,
 
1187
                                    const char            *value,
 
1188
                                    DBusGMethodInvocation *context)
 
1189
{
 
1190
        GConfValue *gvalue;
 
1191
        const char *includes[] = { NULL, NULL };
 
1192
 
 
1193
        gvalue = gconf_value_decode (value);
 
1194
        if (gvalue) {
 
1195
                includes[0] = path;
 
1196
                do_copy (mechanism, TRUE, includes, NULL, gvalue, context, NULL, NULL, NULL);
 
1197
        }
 
1198
}
 
1199