This patch adds BigFileURL and BigSizeMB parameters. If uploaded DIR is bigger than BigSizeMB, then it is not attached to the case, but uploaded to BigFileURL, then a comment is added to the case with the URL of uploaded file.
-- vda diff -x '*.po' -d -urpN libreport.5/src/plugins/abrt_rh_support.c libreport.6/src/plugins/abrt_rh_support.c --- libreport.5/src/plugins/abrt_rh_support.c 2013-02-07 14:31:32.000000000 +0100 +++ libreport.6/src/plugins/abrt_rh_support.c 2013-03-22 13:53:33.069697211 +0100 @@ -108,9 +108,11 @@ xxmlTextWriterWriteString(xmlTextWriterP #endif // +// Reportfile helpers +// + // End the reportfile, and prepare it for delivery. // No more bindings can be added after this. -// static void close_writer(reportfile_t* file) { @@ -123,9 +125,7 @@ close_writer(reportfile_t* file) file->writer = NULL; } -// // This allocates a reportfile_t structure and initializes it. -// reportfile_t* new_reportfile(void) { @@ -159,9 +159,7 @@ internal_reportfile_start_binding(report xxmlTextWriterWriteAttribute(file->writer, "type", "text"); } -// // Add a new text binding -// void reportfile_add_binding_from_string(reportfile_t* file, const char* name, const char* value) { @@ -171,9 +169,7 @@ reportfile_add_binding_from_string(repor xxmlTextWriterEndElement(file->writer); } -// // Add a new binding to a report whose value is represented as a file. -// void reportfile_add_binding_from_namedfile(reportfile_t* file, const char* on_disk_filename, /* unused so far */ @@ -189,9 +185,7 @@ reportfile_add_binding_from_namedfile(re free(href_name); } -// // Return the contents of the reportfile as a string. -// const char* reportfile_as_string(reportfile_t* file) { @@ -222,9 +216,27 @@ void free_rhts_result(rhts_result_t *p) } // -// create_new_case() +// Common // +static const char *const text_plain_header[] = { + "Accept: text/plain", + NULL +}; +// +// Creating new case +// See +// https://access.redhat.com/knowledge/docs/Red_Hat_Customer_Portal/integration_guide.html +// +// $ curl -X POST -H 'Content-Type: application/xml' --data +// '<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +// <case xmlns="http://www.redhat.com/gss/strata"> +// <summary>Example Case</summary> +// <description>Example created with cURL</description> +// <product>Red Hat Enterprise Linux</product><version>6.0</version> +// </case>' +// https://api.access.redhat.com/rs/cases +// static char* make_case_data(const char* summary, const char* description, const char* product, const char* version, @@ -261,52 +273,6 @@ make_case_data(const char* summary, cons return retval; } -#if 0 //unused -static char* -make_response(const char* title, const char* body, - const char* actualURL, const char* displayURL) -{ - char* retval; - xmlTextWriterPtr writer; - xmlBufferPtr buf; - - buf = xxmlBufferCreate(); - writer = xxmlNewTextWriterMemory(buf); - - xxmlTextWriterStartDocument(writer, NULL, "UTF-8", "yes"); - xxmlTextWriterStartElement(writer, "response"); - if (title) { - xxmlTextWriterWriteElement(writer, "title", title); - } - if (body) { - xxmlTextWriterWriteElement(writer, "body", body); - } - if (actualURL || displayURL) { - xxmlTextWriterStartElement(writer, "URL"); - if (actualURL) { - xxmlTextWriterWriteAttribute(writer, "href", actualURL); - } - if (displayURL) { - xxmlTextWriterWriteString(writer, displayURL); - } - } - - xxmlTextWriterEndDocument(writer); - retval = xstrdup((const char*)buf->content); - xmlFreeTextWriter(writer); - xmlBufferFree(buf); - return retval; -} -//Example: -//<?xml version="1.0" encoding="UTF-8" standalone="yes"?> -//<response><title>Case Created and Report Attached</title><body></body><URL href="http://support-services-devel.gss.redhat.com:8080/Strata/cases/00005129/attachments/ccbf3e65-b941-3db7-a016-6a3831691a32">New Case URL</URL></response> -#endif - -static const char *const text_plain_header[] = { - "Accept: text/plain", - NULL -}; - static rhts_result_t* post_case_to_url(const char* url, const char* username, @@ -332,23 +298,23 @@ post_case_to_url(const char* url, int redirect_count = 0; char *errmsg; - post_state_t *case_state; + post_state_t *post_state; - redirect_case: - case_state = new_post_state(0 + redirect: + post_state = new_post_state(0 + POST_WANT_HEADERS + POST_WANT_BODY + POST_WANT_ERROR_MSG + (ssl_verify ? POST_WANT_SSL_VERIFY : 0) ); - case_state->username = username; - case_state->password = password; + post_state->username = username; + post_state->password = password; - post_string(case_state, url, "application/xml", additional_headers, case_data); + post_string(post_state, url, "application/xml", additional_headers, case_data); - char *case_location = find_header_in_post_state(case_state, "Location:"); + char *location = find_header_in_post_state(post_state, "Location:"); - switch (case_state->http_resp_code) + switch (post_state->http_resp_code) { case 404: /* Not strictly necessary (default branch would deal with it too), @@ -363,12 +329,12 @@ post_case_to_url(const char* url, 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 && case_location) + if (++redirect_count < 10 && location) { free(url_copy); - url = url_copy = xstrdup(case_location); - free_post_state(case_state); - goto redirect_case; + url = url_copy = xstrdup(location); + free_post_state(post_state); + goto redirect; } /* fall through */ @@ -388,42 +354,236 @@ post_case_to_url(const char* url, // '^M' // ' ' <------ body is useless result->error = -1; - errmsg = case_state->curl_error_msg; + errmsg = post_state->curl_error_msg; if (errmsg && errmsg[0]) { result->msg = xasprintf(_("Error in case creation: %s"), errmsg); } else { - errmsg = find_header_in_post_state(case_state, "Strata-Message:"); + errmsg = find_header_in_post_state(post_state, "Strata-Message:"); if (!errmsg) - errmsg = case_state->body; + errmsg = post_state->body; if (errmsg && errmsg[0]) result->msg = xasprintf(_("Error in case creation, HTTP code: %d, server says: '%s'"), - case_state->http_resp_code, errmsg); + post_state->http_resp_code, errmsg); else result->msg = xasprintf(_("Error in case creation, HTTP code: %d"), - case_state->http_resp_code); + post_state->http_resp_code); } break; case 200: case 201: - /* Cose created successfully */ - result->url = xstrdup(case_location); /* note: xstrdup(NULL) returns NULL */ - //result->msg = xstrdup("Case created"); + /* Created successfully */ + result->url = xstrdup(location); /* note: xstrdup(NULL) returns NULL */ } /* switch (HTTP code) */ - result->http_resp_code = case_state->http_resp_code; - result->body = case_state->body; - case_state->body = NULL; + result->http_resp_code = post_state->http_resp_code; + result->body = post_state->body; + post_state->body = NULL; - free_post_state(case_state); + free_post_state(post_state); free(case_data); free(url_copy); return result; } +rhts_result_t* +create_new_case(const char* base_url, + const char* username, + const char* password, + bool ssl_verify, + const char* release, + const char* summary, + const char* description, + const char* component) +{ + char *url = concat_path_file(base_url, "cases"); + rhts_result_t *result = post_case_to_url(url, + username, + password, + ssl_verify, + (const char **)text_plain_header, + release, + summary, + description, + component + ); + free(url); + + if (!result->error && !result->url) + { + /* Case Creation returned valid code, but no location */ + result->error = -1; + free(result->msg); + result->msg = xasprintf(_("Error in case creation: no Location URL, HTTP code: %d"), + result->http_resp_code + ); + } + + return result; +} + +// +// Add case comment +// +// $ curl -X POST -H 'Content-Type: application/xml' --data +// '<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +// <comment xmlns="http://www.redhat.com/gss/strata"> +// <text>Test comment! This can contain lots of information, etc.</text> +// </comment>' +// https://api.access.redhat.com/rs/cases/NNNNNNN/comments +// +static char* +make_comment_data(const char *comment_text) +{ + char *retval; + xmlTextWriterPtr writer; + xmlBufferPtr buf; + + buf = xxmlBufferCreate(); + writer = xxmlNewTextWriterMemory(buf); + + xxmlTextWriterStartDocument(writer, NULL, "UTF-8", "yes"); + xxmlTextWriterStartElement(writer, "comment"); + xxmlTextWriterWriteAttribute(writer, "xmlns", + "http://www.redhat.com/gss/strata"); + + xxmlTextWriterWriteElement(writer, "text", comment_text); + + xxmlTextWriterEndDocument(writer); + retval = xstrdup((const char*)buf->content); + xmlFreeTextWriter(writer); + xmlBufferFree(buf); + return retval; +} + +static rhts_result_t* +post_comment_to_url(const char *url, + const char *username, + const char *password, + bool ssl_verify, + const char **additional_headers, + const char *comment_text) +{ + rhts_result_t *result = xzalloc(sizeof(*result)); + char *url_copy = NULL; + + char *xml = make_comment_data(comment_text); + + 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 + + (ssl_verify ? POST_WANT_SSL_VERIFY : 0) + ); + post_state->username = username; + post_state->password = password; + + post_string(post_state, url, "application/xml", additional_headers, xml); + + char *location = find_header_in_post_state(post_state, "Location:"); + + switch (post_state->http_resp_code) + { + case 404: + /* Not strictly necessary (default branch would deal with it too), + * but makes this typical error less cryptic: + * instead of returning html-encoded body, we show short concise message, + * and show offending URL (typos in which is a typical cause) */ + result->error = -1; + result->msg = xasprintf("Error in HTTP POST, " + "HTTP code: 404 (Not found), URL:'%s'", url); + 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->error = -1; + errmsg = post_state->curl_error_msg; + if (errmsg && errmsg[0]) + { + result->msg = xasprintf(_("Error in comment creation: %s"), errmsg); + } + else + { + errmsg = find_header_in_post_state(post_state, "Strata-Message:"); + if (!errmsg) + errmsg = post_state->body; + if (errmsg && errmsg[0]) + result->msg = xasprintf(_("Error in comment creation, HTTP code: %d, server says: '%s'"), + post_state->http_resp_code, errmsg); + else + result->msg = xasprintf(_("Error in comment creation, HTTP code: %d"), + post_state->http_resp_code); + } + break; + + case 200: + case 201: + /* Created successfully */ + result->url = xstrdup(location); /* note: xstrdup(NULL) returns NULL */ + } /* switch (HTTP code) */ + + result->http_resp_code = post_state->http_resp_code; + result->body = post_state->body; + post_state->body = NULL; + + free_post_state(post_state); + free(xml); + free(url_copy); + return result; +} + +rhts_result_t* +add_comment_to_case(const char* base_url, + const char* username, + const char* password, + bool ssl_verify, + const char* comment_text) +{ + char *url = concat_path_file(base_url, "comments"); + rhts_result_t *result = post_comment_to_url(url, + username, + password, + ssl_verify, + (const char **)text_plain_header, + comment_text + ); + free(url); + + if (!result->error && !result->url) + { + /* Creation returned valid code, but no location */ + result->error = -1; + free(result->msg); + result->msg = xasprintf(_("Error in comment creation: no Location URL, HTTP code: %d"), + result->http_resp_code + ); + } + + return result; +} + +// +// Attach file to case +// static rhts_result_t* post_file_to_url(const char* url, const char* username, @@ -522,41 +682,28 @@ post_file_to_url(const char* url, } rhts_result_t* -create_new_case(const char* base_url, +attach_file_to_case(const char* base_url, const char* username, const char* password, bool ssl_verify, - const char* release, - const char* summary, - const char* description, - const char* component) + const char *file_name) { - char *url = concat_path_file(base_url, "cases"); - rhts_result_t *result = post_case_to_url(url, + char *url = concat_path_file(base_url, "attachments"); + rhts_result_t *result = post_file_to_url(url, username, password, ssl_verify, - (const char **)text_plain_header, - release, - summary, - description, - component + /*post_as_form:*/ true, + (const char **) text_plain_header, + file_name ); free(url); - - if (!result->error && !result->url) - { - /* Case Creation returned valid code, but no location */ - result->error = -1; - free(result->msg); - result->msg = xasprintf(_("Error in case creation: no Location URL, HTTP code: %d"), - result->http_resp_code - ); - } - return result; } +// +// Get hint +// rhts_result_t* get_rhts_hints(const char* base_url, const char* username, @@ -584,25 +731,5 @@ get_rhts_hints(const char* base_url, file_name ); free(url); - return result; -} - -rhts_result_t* -attach_file_to_case(const char* base_url, - const char* username, - const char* password, - bool ssl_verify, - const char *file_name) -{ - char *url = concat_path_file(base_url, "attachments"); - rhts_result_t *result = post_file_to_url(url, - username, - password, - ssl_verify, - /*post_as_form:*/ true, - (const char **) text_plain_header, - file_name - ); - free(url); return result; } diff -x '*.po' -d -urpN libreport.5/src/plugins/abrt_rh_support.h libreport.6/src/plugins/abrt_rh_support.h --- libreport.5/src/plugins/abrt_rh_support.h 2013-02-07 14:31:32.000000000 +0100 +++ libreport.6/src/plugins/abrt_rh_support.h 2013-03-22 11:57:17.860089776 +0100 @@ -70,6 +70,13 @@ create_new_case(const char* baseURL, ); rhts_result_t* +add_comment_to_case(const char* base_url, + const char* username, + const char* password, + bool ssl_verify, + const char* comment_text); + +rhts_result_t* attach_file_to_case(const char* baseURL, const char* username, const char* password, diff -x '*.po' -d -urpN libreport.5/src/plugins/reporter-rhtsupport.c libreport.6/src/plugins/reporter-rhtsupport.c --- libreport.5/src/plugins/reporter-rhtsupport.c 2013-03-22 14:56:23.241918966 +0100 +++ libreport.6/src/plugins/reporter-rhtsupport.c 2013-03-22 12:03:39.283404448 +0100 @@ -163,6 +163,15 @@ int create_tarball(const char *tempfile, return 1; /* failure */ } +static +char *get_param_string(const char *name, map_string_h *settings, const char *dflt) +{ + char *envname = xasprintf("RHTSupport_%s", name); + const char *envvar = getenv(envname); + free(envname); + return xstrdup(envvar ? envvar : (get_map_string_item_or_NULL(settings, name) ? : dflt)); +} + int main(int argc, char **argv) { abrt_init(argv); @@ -189,7 +198,8 @@ int main(int argc, char **argv) "\n" "If not specified, CONFFILE defaults to "CONF_DIR"/plugins/rhtsupport.conf\n" "Its lines should have 'PARAM = VALUE' format.\n" - "Recognized string parameters: URL, Login, Password.\n" + "Recognized string parameters: URL, Login, Password, BigFileURL.\n" + "Recognized numeric parameter: BigSizeMB.\n" "Recognized boolean parameter (VALUE should be 1/0, yes/no): SSLVerify.\n" "Parameters can be overridden via $RHTSupport_PARAM environment variables.\n" "\n" @@ -233,21 +243,21 @@ int main(int argc, char **argv) VERB3 log("Loaded '%s'", fn); conf_file = g_list_remove(conf_file, fn); } - char* envvar; - char *url; - char *login; - char *password; - bool ssl_verify; - envvar = getenv("RHTSupport_URL"); - url = xstrdup(envvar ? envvar : (get_map_string_item_or_NULL(settings, "URL") ? : "https://api.access.redhat.com/rs")); - envvar = getenv("RHTSupport_Login"); - login = xstrdup(envvar ? envvar : get_map_string_item_or_empty(settings, "Login")); - envvar = getenv("RHTSupport_Password"); - password = xstrdup(envvar ? envvar : get_map_string_item_or_empty(settings, "Password")); - envvar = getenv("RHTSupport_SSLVerify"); - ssl_verify = string_to_bool(envvar ? envvar : get_map_string_item_or_empty(settings, "SSLVerify")); + char *url = get_param_string("URL" , settings, "https://api.access.redhat.com/rs"); + char *login = get_param_string("Login" , settings, ""); + char *password = get_param_string("Password" , settings, ""); + char *bigurl = get_param_string("BigFileURL", settings, "ftp://dropbox.redhat.com/incoming/"); if (!login[0] || !password[0]) error_msg_and_die(_("Empty RHTS login or password")); + char* envvar; + envvar = getenv("RHTSupport_SSLVerify"); + bool ssl_verify = string_to_bool( + envvar ? envvar : (get_map_string_item_or_NULL(settings, "SSLVerify") ? : "1") + ); + envvar = getenv("RHTSupport_BigSizeMB"); + unsigned bigsize = xatoi_positive( + envvar ? envvar : (get_map_string_item_or_NULL(settings, "BigSizeMB") ? : "1000") + ); free_map_string(settings); if (opts & OPT_t) @@ -471,16 +481,44 @@ int main(int argc, char **argv) log("URL=%s", result->url); } /* else: error msg was already emitted by dd_opendir */ + url = result->url; } - /* Attach the tarball of -d DIR */ - result_atch = attach_file_to_case(url, - login, - password, - ssl_verify, - tempfile - ); + char *remote_filename = NULL; + if (bigsize != 0 && tempfile_size / (1024*1024) >= bigsize) + { + /* Upload tarball of -d DIR to "big file" FTP */ + remote_filename = upload_file(bigurl, tempfile); + } + if (remote_filename) + { + /* Attach a comment where to find uploaded tarball. + * Do not translate this message - it goes to a server + * where *other people* will read it + */ + char *comment_text = xasprintf( + "Problem data was uploaded to %s", + remote_filename + ); + free(remote_filename); + result_atch = add_comment_to_case(url, + login, password, + ssl_verify, + comment_text + ); + free(comment_text); + } + else + { + /* Attach the tarball of -d DIR */ + result_atch = attach_file_to_case(url, + login, password, + ssl_verify, + tempfile + + ); + } if (result_atch->error) { if (!(opts & OPT_t))