Blame SOURCES/0079-ureport-publish-ureport.h-and-refactore-uReport-sour.patch

28bab8
From e67393a38e1739ff1b0453fdb3b68ff7e4fb36e9 Mon Sep 17 00:00:00 2001
28bab8
From: Jakub Filak <jfilak@redhat.com>
28bab8
Date: Fri, 12 Sep 2014 17:20:01 +0200
28bab8
Subject: [LIBREPORT PATCH 79/93] ureport: publish ureport.h and refactore
28bab8
 uReport source
28bab8
28bab8
Allow other plugins to submit uReport and allow external applications to
28bab8
use libreport to submit uReport.
28bab8
28bab8
Related to rhbz1139987
28bab8
28bab8
Signed-off-by: Jakub Filak <jfilak@redhat.com>
28bab8
---
28bab8
 src/include/Makefile.am        |   4 +
28bab8
 src/include/ureport.h          |  76 ++++
28bab8
 src/lib/Makefile.am            |   4 +-
28bab8
 src/lib/json.c                 | 180 ----------
28bab8
 src/lib/ureport.c              | 180 ++++++++++
28bab8
 src/lib/ureport.h              |  76 ----
28bab8
 src/plugins/Makefile.am        |   4 +-
28bab8
 src/plugins/reporter-ureport.c | 777 +++++++++++++++++++++++++++++++++++++++++
28bab8
 src/plugins/ureport.c          | 777 -----------------------------------------
28bab8
 9 files changed, 1043 insertions(+), 1035 deletions(-)
28bab8
 create mode 100644 src/include/ureport.h
28bab8
 delete mode 100644 src/lib/json.c
28bab8
 create mode 100644 src/lib/ureport.c
28bab8
 delete mode 100644 src/lib/ureport.h
28bab8
 create mode 100644 src/plugins/reporter-ureport.c
28bab8
 delete mode 100644 src/plugins/ureport.c
28bab8
28bab8
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
28bab8
index 806b93e..de44cda 100644
28bab8
--- a/src/include/Makefile.am
28bab8
+++ b/src/include/Makefile.am
28bab8
@@ -15,3 +15,7 @@ libreport_include_HEADERS = \
28bab8
     internal_libreport.h \
28bab8
     internal_abrt_dbus.h \
28bab8
     xml_parser.h
28bab8
+
28bab8
+if BUILD_UREPORT
28bab8
+libreport_include_HEADERS += ureport.h
28bab8
+endif
28bab8
diff --git a/src/include/ureport.h b/src/include/ureport.h
28bab8
new file mode 100644
28bab8
index 0000000..d341f6e
28bab8
--- /dev/null
28bab8
+++ b/src/include/ureport.h
28bab8
@@ -0,0 +1,76 @@
28bab8
+/*
28bab8
+    Copyright (C) 2012  ABRT team
28bab8
+    Copyright (C) 2012  RedHat Inc
28bab8
+
28bab8
+    This program is free software; you can redistribute it and/or modify
28bab8
+    it under the terms of the GNU General Public License as published by
28bab8
+    the Free Software Foundation; either version 2 of the License, or
28bab8
+    (at your option) any later version.
28bab8
+
28bab8
+    This program is distributed in the hope that it will be useful,
28bab8
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
28bab8
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28bab8
+    GNU General Public License for more details.
28bab8
+
28bab8
+    You should have received a copy of the GNU General Public License along
28bab8
+    with this program; if not, write to the Free Software Foundation, Inc.,
28bab8
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28bab8
+*/
28bab8
+#ifndef UREPORT_H_
28bab8
+#define UREPORT_H_
28bab8
+
28bab8
+#include "problem_data.h"
28bab8
+
28bab8
+#ifdef __cplusplus
28bab8
+extern "C" {
28bab8
+#endif
28bab8
+
28bab8
+/*
28bab8
+ * uReport generation configuration
28bab8
+ */
28bab8
+struct ureport_preferences
28bab8
+{
28bab8
+    GList *urp_auth_items;  ///< list of file names included in 'auth' key
28bab8
+};
28bab8
+
28bab8
+/*
28bab8
+ * uReport server configuration
28bab8
+ */
28bab8
+struct ureport_server_config
28bab8
+{
28bab8
+    const char *ur_url;   ///< Web service URL
28bab8
+    bool ur_ssl_verify;   ///< Verify HOST and PEER certificates
28bab8
+    char *ur_client_cert; ///< Path to certificate used for client
28bab8
+                          ///< authentication (or NULL)
28bab8
+    char *ur_client_key;  ///< Private key for the certificate
28bab8
+    map_string_t *ur_http_headers; ///< Additional HTTP headers
28bab8
+
28bab8
+    struct ureport_preferences ur_prefs; ///< configuration for uReport generation
28bab8
+};
28bab8
+
28bab8
+struct abrt_post_state;
28bab8
+
28bab8
+#define ureport_post libreport_ureport_post
28bab8
+struct post_state *ureport_post(const char *json_ureport,
28bab8
+                                struct ureport_server_config *config);
28bab8
+
28bab8
+#define ureport_attach_rhbz libreport_ureport_attach_rhbz
28bab8
+struct post_state *ureport_attach_rhbz(const char *bthash, int rhbz_bug_id,
28bab8
+                                       struct ureport_server_config *config);
28bab8
+
28bab8
+#define ureport_attach_email libreport_ureport_attach_email
28bab8
+struct post_state *ureport_attach_email(const char *bthash, const char *email,
28bab8
+                                        struct ureport_server_config *config);
28bab8
+
28bab8
+#define ureport_from_dump_dir libreport_ureport_from_dump_dir
28bab8
+char *ureport_from_dump_dir(const char *dump_dir_path);
28bab8
+
28bab8
+#define ureport_from_dump_dir_ext libreport_ureport_from_dump_dir_ext
28bab8
+char *ureport_from_dump_dir_ext(const char *dump_dir_path,
28bab8
+                                const struct ureport_preferences *preferences);
28bab8
+
28bab8
+#ifdef __cplusplus
28bab8
+}
28bab8
+#endif
28bab8
+
28bab8
+#endif
28bab8
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
28bab8
index d2ff675..7d9722a 100644
28bab8
--- a/src/lib/Makefile.am
28bab8
+++ b/src/lib/Makefile.am
28bab8
@@ -72,6 +72,7 @@ libreport_la_CPPFLAGS = \
28bab8
     -DDEFAULT_DUMP_DIR_MODE=$(DEFAULT_DUMP_DIR_MODE) \
28bab8
     -DDUMP_DIR_OWNED_BY_USER=$(DUMP_DIR_OWNED_BY_USER) \
28bab8
     -DLARGE_DATA_TMP_DIR=\"$(LARGE_DATA_TMP_DIR)\" \
28bab8
+    $(JSON_C_CFLAGS) \
28bab8
     $(GLIB_CFLAGS) \
28bab8
     $(GOBJECT_CFLAGS) \
28bab8
     $(AUGEAS_CFLAGS) \
28bab8
@@ -79,6 +80,7 @@ libreport_la_CPPFLAGS = \
28bab8
 libreport_la_LDFLAGS = \
28bab8
     -version-info 0:1:0
28bab8
 libreport_la_LIBADD = \
28bab8
+    $(JSON_C_LIBS) \
28bab8
     $(GLIB_LIBS) \
28bab8
     $(JOURNAL_LIBS) \
28bab8
     $(GOBJECT_LIBS) \
28bab8
@@ -113,7 +115,7 @@ libreport_web_o += abrt_xmlrpc.h abrt_xmlrpc.c
28bab8
 endif
28bab8
 
28bab8
 if BUILD_UREPORT
28bab8
-libreport_web_o += ureport.h json.c
28bab8
+libreport_web_o += ureport.c
28bab8
 endif
28bab8
 
28bab8
 libreport_web_la_SOURCES = $(libreport_web_o) \
