Blame SOURCES/1001-bugzilla-port-to-Problem-Format-API.patch

Matej Habrnal dcb953
From 914bdfee5da272a99d8dc3f68652534eb132e007 Mon Sep 17 00:00:00 2001
Matej Habrnal dcb953
From: Jakub Filak <jfilak@redhat.com>
Matej Habrnal dcb953
Date: Thu, 4 Dec 2014 08:45:07 +0100
Matej Habrnal dcb953
Subject: [PATCH] bugzilla: port to Problem Format API
Matej Habrnal dcb953
Matej Habrnal dcb953
Related to #303
Matej Habrnal dcb953
Matej Habrnal dcb953
Signed-off-by: Jakub Filak <jfilak@redhat.com>
Matej Habrnal dcb953
---
Matej Habrnal dcb953
 src/plugins/reporter-bugzilla.c | 691 ++++------------------------------------
Matej Habrnal dcb953
 1 file changed, 59 insertions(+), 632 deletions(-)
Matej Habrnal dcb953
Matej Habrnal dcb953
diff --git a/src/plugins/reporter-bugzilla.c b/src/plugins/reporter-bugzilla.c
Matej Habrnal dcb953
index 097924e..38f48ef 100644
Matej Habrnal dcb953
--- a/src/plugins/reporter-bugzilla.c
Matej Habrnal dcb953
+++ b/src/plugins/reporter-bugzilla.c
Matej Habrnal dcb953
@@ -17,515 +17,11 @@
Matej Habrnal dcb953
     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Matej Habrnal dcb953
 */
Matej Habrnal dcb953
 #include "internal_libreport.h"
Matej Habrnal dcb953
+#include "problem_report.h"
Matej Habrnal dcb953
 #include "client.h"
Matej Habrnal dcb953
 #include "abrt_xmlrpc.h"
Matej Habrnal dcb953
 #include "rhbz.h"
Matej Habrnal dcb953
 
