Update media-service-upnp to version 0.3.0 ( ca17a69 )
[profile/ivi/media-service-upnp.git] / src / settings.c
1 /*
2  * media-service-upnp
3  *
4  * Copyright (C) 2012 Intel Corporation. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms and conditions of the GNU Lesser General Public License,
8  * version 2.1, as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
13  * for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Ludovic Ferrandis <ludovic.ferrandis@intel.com>
20  *
21  */
22
23 #include <string.h>
24
25 #include "settings.h"
26
27 struct msu_settings_context_t_ {
28         GKeyFile *keyfile;
29         GFileMonitor *monitor;
30         gulong handler_id;
31         guint ev_id;
32
33         /* Global section */
34         gboolean never_quit;
35
36         /* Log section */
37         msu_log_type_t log_type;
38         int log_level;
39 };
40
41 #define MSU_SETTINGS_KEYFILE_NAME       "media-service-upnp.conf"
42
43 #define MSU_SETTINGS_GROUP_GENERAL      "general"
44 #define MSU_SETTINGS_KEY_NEVER_QUIT     "never-quit"
45
46 #define MSU_SETTINGS_GROUP_LOG          "log"
47 #define MSU_SETTINGS_KEY_LOG_TYPE       "log-type"
48 #define MSU_SETTINGS_KEY_LOG_LEVEL      "log-level"
49
50 #define MSU_SETTINGS_DEFAULT_NEVER_QUIT MSU_NEVER_QUIT
51 #define MSU_SETTINGS_DEFAULT_LOG_TYPE   MSU_LOG_TYPE
52 #define MSU_SETTINGS_DEFAULT_LOG_LEVEL  MSU_LOG_LEVEL
53
54 #define MSU_SETTINGS_LOG_KEYS(sys, loc, settings) \
55 do { \
56         MSU_LOG_DEBUG_NL(); \
57         MSU_LOG_INFO("Load file [%s]", loc ? loc : sys); \
58         MSU_LOG_DEBUG_NL(); \
59         MSU_LOG_DEBUG("[General settings]"); \
60         MSU_LOG_DEBUG("Never Quit: %s", (settings)->never_quit ? "T" : "F"); \
61         MSU_LOG_DEBUG_NL(); \
62         MSU_LOG_DEBUG("[Logging settings]"); \
63         MSU_LOG_DEBUG("Log Type : %d", (settings)->log_type); \
64         MSU_LOG_DEBUG("Log Level: 0x%02X", (settings)->log_level); \
65         MSU_LOG_DEBUG_NL(); \
66 } while (0)
67
68
69 static void prv_msu_settings_get_keyfile_path(gchar **sys_path,
70                                               gchar **loc_path)
71 {
72         const gchar *loc_dir;
73
74         if (sys_path != NULL) {
75                 *sys_path = NULL;
76
77                 if (*SYS_CONFIG_DIR)
78                         *sys_path = g_strdup_printf("%s/%s", SYS_CONFIG_DIR,
79                                                     MSU_SETTINGS_KEYFILE_NAME);
80         }
81
82         if (loc_path != NULL) {
83                 loc_dir =  g_get_user_config_dir();
84                 *loc_path = NULL;
85
86                 if (loc_dir && *loc_dir)
87                         *loc_path = g_strdup_printf("%s/%s", loc_dir,
88                                                     MSU_SETTINGS_KEYFILE_NAME);
89         }
90 }
91
92 static void prv_msu_settings_check_local_keyfile(const gchar *sys_path,
93                                                  const gchar *loc_path)
94 {
95         GFile *sys_file = NULL;
96         GFile *loc_file;
97         GFile *loc_dir;
98
99         loc_file = g_file_new_for_path(loc_path);
100         loc_dir = g_file_get_parent(loc_file);
101
102         if (g_file_query_exists(loc_file, NULL) || (sys_path == NULL))
103                 goto exit;
104
105         if (!g_file_query_exists(loc_dir, NULL)) {
106                 if (!g_file_make_directory(loc_dir, NULL, NULL))
107                         goto exit;
108         }
109
110         sys_file = g_file_new_for_path(sys_path);
111
112         (void) g_file_copy(sys_file, loc_file, G_FILE_COPY_TARGET_DEFAULT_PERMS,
113                            NULL, NULL, NULL, NULL);
114
115 exit:
116         if (loc_dir)
117                 g_object_unref(loc_dir);
118
119         if (loc_file)
120                 g_object_unref(loc_file);
121
122         if (sys_file)
123                 g_object_unref(sys_file);
124 }
125
126 static GKeyFile *prv_msu_settings_load_keyfile(const gchar *filepath)
127 {
128         GKeyFile *keyfile = NULL;
129
130         if (filepath == NULL)
131                 goto exit;
132
133         keyfile = g_key_file_new();
134
135         if (!g_key_file_load_from_file(keyfile, filepath, G_KEY_FILE_NONE,
136                                         NULL)) {
137                 g_key_file_free(keyfile);
138                 keyfile = NULL;
139         }
140
141 exit:
142         return keyfile;
143 }
144
145 static int prv_msu_settings_to_log_level(gint *int_list, gsize length)
146 {
147         gsize i;
148         int log_level_value;
149         int level;
150         int log_level_array[] = { MSU_LOG_LEVEL_DISABLED,
151                                   MSU_LOG_LEVEL_ERROR, MSU_LOG_LEVEL_CRITICAL,
152                                   MSU_LOG_LEVEL_WARNING, MSU_LOG_LEVEL_MESSAGE,
153                                   MSU_LOG_LEVEL_INFO, MSU_LOG_LEVEL_DEBUG,
154                                   MSU_LOG_LEVEL_DEFAULT, MSU_LOG_LEVEL_ALL };
155
156         log_level_value = 0;
157
158         /* Take all valid values, even duplicated ones, and skip all others.
159          * Priority is single value (0,7,8) over multi value (1..6)
160          * Priority for single values is first found */
161         for (i = 0; i < length; ++i) {
162                 level = int_list[i];
163
164                 if (level > 0 && level < 7)
165                         log_level_value |= log_level_array[level];
166                 else if ((level == 0) || (level == 7) || (level == 8)) {
167                         log_level_value = log_level_array[level];
168                         break;
169                 }
170         }
171
172         return log_level_value;
173 }
174
175 static msu_log_type_t prv_msu_settings_to_log_type(int type)
176 {
177         msu_log_type_t log_type = MSU_LOG_TYPE_SYSLOG;
178
179         switch (type) {
180         case 0:
181                 break;
182         case 1:
183                 log_type = MSU_LOG_TYPE_GLIB;
184                 break;
185         default:
186                 break;
187         }
188
189         return log_type;
190 }
191
192 static void prv_msu_settings_read_keys(msu_settings_context_t *settings)
193 {
194         GError *error = NULL;
195         GKeyFile *keyfile = settings->keyfile;
196         gboolean b_val;
197         gint int_val;
198         gint *int_star;
199         gsize length;
200
201         b_val = g_key_file_get_boolean(keyfile, MSU_SETTINGS_GROUP_GENERAL,
202                                                 MSU_SETTINGS_KEY_NEVER_QUIT,
203                                                 &error);
204
205         if (error == NULL)
206                 settings->never_quit = b_val;
207         else {
208                 g_error_free(error);
209                 error = NULL;
210         }
211
212         int_val = g_key_file_get_integer(keyfile, MSU_SETTINGS_GROUP_LOG,
213                                                   MSU_SETTINGS_KEY_LOG_TYPE,
214                                                   &error);
215
216         if (error == NULL)
217                 settings->log_type = prv_msu_settings_to_log_type(int_val);
218         else {
219                 g_error_free(error);
220                 error = NULL;
221         }
222
223         g_key_file_set_list_separator(keyfile, ',');
224
225         int_star = g_key_file_get_integer_list(keyfile, MSU_SETTINGS_GROUP_LOG,
226                                                    MSU_SETTINGS_KEY_LOG_LEVEL,
227                                                    &length,
228                                                    &error);
229
230         if (error == NULL) {
231                 settings->log_level = prv_msu_settings_to_log_level(int_star,
232                                                                      length);
233                 g_free(int_star);
234         } else {
235                 g_error_free(error);
236                 error = NULL;
237         }
238 }
239
240 static void prv_msu_settings_init_default(msu_settings_context_t *settings)
241 {
242         settings->never_quit = MSU_SETTINGS_DEFAULT_NEVER_QUIT;
243
244         settings->log_type = MSU_SETTINGS_DEFAULT_LOG_TYPE;
245         settings->log_level = MSU_SETTINGS_DEFAULT_LOG_LEVEL;
246 }
247
248 static void prv_msu_settings_keyfile_init(msu_settings_context_t *settings,
249                                           const gchar *sys_path,
250                                           const gchar *loc_path)
251 {
252         settings->keyfile = prv_msu_settings_load_keyfile(loc_path);
253
254         if (settings->keyfile == NULL)
255                 settings->keyfile = prv_msu_settings_load_keyfile(sys_path);
256
257         if (settings->keyfile != NULL) {
258                 prv_msu_settings_read_keys(settings);
259                 msu_log_update_type_level(settings->log_type,
260                                           settings->log_level);
261         }
262 }
263
264 static void prv_msu_settings_keyfile_finalize(msu_settings_context_t *settings)
265 {
266         if (settings->keyfile != NULL) {
267                 g_key_file_free(settings->keyfile);
268                 settings->keyfile = NULL;
269         }
270 }
271
272 static void prv_msu_settings_reload(msu_settings_context_t *settings)
273 {
274         gchar *sys_path = NULL;
275         gchar *loc_path = NULL;
276
277         MSU_LOG_INFO("Reload local configuration file");
278
279         prv_msu_settings_keyfile_finalize(settings);
280         prv_msu_settings_init_default(settings);
281         prv_msu_settings_get_keyfile_path(&sys_path, &loc_path);
282
283         if (sys_path || loc_path)
284                 prv_msu_settings_keyfile_init(settings, sys_path, loc_path);
285
286         MSU_SETTINGS_LOG_KEYS(sys_path, loc_path, settings);
287
288         g_free(sys_path);
289         g_free(loc_path);
290 }
291
292 static gboolean prv_msu_settings_monitor_timout_cb(gpointer user_data)
293 {
294         msu_settings_context_t *data = (msu_settings_context_t *) user_data;
295
296         MSU_LOG_INFO("Change in local settings file: Reload");
297
298         prv_msu_settings_reload(data);
299
300         data->ev_id = 0;
301         return FALSE;
302 }
303
304 static void prv_msu_settings_monitor_keyfile_cb(GFileMonitor *monitor,
305                                                 GFile *file,
306                                                 GFile *other_file,
307                                                 GFileMonitorEvent event_type,
308                                                 gpointer user_data)
309 {
310         msu_settings_context_t *data = (msu_settings_context_t *) user_data;
311
312         switch (event_type) {
313         case G_FILE_MONITOR_EVENT_CHANGED:
314         case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
315         case G_FILE_MONITOR_EVENT_DELETED:
316         case G_FILE_MONITOR_EVENT_CREATED:
317         case G_FILE_MONITOR_EVENT_MOVED:
318                 /* Reset the timer to prevent running the cb if monitoring
319                  * event are raised 1 sec after the timer has been set */
320                 if (data->ev_id != 0)
321                         (void) g_source_remove(data->ev_id);
322
323                 data->ev_id = g_timeout_add_seconds(1,
324                                 prv_msu_settings_monitor_timout_cb, user_data);
325                 break;
326         default:
327                 break;
328         }
329 }
330
331 static void prv_msu_settings_monitor_local_keyfile(
332                 msu_settings_context_t *settings, const gchar *loc_path)
333 {
334         GFile *loc_file;
335         GFileMonitor *monitor = NULL;
336         gulong handler_id;
337
338         loc_file = g_file_new_for_path(loc_path);
339         monitor = g_file_monitor_file(loc_file, G_FILE_MONITOR_SEND_MOVED, NULL,
340                                         NULL);
341         g_object_unref(loc_file);
342
343         if (monitor != NULL) {
344                 handler_id = g_signal_connect(monitor, "changed",
345                                 G_CALLBACK(prv_msu_settings_monitor_keyfile_cb),
346                                 settings);
347
348                 settings->monitor = monitor;
349                 settings->handler_id = handler_id;
350         }
351 }
352
353 gboolean msu_settings_is_never_quit(msu_settings_context_t *settings)
354 {
355         return settings->never_quit;
356 }
357
358 void msu_settings_new(msu_settings_context_t **settings)
359 {
360         gchar *sys_path = NULL;
361         gchar *loc_path = NULL;
362
363         *settings = g_malloc0(sizeof(**settings));
364         prv_msu_settings_init_default(*settings);
365
366         prv_msu_settings_get_keyfile_path(&sys_path, &loc_path);
367
368         if (loc_path) {
369                 prv_msu_settings_check_local_keyfile(sys_path, loc_path);
370                 prv_msu_settings_monitor_local_keyfile(*settings, loc_path);
371         }
372
373         if (sys_path || loc_path)
374                 prv_msu_settings_keyfile_init(*settings, sys_path, loc_path);
375
376         MSU_SETTINGS_LOG_KEYS(sys_path, loc_path, *settings);
377
378         g_free(sys_path);
379         g_free(loc_path);
380 }
381
382 void msu_settings_delete(msu_settings_context_t *settings)
383 {
384         if (settings->monitor) {
385                 if (settings->handler_id)
386                         g_signal_handler_disconnect(settings->monitor,
387                                                     settings->handler_id);
388
389                 g_file_monitor_cancel(settings->monitor);
390                 g_object_unref(settings->monitor);
391         }
392
393         prv_msu_settings_keyfile_finalize(settings);
394
395         g_free(settings);
396 }