Blob Blame History Raw
From 611ca48b8d81e5edc0907885ece48cb0dce986fa Mon Sep 17 00:00:00 2001
From: Matej Habrnal <mhabrnal@redhat.com>
Date: Tue, 13 Jan 2015 19:30:27 -0500
Subject: [PATCH] reporter-mantisbt: first version of the reporter-mantisbt

Related to #272

Signed-off-by: Matej Habrnal <mhabrnal@redhat.com>
---
 configure.ac                                   |   33 +
 po/POTFILES.in                                 |   11 +
 src/plugins/Makefile.am                        |   43 +-
 src/plugins/centos_report_event.conf           |   37 +
 src/plugins/mantisbt.c                         | 1111 ++++++++++++++++++++++++
 src/plugins/mantisbt.conf                      |    8 +
 src/plugins/mantisbt.h                         |  140 +++
 src/plugins/mantisbt_format.conf               |   59 ++
 src/plugins/mantisbt_formatdup.conf            |   65 ++
 src/plugins/report_CentOSBugTracker.conf       |    4 +
 src/plugins/report_CentOSBugTracker.xml.in     |   65 ++
 src/plugins/reporter-mantisbt.c                |  696 +++++++++++++++
 src/workflows/Makefile.am                      |   15 +-
 src/workflows/report_centos.conf               |   31 +
 src/workflows/workflow_CentOSCCpp.xml.in       |   12 +
 src/workflows/workflow_CentOSJava.xml.in       |   11 +
 src/workflows/workflow_CentOSKerneloops.xml.in |   11 +
 src/workflows/workflow_CentOSLibreport.xml.in  |    9 +
 src/workflows/workflow_CentOSPython.xml.in     |   11 +
 src/workflows/workflow_CentOSPython3.xml.in    |   11 +
 src/workflows/workflow_CentOSVmcore.xml.in     |   12 +
 src/workflows/workflow_CentOSXorg.xml.in       |    9 +
 22 files changed, 2402 insertions(+), 2 deletions(-)
 create mode 100644 src/plugins/centos_report_event.conf
 create mode 100644 src/plugins/mantisbt.c
 create mode 100644 src/plugins/mantisbt.conf
 create mode 100644 src/plugins/mantisbt.h
 create mode 100644 src/plugins/mantisbt_format.conf
 create mode 100644 src/plugins/mantisbt_formatdup.conf
 create mode 100644 src/plugins/report_CentOSBugTracker.conf
 create mode 100644 src/plugins/report_CentOSBugTracker.xml.in
 create mode 100644 src/plugins/reporter-mantisbt.c
 create mode 100644 src/workflows/report_centos.conf
 create mode 100644 src/workflows/workflow_CentOSCCpp.xml.in
 create mode 100644 src/workflows/workflow_CentOSJava.xml.in
 create mode 100644 src/workflows/workflow_CentOSKerneloops.xml.in
 create mode 100644 src/workflows/workflow_CentOSLibreport.xml.in
 create mode 100644 src/workflows/workflow_CentOSPython.xml.in
 create mode 100644 src/workflows/workflow_CentOSPython3.xml.in
 create mode 100644 src/workflows/workflow_CentOSVmcore.xml.in
 create mode 100644 src/workflows/workflow_CentOSXorg.xml.in

diff --git a/configure.ac b/configure.ac
index 8aea410..66508c0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -131,6 +131,39 @@ do
 done
 fi dnl end NO_BUGZILLA
 
+AC_ARG_WITH(mantisbt,
+AS_HELP_STRING([--with-mantisbt],[use MantisBT plugin (default is YES)]),
+LIBREPORT_PARSE_WITH([mantisbt]))
+
+if test -z "$NO_MANTISBT"; then
+AM_CONDITIONAL(BUILD_MANTISBT, true)
+
+# enable mantisbt & deps translations
+for FILE in `grep -e "#.*antisbt.*" -e "#.*naconda.*" po/POTFILES.in`
+do
+  sed -ie "s,$FILE,${FILE:1}," po/POTFILES.in
+  sed -ie "\,^${FILE:1}$,d" po/POTFILES.skip
+done
+else
+AM_CONDITIONAL(BUILD_MANTISBT, false)
+
+# disablie mantisbt & deps translations
+for FILE in `grep -e "antisbt" -e "naconda" po/POTFILES.in`
+do
+  if test "${FILE:0:1}" = "#"
+  then
+    continue
+  fi
+
+  sed -ie "s,$FILE,#$FILE," po/POTFILES.in
+  grep "$FILE" po/POTFILES.skip > /dev/null 2>&1
+  if test $?
+  then
+    echo "$FILE" >> po/POTFILES.skip
+  fi
+done
+fi dnl end NO_MANTISBT
+
 AC_PATH_PROG([PYTHON_CONFIG], [python-config], [no])
 [if test "$PYTHON_CONFIG" = "no"]
 [then]
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5588540..3415b03 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -36,6 +36,8 @@ src/plugins/reporter-print.c
 src/plugins/reporter-rhtsupport.c
 src/plugins/reporter-rhtsupport-parse.c
 src/plugins/reporter-upload.c
+src/plugins/reporter-mantisbt.c
+src/plugins/report_CentOSBugTracker.xml.in
 src/plugins/report_Kerneloops.xml.in
 src/plugins/report_Logger.xml.in
 src/plugins/report_Mailx.xml.in
@@ -44,12 +46,21 @@ src/plugins/report_Uploader.xml.in
 src/plugins/report_uReport.xml.in
 src/plugins/report_EmergencyAnalysis.xml.in
 src/plugins/rhbz.c
+src/plugins/mantisbt.c
 src/plugins/reporter-ureport.c
 src/report-newt/report-newt.c
 src/workflows/workflow_AnacondaFedora.xml.in
 src/workflows/workflow_AnacondaRHEL.xml.in
 src/workflows/workflow_AnacondaRHELBugzilla.xml.in
 src/workflows/workflow_AnacondaUpload.xml.in
+src/workflows/workflow_CentOSCCpp.xml.in
+src/workflows/workflow_CentOSJava.xml.in
+src/workflows/workflow_CentOSKerneloops.xml.in
+src/workflows/workflow_CentOSLibreport.xml.in
+src/workflows/workflow_CentOSPython.xml.in
+src/workflows/workflow_CentOSPython3.xml.in
+src/workflows/workflow_CentOSVmcore.xml.in
+src/workflows/workflow_CentOSXorg.xml.in
 src/workflows/workflow_FedoraCCpp.xml.in
 src/workflows/workflow_FedoraKerneloops.xml.in
 src/workflows/workflow_FedoraPython.xml.in
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 7ec08d7..d70b4db 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -7,6 +7,11 @@ reporters_bin += \
     report
 endif
 
+if BUILD_MANTISBT
+reporters_bin += \
+    reporter-mantisbt
+endif
+
 if BUILD_UREPORT
 reporters_bin +=  reporter-ureport
 endif
@@ -34,6 +39,12 @@ reporters_plugin_format_conf += bugzilla_format.conf \
     bugzilla_formatdup_anaconda.conf
 endif
 
+if BUILD_MANTISBT
+reporters_plugin_conf += mantisbt.conf
+reporters_plugin_format_conf += mantisbt_format.conf \
+    mantisbt_formatdup.conf
+endif
+
 defaultreportpluginsconfdir = $(DEFAULT_REPORT_PLUGINS_CONF_DIR)
 dist_defaultreportpluginsconf_DATA = $(reporters_plugin_conf) \
     rhtsupport.conf \
@@ -53,6 +64,12 @@ reporters_events += report_Bugzilla.xml
 reporters_events_conf += report_Bugzilla.conf
 endif
 
+if BUILD_MANTISBT
+reporters_events += report_CentOSBugTracker.xml
+
+reporters_events_conf += report_CentOSBugTracker.conf
+endif
+
 if BUILD_UREPORT
 reporters_events += report_uReport.xml
 endif
@@ -77,7 +94,8 @@ dist_eventsdef_DATA = \
     print_event.conf \
     rhtsupport_event.conf \
     uploader_event.conf \
-    emergencyanalysis_event.conf
+    emergencyanalysis_event.conf \
+    centos_report_event.conf
 
 reporters_extra_dist =
 if BUILD_BUGZILLA
@@ -125,6 +143,29 @@ reporter_bugzilla_LDADD = \
     ../lib/libreport.la
 endif
 
+if BUILD_MANTISBT
+reporter_mantisbt_SOURCES = \
+    reporter-mantisbt.c mantisbt.c mantisbt.h
+reporter_mantisbt_CPPFLAGS = \
+    -I$(srcdir)/../include \
+    -I$(srcdir)/../lib \
+    -DBIN_DIR=\"$(bindir)\" \
+    -DCONF_DIR=\"$(CONF_DIR)\" \
+    -DLOCALSTATEDIR='"$(localstatedir)"' \
+    -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \
+    -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \
+    -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \
+    -DPLUGINS_CONF_DIR=\"$(REPORT_PLUGINS_CONF_DIR)\" \
+    $(GLIB_CFLAGS) \
+    $(LIBREPORT_CFLAGS) \
+    $(LIBXML_CFLAGS) \
+    -D_GNU_SOURCE
+reporter_mantisbt_LDADD = \
+    $(GLIB_LIBS) \
+    ../lib/libreport-web.la \
+    ../lib/libreport.la
+endif
+
 reporter_rhtsupport_SOURCES = \
     abrt_rh_support.h abrt_rh_support.c \
     reporter-rhtsupport.h \
