* Fixes NB#91689. fixes a wrong check for ASCII
[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-error.h"
37 #include "modest-marshal.h"
38 #include <stdio.h>
39
40 static void   modest_conf_class_init     (ModestConfClass *klass);
41
42 static void   modest_conf_init           (ModestConf *obj);
43
44 static void   modest_conf_finalize       (GObject *obj);
45
46 static void   modest_conf_on_change      (GConfClient *client, guint conn_id,
47                                           GConfEntry *entry, gpointer data);
48
49 static GConfValueType modest_conf_type_to_gconf_type (ModestConfValueType value_type, 
50                                                       GError **err);
51
52 /* list my signals */
53 enum {
54         KEY_CHANGED_SIGNAL,
55         LAST_SIGNAL
56 };
57 static guint signals[LAST_SIGNAL] = {0}; 
58
59
60 typedef struct _ModestConfPrivate ModestConfPrivate;
61 struct _ModestConfPrivate {
62         GConfClient *gconf_client;
63 };
64 #define MODEST_CONF_GET_PRIVATE(o)      (G_TYPE_INSTANCE_GET_PRIVATE((o), \
65                                                                      MODEST_TYPE_CONF, \
66                                                                      ModestConfPrivate))
67 /* globals */
68 static GObjectClass *parent_class = NULL;
69
70 GType
71 modest_conf_get_type (void)
72 {
73         static GType my_type = 0;
74         if (!my_type) {
75                 static const GTypeInfo my_info = {
76                         sizeof(ModestConfClass),
77                         NULL,           /* base init */
78                         NULL,           /* base finalize */
79                         (GClassInitFunc) modest_conf_class_init,
80                         NULL,           /* class finalize */
81                         NULL,           /* class data */
82                         sizeof(ModestConf),
83                         1,              /* n_preallocs */
84                         (GInstanceInitFunc) modest_conf_init,
85                         NULL
86                 };
87                 my_type = g_type_register_static (G_TYPE_OBJECT,
88                                                   "ModestConf",
89                                                   &my_info, 0);
90         }
91         return my_type;
92 }
93
94 static void
95 modest_conf_class_init (ModestConfClass *klass)
96 {
97         GObjectClass *gobject_class;
98         gobject_class = (GObjectClass*) klass;
99
100         parent_class            = g_type_class_peek_parent (klass);
101         gobject_class->finalize = modest_conf_finalize;
102
103         g_type_class_add_private (gobject_class, sizeof(ModestConfPrivate));
104         
105         signals[KEY_CHANGED_SIGNAL] =
106                 g_signal_new ("key_changed",
107                               G_TYPE_FROM_CLASS (gobject_class),
108                               G_SIGNAL_RUN_FIRST,
109                               G_STRUCT_OFFSET (ModestConfClass,key_changed),
110                               NULL, NULL,
111                               modest_marshal_VOID__STRING_INT_INT,
112                               G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_INT); 
113 }
114
115 static void
116 modest_conf_init (ModestConf *obj)
117 {
118         GConfClient *conf = NULL;
119         GError *error = NULL;
120         ModestConfPrivate *priv = MODEST_CONF_GET_PRIVATE(obj);
121
122         priv->gconf_client = NULL;
123         
124         conf = gconf_client_get_default ();
125         if (!conf) {
126                 g_printerr ("modest: could not get gconf client\n");
127                 return;
128         }
129
130         priv->gconf_client = conf;
131
132         /* All the tree will be listened */
133         gconf_client_add_dir (priv->gconf_client,
134                               "/apps/modest",
135                               GCONF_CLIENT_PRELOAD_NONE,
136                               &error);
137
138         /* Notify every change under namespace */
139         if (!error) {
140                 gconf_client_notify_add (priv->gconf_client,
141                                          "/apps/modest",
142                                          modest_conf_on_change,
143                                          obj,
144                                          NULL,
145                                          &error);
146         } else {
147                 g_error_free (error);
148         }
149 }
150
151 static void
152 modest_conf_finalize (GObject *obj)
153 {
154         ModestConfPrivate *priv = MODEST_CONF_GET_PRIVATE(obj);
155         if (priv->gconf_client) {
156
157                 gconf_client_suggest_sync (priv->gconf_client, NULL);
158
159                 g_object_unref (priv->gconf_client);
160                 priv->gconf_client = NULL;
161         }       
162
163         G_OBJECT_CLASS(parent_class)->finalize (obj);
164 }
165
166 ModestConf*
167 modest_conf_new (void)
168 {
169         ModestConf *conf;
170         ModestConfPrivate *priv;
171         
172         conf = MODEST_CONF(g_object_new(MODEST_TYPE_CONF, NULL));
173         if (!conf) {
174                 g_printerr ("modest: failed to init ModestConf (GConf)\n");
175                 return NULL;
176         }
177
178         priv = MODEST_CONF_GET_PRIVATE(conf);
179         if (!priv->gconf_client) {
180                 g_printerr ("modest: failed to init gconf\n");
181                 g_object_unref (conf);
182                 return NULL;
183         }
184         
185         return conf;
186 }
187
188
189 gchar*
190 modest_conf_get_string (ModestConf* self, const gchar* key, GError **err)
191 {
192         ModestConfPrivate *priv;
193         
194         g_return_val_if_fail (self, NULL);
195         g_return_val_if_fail (key,  NULL);
196
197         priv = MODEST_CONF_GET_PRIVATE(self);
198         return gconf_client_get_string (priv->gconf_client, key, err);
199 }
200
201
202 gint
203 modest_conf_get_int (ModestConf* self, const gchar* key, GError **err)
204 {
205         ModestConfPrivate *priv;
206
207         g_return_val_if_fail (self, -1);
208         g_return_val_if_fail (key, -1);
209
210         priv = MODEST_CONF_GET_PRIVATE(self);
211         
212         return gconf_client_get_int (priv->gconf_client, key, err);
213 }
214
215 gdouble
216 modest_conf_get_float (ModestConf* self, const gchar* key, GError **err)
217 {
218         ModestConfPrivate *priv;
219
220         g_return_val_if_fail (self, -1);
221         g_return_val_if_fail (key, -1);
222
223         priv = MODEST_CONF_GET_PRIVATE(self);
224         
225         return gconf_client_get_float (priv->gconf_client, key, err);
226 }
227
228 gboolean
229 modest_conf_get_bool (ModestConf* self, const gchar* key, GError **err)
230 {
231         ModestConfPrivate *priv;
232
233         g_return_val_if_fail (self, FALSE);
234         g_return_val_if_fail (key, FALSE);
235
236         priv = MODEST_CONF_GET_PRIVATE(self);
237         
238         return gconf_client_get_bool (priv->gconf_client, key, err);
239 }
240
241
242 GSList * 
243 modest_conf_get_list (ModestConf* self, const gchar* key, ModestConfValueType list_type,
244                       GError **err)
245 {
246         ModestConfPrivate *priv;
247         GConfValueType gconf_type;
248        
249         g_return_val_if_fail (self, NULL);
250         g_return_val_if_fail (key,  NULL);
251
252         priv = MODEST_CONF_GET_PRIVATE(self);
253
254         gconf_type = modest_conf_type_to_gconf_type (list_type, err);
255
256         return gconf_client_get_list (priv->gconf_client, key, gconf_type, err);
257 }
258
259
260
261
262 gboolean
263 modest_conf_set_string (ModestConf* self, const gchar* key, const gchar* val,
264                         GError **err)
265 {
266         ModestConfPrivate *priv;
267                 
268         g_return_val_if_fail (self,FALSE);
269         g_return_val_if_fail (key, FALSE);
270         g_return_val_if_fail (val, FALSE);
271         
272         priv = MODEST_CONF_GET_PRIVATE(self);
273
274         if (!gconf_client_key_is_writable(priv->gconf_client,key,err)) {
275                 g_printerr ("modest: '%s' is not writable\n", key);
276                 return FALSE;
277         }
278                         
279         return gconf_client_set_string (priv->gconf_client, key, val, err);
280 }
281
282 gboolean
283 modest_conf_set_int  (ModestConf* self, const gchar* key, gint val,
284                       GError **err)
285 {
286         ModestConfPrivate *priv;
287                 
288         g_return_val_if_fail (self,FALSE);
289         g_return_val_if_fail (key, FALSE);
290         
291         priv = MODEST_CONF_GET_PRIVATE(self);
292
293         if (!gconf_client_key_is_writable(priv->gconf_client,key,err)) {
294                 g_printerr ("modest: '%s' is not writable\n", key);
295                 return FALSE;
296         }
297                         
298         return gconf_client_set_int (priv->gconf_client, key, val, err);
299 }
300
301 gboolean
302 modest_conf_set_float (ModestConf* self, 
303                        const gchar* key, 
304                        gdouble val,
305                        GError **err)
306 {
307         ModestConfPrivate *priv;
308                 
309         g_return_val_if_fail (self,FALSE);
310         g_return_val_if_fail (key, FALSE);
311         
312         priv = MODEST_CONF_GET_PRIVATE(self);
313
314         if (!gconf_client_key_is_writable(priv->gconf_client,key,err)) {
315                 g_printerr ("modest: '%s' is not writable\n", key);
316                 return FALSE;
317         }
318                         
319         return gconf_client_set_float (priv->gconf_client, key, val, err);
320 }
321
322
323 gboolean
324 modest_conf_set_bool (ModestConf* self, const gchar* key, gboolean val,
325                       GError **err)
326 {
327         ModestConfPrivate *priv;
328                 
329         g_return_val_if_fail (self,FALSE);
330         g_return_val_if_fail (key, FALSE);
331         
332         priv = MODEST_CONF_GET_PRIVATE(self);
333
334         if (!gconf_client_key_is_writable(priv->gconf_client,key, err)) {
335                 g_warning ("modest: '%s' is not writable\n", key);
336                 return FALSE;
337         }
338
339         return gconf_client_set_bool (priv->gconf_client, key, val, err);
340 }
341
342
343 gboolean
344 modest_conf_set_list (ModestConf* self, const gchar* key, 
345                       GSList *val, ModestConfValueType list_type, 
346                       GError **err)
347 {
348         ModestConfPrivate *priv;
349         GConfValueType gconf_type;
350        
351         g_return_val_if_fail (self, FALSE);
352         g_return_val_if_fail (key, FALSE);
353
354         priv = MODEST_CONF_GET_PRIVATE(self);
355
356         gconf_type = modest_conf_type_to_gconf_type (list_type, err);
357
358         return gconf_client_set_list (priv->gconf_client, key, gconf_type, val, err);
359 }
360
361
362 GSList*
363 modest_conf_list_subkeys (ModestConf* self, const gchar* key, GError **err)
364 {
365         ModestConfPrivate *priv;
366                 
367         g_return_val_if_fail (self,FALSE);
368         g_return_val_if_fail (key, FALSE);
369         
370         priv = MODEST_CONF_GET_PRIVATE(self);
371                         
372         return gconf_client_all_dirs (priv->gconf_client,key,err);
373 }
374
375
376 gboolean
377 modest_conf_remove_key (ModestConf* self, const gchar* key, GError **err)
378 {
379         ModestConfPrivate *priv;
380         gboolean retval;
381         
382         g_return_val_if_fail (self,FALSE);
383         g_return_val_if_fail (key, FALSE);
384         
385         priv = MODEST_CONF_GET_PRIVATE(self);
386                         
387         retval = gconf_client_recursive_unset (priv->gconf_client,key,0,err);
388         gconf_client_suggest_sync (priv->gconf_client, NULL);
389
390         return retval;
391 }
392
393
394 gboolean
395 modest_conf_key_exists (ModestConf* self, const gchar* key, GError **err)
396 {
397         ModestConfPrivate *priv;
398         GConfValue *val;
399
400         g_return_val_if_fail (self,FALSE);
401         g_return_val_if_fail (key, FALSE);
402         
403         priv = MODEST_CONF_GET_PRIVATE(self);
404
405         /* the fast way... */
406         if (gconf_client_dir_exists (priv->gconf_client,key,err))
407                 return TRUE;
408         
409         val = gconf_client_get (priv->gconf_client, key, NULL);
410         if (!val)
411                 return FALSE;
412         else {
413                 gconf_value_free (val);
414                 return TRUE;
415         }       
416 }
417
418
419 gchar*
420 modest_conf_key_escape (const gchar* key)
421 {
422         g_return_val_if_fail (key, NULL);
423         g_return_val_if_fail (strlen (key) > 0, g_strdup (key));
424         
425         return gconf_escape_key (key, strlen(key));
426 }
427
428
429 gchar*
430 modest_conf_key_unescape (const gchar* key)
431 {
432         g_return_val_if_fail (key, NULL);
433
434         return gconf_unescape_key (key, strlen(key));
435 }
436
437 gboolean
438 modest_conf_key_is_valid (const gchar* key)
439 {
440         return gconf_valid_key (key, NULL);
441 }
442
443 static void
444 modest_conf_on_change (GConfClient *client,
445                        guint conn_id,
446                        GConfEntry *entry,
447                        gpointer data)
448 {
449         ModestConfEvent event;
450         const gchar* key;
451
452         event = (entry->value) ? MODEST_CONF_EVENT_KEY_CHANGED : MODEST_CONF_EVENT_KEY_UNSET;
453         key    = gconf_entry_get_key (entry);
454
455         g_signal_emit (G_OBJECT(data),
456                        signals[KEY_CHANGED_SIGNAL], 0,
457                        key, event, conn_id);
458 }
459
460 static GConfValueType
461 modest_conf_type_to_gconf_type (ModestConfValueType value_type, GError **err)
462 {
463         GConfValueType gconf_type;
464
465         switch (value_type) {
466         case MODEST_CONF_VALUE_INT:
467                 gconf_type = GCONF_VALUE_INT;
468                 break;
469         case MODEST_CONF_VALUE_BOOL:
470                 gconf_type = GCONF_VALUE_BOOL;
471                 break;
472         case MODEST_CONF_VALUE_FLOAT:
473                 gconf_type = GCONF_VALUE_FLOAT;
474                 break;
475         case MODEST_CONF_VALUE_STRING:
476                 gconf_type = GCONF_VALUE_STRING;
477                 break;
478         default:
479                 gconf_type = GCONF_VALUE_INVALID;
480                 g_printerr ("modest: invalid list value type %d\n", value_type);
481                 *err = g_error_new_literal (MODEST_CONF_ERROR, 
482                                             MODEST_CONF_ERROR_INVALID_VALUE, 
483                                             "invalid list value type");
484         }
485         return gconf_type;
486 }
487
488 void
489 modest_conf_listen_to_namespace (ModestConf *self,
490                                  const gchar *namespace)
491 {
492         ModestConfPrivate *priv;
493         GError *error = NULL;
494
495         g_return_if_fail (MODEST_IS_CONF (self));
496         g_return_if_fail (namespace);
497         
498         priv = MODEST_CONF_GET_PRIVATE(self);
499
500         /* Add the namespace to the list of the namespaces that will
501            be observed */
502         gconf_client_add_dir (priv->gconf_client,
503                               namespace,
504                               GCONF_CLIENT_PRELOAD_NONE,
505                               &error);
506 }
507
508 void 
509 modest_conf_forget_namespace (ModestConf *self,
510                               const gchar *namespace)
511 {
512         ModestConfPrivate *priv;
513
514         g_return_if_fail (MODEST_IS_CONF (self));
515         g_return_if_fail (namespace);
516         
517         priv = MODEST_CONF_GET_PRIVATE(self);
518
519         /* Remove the namespace to the list of the namespaces that will
520            be observed */
521         gconf_client_remove_dir (priv->gconf_client, namespace, NULL);
522 }