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