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

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