Matej Habrnal dcb953
-#include <satyr/stacktrace.h>
Matej Habrnal dcb953
-#include <satyr/abrt.h>
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-struct section_t {
Matej Habrnal dcb953
-    char *name;
Matej Habrnal dcb953
-    GList *items;
Matej Habrnal dcb953
-};
Matej Habrnal dcb953
-typedef struct section_t section_t;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-/* Utility functions */
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-static
Matej Habrnal dcb953
-GList* split_string_on_char(const char *str, char ch)
Matej Habrnal dcb953
-{
Matej Habrnal dcb953
-    GList *list = NULL;
Matej Habrnal dcb953
-    for (;;)
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        const char *delim = strchrnul(str, ch);
Matej Habrnal dcb953
-        list = g_list_prepend(list, xstrndup(str, delim - str));
Matej Habrnal dcb953
-        if (*delim == '\0')
Matej Habrnal dcb953
-            break;
Matej Habrnal dcb953
-        str = delim + 1;
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-    return g_list_reverse(list);
Matej Habrnal dcb953
-}
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-static
Matej Habrnal dcb953
-int compare_item_name(const char *lookup, const char *name)
Matej Habrnal dcb953
-{
Matej Habrnal dcb953
-    if (lookup[0] == '-')
Matej Habrnal dcb953
-        lookup++;
Matej Habrnal dcb953
-    else if (strncmp(lookup, "%bare_", 6) == 0)
Matej Habrnal dcb953
-        lookup += 6;
Matej Habrnal dcb953
-    return strcmp(lookup, name);
Matej Habrnal dcb953
-}
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-static
Matej Habrnal dcb953
-int is_item_name_in_section(const section_t *lookup, const char *name)
Matej Habrnal dcb953
-{
Matej Habrnal dcb953
-    if (g_list_find_custom(lookup->items, name, (GCompareFunc)compare_item_name))
Matej Habrnal dcb953
-        return 0; /* "found it!" */
Matej Habrnal dcb953
-    return 1;
Matej Habrnal dcb953
-}
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-static
Matej Habrnal dcb953
-bool is_explicit_or_forbidden(const char *name, GList *comment_fmt_spec)
Matej Habrnal dcb953
-{
Matej Habrnal dcb953
-    return g_list_find_custom(comment_fmt_spec, name, (GCompareFunc)is_item_name_in_section);
Matej Habrnal dcb953
-}
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-static
Matej Habrnal dcb953
-GList* load_bzrep_conf_file(const char *path)
Matej Habrnal dcb953
-{
Matej Habrnal dcb953
-    FILE *fp = stdin;
Matej Habrnal dcb953
-    if (strcmp(path, "-") != 0)
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        fp = fopen(path, "r");
Matej Habrnal dcb953
-        if (!fp)
Matej Habrnal dcb953
-            return NULL;
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    GList *sections = NULL;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    char *line;
Matej Habrnal dcb953
-    while ((line = xmalloc_fgetline(fp)) != NULL)
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        /* Skip comments */
Matej Habrnal dcb953
-        char first = *skip_whitespace(line);
Matej Habrnal dcb953
-        if (first == '#')
Matej Habrnal dcb953
-            goto free_line;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        /* Handle trailing backslash continuation */
Matej Habrnal dcb953
- check_continuation: ;
Matej Habrnal dcb953
-        unsigned len = strlen(line);
Matej Habrnal dcb953
-        if (len && line[len-1] == '\\')
Matej Habrnal dcb953
-        {
Matej Habrnal dcb953
-            line[len-1] = '\0';
Matej Habrnal dcb953
-            char *next_line = xmalloc_fgetline(fp);
Matej Habrnal dcb953
-            if (next_line)
Matej Habrnal dcb953
-            {
Matej Habrnal dcb953
-                line = append_to_malloced_string(line, next_line);
Matej Habrnal dcb953
-                free(next_line);
Matej Habrnal dcb953
-                goto check_continuation;
Matej Habrnal dcb953
-            }
Matej Habrnal dcb953
-        }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        /* We are reusing line buffer to form temporary
Matej Habrnal dcb953
-         * "key\0values\0..." in its beginning
Matej Habrnal dcb953
-         */
Matej Habrnal dcb953
-        bool summary_line = false;
Matej Habrnal dcb953
-        char *value = NULL;
Matej Habrnal dcb953
-        char *src;
Matej Habrnal dcb953
-        char *dst;
Matej Habrnal dcb953
-        for (src = dst = line; *src; src++)
Matej Habrnal dcb953
-        {
Matej Habrnal dcb953
-            char c = *src;
Matej Habrnal dcb953
-            /* did we reach the value list? */
Matej Habrnal dcb953
-            if (!value && c == ':' && src[1] == ':')
Matej Habrnal dcb953
-            {
Matej Habrnal dcb953
-                *dst++ = '\0'; /* terminate key */
Matej Habrnal dcb953
-                src += 2;
Matej Habrnal dcb953
-                value = dst; /* remember where value starts */
Matej Habrnal dcb953
-                summary_line = (strcmp(line, "%summary") == 0);
Matej Habrnal dcb953
-                if (summary_line)
Matej Habrnal dcb953
-                {
Matej Habrnal dcb953
-                    value = src;
Matej Habrnal dcb953
-                    break;
Matej Habrnal dcb953
-                }
Matej Habrnal dcb953
-                continue;
Matej Habrnal dcb953
-            }
Matej Habrnal dcb953
-            /* skip whitespace in value list */
Matej Habrnal dcb953
-            if (value && isspace(c))
Matej Habrnal dcb953
-                continue;
Matej Habrnal dcb953
-            *dst++ = c; /* store next key or value char */
Matej Habrnal dcb953
-        }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        GList *item_list = NULL;
Matej Habrnal dcb953
-        if (summary_line)
Matej Habrnal dcb953
-        {
Matej Habrnal dcb953
-            /* %summary is special */
Matej Habrnal dcb953
-            item_list = g_list_append(NULL, xstrdup(skip_whitespace(value)));
Matej Habrnal dcb953
-        }
Matej Habrnal dcb953
-        else
Matej Habrnal dcb953
-        {
Matej Habrnal dcb953
-            *dst = '\0'; /* terminate value (or key) */
Matej Habrnal dcb953
-            if (value)
Matej Habrnal dcb953
-                item_list = split_string_on_char(value, ',');
Matej Habrnal dcb953
-        }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        section_t *sec = xzalloc(sizeof(*sec));
Matej Habrnal dcb953
-        sec->name = xstrdup(line);
Matej Habrnal dcb953
-        sec->items = item_list;
Matej Habrnal dcb953
-        sections = g_list_prepend(sections, sec);
Matej Habrnal dcb953
-
Matej Habrnal dcb953
- free_line:
Matej Habrnal dcb953
-        free(line);
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    if (fp != stdin)
Matej Habrnal dcb953
-        fclose(fp);
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    return g_list_reverse(sections);
Matej Habrnal dcb953
-}
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-/* Summary generation */
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-#define MAX_OPT_DEPTH 10
Matej Habrnal dcb953
-static
Matej Habrnal dcb953
-char *format_percented_string(const char *str, problem_data_t *pd)
Matej Habrnal dcb953
-{
Matej Habrnal dcb953
-    size_t old_pos[MAX_OPT_DEPTH] = { 0 };
Matej Habrnal dcb953
-    int okay[MAX_OPT_DEPTH] = { 1 };
Matej Habrnal dcb953
-    int opt_depth = 1;
Matej Habrnal dcb953
-    struct strbuf *result = strbuf_new();
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    while (*str) {
Matej Habrnal dcb953
-        switch (*str) {
Matej Habrnal dcb953
-        default:
Matej Habrnal dcb953
-            strbuf_append_char(result, *str);
Matej Habrnal dcb953
-            str++;
Matej Habrnal dcb953
-            break;
Matej Habrnal dcb953
-        case '\\':
Matej Habrnal dcb953
-            if (str[1])
Matej Habrnal dcb953
-                str++;
Matej Habrnal dcb953
-            strbuf_append_char(result, *str);
Matej Habrnal dcb953
-            str++;
Matej Habrnal dcb953
-            break;
Matej Habrnal dcb953
-        case '[':
Matej Habrnal dcb953
-            if (str[1] == '[' && opt_depth < MAX_OPT_DEPTH)
Matej Habrnal dcb953
-            {
Matej Habrnal dcb953
-                old_pos[opt_depth] = result->len;
Matej Habrnal dcb953
-                okay[opt_depth] = 1;
Matej Habrnal dcb953
-                opt_depth++;
Matej Habrnal dcb953
-                str += 2;
Matej Habrnal dcb953
-            } else {
Matej Habrnal dcb953
-                strbuf_append_char(result, *str);
Matej Habrnal dcb953
-                str++;
Matej Habrnal dcb953
-            }
Matej Habrnal dcb953
-            break;
Matej Habrnal dcb953
-        case ']':
Matej Habrnal dcb953
-            if (str[1] == ']' && opt_depth > 1)
Matej Habrnal dcb953
-            {
Matej Habrnal dcb953
-                opt_depth--;
Matej Habrnal dcb953
-                if (!okay[opt_depth])
Matej Habrnal dcb953
-                {
Matej Habrnal dcb953
-                    result->len = old_pos[opt_depth];
Matej Habrnal dcb953
-                    result->buf[result->len] = '\0';
Matej Habrnal dcb953
-                }
Matej Habrnal dcb953
-                str += 2;
Matej Habrnal dcb953
-            } else {
Matej Habrnal dcb953
-                strbuf_append_char(result, *str);
Matej Habrnal dcb953
-                str++;
Matej Habrnal dcb953
-            }
Matej Habrnal dcb953
-            break;
Matej Habrnal dcb953
-        case '%': ;
Matej Habrnal dcb953
-            char *nextpercent = strchr(++str, '%');
Matej Habrnal dcb953
-            if (!nextpercent)
Matej Habrnal dcb953
-            {
Matej Habrnal dcb953
-                error_msg_and_die("Unterminated %%element%%: '%s'", str - 1);
Matej Habrnal dcb953
-            }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-            *nextpercent = '\0';
Matej Habrnal dcb953
-            const problem_item *item = problem_data_get_item_or_NULL(pd, str);
Matej Habrnal dcb953
-            *nextpercent = '%';
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-            if (item && (item->flags & CD_FLAG_TXT))
Matej Habrnal dcb953
-                strbuf_append_str(result, item->content);
Matej Habrnal dcb953
-            else
Matej Habrnal dcb953
-                okay[opt_depth - 1] = 0;
Matej Habrnal dcb953
-            str = nextpercent + 1;
Matej Habrnal dcb953
-            break;
Matej Habrnal dcb953
-        }
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    if (opt_depth > 1)
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        error_msg_and_die("Unbalanced [[ ]] bracket");
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    if (!okay[0])
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        error_msg("Undefined variable outside of [[ ]] bracket");
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    return strbuf_free_nobuf(result);
Matej Habrnal dcb953
-}
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-static
Matej Habrnal dcb953
-char *create_summary_string(problem_data_t *pd, GList *comment_fmt_spec)
Matej Habrnal dcb953
-{
Matej Habrnal dcb953
-    GList *l = comment_fmt_spec;
Matej Habrnal dcb953
-    while (l)
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        section_t *sec = l->data;
Matej Habrnal dcb953
-        l = l->next;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        /* Find %summary" */
Matej Habrnal dcb953
-        if (strcmp(sec->name, "%summary") != 0)
Matej Habrnal dcb953
-            continue;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        GList *item = sec->items;
Matej Habrnal dcb953
-        if (!item)
Matej Habrnal dcb953
-            /* not supposed to happen, there will be at least "" */
Matej Habrnal dcb953
-            error_msg_and_die("BUG in %%summary parser");
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        const char *str = item->data;
Matej Habrnal dcb953
-        return format_percented_string(str, pd);
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    return format_percented_string("%reason%", pd);
Matej Habrnal dcb953
-}
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-/* BZ comment generation */
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-static
Matej Habrnal dcb953
-int append_text(struct strbuf *result, const char *item_name, const char *content, bool print_item_name)
Matej Habrnal dcb953
-{
Matej Habrnal dcb953
-    char *eol = strchrnul(content, '\n');
Matej Habrnal dcb953
-    if (eol[0] == '\0' || eol[1] == '\0')
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        /* one-liner */
Matej Habrnal dcb953
-        int pad = 16 - (strlen(item_name) + 2);
Matej Habrnal dcb953
-        if (pad < 0)
Matej Habrnal dcb953
-            pad = 0;
Matej Habrnal dcb953
-        if (print_item_name)
Matej Habrnal dcb953
-            strbuf_append_strf(result,
Matej Habrnal dcb953
-                    eol[0] == '\0' ? "%s: %*s%s\n" : "%s: %*s%s",
Matej Habrnal dcb953
-                    item_name, pad, "", content
Matej Habrnal dcb953
-            );
Matej Habrnal dcb953
-        else
Matej Habrnal dcb953
-            strbuf_append_strf(result,
Matej Habrnal dcb953
-                    eol[0] == '\0' ? "%s\n" : "%s",
Matej Habrnal dcb953
-                    content
Matej Habrnal dcb953
-            );
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-    else
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        /* multi-line item */
Matej Habrnal dcb953
-        if (print_item_name)
Matej Habrnal dcb953
-            strbuf_append_strf(result, "%s:\n", item_name);
Matej Habrnal dcb953
-        for (;;)
Matej Habrnal dcb953
-        {
Matej Habrnal dcb953
-            eol = strchrnul(content, '\n');
Matej Habrnal dcb953
-            strbuf_append_strf(result,
Matej Habrnal dcb953
-                    /* For %bare_multiline_item, we don't want to print colons */
Matej Habrnal dcb953
-                    (print_item_name ? ":%.*s\n" : "%.*s\n"),
Matej Habrnal dcb953
-                    (int)(eol - content), content
Matej Habrnal dcb953
-            );
Matej Habrnal dcb953
-            if (eol[0] == '\0' || eol[1] == '\0')
Matej Habrnal dcb953
-                break;
Matej Habrnal dcb953
-            content = eol + 1;
Matej Habrnal dcb953
-        }
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-    return 1;
Matej Habrnal dcb953
-}
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-static
Matej Habrnal dcb953
-int append_short_backtrace(struct strbuf *result, problem_data_t *problem_data, size_t max_text_size, bool print_item_name)
Matej Habrnal dcb953
-{
Matej Habrnal dcb953
-    const problem_item *item = problem_data_get_item_or_NULL(problem_data,
Matej Habrnal dcb953
-                                                             FILENAME_BACKTRACE);
Matej Habrnal dcb953
-    if (!item)
Matej Habrnal dcb953
-        return 0; /* "I did not print anything" */
Matej Habrnal dcb953
-    if (!(item->flags & CD_FLAG_TXT))
Matej Habrnal dcb953
-        return 0; /* "I did not print anything" */
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    char *truncated = NULL;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    if (strlen(item->content) >= max_text_size)
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        char *error_msg = NULL;
Matej Habrnal dcb953
-        const char *analyzer = problem_data_get_content_or_NULL(problem_data, FILENAME_ANALYZER);
Matej Habrnal dcb953
-        if (!analyzer)
Matej Habrnal dcb953
-            return 0;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        /* For CCpp crashes, use the GDB-produced backtrace which should be
Matej Habrnal dcb953
-         * available by now. sr_abrt_type_from_analyzer returns SR_REPORT_CORE
Matej Habrnal dcb953
-         * by default for CCpp crashes.
Matej Habrnal dcb953
-         */
Matej Habrnal dcb953
-        enum sr_report_type report_type = sr_abrt_type_from_analyzer(analyzer);
Matej Habrnal dcb953
-        if (strcmp(analyzer, "CCpp") == 0)
Matej Habrnal dcb953
-            report_type = SR_REPORT_GDB;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        struct sr_stacktrace *backtrace = sr_stacktrace_parse(report_type,
Matej Habrnal dcb953
-                item->content, &error_msg);
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        if (!backtrace)
Matej Habrnal dcb953
-        {
Matej Habrnal dcb953
-            log(_("Can't parse backtrace: %s"), error_msg);
Matej Habrnal dcb953
-            free(error_msg);
Matej Habrnal dcb953
-            return 0;
Matej Habrnal dcb953
-        }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        /* Get optimized thread stack trace for 10 top most frames */
Matej Habrnal dcb953
-        truncated = sr_stacktrace_to_short_text(backtrace, 10);
Matej Habrnal dcb953
-        sr_stacktrace_free(backtrace);
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        if (!truncated)
Matej Habrnal dcb953
-        {
Matej Habrnal dcb953
-            log(_("Can't generate stacktrace description (no crash thread?)"));
Matej Habrnal dcb953
-            return 0;
Matej Habrnal dcb953
-        }
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    append_text(result,
Matej Habrnal dcb953
-                /*item_name:*/ truncated ? "truncated_backtrace" : FILENAME_BACKTRACE,
Matej Habrnal dcb953
-                /*content:*/   truncated ? truncated             : item->content,
Matej Habrnal dcb953
-                print_item_name
Matej Habrnal dcb953
-    );
Matej Habrnal dcb953
-    free(truncated);
Matej Habrnal dcb953
-    return 1;
Matej Habrnal dcb953
-}
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-static
Matej Habrnal dcb953
-int append_item(struct strbuf *result, const char *item_name, problem_data_t *pd, GList *comment_fmt_spec)
Matej Habrnal dcb953
-{
Matej Habrnal dcb953
-    bool print_item_name = (strncmp(item_name, "%bare_", strlen("%bare_")) != 0);
Matej Habrnal dcb953
-    if (!print_item_name)
Matej Habrnal dcb953
-        item_name += strlen("%bare_");
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    if (item_name[0] != '%')
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        struct problem_item *item = problem_data_get_item_or_NULL(pd, item_name);
Matej Habrnal dcb953
-        if (!item)
Matej Habrnal dcb953
-            return 0; /* "I did not print anything" */
Matej Habrnal dcb953
-        if (!(item->flags & CD_FLAG_TXT))
Matej Habrnal dcb953
-            return 0; /* "I did not print anything" */
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        char *formatted = problem_item_format(item);
Matej Habrnal dcb953
-        char *content = formatted ? formatted : item->content;
Matej Habrnal dcb953
-        append_text(result, item_name, content, print_item_name);
Matej Habrnal dcb953
-        free(formatted);
Matej Habrnal dcb953
-        return 1; /* "I printed something" */
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    /* Special item name */
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    /* Compat with previously-existed ad-hockery: %short_backtrace */
Matej Habrnal dcb953
-    if (strcmp(item_name, "%short_backtrace") == 0)
Matej Habrnal dcb953
-        return append_short_backtrace(result, pd, CD_TEXT_ATT_SIZE_BZ, print_item_name);
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    /* Compat with previously-existed ad-hockery: %reporter */
Matej Habrnal dcb953
-    if (strcmp(item_name, "%reporter") == 0)
Matej Habrnal dcb953
-        return append_text(result, "reporter", PACKAGE"-"VERSION, print_item_name);
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    /* %oneline,%multiline,%text */
Matej Habrnal dcb953
-    bool oneline   = (strcmp(item_name+1, "oneline"  ) == 0);
Matej Habrnal dcb953
-    bool multiline = (strcmp(item_name+1, "multiline") == 0);
Matej Habrnal dcb953
-    bool text      = (strcmp(item_name+1, "text"     ) == 0);
Matej Habrnal dcb953
-    if (!oneline && !multiline && !text)
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        log("Unknown or unsupported element specifier '%s'", item_name);
Matej Habrnal dcb953
-        return 0; /* "I did not print anything" */
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    int printed = 0;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    /* Iterate over _sorted_ items */
Matej Habrnal dcb953
-    GList *sorted_names = g_hash_table_get_keys(pd);
Matej Habrnal dcb953
-    sorted_names = g_list_sort(sorted_names, (GCompareFunc)strcmp);
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    /* %text => do as if %oneline, then repeat as if %multiline */
Matej Habrnal dcb953
-    if (text)
Matej Habrnal dcb953
-        oneline = 1;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
- again: ;
Matej Habrnal dcb953
-    GList *l = sorted_names;
Matej Habrnal dcb953
-    while (l)
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        const char *name = l->data;
Matej Habrnal dcb953
-        l = l->next;
Matej Habrnal dcb953
-        struct problem_item *item = g_hash_table_lookup(pd, name);
Matej Habrnal dcb953
-        if (!item)
Matej Habrnal dcb953
-            continue; /* paranoia, won't happen */
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        if (!(item->flags & CD_FLAG_TXT))
Matej Habrnal dcb953
-            continue;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        if (is_explicit_or_forbidden(name, comment_fmt_spec))
Matej Habrnal dcb953
-            continue;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        char *formatted = problem_item_format(item);
Matej Habrnal dcb953
-        char *content = formatted ? formatted : item->content;
Matej Habrnal dcb953
-        char *eol = strchrnul(content, '\n');
Matej Habrnal dcb953
-        bool is_oneline = (eol[0] == '\0' || eol[1] == '\0');
Matej Habrnal dcb953
-        if (oneline == is_oneline)
Matej Habrnal dcb953
-            printed |= append_text(result, name, content, print_item_name);
Matej Habrnal dcb953
-        free(formatted);
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-    if (text && oneline)
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        /* %text, and we just did %oneline. Repeat as if %multiline */
Matej Habrnal dcb953
-        oneline = 0;
Matej Habrnal dcb953
-        /*multiline = 1; - not checked in fact, so why bother setting? */
Matej Habrnal dcb953
-        goto again;
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    g_list_free(sorted_names); /* names themselves are not freed */
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    return printed;
Matej Habrnal dcb953
-}
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-static
Matej Habrnal dcb953
-void generate_bz_comment(struct strbuf *result, problem_data_t *pd, GList *comment_fmt_spec)
Matej Habrnal dcb953
-{
Matej Habrnal dcb953
-    bool last_line_is_empty = true;
Matej Habrnal dcb953
-    GList *l = comment_fmt_spec;
Matej Habrnal dcb953
-    while (l)
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        section_t *sec = l->data;
Matej Habrnal dcb953
-        l = l->next;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        /* Skip special sections such as "%attach" */
Matej Habrnal dcb953
-        if (sec->name[0] == '%')
Matej Habrnal dcb953
-            continue;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        if (sec->items)
Matej Habrnal dcb953
-        {
Matej Habrnal dcb953
-            /* "Text: item[,item]..." */
Matej Habrnal dcb953
-            struct strbuf *output = strbuf_new();
Matej Habrnal dcb953
-            GList *item = sec->items;
Matej Habrnal dcb953
-            while (item)
Matej Habrnal dcb953
-            {
Matej Habrnal dcb953
-                const char *str = item->data;
Matej Habrnal dcb953
-                item = item->next;
Matej Habrnal dcb953
-                if (str[0] == '-') /* "-name", ignore it */
Matej Habrnal dcb953
-                    continue;
Matej Habrnal dcb953
-                append_item(output, str, pd, comment_fmt_spec);
Matej Habrnal dcb953
-            }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-            if (output->len != 0)
Matej Habrnal dcb953
-            {
Matej Habrnal dcb953
-                strbuf_append_strf(result,
Matej Habrnal dcb953
-                            sec->name[0] ? "%s:\n%s" : "%s%s",
Matej Habrnal dcb953
-                            sec->name,
Matej Habrnal dcb953
-                            output->buf
Matej Habrnal dcb953
-                );
Matej Habrnal dcb953
-                last_line_is_empty = false;
Matej Habrnal dcb953
-            }
Matej Habrnal dcb953
-            strbuf_free(output);
Matej Habrnal dcb953
-        }
Matej Habrnal dcb953
-        else
Matej Habrnal dcb953
-        {
Matej Habrnal dcb953
-            /* Just "Text" (can be "") */
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-            /* Filter out consecutive empty lines */
Matej Habrnal dcb953
-            if (sec->name[0] != '\0' || !last_line_is_empty)
Matej Habrnal dcb953
-                strbuf_append_strf(result, "%s\n", sec->name);
Matej Habrnal dcb953
-            last_line_is_empty = (sec->name[0] == '\0');
Matej Habrnal dcb953
-        }
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    /* Nuke any trailing empty lines */
Matej Habrnal dcb953
-    while (result->len >= 1
Matej Habrnal dcb953
-     && result->buf[result->len-1] == '\n'
Matej Habrnal dcb953
-     && (result->len == 1 || result->buf[result->len-2] == '\n')
Matej Habrnal dcb953
-    ) {
Matej Habrnal dcb953
-        result->buf[--result->len] = '\0';
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-}
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-
Matej Habrnal dcb953
 /* BZ attachments */
Matej Habrnal dcb953
 
Matej Habrnal dcb953
 static
Matej Habrnal dcb953
@@ -573,104 +69,6 @@ int attach_file_item(struct abrt_xmlrpc *ax, const char *bug_id,
Matej Habrnal dcb953
     return (r == 0);
Matej Habrnal dcb953
 }
Matej Habrnal dcb953
 
Matej Habrnal dcb953
-static
Matej Habrnal dcb953
-int attach_item(struct abrt_xmlrpc *ax, const char *bug_id,
Matej Habrnal dcb953
-                const char *item_name, problem_data_t *pd, GList *comment_fmt_spec)
Matej Habrnal dcb953
-{
Matej Habrnal dcb953
-    if (item_name[0] != '%')
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        struct problem_item *item = problem_data_get_item_or_NULL(pd, item_name);
Matej Habrnal dcb953
-        if (!item)
Matej Habrnal dcb953
-            return 0;
Matej Habrnal dcb953
-        if (item->flags & CD_FLAG_TXT)
Matej Habrnal dcb953
-            return attach_text_item(ax, bug_id, item_name, item);
Matej Habrnal dcb953
-        if (item->flags & CD_FLAG_BIN)
Matej Habrnal dcb953
-            return attach_file_item(ax, bug_id, item_name, item);
Matej Habrnal dcb953
-        return 0;
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    /* Special item name */
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    /* %oneline,%multiline,%text,%binary */
Matej Habrnal dcb953
-    bool oneline   = (strcmp(item_name+1, "oneline"  ) == 0);
Matej Habrnal dcb953
-    bool multiline = (strcmp(item_name+1, "multiline") == 0);
Matej Habrnal dcb953
-    bool text      = (strcmp(item_name+1, "text"     ) == 0);
Matej Habrnal dcb953
-    bool binary    = (strcmp(item_name+1, "binary"   ) == 0);
Matej Habrnal dcb953
-    if (!oneline && !multiline && !text && !binary)
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        log("Unknown or unsupported element specifier '%s'", item_name);
Matej Habrnal dcb953
-        return 0;
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    log_debug("Special item_name '%s', iterating for attach...", item_name);
Matej Habrnal dcb953
-    int done = 0;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    /* Iterate over _sorted_ items */
Matej Habrnal dcb953
-    GList *sorted_names = g_hash_table_get_keys(pd);
Matej Habrnal dcb953
-    sorted_names = g_list_sort(sorted_names, (GCompareFunc)strcmp);
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    GList *l = sorted_names;
Matej Habrnal dcb953
-    while (l)
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        const char *name = l->data;
Matej Habrnal dcb953
-        l = l->next;
Matej Habrnal dcb953
-        struct problem_item *item = g_hash_table_lookup(pd, name);
Matej Habrnal dcb953
-        if (!item)
Matej Habrnal dcb953
-            continue; /* paranoia, won't happen */
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        if (is_explicit_or_forbidden(name, comment_fmt_spec))
Matej Habrnal dcb953
-            continue;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        if ((item->flags & CD_FLAG_TXT) && !binary)
Matej Habrnal dcb953
-        {
Matej Habrnal dcb953
-            char *content = item->content;
Matej Habrnal dcb953
-            char *eol = strchrnul(content, '\n');
Matej Habrnal dcb953
-            bool is_oneline = (eol[0] == '\0' || eol[1] == '\0');
Matej Habrnal dcb953
-            if (text || oneline == is_oneline)
Matej Habrnal dcb953
-                done |= attach_text_item(ax, bug_id, name, item);
Matej Habrnal dcb953
-        }
Matej Habrnal dcb953
-        if ((item->flags & CD_FLAG_BIN) && binary)
Matej Habrnal dcb953
-            done |= attach_file_item(ax, bug_id, name, item);
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    g_list_free(sorted_names); /* names themselves are not freed */
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    log_debug("...Done iterating over '%s' for attach", item_name);
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    return done;
Matej Habrnal dcb953
-}
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-static
Matej Habrnal dcb953
-int attach_files(struct abrt_xmlrpc *ax, const char *bug_id,
Matej Habrnal dcb953
-                problem_data_t *pd, GList *comment_fmt_spec)
Matej Habrnal dcb953
-{
Matej Habrnal dcb953
-    int done = 0;
Matej Habrnal dcb953
-    GList *l = comment_fmt_spec;
Matej Habrnal dcb953
-    while (l)
Matej Habrnal dcb953
-    {
Matej Habrnal dcb953
-        section_t *sec = l->data;
Matej Habrnal dcb953
-        l = l->next;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        /* Find %attach" */
Matej Habrnal dcb953
-        if (strcmp(sec->name, "%attach") != 0)
Matej Habrnal dcb953
-            continue;
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-        GList *item = sec->items;
Matej Habrnal dcb953
-        while (item)
Matej Habrnal dcb953
-        {
Matej Habrnal dcb953
-            const char *str = item->data;
Matej Habrnal dcb953
-            item = item->next;
Matej Habrnal dcb953
-            if (str[0] == '-') /* "-name", ignore it */
Matej Habrnal dcb953
-                continue;
Matej Habrnal dcb953
-            done |= attach_item(ax, bug_id, str, pd, comment_fmt_spec);
Matej Habrnal dcb953
-        }
Matej Habrnal dcb953
-    }
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-    return done;
Matej Habrnal dcb953
-}
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-
Matej Habrnal dcb953
 /* Main */
Matej Habrnal dcb953
 
Matej Habrnal dcb953
 struct bugzilla_struct {
Matej Habrnal dcb953
@@ -1102,18 +500,29 @@ int main(int argc, char **argv)
Matej Habrnal dcb953
 
Matej Habrnal dcb953
     if (opts & OPT_D)
Matej Habrnal dcb953
     {
Matej Habrnal dcb953
-        GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file);
Matej Habrnal dcb953
-        struct strbuf *bzcomment_buf = strbuf_new();
Matej Habrnal dcb953
-        generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec);
Matej Habrnal dcb953
-        char *bzcomment = strbuf_free_nobuf(bzcomment_buf);
Matej Habrnal dcb953
-        char *summary = create_summary_string(problem_data, comment_fmt_spec);
Matej Habrnal dcb953
+        problem_formatter_t *pf = problem_formatter_new();
Matej Habrnal dcb953
+
Matej Habrnal dcb953
+        if (problem_formatter_load_file(pf, fmt_file))
Matej Habrnal dcb953
+            error_msg_and_die("Invalid format file: %s", fmt_file);
Matej Habrnal dcb953
+
Matej Habrnal dcb953
+        problem_report_t *pr = NULL;
Matej Habrnal dcb953
+        if (problem_formatter_generate_report(pf, problem_data, &pr))
Matej Habrnal dcb953
+            error_msg_and_die("Failed to format bug report from problem data");
Matej Habrnal dcb953
+
Matej Habrnal dcb953
         printf("summary: %s\n"
Matej Habrnal dcb953
                 "\n"
Matej Habrnal dcb953
                 "%s"
Matej Habrnal dcb953
-                , summary, bzcomment
Matej Habrnal dcb953
+                "\n"
Matej Habrnal dcb953
+                , problem_report_get_summary(pr)
Matej Habrnal dcb953
+                , problem_report_get_description(pr)
Matej Habrnal dcb953
         );
Matej Habrnal dcb953
-        free(bzcomment);
Matej Habrnal dcb953
-        free(summary);
Matej Habrnal dcb953
+
Matej Habrnal dcb953
+        puts("attachments:");
Matej Habrnal dcb953
+        for (GList *a = problem_report_get_attachments(pr); a != NULL; a = g_list_next(a))
Matej Habrnal dcb953
+            printf(" %s\n", (const char *)a->data);
Matej Habrnal dcb953
+
Matej Habrnal dcb953
+        problem_report_free(pr);
Matej Habrnal dcb953
+        problem_formatter_free(pf);
Matej Habrnal dcb953
         exit(0);
Matej Habrnal dcb953
     }
Matej Habrnal dcb953
 
Matej Habrnal dcb953
@@ -1196,22 +605,29 @@ int main(int argc, char **argv)
Matej Habrnal dcb953
             /* Create new bug */
Matej Habrnal dcb953
             log(_("Creating a new bug"));
Matej Habrnal dcb953
 
Matej Habrnal dcb953
-            GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file);
Matej Habrnal dcb953
+            problem_formatter_t *pf = problem_formatter_new();
Matej Habrnal dcb953
+
Matej Habrnal dcb953
+            if (problem_formatter_load_file(pf, fmt_file))
Matej Habrnal dcb953
+                error_msg_and_die("Invalid format file: %s", fmt_file);
Matej Habrnal dcb953
+
Matej Habrnal dcb953
+            problem_report_t *pr = NULL;
Matej Habrnal dcb953
+            if (problem_formatter_generate_report(pf, problem_data, &pr))
Matej Habrnal dcb953
+                error_msg_and_die("Failed to format problem data");
Matej Habrnal dcb953
 