28bab8
diff --git a/src/lib/json.c b/src/lib/json.c
28bab8
deleted file mode 100644
28bab8
index 6fbbf39..0000000
28bab8
--- a/src/lib/json.c
28bab8
+++ /dev/null
28bab8
@@ -1,180 +0,0 @@
28bab8
-/*
28bab8
-    Copyright (C) 2012  ABRT team
28bab8
-    Copyright (C) 2012  RedHat Inc
28bab8
-
28bab8
-    This program is free software; you can redistribute it and/or modify
28bab8
-    it under the terms of the GNU General Public License as published by
28bab8
-    the Free Software Foundation; either version 2 of the License, or
28bab8
-    (at your option) any later version.
28bab8
-
28bab8
-    This program is distributed in the hope that it will be useful,
28bab8
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
28bab8
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28bab8
-    GNU General Public License for more details.
28bab8
-
28bab8
-    You should have received a copy of the GNU General Public License along
28bab8
-    with this program; if not, write to the Free Software Foundation, Inc.,
28bab8
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28bab8
-*/
28bab8
-
28bab8
-#include <json/json.h>
28bab8
-
28bab8
-#include <satyr/abrt.h>
28bab8
-#include <satyr/report.h>
28bab8
-
28bab8
-#include "internal_libreport.h"
28bab8
-#include "ureport.h"
28bab8
-#include "libreport_curl.h"
28bab8
-
28bab8
-
28bab8
-static void ureport_add_str(struct json_object *ur, const char *key,
28bab8
-                            const char *s)
28bab8
-{
28bab8
-    struct json_object *jstring = json_object_new_string(s);
28bab8
-    if (!jstring)
28bab8
-        die_out_of_memory();
28bab8
-
28bab8
-    json_object_object_add(ur, key, jstring);
28bab8
-}
28bab8
-
28bab8
-char *ureport_from_dump_dir_ext(const char *dump_dir_path, const struct ureport_preferences *preferences)
28bab8
-{
28bab8
-    char *error_message;
28bab8
-    struct sr_report *report = sr_abrt_report_from_dir(dump_dir_path,
28bab8
-                                                       &error_message);
28bab8
-
28bab8
-    if (!report)
28bab8
-        error_msg_and_die("%s", error_message);
28bab8
-
28bab8
-    if (preferences != NULL && preferences->urp_auth_items != NULL)
28bab8
-    {
28bab8
-        struct dump_dir *dd = dd_opendir(dump_dir_path, DD_OPEN_READONLY);
28bab8
-        if (!dd)
28bab8
-            xfunc_die(); /* dd_opendir() already printed an error message */
28bab8
-
28bab8
-        GList *iter = preferences->urp_auth_items;
28bab8
-        for ( ; iter != NULL; iter = g_list_next(iter))
28bab8
-        {
28bab8
-            const char *key = (const char *)iter->data;
28bab8
-            char *value = dd_load_text_ext(dd, key,
28bab8
-                    DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE | DD_FAIL_QUIETLY_ENOENT);
28bab8
-
28bab8
-            if (value == NULL)
28bab8
-            {
28bab8
-                perror_msg("Cannot include '%s' in 'auth'", key);
28bab8
-                continue;
28bab8
-            }
28bab8
-
28bab8
-            sr_report_add_auth(report, key, value);
28bab8
-        }
28bab8
-
28bab8
-        dd_close(dd);
28bab8
-    }
28bab8
-
28bab8
-    char *json_ureport = sr_report_to_json(report);
28bab8
-    sr_report_free(report);
28bab8
-
28bab8
-    return json_ureport;
28bab8
-}
28bab8
-
28bab8
-char *ureport_from_dump_dir(const char *dump_dir_path)
28bab8
-{
28bab8
-    return ureport_from_dump_dir_ext(dump_dir_path, /*no preferences*/NULL);
28bab8
-}
28bab8
-
28bab8
-char *new_json_attachment(const char *bthash, const char *type, const char *data)
28bab8
-{
28bab8
-    struct json_object *attachment = json_object_new_object();
28bab8
-    if (!attachment)
28bab8
-        die_out_of_memory();
28bab8
-
28bab8
-    ureport_add_str(attachment, "bthash", bthash);
28bab8
-    ureport_add_str(attachment, "type", type);
28bab8
-    ureport_add_str(attachment, "data", data);
28bab8
-
28bab8
-    char *result = xstrdup(json_object_to_json_string(attachment));
28bab8
-    json_object_put(attachment);
28bab8
-
28bab8
-    return result;
28bab8
-}
28bab8
-
28bab8
-struct post_state *post_ureport(const char *json, struct ureport_server_config *config)
28bab8
-{
28bab8
-    int flags = POST_WANT_BODY | POST_WANT_ERROR_MSG;
28bab8
-
28bab8
-    if (config->ur_ssl_verify)
28bab8
-        flags |= POST_WANT_SSL_VERIFY;
28bab8
-
28bab8
-    struct post_state *post_state = new_post_state(flags);
28bab8
-
28bab8
-    if (config->ur_client_cert && config->ur_client_key)
28bab8
-    {
28bab8
-        post_state->client_cert_path = config->ur_client_cert;
28bab8
-        post_state->client_key_path = config->ur_client_key;
28bab8
-    }
28bab8
-
28bab8
-    char **headers = xmalloc(sizeof(char *) * (3 + size_map_string(config->ur_http_headers)));
28bab8
-    headers[0] = (char *)"Accept: application/json";
28bab8
-    headers[1] = (char *)"Connection: close";
28bab8
-    headers[2] = NULL;
28bab8
-
28bab8
-    if (config->ur_http_headers != NULL)
28bab8
-    {
28bab8
-        unsigned i = 2;
28bab8
-        const char *header;
28bab8
-        const char *value;
28bab8
-        map_string_iter_t iter;
28bab8
-        init_map_string_iter(&iter, config->ur_http_headers);
28bab8
-        while (next_map_string_iter(&iter, &header, &value))
28bab8
-            headers[i++] = xasprintf("%s: %s", header, value);
28bab8
-        headers[i] = NULL;
28bab8
-    }
28bab8
-
28bab8
-    post_string_as_form_data(post_state, config->ur_url, "application/json",
28bab8
-                    (const char **)headers, json);
28bab8
-
28bab8
-    /* Client authentication failed. Try again without client auth.
28bab8
-     * CURLE_SSL_CONNECT_ERROR - cert not found/server doesnt trust the CA
28bab8
-     * CURLE_SSL_CERTPROBLEM - malformed certificate/no permission
28bab8
-     */
28bab8
-    if ((post_state->curl_result == CURLE_SSL_CONNECT_ERROR
28bab8
-         || post_state->curl_result == CURLE_SSL_CERTPROBLEM)
28bab8
-            && config->ur_client_cert && config->ur_client_key)
28bab8
-    {
28bab8
-        warn_msg("Authentication failed. Retrying unauthenticated.");
28bab8
-        free_post_state(post_state);
28bab8
-        post_state = new_post_state(flags);
28bab8
-
28bab8
-        post_string_as_form_data(post_state, config->ur_url, "application/json",
28bab8
-                         (const char **)headers, json);
28bab8
-
28bab8
-    }
28bab8
-
28bab8
-    for (unsigned i = size_map_string(config->ur_http_headers); i != 0; --i)
28bab8
-        free(headers[i + 1]);
28bab8
-    free(headers);
28bab8
-
28bab8
-    return post_state;
28bab8
-}
28bab8
-
28bab8
-struct post_state *ureport_attach_rhbz(const char *bthash, int rhbz_bug_id,
28bab8
-                                       struct ureport_server_config *config)
28bab8
-{
28bab8
-    char *str_bug_id = xasprintf("%d", rhbz_bug_id);
28bab8
-    char *json_attachment = new_json_attachment(bthash, "RHBZ", str_bug_id);
28bab8
-    struct post_state *post_state = post_ureport(json_attachment, config);
28bab8
-    free(str_bug_id);
28bab8
-    free(json_attachment);
28bab8
-
28bab8
-    return post_state;
28bab8
-}
28bab8
-
28bab8
-struct post_state *ureport_attach_email(const char *bthash, const char *email,
28bab8
-                                       struct ureport_server_config *config)
28bab8
-{
28bab8
-    char *json_attachment = new_json_attachment(bthash, "email", email);
28bab8
-    struct post_state *post_state = post_ureport(json_attachment, config);
28bab8
-    free(json_attachment);
28bab8
-
28bab8
-    return post_state;
28bab8
-}
28bab8
diff --git a/src/lib/ureport.c b/src/lib/ureport.c
28bab8
new file mode 100644
28bab8
index 0000000..761fe62
28bab8
--- /dev/null
28bab8
+++ b/src/lib/ureport.c
28bab8
@@ -0,0 +1,180 @@
28bab8
+/*
28bab8
+    Copyright (C) 2012,2014  ABRT team
28bab8
+    Copyright (C) 2012,2014  RedHat Inc
28bab8
+
28bab8
+    This program is free software; you can redistribute it and/or modify
28bab8
+    it under the terms of the GNU General Public License as published by
28bab8
+    the Free Software Foundation; either version 2 of the License, or
28bab8
+    (at your option) any later version.
28bab8
+
28bab8
+    This program is distributed in the hope that it will be useful,
28bab8
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
28bab8
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28bab8
+    GNU General Public License for more details.
28bab8
+
28bab8
+    You should have received a copy of the GNU General Public License along
28bab8
+    with this program; if not, write to the Free Software Foundation, Inc.,
28bab8
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28bab8
+*/
28bab8
+
28bab8
+#include <json.h>
28bab8
+
28bab8
+#include <satyr/abrt.h>
28bab8
+#include <satyr/report.h>
28bab8
+
28bab8
+#include "internal_libreport.h"
28bab8
+#include "ureport.h"
28bab8
+#include "libreport_curl.h"
28bab8
+
28bab8
+
28bab8
+static void ureport_add_str(struct json_object *ur, const char *key,
28bab8
+                            const char *s)
28bab8
+{
28bab8
+    struct json_object *jstring = json_object_new_string(s);
28bab8
+    if (!jstring)
28bab8
+        die_out_of_memory();
28bab8
+
28bab8
+    json_object_object_add(ur, key, jstring);
28bab8
+}
28bab8
+
28bab8
+char *ureport_from_dump_dir_ext(const char *dump_dir_path, const struct ureport_preferences *preferences)
28bab8
+{
28bab8
+    char *error_message;
28bab8
+    struct sr_report *report = sr_abrt_report_from_dir(dump_dir_path,
28bab8
+                                                       &error_message);
28bab8
+
28bab8
+    if (!report)
28bab8
+        error_msg_and_die("%s", error_message);
28bab8
+
28bab8
+    if (preferences != NULL && preferences->urp_auth_items != NULL)
28bab8
+    {
28bab8
+        struct dump_dir *dd = dd_opendir(dump_dir_path, DD_OPEN_READONLY);
28bab8
+        if (!dd)
28bab8
+            xfunc_die(); /* dd_opendir() already printed an error message */
28bab8
+
28bab8
+        GList *iter = preferences->urp_auth_items;
28bab8
+        for ( ; iter != NULL; iter = g_list_next(iter))
28bab8
+        {
28bab8
+            const char *key = (const char *)iter->data;
28bab8
+            char *value = dd_load_text_ext(dd, key,
28bab8
+                    DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE | DD_FAIL_QUIETLY_ENOENT);
28bab8
+
28bab8
+            if (value == NULL)
28bab8
+            {
28bab8
+                perror_msg("Cannot include '%s' in 'auth'", key);
28bab8
+                continue;
28bab8
+            }
28bab8
+
28bab8
+            sr_report_add_auth(report, key, value);
28bab8
+        }
28bab8
+
28bab8
+        dd_close(dd);
28bab8
+    }
28bab8
+
28bab8
+    char *json_ureport = sr_report_to_json(report);
28bab8
+    sr_report_free(report);
28bab8
+
28bab8
+    return json_ureport;
28bab8
+}
28bab8
+
28bab8
+char *ureport_from_dump_dir(const char *dump_dir_path)
28bab8
+{
28bab8
+    return ureport_from_dump_dir_ext(dump_dir_path, /*no preferences*/NULL);
28bab8
+}
28bab8
+
28bab8
+static char *new_json_attachment(const char *bthash, const char *type, const char *data)
28bab8
+{
28bab8
+    struct json_object *attachment = json_object_new_object();
28bab8
+    if (!attachment)
28bab8
+        die_out_of_memory();
28bab8
+
28bab8
+    ureport_add_str(attachment, "bthash", bthash);
28bab8
+    ureport_add_str(attachment, "type", type);
28bab8
+    ureport_add_str(attachment, "data", data);
28bab8
+
28bab8
+    char *result = xstrdup(json_object_to_json_string(attachment));
28bab8
+    json_object_put(attachment);
28bab8
+
28bab8
+    return result;
28bab8
+}
28bab8
+
28bab8
+struct post_state *ureport_post(const char *json, struct ureport_server_config *config)
28bab8
+{
28bab8
+    int flags = POST_WANT_BODY | POST_WANT_ERROR_MSG;
28bab8
+
28bab8
+    if (config->ur_ssl_verify)
28bab8
+        flags |= POST_WANT_SSL_VERIFY;
28bab8
+
28bab8
+    struct post_state *post_state = new_post_state(flags);
28bab8
+
28bab8
+    if (config->ur_client_cert && config->ur_client_key)
28bab8
+    {
28bab8
+        post_state->client_cert_path = config->ur_client_cert;
28bab8
+        post_state->client_key_path = config->ur_client_key;
28bab8
+    }
28bab8
+
28bab8
+    char **headers = xmalloc(sizeof(char *) * (3 + size_map_string(config->ur_http_headers)));
28bab8
+    headers[0] = (char *)"Accept: application/json";
28bab8
+    headers[1] = (char *)"Connection: close";
28bab8
+    headers[2] = NULL;
28bab8
+
28bab8
+    if (config->ur_http_headers != NULL)
28bab8
+    {
28bab8
+        unsigned i = 2;
28bab8
+        const char *header;
28bab8
+        const char *value;
28bab8
+        map_string_iter_t iter;
28bab8
+        init_map_string_iter(&iter, config->ur_http_headers);
28bab8
+        while (next_map_string_iter(&iter, &header, &value))
28bab8
+            headers[i++] = xasprintf("%s: %s", header, value);
28bab8
+        headers[i] = NULL;
28bab8
+    }
28bab8
+
28bab8
+    post_string_as_form_data(post_state, config->ur_url, "application/json",
28bab8
+                    (const char **)headers, json);
28bab8
+
28bab8
+    /* Client authentication failed. Try again without client auth.
28bab8
+     * CURLE_SSL_CONNECT_ERROR - cert not found/server doesnt trust the CA
28bab8
+     * CURLE_SSL_CERTPROBLEM - malformed certificate/no permission
28bab8
+     */
28bab8
+    if ((post_state->curl_result == CURLE_SSL_CONNECT_ERROR
28bab8
+         || post_state->curl_result == CURLE_SSL_CERTPROBLEM)
28bab8
+            && config->ur_client_cert && config->ur_client_key)
28bab8
+    {
28bab8
+        warn_msg("Authentication failed. Retrying unauthenticated.");
28bab8
+        free_post_state(post_state);
28bab8
+        post_state = new_post_state(flags);
28bab8
+
28bab8
+        post_string_as_form_data(post_state, config->ur_url, "application/json",
28bab8
+                         (const char **)headers, json);
28bab8
+
28bab8
+    }
28bab8
+
28bab8
+    for (unsigned i = size_map_string(config->ur_http_headers); i != 0; --i)
28bab8
+        free(headers[i + 1]);
28bab8
+    free(headers);
28bab8
+
28bab8
+    return post_state;
28bab8
+}
28bab8
+
28bab8
+struct post_state *ureport_attach_rhbz(const char *bthash, int rhbz_bug_id,
28bab8
+                                       struct ureport_server_config *config)
28bab8
+{
28bab8
+    char *str_bug_id = xasprintf("%d", rhbz_bug_id);
28bab8
+    char *json_attachment = new_json_attachment(bthash, "RHBZ", str_bug_id);
28bab8
+    struct post_state *post_state = ureport_post(json_attachment, config);
28bab8
+    free(str_bug_id);
28bab8
+    free(json_attachment);
28bab8
+
28bab8
+    return post_state;
28bab8
+}
28bab8
+
28bab8
+struct post_state *ureport_attach_email(const char *bthash, const char *email,
28bab8
+                                       struct ureport_server_config *config)
28bab8
+{
28bab8
+    char *json_attachment = new_json_attachment(bthash, "email", email);
28bab8
+    struct post_state *post_state = ureport_post(json_attachment, config);
28bab8
+    free(json_attachment);
28bab8
+
28bab8
+    return post_state;
28bab8
+}
28bab8
diff --git a/src/lib/ureport.h b/src/lib/ureport.h
28bab8
deleted file mode 100644
28bab8
index 319aca9..0000000
28bab8
--- a/src/lib/ureport.h
28bab8
+++ /dev/null
28bab8
@@ -1,76 +0,0 @@
28bab8
-/*
28bab8
-    Copyright (C) 2012  ABRT team
28bab8
-    Copyright (C) 2012  RedHat Inc
28bab8
-
28bab8
-    This program is free software; you can redistribute it and/or modify
28bab8
-    it under the terms of the GNU General Public License as published by
28bab8
-    the Free Software Foundation; either version 2 of the License, or
28bab8
-    (at your option) any later version.
28bab8
-
28bab8
-    This program is distributed in the hope that it will be useful,
28bab8
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
28bab8
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28bab8
-    GNU General Public License for more details.
28bab8
-
28bab8
-    You should have received a copy of the GNU General Public License along
28bab8
-    with this program; if not, write to the Free Software Foundation, Inc.,
28bab8
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28bab8
-*/
28bab8
-#ifndef UREPORT_H_
28bab8
-#define UREPORT_H_
28bab8
-
28bab8
-#include "problem_data.h"
28bab8
-
28bab8
-#ifdef __cplusplus
28bab8
-extern "C" {
28bab8
-#endif
28bab8
-
28bab8
-/*
28bab8
- * uReport generation configuration
28bab8
- */
28bab8
-struct ureport_preferences
28bab8
-{
28bab8
-    GList *urp_auth_items;  ///< list of file names included in 'auth' key
28bab8
-};
28bab8
-
28bab8
-/*
28bab8
- * uReport server configuration
28bab8
- */
28bab8
-struct ureport_server_config
28bab8
-{
28bab8
-    const char *ur_url;   ///< Web service URL
28bab8
-    bool ur_ssl_verify;   ///< Verify HOST and PEER certificates
28bab8
-    char *ur_client_cert; ///< Path to certificate used for client
28bab8
-                          ///< authentication (or NULL)
28bab8
-    char *ur_client_key;  ///< Private key for the certificate
28bab8
-    map_string_t *ur_http_headers; ///< Additional HTTP headers
28bab8
-
28bab8
-    struct ureport_preferences ur_prefs; ///< configuration for uReport generation
28bab8
-};
28bab8
-
28bab8
-struct abrt_post_state;
28bab8
-
28bab8
-#define post_ureport libreport_post_ureport
28bab8
-struct post_state *post_ureport(const char *json_ureport,
28bab8
-                                struct ureport_server_config *config);
28bab8
-
28bab8
-#define ureport_attach_rhbz libreport_ureport_attach_rhbz
28bab8
-struct post_state *ureport_attach_rhbz(const char *bthash, int rhbz_bug_id,
28bab8
-                                       struct ureport_server_config *config);
28bab8
-
28bab8
-#define ureport_attach_email libreport_ureport_attach_email
28bab8
-struct post_state *ureport_attach_email(const char *bthash, const char *email,
28bab8
-                                        struct ureport_server_config *config);
28bab8
-
28bab8
-#define ureport_from_dump_dir libreport_ureport_from_dump_dir
28bab8
-char *ureport_from_dump_dir(const char *dump_dir_path);
28bab8
-
28bab8
-#define ureport_from_dump_dir_ext libreport_ureport_from_dump_dir_ext
28bab8
-char *ureport_from_dump_dir_ext(const char *dump_dir_path,
28bab8
-                                const struct ureport_preferences *preferences);
28bab8
-
28bab8
-#ifdef __cplusplus
28bab8
-}
28bab8
-#endif
28bab8
-
28bab8
-#endif
28bab8
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
28bab8
index 7ec5219..7ec08d7 100644
28bab8
--- a/src/plugins/Makefile.am
28bab8
+++ b/src/plugins/Makefile.am
28bab8
@@ -250,15 +250,17 @@ endif
28bab8
 
