Update to upstream 1.0.1
[profile/ivi/gsignond.git] / src / common / gsignond-config.c
1 /* vi: set et sw=4 ts=4 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4  * This file is part of gsignond
5  *
6  * Copyright (C) 2012-2013 Intel Corporation.
7  *
8  * Contact: Jussi Laako <jussi.laako@linux.intel.com>
9  *          Amarnath Valluri <amarnath.valluri@linux.intel.com>
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
24  * 02110-1301 USA
25  */
26
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <glib/gstdio.h>
30
31 #include "config.h"
32
33 #include "gsignond/gsignond-config.h"
34 #include "gsignond/gsignond-config-general.h"
35 #include "gsignond/gsignond-config-dbus.h"
36 #include "gsignond/gsignond-log.h"
37 #include "gsignond/gsignond-dictionary.h"
38
39 /**
40  * SECTION:gsignond-config
41  * @short_description: gSSO configuration information
42  * @include: gsignond/gsignond-config.h
43  *
44  * #GSignondConfig holds configuration information as a set of keys and values
45  * (integer or strings). The key names are defined in 
46  * <link linkend="gsignond-General-configuration">general config keys</link>,
47  * and <link linkend="gsignond-DBus-configuration">DBus config keys</link>.
48  * 
49  * The configuration is retrieved from the gSSO configuration file. See below 
50  * for where the file is searched for.
51  * 
52  * <refsect1><title>Where the configuration file is searched for</title></refsect1>
53  * 
54  * If gSSO has been compiled with --enable-debug, then these locations are used,
55  * in decreasing order of priority:
56  * - GSIGNOND_CONFIG environment variable
57  * - g_get_user_config_dir() + "gsignond.conf"
58  * - path specified in --sysconfdir configure option ($(sysconfdir))
59  * - each of g_get_system_config_dirs() + "gsignond.conf"
60  * 
61  * Otherwise, the config file location is determined at compilation time as 
62  * $(sysconfdir) + "gsignond.conf"
63  * 
64  * <refsect1><title>Example configuration file</title></refsect1>
65  * 
66  * See example configuration file here:
67  * <ulink url="http://code.google.com/p/accounts-sso/source/browse/gsignond.conf.in?repo=gsignond">
68  * http://code.google.com/p/accounts-sso/source/browse/gsignond.conf.in?repo=gsignond</ulink>
69  */
70
71 /**
72  * GSignondConfig:
73  *
74  * Opaque structure for the object.
75  */
76 /**
77  * GSignondConfigClass:
78  *
79  * Opaque structure for the class.
80  */
81
82
83 struct _GSignondConfigPrivate
84 {
85     gchar *config_file_path;
86     GSignondDictionary *config_table;
87 };
88
89 #define GSIGNOND_CONFIG_PRIV(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), GSIGNOND_TYPE_CONFIG, GSignondConfigPrivate)
90
91 G_DEFINE_TYPE (GSignondConfig, gsignond_config, G_TYPE_OBJECT);
92
93 static gchar *
94 _check_config_file (const gchar *path)
95 {
96     gchar *fn;
97
98     fn = g_build_filename (path,
99                            "gsignond.conf",
100                            NULL);
101     DBG ("check config at %s", fn);
102     if (g_access (fn, R_OK) == 0)
103         return fn;
104     g_free (fn);
105     return NULL;
106 }
107
108 static gboolean
109 _load_config (GSignondConfig *self)
110 {
111     GError *err = NULL;
112     gchar **groups = NULL;
113     gsize n_groups = 0;
114     int i,j;
115     GKeyFile *settings = g_key_file_new ();
116
117 #   ifdef ENABLE_DEBUG
118     const gchar * const *sysconfdirs;
119
120     if (!self->priv->config_file_path) {
121         const gchar *cfg_env = g_getenv ("GSIGNOND_CONFIG");
122         if (cfg_env)
123             self->priv->config_file_path = _check_config_file (cfg_env);
124     }
125     if (!self->priv->config_file_path) {
126         gchar *user_cfg = g_strdup_printf ("%s/%s",
127                                            g_get_user_config_dir (),
128                                            "gsignond");
129         self->priv->config_file_path = _check_config_file (user_cfg);
130         g_free (user_cfg);
131     }
132     if (!self->priv->config_file_path) {
133         self->priv->config_file_path =
134             _check_config_file (GSIGNOND_SYSCONF_DIR);
135     }
136     if (!self->priv->config_file_path) {
137         sysconfdirs = g_get_system_config_dirs ();
138         while (*sysconfdirs != NULL) {
139             gchar *sys_cfg = _check_config_file (*sysconfdirs);
140             if (sys_cfg) {
141                 self->priv->config_file_path = sys_cfg;
142                 break;
143             }
144             sysconfdirs++;
145         }
146     }
147 #   else  /* ENABLE_DEBUG */
148 #   ifndef GSIGNOND_SYSCONF_DIR
149 #   error "System configuration directory not defined!"
150 #   endif
151     self->priv->config_file_path = _check_config_file (GSIGNOND_SYSCONF_DIR);
152 #   endif  /* ENABLE_DEBUG */
153
154     if (self->priv->config_file_path) {
155         DBG ("Loading SSO config from %s", self->priv->config_file_path);
156         if (!g_key_file_load_from_file (settings,
157                                         self->priv->config_file_path,
158                                         G_KEY_FILE_NONE, &err)) {
159             WARN ("error reading config file at '%s': %s",
160                  self->priv->config_file_path, err->message);
161             g_error_free (err);
162             g_key_file_free (settings);
163             return FALSE;
164         }
165     }
166
167     groups = g_key_file_get_groups (settings, &n_groups);
168
169     for (i = 0; i < n_groups; i++) {
170         GError *err = NULL;
171         gsize n_keys =0;
172         gchar **keys = g_key_file_get_keys (settings,
173                                             groups[i],
174                                             &n_keys,
175                                             &err);
176         if (err) {
177             WARN ("fail to read group '%s': %s", groups[i], err->message);
178             g_error_free (err);
179             continue;
180         }
181
182         for (j = 0; j < n_keys; j++) {
183             gchar *key = g_strdup_printf ("%s/%s", groups[i], keys[j]);
184             gchar *value = g_key_file_get_value (settings,
185                                                  groups[i],
186                                                  keys[j],
187                                                  &err);
188             if (err) {
189                 WARN ("fail to read key '%s/%s': %s", groups[i], keys[j], err->message);
190                 g_error_free (err);
191                 continue;
192             }
193
194             INFO ("found config : '%s/%s' - '%s'", groups[i], keys[j], value);
195             gsignond_config_set_string (self, key, value);
196
197             g_free (key);
198             g_free (value);
199         }
200
201         g_strfreev (keys);
202     }
203
204     g_strfreev (groups);
205
206     g_key_file_free (settings);
207
208     return TRUE;
209 }
210
211 /**
212  * gsignond_config_get_integer:
213  * @self: an instance of #GSignondConfig
214  * @key: the key name
215  * 
216  * Get an integer configuration value.
217  * 
218  * Returns: the value corresponding to the key as an integer. If the key does not
219  * exist or cannot be converted to the integer, 0 is returned.
220  */
221 gint
222 gsignond_config_get_integer (GSignondConfig *self, const gchar *key)
223 {
224     const gchar *str_value = gsignond_config_get_string (self, key);
225     return (gint) (str_value ? atoi (str_value) : 0);
226 }
227
228 /**
229  * gsignond_config_set_integer:
230  * @self: an instance of #GSignondConfig
231  * @key: the key name
232  * @value: the value
233  * 
234  * Sets the configuration value to the provided integer.
235  */
236 void
237 gsignond_config_set_integer (GSignondConfig *self, const gchar *key,
238                              gint value) 
239 {
240     gchar *s_value = 0;
241     g_return_if_fail (self && GSIGNOND_IS_CONFIG (self));
242
243     s_value = g_strdup_printf ("%d", value);
244     if (!s_value) return;
245
246     gsignond_config_set_string (self, (gpointer) key, s_value);
247
248     g_free (s_value);
249
250 }
251
252 /**
253  * gsignond_config_get_string:
254  * @self: an instance of #GSignondConfig
255  * @key: the key name
256  * 
257  * Get a string configuration value.
258  * 
259  * Returns: (transfer none): the value corresponding to the key as string. If the key does not
260  * exist, NULL is returned.
261  */
262 const gchar *
263 gsignond_config_get_string (GSignondConfig *self, const gchar *key)
264 {
265     g_return_val_if_fail (self && GSIGNOND_IS_CONFIG (self), NULL);
266
267     GVariant* value = gsignond_dictionary_get (self->priv->config_table,
268                                                (gpointer) key);
269     if (!value) return NULL;
270
271     return g_variant_get_string (value, NULL);
272 }
273
274 /**
275  * gsignond_config_set_string:
276  * @self: an instance of #GSignondConfig
277  * @key: the key name
278  * @value: (transfer none): the value
279  * 
280  * Sets the configuration value to the provided string.
281  */
282 void
283 gsignond_config_set_string (GSignondConfig *self, const gchar *key,
284                             const gchar *value) 
285 {
286     g_return_if_fail (self && GSIGNOND_IS_CONFIG (self));
287
288     gsignond_dictionary_set (self->priv->config_table,
289                              (gpointer) key,
290                              g_variant_new_string (value));
291
292 }
293
294 static void
295 gsignond_config_dispose (GObject *object)
296 {
297     GSignondConfig *self = 0;
298     g_return_if_fail (object && GSIGNOND_IS_CONFIG (object));
299
300     self = GSIGNOND_CONFIG (object);
301
302     if (self->priv->config_table) {
303         gsignond_dictionary_unref (self->priv->config_table);
304         self->priv->config_table = NULL;
305     }
306
307     G_OBJECT_CLASS (gsignond_config_parent_class)->dispose (object);
308 }
309
310 static void
311 gsignond_config_finalize (GObject *object)
312 {
313     GSignondConfig *self = 0;
314     g_return_if_fail (object && GSIGNOND_IS_CONFIG (object));
315
316     self = GSIGNOND_CONFIG (object);
317
318     if (self->priv->config_file_path) {
319         g_free (self->priv->config_file_path);
320         self->priv->config_file_path = NULL;
321     }
322
323     G_OBJECT_CLASS (gsignond_config_parent_class)->finalize (object);
324 }
325
326 static void
327 gsignond_config_init (GSignondConfig *self)
328 {
329     self->priv = GSIGNOND_CONFIG_PRIV (self);
330
331     self->priv->config_file_path = NULL;
332     self->priv->config_table = gsignond_dictionary_new();
333     
334     if (!_load_config (self))
335         WARN ("load configuration failed, using default settings");
336 }
337
338 static void
339 gsignond_config_class_init (GSignondConfigClass *klass)
340 {
341     GObjectClass *object_class = G_OBJECT_CLASS (klass);
342
343     g_type_class_add_private (object_class, sizeof (GSignondConfigPrivate));
344
345     object_class->dispose = gsignond_config_dispose;
346     object_class->finalize = gsignond_config_finalize;
347
348 }
349
350 /**
351  * gsignond_config_new:
352  * 
353  * Create a #GSignondConfig object.
354  * 
355  * Returns: an instance of #GSignondConfig. gSSO extensions should not use this
356  * as they're already provided with a config object when they're created.
357  */
358 GSignondConfig *
359 gsignond_config_new ()
360 {
361     return GSIGNOND_CONFIG (g_object_new (GSIGNOND_TYPE_CONFIG, NULL));
362 }
363