diff --git a/src/plugins/centos_report_event.conf b/src/plugins/centos_report_event.conf
new file mode 100644
index 0000000..53f12d8
--- /dev/null
+++ b/src/plugins/centos_report_event.conf
@@ -0,0 +1,37 @@
+EVENT=report_CentOSBugTracker analyzer=xorg
+    reporter-mantisbt
+
+EVENT=report_CentOSBugTracker analyzer=Kerneloops
+    reporter-mantisbt
+
+EVENT=report_CentOSBugTracker analyzer=vmcore
+        reporter-mantisbt
+
+EVENT=report_CentOSBugTracker analyzer=Python component!=anaconda
+        test -f component || abrt-action-save-package-data
+        reporter-mantisbt \
+                -c /etc/libreport/plugins/mantisbt.conf \
+                -F /etc/libreport/plugins/mantisbt_format.conf \
+                -A /etc/libreport/plugins/mantisbt_formatdup.conf
+
+EVENT=report_CentOSBugTracker analyzer=Python3 component!=anaconda
+        test -f component || abrt-action-save-package-data
+        reporter-mantisbt \
+                -c /etc/libreport/plugins/mantisbt.conf \
+                -F /etc/libreport/plugins/mantisbt_format.conf \
+                -A /etc/libreport/plugins/mantisbt_formatdup.conf
+
+EVENT=report_CentOSBugTracker analyzer=CCpp duphash!=
+        test -f component || abrt-action-save-package-data
+        component="`cat component`"
+        format="mantisbt_format.conf"
+        test -f "/etc/libreport/plugins/mantisbt_format_$component.conf" \
+                && format="mantisbt_format_$component.conf"
+        formatdup="mantisbt_formatdup.conf"
+        test -f "/etc/libreport/plugins/mantisbt_formatdup_$component.conf" \
+                && formatdup="mantisbt_formatdup_$component.conf"
+        reporter-mantisbt \
+                -c /etc/libreport/plugins/mantisbt.conf \
+                -F "/etc/libreport/plugins/$format" \
+                -A "/etc/libreport/plugins/$formatdup"
+
diff --git a/src/plugins/mantisbt.c b/src/plugins/mantisbt.c
new file mode 100644
index 0000000..1c496b4
--- /dev/null
+++ b/src/plugins/mantisbt.c
@@ -0,0 +1,1111 @@
+/*
+    Copyright (C) 2014  ABRT team
+    Copyright (C) 2014  RedHat Inc
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include <curl/curl.h>
+
+#include <libxml/xmlreader.h>
+
+#include "internal_libreport.h"
+#include "libreport_curl.h"
+#include "mantisbt.h"
+#include "client.h"
+
+/*
+ * SOAP
+*/
+
+#define XML_VERSION "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+
+/* fprint string */
+#define SOAP_TEMPLATE \
+    "<SOAP-ENV:Envelope xmlns:ns3=\"http://schemas.xmlsoap.org/soap/encoding/\" " \
+        "xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" " \
+        "xmlns:ns0=\"http://schemas.xmlsoap.org/soap/encoding/\" " \
+        "xmlns:ns1=\"http://schemas.xmlsoap.org/soap/envelope/\" " \
+        "xmlns:ns2=\"http://www.w3.org/2001/XMLSchema\" " \
+        "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
+        "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" " \
+        "SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" \
+    "<SOAP-ENV:Header/>" \
+    "<ns1:Body>" \
+        "<ns3:%s>" \
+        "</ns3:%s>" \
+    "</ns1:Body>" \
+    "</SOAP-ENV:Envelope>"
+
+#define MAX_SUMMARY_LENGTH  128
+#define CUSTOMFIELD_DUPHASH "abrt_hash"
+#define CUSTOMFIELD_URL "URL"
+#define MAX_HOPS 5
+
+/* MantisBT limit is 2MB by default
+ */
+#define MANTISBT_MAX_FILE_UPLOAD_SIZE (2 * 1024 * 1024)
+
+typedef struct mantisbt_custom_fields
+{
+    char *cf_abrt_hash_id;
+    char *cf_url_id;
+} mantisbt_custom_fields_t;
+
+/*
+ * MantisBT settings issue info
+ */
+void
+mantisbt_settings_free(mantisbt_settings_t *s)
+{
+    if (s == NULL)
+        return;
+
+    free(s->m_login);
+    free(s->m_password);
+    free(s->m_project);
+    free(s->m_project_id);
+    free(s->m_project_version);
+}
+
+/*
+ * MantisBT issue info
+ */
+mantisbt_issue_info_t *
+mantisbt_issue_info_new()
+{
+    mantisbt_issue_info_t *info = xzalloc(sizeof(mantisbt_issue_info_t));
+    info->mii_id = -1;
+    info->mii_dup_id = -1;
+
+    return info;
+}
+
+void
+mantisbt_issue_info_free(mantisbt_issue_info_t *info)
+{
+    if (info == NULL)
+        return;
+
+    free(info->mii_status);
+    free(info->mii_resolution);
+    free(info->mii_reporter);
+    free(info->mii_project);
+
+    list_free_with_free(info->mii_notes);
+    list_free_with_free(info->mii_attachments);
+
+    free(info);
+}
+
+mantisbt_issue_info_t *
+mantisbt_find_origin_bug_closed_duplicate(mantisbt_settings_t *settings, mantisbt_issue_info_t *info)
+{
+    mantisbt_issue_info_t *info_tmp = mantisbt_issue_info_new();
+    info_tmp->mii_id = info->mii_id;
+    info_tmp->mii_dup_id = info->mii_dup_id;
+
+    for (int ii = 0; ii <= MAX_HOPS; ii++)
+    {
+        if (ii == MAX_HOPS)
+            error_msg_and_die(_("MantisBT couldn't find parent of issue %d"), info->mii_id);
+
+        log("Issue %d is a duplicate, using parent issue %d", info_tmp->mii_id, info_tmp->mii_dup_id);
+        int issue_id = info_tmp->mii_dup_id;
+
+        mantisbt_issue_info_free(info_tmp);
+        info_tmp = mantisbt_get_issue_info(settings, issue_id);
+
+        // found a issue which is not CLOSED as DUPLICATE
+        if (info_tmp->mii_dup_id == -1)
+            break;
+    }
+
+    return info_tmp;
+}
+
+/*
+ * SOAP request
+ */
+static soap_request_t *
+soap_request_new()
+{
+    soap_request_t *req = xzalloc(sizeof(*req));
+
+    return req;
+}
+
+void
+soap_request_free(soap_request_t *req)
+{
+    if (req == NULL)
+        return;
+
+    if (req->sr_root != NULL)
+        xmlFreeDoc(req->sr_root->doc);
+
+    free(req);
+
+    return;
+}
+
+static xmlNodePtr
+soap_node_get_next_element_node(xmlNodePtr node)
+{
+    for (; node != NULL; node = node->next)
+        if (node->type == XML_ELEMENT_NODE)
+            break;
+
+    return node;
+}
+
+static xmlNodePtr
+soap_node_get_child_element(xmlNodePtr node)
+{
+    if (node == NULL)
+        error_msg_and_die(_("SOAP: Failed to get child element because of no parent."));
+
+    return soap_node_get_next_element_node(node->xmlChildrenNode);
+}
+
+static xmlNodePtr
+soap_node_get_next_sibling(xmlNodePtr node)
+{
+    if (node == NULL)
+        error_msg_and_die(_("SOAP: Failed to get next element because of no node."));
+
+    return soap_node_get_next_element_node(node->next);
+}
+
+static xmlNodePtr
+soap_node_get_child_node(xmlNodePtr parent, const char *name)
+{
+    if (parent == NULL)
+        error_msg_and_die(_("SOAP: Failed to get child node because of no parent."));
+
+    xmlNodePtr node;
+    for (node = soap_node_get_child_element(parent); node != NULL; node = soap_node_get_next_sibling(node))
+    {
+        if (xmlStrcmp(node->name, BAD_CAST name) == 0)
+            return node;
+    }
+
+    return NULL;
+}
+
+soap_request_t *
+soap_request_new_for_method(const char *method)
+{
+    char *xml_str = xasprintf(SOAP_TEMPLATE, method, method);
+
+    xmlDocPtr doc = xmlParseDoc(BAD_CAST xml_str);
+    free(xml_str);
+
+    if (doc == NULL)
+        error_msg_and_die(_("SOAP: Failed to parse xml during creating request."));
+
+    soap_request_t *req = soap_request_new();
+
+    req->sr_root = xmlDocGetRootElement(doc);
+    if (req->sr_root == NULL)
+    {
+        soap_request_free(req);
+        error_msg_and_die(_("SOAP: Failed to get xml root element."));
+    }
+
+    req->sr_body = soap_node_get_child_node(req->sr_root, "Body");
+    req->sr_method = soap_node_get_child_node(req->sr_body, method);
+
+    return req;
+}
+
+static xmlNodePtr
+soap_node_add_child_node(xmlNodePtr node, const char *name, const char *type, const char *value)
+{
+    if (node == NULL || name == NULL)
+        error_msg_and_die(_("SOAP: Failed to add a new child node because of no node or no child name."));
+
+    xmlNodePtr new_node = xmlNewTextChild(node, /* namespace */ NULL, BAD_CAST name, BAD_CAST value);
+
+    if (new_node == NULL)
+        error_msg_and_die(_("SOAP: Failed to create a new xml child item."));
+
+    if (type != NULL)
+    {
+        if (xmlNewProp(new_node, BAD_CAST "xsi:type", BAD_CAST type) == NULL)
+            error_msg_and_die(_("SOAP: Failed to create a new property."));
+    }
+
+    return new_node;
+}
+
+void
+soap_request_add_method_parameter(soap_request_t *req, const char *name, const char *type, const char *value)
+{
+    if (req == NULL || req->sr_method == NULL)
+        error_msg_and_die(_("SOAP: Failed to add method parametr."));
+
+    soap_node_add_child_node(req->sr_method, name, type, value);
+    return;
+}
+
+void
+soap_request_add_credentials_parameter(soap_request_t *req, const mantisbt_settings_t *settings)
+{
+    soap_request_add_method_parameter(req, "username", SOAP_STRING, settings->m_login);
+    soap_request_add_method_parameter(req, "password", SOAP_STRING, settings->m_password);
+
+    return;
+}
+
+static void
+soap_add_new_issue_parameters(soap_request_t *req,
+                               const char *project,
+                               const char *version,
+                               const char *category,
+                               const char *summary,
+                               const char *description,
+                               const char *additional_information,
+                               bool private,
+                               mantisbt_custom_fields_t *fields,
+                               const char *duphash,
+                               const char *tracker_url)
+{
+    if (req == NULL || req->sr_method == NULL)
+        error_msg_and_die(_("SOAP: Failed to add new issue parametrs."));
+
+    if (project == NULL || category == NULL || summary == NULL || description == NULL)
+        error_msg_and_die(_("SOAP: Failed to add new issue parameters because the required items are missing."));
+
+    xmlNodePtr issue_node = soap_node_add_child_node(req->sr_method, "issue", SOAP_ISSUEDATA, /* content */ NULL);
+
+    // project
+    xmlNodePtr project_node = soap_node_add_child_node(issue_node, "project", SOAP_OBJECTREF, /* content */ NULL);
+    soap_node_add_child_node(project_node, "name", SOAP_STRING, project);
+
+    // view status
+    xmlNodePtr view_node = soap_node_add_child_node(issue_node, "view_state", SOAP_OBJECTREF, /* content */ NULL);
+    soap_node_add_child_node(view_node, "name", SOAP_STRING, (private) ? "private" : "public");
+
+    /* if any custom field exists */
+    int custom_fields_count = 0;
+    xmlNodePtr duphash_node;
+    if (fields->cf_abrt_hash_id != NULL || fields->cf_url_id != NULL)
+        duphash_node = soap_node_add_child_node(issue_node, "custom_fields", SOAP_CUSTOMFIELD_ARRAY, /* content */ NULL);
+
+    // custom fields (duphash and URL to tracker)
+    xmlNodePtr item_node, field_node;
+    if (fields->cf_abrt_hash_id != NULL)
+    {
+        item_node = soap_node_add_child_node(duphash_node, "item", SOAP_CUSTOMFIELD, /* content */ NULL);
+        field_node = soap_node_add_child_node(item_node, "field", SOAP_OBJECTREF, /* content */ NULL);
+        soap_node_add_child_node(field_node, "id", SOAP_INTEGER, /* custom_field id */ fields->cf_abrt_hash_id);
+        soap_node_add_child_node(item_node, "value", SOAP_STRING, duphash);
+        ++custom_fields_count;
+    }
+
+    // if tracker url exists, attach it to the issue
+    if (tracker_url != NULL && fields->cf_url_id != NULL)
+    {
+        item_node = soap_node_add_child_node(duphash_node, "item", SOAP_CUSTOMFIELD, /* content */ NULL);
+        field_node = soap_node_add_child_node(item_node, "field", SOAP_OBJECTREF, /* content */ NULL);
+        soap_node_add_child_node(field_node, "id", SOAP_INTEGER, /* custom_field */ fields->cf_url_id);
+        soap_node_add_child_node(item_node, "value", SOAP_STRING, tracker_url);
+        ++custom_fields_count;
+    }
+
+    if (custom_fields_count > 0)
+    {
+        char *type = xasprintf("%s[%i]", SOAP_CUSTOMFIELD, custom_fields_count);
+
+        if (xmlNewProp(duphash_node, BAD_CAST "ns3:arrayType", BAD_CAST type) == NULL)
+            error_msg_and_die(_("SOAP: Failed to create a new property in custom fields."));
+
+        free(type);
+    }
+
+    soap_node_add_child_node(issue_node, "os_build", SOAP_STRING, version);
+    soap_node_add_child_node(issue_node, "category", SOAP_STRING, category);
+    soap_node_add_child_node(issue_node, "summary", SOAP_STRING, summary);
+    soap_node_add_child_node(issue_node, "description", SOAP_STRING, description);
+    soap_node_add_child_node(issue_node, "additional_information", SOAP_STRING, additional_information);
+
+    return;
+}
+
+char *
+soap_request_to_str(const soap_request_t *req)
+{
+    if (req == NULL || req->sr_root == NULL || req->sr_root->doc == NULL)
+        error_msg_and_die(_("SOAP: Failed to create SOAP string because of invalid function arguments."));
+
+    xmlBufferPtr buffer = xmlBufferCreate();
+    int err = xmlNodeDump(buffer, req->sr_root->doc, req->sr_root, 1, /* formatting */ 0);
+    if (err == -1)
+    {
+        xmlBufferFree(buffer);
+        error_msg_and_die(_("SOAP: Failed to dump xml node."));
+    }
+
+    char *ret = xasprintf("%s%s", XML_VERSION, (const char *) xmlBufferContent(buffer));
+    xmlBufferFree(buffer);
+
+    return ret;
+}
+
+#if 0
+void
+soap_request_print(soap_request_t *req)
+{
+    if (req == NULL || req->sr_root == NULL || req->sr_root->doc == NULL)
+        error_msg_and_die(_("SOAP: Failed to print SOAP string."));
+
+    xmlBufferPtr buffer = xmlBufferCreate();
+    int err = xmlNodeDump(buffer, req->sr_root->doc, req->sr_root, 1, /* formatting */ 0);
+    if (err == -1)
+    {
+        xmlBufferFree(buffer);
+        error_msg_and_die(_("Failed to dump xml node."));
+    }
+
+    puts((const char *) xmlBufferContent(buffer));
+
+    xmlBufferFree(buffer);
+    return;
+}
+#endif
+
+static bool
+reader_move_reader_if_node_type_is_element_with_name_and_verify_its_value(xmlTextReaderPtr reader, const char *name)
+{
+    /* is not element node */
+    if (xmlTextReaderNodeType(reader) != XML_ELEMENT_NODE)
+        return false;
+
+    /* is not required name */
+    if (xmlStrcmp(xmlTextReaderConstName(reader), BAD_CAST name) != 0)
+        return false;
+
+    /* read next node */
+    if (xmlTextReaderRead(reader) != 1)
+        return false;
+
+    /* no value node */
+    if (xmlTextReaderHasValue(reader) == 0)
+        return false;
+
+    /* no text node */
+    if (xmlTextReaderNodeType(reader) != XML_TEXT_NODE)
+        return false;
+
+    return true;
+}
+
+static void
+reader_find_element_by_name(xmlTextReaderPtr reader, const char *name)
+{
+    while (xmlTextReaderRead(reader) == 1)
+    {
+        /* is not element node */
+        if (xmlTextReaderNodeType(reader) != XML_ELEMENT_NODE)
+            continue;
+
+        /* is not required name */
+        if (xmlStrcmp(xmlTextReaderConstName(reader), BAD_CAST name) != 0)
+            continue;
+
+        break;
+    }
+
+    return;
+}
+
+/* It is not possible to search only by name because the response contains
+ * different node with the same name. (e.g. id - user id, project id, issue id etc.)
+ * We are interested in only about issues id which is located at a different depth than others.
+ * ...
+ *   <item xsi:type="ns1:IssueData">
+ *      <id xsi:type="xsd:integer">10</id>      <-- This is issue ID (required)
+ *      <view_state xsi:type="ns1:ObjectRef">
+ *          <id xsi:type="xsd:integer">10</id>  <-- This is view_state ID (not required)
+ *          <name xsi:type="xsd:string">public</name>
+ *      </view_state>
+ *      <project xsi:type="ns1:ObjectRef">
+ *          <id xsi:type="xsd:integer">1</id>   <-- This is project ID (not required)
+ *          <name xsi:type="xsd:string">test</name>
+ *      </project>
+ * ...
+ */
+static GList *
+response_values_at_depth_by_name(const char *xml, const char *name, int depth)
+{
+    xmlDocPtr doc = xmlParseDoc(BAD_CAST xml);
+    if (doc == NULL)
+        error_msg_and_die(_("SOAP: Failed to parse xml (searching value at depth by name)."));
+
+    xmlTextReaderPtr reader = xmlReaderWalker(doc);
+    if (reader == NULL)
+        error_msg_and_die(_("SOAP: Failed to create xml text reader."));
+
+    GList *result = NULL;
+
+    const xmlChar *value;
+    while (xmlTextReaderRead(reader) == 1)
+    {
+        /* is not right depth */
+        if (depth != -1 && xmlTextReaderDepth(reader) != depth)
+            continue;
+
+        if (reader_move_reader_if_node_type_is_element_with_name_and_verify_its_value(reader, name) == false)
+            continue;
+
+        if ((value = xmlTextReaderConstValue(reader)) != NULL)
+            result = g_list_append(result, xstrdup((const char *) value));
+    }
+    xmlFreeTextReader(reader);
+
+    return result;
+}
+
+/*
+ * Finds an element named 'elem' and returns a text of a child named 'name'
+ *
+ * Example:
+ *  For
+ *  <elem>
+ *      <id>1</id>
+ *      <name>foo</name>
+ *  </elem>
+ *
+ *  returns "foo"
+ */
+static char *
+response_get_name_value_of_element(const char *xml, const char *element)
+{
+    xmlDocPtr doc = xmlParseDoc(BAD_CAST xml);
+    if (doc == NULL)
+        error_msg_and_die(_("SOAP: Failed to parse xml."));
+
+    xmlTextReaderPtr reader = xmlReaderWalker(doc);
+    if (reader == NULL)
+        error_msg_and_die(_("SOAP: Failed to create xml text reader."));
+
+    const xmlChar *value = NULL;
+
+    reader_find_element_by_name(reader, element);
+
+    /* find 'name' element and return its text */
+    while (xmlTextReaderRead(reader) == 1)
+    {
+        if (reader_move_reader_if_node_type_is_element_with_name_and_verify_its_value(reader, "name") == false)
+            continue;
+
+        if ((value = xmlTextReaderConstValue(reader)) != NULL)
+            break;
+    }
+    xmlFreeTextReader(reader);
+
+    return (char *) value;
+}
+
+static int
+response_get_id_of_relatedto_issue(const char *xml)
+{
+    xmlDocPtr doc = xmlParseDoc(BAD_CAST xml);
+    if (doc == NULL)
+        error_msg_and_die(_("SOAP: Failed to parse xml (get related to issue)."));
+
+    xmlTextReaderPtr reader = xmlReaderWalker(doc);
+    if (reader == NULL)
+        error_msg_and_die(_("SOAP: Failed to create xml text reader."));
+
+    const xmlChar *value = NULL;
+    const xmlChar *id = NULL;
+
+    /* find relationships section */
+    reader_find_element_by_name(reader, "relationships");
+
+    /* find "name" value of 'name' element */
+    while (xmlTextReaderRead(reader) == 1)
+    {
+        /* find type of relattionship */
+        if (reader_move_reader_if_node_type_is_element_with_name_and_verify_its_value(reader, "name") == false)
+            continue;
+
+        if ((value = xmlTextReaderConstValue(reader)) == NULL)
+            continue;
+
+        /* we need 'duplicate of' realtionship type */
+        if (xmlStrcmp(value, BAD_CAST "duplicate of") != 0)
+            continue;
+
+        /* find id of duplicate issues */
+        reader_find_element_by_name(reader, "target_id");
+
+        /* verify target_id node */
+        if (reader_move_reader_if_node_type_is_element_with_name_and_verify_its_value(reader, "target_id") == false)
+            continue;
+
+        /* get its value */
+        if ((id = xmlTextReaderConstValue(reader)) != NULL)
+            break;
+    }
+    xmlFreeTextReader(reader);
+
+    return (id == NULL) ? -1 : atoi((const char *) id);
+}
+
+GList *
+response_get_main_ids_list(const char *xml)
+{
+    return response_values_at_depth_by_name(xml, "id", 5);
+}
+
+int
+response_get_main_id(const char *xml)
+{
+    GList *l = response_values_at_depth_by_name(xml, "id", 5);
+    return (l != NULL) ? atoi(l->data) : -1;
+}
+
+static int
+response_get_return_value(const char *xml)
+{
+    GList *l = response_values_at_depth_by_name(xml, "return", 3);
+    return (l != NULL) ? atoi(l->data) : -1;
+}
+
+static char*
+response_get_return_value_as_string(const char *xml)
+{
+    GList *l = response_values_at_depth_by_name(xml, "return", 3);
+    return (l != NULL) ? l->data : NULL;
+}
+
+static char *
+response_get_error_msg(const char *xml)
+{
+    GList *l = response_values_at_depth_by_name(xml, "faultstring", 3);
+    return (l != NULL) ? xstrdup(l->data) : NULL;
+}
+
+static char *
+response_get_additioanl_information(const char *xml)
+{
+    GList *l = response_values_at_depth_by_name(xml, "additional_information", -1);
+    return (l != NULL) ? xstrdup(l->data) : NULL;
+}
+
+void
+response_values_free(GList *values)
+{
+    g_list_free_full(values, free);
+}
+
+/*
+ * POST
+ */
+
+void
+mantisbt_result_free(mantisbt_result_t *result)
+{
+    if (result == NULL)
+        return;
+
+    free(result->mr_url);
+    free(result->mr_msg);
+    free(result->mr_body);
+    free(result);
+}
+
+mantisbt_result_t *
+mantisbt_soap_call(const mantisbt_settings_t *settings, const soap_request_t *req)
+{
+    char *request = soap_request_to_str(req);
+
+    const char *url = settings->m_mantisbt_soap_url;
+
+    mantisbt_result_t *result = xzalloc(sizeof(*result));
+
+    if (url == NULL || request == NULL)
+    {
+        result->mr_error = -2;
+        result->mr_msg = xasprintf(_("Url or request isn't specified."));
+        free(request);
+
+        return result;
+    }
+
+    char *url_copy = NULL;
+
+    int redirect_count = 0;
+    char *errmsg;
+    post_state_t *post_state;
+
+redirect:
+    post_state = new_post_state(0
+            + POST_WANT_HEADERS
+            + POST_WANT_BODY
+            + POST_WANT_ERROR_MSG
+            + (settings->m_ssl_verify ? POST_WANT_SSL_VERIFY : 0)
+    );
+
+    post_string(post_state, settings->m_mantisbt_soap_url, "text/xml", NULL, request);
+
+    char *location = find_header_in_post_state(post_state, "Location:");
+
+    switch (post_state->http_resp_code)
+    {
+    case 404:
+        result->mr_error = -1;
+        result->mr_msg = xasprintf(_("Error in HTTP POST, "
+                        "HTTP code: 404 (Not found), URL:'%s'"), url);
+        break;
+    case 500:
+        result->mr_error = -1;
+        result->mr_msg = response_get_error_msg(post_state->body);
+
+        break;
+    case 301: /* "301 Moved Permanently" (for example, used to move http:// to https://) */
+    case 302: /* "302 Found" (just in case) */
+    case 305: /* "305 Use Proxy" */
+        if (++redirect_count < 10 && location)
+        {
+            free(url_copy);
+            url = url_copy = xstrdup(location);
+            free_post_state(post_state);
+            goto redirect;
+        }
+        /* fall through */
+
+    default:
+        result->mr_error = -1;
+        errmsg = post_state->curl_error_msg;
+        if (errmsg && errmsg[0])
+            result->mr_msg = xasprintf(_("Error in MantisBT request at '%s': %s"), url, errmsg);
+        else
+            result->mr_msg = xasprintf(_("Error in MantisBT request at '%s'"), url);
+        break;
+
+    case 200:
+    case 201:
+        /* sent successfully */
+        result->mr_url = xstrdup(location); /* note: xstrdup(NULL) returns NULL */
+    } /* switch (HTTP code) */
+
+    result->mr_http_resp_code = post_state->http_resp_code;
+    result->mr_body = post_state->body;
+    post_state->body = NULL;
+
+    free_post_state(post_state);
+    free(url_copy);
+    free(request);
+
+    return result;
+}
+
+int
+mantisbt_attach_data(const mantisbt_settings_t *settings, const char *bug_id,
+                    const char *att_name, const char *data, int size)
+{
+    soap_request_t *req = soap_request_new_for_method("mc_issue_attachment_add");
+    soap_request_add_credentials_parameter(req, settings);
+
+    soap_request_add_method_parameter(req, "issue_id", SOAP_INTEGER, bug_id);
+    soap_request_add_method_parameter(req, "name", SOAP_STRING, att_name);
+
+    soap_request_add_method_parameter(req, "file_type", SOAP_STRING, "text");
+    soap_request_add_method_parameter(req, "content", SOAP_BASE64, encode_base64(data, size));
+
+    mantisbt_result_t *result = mantisbt_soap_call(settings, req);
+    soap_request_free(req);
+
+    if (result->mr_http_resp_code != 200)
+    {
+        int ret = -1;
+        if (strcmp(result->mr_msg, "Duplicate filename.") == 0)
+            ret = -2;
+
+        error_msg(_("Failed to attach file: '%s'"), result->mr_msg);
+        mantisbt_result_free(result);
+        return ret;
+    }
+
+    int id = response_get_return_value(result->mr_body);
+
+    mantisbt_result_free(result);
+
+    return id;
+}
+
+static int
+mantisbt_attach_fd(const mantisbt_settings_t *settings, const char *bug_id,
+                const char *att_name, int fd)
+{
+    off_t size = lseek(fd, 0, SEEK_END);
+    if (size < 0)
+    {
+        perror_msg(_("Can't lseek '%s'"), att_name);
+        return -1;
+    }
+
+    if (size >= MANTISBT_MAX_FILE_UPLOAD_SIZE)
+    {
+        error_msg(_("Can't upload '%s', it's too large (%llu bytes)"), att_name, (long long)size);
+        return -1;
+    }
+    lseek(fd, 0, SEEK_SET);
+
+    char *data = xmalloc(size + 1);
+    ssize_t r = full_read(fd, data, size);
+    if (r < 0)
+    {
+        free(data);
+        perror_msg(_("Can't read '%s'"), att_name);
+        return -1;
+    }
+
+    int res = mantisbt_attach_data(settings, bug_id, att_name, data, size);
+    free(data);
+    return res;
+}
+
+int
+mantisbt_attach_file(const mantisbt_settings_t *settings, const char *bug_id,
+                    const char *att_name, const char *path)
+{
+    int fd = open(path, O_RDONLY);
+    if (fd < 0)
+    {
+        perror_msg(_("Can't open '%s'"), path);
+        return 0;
+    }
+    errno = 0;
+    struct stat st;
+    if (fstat(fd, &st) != 0 || !S_ISREG(st.st_mode))
+    {
+        perror_msg("'%s': not a regular file", path);
+        close(fd);
+        return 0;
+    }
+    log_debug("attaching '%s' as file", att_name);
+    int ret = mantisbt_attach_fd(settings, bug_id, att_name, fd);
+    close(fd);
+    return ret;
+}
+
+static void
+soap_filter_add_new_array_parameter(xmlNodePtr filter_node, const char *name, const char *type, const char *value)
+{
+    const char *array_type = NULL;
+    if( strcmp(type, SOAP_INTEGER) == 0 )
+        array_type = SOAP_INTEGERARRAY;
+    else
+        array_type = SOAP_STRINGARRAY;
+
+    xmlNodePtr filter_item = soap_node_add_child_node(filter_node, name, array_type, /* content */ NULL);
+    soap_node_add_child_node(filter_item, "item", type, value);
+}
+
+static void
+soap_filter_custom_fields_add_new_item(xmlNodePtr filter_node, const char *custom_field_name, const char *value)
+{
+    xmlNodePtr item_node = soap_node_add_child_node(filter_node, "item", SOAP_FILTER_CUSTOMFIELD, /* content */ NULL);
+
+    xmlNodePtr field_node = soap_node_add_child_node(item_node, "field", SOAP_OBJECTREF, /* content */ NULL);
+    soap_node_add_child_node(field_node, "name", SOAP_STRING, custom_field_name);
+
+    xmlNodePtr value_node = soap_node_add_child_node(item_node, "value", SOAP_STRINGARRAY, /* content */ NULL);
+    soap_node_add_child_node(value_node, "item", SOAP_STRING, value);
+}
+
+GList *
+mantisbt_search_by_abrt_hash(mantisbt_settings_t *settings, const char *abrt_hash)
+{
+    soap_request_t *req = soap_request_new_for_method("mc_filter_search_issues");
+    soap_request_add_credentials_parameter(req, settings);
+
+    xmlNodePtr filter_node = soap_node_add_child_node(req->sr_method, "filter", SOAP_FILTER_SEARCH_DATA, /* content */ NULL);
+
+    /* 'hide_status_is : -2' means, searching within all status */
+    soap_filter_add_new_array_parameter(filter_node, "hide_status_id", SOAP_INTEGERARRAY, "-2");
+
+    // custom fields
+    xmlNodePtr custom_fields_node = soap_node_add_child_node(filter_node, "custom_fields", SOAP_FILTER_CUSTOMFIELD_ARRAY, /* content */ NULL);
+
+    // custom field 'abrt_hash'
+    soap_filter_custom_fields_add_new_item(custom_fields_node, "abrt_hash", abrt_hash);
+
+    soap_request_add_method_parameter(req, "page_number", SOAP_INTEGER, "1");
+    soap_request_add_method_parameter(req, "per_page", SOAP_INTEGER, /* -1 means get all issues */ "-1");
+
+    mantisbt_result_t *result = mantisbt_soap_call(settings, req);
+    soap_request_free(req);
+
+    if (result->mr_error == -1)
+    {
+        error_msg(_("Failed to search MantisBT issue by duphash: '%s'"), result->mr_msg);
+        mantisbt_result_free(result);
+        return NULL;
+    }
+
+    GList *ids = response_get_main_ids_list(result->mr_body);
+
+    return ids;
+}
+
+GList *
+mantisbt_search_duplicate_issues(mantisbt_settings_t *settings, const char *category,
+                                     const char *version, const char *abrt_hash)
+{
+    soap_request_t *req = soap_request_new_for_method("mc_filter_search_issues");
+    soap_request_add_credentials_parameter(req, settings);
+
+    xmlNodePtr filter_node = soap_node_add_child_node(req->sr_method, "filter", SOAP_FILTER_SEARCH_DATA, /* content */ NULL);
+
+    soap_filter_add_new_array_parameter(filter_node, "project_id", SOAP_INTEGERARRAY, settings->m_project_id);
+
+    /* 'hide_status_is : -2' means, searching within all status */
+    soap_filter_add_new_array_parameter(filter_node, "hide_status_id", SOAP_INTEGERARRAY, "-2");
+
+    soap_filter_add_new_array_parameter(filter_node, "category", SOAP_STRINGARRAY, category);
+
+    // custom fields
+    xmlNodePtr custom_fields_node = soap_node_add_child_node(filter_node, "custom_fields", SOAP_FILTER_CUSTOMFIELD_ARRAY, /* content */ NULL);
+
+    // custom field 'abrt_hash'
+    soap_filter_custom_fields_add_new_item(custom_fields_node, "abrt_hash", abrt_hash);
+
+    // version
+    if (version != NULL)
+        soap_filter_add_new_array_parameter(filter_node, "os_build", SOAP_STRINGARRAY, version);
+
+    soap_request_add_method_parameter(req, "page_number", SOAP_INTEGER, "1");
+    soap_request_add_method_parameter(req, "per_page", SOAP_INTEGER, /* -1 means get all issues */ "-1");
+
+    mantisbt_result_t *result = mantisbt_soap_call(settings, req);
+    soap_request_free(req);
+
+    if (result->mr_error == -1)
+    {
+        error_msg(_("Failed to search MantisBT duplicate issue: '%s'"), result->mr_msg);
+        mantisbt_result_free(result);
+        return NULL;
+    }
+
+    GList *ids = response_get_main_ids_list(result->mr_body);
+
+    return ids;
+}
+
+static char *
+custom_field_get_id_from_name(GList *ids, GList *names, const char *name)
+{
+    GList *i = ids;
+    GList *n = names;
+    for (; i != NULL; i = i->next, n = n->next)
+    {
+        if (strcmp(n->data, name) == 0)
+            return i->data;
+    }
+
+    return NULL;
+}
+
+static void
+custom_field_ask(const char *name)
+{
+    char *msg = xasprintf(_("CentOS Bug Tracker doesn't contain custom field '%s', which is required for full functionality of the reporter. Do you still want to create a new issue?"), name);
+    int yes = ask_yes_no(msg);
+    free(msg);
+
+    if (!yes)
+    {
+        set_xfunc_error_retval(EXIT_CANCEL_BY_USER);
+        xfunc_die();
+    }
+
+    return;
+}
+
+static void
+mantisbt_get_custom_fields(const mantisbt_settings_t *settings, mantisbt_custom_fields_t *fields, const char *project_id)
+{
+    soap_request_t *req = soap_request_new_for_method("mc_project_get_custom_fields");
+    soap_request_add_credentials_parameter(req, settings);
+    soap_request_add_method_parameter(req, "project_id", SOAP_INTEGER, project_id);
+
+    mantisbt_result_t *result = mantisbt_soap_call(settings, req);
+    soap_request_free(req);
+
+    if (result->mr_http_resp_code != 200)
+        error_msg_and_die(_("Failed to get custom fields for '%s' project"), settings->m_project);
+
+    GList *ids = response_values_at_depth_by_name(result->mr_body, "id", -1);
+    GList *names = response_values_at_depth_by_name(result->mr_body, "name", -1);
+
+    mantisbt_result_free(result);
+
+    if ((fields->cf_abrt_hash_id = custom_field_get_id_from_name(ids, names, CUSTOMFIELD_DUPHASH)) == NULL)
+        custom_field_ask(CUSTOMFIELD_DUPHASH);
+
+    if ((fields->cf_url_id = custom_field_get_id_from_name(ids, names, CUSTOMFIELD_URL)) == NULL)
+        custom_field_ask(CUSTOMFIELD_URL);
+
+    return;
+}
+
+int
+mantisbt_create_new_issue(const mantisbt_settings_t *settings,
+                   problem_data_t *problem_data,
+                   const problem_report_t *pr,
+                   const char *tracker_url)
+{
+
+    const char *category = problem_data_get_content_or_NULL(problem_data, FILENAME_COMPONENT);
+    const char *duphash = problem_data_get_content_or_NULL(problem_data, FILENAME_DUPHASH);
+
+    char *summary = shorten_string_to_length(problem_report_get_summary(pr), MAX_SUMMARY_LENGTH);
+
+    const char *description = problem_report_get_description(pr);
+    const char *additional_information = problem_report_get_section(pr, PR_SEC_ADDITIONAL_INFO);
+
+    mantisbt_custom_fields_t fields;
+    mantisbt_get_custom_fields(settings, &fields, settings->m_project_id);
+
+    soap_request_t *req = soap_request_new_for_method("mc_issue_add");
+    soap_request_add_credentials_parameter(req, settings);
+    soap_add_new_issue_parameters(req, settings->m_project, settings->m_project_version, category, summary, description, additional_information, settings->m_create_private, &fields, duphash, tracker_url);
+
+    mantisbt_result_t *result = mantisbt_soap_call(settings, req);
+    soap_request_free(req);
+    free(summary);
+
+    if (result->mr_error == -1)
+    {
+        error_msg(_("Failed to create a new issue: '%s'"), result->mr_msg);
+        mantisbt_result_free(result);
+        return -1;
+    }
+
+    int id = response_get_return_value(result->mr_body);
+
+    mantisbt_result_free(result);
+    return id;
+}
+
+mantisbt_issue_info_t *
+mantisbt_get_issue_info(const mantisbt_settings_t *settings, int issue_id)
+{
+    soap_request_t *req = soap_request_new_for_method("mc_issue_get");
+    soap_request_add_credentials_parameter(req, settings);
+
+    char *issue_id_str = xasprintf("%d", issue_id);
+    soap_request_add_method_parameter(req, "issue_id", SOAP_INTEGER, issue_id_str);
+    free(issue_id_str);
+
+    mantisbt_result_t *result = mantisbt_soap_call(settings, req);
+    soap_request_free(req);
+
+    if (result->mr_error == -1)
+    {
+        error_msg(_("Failed to get MantisBT issue: '%s'"), result->mr_msg);
+        mantisbt_result_free(result);
+        return NULL;
+    }
+
+    mantisbt_issue_info_t *issue_info = mantisbt_issue_info_new();
+
+    issue_info->mii_id = issue_id;
+    issue_info->mii_status = response_get_name_value_of_element(result->mr_body, "status");
+    issue_info->mii_resolution = response_get_name_value_of_element(result->mr_body, "resolution");
+    issue_info->mii_reporter = response_get_name_value_of_element(result->mr_body, "reporter");
+    issue_info->mii_project = response_get_name_value_of_element(result->mr_body, "project");
+
+    if (strcmp(issue_info->mii_status, "closed") == 0 && !issue_info->mii_resolution)
+        error_msg(_("Issue %i is CLOSED, but it has no RESOLUTION"), issue_info->mii_id);
+
+    issue_info->mii_dup_id = response_get_id_of_relatedto_issue(result->mr_body);
+
+    if (strcmp(issue_info->mii_status, "closed") == 0
+        && strcmp(issue_info->mii_resolution, "duplicate") == 0
+        && issue_info->mii_dup_id == -1 )
+    {
+        error_msg(_("Issue %i is CLOSED as DUPLICATE, but it has no DUPLICATE_ID"),
+                            issue_info->mii_id);
+    }
+
+    /* notes are stored in <text> element */
+    issue_info->mii_notes = response_values_at_depth_by_name(result->mr_body, "text", -1);
+
+    /* looking for bt rating in additional information too */
+    char *add_info = response_get_additioanl_information(result->mr_body);
+    if (add_info != NULL)
+        issue_info->mii_notes = g_list_append (issue_info->mii_notes, add_info);
+    issue_info->mii_attachments = response_values_at_depth_by_name(result->mr_body, "filename", -1);
+    issue_info->mii_best_bt_rating = comments_find_best_bt_rating(issue_info->mii_notes);
+
+    mantisbt_result_free(result);
+    return issue_info;
+}
+
+int
+mantisbt_add_issue_note(const mantisbt_settings_t *settings, int issue_id, const char *note)
+{
+    soap_request_t *req = soap_request_new_for_method("mc_issue_note_add");
+    soap_request_add_credentials_parameter(req, settings);
+
+    char *issue_id_str = xasprintf("%i", issue_id);
+    soap_node_add_child_node(req->sr_method, "issue_id", SOAP_INTEGER, issue_id_str);
+
+    xmlNodePtr note_node = soap_node_add_child_node(req->sr_method, "note", SOAP_ISSUENOTE, /* content */ NULL);
+    soap_node_add_child_node(note_node, "text", SOAP_STRING, note);
+
+    mantisbt_result_t *result = mantisbt_soap_call(settings, req);
+
+    free(issue_id_str);
+    soap_request_free(req);
+
+    if (result->mr_error == -1)
+    {
+        error_msg(_("Failed to add MantisBT issue note: '%s'"), result->mr_msg);
+        mantisbt_result_free(result);
+        return -1;
+    }
+    int id = response_get_return_value(result->mr_body);
+
+    mantisbt_result_free(result);
+    return id;
+}
+
+void
+mantisbt_get_project_id_from_name(mantisbt_settings_t *settings)
+{
+    if (settings->m_project == NULL)
+        error_msg_and_die(_("The MantisBT project has not been deretmined."));
+
+    soap_request_t *req = soap_request_new_for_method("mc_project_get_id_from_name");
+    soap_request_add_credentials_parameter(req, settings);
+    soap_node_add_child_node(req->sr_method, "project_name", SOAP_STRING, settings->m_project);
+
+    mantisbt_result_t *result = mantisbt_soap_call(settings, req);
+
+    if (result->mr_http_resp_code != 200)
+        error_msg_and_die(_("Failed to get project id from name"));
+
+    settings->m_project_id = response_get_return_value_as_string(result->mr_body);
+
+    return;
+}
diff --git a/src/plugins/mantisbt.conf b/src/plugins/mantisbt.conf
new file mode 100644
index 0000000..15a1065
--- /dev/null
+++ b/src/plugins/mantisbt.conf
@@ -0,0 +1,8 @@
+# MantisBT URL
+MantisbtURL = https://bugs.centos.org/
+# yes means that ssl certificates will be checked
+SSLVerify = yes
+# your login has to exist, if you don have any, please create one
+Login =
+# your password
+Password =
diff --git a/src/plugins/mantisbt.h b/src/plugins/mantisbt.h
new file mode 100644
index 0000000..c31c174
--- /dev/null
+++ b/src/plugins/mantisbt.h
@@ -0,0 +1,140 @@
+/*
+    Copyright (C) 2014  ABRT team
+    Copyright (C) 2014  RedHat Inc
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef MANTISBT_H
+#define MANTISBT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libxml/encoding.h>
+#include "problem_report.h"
+
+#define SOAP_STRING "ns2:string"
+#define SOAP_INTEGER "ns2:integer"
+#define SOAP_INTEGERARRAY "ns2:IntegerArray"
+#define SOAP_STRINGARRAY "ns2:StringArray"
+#define SOAP_ISSUEDATA "ns3:IssueData"
+#define SOAP_OBJECTREF "ns3:ObjectRef"
+#define SOAP_CUSTOMFIELD_ARRAY "ns2:CustomFieldValueForIssueDataArray"
+#define SOAP_FILTER_CUSTOMFIELD "ns2:FilterCustomField"
+#define SOAP_FILTER_CUSTOMFIELD_ARRAY "ns2:FilterCustomFieldArray"
+#define SOAP_FILTER_SEARCH_DATA "ns2:FilterSearchData"
+#define SOAP_CUSTOMFIELD "ns2:CustomFieldValueForIssueData"
+#define SOAP_BASE64 "SOAP-ENC:base64"
+#define SOAP_ISSUENOTE "ns3:IssueNoteData"
+
+#define PR_SEC_ADDITIONAL_INFO "Additional info"
+
+typedef struct soap_request
+{
+    xmlNodePtr sr_root;
+    xmlNodePtr sr_body;
+    xmlNodePtr sr_method;
+} soap_request_t;
+
+typedef struct mantisbt_settings
+{
+    char *m_login;
+    char *m_password;
+    const char *m_mantisbt_url;
+    const char *m_mantisbt_soap_url;
+    char *m_project;
+    char *m_project_id;
+    char *m_project_version;
+    const char *m_DontMatchComponents;
+    int         m_ssl_verify;
+    int         m_create_private;
+} mantisbt_settings_t;
+
+typedef struct mantisbt_result
+{
+    int mr_http_resp_code;
+    int mr_error;
+    char *mr_msg;
+    char *mr_url;
+    char *mr_body;
+} mantisbt_result_t;
+
+typedef struct mantisbt_issue_info
+{
+    int mii_id;
+    int mii_dup_id;
+    unsigned mii_best_bt_rating;
+
+    char *mii_status;
+    char *mii_resolution;
+    char *mii_reporter;
+    char *mii_project;
+
+    GList *mii_notes;
+    GList *mii_attachments;
+} mantisbt_issue_info_t;
+
+void mantisbt_settings_free(mantisbt_settings_t *settings);
+
+mantisbt_issue_info_t * mantisbt_issue_info_new();
+void mantisbt_issue_info_free(mantisbt_issue_info_t *info);
+mantisbt_issue_info_t * mantisbt_find_origin_bug_closed_duplicate(mantisbt_settings_t *settings, mantisbt_issue_info_t *info);
+
+void soap_request_free(soap_request_t *req);
+
+soap_request_t *soap_request_new_for_method(const char *method);
+
+void soap_request_add_method_parameter(soap_request_t *req, const char *name, const char *type, const char *value);
+void soap_request_add_credentials_parameter(soap_request_t *req, const mantisbt_settings_t *settings);
+
+char *soap_request_to_str(const soap_request_t *req);
+
+#if 0
+void soap_request_print(soap_request_t *req);
+#endif
+
+GList * response_get_main_ids_list(const char *xml);
+int response_get_main_id(const char *xml);
+void response_values_free(GList *values);
+
+void mantisbt_result_free(mantisbt_result_t *result);
+mantisbt_result_t *mantisbt_soap_call(const mantisbt_settings_t *settings, const soap_request_t *req);
+
+int mantisbt_attach_data(const mantisbt_settings_t *settings, const char *bug_id,
+                         const char *att_name, const char *data, int size);
+
+int mantisbt_attach_file(const mantisbt_settings_t *settings, const char *bug_id,
+                    const char *att_name, const char *data);
+
+GList * mantisbt_search_by_abrt_hash(mantisbt_settings_t *settings, const char *abrt_hash);
+GList * mantisbt_search_duplicate_issues(mantisbt_settings_t *settings, const char *category,
+                    const char *version, const char *abrt_hash);
+
+int mantisbt_create_new_issue(const mantisbt_settings_t *settings, problem_data_t *problem_data,
+                       const problem_report_t *pr, const char *tracker_url);
+
+mantisbt_issue_info_t * mantisbt_get_issue_info(const mantisbt_settings_t *settings, int issue_id);
+int mantisbt_add_issue_note(const mantisbt_settings_t *settings, int issue_id, const char *note);
+
+void mantisbt_get_project_id_from_name(mantisbt_settings_t *settings);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/src/plugins/mantisbt_format.conf b/src/plugins/mantisbt_format.conf
new file mode 100644
index 0000000..da08aa6
--- /dev/null
+++ b/src/plugins/mantisbt_format.conf
@@ -0,0 +1,59 @@
+# Lines starting with # are ignored.
+# Lines can be continued on the next line using trailing backslash.
+#
+# Format:
+# %summary:: summary format
+# section:: element1[,element2]...
+# The literal text line to be added to Bugzilla comment. Can be empty.
+# (IOW: empty lines are NOT ignored!)
+#
+# Summary format is a line of text, where %element% is replaced by
+# text element's content, and [[...%element%...]] block is used only if
+# %element% exists. [[...]] blocks can nest.
+#
+# Sections can be:
+# - %summary: bug summary format string.
+# - %attach: a list of elements to attach.
+# - text, double colon (::) and the list of comma-separated elements.
+#   Text can be empty (":: elem1, elem2, elem3" works),
+#   in this case "Text:" header line will be omitted.
+#
+# Elements can be:
+# - problem directory element names, which get formatted as
+#   <element_name>: <contents>
+#   or
+#   <element_name>:
+#   :<contents>
+#   :<contents>
+#   :<contents>
+# - problem directory element names prefixed by "%bare_",
+#   which is formatted as-is, without "<element_name>:" and colons
+# - %oneline, %multiline, %text wildcards, which select all corresponding
+#   elements for output or attachment
+# - %binary wildcard, valid only for %attach section, instructs to attach
+#   binary elements
+# - problem directory element names prefixed by "-",
+#   which excludes given element from all wildcards
+#
+#   Nonexistent elements are silently ignored.
+#   If none of elements exists, the section will not be created.
+
+%summary:: [abrt] %pkg_name%[[: %crash_function%()]][[: %reason%]][[: TAINTED %tainted_short%]]
+
+Description of problem:: %bare_comment
+
+Version-Release number of selected component:: %bare_package
+
+Truncated backtrace:: %bare_%short_backtrace
+
+%Additional info::
+:: -pkg_arch,-pkg_epoch,-pkg_name,-pkg_release,-pkg_version,\
+		-component,-architecture,\
+	-analyzer,-count,-duphash,-uuid,-abrt_version,\
+	-username,-hostname,-os_release,-os_info,\
+	-time,-pid,-pwd,-last_occurrence,-ureports_counter,\
+	%reporter,\
+	%oneline
+
+%attach:: -comment,-reason,-reported_to,-event_log,%multiline,\
+	-coredump,%binary
diff --git a/src/plugins/mantisbt_formatdup.conf b/src/plugins/mantisbt_formatdup.conf
new file mode 100644
index 0000000..b1552ac
--- /dev/null
+++ b/src/plugins/mantisbt_formatdup.conf
@@ -0,0 +1,65 @@
+# Lines starting with # are ignored.
+# Lines can be continued on the next line using trailing backslash.
+#
+# Format:
+# %summary:: summary format
+# section:: element1[,element2]...
+# The literal text line to be added to Bugzilla comment. Can be empty.
+# (IOW: empty lines are NOT ignored!)
+#
+# Summary format is a line of text, where %element% is replaced by
+# text element's content, and [[...%element%...]] block is used only if
+# %element% exists. [[...]] blocks can nest.
+#
+# Sections can be:
+# - %summary: bug summary format string.
+# - %attach: a list of elements to attach.
+# - text, double colon (::) and the list of comma-separated elements.
+#   Text can be empty (":: elem1, elem2, elem3" works),
+#   in this case "Text:" header line will be omitted.
+#
+# Elements can be:
+# - problem directory element names, which get formatted as
+#   <element_name>: <contents>
+#   or
+#   <element_name>:
+#   :<contents>
+#   :<contents>
+#   :<contents>
+# - problem directory element names prefixed by "%bare_",
+#   which is formatted as-is, without "<element_name>:" and colons
+# - %oneline, %multiline, %text wildcards, which select all corresponding
+#   elements for output or attachment
+# - %binary wildcard, valid only for %attach section, instructs to attach
+#   binary elements
+# - problem directory element names prefixed by "-",
+#   which excludes given element from all wildcards
+#
+#   Nonexistent elements are silently ignored.
+#   If none of elements exists, the section will not be created.
+
+# When we add a comment to an existing BZ, %summary is ignored
+# (it specifies *new bug* summary field):
+# %summary:: blah blah
+
+# When dup is detected, BZ reporter adds a comment to it.
+# This comment may interrupt an ongoing conversation in the BZ.
+# (Three people independently filed a bug against abrt about this).
+# Need to clearly explain what this comment is, to prevent confusion.
+# Hopefully, this line would suffice:
+Another user experienced a similar problem:
+
+# If user filled out comment field, show it:
+:: %bare_comment
+
+# var_log_messages has too much variance (time/date),
+# we exclude it from message so that dup message elimination has more chances to work
+:: \
+	-pkg_arch,-pkg_epoch,-pkg_name,-pkg_release,-pkg_version,\
+		-component,-architecture,\
+	-analyzer,-count,-duphash,-uuid,-abrt_version,\
+	-username,-hostname,-os_release,-os_info,\
+	-time,-pid,-pwd,-last_occurrence,-ureports_counter,\
+	-var_log_messages,\
+	%reporter,\
+	%oneline
diff --git a/src/plugins/report_CentOSBugTracker.conf b/src/plugins/report_CentOSBugTracker.conf
new file mode 100644
index 0000000..04cab13
--- /dev/null
+++ b/src/plugins/report_CentOSBugTracker.conf
@@ -0,0 +1,4 @@
+Mantisbt_MantisbtURL = https://bugs.centos.org
+Mantisbt_Login =
+Mantisbt_Password
+Mantisbt_SSLVerify = yes
diff --git a/src/plugins/report_CentOSBugTracker.xml.in b/src/plugins/report_CentOSBugTracker.xml.in
new file mode 100644
index 0000000..81f909b
--- /dev/null
+++ b/src/plugins/report_CentOSBugTracker.xml.in
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<event>
+    <_name>CentOS Bug Tracker</_name>
+    <_description>Report to CentOS Bug Tracker</_description>
+
+    <requires-items>component,duphash,os_release</requires-items>
+    <exclude-items-by-default>coredump,count,event_log,reported_to,vmcore</exclude-items-by-default>
+    <exclude-items-always></exclude-items-always>
+    <exclude-binary-items>no</exclude-binary-items>
+    <include-items-by-default></include-items-by-default>
+    <minimal-rating>3</minimal-rating>
+    <gui-review-elements>yes</gui-review-elements>
+
+    <options>
+        <option type="text" name="Mantisbt_Login">
+            <_label>User name</_label>
+            <allow-empty>no</allow-empty>
+            <_description>CentOS Bug Tracker account user name</_description>
+            <_note-html>You can create bugs.centos.org account &lt;a href="https://bugs.centos.org/signup_page.php"&gt;here&lt;/a&gt;</_note-html>
+        </option>
+        <option type="password" name="Mantisbt_Password">
+            <_label>Password</_label>
+            <allow-empty>no</allow-empty>
+            <_description>CentOS Bug Tracker account password</_description>
+        </option>
+        <advanced-options>
+            <option type="text" name="Mantisbt_MantisbtURL">
+                <_label>CentOS Bug Tracker URL</_label>
+                <allow-empty>no</allow-empty>
+                <_note-html>Address of CentOS Bug Tracker server</_note-html>
+                <default-value>https://bugs.centos.org</default-value>
+            </option>
+            <option type="bool" name="Mantisbt_SSLVerify">
+                <_label>Verify SSL</_label>
+                <_note-html>Check SSL key validity</_note-html>
+                <default-value>yes</default-value>
+            </option>
+            <option type="text" name="Mantisbt_Project">
+                <_label>CentOS Bug Tracker project</_label>
+                <allow-empty>yes</allow-empty>
+                <_note-html>Specify this only if you needed different project than specified in /etc/os-release</_note-html>
+            </option>
+            <option type="text" name="Mantisbt_ProjectVersion">
+                <_label>CentOS Bug Tracker project version</_label>
+                <allow-empty>yes</allow-empty>
+                <_note-html>Specify this only if you needed different project version than specified in /etc/os-release</_note-html>
+            </option>
+            <option type="text" name="http_proxy">
+                <_label>HTTP Proxy</_label>
+                <allow-empty>yes</allow-empty>
+                <_note-html>Sets the proxy server to use for HTTP</_note-html>
+            </option>
+            <option type="text" name="HTTPS_PROXY">
+                <_label>HTTPS Proxy</_label>
+                <allow-empty>yes</allow-empty>
+                <_note-html>Sets the proxy server to use for HTTPS</_note-html>
+            </option>
+            <option type="bool" name="Mantisbt_CreatePrivate">
+                <_label>Restrict access</_label>
+                <_note-html>Restrict access to the created CentOS Bug Tracker issue allowing only users from specified groups to view it (see advanced settings for more details)</_note-html>
+                <default-value>no</default-value>
+            </option>
+        </advanced-options>
+    </options>
+</event>
diff --git a/src/plugins/reporter-mantisbt.c b/src/plugins/reporter-mantisbt.c
new file mode 100644
index 0000000..d281cdb
--- /dev/null
+++ b/src/plugins/reporter-mantisbt.c
@@ -0,0 +1,696 @@
+/*
+    Copyright (C) 2014  ABRT team
+    Copyright (C) 2014  RedHat Inc
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc., 51
+    Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#include "internal_libreport.h"
+#include "client.h"
+#include "mantisbt.h"
+#include "problem_report.h"
+
+static void
+parse_osinfo_for_mantisbt(map_string_t *osinfo, char** project, char** version)
+{
+    const char *name = get_map_string_item_or_NULL(osinfo, "CENTOS_MANTISBT_PROJECT");
+    if (!name)
+        name = get_map_string_item_or_NULL(osinfo, OSINFO_NAME);
+
+    const char *version_id = get_map_string_item_or_NULL(osinfo, "CENTOS_MANTISBT_PROJECT_VERSION");
+    if (!version_id)
+        version_id = get_map_string_item_or_NULL(osinfo, OSINFO_VERSION_ID);
+
+    if (name && version_id)
+    {
+        *project = xstrdup(name);
+        *version = xstrdup(version_id);
+        return;
+    }
+
+    /* something bad happend */
+    *project = NULL;
+    *version = NULL;
+}
+
+static char *
+ask_mantisbt_login(const char *message)
+{
+    char *login = ask(message);
+    if (login == NULL || login[0] == '\0')
+    {
+        set_xfunc_error_retval(EXIT_CANCEL_BY_USER);
+        error_msg_and_die(_("Can't continue without login"));
+    }
+
+    return login;
+}
+
+static char *
+ask_mantisbt_password(const char *message)
+{
+    char *password = ask_password(message);
+    /* TODO: this should be fixed in ask_password() as other tools have the same problem */
+    putchar('\n');
+    if (password == NULL || password[0] == '\0')
+    {
+        set_xfunc_error_retval(EXIT_CANCEL_BY_USER);
+        error_msg_and_die(_("Can't continue without password"));
+    }
+
+    return password;
+}
+
+static void
+ask_mantisbt_credentials(mantisbt_settings_t *settings, const char *pre_message)
+{
+    free(settings->m_login);
+    free(settings->m_password);
+
+    char *question = xasprintf("%s %s", pre_message, _("Please enter your CentOS Bug Tracker login:"));
+    settings->m_login = ask_mantisbt_login(question);
+    free(question);
+
+    question = xasprintf("%s %s '%s':", pre_message, _("Please enter the password for"), settings->m_login);
+    settings->m_password = ask_mantisbt_password(question);
+    free(question);
+
+    return;
+}
+
+static void
+verify_credentials(mantisbt_settings_t *settings)
+{
+    if (settings->m_login[0] == '\0' || settings->m_password[0] == '\0')
+        ask_mantisbt_credentials(settings, _("Credentials are not provided by configuration."));
+
+    while (true)
+    {
+        soap_request_t *req = soap_request_new_for_method("mc_login");
+        soap_request_add_credentials_parameter(req, settings);
+
+        mantisbt_result_t *result = mantisbt_soap_call(settings, req);
+        soap_request_free(req);
+
+        if (g_verbose > 2)
+        {
+            GList *ids = response_get_main_ids_list(result->mr_body);
+            if (ids != NULL)
+                log("%s", (char *)ids->data);
+            response_values_free(ids);
+        }
+
+        int result_val = result->mr_http_resp_code;
+        mantisbt_result_free(result);
+
+        if (result_val == 200)
+            return;
+
+        ask_mantisbt_credentials(settings, _("Invalid password or login."));
+    }
+}
+
+static void
+set_settings(mantisbt_settings_t *m, map_string_t *settings, struct dump_dir *dd)
+{
+    const char *environ;
+
+    environ = getenv("Mantisbt_Login");
+    m->m_login = xstrdup(environ ? environ : get_map_string_item_or_empty(settings, "Login"));
+
+    environ = getenv("Mantisbt_Password");
+    m->m_password = xstrdup(environ ? environ : get_map_string_item_or_empty(settings, "Password"));
+
+    environ = getenv("Mantisbt_MantisbtURL");
+    m->m_mantisbt_url = environ ? environ : get_map_string_item_or_empty(settings, "MantisbtURL");
+    if (!m->m_mantisbt_url[0])
+        m->m_mantisbt_url = "https://bugs.centos.org/";
+    else
+    {
+        /* We don't want trailing '/': "https://host/dir/" -> "https://host/dir" */
+        char *last_slash = strrchr(m->m_mantisbt_url, '/');
+        if (last_slash && last_slash[1] == '\0')
+            *last_slash = '\0';
+    }
+    m->m_mantisbt_soap_url = concat_path_file(m->m_mantisbt_url, "api/soap/mantisconnect.php");
+
+    environ = getenv("Mantisbt_Project");
+    if (environ)
+    {
+        m->m_project = xstrdup(environ);
+        environ = getenv("Mantisbt_ProjectVersion");
+        if (environ)
+            m->m_project_version = xstrdup(environ);
+    }
+    else
+    {
+        const char *option = get_map_string_item_or_NULL(settings, "Project");
+        if (option)
+            m->m_project = xstrdup(option);
+        option = get_map_string_item_or_NULL(settings, "ProjectVersion");
+        if (option)
+            m->m_project_version = xstrdup(option);
+    }
+
+    if (!m->m_project || !*m->m_project) /* if not overridden or empty... */
+    {
+        free(m->m_project);
+        free(m->m_project_version);
+
+        if (dd != NULL)
+        {
+            map_string_t *osinfo = new_map_string();
+
+            char *os_info_data = dd_load_text(dd, FILENAME_OS_INFO);
+            parse_osinfo(os_info_data, osinfo);
+            free(os_info_data);
+
+            parse_osinfo_for_mantisbt(osinfo, &m->m_project, &m->m_project_version);
+            free_map_string(osinfo);
+        }
+    }
+
+    environ = getenv("Mantisbt_SSLVerify");
+    m->m_ssl_verify = string_to_bool(environ ? environ : get_map_string_item_or_empty(settings, "SSLVerify"));
+
+    environ = getenv("Mantisbt_DontMatchComponents");
+    m->m_DontMatchComponents = environ ? environ : get_map_string_item_or_empty(settings, "DontMatchComponents");
+
+    environ = getenv(CREATE_PRIVATE_TICKET);
+    if (environ)
+        m->m_create_private = string_to_bool(environ);
+
+    if (!m->m_create_private)
+    {
+        environ = getenv("Mantisbt_CreatePrivate");
+        m->m_create_private = string_to_bool(environ ? environ : get_map_string_item_or_empty(settings, "CreatePrivate"));
+    }
+    log_notice("create private CentOS Bug Tracker ticket: '%s'", m->m_create_private ? "YES": "NO");
+}
+
+int main(int argc, char **argv)
+{
+    abrt_init(argv);
+
+    /* I18n */
+    setlocale(LC_ALL, "");
+#if ENABLE_NLS
+    bindtextdomain(PACKAGE, LOCALEDIR);
+    textdomain(PACKAGE);
+#endif
+
+    const char *program_usage_string = _(
+        "\n& [-vf] [-c CONFFILE]... [-F FMTFILE] [-A FMTFILE2] -d DIR"
+        "\nor:"
+        "\n& [-v] [-c CONFFILE]... [-d DIR] -t[ID] FILE..."
+        "\nor:"
+        "\n& [-v] [-c CONFFILE]... [-d DIR] -t[ID] -w"
+        "\nor:"
+        "\n& [-v] [-c CONFFILE]... -h DUPHASH"
+        "\n"
+        "\nReports problem to CentOS Bug Tracker."
+        "\n"
+        "\nThe tool reads DIR. Then it tries to find an issue"
+        "\nwith the same abrt_hash in custom field 'abrt_hash'."
+        "\n"
+        "\nIf such issue is not found, then a new issue is created. Elements of DIR"
+        "\nare stored in the issue as part of issue description or as attachments,"
+        "\ndepending on their type and size."
+        "\n"
+        "\nOtherwise, if such issue is found and it is marked as CLOSED DUPLICATE,"
+        "\nthe tool follows the chain of duplicates until it finds a non-DUPLICATE issue."
+        "\nThe tool adds a new comment to found issue."
+        "\n"
+        "\nThe URL to new or modified issue is printed to stdout and recorded in"
+        "\n'reported_to' element."
+        "\n"
+        "\nOption -t uploads FILEs to the already created issue on CentOS Bug Tracker site."
+        "\nThe issue ID is retrieved from directory specified by -d DIR."
+        "\nIf problem data in DIR was never reported to CentOS Bug Tracker, upload will fail."
+        "\n"
+        "\nOption -tID uploads FILEs to the issue with specified ID on CentOS Bug Tracker site."
+        "\n-d DIR is ignored."
+        "\n"
+        "\nOption -r sets the last url from reporter_to element which is prefixed with"
+        "\nTRACKER_NAME to URL field. This option is applied only when a new issue is to be"
+        "\nfiled. The default value is 'ABRT Server'"
+        "\n"
+        "\nIf not specified, CONFFILE defaults to "CONF_DIR"/plugins/mantisb.conf"
+        "\nIts lines should have 'PARAM = VALUE' format."
+        "\nRecognized string parameters: MantisbtURL, Login, Password, Project, ProjectVersion."
+        "\nRecognized boolean parameter (VALUE should be 1/0, yes/no): SSLVerify, CreatePrivate."
+        "\nParameters can be overridden via $Mantisbt_PARAM environment variables."
+        "\n"
+        "\nFMTFILE and FMTFILE2 default to "CONF_DIR"/plugins/mantisbt_format.conf"
+    );
+
+    enum {
+        OPT_v = 1 << 0,
+        OPT_d = 1 << 1,
+        OPT_c = 1 << 2,
+        OPT_F = 1 << 3,
+        OPT_A = 1 << 4,
+        OPT_t = 1 << 5,
+        OPT_f = 1 << 6,
+        OPT_h = 1 << 7,
+        OPT_r = 1 << 8,
+        OPT_D = 1 << 9,
+    };
+
+    const char *dump_dir_name = ".";
+    GList *conf_file = NULL;
+    const char *fmt_file = CONF_DIR"/plugins/mantisbt_format.conf";
+    const char *fmt_file2 = fmt_file;
+    char *abrt_hash = NULL;
+    char *ticket_no = NULL;
+    const char *tracker_str = "ABRT Server";
+    char *debug_str = NULL;
+    mantisbt_settings_t mbt_settings = { 0 };
+    /* Keep enum above and order of options below in sync! */
+    struct options program_options[] = {
+        OPT__VERBOSE(&g_verbose),
+        OPT_STRING(   'd', NULL, &dump_dir_name , "DIR"    , _("Problem directory")),
+        OPT_LIST(     'c', NULL, &conf_file     , "FILE"   , _("Configuration file (may be given many times)")),
+        OPT_STRING(   'F', NULL, &fmt_file      , "FILE"   , _("Formatting file for initial comment")),
+        OPT_STRING(   'A', NULL, &fmt_file2     , "FILE"   , _("Formatting file for duplicates")),
+        OPT_OPTSTRING('t', "ticket", &ticket_no , "ID"     , _("Attach FILEs [to issue with this ID]")),
+        OPT_BOOL(     'f', NULL, NULL,                       _("Force reporting even if this problem is already reported")),
+        OPT_STRING(   'h', "duphash", &abrt_hash, "DUPHASH", _("Print BUG_ID which has given DUPHASH")),
+        OPT_STRING(   'r', "tracker", &tracker_str, "TRACKER_NAME", _("A name of bug tracker for an additional URL from 'reported_to'")),
+
+        OPT_OPTSTRING('D', "debug", &debug_str  , "STR"    , _("Debug")),
+        OPT_END()
+    };
+
+    unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
+    argv += optind;
+
+    export_abrt_envvars(0);
+
+    map_string_t *settings = new_map_string();
+
+    {
+        if (!conf_file)
+            conf_file = g_list_append(conf_file, (char*) CONF_DIR"/plugins/mantisbt.conf");
+        while (conf_file)
+        {
+            char *fn = (char *)conf_file->data;
+            log_notice("Loading settings from '%s'", fn);
+            load_conf_file(fn, settings, /*skip key w/o values:*/ false);
+            log_debug("Loaded '%s'", fn);
+            conf_file = g_list_delete_link(conf_file, conf_file);
+        }
+
+        struct dump_dir *dd = NULL;
+        if (abrt_hash == NULL)
+        {
+            dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+            if (!dd)
+                error_msg_and_die(_("Can't open problem dir '%s'."), dump_dir_name);
+        }
+
+        set_settings(&mbt_settings, settings, dd);
+        dd_close(dd);
+        /* WRONG! set_settings() does not copy the strings, it merely sets up pointers
+         * to settings[] dictionary:
+         */
+        /*free_map_string(settings);*/
+    }
+
+    /* No connection is opened between client and server. Users authentication
+     * is performed on every SOAP method call. In the first step we verify the
+     * credentials by calling 'mc_login' method.  In the case the credentials are
+     * correctly applies the reporter uses them in the next requests. It is not
+     * necessary to call 'mc_login' method because the method provides only
+     * verification of credentials.
+     */
+    verify_credentials(&mbt_settings);
+
+    if (abrt_hash)
+    {
+        log(_("Looking for similar problems in CentOS Bug Tracker"));
+        GList *ids = mantisbt_search_by_abrt_hash(&mbt_settings, abrt_hash);
+        mantisbt_settings_free(&mbt_settings);
+
+        if (ids == NULL)
+            return EXIT_FAILURE;
+
+        puts(ids->data);
+        response_values_free(ids);
+        return EXIT_SUCCESS;
+    }
+
+    mantisbt_get_project_id_from_name(&mbt_settings);
+
+    if (opts & OPT_t)
+    {
+        if (!argv[0])
+            show_usage_and_die(program_usage_string, program_options);
+
+        if (!ticket_no)
+        {
+            struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+            if (!dd)
+                xfunc_die();
+            report_result_t *reported_to = find_in_reported_to(dd, "CentOS Bug Tracker");
+            dd_close(dd);
+
+            if (!reported_to || !reported_to->url)
+                error_msg_and_die(_("Can't get MantisBT ID because this problem has not yet been reported to MantisBT."));
+
+            char *url = reported_to->url;
+            reported_to->url = NULL;
+            free_report_result(reported_to);
+
+            if (prefixcmp(url, mbt_settings.m_mantisbt_url) != 0)
+                error_msg_and_die(_("This problem has been reported to MantisBT '%s' which differs from the configured MantisBT '%s'."), url, mbt_settings.m_mantisbt_url);
+
+            ticket_no = strrchr(url, '=');
+            if (!ticket_no)
+                error_msg_and_die(_("Malformed url to MantisBT '%s'."), url);
+
+            /* won't ever call free on it - it simplifies the code a lot */
+            ticket_no = xstrdup(ticket_no + 1);
+            log(_("Using CentOS Bug Tracker ID '%s'"), ticket_no);
+        }
+
+        /* Attach files to existing MantisBT issues */
+        while (*argv)
+        {
+            const char *path = *argv++;
+            char *filename = basename(path);
+            log(_("Attaching file '%s' to issue %s"), filename, ticket_no);
+            mantisbt_attach_file(&mbt_settings, ticket_no, filename, path);
+        }
+
+        return 0;
+    }
+
+    /* Create new issue in MantisBT */
+
+    if (!(opts & OPT_f))
+    {
+        struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+        if (!dd)
+            xfunc_die();
+        report_result_t *reported_to = find_in_reported_to(dd, "CentOS Bug Tracker");
+        dd_close(dd);
+
+        if (reported_to && reported_to->url)
+        {
+            char *msg = xasprintf(_("This problem was already reported to CentOS Bug Tracker (see '%s')."
+                            " Do you still want to create a new issue?"),
+                            reported_to->url);
+            int yes = ask_yes_no(msg);
+            free(msg);
+            if (!yes)
+                return 0;
+        }
+        free_report_result(reported_to);
+    }
+
+    problem_data_t *problem_data = create_problem_data_for_reporting(dump_dir_name);
+    if (!problem_data)
+        xfunc_die(); /* create_problem_data_for_reporting already emitted error msg */
+
+    const char *category = problem_data_get_content_or_die(problem_data, FILENAME_COMPONENT);
+    const char *duphash   = problem_data_get_content_or_die(problem_data, FILENAME_DUPHASH);
+
+    if (opts & OPT_D)
+    {
+        problem_formatter_t *pf = problem_formatter_new();
+        problem_formatter_add_section(pf, PR_SEC_ADDITIONAL_INFO, /* optional section */ 0);
+
+        if (problem_formatter_load_file(pf, fmt_file))
+            error_msg_and_die("Invalid format file: %s", fmt_file);
+
+        problem_report_t *pr = NULL;
+        if (problem_formatter_generate_report(pf, problem_data, &pr))
+            error_msg_and_die("Failed to format issue report from problem data");
+
+        printf("summary: %s\n"
+                "\n"
+                "Description:\n%s\n"
+                "Additional info:\n%s\n"
+                , problem_report_get_summary(pr)
+                , problem_report_get_description(pr)
+                , problem_report_get_section(pr, PR_SEC_ADDITIONAL_INFO)
+        );
+
+        puts("attachments:");
+        for (GList *a = problem_report_get_attachments(pr); a != NULL; a = g_list_next(a))
+            printf(" %s\n", (const char *)a->data);
+
+        problem_report_free(pr);
+        problem_formatter_free(pf);
+        exit(0);
+    }
+
+     int bug_id = 0;
+
+    /* If REMOTE_RESULT contains "DUPLICATE 12345", we consider it a dup of 12345
+     * and won't search on MantisBT server.
+     */
+    char *remote_result;
+    remote_result = problem_data_get_content_or_NULL(problem_data, FILENAME_REMOTE_RESULT);
+    if (remote_result)
+    {
+        char *cmd = strtok(remote_result, " \n");
+        char *id = strtok(NULL, " \n");
+
+        if (!prefixcmp(cmd, "DUPLICATE"))
+        {
+            errno = 0;
+            char *e;
+            bug_id = strtoul(id, &e, 10);
+            if (errno || id == e || *e != '\0' || bug_id > INT_MAX)
+            {
+                /* error / no digits / illegal trailing chars / too big a number */
+                bug_id = 0;
+            }
+        }
+    }
+
+    mantisbt_issue_info_t *ii;
+    if (!bug_id)
+    {
+        log(_("Checking for duplicates"));
+
+        int existing_id = -1;
+        int crossver_id = -1;
+        {
+            /* Figure out whether we want to match category
+             * when doing dup search.
+             */
+            const char *category_substitute = is_in_comma_separated_list(category, mbt_settings.m_DontMatchComponents) ? NULL : category;
+
+            /* We don't do dup detection across versions (see below why),
+             * but we do add a note if cross-version potential dup exists.
+             * For that, we search for cross version dups first:
+             */
+            // SOAP API searching method is not in the final version, it's possible the project will be string
+            GList *crossver_bugs_ids = mantisbt_search_duplicate_issues(&mbt_settings, category_substitute, /*version*/ NULL, duphash);
+
+            unsigned crossver_bugs_count = g_list_length(crossver_bugs_ids);
+            log_debug("CentOS Bug Tracker has %i reports with duphash '%s' including cross-version ones",
+                    crossver_bugs_count, duphash);
+            if (crossver_bugs_count > 0)
+                crossver_id = atoi(g_list_first(crossver_bugs_ids)->data);
+
+            if (crossver_bugs_count > 0)
+            {
+                // SOAP API searching method is not in the final version, it's possible the project will be string
+                GList *dup_bugs_ids = mantisbt_search_duplicate_issues(&mbt_settings, category_substitute, mbt_settings.m_project_version, duphash);
+
+                unsigned dup_bugs_count =  g_list_length(dup_bugs_ids);
+                log_debug("CentOS Bug Tracker has %i reports with duphash '%s'",
+                        dup_bugs_count, duphash);
+                if (dup_bugs_count > 0)
+                    existing_id = atoi(g_list_first(dup_bugs_ids)->data);
+            }
+        }
+
+        if (existing_id < 0)
+        {
+            /* Create new issue */
+            log(_("Creating a new issue"));
+            problem_formatter_t *pf = problem_formatter_new();
+            problem_formatter_add_section(pf, PR_SEC_ADDITIONAL_INFO, 0);
+
+            if (problem_formatter_load_file(pf, fmt_file))
+                error_msg_and_die(_("Invalid format file: %s"), fmt_file);
+
+            problem_report_t *pr = NULL;
+            if (problem_formatter_generate_report(pf, problem_data, &pr))
+                error_msg_and_die(_("Failed to format problem data"));
+
+            if (crossver_id >= 0)
+                problem_report_buffer_printf(
+                        problem_report_get_buffer(pr, PR_SEC_DESCRIPTION),
+                        "\nPotential duplicate: issue %u\n", crossver_id);
+
+            problem_formatter_free(pf);
+
+            /* get tracker URL if exists */
+            struct dump_dir *dd = dd_opendir(dump_dir_name, 0);
+            char *tracker_url = NULL;
+            if (dd)
+            {
+                report_result_t *reported_to = find_in_reported_to(dd, tracker_str);
+                dd_close(dd);
+
+                if (reported_to && reported_to->url)
+                {
+                    log(_("Adding External URL to issue"));
+                    tracker_url = xstrdup(reported_to->url);
+                    free_report_result(reported_to);
+                }
+            }
+
+            int new_id = mantisbt_create_new_issue(&mbt_settings, problem_data, pr, tracker_url);
+
+            free(tracker_url);
+
+            if (new_id == -1)
+                return EXIT_FAILURE;
+
+            log(_("Adding attachments to issue %i"), new_id);
+            char *new_id_str = xasprintf("%u", new_id);
+
+            for (GList *a = problem_report_get_attachments(pr); a != NULL; a = g_list_next(a))
+            {
+                const char *item_name = (const char *)a->data;
+                struct problem_item *item = problem_data_get_item_or_NULL(problem_data, item_name);
+                if (!item)
+                    continue;
+                else if (item->flags & CD_FLAG_TXT)
+                    mantisbt_attach_data(&mbt_settings, new_id_str, item_name, item->content, strlen(item->content));
+                else if (item->flags & CD_FLAG_BIN)
+                    mantisbt_attach_file(&mbt_settings, new_id_str, item_name, item->content);
+            }
+
+            free(new_id_str);
+            problem_report_free(pr);
+            ii = mantisbt_issue_info_new();
+            ii->mii_id = new_id;
+            ii->mii_status = xstrdup("new");
+
+            goto finish;
+        }
+
+        bug_id = existing_id;
+    }
+
+    ii = mantisbt_get_issue_info(&mbt_settings, bug_id);
+
+    log(_("Bug is already reported: %i"), ii->mii_id);
+
+    /* Follow duplicates */
+    if ((strcmp(ii->mii_status, "closed") == 0)
+     && (strcmp(ii->mii_resolution, "duplicate") == 0)
+    ) {
+        mantisbt_issue_info_t *origin = mantisbt_find_origin_bug_closed_duplicate(&mbt_settings, ii);
+        if (origin)
+        {
+            mantisbt_issue_info_free(ii);
+            ii = origin;
+        }
+    }
+
+    /* TODO CC list
+     * Is no MantisBT SOAP API method which allows adding users to CC list
+     * without updating issue.
+     */
+
+    /* Add comment and bt */
+    const char *comment = problem_data_get_content_or_NULL(problem_data, FILENAME_COMMENT);
+    if (comment && comment[0])
+    {
+        problem_formatter_t *pf = problem_formatter_new();
+
+        if (problem_formatter_load_file(pf, fmt_file2))
+            error_msg_and_die(_("Invalid duplicate format file: '%s"), fmt_file2);
+
+        problem_report_t *pr;
+        if (problem_formatter_generate_report(pf, problem_data, &pr))
+            error_msg_and_die(_("Failed to format duplicate comment from problem data"));
+
+        const char *mbtcomment = problem_report_get_description(pr);
+
+        int dup_comment = is_comment_dup(ii->mii_notes, mbtcomment);
+        if (!dup_comment)
+        {
+            log(_("Adding new comment to issue %d"), ii->mii_id);
+            mantisbt_add_issue_note(&mbt_settings, ii->mii_id, mbtcomment);
+
+            const char *bt = problem_data_get_content_or_NULL(problem_data, FILENAME_BACKTRACE);
+            unsigned rating = 0;
+            const char *rating_str = problem_data_get_content_or_NULL(problem_data, FILENAME_RATING);
+            /* python doesn't have rating file */
+            if (rating_str)
+                rating = xatou(rating_str);
+            if (bt && rating > ii->mii_best_bt_rating)
+            {
+                char *bug_id_str = xasprintf("%i", ii->mii_id);
+
+                log(_("Attaching better backtrace"));
+
+                // find unique filename of attachment
+                char *name = NULL;
+                for (int i = 0;; ++i)
+                {
+                    if (i == 0)
+                        name = xasprintf("%s", FILENAME_BACKTRACE);
+                    else
+                        name = xasprintf("%s%d", FILENAME_BACKTRACE, i);
+
+                    if (g_list_find_custom(ii->mii_attachments, name, (GCompareFunc) strcmp) == NULL)
+                        break;
+
+                    free(name);
+                }
+                mantisbt_attach_data(&mbt_settings, bug_id_str, name, bt, strlen(bt));
+
+                free(name);
+                free(bug_id_str);
+            }
+        }
+        else
+            log(_("Found the same comment in the issue history, not adding a new one"));
+
+        problem_report_free(pr);
+        problem_formatter_free(pf);
+    }
+
+finish:
+    log(_("Status: %s%s%s %s/view.php?id=%u"),
+                ii->mii_status,
+                ii->mii_resolution ? " " : "",
+                ii->mii_resolution ? ii->mii_resolution : "",
+                mbt_settings.m_mantisbt_url,
+                ii->mii_id);
+
+    struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+    if (dd)
+    {
+        char *msg = xasprintf("CentOS Bug Tracker: URL=%s/view.php?id=%u", mbt_settings.m_mantisbt_url, ii->mii_id);
+        add_reported_to(dd, msg);
+        free(msg);
+        dd_close(dd);
+    }
+
+    mantisbt_settings_free(&mbt_settings);
+    return 0;
+}
diff --git a/src/workflows/Makefile.am b/src/workflows/Makefile.am
index 0fc1019..5b8376a 100644
--- a/src/workflows/Makefile.am
+++ b/src/workflows/Makefile.am
@@ -22,6 +22,18 @@ dist_workflows_DATA = \
     workflow_Logger.xml \
     workflow_LoggerCCpp.xml
 
