/*
    Copyright (C) 2010  ABRT team
    Copyright (C) 2010  RedHat Inc

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "libabrt.h"

#define ABRT_CONF "abrt.conf"

char *        g_settings_sWatchCrashdumpArchiveDir = NULL;
unsigned int  g_settings_nMaxCrashReportsSize = 1000;
char *        g_settings_dump_location = NULL;
bool          g_settings_delete_uploaded = 0;
bool          g_settings_autoreporting = 0;
char *        g_settings_autoreporting_event = NULL;
bool          g_settings_shortenedreporting = 0;
bool          g_settings_explorechroots = 0;
unsigned int  g_settings_debug_level = 0;

void free_abrt_conf_data()
{
    free(g_settings_sWatchCrashdumpArchiveDir);
    g_settings_sWatchCrashdumpArchiveDir = NULL;

    free(g_settings_dump_location);
    g_settings_dump_location = NULL;

    free(g_settings_autoreporting_event);
    g_settings_autoreporting_event = NULL;
}

/* Beware - the function normalizes only slashes - that's the most often
 * problem we have to face.
 */
static char *xstrdup_normalized_path(const char *path)
{
    const size_t len = strlen(path);
    char *const res = xzalloc(len + 1);

    res[0] = path[0];

    const char *p = path + 1;
    char *r = res;
    for (; p - path < len; ++p)
        if (*p != '/' || *r != '/')
            *++r = *p;

    /* remove trailing slash if the path is not '/' */
    if (r - res > 1 && *r == '/')
        *r = '\0';

    return res;
}

static void ParseCommon(map_string_t *settings, const char *conf_filename)
{
    const char *value;

    value = get_map_string_item_or_NULL(settings, "WatchCrashdumpArchiveDir");
    if (value)
    {
        g_settings_sWatchCrashdumpArchiveDir = xstrdup_normalized_path(value);
        remove_map_string_item(settings, "WatchCrashdumpArchiveDir");
    }

    value = get_map_string_item_or_NULL(settings, "MaxCrashReportsSize");
    if (value)
    {
        char *end;
        errno = 0;
        unsigned long ul = strtoul(value, &end, 10);
        if (errno || end == value || *end != '\0' || ul > INT_MAX)
            error_msg("Error parsing %s setting: '%s'", "MaxCrashReportsSize", value);
        else
            g_settings_nMaxCrashReportsSize = ul;
        remove_map_string_item(settings, "MaxCrashReportsSize");
    }

    value = get_map_string_item_or_NULL(settings, "DumpLocation");
    if (value)
    {
        g_settings_dump_location = xstrdup_normalized_path(value);
        remove_map_string_item(settings, "DumpLocation");
    }
    else
        g_settings_dump_location = xstrdup(DEFAULT_DUMP_LOCATION);

    value = get_map_string_item_or_NULL(settings, "DeleteUploaded");
    if (value)
    {
        g_settings_delete_uploaded = string_to_bool(value);
        remove_map_string_item(settings, "DeleteUploaded");
    }

    value = get_map_string_item_or_NULL(settings, "AutoreportingEnabled");
    if (value)
    {
        g_settings_autoreporting = string_to_bool(value);
        remove_map_string_item(settings, "AutoreportingEnabled");
    }

    value = get_map_string_item_or_NULL(settings, "AutoreportingEvent");
    if (value)
    {
        g_settings_autoreporting_event = xstrdup(value);
        remove_map_string_item(settings, "AutoreportingEvent");
    }
    else
        g_settings_autoreporting_event = xstrdup("report_uReport");

    value = get_map_string_item_or_NULL(settings, "ShortenedReporting");
    if (value)
    {
        g_settings_shortenedreporting = string_to_bool(value);
        remove_map_string_item(settings, "ShortenedReporting");
    }
    else
    {
        /* Default: enabled for GNOME desktop, else disabled */
        const char *desktop_env = getenv("DESKTOP_SESSION");
        g_settings_shortenedreporting = (desktop_env && strcasestr(desktop_env, "gnome") != NULL);
    }

    value = get_map_string_item_or_NULL(settings, "ExploreChroots");
    if (value)
    {
        g_settings_explorechroots = string_to_bool(value);
        remove_map_string_item(settings, "ExploreChroots");
    }
    else
        g_settings_explorechroots = false;

    value = get_map_string_item_or_NULL(settings, "DebugLevel");
    if (value)
    {
        char *end;
        errno = 0;
        unsigned long ul = strtoul(value, &end, 10);
        if (errno || end == value || *end != '\0' || ul > INT_MAX)
            error_msg("Error parsing %s setting: '%s'", "DebugLevel", value);
        else
            g_settings_debug_level = ul;
        remove_map_string_item(settings, "DebugLevel");
    }

    GHashTableIter iter;
    const char *name;
    /*char *value; - already declared */
    init_map_string_iter(&iter, settings);
    while (next_map_string_iter(&iter, &name, &value))
    {
        error_msg("Unrecognized variable '%s' in '%s'", name, conf_filename);
    }
}

static const char *get_abrt_conf_file_name(void)
{
    const char *const abrt_conf = getenv("ABRT_CONF_FILE_NAME");
    return abrt_conf == NULL ? ABRT_CONF : abrt_conf;
}

int load_abrt_conf()
{
    free_abrt_conf_data();

    const char *const abrt_conf = get_abrt_conf_file_name();
    map_string_t *settings = new_map_string();
    if (!load_abrt_conf_file(abrt_conf, settings))
        perror_msg("Can't load '%s'", abrt_conf);

    ParseCommon(settings, abrt_conf);
    free_map_string(settings);

    return 0;
}

static const char *const *get_conf_directories(void)
{
    static const char *base_directories[3];

    const char *d = getenv("ABRT_DEFAULT_CONF_DIR");
    const char *c = getenv("ABRT_CONF_DIR");

    base_directories[0] = d != NULL ? d : DEFAULT_CONF_DIR;
    base_directories[1] = c != NULL ? d : CONF_DIR;
    base_directories[2] = NULL;

    return base_directories;
}

int load_abrt_conf_file(const char *file, map_string_t *settings)
{
    const char *const *conf_directories = get_conf_directories();
    return load_conf_file_from_dirs(file, conf_directories, settings, /*skip key w/o values:*/ false);
}

int load_abrt_plugin_conf_file(const char *file, map_string_t *settings)
{
    static const char *const base_directories[] = { DEFAULT_PLUGINS_CONF_DIR, PLUGINS_CONF_DIR, NULL };

    return load_conf_file_from_dirs(file, base_directories, settings, /*skip key w/o values:*/ false);
}

int save_abrt_conf_file(const char *file, map_string_t *settings)
{
    char *path = concat_path_file(CONF_DIR, file);
    int retval = save_conf_file(path, settings);
    free(path);
    return retval;
}

int save_abrt_plugin_conf_file(const char *file, map_string_t *settings)
{
    char *path = concat_path_file(PLUGINS_CONF_DIR, file);
    int retval = save_conf_file(path, settings);
    free(path);
    return retval;
}
