Move Nautilus-Actions configuration files to nautilus-actions/ subdir
[nautilus-actions.git] / src / core / na-settings.c
blob6a044e2c3e1e0b7730f9f69145cdb9c0efc43e3a
1 /*
2 * Nautilus-Actions
3 * A Nautilus extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009, 2010, 2011 Pierre Wieser and others (see AUTHORS)
9 * This Program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
14 * This Program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this Library; see the file COPYING. If not,
21 * write to the Free Software Foundation, Inc., 59 Temple Place,
22 * Suite 330, Boston, MA 02111-1307, USA.
24 * Authors:
25 * Frederic Ruaudel <grumz@grumz.net>
26 * Rodrigo Moya <rodrigo@gnome-db.org>
27 * Pierre Wieser <pwieser@trychlos.org>
28 * ... and many others (see AUTHORS)
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
35 #include <gio/gio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <strings.h>
40 #include <api/na-boxed.h>
41 #include <api/na-data-types.h>
42 #include <api/na-core-utils.h>
43 #include <api/na-timeout.h>
45 #include "na-settings.h"
46 #include "na-marshal.h"
48 /* private class data
50 struct _NASettingsClassPrivate {
51 void *empty; /* so that gcc -pedantic is happy */
54 /* The characteristics of a configuration file.
55 * We manage two configuration files:
56 * - the global configuration file handles mandatory preferences;
57 * - the user configuration file handles.. well, user preferences.
59 typedef struct {
60 gchar *fname;
61 GKeyFile *key_file;
62 GFileMonitor *monitor;
63 gulong handler;
65 KeyFile;
67 /* Each consumer may register a callback function which will be triggered
68 * when a key is modified.
70 * The monitored key usually is the real key read in the file;
71 * as a special case, composite keys are defined:
72 * - NA_IPREFS_IO_PROVIDERS_READ_STATUS monitors the 'readable' key for all i/o providers
74 * Note that we actually monitor the _user_view_ of the configuration:
75 * e.g. if a key has a mandatory value in global conf, then the same
76 * key in user conf will just be ignored.
78 typedef struct {
79 gchar *monitored_key;
80 GCallback callback;
81 gpointer user_data;
83 Consumer;
85 /* private instance data
87 struct _NASettingsPrivate {
88 gboolean dispose_has_run;
89 KeyFile *mandatory;
90 KeyFile *user;
91 GList *content;
92 GList *consumers;
93 NATimeout timeout;
96 #define GROUP_NACT "nact"
97 #define GROUP_RUNTIME "runtime"
99 typedef struct {
100 const gchar *key;
101 const gchar *group;
102 guint type;
103 const gchar *default_value;
105 KeyDef;
107 static const KeyDef st_def_keys[] = {
108 { NA_IPREFS_ADMIN_PREFERENCES_LOCKED, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
109 { NA_IPREFS_ADMIN_IO_PROVIDERS_LOCKED, GROUP_RUNTIME, NA_DATA_TYPE_BOOLEAN, "false" },
110 { NA_IPREFS_ASSISTANT_ESC_CONFIRM, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "true" },
111 { NA_IPREFS_ASSISTANT_ESC_QUIT, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "true" },
112 { NA_IPREFS_CAPABILITY_ADD_CAPABILITY_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
113 { NA_IPREFS_COMMAND_CHOOSER_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
114 { NA_IPREFS_COMMAND_CHOOSER_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///bin" },
115 { NA_IPREFS_COMMAND_LEGEND_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
116 { NA_IPREFS_CONFIRM_LOGOUT_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
117 { NA_IPREFS_WORKING_DIR_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
118 { NA_IPREFS_WORKING_DIR_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///" },
119 { NA_IPREFS_SHOW_IF_RUNNING_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
120 { NA_IPREFS_SHOW_IF_RUNNING_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///bin" },
121 { NA_IPREFS_TRY_EXEC_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
122 { NA_IPREFS_TRY_EXEC_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///bin" },
123 { NA_IPREFS_EXPORT_ASK_USER_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
124 { NA_IPREFS_EXPORT_ASK_USER_LAST_FORMAT, GROUP_NACT, NA_DATA_TYPE_STRING, NA_IPREFS_DEFAULT_EXPORT_FORMAT },
125 { NA_IPREFS_EXPORT_ASK_USER_KEEP_LAST_CHOICE, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
126 { NA_IPREFS_EXPORT_ASSISTANT_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
127 { NA_IPREFS_EXPORT_ASSISTANT_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///tmp" },
128 { NA_IPREFS_EXPORT_PREFERRED_FORMAT, GROUP_NACT, NA_DATA_TYPE_STRING, NA_IPREFS_DEFAULT_EXPORT_FORMAT },
129 { NA_IPREFS_FOLDER_CHOOSER_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
130 { NA_IPREFS_FOLDER_CHOOSER_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///" },
131 { NA_IPREFS_IMPORT_ASK_USER_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
132 { NA_IPREFS_IMPORT_ASK_USER_LAST_MODE, GROUP_NACT, NA_DATA_TYPE_STRING, NA_IPREFS_DEFAULT_IMPORT_MODE },
133 { NA_IPREFS_IMPORT_ASSISTANT_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
134 { NA_IPREFS_IMPORT_ASSISTANT_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///tmp" },
135 { NA_IPREFS_IMPORT_ASK_USER_KEEP_LAST_CHOICE, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
136 { NA_IPREFS_IMPORT_PREFERRED_MODE, GROUP_NACT, NA_DATA_TYPE_STRING, NA_IPREFS_DEFAULT_IMPORT_MODE },
137 { NA_IPREFS_IO_PROVIDERS_WRITE_ORDER, GROUP_NACT, NA_DATA_TYPE_STRING_LIST, "" },
138 { NA_IPREFS_ICON_CHOOSER_URI, GROUP_NACT, NA_DATA_TYPE_STRING, "file:///" },
139 { NA_IPREFS_ICON_CHOOSER_PANED, GROUP_NACT, NA_DATA_TYPE_UINT, "200" },
140 { NA_IPREFS_ICON_CHOOSER_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
141 { NA_IPREFS_ITEMS_ADD_ABOUT_ITEM, GROUP_RUNTIME, NA_DATA_TYPE_BOOLEAN, "true" },
142 { NA_IPREFS_ITEMS_CREATE_ROOT_MENU, GROUP_RUNTIME, NA_DATA_TYPE_BOOLEAN, "true" },
143 { NA_IPREFS_ITEMS_LEVEL_ZERO_ORDER, GROUP_RUNTIME, NA_DATA_TYPE_STRING_LIST, "" },
144 { NA_IPREFS_ITEMS_LIST_ORDER_MODE, GROUP_RUNTIME, NA_DATA_TYPE_STRING, NA_IPREFS_DEFAULT_LIST_ORDER_MODE },
145 { NA_IPREFS_MAIN_PANED, GROUP_NACT, NA_DATA_TYPE_UINT, "200" },
146 { NA_IPREFS_MAIN_SAVE_AUTO, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
147 { NA_IPREFS_MAIN_SAVE_PERIOD, GROUP_NACT, NA_DATA_TYPE_UINT, "5" },
148 { NA_IPREFS_MAIN_TOOLBAR_EDIT_DISPLAY, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "true" },
149 { NA_IPREFS_MAIN_TOOLBAR_FILE_DISPLAY, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "true" },
150 { NA_IPREFS_MAIN_TOOLBAR_HELP_DISPLAY, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "true" },
151 { NA_IPREFS_MAIN_TOOLBAR_TOOLS_DISPLAY, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
152 { NA_IPREFS_MAIN_WINDOW_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
153 { NA_IPREFS_PREFERENCES_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
154 { NA_IPREFS_RELABEL_DUPLICATE_ACTION, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
155 { NA_IPREFS_RELABEL_DUPLICATE_MENU, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
156 { NA_IPREFS_RELABEL_DUPLICATE_PROFILE, GROUP_NACT, NA_DATA_TYPE_BOOLEAN, "false" },
157 { NA_IPREFS_SCHEME_ADD_SCHEME_WSP, GROUP_NACT, NA_DATA_TYPE_UINT_LIST, "" },
158 { NA_IPREFS_SCHEME_DEFAULT_LIST, GROUP_NACT, NA_DATA_TYPE_STRING_LIST, "" },
159 { NA_IPREFS_IO_PROVIDER_READABLE, NA_IPREFS_IO_PROVIDER_GROUP, NA_DATA_TYPE_BOOLEAN, "true" },
160 { NA_IPREFS_IO_PROVIDER_WRITABLE, NA_IPREFS_IO_PROVIDER_GROUP, NA_DATA_TYPE_BOOLEAN, "true" },
161 { 0 }
164 /* The configuration content is handled as a GList of KeyValue structs.
165 * This list is loaded at initialization time, and then compared each
166 * time our file monitors signal us that a change has occured.
168 typedef struct {
169 const KeyDef *def;
170 const gchar *group;
171 gboolean mandatory;
172 NABoxed *boxed;
174 KeyValue;
176 /* signals
178 enum {
179 KEY_CHANGED,
180 LAST_SIGNAL
183 static GObjectClass *st_parent_class = NULL;
184 static gint st_burst_timeout = 100; /* burst timeout in msec */
185 static gint st_signals[ LAST_SIGNAL ] = { 0 };
187 static GType register_type( void );
188 static void class_init( NASettingsClass *klass );
189 static void instance_init( GTypeInstance *instance, gpointer klass );
190 static void instance_dispose( GObject *object );
191 static void instance_finalize( GObject *object );
193 static GList *content_diff( GList *old, GList *new );
194 static GList *content_load( NASettings *settings );
195 static GList *content_load_keys( NASettings *settings, GList *content, KeyFile *key_file, gboolean mandatory );
196 static KeyDef *get_key_def( const gchar *key );
197 static KeyFile *key_file_new( NASettings *settings, const gchar *dir );
198 static void on_keyfile_changed( GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, NASettings *settings );
199 static void on_keyfile_changed_timeout( NASettings *settings );
200 static void on_key_changed_final_handler( NASettings *settings, gchar *group, gchar *key, NABoxed *new_value, gboolean mandatory );
201 static KeyValue *peek_key_value_from_content( GList *content, const gchar *group, const gchar *key );
202 static KeyValue *read_key_value( NASettings *settings, const gchar *group, const gchar *key, gboolean *found, gboolean *mandatory );
203 static KeyValue *read_key_value_from_key_file( GKeyFile *key_file, const gchar *group, const gchar *key, const KeyDef *key_def );
204 static void release_consumer( Consumer *consumer );
205 static void release_key_file( KeyFile *key_file );
206 static void release_key_value( KeyValue *value );
207 static gboolean set_key_value( NASettings *settings, const gchar *group, const gchar *key, const gchar *string );
208 static gboolean write_user_key_file( NASettings *settings );
210 GType
211 na_settings_get_type( void )
213 static GType object_type = 0;
215 if( !object_type ){
216 object_type = register_type();
219 return( object_type );
222 static GType
223 register_type( void )
225 static const gchar *thisfn = "na_settings_register_type";
226 GType type;
228 static GTypeInfo info = {
229 sizeof( NASettingsClass ),
230 ( GBaseInitFunc ) NULL,
231 ( GBaseFinalizeFunc ) NULL,
232 ( GClassInitFunc ) class_init,
233 NULL,
234 NULL,
235 sizeof( NASettings ),
237 ( GInstanceInitFunc ) instance_init
240 g_debug( "%s", thisfn );
242 type = g_type_register_static( G_TYPE_OBJECT, "NASettings", &info, 0 );
244 return( type );
247 static void
248 class_init( NASettingsClass *klass )
250 static const gchar *thisfn = "na_settings_class_init";
251 GObjectClass *object_class;
253 g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
255 st_parent_class = g_type_class_peek_parent( klass );
257 object_class = G_OBJECT_CLASS( klass );
258 object_class->dispose = instance_dispose;
259 object_class->finalize = instance_finalize;
261 klass->private = g_new0( NASettingsClassPrivate, 1 );
264 * NASettings::settings-key-changed:
266 * This signal is sent by NASettings when the value of a key is modified.
268 * Arguments are the group, the key, the new value as a NABoxed,
269 * and whether it is mandatory.
271 * Handler is of type:
272 * void ( *handler )( NASettings *settings,
273 * const gchar *group,
274 * const gchar *key,
275 * NABoxed *value,
276 * gboolean mandatory,
277 * gpointer user_data );
279 * The default class handler frees these datas.
281 st_signals[ KEY_CHANGED ] = g_signal_new_class_handler(
282 SETTINGS_SIGNAL_KEY_CHANGED,
283 NA_SETTINGS_TYPE,
284 G_SIGNAL_RUN_CLEANUP | G_SIGNAL_ACTION,
285 G_CALLBACK( on_key_changed_final_handler ),
286 NULL, /* accumulator */
287 NULL, /* accumulator data */
288 na_cclosure_marshal_VOID__STRING_STRING_POINTER_BOOLEAN,
289 G_TYPE_NONE,
291 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN );
294 static void
295 instance_init( GTypeInstance *instance, gpointer klass )
297 static const gchar *thisfn = "na_settings_instance_init";
298 NASettings *self;
300 g_return_if_fail( NA_IS_SETTINGS( instance ));
302 g_debug( "%s: instance=%p (%s), klass=%p",
303 thisfn, ( void * ) instance, G_OBJECT_TYPE_NAME( instance ), ( void * ) klass );
305 self = NA_SETTINGS( instance );
307 self->private = g_new0( NASettingsPrivate, 1 );
309 self->private->dispose_has_run = FALSE;
310 self->private->mandatory = NULL;
311 self->private->user = NULL;
312 self->private->content = NULL;
313 self->private->consumers = NULL;
315 self->private->timeout.timeout = st_burst_timeout;
316 self->private->timeout.handler = ( NATimeoutFunc ) on_keyfile_changed_timeout;
317 self->private->timeout.user_data = self;
318 self->private->timeout.source_id = 0;
321 static void
322 instance_dispose( GObject *object )
324 static const gchar *thisfn = "na_settings_instance_dispose";
325 NASettings *self;
327 g_return_if_fail( NA_IS_SETTINGS( object ));
329 self = NA_SETTINGS( object );
331 if( !self->private->dispose_has_run ){
333 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
335 self->private->dispose_has_run = TRUE;
337 release_key_file( self->private->mandatory );
338 release_key_file( self->private->user );
340 if( G_OBJECT_CLASS( st_parent_class )->dispose ){
341 G_OBJECT_CLASS( st_parent_class )->dispose( object );
346 static void
347 instance_finalize( GObject *object )
349 static const gchar *thisfn = "na_settings_instance_finalize";
350 NASettings *self;
352 g_return_if_fail( NA_IS_SETTINGS( object ));
354 g_debug( "%s: object=%p (%s)", thisfn, ( void * ) object, G_OBJECT_TYPE_NAME( object ));
356 self = NA_SETTINGS( object );
358 g_list_foreach( self->private->content, ( GFunc ) release_key_value, NULL );
359 g_list_free( self->private->content );
361 g_list_foreach( self->private->consumers, ( GFunc ) release_consumer, NULL );
362 g_list_free( self->private->consumers );
364 g_free( self->private );
366 /* chain call to parent class */
367 if( G_OBJECT_CLASS( st_parent_class )->finalize ){
368 G_OBJECT_CLASS( st_parent_class )->finalize( object );
373 * na_settings_new:
375 * Returns: a new #NASettings object which should be g_object_unref()
376 * by the caller.
378 NASettings *
379 na_settings_new( void )
381 static const gchar *thisfn = "na_settings_new";
382 NASettings *settings;
383 gchar *dir;
385 settings = g_object_new( NA_SETTINGS_TYPE, NULL );
387 dir = g_build_filename( SYSCONFDIR, "xdg", PACKAGE, NULL );
388 g_debug( "%s: reading mandatory configuration", thisfn );
389 settings->private->mandatory = key_file_new( settings, dir );
390 g_free( dir );
392 dir = g_build_filename( g_get_home_dir(), ".config", PACKAGE, NULL );
393 g_debug( "%s: reading user configuration", thisfn );
394 settings->private->user = key_file_new( settings, dir );
395 g_free( dir );
397 settings->private->content = content_load( settings );
399 return( settings );
403 * na_settings_register_key_callback:
404 * @settings: this #NASettings instance.
405 * @key: the key to be monitored.
406 * @callback: the function to be called when the value of the key changes.
407 * @user_data: data to be passed to the @callback function.
409 * Registers a new consumer of the monitoring of the @key.
411 * Since: 3.1.0
413 void
414 na_settings_register_key_callback( NASettings *settings, const gchar *key, GCallback callback, gpointer user_data )
416 static const gchar *thisfn = "na_settings_register_key_callback";
418 g_return_if_fail( NA_IS_SETTINGS( settings ));
420 if( !settings->private->dispose_has_run ){
421 g_debug( "%s: settings=%p, key=%s, callback=%p, user_data=%p",
422 thisfn, ( void * ) settings, key, ( void * ) callback, ( void * ) user_data );
424 Consumer *consumer = g_new0( Consumer, 1 );
426 consumer->monitored_key = g_strdup( key );
427 consumer->callback = callback;
428 consumer->user_data = user_data;
429 settings->private->consumers = g_list_prepend( settings->private->consumers, consumer );
434 * na_settings_get_boolean:
435 * @settings: this #NASettings instance.
436 * @key: the key whose value is to be returned.
437 * @found: if not %NULL, a pointer to a gboolean in which we will store
438 * whether the searched @key has been found (%TRUE), or if the returned
439 * value comes from default (%FALSE).
440 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
441 * whether the returned value has been read from mandatory preferences
442 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
443 * been found, @mandatory is set to %FALSE.
445 * This function should only be called for unambiguous keys; the resultat
446 * is otherwise undefined (and rather unpredictable).
448 * Returns: the value of the key, of its default value if not found.
450 * Since: 3.1.0
452 gboolean
453 na_settings_get_boolean( NASettings *settings, const gchar *key, gboolean *found, gboolean *mandatory )
455 return( na_settings_get_boolean_ex( settings, NULL, key, found, mandatory ));
459 * na_settings_get_boolean_ex:
460 * @settings: this #NASettings instance.
461 * @group: the group where the @key is to be searched for. May be %NULL.
462 * @key: the key whose value is to be returned.
463 * @found: if not %NULL, a pointer to a gboolean in which we will store
464 * whether the searched @key has been found (%TRUE), or if the returned
465 * value comes from default (%FALSE).
466 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
467 * whether the returned value has been read from mandatory preferences
468 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
469 * been found, @mandatory is set to %FALSE.
471 * Returns: the value of the key, of its default value if not found.
473 * Since: 3.1.0
475 gboolean
476 na_settings_get_boolean_ex( NASettings *settings, const gchar *group, const gchar *key, gboolean *found, gboolean *mandatory )
478 gboolean value;
479 KeyValue *key_value;
480 KeyDef *key_def;
482 value = FALSE;
483 key_value = read_key_value( settings, group, key, found, mandatory );
485 if( key_value ){
486 value = na_boxed_get_boolean( key_value->boxed );
487 release_key_value( key_value );
489 } else {
490 key_def = get_key_def( key );
491 if( key_def ){
492 value = ( key_def->default_value ? ( strcasecmp( key_def->default_value, "true" ) == 0 || atoi( key_def->default_value ) != 0 ) : FALSE );
496 return( value );
500 * na_settings_get_string:
501 * @settings: this #NASettings instance.
502 * @key: the key whose value is to be returned.
503 * @found: if not %NULL, a pointer to a gboolean in which we will store
504 * whether the searched @key has been found (%TRUE), or if the returned
505 * value comes from default (%FALSE).
506 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
507 * whether the returned value has been read from mandatory preferences
508 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
509 * been found, @mandatory is set to %FALSE.
511 * This function should only be called for unambiguous keys; the resultat
512 * is otherwise undefined (and rather unpredictable).
514 * Returns: the value of the key as a newly allocated string, which should
515 * be g_free() by the caller.
517 * Since: 3.1.0
519 gchar *
520 na_settings_get_string( NASettings *settings, const gchar *key, gboolean *found, gboolean *mandatory )
522 gchar *value;
523 KeyValue *key_value;
524 KeyDef *key_def;
526 value = NULL;
527 key_value = read_key_value( settings, NULL, key, found, mandatory );
529 if( key_value ){
530 value = na_boxed_get_string( key_value->boxed );
531 release_key_value( key_value );
533 } else {
534 key_def = get_key_def( key );
535 if( key_def && key_def->default_value ){
536 value = g_strdup( key_def->default_value );
540 return( value );
544 * na_settings_get_string_list:
545 * @settings: this #NASettings instance.
546 * @key: the key whose value is to be returned.
547 * @found: if not %NULL, a pointer to a gboolean in which we will store
548 * whether the searched @key has been found (%TRUE), or if the returned
549 * value comes from default (%FALSE).
550 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
551 * whether the returned value has been read from mandatory preferences
552 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
553 * been found, @mandatory is set to %FALSE.
555 * This function should only be called for unambiguous keys; the resultat
556 * is otherwise undefined (and rather unpredictable).
558 * Returns: the value of the key as a newly allocated list of strings.
559 * The returned list should be na_core_utils_slist_free() by the caller.
561 * Since: 3.1.0
563 GSList *
564 na_settings_get_string_list( NASettings *settings, const gchar *key, gboolean *found, gboolean *mandatory )
566 GSList *value;
567 KeyValue *key_value;
568 KeyDef *key_def;
570 value = NULL;
571 key_value = read_key_value( settings, NULL, key, found, mandatory );
573 if( key_value ){
574 value = na_boxed_get_string_list( key_value->boxed );
575 release_key_value( key_value );
577 } else {
578 key_def = get_key_def( key );
579 if( key_def && key_def->default_value && strlen( key_def->default_value )){
580 value = g_slist_append( NULL, g_strdup( key_def->default_value ));
584 return( value );
588 * na_settings_get_uint:
589 * @settings: this #NASettings instance.
590 * @key: the key whose value is to be returned.
591 * @found: if not %NULL, a pointer to a gboolean in which we will store
592 * whether the searched @key has been found (%TRUE), or if the returned
593 * value comes from default (%FALSE).
594 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
595 * whether the returned value has been read from mandatory preferences
596 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
597 * been found, @mandatory is set to %FALSE.
599 * This function should only be called for unambiguous keys; the resultat
600 * is otherwise undefined (and rather unpredictable).
602 * Returns: the value of the key.
604 * Since: 3.1.0
606 guint
607 na_settings_get_uint( NASettings *settings, const gchar *key, gboolean *found, gboolean *mandatory )
609 guint value;
610 KeyDef *key_def;
611 KeyValue *key_value;
613 value = 0;
614 key_value = read_key_value( settings, NULL, key, found, mandatory );
616 if( key_value ){
617 value = na_boxed_get_uint( key_value->boxed );
618 release_key_value( key_value );
620 } else {
621 key_def = get_key_def( key );
622 if( key_def && key_def->default_value ){
623 value = atoi( key_def->default_value );
627 return( value );
631 * na_settings_get_uint_list:
632 * @settings: this #NASettings instance.
633 * @key: the key whose value is to be returned.
634 * @found: if not %NULL, a pointer to a gboolean in which we will store
635 * whether the searched @key has been found (%TRUE), or if the returned
636 * value comes from default (%FALSE).
637 * @mandatory: if not %NULL, a pointer to a gboolean in which we will store
638 * whether the returned value has been read from mandatory preferences
639 * (%TRUE), or from the user preferences (%FALSE). When the @key has not
640 * been found, @mandatory is set to %FALSE.
642 * This function should only be called for unambiguous keys; the resultat
643 * is otherwise undefined (and rather unpredictable).
645 * Returns: the value of the key as a newly allocated list of uints.
646 * The returned list should be g_list_free() by the caller.
648 * Since: 3.1.0
650 GList *
651 na_settings_get_uint_list( NASettings *settings, const gchar *key, gboolean *found, gboolean *mandatory )
653 GList *value;
654 KeyDef *key_def;
655 KeyValue *key_value;
657 value = NULL;
658 key_value = read_key_value( settings, NULL, key, found, mandatory );
660 if( key_value ){
661 value = na_boxed_get_uint_list( key_value->boxed );
662 release_key_value( key_value );
664 } else {
665 key_def = get_key_def( key );
666 if( key_def && key_def->default_value ){
667 value = g_list_append( NULL, GUINT_TO_POINTER( atoi( key_def->default_value )));
671 return( value );
675 * na_settings_set_boolean:
676 * @settings: this #NASettings instance.
677 * @key: the key whose value is to be returned.
678 * @value: the boolean to be written.
680 * This function writes @value as a user preference.
682 * This function should only be called for unambiguous keys; the resultat
683 * is otherwise undefined (and rather unpredictable).
685 * Returns: %TRUE is the writing has been successful, %FALSE else.
687 * Since: 3.1.0
689 gboolean
690 na_settings_set_boolean( NASettings *settings, const gchar *key, gboolean value )
692 gchar *string;
693 gboolean ok;
695 string = g_strdup_printf( "%s", value ? "true" : "false" );
696 ok = set_key_value( settings, NULL, key, string );
697 g_free( string );
699 return( ok );
703 * na_settings_set_boolean_ex:
704 * @settings: this #NASettings instance.
705 * @group: the group in the keyed file;
706 * @key: the key whose value is to be returned.
707 * @value: the boolean to be written.
709 * This function writes @value as a user preference.
711 * Returns: %TRUE is the writing has been successful, %FALSE else.
713 * Since: 3.1.0
715 gboolean
716 na_settings_set_boolean_ex( NASettings *settings, const gchar *group, const gchar *key, gboolean value )
718 gchar *string;
719 gboolean ok;
721 string = g_strdup_printf( "%s", value ? "true" : "false" );
722 ok = set_key_value( settings, group, key, string );
723 g_free( string );
725 return( ok );
729 * na_settings_set_string:
730 * @settings: this #NASettings instance.
731 * @key: the key whose value is to be returned.
732 * @value: the string to be written.
734 * This function writes @value as a user preference.
736 * This function should only be called for unambiguous keys; the resultat
737 * is otherwise undefined (and rather unpredictable).
739 * Returns: %TRUE is the writing has been successful, %FALSE else.
741 * Since: 3.1.0
743 gboolean
744 na_settings_set_string( NASettings *settings, const gchar *key, const gchar *value )
746 return( set_key_value( settings, NULL, key, value ));
750 * na_settings_set_string_list:
751 * @settings: this #NASettings instance.
752 * @key: the key whose value is to be returned.
753 * @value: the list of strings to be written.
755 * This function writes @value as a user preference.
757 * This function should only be called for unambiguous keys; the resultat
758 * is otherwise undefined (and rather unpredictable).
760 * Returns: %TRUE is the writing has been successful, %FALSE else.
762 * Since: 3.1.0
764 gboolean
765 na_settings_set_string_list( NASettings *settings, const gchar *key, const GSList *value )
767 GString *string;
768 const GSList *it;
769 gboolean ok;
771 string = g_string_new( "" );
772 for( it = value ; it ; it = it->next ){
773 g_string_append_printf( string, "%s;", ( const gchar * ) it->data );
775 ok = set_key_value( settings, NULL, key, string->str );
776 g_string_free( string, TRUE );
778 return( ok );
782 * na_settings_set_uint:
783 * @settings: this #NASettings instance.
784 * @key: the key whose value is to be returned.
785 * @value: the unsigned integer to be written.
787 * This function writes @value as a user preference.
789 * This function should only be called for unambiguous keys; the resultat
790 * is otherwise undefined (and rather unpredictable).
792 * Returns: %TRUE is the writing has been successful, %FALSE else.
794 * Since: 3.1.0
796 gboolean
797 na_settings_set_uint( NASettings *settings, const gchar *key, guint value )
799 gchar *string;
800 gboolean ok;
802 string = g_strdup_printf( "%u", value );
803 ok = set_key_value( settings, NULL, key, string );
804 g_free( string );
806 return( ok );
810 * na_settings_set_uint_list:
811 * @settings: this #NASettings instance.
812 * @key: the key whose value is to be returned.
813 * @value: the list of unsigned integers to be written.
815 * This function writes @value as a user preference.
817 * This function should only be called for unambiguous keys; the resultat
818 * is otherwise undefined (and rather unpredictable).
820 * Returns: %TRUE is the writing has been successful, %FALSE else.
822 * Since: 3.1.0
824 gboolean
825 na_settings_set_uint_list( NASettings *settings, const gchar *key, const GList *value )
827 GString *string;
828 const GList *it;
829 gboolean ok;
831 string = g_string_new( "" );
832 for( it = value ; it ; it = it->next ){
833 g_string_append_printf( string, "%u;", GPOINTER_TO_UINT( it->data ));
835 ok = set_key_value( settings, NULL, key, string->str );
836 g_string_free( string, TRUE );
838 return( ok );
842 * na_settings_get_groups:
843 * @settings: this #NASettings instance.
845 * Returns: the list of groups in the configuration; this list should be
846 * na_core_utils_slist_free() by the caller.
848 * This function participates to a rather bad hack to obtain the list of
849 * known i/o providers from preferences. We do not care of returning unique
850 * or sorted group names.
852 * Since: 3.1.0
854 GSList *
855 na_settings_get_groups( NASettings *settings )
857 GSList *groups;
858 gchar **array;
860 groups = NULL;
862 g_return_val_if_fail( NA_IS_SETTINGS( settings ), NULL );
864 if( !settings->private->dispose_has_run ){
866 array = g_key_file_get_groups( settings->private->mandatory->key_file, NULL );
867 if( array ){
868 groups = na_core_utils_slist_from_array(( const gchar ** ) array );
869 g_strfreev( array );
872 array = g_key_file_get_groups( settings->private->user->key_file, NULL );
873 if( array ){
874 groups = g_slist_concat( groups, na_core_utils_slist_from_array(( const gchar ** ) array ));
875 g_strfreev( array );
879 return( groups );
883 * returns a list of modified KeyValue
884 * - order in the lists is not signifiant
885 * - the mandatory flag is not signifiant
886 * - a key is modified:
887 * > if it appears in new
888 * > if it disappears: the value is so reset to its default
889 * > if the value has been modified
891 * we return here a new list, with newly allocated KeyValue structs
892 * which hold the new value of each modified key
894 static GList *
895 content_diff( GList *old, GList *new )
897 GList *diffs, *io, *in;
898 KeyValue *kold, *knew, *kdiff;
899 gboolean found;
901 diffs = NULL;
903 for( io = old ; io ; io = io->next ){
904 kold = ( KeyValue * ) io->data;
905 found = FALSE;
906 for( in = new ; in && !found ; in = in->next ){
907 knew = ( KeyValue * ) in->data;
908 if( !strcmp( kold->group, knew->group ) && ( gpointer ) kold->def == ( gpointer ) knew->def ){
909 found = TRUE;
910 if( !na_boxed_are_equal( kold->boxed, knew->boxed )){
911 /* a key has been modified */
912 kdiff = g_new0( KeyValue, 1 );
913 kdiff->group = g_strdup( knew->group );
914 kdiff->def = knew->def;
915 kdiff->mandatory = knew->mandatory;
916 kdiff->boxed = na_boxed_copy( knew->boxed );
917 diffs = g_list_prepend( diffs, kdiff );
921 if( !found ){
922 /* a key has disappeared */
923 kdiff = g_new0( KeyValue, 1 );
924 kdiff->group = g_strdup( kold->group );
925 kdiff->def = kold->def;
926 kdiff->mandatory = FALSE;
927 kdiff->boxed = na_boxed_new_from_string( kold->def->type, kold->def->default_value );
928 diffs = g_list_prepend( diffs, kdiff );
932 for( in = new ; in ; in = in->next ){
933 knew = ( KeyValue * ) in->data;
934 found = FALSE;
935 for( io = old ; io && !found ; io = io->next ){
936 kold = ( KeyValue * ) io->data;
937 if( !strcmp( kold->group, knew->group ) && ( gpointer ) kold->def == ( gpointer ) knew->def ){
938 found = TRUE;
941 if( !found ){
942 /* a key is new */
943 kdiff = g_new0( KeyValue, 1 );
944 kdiff->group = g_strdup( knew->group );
945 kdiff->def = knew->def;
946 kdiff->mandatory = knew->mandatory;
947 kdiff->boxed = na_boxed_copy( knew->boxed );
948 diffs = g_list_prepend( diffs, kdiff );
952 return( diffs );
955 /* load the content of the two configuration files (actually of _the_ configuration)
956 * taking care of not overriding mandatory preferences with user ones
958 static GList *
959 content_load( NASettings *settings )
961 GList *content;
963 content = content_load_keys( settings, NULL, settings->private->mandatory, TRUE );
964 content = content_load_keys( settings, content, settings->private->user, FALSE );
966 return( content );
969 static GList *
970 content_load_keys( NASettings *settings, GList *content, KeyFile *key_file, gboolean mandatory )
972 static const gchar *thisfn = "na_settings_content_load_keys";
973 GError *error;
974 gchar **groups, **ig;
975 gchar **keys, **ik;
976 KeyValue *key_value;
977 KeyDef *key_def;
979 error = NULL;
980 if( !g_key_file_load_from_file( key_file->key_file, key_file->fname, G_KEY_FILE_KEEP_COMMENTS, &error )){
981 if( error->code != G_FILE_ERROR_NOENT ){
982 g_warning( "%s: %s (%d) %s", thisfn, key_file->fname, error->code, error->message );
984 g_error_free( error );
985 error = NULL;
987 } else {
988 groups = g_key_file_get_groups( key_file->key_file, NULL );
989 ig = groups;
990 while( *ig ){
991 keys = g_key_file_get_keys( key_file->key_file, *ig, NULL, NULL );
992 ik = keys;
993 while( *ik ){
994 key_def = get_key_def( *ik );
995 if( key_def ){
996 key_value = peek_key_value_from_content( content, *ig, *ik );
997 if( !key_value ){
998 key_value = read_key_value_from_key_file( key_file->key_file, *ig, *ik, key_def );
999 if( key_value ){
1000 key_value->mandatory = mandatory;
1001 content = g_list_prepend( content, key_value );
1005 ik++;
1007 g_strfreev( keys );
1008 ig++;
1010 g_strfreev( groups );
1013 return( content );
1016 static KeyDef *
1017 get_key_def( const gchar *key )
1019 static const gchar *thisfn = "na_settings_get_key_def";
1020 KeyDef *found = NULL;
1021 KeyDef *idef;
1023 idef = ( KeyDef * ) st_def_keys;
1024 while( idef->key && !found ){
1025 if( !strcmp( idef->key, key )){
1026 found = idef;
1028 idef++;
1030 if( !found ){
1031 g_warning( "%s: no KeyDef found for key=%s", thisfn, key );
1034 return( found );
1038 * called from na_settings_new
1039 * allocate and load the key files for global and user preferences
1041 static KeyFile *
1042 key_file_new( NASettings *settings, const gchar *dir )
1044 static const gchar *thisfn = "na_settings_key_file_new";
1045 KeyFile *key_file;
1046 GError *error;
1047 GFile *file;
1049 key_file = g_new0( KeyFile, 1 );
1051 key_file->key_file = g_key_file_new();
1052 key_file->fname = g_strdup_printf( "%s/%s.conf", dir, PACKAGE );
1054 error = NULL;
1055 file = g_file_new_for_path( key_file->fname );
1056 key_file->monitor = g_file_monitor_file( file, 0, NULL, &error );
1057 if( error ){
1058 g_warning( "%s: %s: %s", thisfn, key_file->fname, error->message );
1059 g_error_free( error );
1060 error = NULL;
1061 } else {
1062 key_file->handler = g_signal_connect( key_file->monitor, "changed", ( GCallback ) on_keyfile_changed, settings );
1064 g_object_unref( file );
1066 return( key_file );
1070 * one of the two monitored configuration files have changed on the disk
1071 * we do not try to identify which keys have actually change
1072 * instead we trigger each registered consumer for the 'global' event
1074 * consumers which register for the 'global_conf' event are recorded
1075 * with a NULL key
1077 static void
1078 on_keyfile_changed( GFileMonitor *monitor,
1079 GFile *file, GFile *other_file, GFileMonitorEvent event_type, NASettings *settings )
1081 g_return_if_fail( NA_IS_SETTINGS( settings ));
1083 if( !settings->private->dispose_has_run ){
1085 na_timeout_event( &settings->private->timeout );
1089 static void
1090 on_keyfile_changed_timeout( NASettings *settings )
1092 static const gchar *thisfn = "na_settings_on_keyfile_changed_timeout";
1093 GList *new_content;
1094 GList *modifs;
1095 GList *ic, *im;
1096 const KeyValue *changed;
1097 const Consumer *consumer;
1098 gchar *group_prefix, *key;
1099 #ifdef NA_MAINTAINER_MODE
1100 gchar *value;
1101 #endif
1103 /* last individual notification is older that the st_burst_timeout
1104 * we may so suppose that the burst is terminated
1106 new_content = content_load( settings );
1107 modifs = content_diff( settings->private->content, new_content );
1109 #ifdef NA_MAINTAINER_MODE
1110 g_debug( "%s: %d found update(s)", thisfn, g_list_length( modifs ));
1111 for( im = modifs ; im ; im = im->next ){
1112 changed = ( const KeyValue * ) im->data;
1113 value = na_boxed_get_string( changed->boxed );
1114 g_debug( "%s: group=%s, key=%s, value=%s", thisfn, changed->group, changed->def->key, value );
1115 g_free( value );
1117 #endif
1119 /* for each modification found,
1120 * - check if a consumer has registered for this key, and triggers callback if apply
1121 * - send a notification message
1123 for( im = modifs ; im ; im = im->next ){
1124 changed = ( const KeyValue * ) im->data;
1126 for( ic = settings->private->consumers ; ic ; ic = ic->next ){
1127 consumer = ( const Consumer * ) ic->data;
1128 group_prefix = NULL;
1130 if( !strcmp( consumer->monitored_key, NA_IPREFS_IO_PROVIDERS_READ_STATUS )){
1131 group_prefix = g_strdup_printf( "%s ", NA_IPREFS_IO_PROVIDER_GROUP );
1132 key = NA_IPREFS_IO_PROVIDER_READABLE;
1133 } else {
1134 key = consumer->monitored_key;
1137 if(( !group_prefix || g_str_has_prefix( changed->group, group_prefix )) && !strcmp( changed->def->key, key )){
1138 ( *( NASettingsKeyCallback ) consumer->callback )(
1139 changed->group,
1140 changed->def->key,
1141 na_boxed_get_pointer( changed->boxed ),
1142 changed->mandatory,
1143 consumer->user_data );
1146 g_free( group_prefix );
1149 g_debug( "%s: sending signal for group=%s, key=%s", thisfn, changed->group, changed->def->key );
1150 g_signal_emit_by_name( settings,
1151 SETTINGS_SIGNAL_KEY_CHANGED,
1152 changed->group, changed->def->key, changed->boxed, changed->mandatory );
1155 g_debug( "%s: releasing content", thisfn );
1156 g_list_foreach( settings->private->content, ( GFunc ) release_key_value, NULL );
1157 g_list_free( settings->private->content );
1158 settings->private->content = new_content;
1160 g_debug( "%s: releasing modifs", thisfn );
1161 g_list_foreach( modifs, ( GFunc ) release_key_value, NULL );
1162 g_list_free( modifs );
1165 static void
1166 on_key_changed_final_handler( NASettings *settings, gchar *group, gchar *key, NABoxed *new_value, gboolean mandatory )
1168 g_debug( "na_settings_on_key_changed_final_handler: group=%s, key=%s", group, key );
1169 na_boxed_dump( new_value );
1172 static KeyValue *
1173 peek_key_value_from_content( GList *content, const gchar *group, const gchar *key )
1175 KeyValue *value, *found;
1176 GList *ic;
1178 found = NULL;
1179 for( ic = content ; ic && !found ; ic = ic->next ){
1180 value = ( KeyValue * ) ic->data;
1181 if( !strcmp( value->group, group ) && !strcmp( value->def->key, key )){
1182 found = value;
1186 return( found );
1189 /* group may be NULL
1191 static KeyValue *
1192 read_key_value( NASettings *settings, const gchar *group, const gchar *key, gboolean *found, gboolean *mandatory )
1194 KeyDef *key_def;
1195 gboolean has_entry;
1196 KeyValue *key_value;
1198 g_return_val_if_fail( NA_IS_SETTINGS( settings ), NULL );
1200 key_value = NULL;
1201 if( found ){
1202 *found = FALSE;
1204 if( mandatory ){
1205 *mandatory = FALSE;
1208 if( !settings->private->dispose_has_run ){
1210 key_def = get_key_def( key );
1211 if( key_def ){
1212 has_entry = FALSE;
1213 key_value = read_key_value_from_key_file( settings->private->mandatory->key_file, group ? group : key_def->group, key, key_def );
1214 if( key_value ){
1215 has_entry = TRUE;
1216 if( found ){
1217 *found = TRUE;
1219 if( mandatory ){
1220 *mandatory = TRUE;
1223 if( !has_entry ){
1224 key_value = read_key_value_from_key_file( settings->private->user->key_file, group ? group : key_def->group, key, key_def );
1225 if( key_value ){
1226 has_entry = TRUE;
1227 if( found ){
1228 *found = TRUE;
1235 return( key_value );
1238 static KeyValue *
1239 read_key_value_from_key_file( GKeyFile *key_file, const gchar *group, const gchar *key, const KeyDef *key_def )
1241 static const gchar *thisfn = "na_settings_read_key_value_from_key_file";
1242 KeyValue *value;
1243 gchar *str;
1244 GError *error;
1246 g_debug( "%s: group=%s, key=%s", thisfn, group, key );
1248 value = NULL;
1249 error = NULL;
1251 switch( key_def->type ){
1253 case NA_DATA_TYPE_STRING:
1254 case NA_DATA_TYPE_STRING_LIST:
1255 case NA_DATA_TYPE_UINT:
1256 case NA_DATA_TYPE_UINT_LIST:
1257 case NA_DATA_TYPE_BOOLEAN:
1258 str = g_key_file_get_string( key_file, group, key, &error );
1259 if( error ){
1260 if( error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND && error->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND ){
1261 g_warning( "%s: %s", thisfn, error->message );
1263 g_error_free( error );
1265 /* key exists, but may be empty */
1266 } else {
1267 value = g_new0( KeyValue, 1 );
1268 value->group = g_strdup( group );
1269 value->def = key_def;
1270 switch( key_def->type ){
1271 case NA_DATA_TYPE_STRING:
1272 case NA_DATA_TYPE_UINT:
1273 case NA_DATA_TYPE_BOOLEAN:
1274 case NA_DATA_TYPE_STRING_LIST:
1275 case NA_DATA_TYPE_UINT_LIST:
1276 value->boxed = na_boxed_new_from_string( key_def->type, str );
1277 break;
1280 g_free( str );
1281 break;
1283 default:
1284 g_warning( "%s: unmanaged boxed type: %d", thisfn, key_def->type );
1285 break;
1288 return( value );
1292 * called from instance_finalize
1293 * release the list of registered consumers
1295 static void
1296 release_consumer( Consumer *consumer )
1298 g_free( consumer->monitored_key );
1299 g_free( consumer );
1303 * called from instance_dispose
1304 * release the opened and monitored GKeyFiles
1306 static void
1307 release_key_file( KeyFile *key_file )
1309 g_key_file_free( key_file->key_file );
1310 if( key_file->monitor ){
1311 if( key_file->handler ){
1312 g_signal_handler_disconnect( key_file->monitor, key_file->handler );
1314 g_file_monitor_cancel( key_file->monitor );
1315 g_object_unref( key_file->monitor );
1317 g_free( key_file->fname );
1318 g_free( key_file );
1322 * called from instance_finalize
1323 * release a KeyValue struct
1325 static void
1326 release_key_value( KeyValue *value )
1328 g_free(( gpointer ) value->group );
1329 g_object_unref( value->boxed );
1330 g_free( value );
1333 static gboolean
1334 set_key_value( NASettings *settings, const gchar *group, const gchar *key, const gchar *string )
1336 KeyDef *key_def;
1337 const gchar *wgroup;
1338 gboolean ok;
1340 g_return_val_if_fail( NA_IS_SETTINGS( settings ), FALSE );
1342 ok = FALSE;
1344 if( !settings->private->dispose_has_run ){
1346 wgroup = group;
1347 if( !wgroup ){
1348 key_def = get_key_def( key );
1349 if( key_def ){
1350 wgroup = key_def->group;
1353 if( wgroup ){
1354 g_key_file_set_string( settings->private->user->key_file, wgroup, key, string );
1355 ok = write_user_key_file( settings );
1359 return( ok );
1362 static gboolean
1363 write_user_key_file( NASettings *settings )
1365 static const gchar *thisfn = "na_settings_write_user_key_file";
1366 gchar *data;
1367 GFile *file;
1368 GFileOutputStream *stream;
1369 GError *error;
1370 gsize length;
1372 error = NULL;
1373 data = g_key_file_to_data( settings->private->user->key_file, &length, NULL );
1374 file = g_file_new_for_path( settings->private->user->fname );
1376 stream = g_file_replace( file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error );
1377 if( error ){
1378 g_warning( "%s: g_file_replace: %s", thisfn, error->message );
1379 g_error_free( error );
1380 if( stream ){
1381 g_object_unref( stream );
1383 g_object_unref( file );
1384 g_free( data );
1385 return( FALSE );
1388 g_output_stream_write( G_OUTPUT_STREAM( stream ), data, length, NULL, &error );
1389 if( error ){
1390 g_warning( "%s: g_output_stream_write: %s", thisfn, error->message );
1391 g_error_free( error );
1392 g_object_unref( stream );
1393 g_object_unref( file );
1394 g_free( data );
1395 return( FALSE );
1398 g_output_stream_close( G_OUTPUT_STREAM( stream ), NULL, &error );
1399 if( error ){
1400 g_warning( "%s: g_output_stream_close: %s", thisfn, error->message );
1401 g_error_free( error );
1402 g_object_unref( stream );
1403 g_object_unref( file );
1404 g_free( data );
1405 return( FALSE );
1408 g_object_unref( stream );
1409 g_object_unref( file );
1410 g_free( data );
1412 return( TRUE );