* Fixes NB#91062, fixes a memory leak
[modest] / src / modest-conf.c
1 /* Copyright (c) 2006, Nokia Corporation
2  * All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  *   notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  *   notice, this list of conditions and the following disclaimer in the
12  *   documentation and/or other materials provided with the distribution.
13  * * Neither the name of the Nokia Corporation nor the names of its
14  *   contributors may be used to endorse or promote products derived from
15  *   this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
18  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
21  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <gconf/gconf-client.h>
31 #include <config.h>
32 #include <string.h>
33 #include <glib/gi18n.h>
34 #include "modest-defs.h"
35 #include "modest-conf.h"
36 #include "modest-marshal.h"
37 #include <stdio.h>
38
39 static void   modest_conf_class_init     (ModestConfClass *klass);
40
41 static void   modest_conf_init           (ModestConf *obj);
42
43 static void   modest_conf_finalize       (GObject *obj);
44
45 static void   modest_conf_on_change      (GConfClient *client, guint conn_id,
46                                           GConfEntry *entry, gpointer data);
47
48 static GConfValueType modest_conf_type_to_gconf_type (ModestConfValueType value_type, 
49                                                       GError **err);
50
51 /* list my signals */
52 enum {
53         KEY_CHANGED_SIGNAL,
54         LAST_SIGNAL
55 };
56 static guint signals[LAST_SIGNAL] = {0}; 
57
58
59 typedef struct _ModestConfPrivate ModestConfPrivate;
60 struct _ModestConfPrivate {
61         GConfClient *gconf_client;
62 };
63 #define MODEST_CONF_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
64                                                                      MODEST_TYPE_CONF, \
65                                                                      ModestConfPrivate))
66 /* globals */
67 static GObjectClass *parent_class = NULL;
68
69 GType
70 modest_conf_get_type (void)
71 {
72         static GType my_type = 0;
73         if (!my_type) {
74                 static const GTypeInfo my_info = {
75                         sizeof(ModestConfClass),
76                         NULL,           /* base init */
77                         NULL,           /* base finalize */
78                         (GClassInitFunc) modest_conf_class_init,
79                         NULL,           /* class finalize */
80                         NULL,           /* class data */
81                         sizeof(ModestConf),
82                         1,              /* n_preallocs */
83                         (GInstanceInitFunc) modest_conf_init,
84                         NULL
85                 };
86                 my_type = g_type_register_static (G_TYPE_OBJECT,
87                                                   "ModestConf",
88                                                   &my_info, 0);
89         }
90         return my_type;
91 }
92
93 static void
94 modest_conf_class_init (ModestConfClass *klass)
95 {
96         GObjectClass *gobject_class;
97         gobject_class = (GObjectClass*) klass;
98
99         parent_class            = g_type_class_peek_parent (klass);
100         gobject_class->finalize = modest_conf_finalize;
101
102         g_type_class_add_private (gobject_class, sizeof(ModestConfPrivate));
103         
104         signals[KEY_CHANGED_SIGNAL] =
105                 g_signal_new ("key_changed",
106                               G_TYPE_FROM_CLASS (gobject_class),
107                               G_SIGNAL_RUN_FIRST,
108                               G_STRUCT_OFFSET (ModestConfClass,key_changed),
109                               NULL, NULL,
110                               modest_marshal_VOID__STRING_INT_INT,
111                               G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT); 
112 }
113
114 static void
115 modest_conf_init (ModestConf *obj)
116 {
117         GConfClient *conf = NULL;
118         GError *error = NULL;
119         ModestConfPrivate *priv = MODEST_CONF_GET_PRIVATE(obj);
120
121         priv->gconf_client = NULL;
122         
123         conf = gconf_client_get_default ();
124         if (!conf) {
125                 g_printerr ("modest: could not get gconf client\n");
126                 return;
127         }
128
129         priv->gconf_client = conf;
130
131         /* All the tree will be listened */
132         gconf_client_add_dir (priv->gconf_client,
133                               "/apps/modest",
134                               GCONF_CLIENT_PRELOAD_NONE,
135                               &error);
136
137         /* Notify every change under namespace */
138         if (!error) {
139                 gconf_client_notify_add (priv->gconf_client,
140                                          "/apps/modest",
141                                          modest_conf_on_change,
142                                          obj,
143                                          NULL,
144                                          &error);
145         } else {
146                 g_error_free (error);
147         }
148 }
149
150 static void
151 modest_conf_finalize (GObject *obj)
152 {
153         ModestConfPrivate *priv = MODEST_CONF_GET_PRIVATE(obj);
154         if (priv->gconf_client) {
155
156                 gconf_client_suggest_sync (priv->gconf_client, NULL);
157
158                 g_object_unref (priv->gconf_client);
159                 priv->gconf_client = NULL;
160         }       
161
162         G_OBJECT_CLASS(parent_class)->finalize (obj);
163 }
164
165 ModestConf*
166 modest_conf_new (void)
167 {
168         ModestConf *conf;
169         ModestConfPrivate *priv;
170         
171         conf = MODEST_CONF(g_object_new(MODEST_TYPE_CONF, NULL));
172         if (!conf) {
173                 g_printerr ("modest: failed to init ModestConf (GConf)\n");
174                 return NULL;
175         }
176
177         priv = MODEST_CONF_GET_PRIVATE(conf);
178         if (!priv->gconf_client) {
179                 g_printerr ("modest: failed to init gconf\n");
180                 g_object_unref (conf);
181                 return NULL;
182         }
183         
184         return conf;
185 }
186
187
188 gchar*
189 modest_conf_get_string (ModestConf* self, const gchar* key, GError **err)
190 {
191         ModestConfPrivate *priv;
192         
193         g_return_val_if_fail (self, NULL);
194         g_return_val_if_fail (key,  NULL);
195
196         priv = MODEST_CONF_GET_PRIVATE(self);
197         return gconf_client_get_string (priv->gconf_client, key, err);
198 }
199
200
201 gint
202 modest_conf_get_int (ModestConf* self, const gchar* key, GError **err)
203 {
204         ModestConfPrivate *priv;
205
206         g_return_val_if_fail (self, -1);
207         g_return_val_if_fail (key, -1);
208
209         priv = MODEST_CONF_GET_PRIVATE(self);
210         
211         return gconf_client_get_int (priv->gconf_client, key, err);
212 }
213
214 gdouble
215 modest_conf_get_float (ModestConf* self, const gchar* key, GError **err)
216 {
217         ModestConfPrivate *priv;
218
219         g_return_val_if_fail (self, -1);
220         g_return_val_if_fail (key, -1);
221
222         priv = MODEST_CONF_GET_PRIVATE(self);
223         
224         return gconf_client_get_float (priv->gconf_client, key, err);
225 }
226
227 gboolean
228 modest_conf_get_bool (ModestConf* self, const gchar* key, GError **err)
229 {
230         ModestConfPrivate *priv;
231
232         g_return_val_if_fail (self, FALSE);
233         g_return_val_if_fail (key, FALSE);
234
235         priv = MODEST_CONF_GET_PRIVATE(self);
236         
237         return gconf_client_get_bool (priv->gconf_client, key, err);
238 }
239
240
241 GSList * 
242 modest_conf_get_list (ModestConf* self, const gchar* key, ModestConfValueType list_type,
243                       GError **err)
244 {
245         ModestConfPrivate *priv;
246         GConfValueType gconf_type;
247        
248         g_return_val_if_fail (self, NULL);
249         g_return_val_if_fail (key,  NULL);
250
251         priv = MODEST_CONF_GET_PRIVATE(self);
252
253         gconf_type = modest_conf_type_to_gconf_type (list_type, err);
254
255         return gconf_client_get_list (priv->gconf_client, key, gconf_type, err);
256 }
257
258
259
260
261 gboolean
262 modest_conf_set_string (ModestConf* self, const gchar* key, const gchar* val,
263                         GError **err)
264 {
265         ModestConfPrivate *priv;
266                 
267         g_return_val_if_fail (self,FALSE);
268         g_return_val_if_fail (key, FALSE);
269         g_return_val_if_fail (val, FALSE);
270         
271         priv = MODEST_CONF_GET_PRIVATE(self);
272
273         if (!gconf_client_key_is_writable(priv->gconf_client,key,err)) {
274                 g_printerr ("modest: '%s' is not writable\n", key);
275                 return FALSE;
276         }
277                         
278         return gconf_client_set_string (priv->gconf_client, key, val, err);
279 }
280
281 gboolean
282 modest_conf_set_int  (ModestConf* self, const gchar* key, gint val,
283                       GError **err)
284 {
285         ModestConfPrivate *priv;
286                 
287         g_return_val_if_fail (self,FALSE);
288         g_return_val_if_fail (key, FALSE);
289         
290         priv = MODEST_CONF_GET_PRIVATE(self);
291
292         if (!gconf_client_key_is_writable(priv->gconf_client,key,err)) {
293                 g_printerr ("modest: '%s' is not writable\n", key);
294                 return FALSE;
295         }
296                         
297         return gconf_client_set_int (priv->gconf_client, key, val, err);
298 }
299
300 gboolean
301 modest_conf_set_float (ModestConf* self, 
302                        const gchar* key, 
303                        gdouble val,
304                        GError **err)
305 {
306         ModestConfPrivate *priv;
307                 
308         g_return_val_if_fail (self,FALSE);
309         g_return_val_if_fail (key, FALSE);
310         
311         priv = MODEST_CONF_GET_PRIVATE(self);
312
313         if (!gconf_client_key_is_writable(priv->gconf_client,key,err)) {
314                 g_printerr ("modest: '%s' is not writable\n", key);
315                 return FALSE;
316         }
317                         
318         return gconf_client_set_float (priv->gconf_client, key, val, err);
319 }
320
321
322 gboolean
323 modest_conf_set_bool (ModestConf* self, const gchar* key, gboolean val,
324                       GError **err)
325 {
326         ModestConfPrivate *priv;
327                 
328         g_return_val_if_fail (self,FALSE);
329         g_return_val_if_fail (key, FALSE);
330         
331         priv = MODEST_CONF_GET_PRIVATE(self);
332
333         if (!gconf_client_key_is_writable(priv->gconf_client,key, err)) {
334                 g_warning ("modest: '%s' is not writable\n", key);
335                 return FALSE;
336         }
337
338         return gconf_client_set_bool (priv->gconf_client, key, val, err);
339 }
340
341
342 gboolean
343 modest_conf_set_list (ModestConf* self, const gchar* key, 
344                       GSList *val, ModestConfValueType list_type, 
345                       GError **err)
346 {
347         ModestConfPrivate *priv;
348         GConfValueType gconf_type;
349        
350         g_return_val_if_fail (self, FALSE);
351         g_return_val_if_fail (key, FALSE);
352
353         priv = MODEST_CONF_GET_PRIVATE(self);
354
355         gconf_type = modest_conf_type_to_gconf_type (list_type, err);
356
357         return gconf_client_set_list (priv->gconf_client, key, gconf_type, val, err);
358 }
359
360
361 GSList*
362 modest_conf_list_subkeys (ModestConf* self, const gchar* key, GError **err)
363 {
364         ModestConfPrivate *priv;
365                 
366         g_return_val_if_fail (self,FALSE);
367         g_return_val_if_fail (key, FALSE);
368         
369         priv = MODEST_CONF_GET_PRIVATE(self);
370                         
371         return gconf_client_all_dirs (priv->gconf_client,key,err);
372 }
373
374
375 gboolean
376 modest_conf_remove_key (ModestConf* self, const gchar* key, GError **err)
377 {
378         ModestConfPrivate *priv;
379         gboolean retval;
380         
381         g_return_val_if_fail (self,FALSE);
382         g_return_val_if_fail (key, FALSE);
383         
384         priv = MODEST_CONF_GET_PRIVATE(self);
385                         
386         retval = gconf_client_recursive_unset (priv->gconf_client,key,0,err);
387         gconf_client_suggest_sync (priv->gconf_client, NULL);
388
389         return retval;
390 }
391
392
393 gboolean
394 modest_conf_key_exists (ModestConf* self, const gchar* key, GError **err)
395 {
396         ModestConfPrivate *priv;
397         GConfValue *val;
398
399         g_return_val_if_fail (self,FALSE);
400         g_return_val_if_fail (key, FALSE);
401         
402         priv = MODEST_CONF_GET_PRIVATE(self);
403
404         /* the fast way... */
405         if (gconf_client_dir_exists (priv->gconf_client,key,err))
406                 return TRUE;
407         
408         val = gconf_client_get (priv->gconf_client, key, NULL);
409         if (!val)
410                 return FALSE;
411         else {
412                 gconf_value_free (val);
413                 return TRUE;
414         }       
415 }
416
417
418 gchar*
419 modest_conf_key_escape (const gchar* key)
420 {
421         g_return_val_if_fail (key, NULL);
422         g_return_val_if_fail (strlen (key) > 0, g_strdup (key));
423         
424         return gconf_escape_key (key, strlen(key));
425 }
426
427
428 gchar*
429 modest_conf_key_unescape (const gchar* key)
430 {
431         g_return_val_if_fail (key, NULL);
432
433         return gconf_unescape_key (key, strlen(key));
434 }
435
436 gboolean
437 modest_conf_key_is_valid (const gchar* key)
438 {
439         return gconf_valid_key (key, NULL);
440 }
441
442 static void
443 modest_conf_on_change (GConfClient *client,
444                        guint conn_id,
445                        GConfEntry *entry,
446                        gpointer data)
447 {
448         ModestConfEvent event;
449         const gchar* key;
450
451         event = (entry->value) ? MODEST_CONF_EVENT_KEY_CHANGED : MODEST_CONF_EVENT_KEY_UNSET;
452         key    = gconf_entry_get_key (entry);
453
454         g_signal_emit (G_OBJECT(data),
455                        signals[KEY_CHANGED_SIGNAL], 0,
456                        key, event, conn_id);
457 }
458
459 static GConfValueType
460 modest_conf_type_to_gconf_type (ModestConfValueType value_type, GError **err)
461 {
462         GConfValueType gconf_type;
463
464         switch (value_type) {
465         case MODEST_CONF_VALUE_INT:
466                 gconf_type = GCONF_VALUE_INT;
467                 break;
468         case MODEST_CONF_VALUE_BOOL:
469                 gconf_type = GCONF_VALUE_BOOL;
470                 break;
471         case MODEST_CONF_VALUE_FLOAT:
472                 gconf_type = GCONF_VALUE_FLOAT;
473                 break;
474         case MODEST_CONF_VALUE_STRING:
475                 gconf_type = GCONF_VALUE_STRING;
476                 break;
477         default:
478                 /* FIXME: use MODEST_ERROR, and error code */
479                 gconf_type = GCONF_VALUE_INVALID;
480                 g_printerr ("modest: invalid list value type %d\n", value_type);
481                 *err = g_error_new_literal (0, 0, "invalid list value type");
482         }       
483         return gconf_type;
484 }
485
486 void
487 modest_conf_listen_to_namespace (ModestConf *self,
488                                  const gchar *namespace)
489 {
490         ModestConfPrivate *priv;
491         GError *error = NULL;
492
493         g_return_if_fail (MODEST_IS_CONF (self));
494         g_return_if_fail (namespace);
495         
496         priv = MODEST_CONF_GET_PRIVATE(self);
497
498         /* Add the namespace to the list of the namespaces that will
499            be observed */
500         gconf_client_add_dir (priv->gconf_client,
501                               namespace,
502                               GCONF_CLIENT_PRELOAD_NONE,
503                               &error);
504 }
505
506 void 
507 modest_conf_forget_namespace (ModestConf *self,
508                               const gchar *namespace)
509 {
510         ModestConfPrivate *priv;
511
512         g_return_if_fail (MODEST_IS_CONF (self));
513         g_return_if_fail (namespace);
514         
515         priv = MODEST_CONF_GET_PRIVATE(self);
516
517         /* Remove the namespace to the list of the namespaces that will
518            be observed */
519         gconf_client_remove_dir (priv->gconf_client, namespace, NULL);
520 }