+if BUILD_MANTISBT
+dist_workflows_DATA += \
+    workflow_CentOSCCpp.xml \
+    workflow_CentOSKerneloops.xml \
+    workflow_CentOSPython.xml \
+    workflow_CentOSPython3.xml \
+    workflow_CentOSVmcore.xml \
+    workflow_CentOSXorg.xml \
+    workflow_CentOSLibreport.xml \
+    workflow_CentOSJava.xml
+endif
+
 if BUILD_BUGZILLA
 dist_workflows_DATA += \
     workflow_AnacondaFedora.xml \
@@ -44,7 +56,8 @@ dist_workflowsdef_DATA =\
     report_rhel.conf \
     report_mailx.conf \
     report_logger.conf \
-    report_uploader.conf
+    report_uploader.conf \
+    report_centos.conf
 
 if BUILD_BUGZILLA
 dist_workflowsdef_DATA += \
diff --git a/src/workflows/report_centos.conf b/src/workflows/report_centos.conf
new file mode 100644
index 0000000..07b0d40
--- /dev/null
+++ b/src/workflows/report_centos.conf
@@ -0,0 +1,31 @@
+EVENT=workflow_CentOSLibreport analyzer=libreport
+# this is just a meta event which consists of other events
+# the list is defined in the xml file
+
+EVENT=workflow_CentOSCCpp analyzer=CCpp
+# this is just a meta event which consists of other events
+# the list is defined in the xml file
+
+EVENT=workflow_CentOSPython analyzer=Python component!=anaconda
+# this is just a meta event which consists of other events
+# the list is defined in the xml file
+
+EVENT=workflow_CentOSPython3 analyzer=Python3 component!=anaconda
+# this is just a meta event which consists of other events
+# the list is defined in the xml file
+
+EVENT=workflow_CentOSKerneloops analyzer=Kerneloops
+# this is just a meta event which consists of other events
+# the list is defined in the xml file
+
+EVENT=workflow_CentOSVmcore analyzer=vmcore
+# this is just a meta event which consists of other events
+# the list is defined in the xml file
+
+EVENT=workflow_CentOSXorg analyzer=xorg
+# this is just a meta event which consists of other events
+# the list is defined in the xml file
+
+EVENT=workflow_CentOSJava analyzer=Java
+# this is just a meta event which consists of other events
+# the list is defined in the xml file
diff --git a/src/workflows/workflow_CentOSCCpp.xml.in b/src/workflows/workflow_CentOSCCpp.xml.in
new file mode 100644
index 0000000..ea94d56
--- /dev/null
+++ b/src/workflows/workflow_CentOSCCpp.xml.in
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<workflow>
+    <_name>Report to CentOS Bug Tracker</_name>
+    <_description>Process the C/C++ crash using the CentOS infrastructure</_description>
+
+    <events>
+        <event>report_uReport</event>
+        <event>collect_*</event>
+        <event>analyze_CCpp</event>
+        <event>report_CentOSBugTracker</event>
+    </events>
+</workflow>
diff --git a/src/workflows/workflow_CentOSJava.xml.in b/src/workflows/workflow_CentOSJava.xml.in
new file mode 100644
index 0000000..89f9295
--- /dev/null
+++ b/src/workflows/workflow_CentOSJava.xml.in
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<workflow>
+    <_name>Report to CentOS Bug Tracker</_name>
+    <_description>Process the Java exception using the CentOS infrastructure</_description>
+
+    <events>
+        <event>report_uReport</event>
+        <event>collect_*</event>
+        <event>report_CentOSBugTracker</event>
+    </events>
+</workflow>
diff --git a/src/workflows/workflow_CentOSKerneloops.xml.in b/src/workflows/workflow_CentOSKerneloops.xml.in
new file mode 100644
index 0000000..c43c681
--- /dev/null
+++ b/src/workflows/workflow_CentOSKerneloops.xml.in
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<workflow>
+    <_name>Report to CentOS Bug Tracker</_name>
+    <_description>Process the kerneloops using the CentOS infrastructure</_description>
+
+    <events>
+        <event>report_uReport</event>
+        <event>collect_*</event>
+        <event>report_CentOSBugTracker</event>
+    </events>
+</workflow>
diff --git a/src/workflows/workflow_CentOSLibreport.xml.in b/src/workflows/workflow_CentOSLibreport.xml.in
new file mode 100644
index 0000000..2f6ed82
--- /dev/null
+++ b/src/workflows/workflow_CentOSLibreport.xml.in
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<workflow>
+    <_name>Report to CentOS Bug Tracker</_name>
+    <_description>Process the problem using the CentOS infrastructure</_description>
+
+    <events>
+        <event>report_CentOSBugTracker</event>
+    </events>
+</workflow>
diff --git a/src/workflows/workflow_CentOSPython.xml.in b/src/workflows/workflow_CentOSPython.xml.in
new file mode 100644
index 0000000..7e26c6c
--- /dev/null
+++ b/src/workflows/workflow_CentOSPython.xml.in
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<workflow>
+    <_name>Report to CentOS Bug Tracker</_name>
+    <_description>Process the python exception using the CentOS infrastructure</_description>
+
+    <events>
+        <event>report_uReport</event>
+        <event>collect_*</event>
+        <event>report_CentOSBugTracker</event>
+    </events>
+</workflow>
diff --git a/src/workflows/workflow_CentOSPython3.xml.in b/src/workflows/workflow_CentOSPython3.xml.in
new file mode 100644
index 0000000..f1dd8a9
--- /dev/null
+++ b/src/workflows/workflow_CentOSPython3.xml.in
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<workflow>
+    <_name>Report to CentOS Bug Tracker</_name>
+    <_description>Process the python 3 exception using the CentOS infrastructure</_description>
+
+    <events>
+        <event>report_uReport</event>
+        <event>collect_*</event>
+        <event>report_CentOSBugTracker</event>
+    </events>
+</workflow>
diff --git a/src/workflows/workflow_CentOSVmcore.xml.in b/src/workflows/workflow_CentOSVmcore.xml.in
new file mode 100644
index 0000000..c876594
--- /dev/null
+++ b/src/workflows/workflow_CentOSVmcore.xml.in
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<workflow>
+    <_name>Report to CentOS Bug Tracker</_name>
+    <_description>Process the kernel crash using the CentOS infrastructure</_description>
+
+    <events>
+        <event>analyze_VMcore</event>
+        <event>report_uReport</event>
+        <event>collect_*</event>
+        <event>report_CentOSBugTracker</event>
+    </events>
+</workflow>
diff --git a/src/workflows/workflow_CentOSXorg.xml.in b/src/workflows/workflow_CentOSXorg.xml.in
new file mode 100644
index 0000000..bf52221
--- /dev/null
+++ b/src/workflows/workflow_CentOSXorg.xml.in
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<workflow>
+    <_name>Report to CentOS Bug Tracker</_name>
+    <_description>Process the X Server problem using the CentOS infrastructure</_description>
+
+    <events>
+        <event>report_CentOSBugTracker</event>
+    </events>
+</workflow>
-- 
1.8.3.1