Blame src/report-newt/report-newt.c

Packit Service 779887
/*
Packit Service 779887
    Copyright (C) 2011  ABRT Team
Packit Service 779887
    Copyright (C) 2011  RedHat inc.
Packit Service 779887
Packit Service 779887
    This program is free software; you can redistribute it and/or modify
Packit Service 779887
    it under the terms of the GNU General Public License as published by
Packit Service 779887
    the Free Software Foundation; either version 2 of the License, or
Packit Service 779887
    (at your option) any later version.
Packit Service 779887
Packit Service 779887
    This program is distributed in the hope that it will be useful,
Packit Service 779887
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 779887
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 779887
    GNU General Public License for more details.
Packit Service 779887
Packit Service 779887
    You should have received a copy of the GNU General Public License along
Packit Service 779887
    with this program; if not, write to the Free Software Foundation, Inc.,
Packit Service 779887
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit Service 779887
*/
Packit Service 779887
Packit Service 779887
#include <newt.h>
Packit Service 779887
#include "internal_libreport.h"
Packit Service 779887
#if HAVE_LOCALE_H
Packit Service 779887
# include <locale.h>
Packit Service 779887
#endif
Packit Service 779887
Packit Service 779887
struct reporter {
Packit Service 779887
    char *name;
Packit Service 779887
    event_config_t *config;
Packit Service 779887
    bool selected;
Packit Service 779887
};
Packit Service 779887
Packit Service 779887
static GArray *get_available_reporters(char *events)
Packit Service 779887
{
Packit Service 779887
    GArray *reporters = g_array_new(FALSE, FALSE, sizeof (struct reporter));;
Packit Service 779887
    struct reporter r;
Packit Service 779887
    char *s;
Packit Service 779887
Packit Service 779887
    for (s = events; (events = strtok(s, "\n")); s = NULL)
Packit Service 779887
    {
Packit Service 779887
        r.name = events;
Packit Service 779887
        r.config = get_event_config(events);
Packit Service 779887
        r.selected = 0;
Packit Service 779887
        g_array_append_val(reporters, r);
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    return reporters;
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
static int select_reporters(GArray *reporters)
Packit Service 779887
{
Packit Service 779887
    newtGrid grid, cgrid, bgrid;
Packit Service 779887
    newtComponent *checkboxes, text, form, button_ok, button_cancel;
Packit Service 779887
    int i, selected;
Packit Service 779887
Packit Service 779887
    text = newtTextboxReflowed(0, 0, _("How would you like to report the problem?"), 35, 5, 5, 0);
Packit Service 779887
Packit Service 779887
    checkboxes = g_alloca(sizeof (newtComponent) * reporters->len);
Packit Service 779887
    cgrid = newtCreateGrid(1, reporters->len);
Packit Service 779887
    for (i = 0; i < reporters->len; i++)
Packit Service 779887
    {
Packit Service 779887
        struct reporter *r = &g_array_index(reporters, struct reporter, i);
Packit Service 779887
Packit Service 779887
        checkboxes[i] = newtCheckbox(20, i + 1, r->config && ec_get_screen_name(r->config) ?
Packit Service 779887
                ec_get_screen_name(r->config) : r->name, 0, NULL, NULL);
Packit Service 779887
        newtGridSetField(cgrid, 0, i, NEWT_GRID_COMPONENT, checkboxes[i], 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    bgrid = newtButtonBar(_("Ok"), &button_ok, _("Cancel"), &button_cancel, NULL);
Packit Service 779887
Packit Service 779887
    grid = newtGridBasicWindow(text, cgrid, bgrid);
Packit Service 779887
    newtGridWrappedWindow(grid, NULL);
Packit Service 779887
Packit Service 779887
    form = newtForm (NULL, NULL, 0);
Packit Service 779887
    newtGridAddComponentsToForm(grid, form, 1);
Packit Service 779887
Packit Service 779887
    selected = 0;
Packit Service 779887
    if (newtRunForm(form) == button_ok)
Packit Service 779887
    {
Packit Service 779887
        for (i = 0; i < reporters->len; i++)
Packit Service 779887
            if (newtCheckboxGetValue(checkboxes[i]) == '*')
Packit Service 779887
            {
Packit Service 779887
                g_array_index(reporters, struct reporter, i).selected = 1;
Packit Service 779887
                selected++;
Packit Service 779887
            }
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    newtFormDestroy(form);
Packit Service 779887
    newtGridFree(grid, 1);
Packit Service 779887
    newtPopWindow();
Packit Service 779887
Packit Service 779887
    return selected;
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
static int configure_reporter(struct reporter *r, bool skip_if_valid)
Packit Service 779887
{
Packit Service 779887
    GList *error_list, *option;
Packit Service 779887
    event_option_t *opt;
Packit Service 779887
    bool first = true, cancel = false;
Packit Service 779887
    int num_opts, i;
Packit Service 779887
    newtComponent text, *options, button_ok, button_cancel, form;
Packit Service 779887
    newtGrid grid, ogrid, bgrid;
Packit Service 779887
Packit Service 779887
    while ((error_list = get_options_with_err_msg(r->name)) ||
Packit Service 779887
            (!skip_if_valid && first && r->config))
Packit Service 779887
    {
Packit Service 779887
        text = newtTextboxReflowed(0, 0, ec_get_screen_name(r->config) ?
Packit Service 779887
                xstrdup(ec_get_screen_name(r->config)) : r->name, 35, 5, 5, 0);
Packit Service 779887
Packit Service 779887
        num_opts = g_list_length(r->config->options);
Packit Service 779887
        options = xmalloc(sizeof (newtComponent) * num_opts);
Packit Service 779887
        ogrid = newtCreateGrid(2, num_opts);
Packit Service 779887
Packit Service 779887
        for (option = r->config->options, i = 0; option && i < num_opts;
Packit Service 779887
                option = g_list_next(option), i++)
Packit Service 779887
        {
Packit Service 779887
            opt = (event_option_t *)option->data;
Packit Service 779887
            switch (opt->eo_type)
Packit Service 779887
            {
Packit Service 779887
                case OPTION_TYPE_TEXT:
Packit Service 779887
                case OPTION_TYPE_NUMBER:
Packit Service 779887
                    options[i] = newtEntry(0, 0, opt->eo_value, 30, NULL,
Packit Service 779887
                            NEWT_FLAG_SCROLL);
Packit Service 779887
                    break;
Packit Service 779887
                case OPTION_TYPE_PASSWORD:
Packit Service 779887
                    options[i] = newtEntry(0, 0, opt->eo_value, 30, NULL,
Packit Service 779887
                            NEWT_FLAG_SCROLL | NEWT_FLAG_PASSWORD);
Packit Service 779887
                    break;
Packit Service 779887
                case OPTION_TYPE_BOOL:
Packit Service 779887
                    options[i] = newtCheckbox(0, 0, "", opt->eo_value &&
Packit Service 779887
                            !strcmp(opt->eo_value, "yes") ? '*' : ' ', NULL, NULL);
Packit Service 779887
                    break;
Packit Service 779887
                default: /* TODO? */
Packit Service 779887
                    options[i] = NULL;
Packit Service 779887
                    break;
Packit Service 779887
            }
Packit Service 779887
Packit Service 779887
            newtGridSetField(ogrid, 0, i, NEWT_GRID_COMPONENT,
Packit Service 779887
                    newtLabel(0, 0, opt->eo_label ? opt->eo_label : opt->eo_name),
Packit Service 779887
                    0, 0, 1, 0, NEWT_ANCHOR_LEFT, 0);
Packit Service 779887
            if (options[i])
Packit Service 779887
                newtGridSetField(ogrid, 1, i, NEWT_GRID_COMPONENT, options[i], 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0);
Packit Service 779887
        }
Packit Service 779887
        assert(i == num_opts);
Packit Service 779887
Packit Service 779887
        bgrid = newtButtonBar(_("Ok"), &button_ok, _("Cancel"), &button_cancel, NULL);
Packit Service 779887
Packit Service 779887
        grid = newtGridBasicWindow(text, ogrid, bgrid);
Packit Service 779887
        newtGridWrappedWindow(grid, NULL);
Packit Service 779887
Packit Service 779887
        form = newtForm(NULL, NULL, 0);
Packit Service 779887
        newtGridAddComponentsToForm(grid, form, 1);
Packit Service 779887
Packit Service 779887
        if (!first && error_list)
Packit Service 779887
        {
Packit Service 779887
            GList *iter;
Packit Service 779887
            char buf[4096];
Packit Service 779887
Packit Service 779887
            /* Catenate the error messages */
Packit Service 779887
            buf[0] = '\0';
Packit Service 779887
            for (iter = error_list; iter; iter = iter->next)
Packit Service 779887
            {
Packit Service 779887
                invalid_option_t *inv_data = (invalid_option_t *)iter->data;
Packit Service 779887
                opt = get_event_option_from_list(inv_data->invopt_name, r->config->options);
Packit Service 779887
                snprintf(buf + strlen(buf), sizeof (buf) - strlen(buf), "%s: %s\n",
Packit Service 779887
                        opt->eo_label ? opt->eo_label : opt->eo_name, inv_data->invopt_error);
Packit Service 779887
            }
Packit Service 779887
Packit Service 779887
            newtWinMessage(_("Error"), _("Ok"), buf);
Packit Service 779887
        }
Packit Service 779887
Packit Service 779887
        if (newtRunForm(form) == button_ok)
Packit Service 779887
        {
Packit Service 779887
            for (option = r->config->options, i = 0; option && i < num_opts;
Packit Service 779887
                    option = g_list_next(option), i++)
Packit Service 779887
            {
Packit Service 779887
                opt = (event_option_t *)option->data;
Packit Service 779887
                switch (opt->eo_type)
Packit Service 779887
                {
Packit Service 779887
                    case OPTION_TYPE_TEXT:
Packit Service 779887
                    case OPTION_TYPE_NUMBER:
Packit Service 779887
                    case OPTION_TYPE_PASSWORD:
Packit Service 779887
                        free(opt->eo_value);
Packit Service 779887
                        opt->eo_value = strdup(newtEntryGetValue(options[i]));
Packit Service 779887
                        break;
Packit Service 779887
                    case OPTION_TYPE_BOOL:
Packit Service 779887
                        free(opt->eo_value);
Packit Service 779887
                        opt->eo_value = strdup(newtCheckboxGetValue(options[i]) == '*' ? "yes" : "no");
Packit Service 779887
                        break;
Packit Service 779887
                    default:
Packit Service 779887
                        break;
Packit Service 779887
                }
Packit Service 779887
            }
Packit Service 779887
        }
Packit Service 779887
        else
Packit Service 779887
            cancel = true;
Packit Service 779887
Packit Service 779887
        newtFormDestroy(form);
Packit Service 779887
        newtGridFree(grid, 1);
Packit Service 779887
        newtPopWindow();
Packit Service 779887
Packit Service 779887
        free(options);
Packit Service 779887
Packit Service 779887
        if (error_list)
Packit Service 779887
            g_list_free_full(error_list,(GDestroyNotify)free_invalid_options);
Packit Service 779887
        if (cancel)
Packit Service 779887
            break;
Packit Service 779887
        first = false;
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    return !error_list;
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
struct log {
Packit Service 779887
    newtComponent co;
Packit Service 779887
    char *text;
Packit Service 779887
};
Packit Service 779887
Packit Service 779887
static char *save_log_line(char *log_line, void *param)
Packit Service 779887
{
Packit Service 779887
    struct log *log = (struct log *)param;
Packit Service 779887
    char *new;
Packit Service 779887
    size_t len;
Packit Service 779887
Packit Service 779887
    if (log->text == NULL)
Packit Service 779887
    {
Packit Service 779887
        log->text = log_line;
Packit Service 779887
        newtTextboxSetText(log->co, log_line);
Packit Service 779887
    }
Packit Service 779887
    else
Packit Service 779887
    {
Packit Service 779887
        /* Append the log line */
Packit Service 779887
        len = strlen(log->text) + 1 + strlen(log_line) + 1;
Packit Service 779887
        new = xmalloc(len);
Packit Service 779887
        snprintf(new, len, "%s\n%s", log->text, log_line);
Packit Service 779887
        free(log->text);
Packit Service 779887
        free(log_line);
Packit Service 779887
        log->text = new;
Packit Service 779887
        newtTextboxSetText(log->co, new);
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    newtRefresh();
Packit Service 779887
Packit Service 779887
    return NULL;
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
static void run_reporter(const char *dump_dir_name, struct reporter *r)
Packit Service 779887
{
Packit Service 779887
    newtComponent text, form, button;
Packit Service 779887
    newtGrid grid, bgrid;
Packit Service 779887
    GList *env_list;
Packit Service 779887
    struct run_event_state *run_state;
Packit Service 779887
    struct log log;
Packit Service 779887
    int x;
Packit Service 779887
Packit Service 779887
    text = newtTextboxReflowed(0, 0, _("Reporting"), 35, 5, 5, 0);
Packit Service 779887
    log.co = newtTextbox(0, 0, 60, 11, NEWT_FLAG_WRAP | NEWT_FLAG_SCROLL);
Packit Service 779887
    log.text = NULL;
Packit Service 779887
    bgrid = newtButtonBar(_("Ok"), &button, NULL);
Packit Service 779887
    grid = newtGridSimpleWindow(text, log.co, bgrid);
Packit Service 779887
Packit Service 779887
    newtGridWrappedWindow(grid, NULL);
Packit Service 779887
Packit Service 779887
    form = newtForm (NULL, NULL, NEWT_FLAG_SCROLL);
Packit Service 779887
    newtFormAddComponents(form, text, log.co, button, NULL);
Packit Service 779887
Packit Service 779887
    newtDrawForm(form);
Packit Service 779887
Packit Service 779887
    run_state = new_run_event_state();
Packit Service 779887
    run_state->logging_callback = save_log_line;
Packit Service 779887
    run_state->logging_param = &log;
Packit Service 779887
Packit Service 779887
    /* Export overridden settings as environment variables */
Packit Service 779887
    env_list = export_event_config(r->name);
Packit Service 779887
Packit Service 779887
    save_log_line(xasprintf(_("--- Running %s ---"), r->name), &log;;
Packit Service 779887
Packit Service 779887
    x = run_event_on_dir_name(run_state, dump_dir_name, r->name);
Packit Service 779887
    if (x)
Packit Service 779887
        save_log_line(xasprintf("(exited with %d)", x), &log;;
Packit Service 779887
Packit Service 779887
    newtFormSetCurrent(form, button);
Packit Service 779887
    newtRunForm(form);
Packit Service 779887
Packit Service 779887
    unexport_event_config(env_list);
Packit Service 779887
    free_run_event_state(run_state);
Packit Service 779887
    free(log.text);
Packit Service 779887
Packit Service 779887
    newtFormDestroy(form);
Packit Service 779887
    newtGridFree(grid, 1);
Packit Service 779887
    newtPopWindow();
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
static void run_selected_reporters(const char *dump_dir_name, GArray *reporters)
Packit Service 779887
{
Packit Service 779887
    int i;
Packit Service 779887
Packit Service 779887
    for (i = 0; i < reporters->len; i++)
Packit Service 779887
    {
Packit Service 779887
        struct reporter *r = &g_array_index(reporters, struct reporter, i);
Packit Service 779887
Packit Service 779887
        if (!r->selected)
Packit Service 779887
            continue;
Packit Service 779887
Packit Service 779887
        if (!configure_reporter(r, true))
Packit Service 779887
            continue;
Packit Service 779887
Packit Service 779887
        run_reporter(dump_dir_name, r);
Packit Service 779887
    }
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
static int report(const char *dump_dir_name)
Packit Service 779887
{
Packit Service 779887
    GArray *reporters;
Packit Service 779887
    struct dump_dir *dd;
Packit Service 779887
    char *events_as_lines;
Packit Service 779887
Packit Service 779887
    if (!(dd = dd_opendir(dump_dir_name, 0)))
Packit Service 779887
        return -1;
Packit Service 779887
    events_as_lines = list_possible_events(dd, NULL, "report");
Packit Service 779887
Packit Service 779887
    char *not_reportable = dd_load_text_ext(dd, FILENAME_NOT_REPORTABLE, 0
Packit Service 779887
                                            | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE
Packit Service 779887
                                            | DD_FAIL_QUIETLY_ENOENT
Packit Service 779887
                                            | DD_FAIL_QUIETLY_EACCES);
Packit Service 779887
Packit Service 779887
    if (not_reportable)
Packit Service 779887
    {
Packit Service 779887
        char *reason = dd_load_text_ext(dd, FILENAME_REASON, 0
Packit Service 779887
                                        | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE);
Packit Service 779887
        char *t = xasprintf("%s %s",
Packit Service 779887
                            not_reportable,
Packit Service 779887
                            reason ? : _("(no description)"));
Packit Service 779887
Packit Service 779887
        newtWinMessage(_("Error"), _("Ok"), (char *)"%s", t);
Packit Service 779887
        free(t);
Packit Service 779887
        free(not_reportable);
Packit Service 779887
        free(reason);
Packit Service 779887
Packit Service 779887
        if (get_global_stop_on_not_reportable())
Packit Service 779887
        {
Packit Service 779887
            dd_close(dd);
Packit Service 779887
            return -1;
Packit Service 779887
        }
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    dd_close(dd);
Packit Service 779887
Packit Service 779887
    reporters = get_available_reporters(events_as_lines);
Packit Service 779887
Packit Service 779887
    if (reporters->len > 0)
Packit Service 779887
    {
Packit Service 779887
        if (select_reporters(reporters) > 0)
Packit Service 779887
            run_selected_reporters(dump_dir_name, reporters);
Packit Service 779887
    }
Packit Service 779887
    else
Packit Service 779887
        newtWinMessage(NULL, _("Ok"), _("No reporters available"));
Packit Service 779887
Packit Service 779887
    g_array_free(reporters, TRUE);
Packit Service 779887
    free(events_as_lines);
Packit Service 779887
Packit Service 779887
    return 0;
Packit Service 779887
}
Packit Service 779887
Packit Service 779887
int main(int argc, char **argv)
Packit Service 779887
{
Packit Service 779887
    char *dump_dir_name = NULL;
Packit Service 779887
Packit Service 779887
    abrt_init(argv);
Packit Service 779887
Packit Service 779887
    setlocale(LC_ALL, "");
Packit Service 779887
    /* Hack:
Packit Service 779887
     * Right-to-left scripts don't work properly in many terminals.
Packit Service 779887
     * Hebrew speaking people say he_IL.utf8 looks so mangled
Packit Service 779887
     * they prefer en_US.utf8 instead.
Packit Service 779887
     */
Packit Service 779887
    const char *msg_locale = setlocale(LC_MESSAGES, NULL);
Packit Service 779887
    if (msg_locale && strcmp(msg_locale, "he_IL.utf8") == 0)
Packit Service 779887
        setlocale(LC_MESSAGES, "en_US.utf8");
Packit Service 779887
#if ENABLE_NLS
Packit Service 779887
    bindtextdomain(PACKAGE, LOCALEDIR);
Packit Service 779887
    textdomain(PACKAGE);
Packit Service 779887
#endif
Packit Service 779887
Packit Service 779887
    /* Can't keep these strings/structs static: _() doesn't support that */
Packit Service 779887
    const char *program_usage_string = _(
Packit Service 779887
        "& [-d] DIR\n"
Packit Service 779887
        "\n"
Packit Service 779887
        "newt tool to report problem saved in specified DIR"
Packit Service 779887
    );
Packit Service 779887
    enum {
Packit Service 779887
        OPT_r = 1 << 0,
Packit Service 779887
        OPT_V = 1 << 1,
Packit Service 779887
    };
Packit Service 779887
    /* Keep enum above and order of options below in sync! */
Packit Service 779887
    struct options program_options[] = {
Packit Service 779887
        OPT_BOOL('d', "delete", NULL,      _("Remove DIR after reporting")),
Packit Service 779887
        OPT_BOOL('V', "version", NULL,     _("Display version and exit")),
Packit Service 779887
        OPT_END()
Packit Service 779887
    };
Packit Service 779887
    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
Packit Service 779887
    argv += optind;
Packit Service 779887
    /* >0 arguments with -V */
Packit Service 779887
    if (((opts & OPT_V) && argv[0]) || !argv[0])
Packit Service 779887
        show_usage_and_die(program_usage_string, program_options);
Packit Service 779887
Packit Service 779887
    if (opts & OPT_V)
Packit Service 779887
    {
Packit Service 779887
        printf("%s "VERSION"\n", g_progname);
Packit Service 779887
        return 0;
Packit Service 779887
    }
Packit Service 779887
Packit Service 779887
    dump_dir_name = argv[0];
Packit Service 779887
Packit Service 779887
    /* Get settings */
Packit Service 779887
    load_event_config_data();
Packit Service 779887
Packit Service 779887
    newtInit();
Packit Service 779887
    newtCls();
Packit Service 779887
Packit Service 779887
    report(dump_dir_name);
Packit Service 779887
Packit Service 779887
    if (opts & OPT_r)
Packit Service 779887
        delete_dump_dir_possibly_using_abrtd(dump_dir_name);
Packit Service 779887
Packit Service 779887
    newtFinished();
Packit Service 779887
Packit Service 779887
    free_event_config_data();
Packit Service 779887
Packit Service 779887
    return 0;
Packit Service 779887
}