Matej Habrnal dcb953
-            struct strbuf *bzcomment_buf = strbuf_new();
Matej Habrnal dcb953
-            generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec);
Matej Habrnal dcb953
             if (crossver_id >= 0)
Matej Habrnal dcb953
-                strbuf_append_strf(bzcomment_buf, "\nPotential duplicate: bug %u\n", crossver_id);
Matej Habrnal dcb953
-            char *bzcomment = strbuf_free_nobuf(bzcomment_buf);
Matej Habrnal dcb953
-            char *summary = create_summary_string(problem_data, comment_fmt_spec);
Matej Habrnal dcb953
+                problem_report_buffer_printf(
Matej Habrnal dcb953
+                        problem_report_get_buffer(pr, PR_SEC_DESCRIPTION),
Matej Habrnal dcb953
+                        "\nPotential duplicate: bug %u\n", crossver_id);
Matej Habrnal dcb953
+
Matej Habrnal dcb953
+            problem_formatter_free(pf);
Matej Habrnal dcb953
+
Matej Habrnal dcb953
             int new_id = rhbz_new_bug(client,
Matej Habrnal dcb953
                     problem_data, rhbz.b_product, rhbz.b_product_version,
Matej Habrnal dcb953
-                    summary, bzcomment,
Matej Habrnal dcb953
+                    problem_report_get_summary(pr),
Matej Habrnal dcb953
+                    problem_report_get_description(pr),
Matej Habrnal dcb953
                     (rhbz.b_create_private | (opts & OPT_g)), // either we got Bugzilla_CreatePrivate from settings or -g was specified on cmdline
Matej Habrnal dcb953
                     rhbz.b_private_groups
Matej Habrnal dcb953
                     );
