Blame src/lib/event_config.c

Packit 4f15d5
/*
Packit 4f15d5
    Copyright (C) 2011  ABRT Team
Packit 4f15d5
    Copyright (C) 2011  RedHat inc.
Packit 4f15d5
Packit 4f15d5
    This program is free software; you can redistribute it and/or modify
Packit 4f15d5
    it under the terms of the GNU General Public License as published by
Packit 4f15d5
    the Free Software Foundation; either version 2 of the License, or
Packit 4f15d5
    (at your option) any later version.
Packit 4f15d5
Packit 4f15d5
    This program is distributed in the hope that it will be useful,
Packit 4f15d5
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 4f15d5
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 4f15d5
    GNU General Public License for more details.
Packit 4f15d5
Packit 4f15d5
    You should have received a copy of the GNU General Public License along
Packit 4f15d5
    with this program; if not, write to the Free Software Foundation, Inc.,
Packit 4f15d5
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 4f15d5
*/
Packit 4f15d5
Packit 4f15d5
#include "internal_libreport.h"
Packit 4f15d5
Packit 4f15d5
GHashTable *g_event_config_list;
Packit 4f15d5
static GHashTable *g_event_config_symlinks;
Packit 4f15d5
Packit 4f15d5
invalid_option_t *new_invalid_option(void)
Packit 4f15d5
{
Packit 4f15d5
    return xzalloc(sizeof(invalid_option_t));
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
event_option_t *new_event_option(void)
Packit 4f15d5
{
Packit 4f15d5
    return xzalloc(sizeof(event_option_t));
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
event_config_t *new_event_config(const char *name)
Packit 4f15d5
{
Packit 4f15d5
    event_config_t *e = xzalloc(sizeof(event_config_t));
Packit 4f15d5
    e->info = new_config_info(name);
Packit 4f15d5
    return e;
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
config_item_info_t *ec_get_config_info(event_config_t * ec)
Packit 4f15d5
{
Packit 4f15d5
    return ec->info;
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
void ec_set_screen_name(event_config_t *ec, const char *screen_name)
Packit 4f15d5
{
Packit 4f15d5
    ci_set_screen_name(ec->info, screen_name);
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
const char *ec_get_screen_name(event_config_t *ec)
Packit 4f15d5
{
Packit 4f15d5
    return ci_get_screen_name(ec->info);
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
const char *ec_get_description(event_config_t *ec)
Packit 4f15d5
{
Packit 4f15d5
    return ci_get_description(ec->info);
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
void ec_set_description(event_config_t *ec, const char *description)
Packit 4f15d5
{
Packit 4f15d5
    ci_set_description(ec->info, description);
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
const char *ec_get_name(event_config_t *ec)
Packit 4f15d5
{
Packit 4f15d5
    return ci_get_name(ec->info);
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
const char *ec_get_long_desc(event_config_t *ec)
Packit 4f15d5
{
Packit 4f15d5
    return ci_get_long_desc(ec->info);
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
void ec_set_long_desc(event_config_t *ec, const char *long_descr)
Packit 4f15d5
{
Packit 4f15d5
    ci_set_long_desc(ec->info, long_descr);
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
bool ec_is_configurable(event_config_t* ec)
Packit 4f15d5
{
Packit 4f15d5
    return g_list_length(ec->options) > 0;
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
void ec_print(event_config_t *ec)
Packit 4f15d5
{
Packit 4f15d5
    printf("%s\n\t%s\n\t%s\n",
Packit 4f15d5
        ec_get_name(ec),
Packit 4f15d5
        ec_get_screen_name(ec),
Packit 4f15d5
        ec_get_description(ec)
Packit 4f15d5
        );
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
bool ec_restricted_access_enabled(event_config_t *ec)
Packit 4f15d5
{
Packit 4f15d5
    if (!ec->ec_supports_restricted_access)
Packit 4f15d5
    {
Packit 4f15d5
        if (ec->ec_restricted_access_option != NULL)
Packit 4f15d5
            log_warning("Event '%s' does not support restricted access but has the option", ec_get_name(ec));
Packit 4f15d5
Packit 4f15d5
        return false;
Packit 4f15d5
    }
Packit 4f15d5
Packit 4f15d5
    if (ec->ec_restricted_access_option == NULL)
Packit 4f15d5
    {
Packit 4f15d5
        log_debug("Event '%s' supports restricted access but is missing the option", ec_get_name(ec));
Packit 4f15d5
        return false;
Packit 4f15d5
    }
Packit 4f15d5
Packit 4f15d5
    event_option_t *eo = get_event_option_from_list(ec->ec_restricted_access_option, ec->options);
Packit 4f15d5
    if (eo == NULL)
Packit 4f15d5
    {
Packit 4f15d5
        log_warning("Event '%s' supports restricted access but the option is not defined", ec_get_name(ec));
Packit 4f15d5
        return false;
Packit 4f15d5
    }
Packit 4f15d5
Packit 4f15d5
    if (eo->eo_type != OPTION_TYPE_BOOL)
Packit 4f15d5
    {
Packit 4f15d5
        log_warning("Restricted option '%s' of Event '%s' is not of 'bool' type",
Packit 4f15d5
                    ec->ec_restricted_access_option, ec_get_name(ec));
Packit 4f15d5
        return false;
Packit 4f15d5
    }
Packit 4f15d5
Packit 4f15d5
    return eo->eo_value != NULL && string_to_bool(eo->eo_value);
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
void free_invalid_options(invalid_option_t *p)
Packit 4f15d5
{
Packit 4f15d5
    if (!p)
Packit 4f15d5
        return;
Packit 4f15d5
    free(p->invopt_name);
Packit 4f15d5
    free(p->invopt_error);
Packit 4f15d5
    free(p);
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
void free_event_option(event_option_t *p)
Packit 4f15d5
{
Packit 4f15d5
    if (!p)
Packit 4f15d5
        return;
Packit 4f15d5
    free(p->eo_name);
Packit 4f15d5
    free(p->eo_value);
Packit 4f15d5
    free(p->eo_label);
Packit 4f15d5
    free(p->eo_note_html);
Packit 4f15d5
    //free(p->eo_description);
Packit 4f15d5
    //free(p->eo_allowed_value);
Packit 4f15d5
    free(p);
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
void free_event_config(event_config_t *p)
Packit 4f15d5
{
Packit 4f15d5
    if (!p)
Packit 4f15d5
        return;
Packit 4f15d5
Packit 4f15d5
    free_config_info(p->info);
Packit 4f15d5
    free(p->ec_creates_items);
Packit 4f15d5
    free(p->ec_requires_items);
Packit 4f15d5
    free(p->ec_exclude_items_by_default);
Packit 4f15d5
    free(p->ec_include_items_by_default);
Packit 4f15d5
    free(p->ec_exclude_items_always);
Packit 4f15d5
    free(p->ec_restricted_access_option);
Packit 4f15d5
    g_list_free_full(p->ec_imported_event_names, free);
Packit 4f15d5
    g_list_free_full(p->options, (GDestroyNotify)free_event_option);
Packit 4f15d5
Packit 4f15d5
    free(p);
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
Packit 4f15d5
static int cmp_event_option_name_with_string(gconstpointer a, gconstpointer b)
Packit 4f15d5
{
Packit 4f15d5
    const event_option_t *evopt = a;
Packit 4f15d5
    return !evopt->eo_name || strcmp(evopt->eo_name, (char *)b) != 0;
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
event_option_t *get_event_option_from_list(const char *name, GList *options)
Packit 4f15d5
{
Packit 4f15d5
    GList *elem = g_list_find_custom(options, name, &cmp_event_option_name_with_string);
Packit 4f15d5
    if (elem)
Packit 4f15d5
        return (event_option_t *)elem->data;
Packit 4f15d5
    return NULL;
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
static void load_config_files(const char *dir_path)
Packit 4f15d5
{
Packit 4f15d5
    GList *conf_files = get_file_list(dir_path, "conf");
Packit 4f15d5
    while (conf_files != NULL)
Packit 4f15d5
    {
Packit 4f15d5
        file_obj_t *file = (file_obj_t *)conf_files->data;
Packit 4f15d5
        char *fullpath = file->fullpath;
Packit 4f15d5
        char *filename = file->filename;
Packit 4f15d5
Packit 4f15d5
        event_config_t *event_config = get_event_config(filename);
Packit 4f15d5
        bool new_config = (!event_config);
Packit 4f15d5
        if (new_config)
Packit 4f15d5
            event_config = new_event_config(filename);
Packit 4f15d5
Packit 4f15d5
        map_string_t *keys_and_values = new_map_string();
Packit 4f15d5
Packit 4f15d5
        load_conf_file(fullpath, keys_and_values, /*skipKeysWithoutValue:*/ false);
Packit 4f15d5
Packit 4f15d5
        /* Insert or replace every key/value from keys_and_values to event_config->option */
Packit 4f15d5
        map_string_iter_t iter;
Packit 4f15d5
        const char *name;
Packit 4f15d5
        const char *value;
Packit 4f15d5
        init_map_string_iter(&iter, keys_and_values);
Packit 4f15d5
        while (next_map_string_iter(&iter, &name, &value))
Packit 4f15d5
        {
Packit 4f15d5
            event_option_t *opt;
Packit 4f15d5
            GList *elem = g_list_find_custom(event_config->options, name,
Packit 4f15d5
                                            cmp_event_option_name_with_string);
Packit 4f15d5
            if (elem)
Packit 4f15d5
            {
Packit 4f15d5
                opt = elem->data;
Packit 4f15d5
                // log_warning("conf: replacing '%s' value:'%s'->'%s'", name, opt->value, value);
Packit 4f15d5
                free(opt->eo_value);
Packit 4f15d5
            }
Packit 4f15d5
            else
Packit 4f15d5
            {
Packit 4f15d5
                // log_warning("conf: new value %s='%s'", name, value);
Packit 4f15d5
                opt = new_event_option();
Packit 4f15d5
                opt->eo_name = xstrdup(name);
Packit 4f15d5
            }
Packit 4f15d5
            opt->eo_value = xstrdup(value);
Packit 4f15d5
            if (!elem)
Packit 4f15d5
                event_config->options = g_list_append(event_config->options, opt);
Packit 4f15d5
        }
Packit 4f15d5
Packit 4f15d5
        free_map_string(keys_and_values);
Packit 4f15d5
Packit 4f15d5
        if (new_config)
Packit 4f15d5
            g_hash_table_replace(g_event_config_list, xstrdup(ec_get_name(event_config)), event_config);
Packit 4f15d5
Packit 4f15d5
        free_file_obj(file);
Packit 4f15d5
        conf_files = g_list_delete_link(conf_files, conf_files);
Packit 4f15d5
    }
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
/* (Re)loads data from /etc/abrt/events/foo.{xml,conf} and $XDG_CACHE_HOME/abrt/events/foo.conf */
Packit 4f15d5
GHashTable *load_event_config_data(void)
Packit 4f15d5
{
Packit 4f15d5
    free_event_config_data();
Packit 4f15d5
Packit 4f15d5
    if (!g_event_config_list)
Packit 4f15d5
        g_event_config_list = g_hash_table_new_full(
Packit 4f15d5
                /*hash_func*/ g_str_hash,
Packit 4f15d5
                /*key_equal_func:*/ g_str_equal,
Packit 4f15d5
                /*key_destroy_func:*/ free,
Packit 4f15d5
                /*value_destroy_func:*/ (GDestroyNotify) free_event_config
Packit 4f15d5
        );
Packit 4f15d5
    if (!g_event_config_symlinks)
Packit 4f15d5
        g_event_config_symlinks = g_hash_table_new_full(
Packit 4f15d5
                /*hash_func*/ g_str_hash,
Packit 4f15d5
                /*key_equal_func:*/ g_str_equal,
Packit 4f15d5
                /*key_destroy_func:*/ free,
Packit 4f15d5
                /*value_destroy_func:*/ free
Packit 4f15d5
        );
Packit 4f15d5
Packit 4f15d5
    GList *event_files = get_file_list(EVENTS_DIR, "xml");
Packit 4f15d5
    while (event_files)
Packit 4f15d5
    {
Packit 4f15d5
        file_obj_t *file = (file_obj_t *)event_files->data;
Packit 4f15d5
Packit 4f15d5
        event_config_t *event_config = get_event_config(file->filename);
Packit 4f15d5
        bool new_config = (!event_config);
Packit 4f15d5
        if (new_config)
Packit 4f15d5
           event_config = new_event_config(file->filename);
Packit 4f15d5
Packit 4f15d5
        load_event_description_from_file(event_config, file->fullpath);
Packit 4f15d5
Packit 4f15d5
        if (new_config)
Packit 4f15d5
            g_hash_table_replace(g_event_config_list, xstrdup(ec_get_name(event_config)), event_config);
Packit 4f15d5
Packit 4f15d5
        free_file_obj(file);
Packit 4f15d5
        event_files = g_list_delete_link(event_files, event_files);
Packit 4f15d5
    }
Packit 4f15d5
Packit 4f15d5
    /* EVENTS_DIR      -> /usr/share/libreport/events/$EVENT_NAME.xml
Packit 4f15d5
     *   - event xml definition files
Packit 4f15d5
     *
Packit 4f15d5
     * EVENTS_CONF_DIR -> /etc/libreport/events/$EVENT_NAME.conf
Packit 4f15d5
     *   - default values for xml definitions
Packit 4f15d5
     *
Packit 4f15d5
     * https://fedorahosted.org/abrt/wiki/AbrtConfiguration#Adjustingpluginconfiguration
Packit 4f15d5
     */
Packit 4f15d5
    load_config_files(EVENTS_CONF_DIR);
Packit 4f15d5
Packit 4f15d5
    char *cachedir;
Packit 4f15d5
    cachedir = concat_path_file(g_get_user_cache_dir(), "abrt/events");
Packit 4f15d5
    load_config_files(cachedir);
Packit 4f15d5
    free(cachedir);
Packit 4f15d5
Packit 4f15d5
    return g_event_config_list;
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
/* Frees all loaded data */
Packit 4f15d5
void free_event_config_data(void)
Packit 4f15d5
{
Packit 4f15d5
    if (g_event_config_list)
Packit 4f15d5
    {
Packit 4f15d5
        g_hash_table_destroy(g_event_config_list);
Packit 4f15d5
        g_event_config_list = NULL;
Packit 4f15d5
    }
Packit 4f15d5
    if (g_event_config_symlinks)
Packit 4f15d5
    {
Packit 4f15d5
        g_hash_table_destroy(g_event_config_symlinks);
Packit 4f15d5
        g_event_config_symlinks = NULL;
Packit 4f15d5
    }
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
event_config_t *get_event_config(const char *name)
Packit 4f15d5
{
Packit 4f15d5
    if (!g_event_config_list)
Packit 4f15d5
        return NULL;
Packit 4f15d5
    if (g_event_config_symlinks)
Packit 4f15d5
    {
Packit 4f15d5
        char *link = g_hash_table_lookup(g_event_config_symlinks, name);
Packit 4f15d5
        if (link)
Packit 4f15d5
            name = link;
Packit 4f15d5
    }
Packit 4f15d5
    return g_hash_table_lookup(g_event_config_list, name);
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
GList *export_event_config(const char *event_name)
Packit 4f15d5
{
Packit 4f15d5
    GList *env_list = NULL;
Packit 4f15d5
Packit 4f15d5
    event_config_t *config = get_event_config(event_name);
Packit 4f15d5
    if (config)
Packit 4f15d5
    {
Packit 4f15d5
        GList *imported = config->ec_imported_event_names;
Packit 4f15d5
        while (imported)
Packit 4f15d5
        {
Packit 4f15d5
            GList *exported = export_event_config(/*Event name*/imported->data);
Packit 4f15d5
            while (exported)
Packit 4f15d5
            {
Packit 4f15d5
                if (!g_list_find_custom(env_list, exported->data, (GCompareFunc)strcmp))
Packit 4f15d5
                    /* It is not necessary to make a copy of opt->eo_name */
Packit 4f15d5
                    /* since its memory is owned by event_option_t and it */
Packit 4f15d5
                    /* has global scope */
Packit 4f15d5
                    env_list = g_list_prepend(env_list, exported->data);
Packit 4f15d5
Packit 4f15d5
                exported = g_list_remove_link(exported, exported);
Packit 4f15d5
            }
Packit 4f15d5
Packit 4f15d5
            imported = g_list_next(imported);
Packit 4f15d5
        }
Packit 4f15d5
Packit 4f15d5
        GList *lopt;
Packit 4f15d5
        for (lopt = config->options; lopt; lopt = lopt->next)
Packit 4f15d5
        {
Packit 4f15d5
            event_option_t *opt = lopt->data;
Packit 4f15d5
            if (!opt->eo_value)
Packit 4f15d5
                continue;
Packit 4f15d5
Packit 4f15d5
            log_debug("Exporting '%s=%s'", opt->eo_name, opt->eo_value);
Packit 4f15d5
Packit 4f15d5
            /* Add the exported key only if it is not in the list */
Packit 4f15d5
            if (!g_list_find_custom(env_list, opt->eo_name, (GCompareFunc)strcmp))
Packit 4f15d5
                /* It is not necessary to make a copy of opt->eo_name */
Packit 4f15d5
                /* since its memory is owned by opt and it has global scope */
Packit 4f15d5
                env_list = g_list_prepend(env_list, opt->eo_name);
Packit 4f15d5
Packit 4f15d5
            /* setenv() makes copies of strings */
Packit 4f15d5
            xsetenv(opt->eo_name, opt->eo_value);
Packit 4f15d5
        }
Packit 4f15d5
    }
Packit 4f15d5
Packit 4f15d5
    return env_list;
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
/*
Packit 4f15d5
 * Goes through given list and calls unsetnev() for each list item.
Packit 4f15d5
 *
Packit 4f15d5
 * Accepts a list of 'const char *' type items which contains names of exported
Packit 4f15d5
 * environment variables and which was returned from export_event_config()
Packit 4f15d5
 * function.
Packit 4f15d5
 */
Packit 4f15d5
void unexport_event_config(GList *env_list)
Packit 4f15d5
{
Packit 4f15d5
    while (env_list)
Packit 4f15d5
    {
Packit 4f15d5
        char *var_val = env_list->data;
Packit 4f15d5
        log_debug("Unexporting '%s'", var_val);
Packit 4f15d5
        safe_unsetenv(var_val);
Packit 4f15d5
Packit 4f15d5
        /* The list doesn't own memory of values: see export_event_config() */
Packit 4f15d5
        env_list = g_list_remove(env_list, var_val);
Packit 4f15d5
    }
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
/* return NULL if successful otherwise appropriate error message */
Packit 4f15d5
static char *validate_event_option(event_option_t *opt)
Packit 4f15d5
{
Packit 4f15d5
    if (!opt->eo_allow_empty && (!opt->eo_value || !opt->eo_value[0]))
Packit 4f15d5
        return xstrdup(_("Missing mandatory value"));
Packit 4f15d5
Packit 4f15d5
    /* if value is NULL and allow-empty yes than it doesn't make sence to check it */
Packit 4f15d5
    if (!opt->eo_value)
Packit 4f15d5
        return NULL;
Packit 4f15d5
Packit 4f15d5
    const gchar *s = NULL;
Packit 4f15d5
    if (!g_utf8_validate(opt->eo_value, -1, &s))
Packit 4f15d5
            return xasprintf(_("Invalid utf8 character '%c'"), *s);
Packit 4f15d5
Packit 4f15d5
    switch (opt->eo_type) {
Packit 4f15d5
    case OPTION_TYPE_TEXT:
Packit 4f15d5
    case OPTION_TYPE_PASSWORD:
Packit 4f15d5
        break;
Packit 4f15d5
    case OPTION_TYPE_NUMBER:
Packit 4f15d5
    {
Packit 4f15d5
        char *endptr;
Packit 4f15d5
        errno = 0;
Packit 4f15d5
        long r = strtol(opt->eo_value, &endptr, 10);
Packit 4f15d5
        (void) r;
Packit 4f15d5
        if (errno != 0 || endptr == opt->eo_value || *endptr != '\0')
Packit 4f15d5
            return xasprintf(_("Invalid number '%s'"), opt->eo_value);
Packit 4f15d5
Packit 4f15d5
        break;
Packit 4f15d5
    }
Packit 4f15d5
    case OPTION_TYPE_BOOL:
Packit 4f15d5
        /* note: should match strings which string_to_bool accepts */
Packit 4f15d5
        if (strcasecmp(opt->eo_value, "yes") != 0
Packit 4f15d5
         && strcasecmp(opt->eo_value, "no") != 0
Packit 4f15d5
         && strcasecmp(opt->eo_value, "on") != 0
Packit 4f15d5
         && strcasecmp(opt->eo_value, "off") != 0
Packit 4f15d5
         && strcasecmp(opt->eo_value, "true") != 0
Packit 4f15d5
         && strcasecmp(opt->eo_value, "false") != 0
Packit 4f15d5
         && strcmp(opt->eo_value, "1") != 0
Packit 4f15d5
         && strcmp(opt->eo_value, "0") != 0
Packit 4f15d5
        ) {
Packit 4f15d5
            return xasprintf(_("Invalid boolean value '%s'"), opt->eo_value);
Packit 4f15d5
        }
Packit 4f15d5
        break;
Packit 4f15d5
    case OPTION_TYPE_HINT_HTML:
Packit 4f15d5
        return NULL;
Packit 4f15d5
    default:
Packit 4f15d5
        return xstrdup(_("Unsupported option type"));
Packit 4f15d5
    };
Packit 4f15d5
Packit 4f15d5
    return NULL;
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
GList *get_options_with_err_msg(const char *event_name)
Packit 4f15d5
{
Packit 4f15d5
    INITIALIZE_LIBREPORT();
Packit 4f15d5
Packit 4f15d5
    event_config_t *config = get_event_config(event_name);
Packit 4f15d5
    if (!config)
Packit 4f15d5
        return NULL;
Packit 4f15d5
Packit 4f15d5
    GList *iter, *err_list = NULL;
Packit 4f15d5
Packit 4f15d5
    for (iter = config->options; iter; iter = iter->next)
Packit 4f15d5
    {
Packit 4f15d5
        event_option_t *opt = (event_option_t *)iter->data;
Packit 4f15d5
        char *err = validate_event_option(opt);
Packit 4f15d5
        if (err)
Packit 4f15d5
        {
Packit 4f15d5
            invalid_option_t *inv_opt = new_invalid_option();
Packit 4f15d5
            inv_opt->invopt_name = xstrdup(opt->eo_name);
Packit 4f15d5
            inv_opt->invopt_error = xstrdup(err);
Packit 4f15d5
            err_list = g_list_prepend(err_list, inv_opt);
Packit 4f15d5
Packit 4f15d5
            free(err);
Packit 4f15d5
        }
Packit 4f15d5
    }
Packit 4f15d5
Packit 4f15d5
    if (err_list != NULL)
Packit 4f15d5
        return g_list_reverse(err_list);
Packit 4f15d5
Packit 4f15d5
    return NULL;
Packit 4f15d5
}
Packit 4f15d5
Packit 4f15d5
/*
Packit 4f15d5
 * This function checks if a value of problem's backtrace rating is acceptable
Packit 4f15d5
 * for event according to event's required rating value.
Packit 4f15d5
 *
Packit 4f15d5
 * The solved problem seems to be pretty straightforward but there are some
Packit 4f15d5
 * pitfalls.
Packit 4f15d5
 *
Packit 4f15d5
 * 1. Is rating acceptable if event doesn't have configuration?
Packit 4f15d5
 * 2. Is rating acceptable if problem's data doesn't contains rating value?
Packit 4f15d5
 * 3. Is rating acceptable if rating value is not a number?
Packit 4f15d5
 * 4. What message show to user if there is a concern about usability?
Packit 4f15d5
 */
Packit 4f15d5
bool check_problem_rating_usability(const event_config_t *cfg,
Packit 4f15d5
                                    problem_data_t *pd,
Packit 4f15d5
                                    char **description,
Packit 4f15d5
                                    char **detail)
Packit 4f15d5
{
Packit 4f15d5
    INITIALIZE_LIBREPORT();
Packit 4f15d5
Packit 4f15d5
    char *tmp_desc = NULL;
Packit 4f15d5
    char *tmp_detail = NULL;
Packit 4f15d5
    bool result = true;
Packit 4f15d5
Packit 4f15d5
    if (!cfg)
Packit 4f15d5
        goto finish;
Packit 4f15d5
Packit 4f15d5
    const char *rating_str = problem_data_get_content_or_NULL(pd, FILENAME_RATING);
Packit 4f15d5
Packit 4f15d5
    if (!rating_str)
Packit 4f15d5
        goto finish;
Packit 4f15d5
Packit 4f15d5
    /* just to be sure */
Packit 4f15d5
    result = false;
Packit 4f15d5
Packit 4f15d5
    const long minimal_rating = cfg->ec_minimal_rating;
Packit 4f15d5
    char *endptr;
Packit 4f15d5
    errno = 0;
Packit 4f15d5
    const long rating = strtol(rating_str, &endptr, 10);
Packit 4f15d5
    if (errno != 0 || endptr == rating_str || *endptr != '\0')
Packit 4f15d5
    {
Packit 4f15d5
        tmp_desc = xasprintf(
Packit 4f15d5
                _("The problem cannot be reported due to an invalid data. " \
Packit 4f15d5
                  "'%s' file does not contain a number."),
Packit 4f15d5
                FILENAME_RATING);
Packit 4f15d5
Packit 4f15d5
        tmp_detail = xstrdup(_("Please report this problem to ABRT project developers."));
Packit 4f15d5
Packit 4f15d5
        result = false;
Packit 4f15d5
    }
Packit 4f15d5
    else if (rating == minimal_rating) /* bt is usable, but not complete, so show a warning */
Packit 4f15d5
    {
Packit 4f15d5
        tmp_desc = xstrdup(_("The backtrace is incomplete, please make sure you provide the steps to reproduce."));
Packit 4f15d5
        tmp_detail = xstrdup(_("The backtrace probably can't help developer to diagnose the bug."));
Packit 4f15d5
Packit 4f15d5
        result = true;
Packit 4f15d5
    }
Packit 4f15d5
    else if (rating < minimal_rating)
Packit 4f15d5
    {
Packit 4f15d5
        tmp_desc = xstrdup(_("Reporting disabled because the backtrace is unusable."));
Packit 4f15d5
Packit 4f15d5
        const char *package = problem_data_get_content_or_NULL(pd, FILENAME_PACKAGE);
Packit 4f15d5
        if (package && package[0])
Packit 4f15d5
            tmp_detail = xasprintf(_("Please try to install debuginfo manually using the command: \"debuginfo-install %s\" and try again."), package);
Packit 4f15d5
        else
Packit 4f15d5
            tmp_detail = xstrdup(_("A proper debuginfo is probably missing or the coredump is corrupted."));
Packit 4f15d5
Packit 4f15d5
        result = false;
Packit 4f15d5
    }
Packit 4f15d5
    else /* rating > minimal_rating */
Packit 4f15d5
        result = true;
Packit 4f15d5
Packit 4f15d5
finish:
Packit 4f15d5
    if (description)
Packit 4f15d5
        *description = tmp_desc;
Packit 4f15d5
    else
Packit 4f15d5
        free(tmp_desc);
Packit 4f15d5
Packit 4f15d5
    if (detail)
Packit 4f15d5
        *detail = tmp_detail;
Packit 4f15d5
    else
Packit 4f15d5
        free(tmp_detail);
Packit 4f15d5
Packit 4f15d5
    return result;
Packit 4f15d5
}