28bab8
 if BUILD_UREPORT
28bab8
 reporter_ureport_SOURCES = \
28bab8
-    ureport.c
28bab8
+    reporter-ureport.c
28bab8
 reporter_ureport_CPPFLAGS = \
28bab8
     -I$(srcdir)/../include \
28bab8
     -I$(srcdir)/../lib \
28bab8
+    $(JSON_C_CFLAGS) \
28bab8
     $(GLIB_CFLAGS) \
28bab8
     $(LIBREPORT_CFLAGS) \
28bab8
     -DPLUGINS_CONF_DIR=\"$(REPORT_PLUGINS_CONF_DIR)\" \
28bab8
     -D_GNU_SOURCE
28bab8
 reporter_ureport_LDADD = \
28bab8
+    $(JSON_C_LIBS) \
28bab8
     ../lib/libreport.la \
28bab8
     ../lib/libreport-web.la
28bab8
 endif
28bab8
diff --git a/src/plugins/reporter-ureport.c b/src/plugins/reporter-ureport.c
28bab8
new file mode 100644
28bab8
index 0000000..d827c7d
28bab8
--- /dev/null
28bab8
+++ b/src/plugins/reporter-ureport.c
28bab8
@@ -0,0 +1,777 @@
28bab8
+/*
28bab8
+    Copyright (C) 2012  ABRT Team
28bab8
+    Copyright (C) 2012  RedHat inc.
28bab8
+
28bab8
+    This program is free software; you can redistribute it and/or modify
28bab8
+    it under the terms of the GNU General Public License as published by
28bab8
+    the Free Software Foundation; either version 2 of the License, or
28bab8
+    (at your option) any later version.
28bab8
+
28bab8
+    This program is distributed in the hope that it will be useful,
28bab8
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
28bab8
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28bab8
+    GNU General Public License for more details.
28bab8
+
28bab8
+    You should have received a copy of the GNU General Public License along
28bab8
+    with this program; if not, write to the Free Software Foundation, Inc.,
28bab8
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28bab8
+*/
28bab8
+
28bab8
+#include <json.h>
28bab8
+#include "internal_libreport.h"
28bab8
+#include "ureport.h"
28bab8
+#include "libreport_curl.h"
28bab8
+
28bab8
+#define CONF_FILE_PATH PLUGINS_CONF_DIR"/ureport.conf"
28bab8
+
28bab8
+#define REPORT_URL_SFX "reports/new/"
28bab8
+#define ATTACH_URL_SFX "reports/attach/"
28bab8
+#define BTHASH_URL_SFX "reports/bthash/"
28bab8
+
28bab8
+#define RHSM_CERT_PATH "/etc/pki/consumer/cert.pem"
28bab8
+#define RHSM_KEY_PATH "/etc/pki/consumer/key.pem"
28bab8
+
28bab8
+#define RHAP_PEM_DIR_PATH "/etc/pki/entitlement"
28bab8
+#define RHAP_ENT_DATA_BEGIN_TAG "-----BEGIN ENTITLEMENT DATA-----"
28bab8
+#define RHAP_ENT_DATA_END_TAG "-----END ENTITLEMENT DATA-----"
28bab8
+#define RHAP_SIG_DATA_BEGIN_TAG "-----BEGIN RSA SIGNATURE-----"
28bab8
+#define RHAP_SIG_DATA_END_TAG "-----END RSA SIGNATURE-----"
28bab8
+
28bab8
+#define VALUE_FROM_CONF(opt, var, tr) do { const char *value = getenv("uReport_"opt); \
28bab8
+        if (!value) { value = get_map_string_item_or_NULL(settings, opt); } if (value) { var = tr(value); } \
28bab8
+    } while(0)
28bab8
+
28bab8
+static char *puppet_config_print(const char *key)
28bab8
+{
28bab8
+    char *command = xasprintf("puppet config print %s", key);
28bab8
+    char *result = run_in_shell_and_save_output(0, command, NULL, NULL);
28bab8
+    free(command);
28bab8
+
28bab8
+    /* run_in_shell_and_save_output always returns non-NULL */
28bab8
+    if (result[0] != '/')
28bab8
+        goto error;
28bab8
+
28bab8
+    char *newline = strchrnul(result, '\n');
28bab8
+    if (!newline)
28bab8
+        goto error;
28bab8
+
28bab8
+    *newline = '\0';
28bab8
+    return result;
28bab8
+error:
28bab8
+    free(result);
28bab8
+    error_msg_and_die("Unable to determine puppet %s path (puppet not installed?)", key);
28bab8
+}
28bab8
+
28bab8
+static void parse_client_auth_paths(struct ureport_server_config *config, const char *client_auth)
28bab8
+{
28bab8
+    if (client_auth == NULL)
28bab8
+        return;
28bab8
+
28bab8
+    if (strcmp(client_auth, "") == 0)
28bab8
+    {
28bab8
+        config->ur_client_cert = NULL;
28bab8
+        config->ur_client_key = NULL;
28bab8
+        log_notice("Not using client authentication");
28bab8
+    }
28bab8
+    else if (strcmp(client_auth, "rhsm") == 0)
28bab8
+    {
28bab8
+        config->ur_client_cert = xstrdup(RHSM_CERT_PATH);
28bab8
+        config->ur_client_key = xstrdup(RHSM_KEY_PATH);
28bab8
+    }
28bab8
+    else if (strcmp(client_auth, "rhsm-entitlement") == 0)
28bab8
+    {
28bab8
+        GList *certs = get_file_list(RHAP_PEM_DIR_PATH, "pem");
28bab8
+        if (g_list_length(certs) != 2)
28bab8
+        {
28bab8
+            log_notice(RHAP_PEM_DIR_PATH" does not contain unique cert-key files pair");
28bab8
+            log_notice("Not using client authentication");
28bab8
+            return;
28bab8
+        }
28bab8
+
28bab8
+        const char *cert = NULL;
28bab8
+        const char *key = NULL;
28bab8
+
28bab8
+        file_obj_t *fst = (file_obj_t *)certs->data;
28bab8
+        file_obj_t *scn = (file_obj_t *)certs->next->data;
28bab8
+
28bab8
+        if (strlen(fo_get_filename(fst)) < strlen(fo_get_filename(scn)))
28bab8
+        {
28bab8
+            cert = fo_get_filename(fst);
28bab8
+            key = fo_get_filename(scn);
28bab8
+
28bab8
+            config->ur_client_cert = xstrdup(fo_get_fullpath(fst));
28bab8
+            config->ur_client_key = xstrdup(fo_get_fullpath(scn));
28bab8
+        }
28bab8
+        else
28bab8
+        {
28bab8
+            cert = fo_get_filename(scn);
28bab8
+            key = fo_get_filename(fst);
28bab8
+
28bab8
+            config->ur_client_cert = xstrdup(fo_get_fullpath(scn));
28bab8
+            config->ur_client_key = xstrdup(fo_get_fullpath(fst));
28bab8
+        }
28bab8
+
28bab8
+        const bool iscomplement = prefixcmp(key, cert) != 0 || strcmp("-key", key + strlen(cert)) != 0;
28bab8
+        g_list_free_full(certs, (GDestroyNotify)free_file_obj);
28bab8
+
28bab8
+        if (iscomplement)
28bab8
+        {
28bab8
+            log_notice("Key file '%s' isn't complement to cert file '%s'",
28bab8
+                    config->ur_client_key, config->ur_client_cert);
28bab8
+            log_notice("Not using client authentication");
28bab8
+
28bab8
+            free(config->ur_client_cert);
28bab8
+            free(config->ur_client_key);
28bab8
+            config->ur_client_cert = NULL;
28bab8
+            config->ur_client_key = NULL;
28bab8
+
28bab8
+            return;
28bab8
+        }
28bab8
+
28bab8
+        char *certdata = xmalloc_open_read_close(config->ur_client_cert, /*no size limit*/NULL);
28bab8
+        if (certdata != NULL)
28bab8
+        {
28bab8
+            char *ent_data = xstrdup_between(certdata,
28bab8
+                    RHAP_ENT_DATA_BEGIN_TAG, RHAP_ENT_DATA_END_TAG);
28bab8
+
28bab8
+            char *sig_data = xstrdup_between(certdata,
28bab8
+                    RHAP_SIG_DATA_BEGIN_TAG, RHAP_SIG_DATA_END_TAG);
28bab8
+
28bab8
+            if (ent_data != NULL && sig_data != NULL)
28bab8
+            {
28bab8
+                ent_data = strremovech(ent_data, '\n');
28bab8
+                insert_map_string(config->ur_http_headers,
28bab8
+                        xstrdup("X-RH-Entitlement-Data"),
28bab8
+                        xasprintf(RHAP_ENT_DATA_BEGIN_TAG"%s"RHAP_ENT_DATA_END_TAG, ent_data));
28bab8
+
28bab8
+                sig_data = strremovech(sig_data, '\n');
28bab8
+                insert_map_string(config->ur_http_headers,
28bab8
+                        xstrdup("X-RH-Entitlement-Sig"),
28bab8
+                        xasprintf(RHAP_SIG_DATA_BEGIN_TAG"%s"RHAP_SIG_DATA_END_TAG, sig_data));
28bab8
+            }
28bab8
+            else
28bab8
+            {
28bab8
+                log_notice("Cert file '%s' doesn't contain Entitlement and RSA Signature sections", config->ur_client_cert);
28bab8
+                log_notice("Not using HTTP authentication headers");
28bab8
+            }
28bab8
+
28bab8
+            free(sig_data);
28bab8
+            free(ent_data);
28bab8
+            free(certdata);
28bab8
+        }
28bab8
+    }
28bab8
+    else if (strcmp(client_auth, "puppet") == 0)
28bab8
+    {
28bab8
+        config->ur_client_cert = puppet_config_print("hostcert");
28bab8
+        config->ur_client_key = puppet_config_print("hostprivkey");
28bab8
+    }
28bab8
+    else
28bab8
+    {
28bab8
+        char *scratch = xstrdup(client_auth);
28bab8
+        config->ur_client_cert = xstrdup(strtok(scratch, ":"));
28bab8
+        config->ur_client_key = xstrdup(strtok(NULL, ":"));
28bab8
+        free(scratch);
28bab8
+        if (config->ur_client_cert == NULL || config->ur_client_key == NULL)
28bab8
+            error_msg_and_die("Invalid client authentication specification");
28bab8
+    }
28bab8
+
28bab8
+    if (config->ur_client_cert && config->ur_client_key)
28bab8
+    {
28bab8
+        log_notice("Using client certificate: %s", config->ur_client_cert);
28bab8
+        log_notice("Using client private key: %s", config->ur_client_key);
28bab8
+    }
28bab8
+}
28bab8
+
28bab8
+/*
28bab8
+ * Loads uReport configuration from various sources.
28bab8
+ *
28bab8
+ * Replaces a value of an already configured option only if the
28bab8
+ * option was found in a configuration source.
28bab8
+ *
28bab8
+ * @param config a server configuration to be populated
28bab8
+ */
28bab8
+static void load_ureport_server_config(struct ureport_server_config *config, map_string_t *settings)
28bab8
+{
28bab8
+    VALUE_FROM_CONF("URL", config->ur_url, (const char *));
28bab8
+    VALUE_FROM_CONF("SSLVerify", config->ur_ssl_verify, string_to_bool);
28bab8
+
28bab8
+    bool include_auth = false;
28bab8
+    VALUE_FROM_CONF("IncludeAuthData", include_auth, string_to_bool);
28bab8
+
28bab8
+    if (include_auth)
28bab8
+    {
28bab8
+        const char *auth_items = NULL;
28bab8
+        VALUE_FROM_CONF("AuthDataItems", auth_items, (const char *));
28bab8
+        config->ur_prefs.urp_auth_items = parse_list(auth_items);
28bab8
+
28bab8
+        if (config->ur_prefs.urp_auth_items == NULL)
28bab8
+            log_warning("IncludeAuthData set to 'yes' but AuthDataItems is empty.");
28bab8
+    }
28bab8
+
28bab8
+    const char *client_auth = NULL;
28bab8
+    VALUE_FROM_CONF("SSLClientAuth", client_auth, (const char *));
28bab8
+    parse_client_auth_paths(config, client_auth);
28bab8
+}
28bab8
+
28bab8
+struct ureport_server_response {
28bab8
+    bool is_error;
28bab8
+    char *value;
28bab8
+    char *message;
28bab8
+    char *bthash;
28bab8
+    GList *reported_to_list;
28bab8
+    char *solution;
28bab8
+};
28bab8
+
28bab8
+void free_ureport_server_response(struct ureport_server_response *resp)
28bab8
+{
28bab8
+    if (!resp)
28bab8
+        return;
28bab8
+
28bab8
+    free(resp->solution);
28bab8
+    g_list_free_full(resp->reported_to_list, g_free);
28bab8
+    free(resp->bthash);
28bab8
+    free(resp->message);
28bab8
+    free(resp->value);
28bab8
+    free(resp);
28bab8
+}
28bab8
+
28bab8
+static char *parse_solution_from_json_list(struct json_object *list, GList **reported_to)
28bab8
+{
28bab8
+    json_object *list_elem, *struct_elem;
28bab8
+    const char *cause, *note, *url;
28bab8
+    struct strbuf *solution_buf = strbuf_new();
28bab8
+
28bab8
+    const unsigned length = json_object_array_length(list);
28bab8
+
28bab8
+    const char *one_format = _("Your problem seems to be caused by %s\n\n%s\n");
28bab8
+    if (length > 1)
28bab8
+    {
28bab8
+        strbuf_append_str(solution_buf, _("Your problem seems to be caused by one of the following:\n"));
28bab8
+        one_format = "\n* %s\n\n%s\n";
28bab8
+    }
28bab8
+
28bab8
+    bool empty = true;
28bab8
+    for (unsigned i = 0; i < length; ++i)
28bab8
+    {
28bab8
+        list_elem = json_object_array_get_idx(list, i);
28bab8
+        if (!list_elem)
28bab8
+            continue;
28bab8
+
28bab8
+        if (!json_object_object_get_ex(list_elem, "cause", &struct_elem))
28bab8
+            continue;
28bab8
+
28bab8
+        cause = json_object_get_string(struct_elem);
28bab8
+            continue;
28bab8
+
28bab8
+        if (!json_object_object_get_ex(list_elem, "note", &struct_elem))
28bab8
+            continue;
28bab8
+
28bab8
+        note = json_object_get_string(struct_elem);
28bab8
+        if (!note)
28bab8
+            continue;
28bab8
+
28bab8
+        empty = false;
28bab8
+        strbuf_append_strf(solution_buf, one_format, cause, note);
28bab8
+
28bab8
+        if (!json_object_object_get_ex(list_elem, "url", &struct_elem))
28bab8
+            continue;
28bab8
+
28bab8
+        url = json_object_get_string(struct_elem);
28bab8
+        if (url)
28bab8
+        {
28bab8
+            char *reported_to_line = xasprintf("%s: URL=%s", cause, url);
28bab8
+            *reported_to = g_list_append(*reported_to, reported_to_line);
28bab8
+        }
28bab8
+    }
28bab8
+
28bab8
+    if (empty)
28bab8
+    {
28bab8
+        strbuf_free(solution_buf);
28bab8
+        return NULL;
28bab8
+    }
28bab8
+
28bab8
+    return strbuf_free_nobuf(solution_buf);
28bab8
+}
28bab8
+
28bab8
+/* reported_to json element should be a list of structures
28bab8
+{ "reporter": "Bugzilla",
28bab8
+  "type": "url",
28bab8
+  "value": "https://bugzilla.redhat.com/show_bug.cgi?id=XYZ" } */
28bab8
+static GList *parse_reported_to_from_json_list(struct json_object *list)
28bab8
+{
28bab8
+    int i;
28bab8
+    json_object *list_elem, *struct_elem;
28bab8
+    const char *reporter, *value, *type;
28bab8
+    char *reported_to_line, *prefix;
28bab8
+    GList *result = NULL;
28bab8
+
28bab8
+    for (i = 0; i < json_object_array_length(list); ++i)
28bab8
+    {
28bab8
+        prefix = NULL;
28bab8
+        list_elem = json_object_array_get_idx(list, i);
28bab8
+        if (!list_elem)
28bab8
+            continue;
28bab8
+
28bab8
+        if (!json_object_object_get_ex(list_elem, "reporter", &struct_elem))
28bab8
+            continue;
28bab8
+
28bab8
+        reporter = json_object_get_string(struct_elem);
28bab8
+        if (!reporter)
28bab8
+            continue;
28bab8
+
28bab8
+        if (!json_object_object_get_ex(list_elem, "value", &struct_elem))
28bab8
+            continue;
28bab8
+
28bab8
+        value = json_object_get_string(struct_elem);
28bab8
+        if (!value)
28bab8
+            continue;
28bab8
+
28bab8
+        if (!json_object_object_get_ex(list_elem, "type", &struct_elem))
28bab8
+            continue;
28bab8
+
28bab8
+        type = json_object_get_string(struct_elem);
28bab8
+        if (type)
28bab8
+        {
28bab8
+            if (strcasecmp("url", type) == 0)
28bab8
+                prefix = xstrdup("URL=");
28bab8
+            else if (strcasecmp("bthash", type) == 0)
28bab8
+                prefix = xstrdup("BTHASH=");
28bab8
+        }
28bab8
+
28bab8
+        if (!prefix)
28bab8
+            prefix = xstrdup("");
28bab8
+
28bab8
+        reported_to_line = xasprintf("%s: %s%s", reporter, prefix, value);
28bab8
+        free(prefix);
28bab8
+
28bab8
+        result = g_list_append(result, reported_to_line);
28bab8
+    }
28bab8
+
28bab8
+    return result;
28bab8
+}
28bab8
+
28bab8
+/*
28bab8
+ * Reponse samples:
28bab8
+ * {"error":"field 'foo' is required"}
28bab8
+ * {"response":"true"}
28bab8
+ * {"response":"false"}
28bab8
+ */
28bab8
+static struct ureport_server_response *ureport_server_parse_json(json_object *json)
28bab8
+{
28bab8
+    json_object *obj = NULL;
28bab8
+    if (json_object_object_get_ex(json, "error", &obj))
28bab8
+    {
28bab8
+        struct ureport_server_response *out_response = xzalloc(sizeof(*out_response));
28bab8
+        out_response->is_error = true;
28bab8
+        /*
28bab8
+         * Used to use json_object_to_json_string(obj), but it returns
28bab8
+         * the string in quote marks (") - IOW, json-formatted string.
28bab8
+         */
28bab8
+        out_response->value = xstrdup(json_object_get_string(obj));
28bab8
+        return out_response;
28bab8
+    }
28bab8
+
28bab8
+    if (json_object_object_get_ex(json, "result", &obj))
28bab8
+    {
28bab8
+        struct ureport_server_response *out_response = xzalloc(sizeof(*out_response));
28bab8
+        out_response->value = xstrdup(json_object_get_string(obj));
28bab8
+
28bab8
+        json_object *message = NULL;
28bab8
+        if (json_object_object_get_ex(json, "message", &message))
28bab8
+            out_response->message = xstrdup(json_object_get_string(message));
28bab8
+
28bab8
+        json_object *bthash = NULL;
28bab8
+        if (json_object_object_get_ex(json, "bthash", &bthash))
28bab8
+            out_response->bthash = xstrdup(json_object_get_string(bthash));
28bab8
+
28bab8
+        json_object *reported_to_list = NULL;
28bab8
+        if (json_object_object_get_ex(json, "reported_to", &reported_to_list))
28bab8
+            out_response->reported_to_list = parse_reported_to_from_json_list(reported_to_list);
28bab8
+
28bab8
+        json_object *solutions = NULL;
28bab8
+        if (json_object_object_get_ex(json, "solutions", &solutions))
28bab8
+            out_response->solution = parse_solution_from_json_list(solutions, &(out_response->reported_to_list));
28bab8
+
28bab8
+        return out_response;
28bab8
+    }
28bab8
+
28bab8
+    return NULL;
28bab8
+}
28bab8
+
28bab8
+static struct ureport_server_response *get_server_response(post_state_t *post_state, struct ureport_server_config *config)
28bab8
+{
28bab8
+    /* Previously, the condition here was (post_state->errmsg[0] != '\0')
28bab8
+     * however when the server asks for optional client authentication and we do not have the certificates,
28bab8
+     * then post_state->errmsg contains "NSS: client certificate not found (nickname not specified)" even though
28bab8
+     * the request succeeded.
28bab8
+     */
28bab8
+    if (post_state->curl_result != CURLE_OK)
28bab8
+    {
28bab8
+        error_msg(_("Failed to upload uReport to the server '%s' with curl: %s"), config->ur_url, post_state->errmsg);
28bab8
+        return NULL;
28bab8
+    }
28bab8
+
28bab8
+    if (post_state->http_resp_code == 404)
28bab8
+    {
28bab8
+        error_msg(_("The URL '%s' does not exist (got error 404 from server)"), config->ur_url);
28bab8
+        return NULL;
28bab8
+    }
28bab8
+
28bab8
+    if (post_state->http_resp_code == 500)
28bab8
+    {
28bab8
+        error_msg(_("The server at '%s' encountered an internal error (got error 500)"), config->ur_url);
28bab8
+        return NULL;
28bab8
+    }
28bab8
+
28bab8
+    if (post_state->http_resp_code == 503)
28bab8
+    {
28bab8
+        error_msg(_("The server at '%s' currently can't handle the request (got error 503)"), config->ur_url);
28bab8
+        return NULL;
28bab8
+    }
28bab8
+
28bab8
+    if (post_state->http_resp_code != 202
28bab8
+            && post_state->http_resp_code != 400
28bab8
+            && post_state->http_resp_code != 413)
28bab8
+    {
28bab8
+        /* can't print better error message */
28bab8
+        error_msg(_("Unexpected HTTP response from '%s': %d"), config->ur_url, post_state->http_resp_code);
28bab8
+        log_notice("%s", post_state->body);
28bab8
+        return NULL;
28bab8
+    }
28bab8
+
28bab8
+    json_object *const json = json_tokener_parse(post_state->body);
28bab8
+
28bab8
+    if (is_error(json))
28bab8
+    {
28bab8
+        error_msg(_("Unable to parse response from ureport server at '%s'"), config->ur_url);
28bab8
+        log_notice("%s", post_state->body);
28bab8
+        json_object_put(json);
28bab8
+        return NULL;
28bab8
+    }
28bab8
+
28bab8
+    struct ureport_server_response *response = ureport_server_parse_json(json);
28bab8
+    json_object_put(json);
28bab8
+
28bab8
+    if (!response)
28bab8
+        error_msg(_("The response from '%s' has invalid format"), config->ur_url);
28bab8
+    else if ((post_state->http_resp_code == 202 && response->is_error)
28bab8
+                || (post_state->http_resp_code != 202 && !response->is_error))
28bab8
+    {
28bab8
+        /* HTTP CODE 202 means that call was successful but the response */
28bab8
+        /* has an error message */
28bab8
+        error_msg(_("Type mismatch has been detected in the response from '%s'"), config->ur_url);
28bab8
+    }
28bab8
+
28bab8
+    return response;
28bab8
+}
28bab8
+
28bab8
+typedef post_state_t *(*attach_handler)(const char *, void *, struct ureport_server_config *);
28bab8
+
28bab8
+static post_state_t *wrp_ureport_attach_rhbz(const char *ureport_hash, int *rhbz_bug,
28bab8
+        struct ureport_server_config *config)
28bab8
+{
28bab8
+    return ureport_attach_rhbz(ureport_hash, *rhbz_bug, config);
28bab8
+}
28bab8
+
28bab8
+static bool perform_attach(struct ureport_server_config *config, const char *ureport_hash,
28bab8
+        attach_handler handler, void *args)
28bab8
+{
28bab8
+    char *dest_url = concat_path_file(config->ur_url, ATTACH_URL_SFX);
28bab8
+    const char *old_url = config->ur_url;
28bab8
+    config->ur_url = dest_url;
28bab8
+    post_state_t *post_state = handler(ureport_hash, args, config);
28bab8
+    config->ur_url = old_url;
28bab8
+    free(dest_url);
28bab8
+
28bab8
+    struct ureport_server_response *resp = get_server_response(post_state, config);
28bab8
+    free_post_state(post_state);
28bab8
+    /* don't use str_bo_bool() because we require "true" string */
28bab8
+    const int result = !resp || resp->is_error || strcmp(resp->value,"true") != 0;
28bab8
+
28bab8
+    if (resp && resp->is_error)
28bab8
+    {
28bab8
+        error_msg(_("The server at '%s' responded with an error: '%s'"), config->ur_url, resp->value);
28bab8
+    }
28bab8
+
28bab8
+    free_ureport_server_response(resp);
28bab8
+
28bab8
+    return result;
28bab8
+}
28bab8
+
28bab8
+int main(int argc, char **argv)
28bab8
+{
28bab8
+    setlocale(LC_ALL, "");
28bab8
+#if ENABLE_NLS
28bab8
+    bindtextdomain(PACKAGE, LOCALEDIR);
28bab8
+    textdomain(PACKAGE);
28bab8
+#endif
28bab8
+
28bab8
+    abrt_init(argv);
28bab8
+
28bab8
+    struct ureport_server_config config = {
28bab8
+        .ur_url = NULL,
28bab8
+        .ur_ssl_verify = true,
28bab8
+        .ur_client_cert = NULL,
28bab8
+        .ur_client_key = NULL,
28bab8
+        .ur_http_headers = NULL,
28bab8
+        {
28bab8
+            .urp_auth_items = NULL,
28bab8
+        },
28bab8
+    };
28bab8
+
28bab8
+    config.ur_http_headers = new_map_string();
28bab8
+
28bab8
+    enum {
28bab8
+        OPT_v = 1 << 0,
28bab8
+        OPT_d = 1 << 1,
28bab8
+        OPT_u = 1 << 2,
28bab8
+        OPT_k = 1 << 3,
28bab8
+        OPT_t = 1 << 4,
28bab8
+        OPT_i = 1 << 5,
28bab8
+    };
28bab8
+
28bab8
+    int ret = 1; /* "failure" (for now) */
28bab8
+    bool insecure = !config.ur_ssl_verify;
28bab8
+    const char *conf_file = CONF_FILE_PATH;
28bab8
+    const char *arg_server_url = NULL;
28bab8
+    const char *client_auth = NULL;
28bab8
+    GList *auth_items = NULL;
28bab8
+    const char *dump_dir_path = ".";
28bab8
+    const char *ureport_hash = NULL;
28bab8
+    bool ureport_hash_from_rt = false;
28bab8
+    int rhbz_bug = -1;
28bab8
+    bool rhbz_bug_from_rt = false;
28bab8
+    const char *email_address = NULL;
28bab8
+    bool email_address_from_env = false;
28bab8
+    struct dump_dir *dd = NULL;
28bab8
+    struct options program_options[] = {
28bab8
+        OPT__VERBOSE(&g_verbose),
28bab8
+        OPT__DUMP_DIR(&dump_dir_path),
28bab8
+        OPT_STRING('u', "url", &arg_server_url, "URL", _("Specify server URL")),
28bab8
+        OPT_BOOL('k', "insecure", &insecure,
28bab8
+                          _("Allow insecure connection to ureport server")),
28bab8
+        OPT_STRING('t', "auth", &client_auth, "SOURCE", _("Use client authentication")),
28bab8
+        OPT_LIST('i', "auth_items", &auth_items, "AUTH_ITEMS", _("Additional files included in 'auth' key")),
28bab8
+        OPT_STRING('c', NULL, &conf_file, "FILE", _("Configuration file")),
28bab8
+        OPT_STRING('a', "attach", &ureport_hash, "BTHASH",
28bab8
+                          _("bthash of uReport to attach (conflicts with -A)")),
28bab8
+        OPT_BOOL('A', "attach-rt", &ureport_hash_from_rt,
28bab8
+                          _("attach to a bthash from reported_to (conflicts with -a)")),
28bab8
+        OPT_STRING('e', "email", &email_address, "EMAIL",
28bab8
+                          _("contact e-mail address (requires -a|-A, conflicts with -E)")),
28bab8
+        OPT_BOOL('E', "email-env", &email_address_from_env,
28bab8
+                          _("contact e-mail address from environment or configuration file (requires -a|-A, conflicts with -e)")),
28bab8
+        OPT_INTEGER('b', "bug-id", &rhbz_bug,
28bab8
+                          _("attach RHBZ bug (requires -a|-A, conflicts with -B)")),
28bab8
+        OPT_BOOL('B', "bug-id-rt", &rhbz_bug_from_rt,
28bab8
+                          _("attach last RHBZ bug from reported_to (requires -a|-A, conflicts with -b)")),
28bab8
+        OPT_END(),
28bab8
+    };
28bab8
+
28bab8
+    const char *program_usage_string = _(
28bab8
+        "& [-v] [-c FILE] [-u URL] [-k] [-t SOURCE] [-A -a bthash -B -b bug-id -E -e email] [-d DIR]\n"
28bab8
+        "& [-v] [-c FILE] [-u URL] [-k] [-t SOURCE] [-i AUTH_ITEMS]\\\n"
28bab8
+        "  [-A -a bthash -B -b bug-id -E -e email] [-d DIR]\n"
28bab8
+        "\n"
28bab8
+        "Upload micro report or add an attachment to a micro report\n"
28bab8
+        "\n"
28bab8
+        "Reads the default configuration from "CONF_FILE_PATH
28bab8
+    );
28bab8
+
28bab8
+    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
28bab8
+
28bab8
+    map_string_t *settings = new_map_string();
28bab8
+    load_conf_file(conf_file, settings, /*skip key w/o values:*/ false);
28bab8
+
28bab8
+    load_ureport_server_config(&config, settings);
28bab8
+
28bab8
+    if (opts & OPT_u)
28bab8
+        config.ur_url = arg_server_url;
28bab8
+    if (opts & OPT_k)
28bab8
+        config.ur_ssl_verify = !insecure;
28bab8
+    if (opts & OPT_t)
28bab8
+        parse_client_auth_paths(&config, client_auth);
28bab8
+    if (opts & OPT_i)
28bab8
+    {
28bab8
+        g_list_free_full(config.ur_prefs.urp_auth_items, free);
28bab8
+        config.ur_prefs.urp_auth_items = auth_items;
28bab8
+    }
28bab8
+
28bab8
+    if (!config.ur_url)
28bab8
+        error_msg_and_die("You need to specify server URL");
28bab8
+
28bab8
+    post_state_t *post_state = NULL;
28bab8
+
28bab8
+    if (ureport_hash && ureport_hash_from_rt)
28bab8
+        error_msg_and_die("You need to pass either -a bthash or -A");
28bab8
+
28bab8
+    if (rhbz_bug >= 0 && rhbz_bug_from_rt)
28bab8
+        error_msg_and_die("You need to pass either -b bug-id or -B");
28bab8
+
28bab8
+    if (email_address && email_address_from_env)
28bab8
+        error_msg_and_die("You need to pass either -e bthash or -E");
28bab8
+
28bab8
+    if (ureport_hash_from_rt || rhbz_bug_from_rt)
28bab8
+    {
28bab8
+        dd = dd_opendir(dump_dir_path, DD_OPEN_READONLY);
28bab8
+        if (!dd)
28bab8
+            xfunc_die();
28bab8
+
28bab8
+        if (ureport_hash_from_rt)
28bab8
+        {
28bab8
+            report_result_t *ureport_result = find_in_reported_to(dd, "uReport");
28bab8
+
28bab8
+            if (!ureport_result || !ureport_result->bthash)
28bab8
+                error_msg_and_die(_("This problem does not have an uReport assigned."));
28bab8
+
28bab8
+            /* sorry, this will be leaked */
28bab8
+            ureport_hash = xstrdup(ureport_result->bthash);
28bab8
+
28bab8
+            free_report_result(ureport_result);
28bab8
+        }
28bab8
+
28bab8
+        if (rhbz_bug_from_rt)
28bab8
+        {
28bab8
+            report_result_t *bz_result = find_in_reported_to(dd, "Bugzilla");
28bab8
+
28bab8
+            if (!bz_result || !bz_result->url)
28bab8
+                error_msg_and_die(_("This problem has not been reported to Bugzilla."));
28bab8
+
28bab8
+            char *bugid_ptr = strstr(bz_result->url, "show_bug.cgi?id=");
28bab8
+            if (!bugid_ptr)
28bab8
+                error_msg_and_die(_("Unable to find bug ID in bugzilla URL '%s'"), bz_result->url);
28bab8
+            bugid_ptr += strlen("show_bug.cgi?id=");
28bab8
+
28bab8
+            /* we're just reading int, sscanf works fine */
28bab8
+            if (sscanf(bugid_ptr, "%d", &rhbz_bug) != 1)
28bab8
+                error_msg_and_die(_("Unable to parse bug ID from bugzilla URL '%s'"), bz_result->url);
28bab8
+
28bab8
+            free_report_result(bz_result);
28bab8
+        }
28bab8
+
28bab8
+        dd_close(dd);
28bab8
+    }
28bab8
+
28bab8
+    if (email_address_from_env)
28bab8
+    {
28bab8
+        VALUE_FROM_CONF("ContactEmail", email_address, (const char *));
28bab8
+
28bab8
+        if (!email_address)
28bab8
+            error_msg_and_die(_("Neither environment variable 'uReport_ContactEmail' nor configuration option 'ContactEmail' is set"));
28bab8
+    }
28bab8
+
28bab8
+    if (ureport_hash)
28bab8
+    {
28bab8
+        if (rhbz_bug < 0 && !email_address)
28bab8
+            error_msg_and_die(_("You need to specify bug ID, contact email or both"));
28bab8
+
28bab8
+        if (rhbz_bug >= 0)
28bab8
+        {
28bab8
+            if (perform_attach(&config, ureport_hash, (attach_handler)wrp_ureport_attach_rhbz, (void *)&rhbz_bug))
28bab8
+                goto finalize;
28bab8
+        }
28bab8
+
28bab8
+        if (email_address)
28bab8
+        {
28bab8
+            if (perform_attach(&config, ureport_hash, (attach_handler)ureport_attach_email, (void *)email_address))
28bab8
+                goto finalize;
28bab8
+        }
28bab8
+
28bab8
+        ret = 0;
28bab8
+        goto finalize;
28bab8
+    }
28bab8
+    if (!ureport_hash && (rhbz_bug >= 0 || email_address))
28bab8
+        error_msg_and_die(_("You need to specify bthash of the uReport to attach."));
28bab8
+
28bab8
+    /* -b, -a nor -r were specified - upload uReport from dump_dir */
28bab8
+    const char *server_url = config.ur_url;
28bab8
+    char *dest_url = concat_path_file(config.ur_url, REPORT_URL_SFX);
28bab8
+    config.ur_url = dest_url;
28bab8
+
28bab8
+    char *json_ureport = ureport_from_dump_dir_ext(dump_dir_path, &(config.ur_prefs));
28bab8
+    if (!json_ureport)
28bab8
+    {
28bab8
+        error_msg(_("Not uploading an empty uReport"));
28bab8
+        goto format_err;
28bab8
+    }
28bab8
+
28bab8
+    post_state = ureport_post(json_ureport, &config);
28bab8
+    free(json_ureport);
28bab8
+
28bab8
+    if (!post_state)
28bab8
+    {
28bab8
+        error_msg(_("Failed on submitting the problem"));
28bab8
+        goto format_err;
28bab8
+    }
28bab8
+
28bab8
+    struct ureport_server_response *response = get_server_response(post_state, &config);
28bab8
+
28bab8
+    if (!response)
28bab8
+        goto format_err;
28bab8
+
28bab8
+    if (!response->is_error)
28bab8
+    {
28bab8
+        log_notice("is known: %s", response->value);
28bab8
+        ret = 0; /* "success" */
28bab8
+
28bab8
+        dd = dd_opendir(dump_dir_path, /* flags */ 0);
28bab8
+        if (!dd)
28bab8
+            xfunc_die();
28bab8
+
28bab8
+        if (response->bthash)
28bab8
+        {
28bab8
+            char *msg = xasprintf("uReport: BTHASH=%s", response->bthash);
28bab8
+            add_reported_to(dd, msg);
28bab8
+            free(msg);
28bab8
+
28bab8
+            char *bthash_url = concat_path_file(server_url, BTHASH_URL_SFX);
28bab8
+            msg = xasprintf("ABRT Server: URL=%s%s", bthash_url, response->bthash);
28bab8
+            add_reported_to(dd, msg);
28bab8
+            free(msg);
28bab8
+            free(bthash_url);
28bab8
+        }
28bab8
+
28bab8
+        if (response->reported_to_list)
28bab8
+        {
28bab8
+            for (GList *e = response->reported_to_list; e; e = g_list_next(e))
28bab8
+                add_reported_to(dd, e->data);
28bab8
+        }
28bab8
+
28bab8
+        if (response->solution)
28bab8
+            dd_save_text(dd, FILENAME_NOT_REPORTABLE, response->solution);
28bab8
+
28bab8
+        dd_close(dd);
28bab8
+
28bab8
+        /* If a reported problem is not known then emit NEEDMORE */
28bab8
+        if (strcmp("true", response->value) == 0)
28bab8
+        {
28bab8
+            log(_("This problem has already been reported."));
28bab8
+            if (response->message)
28bab8
+                log(response->message);
28bab8
+
28bab8
+            ret = EXIT_STOP_EVENT_RUN;
28bab8
+        }
28bab8
+    }
28bab8
+    else
28bab8
+    {
28bab8
+        error_msg(_("Server responded with an error: '%s'"), response->value);
28bab8
+    }
28bab8
+
28bab8
+    free_ureport_server_response(response);
28bab8
+
28bab8
+format_err:
28bab8
+    free_post_state(post_state);
28bab8
+    free(dest_url);
28bab8
+
28bab8
+finalize:
28bab8
+    if (config.ur_prefs.urp_auth_items != auth_items)
28bab8
+        g_list_free_full(config.ur_prefs.urp_auth_items, free);
28bab8
+
28bab8
+    free_map_string(config.ur_http_headers);
28bab8
+
28bab8
+    free_map_string(settings);
28bab8
+    free(config.ur_client_cert);
28bab8
+    free(config.ur_client_key);
28bab8
+
28bab8
+    return ret;
28bab8
+}
28bab8
diff --git a/src/plugins/ureport.c b/src/plugins/ureport.c
28bab8
deleted file mode 100644
28bab8
index 9c69cad..0000000
28bab8
--- a/src/plugins/ureport.c
28bab8
+++ /dev/null
28bab8
@@ -1,777 +0,0 @@
28bab8
-/*
28bab8
-    Copyright (C) 2012  ABRT Team
28bab8
-    Copyright (C) 2012  RedHat inc.
28bab8
-
28bab8
-    This program is free software; you can redistribute it and/or modify
28bab8
-    it under the terms of the GNU General Public License as published by
28bab8
-    the Free Software Foundation; either version 2 of the License, or
28bab8
-    (at your option) any later version.
28bab8
-
28bab8
-    This program is distributed in the hope that it will be useful,
28bab8
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
28bab8
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28bab8
-    GNU General Public License for more details.
28bab8
-
28bab8
-    You should have received a copy of the GNU General Public License along
28bab8
-    with this program; if not, write to the Free Software Foundation, Inc.,
28bab8
-    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28bab8
-*/
28bab8
-
28bab8
-#include <json/json.h>
28bab8
-#include "internal_libreport.h"
28bab8
-#include "ureport.h"
28bab8
-#include "libreport_curl.h"
28bab8
-
28bab8
-#define CONF_FILE_PATH PLUGINS_CONF_DIR"/ureport.conf"
28bab8
-
28bab8
-#define REPORT_URL_SFX "reports/new/"
28bab8
-#define ATTACH_URL_SFX "reports/attach/"
28bab8
-#define BTHASH_URL_SFX "reports/bthash/"
28bab8
-
28bab8
-#define RHSM_CERT_PATH "/etc/pki/consumer/cert.pem"
28bab8
-#define RHSM_KEY_PATH "/etc/pki/consumer/key.pem"
28bab8
-
28bab8
-#define RHAP_PEM_DIR_PATH "/etc/pki/entitlement"
28bab8
-#define RHAP_ENT_DATA_BEGIN_TAG "-----BEGIN ENTITLEMENT DATA-----"
28bab8
-#define RHAP_ENT_DATA_END_TAG "-----END ENTITLEMENT DATA-----"
28bab8
-#define RHAP_SIG_DATA_BEGIN_TAG "-----BEGIN RSA SIGNATURE-----"
28bab8
-#define RHAP_SIG_DATA_END_TAG "-----END RSA SIGNATURE-----"
28bab8
-
28bab8
-#define VALUE_FROM_CONF(opt, var, tr) do { const char *value = getenv("uReport_"opt); \
28bab8
-        if (!value) { value = get_map_string_item_or_NULL(settings, opt); } if (value) { var = tr(value); } \
28bab8
-    } while(0)
28bab8
-
28bab8
-static char *puppet_config_print(const char *key)
28bab8
-{
28bab8
-    char *command = xasprintf("puppet config print %s", key);
28bab8
-    char *result = run_in_shell_and_save_output(0, command, NULL, NULL);
28bab8
-    free(command);
28bab8
-
28bab8
-    /* run_in_shell_and_save_output always returns non-NULL */
28bab8
-    if (result[0] != '/')
28bab8
-        goto error;
28bab8
-
28bab8
-    char *newline = strchrnul(result, '\n');
28bab8
-    if (!newline)
28bab8
-        goto error;
28bab8
-
28bab8
-    *newline = '\0';
28bab8
-    return result;
28bab8
-error:
28bab8
-    free(result);
28bab8
-    error_msg_and_die("Unable to determine puppet %s path (puppet not installed?)", key);
28bab8
-}
28bab8
-
28bab8
-static void parse_client_auth_paths(struct ureport_server_config *config, const char *client_auth)
28bab8
-{
28bab8
-    if (client_auth == NULL)
28bab8
-        return;
28bab8
-
28bab8
-    if (strcmp(client_auth, "") == 0)
28bab8
-    {
28bab8
-        config->ur_client_cert = NULL;
28bab8
-        config->ur_client_key = NULL;
28bab8
-        log_notice("Not using client authentication");
28bab8
-    }
28bab8
-    else if (strcmp(client_auth, "rhsm") == 0)
28bab8
-    {
28bab8
-        config->ur_client_cert = xstrdup(RHSM_CERT_PATH);
28bab8
-        config->ur_client_key = xstrdup(RHSM_KEY_PATH);
28bab8
-    }
28bab8
-    else if (strcmp(client_auth, "rhsm-entitlement") == 0)
28bab8
-    {
28bab8
-        GList *certs = get_file_list(RHAP_PEM_DIR_PATH, "pem");
28bab8
-        if (g_list_length(certs) != 2)
28bab8
-        {
28bab8
-            log_notice(RHAP_PEM_DIR_PATH" does not contain unique cert-key files pair");
28bab8
-            log_notice("Not using client authentication");
28bab8
-            return;
28bab8
-        }
28bab8
-
28bab8
-        const char *cert = NULL;
28bab8
-        const char *key = NULL;
28bab8
-
28bab8
-        file_obj_t *fst = (file_obj_t *)certs->data;
28bab8
-        file_obj_t *scn = (file_obj_t *)certs->next->data;
28bab8
-
28bab8
-        if (strlen(fo_get_filename(fst)) < strlen(fo_get_filename(scn)))
28bab8
-        {
28bab8
-            cert = fo_get_filename(fst);
28bab8
-            key = fo_get_filename(scn);
28bab8
-
28bab8
-            config->ur_client_cert = xstrdup(fo_get_fullpath(fst));
28bab8
-            config->ur_client_key = xstrdup(fo_get_fullpath(scn));
28bab8
-        }
28bab8
-        else
28bab8
-        {
28bab8
-            cert = fo_get_filename(scn);
28bab8
-            key = fo_get_filename(fst);
28bab8
-
28bab8
-            config->ur_client_cert = xstrdup(fo_get_fullpath(scn));
28bab8
-            config->ur_client_key = xstrdup(fo_get_fullpath(fst));
28bab8
-        }
28bab8
-
28bab8
-        const bool iscomplement = prefixcmp(key, cert) != 0 || strcmp("-key", key + strlen(cert)) != 0;
28bab8
-        g_list_free_full(certs, (GDestroyNotify)free_file_obj);
28bab8
-
28bab8
-        if (iscomplement)
28bab8
-        {
28bab8
-            log_notice("Key file '%s' isn't complement to cert file '%s'",
28bab8
-                    config->ur_client_key, config->ur_client_cert);
28bab8
-            log_notice("Not using client authentication");
28bab8
-
28bab8
-            free(config->ur_client_cert);
28bab8
-            free(config->ur_client_key);
28bab8
-            config->ur_client_cert = NULL;
28bab8
-            config->ur_client_key = NULL;
28bab8
-
28bab8
-            return;
28bab8
-        }
28bab8
-
28bab8
-        char *certdata = xmalloc_open_read_close(config->ur_client_cert, /*no size limit*/NULL);
28bab8
-        if (certdata != NULL)
28bab8
-        {
28bab8
-            char *ent_data = xstrdup_between(certdata,
28bab8
-                    RHAP_ENT_DATA_BEGIN_TAG, RHAP_ENT_DATA_END_TAG);
28bab8
-
28bab8
-            char *sig_data = xstrdup_between(certdata,
28bab8
-                    RHAP_SIG_DATA_BEGIN_TAG, RHAP_SIG_DATA_END_TAG);
28bab8
-
28bab8
-            if (ent_data != NULL && sig_data != NULL)
28bab8
-            {
28bab8
-                ent_data = strremovech(ent_data, '\n');
28bab8
-                insert_map_string(config->ur_http_headers,
28bab8
-                        xstrdup("X-RH-Entitlement-Data"),
28bab8
-                        xasprintf(RHAP_ENT_DATA_BEGIN_TAG"%s"RHAP_ENT_DATA_END_TAG, ent_data));
28bab8
-
28bab8
-                sig_data = strremovech(sig_data, '\n');
28bab8
-                insert_map_string(config->ur_http_headers,
28bab8
-                        xstrdup("X-RH-Entitlement-Sig"),
28bab8
-                        xasprintf(RHAP_SIG_DATA_BEGIN_TAG"%s"RHAP_SIG_DATA_END_TAG, sig_data));
28bab8
-            }
28bab8
-            else
28bab8
-            {
28bab8
-                log_notice("Cert file '%s' doesn't contain Entitlement and RSA Signature sections", config->ur_client_cert);
28bab8
-                log_notice("Not using HTTP authentication headers");
28bab8
-            }
28bab8
-
28bab8
-            free(sig_data);
28bab8
-            free(ent_data);
28bab8
-            free(certdata);
28bab8
-        }
28bab8
-    }
28bab8
-    else if (strcmp(client_auth, "puppet") == 0)
28bab8
-    {
28bab8
-        config->ur_client_cert = puppet_config_print("hostcert");
28bab8
-        config->ur_client_key = puppet_config_print("hostprivkey");
28bab8
-    }
28bab8
-    else
28bab8
-    {
28bab8
-        char *scratch = xstrdup(client_auth);
28bab8
-        config->ur_client_cert = xstrdup(strtok(scratch, ":"));
28bab8
-        config->ur_client_key = xstrdup(strtok(NULL, ":"));
28bab8
-        free(scratch);
28bab8
-        if (config->ur_client_cert == NULL || config->ur_client_key == NULL)
28bab8
-            error_msg_and_die("Invalid client authentication specification");
28bab8
-    }
28bab8
-
28bab8
-    if (config->ur_client_cert && config->ur_client_key)
28bab8
-    {
28bab8
-        log_notice("Using client certificate: %s", config->ur_client_cert);
28bab8
-        log_notice("Using client private key: %s", config->ur_client_key);
28bab8
-    }
28bab8
-}
28bab8
-
28bab8
-/*
28bab8
- * Loads uReport configuration from various sources.
28bab8
- *
28bab8
- * Replaces a value of an already configured option only if the
28bab8
- * option was found in a configuration source.
28bab8
- *
28bab8
- * @param config a server configuration to be populated
28bab8
- */
28bab8
-static void load_ureport_server_config(struct ureport_server_config *config, map_string_t *settings)
28bab8
-{
28bab8
-    VALUE_FROM_CONF("URL", config->ur_url, (const char *));
28bab8
-    VALUE_FROM_CONF("SSLVerify", config->ur_ssl_verify, string_to_bool);
28bab8
-
28bab8
-    bool include_auth = false;
28bab8
-    VALUE_FROM_CONF("IncludeAuthData", include_auth, string_to_bool);
28bab8
-
28bab8
-    if (include_auth)
28bab8
-    {
28bab8
-        const char *auth_items = NULL;
28bab8
-        VALUE_FROM_CONF("AuthDataItems", auth_items, (const char *));
28bab8
-        config->ur_prefs.urp_auth_items = parse_list(auth_items);
28bab8
-
28bab8
-        if (config->ur_prefs.urp_auth_items == NULL)
28bab8
-            log_warning("IncludeAuthData set to 'yes' but AuthDataItems is empty.");
28bab8
-    }
28bab8
-
28bab8
-    const char *client_auth = NULL;
28bab8
-    VALUE_FROM_CONF("SSLClientAuth", client_auth, (const char *));
28bab8
-    parse_client_auth_paths(config, client_auth);
28bab8
-}
28bab8
-
28bab8
-struct ureport_server_response {
28bab8
-    bool is_error;
28bab8
-    char *value;
28bab8
-    char *message;
28bab8
-    char *bthash;
28bab8
-    GList *reported_to_list;
28bab8
-    char *solution;
28bab8
-};
28bab8
-
28bab8
-void free_ureport_server_response(struct ureport_server_response *resp)
28bab8
-{
28bab8
-    if (!resp)
28bab8
-        return;
28bab8
-
28bab8
-    free(resp->solution);
28bab8
-    g_list_free_full(resp->reported_to_list, g_free);
28bab8
-    free(resp->bthash);
28bab8
-    free(resp->message);
28bab8
-    free(resp->value);
28bab8
-    free(resp);
28bab8
-}
28bab8
-
28bab8
-static char *parse_solution_from_json_list(struct json_object *list, GList **reported_to)
28bab8
-{
28bab8
-    json_object *list_elem, *struct_elem;
28bab8
-    const char *cause, *note, *url;
28bab8
-    struct strbuf *solution_buf = strbuf_new();
28bab8
-
28bab8
-    const unsigned length = json_object_array_length(list);
28bab8
-
28bab8
-    const char *one_format = _("Your problem seems to be caused by %s\n\n%s\n");
28bab8
-    if (length > 1)
28bab8
-    {
28bab8
-        strbuf_append_str(solution_buf, _("Your problem seems to be caused by one of the following:\n"));
28bab8
-        one_format = "\n* %s\n\n%s\n";
28bab8
-    }
28bab8
-
28bab8
-    bool empty = true;
28bab8
-    for (unsigned i = 0; i < length; ++i)
28bab8
-    {
28bab8
-        list_elem = json_object_array_get_idx(list, i);
28bab8
-        if (!list_elem)
28bab8
-            continue;
28bab8
-
28bab8
-        if (!json_object_object_get_ex(list_elem, "cause", &struct_elem))
28bab8
-            continue;
28bab8
-
28bab8
-        cause = json_object_get_string(struct_elem);
28bab8
-            continue;
28bab8
-
28bab8
-        if (!json_object_object_get_ex(list_elem, "note", &struct_elem))
28bab8
-            continue;
28bab8
-
28bab8
-        note = json_object_get_string(struct_elem);
28bab8
-        if (!note)
28bab8
-            continue;
28bab8
-
28bab8
-        empty = false;
28bab8
-        strbuf_append_strf(solution_buf, one_format, cause, note);
28bab8
-
28bab8
-        if (!json_object_object_get_ex(list_elem, "url", &struct_elem))
28bab8
-            continue;
28bab8
-
28bab8
-        url = json_object_get_string(struct_elem);
28bab8
-        if (url)
28bab8
-        {
28bab8
-            char *reported_to_line = xasprintf("%s: URL=%s", cause, url);
28bab8
-            *reported_to = g_list_append(*reported_to, reported_to_line);
28bab8
-        }
28bab8
-    }
28bab8
-
28bab8
-    if (empty)
28bab8
-    {
28bab8
-        strbuf_free(solution_buf);
28bab8
-        return NULL;
28bab8
-    }
28bab8
-
28bab8
-    return strbuf_free_nobuf(solution_buf);
28bab8
-}
28bab8
-
28bab8
-/* reported_to json element should be a list of structures
28bab8
-{ "reporter": "Bugzilla",
28bab8
-  "type": "url",
28bab8
-  "value": "https://bugzilla.redhat.com/show_bug.cgi?id=XYZ" } */
28bab8
-static GList *parse_reported_to_from_json_list(struct json_object *list)
28bab8
-{
28bab8
-    int i;
28bab8
-    json_object *list_elem, *struct_elem;
28bab8
-    const char *reporter, *value, *type;
28bab8
-    char *reported_to_line, *prefix;
28bab8
-    GList *result = NULL;
28bab8
-
28bab8
-    for (i = 0; i < json_object_array_length(list); ++i)
28bab8
-    {
28bab8
-        prefix = NULL;
28bab8
-        list_elem = json_object_array_get_idx(list, i);
28bab8
-        if (!list_elem)
28bab8
-            continue;
28bab8
-
28bab8
-        if (!json_object_object_get_ex(list_elem, "reporter", &struct_elem))
28bab8
-            continue;
28bab8
-
28bab8
-        reporter = json_object_get_string(struct_elem);
28bab8
-        if (!reporter)
28bab8
-            continue;
28bab8
-
28bab8
-        if (!json_object_object_get_ex(list_elem, "value", &struct_elem))
28bab8
-            continue;
28bab8
-
28bab8
-        value = json_object_get_string(struct_elem);
28bab8
-        if (!value)
28bab8
-            continue;
28bab8
-
28bab8
-        if (!json_object_object_get_ex(list_elem, "type", &struct_elem))
28bab8
-            continue;
28bab8
-
28bab8
-        type = json_object_get_string(struct_elem);
28bab8
-        if (type)
28bab8
-        {
28bab8
-            if (strcasecmp("url", type) == 0)
28bab8
-                prefix = xstrdup("URL=");
28bab8
-            else if (strcasecmp("bthash", type) == 0)
28bab8
-                prefix = xstrdup("BTHASH=");
28bab8
-        }
28bab8
-
28bab8
-        if (!prefix)
28bab8
-            prefix = xstrdup("");
28bab8
-
28bab8
-        reported_to_line = xasprintf("%s: %s%s", reporter, prefix, value);
28bab8
-        free(prefix);
28bab8
-
28bab8
-        result = g_list_append(result, reported_to_line);
28bab8
-    }
28bab8
-
28bab8
-    return result;
28bab8
-}
28bab8
-
28bab8
-/*
28bab8
- * Reponse samples:
28bab8
- * {"error":"field 'foo' is required"}
28bab8
- * {"response":"true"}
28bab8
- * {"response":"false"}
28bab8
- */
28bab8
-static struct ureport_server_response *ureport_server_parse_json(json_object *json)
28bab8
-{
28bab8
-    json_object *obj = NULL;
28bab8
-    if (json_object_object_get_ex(json, "error", &obj))
28bab8
-    {
28bab8
-        struct ureport_server_response *out_response = xzalloc(sizeof(*out_response));
28bab8
-        out_response->is_error = true;
28bab8
-        /*
28bab8
-         * Used to use json_object_to_json_string(obj), but it returns
28bab8
-         * the string in quote marks (") - IOW, json-formatted string.
28bab8
-         */
28bab8
-        out_response->value = xstrdup(json_object_get_string(obj));
28bab8
-        return out_response;
28bab8
-    }
28bab8
-
28bab8
-    if (json_object_object_get_ex(json, "result", &obj))
28bab8
-    {
28bab8
-        struct ureport_server_response *out_response = xzalloc(sizeof(*out_response));
28bab8
-        out_response->value = xstrdup(json_object_get_string(obj));
28bab8
-
28bab8
-        json_object *message = NULL;
28bab8
-        if (json_object_object_get_ex(json, "message", &message))
28bab8
-            out_response->message = xstrdup(json_object_get_string(message));
28bab8
-
28bab8
-        json_object *bthash = NULL;
28bab8
-        if (json_object_object_get_ex(json, "bthash", &bthash))
28bab8
-            out_response->bthash = xstrdup(json_object_get_string(bthash));
28bab8
-
28bab8
-        json_object *reported_to_list = NULL;
28bab8
-        if (json_object_object_get_ex(json, "reported_to", &reported_to_list))
28bab8
-            out_response->reported_to_list = parse_reported_to_from_json_list(reported_to_list);
28bab8
-
28bab8
-        json_object *solutions = NULL;
28bab8
-        if (json_object_object_get_ex(json, "solutions", &solutions))
28bab8
-            out_response->solution = parse_solution_from_json_list(solutions, &(out_response->reported_to_list));
28bab8
-
28bab8
-        return out_response;
28bab8
-    }
28bab8
-
28bab8
-    return NULL;
28bab8
-}
28bab8
-
28bab8
-static struct ureport_server_response *get_server_response(post_state_t *post_state, struct ureport_server_config *config)
28bab8
-{
28bab8
-    /* Previously, the condition here was (post_state->errmsg[0] != '\0')
28bab8
-     * however when the server asks for optional client authentication and we do not have the certificates,
28bab8
-     * then post_state->errmsg contains "NSS: client certificate not found (nickname not specified)" even though
28bab8
-     * the request succeeded.
28bab8
-     */
28bab8
-    if (post_state->curl_result != CURLE_OK)
28bab8
-    {
28bab8
-        error_msg(_("Failed to upload uReport to the server '%s' with curl: %s"), config->ur_url, post_state->errmsg);
28bab8
-        return NULL;
28bab8
-    }
28bab8
-
28bab8
-    if (post_state->http_resp_code == 404)
28bab8
-    {
28bab8
-        error_msg(_("The URL '%s' does not exist (got error 404 from server)"), config->ur_url);
28bab8
-        return NULL;
28bab8
-    }
28bab8
-
28bab8
-    if (post_state->http_resp_code == 500)
28bab8
-    {
28bab8
-        error_msg(_("The server at '%s' encountered an internal error (got error 500)"), config->ur_url);
28bab8
-        return NULL;
28bab8
-    }
28bab8
-
28bab8
-    if (post_state->http_resp_code == 503)
28bab8
-    {
28bab8
-        error_msg(_("The server at '%s' currently can't handle the request (got error 503)"), config->ur_url);
28bab8
-        return NULL;
28bab8
-    }
28bab8
-
28bab8
-    if (post_state->http_resp_code != 202
28bab8
-            && post_state->http_resp_code != 400
28bab8
-            && post_state->http_resp_code != 413)
28bab8
-    {
28bab8
-        /* can't print better error message */
28bab8
-        error_msg(_("Unexpected HTTP response from '%s': %d"), config->ur_url, post_state->http_resp_code);
28bab8
-        log_notice("%s", post_state->body);
28bab8
-        return NULL;
28bab8
-    }
28bab8
-
28bab8
-    json_object *const json = json_tokener_parse(post_state->body);
28bab8
-
28bab8
-    if (is_error(json))
28bab8
-    {
28bab8
-        error_msg(_("Unable to parse response from ureport server at '%s'"), config->ur_url);
28bab8
-        log_notice("%s", post_state->body);
28bab8
-        json_object_put(json);
28bab8
-        return NULL;
28bab8
-    }
28bab8
-
28bab8
-    struct ureport_server_response *response = ureport_server_parse_json(json);
28bab8
-    json_object_put(json);
28bab8
-
28bab8
-    if (!response)
28bab8
-        error_msg(_("The response from '%s' has invalid format"), config->ur_url);
28bab8
-    else if ((post_state->http_resp_code == 202 && response->is_error)
28bab8
-                || (post_state->http_resp_code != 202 && !response->is_error))
28bab8
-    {
28bab8
-        /* HTTP CODE 202 means that call was successful but the response */
28bab8
-        /* has an error message */
28bab8
-        error_msg(_("Type mismatch has been detected in the response from '%s'"), config->ur_url);
28bab8
-    }
28bab8
-
28bab8
-    return response;
28bab8
-}
28bab8
-
28bab8
-typedef post_state_t *(*attach_handler)(const char *, void *, struct ureport_server_config *);
28bab8
-
28bab8
-static post_state_t *wrp_ureport_attach_rhbz(const char *ureport_hash, int *rhbz_bug,
28bab8
-        struct ureport_server_config *config)
28bab8
-{
28bab8
-    return ureport_attach_rhbz(ureport_hash, *rhbz_bug, config);
28bab8
-}
28bab8
-
28bab8
-static bool perform_attach(struct ureport_server_config *config, const char *ureport_hash,
28bab8
-        attach_handler handler, void *args)
28bab8
-{
28bab8
-    char *dest_url = concat_path_file(config->ur_url, ATTACH_URL_SFX);
28bab8
-    const char *old_url = config->ur_url;
28bab8
-    config->ur_url = dest_url;
28bab8
-    post_state_t *post_state = handler(ureport_hash, args, config);
28bab8
-    config->ur_url = old_url;
28bab8
-    free(dest_url);
28bab8
-
28bab8
-    struct ureport_server_response *resp = get_server_response(post_state, config);
28bab8
-    free_post_state(post_state);
28bab8
-    /* don't use str_bo_bool() because we require "true" string */
28bab8
-    const int result = !resp || resp->is_error || strcmp(resp->value,"true") != 0;
28bab8
-
28bab8
-    if (resp && resp->is_error)
28bab8
-    {
28bab8
-        error_msg(_("The server at '%s' responded with an error: '%s'"), config->ur_url, resp->value);
28bab8
-    }
28bab8
-
28bab8
-    free_ureport_server_response(resp);
28bab8
-
28bab8
-    return result;
28bab8
-}
28bab8
-
28bab8
-int main(int argc, char **argv)
28bab8
-{
28bab8
-    setlocale(LC_ALL, "");
28bab8
-#if ENABLE_NLS
28bab8
-    bindtextdomain(PACKAGE, LOCALEDIR);
28bab8
-    textdomain(PACKAGE);
28bab8
-#endif
28bab8
-
28bab8
-    abrt_init(argv);
28bab8
-
28bab8
-    struct ureport_server_config config = {
28bab8
-        .ur_url = NULL,
28bab8
-        .ur_ssl_verify = true,
28bab8
-        .ur_client_cert = NULL,
28bab8
-        .ur_client_key = NULL,
28bab8
-        .ur_http_headers = NULL,
28bab8
-        {
28bab8
-            .urp_auth_items = NULL,
28bab8
-        },
28bab8
-    };
28bab8
-
28bab8
-    config.ur_http_headers = new_map_string();
28bab8
-
28bab8
-    enum {
28bab8
-        OPT_v = 1 << 0,
28bab8
-        OPT_d = 1 << 1,
28bab8
-        OPT_u = 1 << 2,
28bab8
-        OPT_k = 1 << 3,
28bab8
-        OPT_t = 1 << 4,
28bab8
-        OPT_i = 1 << 5,
28bab8
-    };
28bab8
-
28bab8
-    int ret = 1; /* "failure" (for now) */
28bab8
-    bool insecure = !config.ur_ssl_verify;
28bab8
-    const char *conf_file = CONF_FILE_PATH;
28bab8
-    const char *arg_server_url = NULL;
28bab8
-    const char *client_auth = NULL;
28bab8
-    GList *auth_items = NULL;
28bab8
-    const char *dump_dir_path = ".";
28bab8
-    const char *ureport_hash = NULL;
28bab8
-    bool ureport_hash_from_rt = false;
28bab8
-    int rhbz_bug = -1;
28bab8
-    bool rhbz_bug_from_rt = false;
28bab8
-    const char *email_address = NULL;
28bab8
-    bool email_address_from_env = false;
28bab8
-    struct dump_dir *dd = NULL;
28bab8
-    struct options program_options[] = {
28bab8
-        OPT__VERBOSE(&g_verbose),
28bab8
-        OPT__DUMP_DIR(&dump_dir_path),
28bab8
-        OPT_STRING('u', "url", &arg_server_url, "URL", _("Specify server URL")),
28bab8
-        OPT_BOOL('k', "insecure", &insecure,
28bab8
-                          _("Allow insecure connection to ureport server")),
28bab8
-        OPT_STRING('t', "auth", &client_auth, "SOURCE", _("Use client authentication")),
28bab8
-        OPT_LIST('i', "auth_items", &auth_items, "AUTH_ITEMS", _("Additional files included in 'auth' key")),
28bab8
-        OPT_STRING('c', NULL, &conf_file, "FILE", _("Configuration file")),
28bab8
-        OPT_STRING('a', "attach", &ureport_hash, "BTHASH",
28bab8
-                          _("bthash of uReport to attach (conflicts with -A)")),
28bab8
-        OPT_BOOL('A', "attach-rt", &ureport_hash_from_rt,
28bab8
-                          _("attach to a bthash from reported_to (conflicts with -a)")),
28bab8
-        OPT_STRING('e', "email", &email_address, "EMAIL",
28bab8
-                          _("contact e-mail address (requires -a|-A, conflicts with -E)")),
28bab8
-        OPT_BOOL('E', "email-env", &email_address_from_env,
28bab8
-                          _("contact e-mail address from environment or configuration file (requires -a|-A, conflicts with -e)")),
28bab8
-        OPT_INTEGER('b', "bug-id", &rhbz_bug,
28bab8
-                          _("attach RHBZ bug (requires -a|-A, conflicts with -B)")),
28bab8
-        OPT_BOOL('B', "bug-id-rt", &rhbz_bug_from_rt,
28bab8
-                          _("attach last RHBZ bug from reported_to (requires -a|-A, conflicts with -b)")),
28bab8
-        OPT_END(),
28bab8
-    };
28bab8
-
28bab8
-    const char *program_usage_string = _(
28bab8
-        "& [-v] [-c FILE] [-u URL] [-k] [-t SOURCE] [-A -a bthash -B -b bug-id -E -e email] [-d DIR]\n"
28bab8
-        "& [-v] [-c FILE] [-u URL] [-k] [-t SOURCE] [-i AUTH_ITEMS]\\\n"
28bab8
-        "  [-A -a bthash -B -b bug-id -E -e email] [-d DIR]\n"
28bab8
-        "\n"
28bab8
-        "Upload micro report or add an attachment to a micro report\n"
28bab8
-        "\n"
28bab8
-        "Reads the default configuration from "CONF_FILE_PATH
28bab8
-    );
28bab8
-
28bab8
-    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
28bab8
-
28bab8
-    map_string_t *settings = new_map_string();
28bab8
-    load_conf_file(conf_file, settings, /*skip key w/o values:*/ false);
28bab8
-
28bab8
-    load_ureport_server_config(&config, settings);
28bab8
-
28bab8
-    if (opts & OPT_u)
28bab8
-        config.ur_url = arg_server_url;
28bab8
-    if (opts & OPT_k)
28bab8
-        config.ur_ssl_verify = !insecure;
28bab8
-    if (opts & OPT_t)
28bab8
-        parse_client_auth_paths(&config, client_auth);
28bab8
-    if (opts & OPT_i)
28bab8
-    {
28bab8
-        g_list_free_full(config.ur_prefs.urp_auth_items, free);
28bab8
-        config.ur_prefs.urp_auth_items = auth_items;
28bab8
-    }
28bab8
-
28bab8
-    if (!config.ur_url)
28bab8
-        error_msg_and_die("You need to specify server URL");
28bab8
-
28bab8
-    post_state_t *post_state = NULL;
28bab8
-
28bab8
-    if (ureport_hash && ureport_hash_from_rt)
28bab8
-        error_msg_and_die("You need to pass either -a bthash or -A");
28bab8
-
28bab8
-    if (rhbz_bug >= 0 && rhbz_bug_from_rt)
28bab8
-        error_msg_and_die("You need to pass either -b bug-id or -B");
28bab8
-
28bab8
-    if (email_address && email_address_from_env)
28bab8
-        error_msg_and_die("You need to pass either -e bthash or -E");
28bab8
-
28bab8
-    if (ureport_hash_from_rt || rhbz_bug_from_rt)
28bab8
-    {
28bab8
-        dd = dd_opendir(dump_dir_path, DD_OPEN_READONLY);
28bab8
-        if (!dd)
28bab8
-            xfunc_die();
28bab8
-
28bab8
-        if (ureport_hash_from_rt)
28bab8
-        {
28bab8
-            report_result_t *ureport_result = find_in_reported_to(dd, "uReport");
28bab8
-
28bab8
-            if (!ureport_result || !ureport_result->bthash)
28bab8
-                error_msg_and_die(_("This problem does not have an uReport assigned."));
28bab8
-
28bab8
-            /* sorry, this will be leaked */
28bab8
-            ureport_hash = xstrdup(ureport_result->bthash);
28bab8
-
28bab8
-            free_report_result(ureport_result);
28bab8
-        }
28bab8
-
28bab8
-        if (rhbz_bug_from_rt)
28bab8
-        {
28bab8
-            report_result_t *bz_result = find_in_reported_to(dd, "Bugzilla");
28bab8
-
28bab8
-            if (!bz_result || !bz_result->url)
28bab8
-                error_msg_and_die(_("This problem has not been reported to Bugzilla."));
28bab8
-
28bab8
-            char *bugid_ptr = strstr(bz_result->url, "show_bug.cgi?id=");
28bab8
-            if (!bugid_ptr)
28bab8
-                error_msg_and_die(_("Unable to find bug ID in bugzilla URL '%s'"), bz_result->url);
28bab8
-            bugid_ptr += strlen("show_bug.cgi?id=");
28bab8
-
28bab8
-            /* we're just reading int, sscanf works fine */
28bab8
-            if (sscanf(bugid_ptr, "%d", &rhbz_bug) != 1)
28bab8
-                error_msg_and_die(_("Unable to parse bug ID from bugzilla URL '%s'"), bz_result->url);
28bab8
-
28bab8
-            free_report_result(bz_result);
28bab8
-        }
28bab8
-
28bab8
-        dd_close(dd);
28bab8
-    }
28bab8
-
28bab8
-    if (email_address_from_env)
28bab8
-    {
28bab8
-        VALUE_FROM_CONF("ContactEmail", email_address, (const char *));
28bab8
-
28bab8
-        if (!email_address)
28bab8
-            error_msg_and_die(_("Neither environment variable 'uReport_ContactEmail' nor configuration option 'ContactEmail' is set"));
28bab8
-    }
28bab8
-
28bab8
-    if (ureport_hash)
28bab8
-    {
28bab8
-        if (rhbz_bug < 0 && !email_address)
28bab8
-            error_msg_and_die(_("You need to specify bug ID, contact email or both"));
28bab8
-
28bab8
-        if (rhbz_bug >= 0)
28bab8
-        {
28bab8
-            if (perform_attach(&config, ureport_hash, (attach_handler)wrp_ureport_attach_rhbz, (void *)&rhbz_bug))
28bab8
-                goto finalize;
28bab8
-        }
28bab8
-
28bab8
-        if (email_address)
28bab8
-        {
28bab8
-            if (perform_attach(&config, ureport_hash, (attach_handler)ureport_attach_email, (void *)email_address))
28bab8
-                goto finalize;
28bab8
-        }
28bab8
-
28bab8
-        ret = 0;
28bab8
-        goto finalize;
28bab8
-    }
28bab8
-    if (!ureport_hash && (rhbz_bug >= 0 || email_address))
28bab8
-        error_msg_and_die(_("You need to specify bthash of the uReport to attach."));
28bab8
-
28bab8
-    /* -b, -a nor -r were specified - upload uReport from dump_dir */
28bab8
-    const char *server_url = config.ur_url;
28bab8
-    char *dest_url = concat_path_file(config.ur_url, REPORT_URL_SFX);
28bab8
-    config.ur_url = dest_url;
28bab8
-
28bab8
-    char *json_ureport = ureport_from_dump_dir_ext(dump_dir_path, &(config.ur_prefs));
28bab8
-    if (!json_ureport)
28bab8
-    {
28bab8
-        error_msg(_("Not uploading an empty uReport"));
28bab8
-        goto format_err;
28bab8
-    }
28bab8
-
28bab8
-    post_state = post_ureport(json_ureport, &config);
28bab8
-    free(json_ureport);
28bab8
-
28bab8
-    if (!post_state)
28bab8
-    {
28bab8
-        error_msg(_("Failed on submitting the problem"));
28bab8
-        goto format_err;
28bab8
-    }
28bab8
-
28bab8
-    struct ureport_server_response *response = get_server_response(post_state, &config);
28bab8
-
28bab8
-    if (!response)
28bab8
-        goto format_err;
28bab8
-
28bab8
-    if (!response->is_error)
28bab8
-    {
28bab8
-        log_notice("is known: %s", response->value);
28bab8
-        ret = 0; /* "success" */
28bab8
-
28bab8
-        dd = dd_opendir(dump_dir_path, /* flags */ 0);
28bab8
-        if (!dd)
28bab8
-            xfunc_die();
28bab8
-
28bab8
-        if (response->bthash)
28bab8
-        {
28bab8
-            char *msg = xasprintf("uReport: BTHASH=%s", response->bthash);
28bab8
-            add_reported_to(dd, msg);
28bab8
-            free(msg);
28bab8
-
28bab8
-            char *bthash_url = concat_path_file(server_url, BTHASH_URL_SFX);
28bab8
-            msg = xasprintf("ABRT Server: URL=%s%s", bthash_url, response->bthash);
28bab8
-            add_reported_to(dd, msg);
28bab8
-            free(msg);
28bab8
-            free(bthash_url);
28bab8
-        }
28bab8
-
28bab8
-        if (response->reported_to_list)
28bab8
-        {
28bab8
-            for (GList *e = response->reported_to_list; e; e = g_list_next(e))
28bab8
-                add_reported_to(dd, e->data);
28bab8
-        }
28bab8
-
28bab8
-        if (response->solution)
28bab8
-            dd_save_text(dd, FILENAME_NOT_REPORTABLE, response->solution);
28bab8
-
28bab8
-        dd_close(dd);
28bab8
-
28bab8
-        /* If a reported problem is not known then emit NEEDMORE */
28bab8
-        if (strcmp("true", response->value) == 0)
28bab8
-        {
28bab8
-            log(_("This problem has already been reported."));
28bab8
-            if (response->message)
28bab8
-                log(response->message);
28bab8
-
28bab8
-            ret = EXIT_STOP_EVENT_RUN;
28bab8
-        }
28bab8
-    }
28bab8
-    else
28bab8
-    {
28bab8
-        error_msg(_("Server responded with an error: '%s'"), response->value);
28bab8
-    }
28bab8
-
28bab8
-    free_ureport_server_response(response);
28bab8
-
28bab8
-format_err:
28bab8
-    free_post_state(post_state);
28bab8
-    free(dest_url);
28bab8
-
28bab8
-finalize:
28bab8
-    if (config.ur_prefs.urp_auth_items != auth_items)
28bab8
-        g_list_free_full(config.ur_prefs.urp_auth_items, free);
28bab8
-
28bab8
-    free_map_string(config.ur_http_headers);
28bab8
-
28bab8
-    free_map_string(settings);
28bab8
-    free(config.ur_client_cert);
28bab8
-    free(config.ur_client_key);
28bab8
-
28bab8
-    return ret;
28bab8
-}
28bab8
-- 
28bab8
1.8.3.1
28bab8