Matej Habrnal dcb953
-            free(bzcomment);
Matej Habrnal dcb953
-            free(summary);
Matej Habrnal dcb953
 
Matej Habrnal dcb953
             if (new_id == -1)
Matej Habrnal dcb953
             {
Matej Habrnal dcb953
@@ -1236,9 +652,17 @@ int main(int argc, char **argv)
Matej Habrnal dcb953
             char new_id_str[sizeof(int)*3 + 2];
Matej Habrnal dcb953
             sprintf(new_id_str, "%i", new_id);
Matej Habrnal dcb953
 
Matej Habrnal dcb953
-            attach_files(client, new_id_str, problem_data, comment_fmt_spec);
Matej Habrnal dcb953
-
Matej Habrnal dcb953
-//TODO: free_comment_fmt_spec(comment_fmt_spec);
Matej Habrnal dcb953
+            for (GList *a = problem_report_get_attachments(pr); a != NULL; a = g_list_next(a))
Matej Habrnal dcb953
+            {
Matej Habrnal dcb953
+                const char *item_name = (const char *)a->data;
Matej Habrnal dcb953
+                struct problem_item *item = problem_data_get_item_or_NULL(problem_data, item_name);
Matej Habrnal dcb953
+                if (!item)
Matej Habrnal dcb953
+                    continue;
Matej Habrnal dcb953
+                else if (item->flags & CD_FLAG_TXT)
Matej Habrnal dcb953
+                    attach_text_item(client, new_id_str, item_name, item);
Matej Habrnal dcb953
+                else if (item->flags & CD_FLAG_BIN)
Matej Habrnal dcb953
+                    attach_file_item(client, new_id_str, item_name, item);
Matej Habrnal dcb953
+            }
Matej Habrnal dcb953
 
Matej Habrnal dcb953
             bz = new_bug_info();
Matej Habrnal dcb953
             bz->bi_status = xstrdup("NEW");
Matej Habrnal dcb953
@@ -1302,18 +726,21 @@ int main(int argc, char **argv)
Matej Habrnal dcb953
     const char *comment = problem_data_get_content_or_NULL(problem_data, FILENAME_COMMENT);
Matej Habrnal dcb953
     if (comment && comment[0])
Matej Habrnal dcb953
     {
Matej Habrnal dcb953
-        GList *comment_fmt_spec = load_bzrep_conf_file(fmt_file2);
Matej Habrnal dcb953
-        struct strbuf *bzcomment_buf = strbuf_new();
Matej Habrnal dcb953
-        generate_bz_comment(bzcomment_buf, problem_data, comment_fmt_spec);
Matej Habrnal dcb953
-        char *bzcomment = strbuf_free_nobuf(bzcomment_buf);
Matej Habrnal dcb953
-//TODO: free_comment_fmt_spec(comment_fmt_spec);
Matej Habrnal dcb953
+        problem_formatter_t *pf = problem_formatter_new();
Matej Habrnal dcb953
+        if (problem_formatter_load_file(pf, fmt_file2))
Matej Habrnal dcb953
+            error_msg_and_die("Invalid duplicate format file: '%s", fmt_file2);
Matej Habrnal dcb953
+
Matej Habrnal dcb953
+        problem_report_t *pr;
Matej Habrnal dcb953
+        if (problem_formatter_generate_report(pf, problem_data, &pr))
Matej Habrnal dcb953
+            error_msg_and_die("Failed to format duplicate comment from problem data");
Matej Habrnal dcb953
+
Matej Habrnal dcb953
+        const char *bzcomment = problem_report_get_description(pr);
Matej Habrnal dcb953
 
Matej Habrnal dcb953
         int dup_comment = is_comment_dup(bz->bi_comments, bzcomment);
Matej Habrnal dcb953
         if (!dup_comment)
Matej Habrnal dcb953
         {
Matej Habrnal dcb953
             log(_("Adding new comment to bug %d"), bz->bi_id);
Matej Habrnal dcb953
             rhbz_add_comment(client, bz->bi_id, bzcomment, 0);
Matej Habrnal dcb953
-            free(bzcomment);
Matej Habrnal dcb953
 
Matej Habrnal dcb953
             const char *bt = problem_data_get_content_or_NULL(problem_data, FILENAME_BACKTRACE);
Matej Habrnal dcb953
             unsigned rating = 0;
Matej Habrnal dcb953
@@ -1331,10 +758,10 @@ int main(int argc, char **argv)
Matej Habrnal dcb953
             }
Matej Habrnal dcb953
         }
Matej Habrnal dcb953
         else
Matej Habrnal dcb953
-        {
Matej Habrnal dcb953
-            free(bzcomment);
Matej Habrnal dcb953
             log(_("Found the same comment in the bug history, not adding a new one"));
Matej Habrnal dcb953
-        }
Matej Habrnal dcb953
+
Matej Habrnal dcb953
+        problem_report_free(pr);
Matej Habrnal dcb953
+        problem_formatter_free(pf);
Matej Habrnal dcb953
     }
Matej Habrnal dcb953
 
Matej Habrnal dcb953
  log_out:
Matej Habrnal dcb953
-- 
Matej Habrnal dcb953
1.8.3.1
Matej Habrnal dcb953