summaryrefslogtreecommitdiff
path: root/src/settings.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/settings.c')
-rw-r--r--src/settings.c439
1 files changed, 439 insertions, 0 deletions
diff --git a/src/settings.c b/src/settings.c
new file mode 100644
index 0000000..701f527
--- /dev/null
+++ b/src/settings.c
@@ -0,0 +1,439 @@
+/*
+ * dLeyna
+ *
+ * Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Ludovic Ferrandis <ludovic.ferrandis@intel.com>
+ *
+ */
+
+#include <string.h>
+#include <gio/gio.h>
+
+#include "log.h"
+#include "settings.h"
+
+struct dleyna_settings_t_ {
+ GKeyFile *keyfile;
+ GFileMonitor *monitor;
+ gulong handler_id;
+ guint ev_id;
+ gchar *file_name;
+
+ /* Global section */
+ gboolean never_quit;
+ gchar *connector_name;
+
+ /* Log section */
+ dleyna_log_type_t log_type;
+ int log_level;
+};
+
+#define DLEYNA_SETTINGS_GROUP_GENERAL "general"
+#define DLEYNA_SETTINGS_KEY_NEVER_QUIT "never-quit"
+#define DLEYNA_SETTINGS_KEY_CONNECTOR_NAME "connector-name"
+
+#define DLEYNA_SETTINGS_GROUP_LOG "log"
+#define DLEYNA_SETTINGS_KEY_LOG_TYPE "log-type"
+#define DLEYNA_SETTINGS_KEY_LOG_LEVEL "log-level"
+
+#define DLEYNA_SETTINGS_DEFAULT_NEVER_QUIT DLEYNA_NEVER_QUIT
+#define DLEYNA_SETTINGS_DEFAULT_CONNECTOR_NAME DLEYNA_CONNECTOR_NAME
+#define DLEYNA_SETTINGS_DEFAULT_LOG_TYPE DLEYNA_LOG_TYPE
+#define DLEYNA_SETTINGS_DEFAULT_LOG_LEVEL DLEYNA_LOG_LEVEL
+
+#define DLEYNA_SETTINGS_LOG_KEYS(sys, loc, settings) \
+do { \
+ DLEYNA_LOG_DEBUG_NL(); \
+ DLEYNA_LOG_INFO("Load file [%s]", loc ? loc : sys); \
+ DLEYNA_LOG_DEBUG_NL(); \
+ DLEYNA_LOG_DEBUG("[General settings]"); \
+ DLEYNA_LOG_DEBUG("Never Quit: %s", (settings)->never_quit ? "T" : "F");\
+ DLEYNA_LOG_DEBUG_NL(); \
+ DLEYNA_LOG_DEBUG("Connector Name: %s", (settings)->connector_name);\
+ DLEYNA_LOG_DEBUG_NL(); \
+ DLEYNA_LOG_DEBUG("[Logging settings]"); \
+ DLEYNA_LOG_DEBUG("Log Type : %d", (settings)->log_type); \
+ DLEYNA_LOG_DEBUG("Log Level: 0x%02X", (settings)->log_level); \
+ DLEYNA_LOG_DEBUG_NL(); \
+} while (0)
+
+
+static void prv_get_keyfile_path(const gchar *file, gchar **sys_path,
+ gchar **loc_path)
+{
+ const gchar *loc_dir;
+
+ if (sys_path != NULL) {
+ *sys_path = NULL;
+
+ if (*SYS_CONFIG_DIR)
+ *sys_path = g_strdup_printf("%s/%s", SYS_CONFIG_DIR,
+ file);
+ }
+
+ if (loc_path != NULL) {
+ loc_dir = g_get_user_config_dir();
+ *loc_path = NULL;
+
+ if (loc_dir && *loc_dir)
+ *loc_path = g_strdup_printf("%s/%s", loc_dir,
+ file);
+ }
+}
+
+static void prv_check_local_keyfile(const gchar *sys_path,
+ const gchar *loc_path)
+{
+ GFile *sys_file = NULL;
+ GFile *loc_file;
+ GFile *loc_dir;
+
+ loc_file = g_file_new_for_path(loc_path);
+ loc_dir = g_file_get_parent(loc_file);
+
+ if (g_file_query_exists(loc_file, NULL) || (sys_path == NULL))
+ goto exit;
+
+ if (!g_file_query_exists(loc_dir, NULL)) {
+ if (!g_file_make_directory(loc_dir, NULL, NULL))
+ goto exit;
+ }
+
+ sys_file = g_file_new_for_path(sys_path);
+
+ (void) g_file_copy(sys_file, loc_file, G_FILE_COPY_TARGET_DEFAULT_PERMS,
+ NULL, NULL, NULL, NULL);
+
+exit:
+ if (loc_dir)
+ g_object_unref(loc_dir);
+
+ if (loc_file)
+ g_object_unref(loc_file);
+
+ if (sys_file)
+ g_object_unref(sys_file);
+}
+
+static GKeyFile *prv_load_keyfile(const gchar *filepath)
+{
+ GKeyFile *keyfile = NULL;
+
+ if (filepath == NULL)
+ goto exit;
+
+ keyfile = g_key_file_new();
+
+ if (!g_key_file_load_from_file(keyfile, filepath, G_KEY_FILE_NONE,
+ NULL)) {
+ g_key_file_free(keyfile);
+ keyfile = NULL;
+ }
+
+exit:
+ return keyfile;
+}
+
+static int prv_to_log_level(gint *int_list, gsize length)
+{
+ gsize i;
+ int log_level_value;
+ int level;
+ int log_level_array[] = {
+ DLEYNA_LOG_LEVEL_DISABLED, DLEYNA_LOG_LEVEL_ERROR,
+ DLEYNA_LOG_LEVEL_CRITICAL, DLEYNA_LOG_LEVEL_WARNING,
+ DLEYNA_LOG_LEVEL_MESSAGE, DLEYNA_LOG_LEVEL_INFO,
+ DLEYNA_LOG_LEVEL_DEBUG, DLEYNA_LOG_LEVEL_DEFAULT,
+ DLEYNA_LOG_LEVEL_ALL };
+
+ log_level_value = 0;
+
+ /* Take all valid values, even duplicated ones, and skip all others.
+ * Priority is single value (0,7,8) over multi value (1..6)
+ * Priority for single values is first found */
+ for (i = 0; i < length; ++i) {
+ level = int_list[i];
+
+ if (level > 0 && level < 7) {
+ log_level_value |= log_level_array[level];
+ } else if ((level == 0) || (level == 7) || (level == 8)) {
+ log_level_value = log_level_array[level];
+ break;
+ }
+ }
+
+ return log_level_value;
+}
+
+static dleyna_log_type_t prv_to_log_type(int type)
+{
+ dleyna_log_type_t log_type = DLEYNA_LOG_TYPE_SYSLOG;
+
+ switch (type) {
+ case 0:
+ break;
+ case 1:
+ log_type = DLEYNA_LOG_TYPE_GLIB;
+ break;
+ default:
+ break;
+ }
+
+ return log_type;
+}
+
+static void prv_read_keys(dleyna_settings_t *settings)
+{
+ GError *error = NULL;
+ GKeyFile *keyfile = settings->keyfile;
+ gboolean b_val;
+ gint int_val;
+ gchar *s_val;
+ gint *int_star;
+ gsize length;
+
+ b_val = g_key_file_get_boolean(keyfile,
+ DLEYNA_SETTINGS_GROUP_GENERAL,
+ DLEYNA_SETTINGS_KEY_NEVER_QUIT,
+ &error);
+
+ if (error == NULL) {
+ settings->never_quit = b_val;
+ } else {
+ g_error_free(error);
+ error = NULL;
+ }
+
+ s_val = g_key_file_get_string(keyfile,
+ DLEYNA_SETTINGS_GROUP_GENERAL,
+ DLEYNA_SETTINGS_KEY_CONNECTOR_NAME,
+ &error);
+
+ if (error == NULL) {
+ g_free(settings->connector_name);
+ settings->connector_name = s_val;
+ } else {
+ g_error_free(error);
+ error = NULL;
+ }
+
+ int_val = g_key_file_get_integer(keyfile,
+ DLEYNA_SETTINGS_GROUP_LOG,
+ DLEYNA_SETTINGS_KEY_LOG_TYPE,
+ &error);
+
+ if (error == NULL) {
+ settings->log_type = prv_to_log_type(int_val);
+ } else {
+ g_error_free(error);
+ error = NULL;
+ }
+
+ g_key_file_set_list_separator(keyfile, ',');
+
+ int_star = g_key_file_get_integer_list(keyfile,
+ DLEYNA_SETTINGS_GROUP_LOG,
+ DLEYNA_SETTINGS_KEY_LOG_LEVEL,
+ &length,
+ &error);
+
+ if (error == NULL) {
+ settings->log_level = prv_to_log_level(int_star,
+ length);
+ g_free(int_star);
+ } else {
+ g_error_free(error);
+ error = NULL;
+ }
+}
+
+static void prv_init_default(dleyna_settings_t *settings)
+{
+ settings->never_quit = DLEYNA_SETTINGS_DEFAULT_NEVER_QUIT;
+ settings->connector_name = g_strdup(
+ DLEYNA_SETTINGS_DEFAULT_CONNECTOR_NAME);
+
+ settings->log_type = DLEYNA_SETTINGS_DEFAULT_LOG_TYPE;
+ settings->log_level = DLEYNA_SETTINGS_DEFAULT_LOG_LEVEL;
+}
+
+static void prv_keyfile_init(dleyna_settings_t *settings,
+ const gchar *sys_path,
+ const gchar *loc_path)
+{
+ settings->keyfile = prv_load_keyfile(loc_path);
+
+ if (settings->keyfile == NULL)
+ settings->keyfile = prv_load_keyfile(sys_path);
+
+ if (settings->keyfile != NULL) {
+ prv_read_keys(settings);
+ dleyna_log_update_type_level(settings->log_type,
+ settings->log_level);
+ }
+}
+
+static void prv_keyfile_finalize(dleyna_settings_t *settings)
+{
+ if (settings->keyfile != NULL) {
+ g_key_file_free(settings->keyfile);
+ settings->keyfile = NULL;
+ }
+}
+
+static void prv_reload(dleyna_settings_t *settings)
+{
+ gchar *sys_path = NULL;
+ gchar *loc_path = NULL;
+
+ DLEYNA_LOG_INFO("Reload local configuration file");
+
+ prv_keyfile_finalize(settings);
+ prv_init_default(settings);
+ prv_get_keyfile_path(settings->file_name, &sys_path, &loc_path);
+
+ if (sys_path || loc_path)
+ prv_keyfile_init(settings, sys_path, loc_path);
+
+ DLEYNA_SETTINGS_LOG_KEYS(sys_path, loc_path, settings);
+
+ g_free(sys_path);
+ g_free(loc_path);
+}
+
+static gboolean prv_monitor_timout_cb(gpointer user_data)
+{
+ dleyna_settings_t *data = (dleyna_settings_t *)user_data;
+
+ DLEYNA_LOG_INFO("Change in local settings file: Reload");
+
+ prv_reload(data);
+
+ data->ev_id = 0;
+ return FALSE;
+}
+
+static void prv_monitor_keyfile_cb(GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ gpointer user_data)
+{
+ dleyna_settings_t *data = (dleyna_settings_t *)user_data;
+
+ switch (event_type) {
+ case G_FILE_MONITOR_EVENT_CHANGED:
+ case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+ case G_FILE_MONITOR_EVENT_DELETED:
+ case G_FILE_MONITOR_EVENT_CREATED:
+ case G_FILE_MONITOR_EVENT_MOVED:
+ /* Reset the timer to prevent running the cb if monitoring
+ * event are raised 1 sec after the timer has been set */
+ if (data->ev_id != 0)
+ (void) g_source_remove(data->ev_id);
+
+ data->ev_id = g_timeout_add_seconds(1,
+ prv_monitor_timout_cb,
+ user_data);
+ break;
+ default:
+ break;
+ }
+}
+
+static void prv_monitor_local_keyfile(dleyna_settings_t *settings,
+ const gchar *loc_path)
+{
+ GFile *loc_file;
+ GFileMonitor *monitor = NULL;
+ gulong handler_id;
+
+ loc_file = g_file_new_for_path(loc_path);
+ monitor = g_file_monitor_file(loc_file, G_FILE_MONITOR_SEND_MOVED, NULL,
+ NULL);
+ g_object_unref(loc_file);
+
+ if (monitor != NULL) {
+ handler_id = g_signal_connect(monitor, "changed",
+ G_CALLBACK(prv_monitor_keyfile_cb),
+ settings);
+
+ settings->monitor = monitor;
+ settings->handler_id = handler_id;
+ }
+}
+
+gboolean dleyna_settings_is_never_quit(dleyna_settings_t *settings)
+{
+ return settings->never_quit;
+}
+
+const gchar *dleyna_settings_connector_name(dleyna_settings_t *settings)
+{
+ return settings->connector_name;
+}
+
+void dleyna_settings_new(const gchar *server, dleyna_settings_t **settings)
+{
+ gchar *sys_path = NULL;
+ gchar *loc_path = NULL;
+ const gchar *server_name;
+
+ *settings = g_malloc0(sizeof(**settings));
+
+ server_name = strrchr(server, '/');
+ if (server_name)
+ server_name++;
+ else
+ server_name = server;
+ (*settings)->file_name = g_strdup_printf("%s%s", server_name, ".conf");
+
+ prv_init_default(*settings);
+
+ prv_get_keyfile_path((*settings)->file_name, &sys_path, &loc_path);
+
+ if (loc_path) {
+ prv_check_local_keyfile(sys_path, loc_path);
+ prv_monitor_local_keyfile(*settings, loc_path);
+ }
+
+ if (sys_path || loc_path)
+ prv_keyfile_init(*settings, sys_path, loc_path);
+
+ DLEYNA_SETTINGS_LOG_KEYS(sys_path, loc_path, *settings);
+
+ g_free(sys_path);
+ g_free(loc_path);
+}
+
+void dleyna_settings_delete(dleyna_settings_t *settings)
+{
+ if (settings->monitor) {
+ if (settings->handler_id)
+ g_signal_handler_disconnect(settings->monitor,
+ settings->handler_id);
+
+ g_file_monitor_cancel(settings->monitor);
+ g_object_unref(settings->monitor);
+ }
+ g_free(settings->connector_name);
+ g_free(settings->file_name);
+
+ prv_keyfile_finalize(settings);
+
+ g_free(settings);
+}