summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2009-11-09 18:39:20 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2009-11-09 18:39:20 +0100
commit2094c666c6175e6e8cfb5a5a7a49da6004d042d8 (patch)
tree4a5ef1b1d9f3b653b4a522dddc65e0401d3e32c2 /lib
parent48d30ac32352545800bbc70130796a85ab7a62c3 (diff)
downloadabrt-2094c666c6175e6e8cfb5a5a7a49da6004d042d8.tar.gz
abrt-2094c666c6175e6e8cfb5a5a7a49da6004d042d8.tar.xz
abrt-2094c666c6175e6e8cfb5a5a7a49da6004d042d8.zip
applied gavin's patch to Catcut. Refactored common xmlrpc code into lib/Utils.
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/Plugins/Bugzilla.cpp110
-rw-r--r--lib/Plugins/Catcut.cpp609
-rw-r--r--lib/Plugins/Catcut.h3
-rw-r--r--lib/Utils/Makefile.am4
-rw-r--r--lib/Utils/abrt_xmlrpc.cpp76
-rw-r--r--lib/Utils/abrt_xmlrpc.h27
6 files changed, 554 insertions, 275 deletions
diff --git a/lib/Plugins/Bugzilla.cpp b/lib/Plugins/Bugzilla.cpp
index ecd4dd67..b3cef929 100644
--- a/lib/Plugins/Bugzilla.cpp
+++ b/lib/Plugins/Bugzilla.cpp
@@ -1,6 +1,7 @@
#include <xmlrpc-c/base.h>
#include <xmlrpc-c/client.h>
#include "abrtlib.h"
+#include "abrt_xmlrpc.h"
#include "Bugzilla.h"
#include "CrashTypes.h"
#include "DebugDump.h"
@@ -50,20 +51,6 @@ static void create_new_bug_description(const map_crash_report_t& pCrashReport, s
pDescription += make_description_bz(pCrashReport);
}
-// FIXME: we still leak memory if this function detects a fault:
-// many instances when we leave non-freed or non-xmlrpc_DECREF'ed data behind.
-static void throw_if_xml_fault_occurred(xmlrpc_env *env)
-{
- if (env->fault_occurred)
- {
- std::string errmsg = ssprintf("XML-RPC Fault: %s(%d)", env->fault_string, env->fault_code);
- xmlrpc_env_clean(env); // this is needed ONLY if fault_occurred
- xmlrpc_env_init(env); // just in case user catches ex and _continues_ to use env
- error_msg("%s", errmsg.c_str()); // show error in daemon log
- throw CABRTException(EXCEP_PLUGIN, errmsg);
- }
-}
-
/*
* Static namespace for xmlrpc stuff.
@@ -72,81 +59,18 @@ static void throw_if_xml_fault_occurred(xmlrpc_env *env)
namespace {
-struct ctx {
- xmlrpc_client* client;
- xmlrpc_server_info* server_info;
-
- ctx(const char* url, bool no_ssl_verify) { new_xmlrpc_client(url, no_ssl_verify); }
- ~ctx() { destroy_xmlrpc_client(); }
+struct ctx: public abrt_xmlrpc_conn {
+ ctx(const char* url, bool no_ssl_verify): abrt_xmlrpc_conn(url, no_ssl_verify) {}
- void new_xmlrpc_client(const char* url, bool no_ssl_verify);
- void destroy_xmlrpc_client();
-
- void login(const char* login, const char* passwd);
- void logout();
- int32_t check_uuid_in_bugzilla(const char* component, const char* UUID);
- bool check_cc_and_reporter(uint32_t bug_id, const char* login);
- void add_plus_one_cc(uint32_t bug_id, const char* login);
- uint32_t new_bug(const map_crash_report_t& pCrashReport);
- void add_attachments(const char* bug_id_str, const map_crash_report_t& pCrashReport);
+ void login(const char* login, const char* passwd);
+ void logout();
+ int32_t check_uuid_in_bugzilla(const char* component, const char* UUID);
+ bool check_cc_and_reporter(uint32_t bug_id, const char* login);
+ void add_plus_one_cc(uint32_t bug_id, const char* login);
+ uint32_t new_bug(const map_crash_report_t& pCrashReport);
+ void add_attachments(const char* bug_id_str, const map_crash_report_t& pCrashReport);
};
-void ctx::new_xmlrpc_client(const char* url, bool no_ssl_verify)
-{
- xmlrpc_env env;
- xmlrpc_env_init(&env);
-
- /* This should be done at program startup, once.
- * We do it in abrtd's main */
- /* xmlrpc_client_setup_global_const(&env); */
-
- struct xmlrpc_curl_xportparms curlParms;
- memset(&curlParms, 0, sizeof(curlParms));
- /* curlParms.network_interface = NULL; - done by memset */
- curlParms.no_ssl_verifypeer = no_ssl_verify;
- curlParms.no_ssl_verifyhost = no_ssl_verify;
-#ifdef VERSION
- curlParms.user_agent = PACKAGE_NAME"/"VERSION;
-#else
- curlParms.user_agent = "abrt";
-#endif
-
- struct xmlrpc_clientparms clientParms;
- memset(&clientParms, 0, sizeof(clientParms));
- clientParms.transport = "curl";
- clientParms.transportparmsP = &curlParms;
- clientParms.transportparm_size = XMLRPC_CXPSIZE(user_agent);
-
- client = NULL;
- xmlrpc_client_create(&env, XMLRPC_CLIENT_NO_FLAGS,
- PACKAGE_NAME, VERSION,
- &clientParms, XMLRPC_CPSIZE(transportparm_size),
- &client);
- throw_if_xml_fault_occurred(&env);
-
- server_info = xmlrpc_server_info_new(&env, url);
- if (env.fault_occurred)
- {
- xmlrpc_client_destroy(client);
- client = NULL;
- }
- throw_if_xml_fault_occurred(&env);
-}
-
-void ctx::destroy_xmlrpc_client()
-{
- if (server_info)
- {
- xmlrpc_server_info_free(server_info);
- server_info = NULL;
- }
- if (client)
- {
- xmlrpc_client_destroy(client);
- client = NULL;
- }
-}
-
void ctx::login(const char* login, const char* passwd)
{
xmlrpc_env env;
@@ -156,7 +80,7 @@ void ctx::login(const char* login, const char* passwd)
throw_if_xml_fault_occurred(&env);
xmlrpc_value* result = NULL;
- xmlrpc_client_call2(&env, client, server_info, "User.login", param, &result);
+ xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "User.login", param, &result);
xmlrpc_DECREF(param);
if (result)
xmlrpc_DECREF(result);
@@ -179,7 +103,7 @@ void ctx::logout()
throw_if_xml_fault_occurred(&env);
xmlrpc_value* result = NULL;
- xmlrpc_client_call2(&env, client, server_info, "User.logout", param, &result);
+ xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "User.logout", param, &result);
xmlrpc_DECREF(param);
if (result)
xmlrpc_DECREF(result);
@@ -195,7 +119,7 @@ bool ctx::check_cc_and_reporter(uint32_t bug_id, const char* login)
throw_if_xml_fault_occurred(&env);
xmlrpc_value* result = NULL;
- xmlrpc_client_call2(&env, client, server_info, "bugzilla.getBug", param, &result);
+ xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "bugzilla.getBug", param, &result);
throw_if_xml_fault_occurred(&env);
xmlrpc_DECREF(param);
@@ -263,7 +187,7 @@ void ctx::add_plus_one_cc(uint32_t bug_id, const char* login)
throw_if_xml_fault_occurred(&env);
xmlrpc_value* result = NULL;
- xmlrpc_client_call2(&env, client, server_info, "Bug.update", param, &result);
+ xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Bug.update", param, &result);
throw_if_xml_fault_occurred(&env);
xmlrpc_DECREF(result);
@@ -281,7 +205,7 @@ int32_t ctx::check_uuid_in_bugzilla(const char* component, const char* UUID)
throw_if_xml_fault_occurred(&env);
xmlrpc_value* result = NULL;
- xmlrpc_client_call2(&env, client, server_info, "Bug.search", param, &result);
+ xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Bug.search", param, &result);
throw_if_xml_fault_occurred(&env);
xmlrpc_DECREF(param);
@@ -362,7 +286,7 @@ uint32_t ctx::new_bug(const map_crash_report_t& pCrashReport)
throw_if_xml_fault_occurred(&env);
xmlrpc_value* result;
- xmlrpc_client_call2(&env, client, server_info, "Bug.create", param, &result);
+ xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Bug.create", param, &result);
throw_if_xml_fault_occurred(&env);
xmlrpc_value* id;
@@ -409,7 +333,7 @@ void ctx::add_attachments(const char* bug_id_str, const map_crash_report_t& pCra
free(encoded64);
throw_if_xml_fault_occurred(&env);
- xmlrpc_client_call2(&env, client, server_info, "bugzilla.addAttachment", param, &result);
+ xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "bugzilla.addAttachment", param, &result);
throw_if_xml_fault_occurred(&env);
xmlrpc_DECREF(result);
xmlrpc_DECREF(param);
diff --git a/lib/Plugins/Catcut.cpp b/lib/Plugins/Catcut.cpp
index 13fa8a41..f594bb48 100644
--- a/lib/Plugins/Catcut.cpp
+++ b/lib/Plugins/Catcut.cpp
@@ -1,7 +1,8 @@
#include <xmlrpc-c/base.h>
#include <xmlrpc-c/client.h>
-
+#include <curl/curl.h>
#include "abrtlib.h"
+#include "abrt_xmlrpc.h"
#include "Catcut.h"
#include "CrashTypes.h"
#include "DebugDump.h"
@@ -13,108 +14,8 @@
using namespace std;
-static xmlrpc_env env;
-static xmlrpc_client* client = NULL;
-static struct xmlrpc_clientparms clientParms;
-static struct xmlrpc_curl_xportparms curlParms;
-static xmlrpc_server_info* server_info = NULL;
-
-
-static string login(const char* login, const char* passwd);
-//static void logout();
-static void new_xmlrpc_client(const char* url, bool no_ssl_verify);
-static void destroy_xmlrpc_client();
-static void create_new_bug_description(const map_crash_report_t& pCrashReport, string& pDescription);
-static void get_product_and_version(const string& pRelease,
- string& pProduct,
- string& pVersion);
-
-
-static void throw_if_xml_fault_occurred()
-{
- if (env.fault_occurred)
- {
- string errmsg = ssprintf("XML-RPC Fault: %s(%d)", env.fault_string, env.fault_code);
- error_msg("%s", errmsg.c_str()); // show error in daemon log
- throw CABRTException(EXCEP_PLUGIN, errmsg);
- }
-}
-
-static void new_xmlrpc_client(const char* url, bool no_ssl_verify)
-{
- xmlrpc_env_init(&env);
-
- /* This should be done at program startup, once.
- * We do it in abrtd's main */
- /* xmlrpc_client_setup_global_const(&env); */
-
- curlParms.network_interface = NULL;
- curlParms.no_ssl_verifypeer = no_ssl_verify;
- curlParms.no_ssl_verifyhost = no_ssl_verify;
-#ifdef VERSION
- curlParms.user_agent = PACKAGE_NAME"/"VERSION;
-#else
- curlParms.user_agent = "abrt";
-#endif
-
- clientParms.transport = "curl";
- clientParms.transportparmsP = &curlParms;
- clientParms.transportparm_size = XMLRPC_CXPSIZE(user_agent);
-
- xmlrpc_client_create(&env, XMLRPC_CLIENT_NO_FLAGS, PACKAGE_NAME, VERSION, &clientParms, XMLRPC_CPSIZE(transportparm_size),
- &client);
- throw_if_xml_fault_occurred();
-
- server_info = xmlrpc_server_info_new(&env, url);
- throw_if_xml_fault_occurred();
-}
-
-static void destroy_xmlrpc_client()
-{
- xmlrpc_server_info_free(server_info);
- xmlrpc_env_clean(&env);
- xmlrpc_client_destroy(client);
-}
-
-static string login(const char* login, const char* passwd)
-{
- xmlrpc_value* param = xmlrpc_build_value(&env, "(ss)", login, passwd);
- throw_if_xml_fault_occurred();
-
- xmlrpc_value* result;
- xmlrpc_client_call2(&env, client, server_info, "Catcut.auth", param, &result);
- throw_if_xml_fault_occurred();
- xmlrpc_DECREF(param);
-
- xmlrpc_value *cookie_xml;
- const char *cookie;
- string cookie_str;
- xmlrpc_struct_find_value(&env, result, "cookie", &cookie_xml);
- throw_if_xml_fault_occurred();
- xmlrpc_read_string(&env, cookie_xml, &cookie);
- throw_if_xml_fault_occurred();
- cookie_str = cookie;
- /* xmlrpc_read_string returns *malloc'ed ptr*.
- * doc is not very clear on it, but I looked in xmlrpc sources. */
- free((void*)cookie);
- xmlrpc_DECREF(cookie_xml);
-
- xmlrpc_DECREF(result);
-
- return cookie_str;
-}
-
-// catcut does not have it (yet?)
-//static void logout()
-//{
-// xmlrpc_value* param = xmlrpc_build_value(&env, "(s)", "");
-// throw_if_xml_fault_occurred();
-//
-// xmlrpc_value* result = NULL; /* paranoia */
-// xmlrpc_client_call2(&env, client, server_info, "User.logout", param, &result);
-// throw_if_xml_fault_occurred();
-//}
+//TODO: move to make_descr.cpp
static void create_new_bug_description(const map_crash_report_t& pCrashReport, string& pDescription)
{
string howToReproduce;
@@ -167,39 +68,288 @@ static void create_new_bug_description(const map_crash_report_t& pCrashReport, s
}
}
-static void get_product_and_version(const string& pRelease,
- string& pProduct,
- string& pVersion)
+static void
+get_product_and_version(const char *pRelease,
+ string& pProduct,
+ string& pVersion)
{
- if (pRelease.find("Rawhide") != string::npos)
+ if (strstr(pRelease, "Rawhide"))
{
pProduct = "Fedora";
pVersion = "rawhide";
return;
}
- if (pRelease.find("Fedora") != string::npos)
+ if (strstr(pRelease, "Fedora"))
{
pProduct = "Fedora";
}
- else if (pRelease.find("Red Hat Enterprise Linux") != string::npos)
+ else if (strstr(pRelease, "Red Hat Enterprise Linux"))
{
pProduct = "Red Hat Enterprise Linux ";
}
- string::size_type pos = pRelease.find("release");
- pos = pRelease.find(" ", pos) + 1;
- while (pRelease[pos] != ' ')
+
+ const char *release = strstr(pRelease, "release");
+ const char *space = release ? strchr(release, ' ') : NULL;
+
+ if (space++) while (*space != '\0' && *space != ' ')
{
- pVersion += pRelease[pos];
+ /* Eat string like "5.2" */
+ pVersion += *space;
if (pProduct == "Red Hat Enterprise Linux ")
{
- pProduct += pRelease[pos];
+ pProduct += *space;
}
- pos++;
+ space++;
+ }
+}
+
+static int
+put_stream(const char *pURL, FILE* f, size_t content_length)
+{
+ CURL* curl = curl_easy_init();
+ if (!curl)
+ {
+ throw CABRTException(EXCEP_PLUGIN, "put_stream: Curl library error.");
+ }
+ /* enable uploading */
+ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
+ /* specify target */
+ curl_easy_setopt(curl, CURLOPT_URL, pURL);
+ /* file handle: passed to the default callback, it will fread() it */
+ curl_easy_setopt(curl, CURLOPT_READDATA, f);
+ /* get file size */
+ curl_easy_setopt(curl, CURLOPT_INFILESIZE, content_length);
+ /*everything is done here; result 0 means success*/
+ int result = curl_easy_perform(curl);
+ /* goodbye */
+ curl_easy_cleanup(curl);
+ return result;
+}
+
+static void
+send_string(const char *pURL,
+ const char *pContent,
+ int retryCount,
+ int retryDelaySeconds)
+{
+ if (pURL[0] == '\0')
+ {
+ error_msg(_("send_string: URL not specified"));
+ return;
+ }
+
+ do
+ {
+ int content_length = strlen(pContent);
+ FILE* f = fmemopen((void*)pContent, content_length, "r");
+ if (!f)
+ {
+ throw CABRTException(EXCEP_PLUGIN, "send_string: could not open string stream");
+ }
+ int result = put_stream(pURL, f, content_length);
+ fclose(f);
+ if (!result)
+ return;
+ update_client(_("Sending failed, try it again: %s"), curl_easy_strerror((CURLcode)result));
+ }
+ /*retry the upload if not succesful, wait a bit before next try*/
+ while (--retryCount != 0 && (sleep(retryDelaySeconds), 1));
+
+ throw CABRTException(EXCEP_PLUGIN, "send_string: could not send string");
+}
+
+static void
+send_file(const char *pURL,
+ const char *pFilename,
+ int retryCount,
+ int retryDelaySeconds)
+{
+ if (pURL[0] == '\0')
+ {
+ error_msg(_("send_file: URL not specified"));
+ return;
+ }
+
+ update_client(_("Sending file %s to %s"), pFilename, pURL);
+
+ do
+ {
+ FILE* f = fopen(pFilename, "r");
+ if (!f)
+ {
+ throw CABRTException(EXCEP_PLUGIN, "send_file: could not open string stream");
+ }
+ struct stat buf;
+ fstat(fileno(f), &buf); /* can't fail */
+ int content_length = buf.st_size;
+ int result = put_stream(pURL, f, content_length);
+ fclose(f);
+ if (!result)
+ return;
+ update_client(_("Sending failed, try it again: %s"), curl_easy_strerror((CURLcode)result));
+ }
+ /*retry the upload if not succesful, wait a bit before next try*/
+ while (--retryCount != 0 && (sleep(retryDelaySeconds), 1));
+
+ throw CABRTException(EXCEP_PLUGIN, "send_file: could not send file");
+}
+
+static string
+resolve_relative_url(const char *url, const char *base)
+{
+ // if 'url' is relative (not absolute) combine it with 'base'
+ // (which must be absolute)
+ // Only works in limited cases:
+ // 0) url is already absolute
+ // 1) url starts with two slashes
+ // 2) url starts with one slash
+
+ const char *colon = strchr(url, ':');
+ const char *slash = strchr(url, '/');
+
+ if (colon && (!slash || colon < slash))
+ {
+ return url;
+ }
+
+ const char *end_of_protocol = strchr(base, ':');
+ string protocol(base, end_of_protocol - base);
+
+ end_of_protocol += 3; /* skip "://" */
+ const char *end_of_host = strchr(end_of_protocol, '/');
+ string host(end_of_protocol, end_of_host - end_of_protocol);
+
+ if (url[0] == '/')
+ {
+ if (url[1] == '/')
+ {
+ protocol += ':';
+ protocol += url;
+ return protocol;
+ }
+ protocol += "://";
+ protocol += host;
+ protocol += url;
+ return protocol;
+ }
+ throw CABRTException(EXCEP_PLUGIN, "resolve_relative_url: unhandled relative url");
+}
+
+//
+// struct_find_XXXX
+// abstract all the busy work of getting a field's value from
+// a struct. XXXX is a type.
+// Return true/false = the field is in the struct
+// If true, return the field's value in 'value'.
+//
+// This function currently just assumes that the value in the
+// field can be read into the type of 'value'. This should probably
+// be fixed to either convert the fields value to the type of 'value'
+// or error specifically/usefully.
+//
+// This function probably should be converted to an overloaded function
+// (overloaded on the type of 'value'). It could also be a function
+// template.
+//
+
+static bool
+struct_find_int(xmlrpc_env* env, xmlrpc_value* result,
+ const char* fieldName, int& value)
+{
+ xmlrpc_value* an_xmlrpc_value;
+ xmlrpc_struct_find_value(env, result, fieldName, &an_xmlrpc_value);
+ throw_if_xml_fault_occurred(env);
+ if (an_xmlrpc_value)
+ {
+ xmlrpc_read_int(env, an_xmlrpc_value, &value);
+ throw_if_xml_fault_occurred(env);
+ xmlrpc_DECREF(an_xmlrpc_value);
+ return true;
}
+ return false;
}
-static string new_bug(const char *auth_cookie, const map_crash_report_t& pCrashReport)
+static bool
+struct_find_string(xmlrpc_env* env, xmlrpc_value* result,
+ const char* fieldName, string& value)
{
+ xmlrpc_value* an_xmlrpc_value;
+ xmlrpc_struct_find_value(env, result, fieldName, &an_xmlrpc_value);
+ throw_if_xml_fault_occurred(env);
+ if (an_xmlrpc_value)
+ {
+ const char* value_s;
+ xmlrpc_read_string(env, an_xmlrpc_value, &value_s);
+ throw_if_xml_fault_occurred(env);
+ value = value_s;
+ xmlrpc_DECREF(an_xmlrpc_value);
+ free((void*)value_s);
+ return true;
+ }
+ return false;
+}
+
+
+/*
+ * Static namespace for xmlrpc stuff.
+ * Used mainly to ensure we always destroy xmlrpc client and server_info.
+ */
+
+namespace {
+
+struct ctx: public abrt_xmlrpc_conn {
+ ctx(const char* url, bool no_ssl_verify): abrt_xmlrpc_conn(url, no_ssl_verify) {}
+
+ string login(const char* login, const char* passwd);
+ string new_bug(const char *auth_cookie, const map_crash_report_t& pCrashReport);
+ string request_upload(const char* auth_cookie, const char* pTicketName,
+ const char* fileName, const char* description);
+ void add_attachments(const char* xmlrpc_URL,
+ const char* auth_cookie,
+ const char* pTicketName,
+ const map_crash_report_t& pCrashReport,
+ int retryCount,
+ int retryDelaySeconds);
+};
+
+string
+ctx::login(const char* login, const char* passwd)
+{
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+
+ xmlrpc_value* param = xmlrpc_build_value(&env, "(ss)", login, passwd);
+ throw_if_xml_fault_occurred(&env);
+
+ xmlrpc_value* result;
+ xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Catcut.auth", param, &result);
+ xmlrpc_DECREF(param);
+ throw_if_xml_fault_occurred(&env);
+
+ xmlrpc_value *cookie_xml;
+ const char *cookie;
+ string cookie_str;
+ xmlrpc_struct_find_value(&env, result, "cookie", &cookie_xml);
+ throw_if_xml_fault_occurred(&env);
+ xmlrpc_read_string(&env, cookie_xml, &cookie);
+ throw_if_xml_fault_occurred(&env);
+ cookie_str = cookie;
+ /* xmlrpc_read_string returns *malloc'ed ptr*.
+ * doc is not very clear on it, but I looked in xmlrpc sources. */
+ free((void*)cookie);
+ xmlrpc_DECREF(cookie_xml);
+
+ xmlrpc_DECREF(result);
+
+ return cookie_str;
+}
+
+string
+ctx::new_bug(const char *auth_cookie, const map_crash_report_t& pCrashReport)
+{
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+
string package = pCrashReport.find(FILENAME_PACKAGE)->second[CD_CONTENT];
string component = pCrashReport.find(FILENAME_COMPONENT)->second[CD_CONTENT];
string release = pCrashReport.find(FILENAME_RELEASE)->second[CD_CONTENT];
@@ -214,7 +364,7 @@ static string new_bug(const char *auth_cookie, const map_crash_report_t& pCrashR
string product;
string version;
- get_product_and_version(release, product, version);
+ get_product_and_version(release.c_str(), product, version);
xmlrpc_value *param = xmlrpc_build_value(&env, "(s{s:s,s:s,s:s,s:s,s:s,s:s,s:s})",
auth_cookie,
@@ -226,20 +376,20 @@ static string new_bug(const char *auth_cookie, const map_crash_report_t& pCrashR
"status_whiteboard", status_whiteboard.c_str(),
"platform", arch.c_str()
);
- throw_if_xml_fault_occurred();
+ throw_if_xml_fault_occurred(&env);
xmlrpc_value *result;
- xmlrpc_client_call2(&env, client, server_info, "Catcut.createTicket", param, &result);
- throw_if_xml_fault_occurred();
+ xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Catcut.createTicket", param, &result);
xmlrpc_DECREF(param);
+ throw_if_xml_fault_occurred(&env);
xmlrpc_value *bug_id_xml;
const char *bug_id;
string bug_id_str;
xmlrpc_struct_find_value(&env, result, "ticket", &bug_id_xml);
- throw_if_xml_fault_occurred();
+ throw_if_xml_fault_occurred(&env);
xmlrpc_read_string(&env, bug_id_xml, &bug_id);
- throw_if_xml_fault_occurred();
+ throw_if_xml_fault_occurred(&env);
bug_id_str = bug_id;
log("New bug id: %s", bug_id);
update_client(_("New bug id: %s"), bug_id);
@@ -251,78 +401,175 @@ static string new_bug(const char *auth_cookie, const map_crash_report_t& pCrashR
return bug_id_str;
}
-//static
-//void add_attachments(const string& pBugId, const map_crash_report_t& pCrashReport)
-//{
-// xmlrpc_value* result = NULL;
-//
-// map_crash_report_t::const_iterator it = pCrashReport.begin();
-// for (; it != pCrashReport.end(); it++)
-// {
-// if (it->second[CD_TYPE] == CD_ATT)
-// {
-// string description = "File: " + it->first;
-// const string& to_encode = it->second[CD_CONTENT];
-// char *encoded64 = encode_base64(to_encode.c_str(), to_encode.length());
-// xmlrpc_value* param = xmlrpc_build_value(&env,"(s{s:s,s:s,s:s,s:s})",
-// pBugId.c_str(),
-// "description", description.c_str(),
-// "filename", it->first.c_str(),
-// "contenttype", "text/plain",
-// "data", encoded64
-// );
-// free(encoded64);
-// throw_if_xml_fault_occurred();
-//
-//// catcut has this API:
-//// struct response requestUpload(string cookie, string ticket, string filename, string description)
-////response MUST include "errno", "errmsg" members; if an upload is approved,
-////a "URL" MUST be returned in the response. The description string
-////should include a brief description of the file.
-////
-////The client should upload the file via HTTP PUT to the provided
-////URL. The provided URL may be absolute or relative, if relative it must
-////be combined with the base URL of the XML-RPC server using the usual
-////rules for relative URL's (RFC 3986).
-// xmlrpc_client_call2(&env, client, server_info, "catcut.addAttachment", param, &result);
-// throw_if_xml_fault_occurred();
-// }
-// }
-//}
+string
+ctx::request_upload(const char* auth_cookie, const char* pTicketName,
+ const char* fileName, const char* description)
+{
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+
+ xmlrpc_value* param = xmlrpc_build_value(&env, "(ssss)",
+ auth_cookie,
+ pTicketName,
+ fileName,
+ description);
+ throw_if_xml_fault_occurred(&env);
+
+ xmlrpc_value* result = NULL;
+ xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Catcut.requestUpload", param, &result);
+ xmlrpc_DECREF(param);
+ throw_if_xml_fault_occurred(&env);
+
+ string URL;
+ bool has_URL = struct_find_string(&env, result, "uri", URL);
+ if (!has_URL || URL == "")
+ {
+ int err;
+ bool has_errno = struct_find_int(&env, result, "errno", err);
+ if (has_errno && err)
+ {
+ string errmsg;
+ bool has_errmsg = struct_find_string(&env, result, "errmsg", errmsg);
+ if (has_errmsg)
+ {
+ log("error returned by requestUpload: %s", errmsg.c_str());
+ update_client(_("error returned by requestUpload: %s"), errmsg.c_str());
+ }
+ else
+ {
+ log("error returned by requestUpload: %d", err);
+ update_client(_("error returned by requestUpload: %d"), err);
+ }
+ }
+ else
+ {
+ log("no URL returned by requestUpload, and no err");
+ update_client(_("no URL returned by requestUpload, and no errno"));
+ }
+ }
+
+ log("requestUpload returned URL: %s", URL.c_str());
+ update_client(_("requestUpload returned URL: %s"), URL.c_str());
+
+ xmlrpc_DECREF(result);
+ return URL;
+}
+
+void
+ctx::add_attachments(const char* xmlrpc_URL,
+ const char* auth_cookie,
+ const char* pTicketName,
+ const map_crash_report_t& pCrashReport,
+ int retryCount,
+ int retryDelaySeconds)
+{
+
+ map_crash_report_t::const_iterator it = pCrashReport.begin();
+ for (; it != pCrashReport.end(); it++)
+ {
+ if (it->second[CD_TYPE] == CD_ATT)
+ {
+ update_client(_("Attaching (CD_ATT): %s"), it->first.c_str());
+
+ string description = "File: " + it->first;
+ string URL = request_upload(auth_cookie,
+ pTicketName,
+ it->first.c_str(),
+ description.c_str());
+
+ URL = resolve_relative_url(URL.c_str(), xmlrpc_URL);
+
+ log("rebased URL: %s", URL.c_str());
+ update_client(_("rebased URL: %s"), URL.c_str());
+
+ send_string(URL.c_str(), it->second[CD_CONTENT].c_str(),
+ retryCount, retryDelaySeconds);
+ }
+ else if (it->second[CD_TYPE] == CD_BIN)
+ {
+ update_client(_("Attaching (CD_ATT): %s"), it->first.c_str());
+
+ string description = "File: " + it->first;
+ string URL = request_upload(auth_cookie,
+ pTicketName,
+ it->first.c_str(),
+ description.c_str());
+
+ URL = resolve_relative_url(URL.c_str(), xmlrpc_URL);
+
+ log("rebased URL: %s", URL.c_str());
+ update_client(_("rebased URL: %s"), URL.c_str());
+
+ send_file(URL.c_str(), it->second[CD_CONTENT].c_str(),
+ retryCount, retryDelaySeconds);
+ }
+ }
+}
+
+} /* namespace */
+
+
+/*
+ * CReporterCatcut
+ */
CReporterCatcut::CReporterCatcut() :
m_sCatcutURL("http://127.0.0.1:8080/catcut/xmlrpc"),
- m_bNoSSLVerify(false)
+ m_bNoSSLVerify(false),
+ m_nRetryCount(3),
+ m_nRetryDelay(20)
{}
CReporterCatcut::~CReporterCatcut()
{}
string CReporterCatcut::Report(const map_crash_report_t& pCrashReport,
- const map_plugin_settings_t& pSettings, const string& pArgs)
+ const map_plugin_settings_t& pSettings,
+ const string& pArgs)
{
update_client(_("Creating new bug..."));
try
{
- new_xmlrpc_client(m_sCatcutURL.c_str(), m_bNoSSLVerify);
- string auth_cookie = login(m_sLogin.c_str(), m_sPassword.c_str());
- string bug_id = (auth_cookie != "") ? new_bug(auth_cookie.c_str(), pCrashReport) : "";
-// add_attachments(to_string(bug_id), pCrashReport);
-// update_client(_("Logging out..."));
-// logout();
- destroy_xmlrpc_client();
- return "New catcut bug ID: " + bug_id;
+ ctx catcut_server(m_sCatcutURL.c_str(), m_bNoSSLVerify);
+ string auth_cookie = catcut_server.login(m_sLogin.c_str(), m_sPassword.c_str());
+ string message;
+ if (auth_cookie != "")
+ {
+ string ticket_name = catcut_server.new_bug(auth_cookie.c_str(), pCrashReport);
+ if (ticket_name != "")
+ {
+ catcut_server.add_attachments(
+ m_sCatcutURL.c_str(),
+ auth_cookie.c_str(),
+ ticket_name.c_str(),
+ pCrashReport,
+ m_nRetryCount,
+ m_nRetryDelay
+ );
+ message = "New catcut bug ID: " + ticket_name;
+ }
+ else
+ {
+ message = "Error could not create ticket";
+ }
+ }
+ else
+ {
+ message = "Error could not create ticket";
+ }
+ return message;
}
catch (CABRTException& e)
{
- destroy_xmlrpc_client();
- throw CABRTException(EXCEP_PLUGIN, string("CReporterCatcut::Report(): ") + e.what());
+ throw CABRTException(EXCEP_PLUGIN, e.what());
}
}
void CReporterCatcut::SetSettings(const map_plugin_settings_t& pSettings)
{
+ m_pSettings = pSettings;
+
map_plugin_settings_t::const_iterator it;
map_plugin_settings_t::const_iterator end = pSettings.end();
@@ -346,16 +593,16 @@ void CReporterCatcut::SetSettings(const map_plugin_settings_t& pSettings)
{
m_bNoSSLVerify = it->second == "yes";
}
-}
-
-const map_plugin_settings_t& CReporterCatcut::GetSettings()
-{
- m_pSettings["CatcutURL"] = m_sCatcutURL;
- m_pSettings["Login"] = m_sLogin;
- m_pSettings["Password"] = m_sPassword;
- m_pSettings["NoSSLVerify"] = m_bNoSSLVerify ? "yes" : "no";
-
- return m_pSettings;
+ it = pSettings.find("RetryCount");
+ if (it != end)
+ {
+ m_nRetryCount = atoi(it->second.c_str());
+ }
+ it = pSettings.find("RetryDelay");
+ if (it != end)
+ {
+ m_nRetryDelay = atoi(it->second.c_str());
+ }
}
PLUGIN_INFO(REPORTER,
diff --git a/lib/Plugins/Catcut.h b/lib/Plugins/Catcut.h
index 15efdc1d..4fb89e22 100644
--- a/lib/Plugins/Catcut.h
+++ b/lib/Plugins/Catcut.h
@@ -11,13 +11,14 @@ class CReporterCatcut : public CReporter
std::string m_sLogin;
std::string m_sPassword;
bool m_bNoSSLVerify;
+ int m_nRetryCount;
+ int m_nRetryDelay;
public:
CReporterCatcut();
virtual ~CReporterCatcut();
virtual void SetSettings(const map_plugin_settings_t& pSettings);
- virtual const map_plugin_settings_t& GetSettings();
virtual std::string Report(const map_crash_report_t& pCrashReport,
const map_plugin_settings_t& pSettings,
diff --git a/lib/Utils/Makefile.am b/lib/Utils/Makefile.am
index 68c925fd..d2596f39 100644
--- a/lib/Utils/Makefile.am
+++ b/lib/Utils/Makefile.am
@@ -15,6 +15,7 @@ libABRTUtils_la_SOURCES = \
DebugDump.h DebugDump.cpp \
CommLayerInner.h CommLayerInner.cpp \
abrt_dbus.h abrt_dbus.cpp \
+ abrt_xmlrpc.h abrt_xmlrpc.cpp \
Plugin.h Plugin.cpp make_descr.cpp \
Polkit.h Polkit.cpp \
Action.h Database.h Reporter.h Analyzer.h \
@@ -30,6 +31,7 @@ libABRTUtils_la_CPPFLAGS = \
-DVAR_RUN=\"$(VAR_RUN)\" \
$(GLIB_CFLAGS) \
$(DBUS_CFLAGS) \
+ $(XMLRPC_CFLAGS) $(XMLRPC_CLIENT_CFLAGS) \
$(POLKIT_CFLAGS) \
-D_GNU_SOURCE
libABRTUtils_la_LDFLAGS = \
@@ -37,8 +39,10 @@ libABRTUtils_la_LDFLAGS = \
$(DL_LIBS) \
$(DBUS_LIBS)
libABRTUtils_la_LIBADD = \
+ $(XMLRPC_LIBS) $(XMLRPC_CLIENT_LIBS) \
$(POLKIT_LIBS)
+
install-data-local:
$(mkdir_p) '$(DESTDIR)/$(DEBUG_DUMPS_DIR)'
chmod 1777 '$(DESTDIR)/$(DEBUG_DUMPS_DIR)'
diff --git a/lib/Utils/abrt_xmlrpc.cpp b/lib/Utils/abrt_xmlrpc.cpp
new file mode 100644
index 00000000..11c431b8
--- /dev/null
+++ b/lib/Utils/abrt_xmlrpc.cpp
@@ -0,0 +1,76 @@
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "abrtlib.h"
+#include "abrt_xmlrpc.h"
+#include "ABRTException.h"
+
+void throw_if_xml_fault_occurred(xmlrpc_env *env)
+{
+ if (env->fault_occurred)
+ {
+ std::string errmsg = ssprintf("XML-RPC Fault: %s(%d)", env->fault_string, env->fault_code);
+ xmlrpc_env_clean(env); // this is needed ONLY if fault_occurred
+ xmlrpc_env_init(env); // just in case user catches ex and _continues_ to use env
+ error_msg("%s", errmsg.c_str()); // show error in daemon log
+ throw CABRTException(EXCEP_PLUGIN, errmsg);
+ }
+}
+
+void abrt_xmlrpc_conn::new_xmlrpc_client(const char* url, bool no_ssl_verify)
+{
+ m_pClient = NULL;
+ m_pServer_info = NULL;
+
+ xmlrpc_env env;
+ xmlrpc_env_init(&env);
+
+ /* This should be done at program startup, once.
+ * We do it in abrtd's main */
+ /* xmlrpc_client_setup_global_const(&env); */
+
+ struct xmlrpc_curl_xportparms curlParms;
+ memset(&curlParms, 0, sizeof(curlParms));
+ /* curlParms.network_interface = NULL; - done by memset */
+ curlParms.no_ssl_verifypeer = no_ssl_verify;
+ curlParms.no_ssl_verifyhost = no_ssl_verify;
+#ifdef VERSION
+ curlParms.user_agent = PACKAGE_NAME"/"VERSION;
+#else
+ curlParms.user_agent = "abrt";
+#endif
+
+ struct xmlrpc_clientparms clientParms;
+ memset(&clientParms, 0, sizeof(clientParms));
+ clientParms.transport = "curl";
+ clientParms.transportparmsP = &curlParms;
+ clientParms.transportparm_size = XMLRPC_CXPSIZE(user_agent);
+
+ xmlrpc_client_create(&env, XMLRPC_CLIENT_NO_FLAGS,
+ PACKAGE_NAME, VERSION,
+ &clientParms, XMLRPC_CPSIZE(transportparm_size),
+ &m_pClient);
+ throw_if_xml_fault_occurred(&env);
+
+ m_pServer_info = xmlrpc_server_info_new(&env, url);
+ if (env.fault_occurred)
+ {
+ xmlrpc_client_destroy(m_pClient);
+ m_pClient = NULL;
+ }
+ throw_if_xml_fault_occurred(&env);
+}
+
+void abrt_xmlrpc_conn::destroy_xmlrpc_client()
+{
+ if (m_pServer_info)
+ {
+ xmlrpc_server_info_free(m_pServer_info);
+ m_pServer_info = NULL;
+ }
+ if (m_pClient)
+ {
+ xmlrpc_client_destroy(m_pClient);
+ m_pClient = NULL;
+ }
+}
diff --git a/lib/Utils/abrt_xmlrpc.h b/lib/Utils/abrt_xmlrpc.h
new file mode 100644
index 00000000..e67ab19a
--- /dev/null
+++ b/lib/Utils/abrt_xmlrpc.h
@@ -0,0 +1,27 @@
+#ifndef ABRT_XMLRPC_H_
+#define ABRT_XMLRPC_H_ 1
+
+#include <xmlrpc-c/base.h>
+#include <xmlrpc-c/client.h>
+
+/*
+ * Simple class holding XMLRPC connection data.
+ * Used mainly to ensure we always destroy xmlrpc client and server_info
+ * on return or throw.
+ */
+
+struct abrt_xmlrpc_conn {
+ xmlrpc_client* m_pClient;
+ xmlrpc_server_info* m_pServer_info;
+
+ abrt_xmlrpc_conn(const char* url, bool no_ssl_verify) { new_xmlrpc_client(url, no_ssl_verify); }
+ ~abrt_xmlrpc_conn() { destroy_xmlrpc_client(); }
+
+ void new_xmlrpc_client(const char* url, bool no_ssl_verify);
+ void destroy_xmlrpc_client();
+};
+
+/* Utility function */
+void throw_if_xml_fault_occurred(xmlrpc_env *env);
+
+#endif