Blame src/plugins/bodhi.c

Packit 8ea169
/*
Packit 8ea169
    Copyright (C) 2011  ABRT Team
Packit 8ea169
    Copyright (C) 2011  RedHat inc.
Packit 8ea169
Packit 8ea169
    This program is free software; you can redistribute it and/or modify
Packit 8ea169
    it under the terms of the GNU General Public License as published by
Packit 8ea169
    the Free Software Foundation; either version 2 of the License, or
Packit 8ea169
    (at your option) any later version.
Packit 8ea169
Packit 8ea169
    This program is distributed in the hope that it will be useful,
Packit 8ea169
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8ea169
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8ea169
    GNU General Public License for more details.
Packit 8ea169
Packit 8ea169
    You should have received a copy of the GNU General Public License along
Packit 8ea169
    with this program; if not, write to the Free Software Foundation, Inc.,
Packit 8ea169
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 8ea169
*/
Packit 8ea169
Packit 8ea169
#include <json.h>
Packit 8ea169
#include <rpm/rpmts.h>
Packit 8ea169
#include <rpm/rpmcli.h>
Packit 8ea169
#include <rpm/rpmdb.h>
Packit 8ea169
#include <rpm/rpmpgp.h>
Packit 8ea169
Packit 8ea169
#include <libreport/internal_libreport.h>
Packit 8ea169
#include <libreport/libreport_curl.h>
Packit 8ea169
#include <libreport/client.h>
Packit 8ea169
Packit 8ea169
#include "libabrt.h"
Packit 8ea169
Packit 8ea169
//699198,705037,705036
Packit 8ea169
Packit 8ea169
/* bodhi returns json structure
Packit 8ea169
Packit 8ea169
{
Packit 8ea169
 "rows_per_page": 20,
Packit 8ea169
    "total": 1,
Packit 8ea169
    "chrome": true,
Packit 8ea169
    "display_user": true,
Packit 8ea169
    "pages": 1,
Packit 8ea169
    "updates": [
Packit 8ea169
       {
Packit 8ea169
        "close_bugs": true,
Packit 8ea169
        "old_updateid": "FEDORA-2015-13720",
Packit 8ea169
        "pushed": true,
Packit 8ea169
        "require_testcases": false,
Packit 8ea169
        "critpath": false,
Packit 8ea169
        "date_approved": null,
Packit 8ea169
        "stable_karma": null,
Packit 8ea169
        "date_pushed": "2015-08-19 04:49:00",
Packit 8ea169
        "requirements": null,
Packit 8ea169
        "severity": "unspecified",
Packit 8ea169
        "title": "hwloc-1.11.0-3.fc22",
Packit 8ea169
        "suggest": "unspecified",
Packit 8ea169
        "require_bugs": false,
Packit 8ea169
        "comments": [
Packit 8ea169
           {
Packit 8ea169
            "bug_feedback": [],
Packit 8ea169
            "user_id": 91,
Packit 8ea169
            "text": "This update has been submitted for testing by jhladky. ",
Packit 8ea169
            "testcase_feedback": [],
Packit 8ea169
            "karma_critpath": 0,
Packit 8ea169
            "update": 21885,
Packit 8ea169
            "update_id": 21885,
Packit 8ea169
            "karma": 0,
Packit 8ea169
            "anonymous": false,
Packit 8ea169
            "timestamp": "2015-08-18 13:38:35",
Packit 8ea169
            "id": 166016,
Packit 8ea169
            "user": {"stacks": [],
Packit 8ea169
                "name": "bodhi",
Packit 8ea169
                "avatar": "https://apps.fedoraproject.org/img/icons/bodhi-24.png"}
Packit 8ea169
           },
Packit 8ea169
           {
Packit 8ea169
           ...
Packit 8ea169
           }
Packit 8ea169
        ],
Packit 8ea169
        "updateid": "FEDORA-2015-13720",
Packit 8ea169
        "cves": [],
Packit 8ea169
        "type": "bugfix",
Packit 8ea169
        "status": "testing",
Packit 8ea169
        "date_submitted": "2015-08-18 13:37:26",
Packit 8ea169
        "unstable_karma": null,
Packit 8ea169
        "submitter": "jhladky",
Packit 8ea169
        "user":
Packit 8ea169
           {
Packit 8ea169
            "stacks": [],
Packit 8ea169
            "buildroot_overrides": [],
Packit 8ea169
            "name": "jhladky",
Packit 8ea169
            "avatar": "https://seccdn.libravatar.org/avatar/b838b78fcf707a13cdaeb1c846d514e614d617cbf2c106718e71cb397607f59b?s=24&d=retro"
Packit 8ea169
           },
Packit 8ea169
        "locked": false,
Packit 8ea169
        "builds": [{"override": null,
Packit 8ea169
            "nvr": "hwloc-1.11.0-3.fc22"}],
Packit 8ea169
        "date_modified": null,
Packit 8ea169
        "test_cases": [],
Packit 8ea169
        "notes": "Fix for BZ1253977",
Packit 8ea169
        "request": null,
Packit 8ea169
        "bugs": [
Packit 8ea169
           {
Packit 8ea169
            "bug_id": 1253977,
Packit 8ea169
            "security": false,
Packit 8ea169
            "feedback": [],
Packit 8ea169
            "parent": false,
Packit 8ea169
            "title": "conflict between hwloc-libs-1.11.0-1.fc22.i686 and hwloc-libs-1.11.0-1.fc22.x86_64"
Packit 8ea169
           }
Packit 8ea169
        ],
Packit 8ea169
        "alias": "FEDORA-2015-13720",
Packit 8ea169
        "karma": 0,
Packit 8ea169
        "release":
Packit 8ea169
           {
Packit 8ea169
            "dist_tag": "f22",
Packit 8ea169
            "name": "F22",
Packit 8ea169
            "testing_tag": "f22-updates-testing",
Packit 8ea169
            "pending_stable_tag": "f22-updates-pending",
Packit 8ea169
            "long_name": "Fedora 22",
Packit 8ea169
            "state": "current",
Packit 8ea169
            "version": "22",
Packit 8ea169
            "override_tag": "f22-override",
Packit 8ea169
            "branch": "f22",
Packit 8ea169
            "id_prefix": "FEDORA",
Packit 8ea169
            "pending_testing_tag": "f22-updates-testing-pending",
Packit 8ea169
            "stable_tag": "f22-updates",
Packit 8ea169
            "candidate_tag": "f22-updates-candidate"
Packit 8ea169
           }
Packit 8ea169
       }
Packit 8ea169
    ],
Packit 8ea169
    "display_request": true,
Packit 8ea169
    "page": 1
Packit 8ea169
}
Packit 8ea169
*/
Packit 8ea169
Packit 8ea169
static const char *bodhi_url = "https://bodhi.fedoraproject.org/updates";
Packit 8ea169
Packit 8ea169
struct bodhi {
Packit 8ea169
    char *nvr;
Packit 8ea169
#if 0
Packit 8ea169
    char *date_pushed;
Packit 8ea169
    char *status;
Packit 8ea169
    char *dist_tag;
Packit 8ea169
Packit 8ea169
    GList *bz_ids;
Packit 8ea169
#endif
Packit 8ea169
};
Packit 8ea169
Packit 8ea169
enum {
Packit 8ea169
    BODHI_READ_STR,
Packit 8ea169
    BODHI_READ_INT,
Packit 8ea169
    BODHI_READ_JSON_OBJ,
Packit 8ea169
};
Packit 8ea169
Packit 8ea169
static void free_bodhi_item(struct bodhi *b)
Packit 8ea169
{
Packit 8ea169
    if (!b)
Packit 8ea169
        return;
Packit 8ea169
Packit 8ea169
    free(b->nvr);
Packit 8ea169
Packit 8ea169
#if 0
Packit 8ea169
    list_free_with_free(b->bz_ids);
Packit 8ea169
    free(b->date_pushed);
Packit 8ea169
    free(b->status);
Packit 8ea169
    free(b->dist_tag);
Packit 8ea169
#endif
Packit 8ea169
Packit 8ea169
    free(b);
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static void bodhi_read_value(json_object *json, const char *item_name,
Packit 8ea169
                             void *value, int flags)
Packit 8ea169
{
Packit 8ea169
    json_object *j = NULL;
Packit 8ea169
    if (!json_object_object_get_ex(json, item_name, &j))
Packit 8ea169
    {
Packit 8ea169
        error_msg("'%s' section is not available", item_name);
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    switch (flags) {
Packit 8ea169
    case BODHI_READ_INT:
Packit 8ea169
        *(int *) value = json_object_get_int(j);
Packit 8ea169
        break;
Packit 8ea169
    case BODHI_READ_STR:
Packit 8ea169
        *(char **) value = (char *) strtrimch(xstrdup(json_object_to_json_string(j)), '"');
Packit 8ea169
        break;
Packit 8ea169
    case BODHI_READ_JSON_OBJ:
Packit 8ea169
        *(json_object **) value = (json_object *) j;
Packit 8ea169
        break;
Packit 8ea169
    };
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
#if 0
Packit 8ea169
static void print_bodhi(struct bodhi *b)
Packit 8ea169
{
Packit 8ea169
    for (GList *l = b->nvr; l; l = l->next)
Packit 8ea169
        printf("'%s' ", (char *)l->data);
Packit 8ea169
Packit 8ea169
    for (GList *l = b->name; l; l = l->next)
Packit 8ea169
        printf("'%s' ", (char *)l->data);
Packit 8ea169
Packit 8ea169
    if (b->date_pushed)
Packit 8ea169
        printf(" '%s'", b->date_pushed);
Packit 8ea169
Packit 8ea169
    if (b->status)
Packit 8ea169
        printf(" '%s'", b->status);
Packit 8ea169
Packit 8ea169
    if (b->dist_tag)
Packit 8ea169
        printf(" '%s'", b->dist_tag);
Packit 8ea169
Packit 8ea169
    printf(" %i", b->karma);
Packit 8ea169
Packit 8ea169
Packit 8ea169
/*
Packit 8ea169
    for (GList *li = b->bz_ids; li; li = li->next)
Packit 8ea169
        printf(" %i", *(int*) li->data);
Packit 8ea169
*/
Packit 8ea169
    puts("");
Packit 8ea169
}
Packit 8ea169
#endif
Packit 8ea169
Packit 8ea169
/* bodhi returns following json structure in case of error
Packit 8ea169
{
Packit 8ea169
   "status": "error",
Packit 8ea169
   "errors":
Packit 8ea169
              [
Packit 8ea169
                {
Packit 8ea169
                   "location": "querystring",
Packit 8ea169
                   "name": "releases",
Packit 8ea169
                   "description": "Invalid releases specified: Rawhide"
Packit 8ea169
                }
Packit 8ea169
              ]
Packit 8ea169
}
Packit 8ea169
*/
Packit 8ea169
static void bodhi_print_errors_from_json(json_object *json)
Packit 8ea169
{
Packit 8ea169
Packit 8ea169
    json_object *errors_array = NULL;
Packit 8ea169
    bodhi_read_value(json, "errors", &errors_array, BODHI_READ_JSON_OBJ);
Packit 8ea169
    if (!errors_array)
Packit 8ea169
    {
Packit 8ea169
        error_msg("Error: unable to read 'errors' array from json");
Packit 8ea169
        return;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    int errors_len = json_object_array_length(errors_array);
Packit 8ea169
    for (int i = 0; i < errors_len; ++i)
Packit 8ea169
    {
Packit 8ea169
        json_object *error = json_object_array_get_idx(errors_array, i);
Packit 8ea169
        if (!error)
Packit 8ea169
        {
Packit 8ea169
            error_msg("Error: unable to get 'error[%d]'", i);
Packit 8ea169
            json_object_put(errors_array);
Packit 8ea169
            return;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        char *desc_item = NULL;
Packit 8ea169
        bodhi_read_value(error, "description", &desc_item, BODHI_READ_STR);
Packit 8ea169
        if (!desc_item)
Packit 8ea169
        {
Packit 8ea169
            error_msg("Error: unable to get 'description' from 'error[%d]'", i);
Packit 8ea169
            continue;
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
        error_msg("Error: %s", desc_item);
Packit 8ea169
        json_object_put(error);
Packit 8ea169
        free(desc_item);
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    json_object_put(errors_array);
Packit 8ea169
    return;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
/**
Packit 8ea169
 * Parses only name from nvr
Packit 8ea169
 * nvr is RPM packages naming convention format: name-version-release
Packit 8ea169
 *
Packit 8ea169
 * for example: meanwhile3.34.3-3.34-3.fc666
Packit 8ea169
 *              ^name           ^ver.^release
Packit 8ea169
 */
Packit 8ea169
static int parse_nvr_name(const char *nvr, char **name)
Packit 8ea169
{
Packit 8ea169
    const int len = strlen(nvr);
Packit 8ea169
    if (len <= 0)
Packit 8ea169
        return EINVAL;
Packit 8ea169
    const char *c = nvr + len - 1;
Packit 8ea169
    /* skip release */
Packit 8ea169
    for (; *c != '-'; --c)
Packit 8ea169
    {
Packit 8ea169
        if (c <= nvr)
Packit 8ea169
            return EINVAL;
Packit 8ea169
    }
Packit 8ea169
    --c;
Packit 8ea169
    /* skip version */
Packit 8ea169
    for (; *c != '-'; --c)
Packit 8ea169
    {
Packit 8ea169
        if (c <= nvr)
Packit 8ea169
            return EINVAL;
Packit 8ea169
    }
Packit 8ea169
    if (c <= nvr)
Packit 8ea169
        return EINVAL;
Packit 8ea169
Packit 8ea169
    *name = xstrndup(nvr, (c - nvr));
Packit 8ea169
Packit 8ea169
    return 0;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static GHashTable *bodhi_parse_json(json_object *json, const char *release)
Packit 8ea169
{
Packit 8ea169
Packit 8ea169
    int num_items = 0;
Packit 8ea169
    bodhi_read_value(json, "total", &num_items, BODHI_READ_INT);
Packit 8ea169
    if (num_items <= 0)
Packit 8ea169
        return NULL;
Packit 8ea169
Packit 8ea169
    json_object *updates = NULL;
Packit 8ea169
    bodhi_read_value(json, "updates", &updates, BODHI_READ_JSON_OBJ);
Packit 8ea169
    if (!updates)
Packit 8ea169
        return NULL;
Packit 8ea169
Packit 8ea169
    int updates_len = json_object_array_length(updates);
Packit 8ea169
Packit 8ea169
    GHashTable *bodhi_table = g_hash_table_new_full(g_str_hash, g_str_equal, free,
Packit 8ea169
                                                    (GDestroyNotify) free_bodhi_item);
Packit 8ea169
    for (int i = 0; i < updates_len; ++i)
Packit 8ea169
    {
Packit 8ea169
        json_object *updates_item = json_object_array_get_idx(updates, i);
Packit 8ea169
Packit 8ea169
        /* some of item are null */
Packit 8ea169
        if (!updates_item)
Packit 8ea169
            continue;
Packit 8ea169
Packit 8ea169
        json_object *builds_item = NULL;
Packit 8ea169
        bodhi_read_value(updates_item, "builds", &builds_item, BODHI_READ_JSON_OBJ);
Packit 8ea169
        if (!builds_item) /* broken json */
Packit 8ea169
            continue;
Packit 8ea169
Packit 8ea169
        int karma, unstable_karma;
Packit 8ea169
        bodhi_read_value(updates_item, "karma", &karma, BODHI_READ_INT);
Packit 8ea169
        bodhi_read_value(updates_item, "unstable_karma", &unstable_karma, BODHI_READ_INT);
Packit 8ea169
        if (karma <= unstable_karma)
Packit 8ea169
            continue;
Packit 8ea169
Packit 8ea169
        struct bodhi *b = NULL;
Packit 8ea169
        int builds_len = json_object_array_length(builds_item);
Packit 8ea169
        for (int k = 0; k < builds_len; ++k)
Packit 8ea169
        {
Packit 8ea169
            b = xzalloc(sizeof(struct bodhi));
Packit 8ea169
Packit 8ea169
            char *name = NULL;
Packit 8ea169
            json_object *build = json_object_array_get_idx(builds_item, k);
Packit 8ea169
Packit 8ea169
            bodhi_read_value(build, "nvr", &b->nvr, BODHI_READ_STR);
Packit 8ea169
Packit 8ea169
            if (parse_nvr_name(b->nvr, &name))
Packit 8ea169
                error_msg_and_die("failed to parse package name from nvr: '%s'", b->nvr);
Packit 8ea169
Packit 8ea169
            log_info("Found package: %s\n", name);
Packit 8ea169
Packit 8ea169
            struct bodhi *bodhi_tbl_item = g_hash_table_lookup(bodhi_table, name);
Packit 8ea169
            if (bodhi_tbl_item && rpmvercmp(bodhi_tbl_item->nvr, b->nvr) > 0)
Packit 8ea169
            {
Packit 8ea169
                free_bodhi_item(b);
Packit 8ea169
                continue;
Packit 8ea169
            }
Packit 8ea169
            g_hash_table_replace(bodhi_table, name, b);
Packit 8ea169
        }
Packit 8ea169
Packit 8ea169
#if 0
Packit 8ea169
        bodhi_read_value(updates_item, "date_pushed", &b->date_pushed, BODHI_READ_STR);
Packit 8ea169
        bodhi_read_value(updates_item, "status", &b->status, BODHI_READ_STR);
Packit 8ea169
Packit 8ea169
        json_object *release_item = NULL;
Packit 8ea169
        bodhi_read_value(updates_item, "release", &release_item, BODHI_READ_JSON_OBJ);
Packit 8ea169
        if (release_item)
Packit 8ea169
            bodhi_read_value(release_item, "dist_tag", &b->dist_tag, BODHI_READ_STR);
Packit 8ea169
Packit 8ea169
        json_object *bugs = NULL;
Packit 8ea169
        bodhi_read_value(updates_item, "bugs", &release_item, BODHI_READ_JSON_OBJ);
Packit 8ea169
        if (bugs)
Packit 8ea169
        {
Packit 8ea169
            for (int j = 0; j < json_object_array_length(bugs); ++j)
Packit 8ea169
            {
Packit 8ea169
                int *bz_id = xmalloc(sizeof(int));
Packit 8ea169
                json_object *bug_item = json_object_array_get_idx(bugs, j);
Packit 8ea169
                bodhi_read_value(bug_item, "bz_id", bz_id, BODHI_READ_INT);
Packit 8ea169
                b->bz_ids = g_list_append(b->bz_ids, bz_id);
Packit 8ea169
            }
Packit 8ea169
        }
Packit 8ea169
#endif
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    return bodhi_table;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static GHashTable *bodhi_query_list(const char *query, const char *release)
Packit 8ea169
{
Packit 8ea169
    char *bodhi_url_bugs = xasprintf("%s/?%s", bodhi_url, query);
Packit 8ea169
Packit 8ea169
    post_state_t *post_state = new_post_state(POST_WANT_BODY
Packit 8ea169
                                              | POST_WANT_SSL_VERIFY
Packit 8ea169
                                              | POST_WANT_ERROR_MSG);
Packit 8ea169
Packit 8ea169
    const char *headers[] = {
Packit 8ea169
        "Accept: application/json",
Packit 8ea169
        NULL
Packit 8ea169
    };
Packit 8ea169
Packit 8ea169
    get(post_state, bodhi_url_bugs, "application/x-www-form-urlencoded",
Packit 8ea169
                     headers);
Packit 8ea169
Packit 8ea169
    if (post_state->http_resp_code != 200 && post_state->http_resp_code != 400)
Packit 8ea169
    {
Packit 8ea169
        char *errmsg = post_state->curl_error_msg;
Packit 8ea169
        if (errmsg && errmsg[0])
Packit 8ea169
            error_msg_and_die("%s '%s'", errmsg, bodhi_url_bugs);
Packit 8ea169
    }
Packit 8ea169
    free(bodhi_url_bugs);
Packit 8ea169
Packit 8ea169
//    log_warning("%s", post_state->body);
Packit 8ea169
Packit 8ea169
    json_object *json = json_tokener_parse(post_state->body);
Packit 8ea169
    if (json == NULL)
Packit 8ea169
        error_msg_and_die("fatal: unable parse response from bodhi server");
Packit 8ea169
Packit 8ea169
    /* we must check the http_resp_code because only error responses contain
Packit 8ea169
     * 'status' item. 'bodhi_read_value' function prints an error message in
Packit 8ea169
     * the case it did not found the item */
Packit 8ea169
    if (post_state->http_resp_code != 200)
Packit 8ea169
    {
Packit 8ea169
        char *status_item = NULL;
Packit 8ea169
        bodhi_read_value(json, "status", &status_item, BODHI_READ_STR);
Packit 8ea169
        if (status_item != NULL && strcmp(status_item, "error") == 0)
Packit 8ea169
        {
Packit 8ea169
            free(status_item);
Packit 8ea169
            bodhi_print_errors_from_json(json);
Packit 8ea169
            json_object_put(json);
Packit 8ea169
            xfunc_die(); // error_msg are printed in bodhi_print_errors_from_json
Packit 8ea169
        }
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    GHashTable *bodhi_table = bodhi_parse_json(json, release);
Packit 8ea169
    json_object_put(json);
Packit 8ea169
    free_post_state(post_state);
Packit 8ea169
Packit 8ea169
    return bodhi_table;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
static char *rpm_get_nvr_by_pkg_name(const char *pkg_name)
Packit 8ea169
{
Packit 8ea169
    int status = rpmReadConfigFiles((const char *) NULL, (const char *) NULL);
Packit 8ea169
    if (status)
Packit 8ea169
        error_msg_and_die("error reading RPM rc files");
Packit 8ea169
Packit 8ea169
    char *nvr = NULL;
Packit 8ea169
Packit 8ea169
    rpmts ts = rpmtsCreate();
Packit 8ea169
    rpmdbMatchIterator iter = rpmtsInitIterator(ts, RPMTAG_NAME, pkg_name, 0);
Packit 8ea169
    Header header = rpmdbNextIterator(iter);
Packit 8ea169
Packit 8ea169
    if (!header)
Packit 8ea169
        goto error;
Packit 8ea169
Packit 8ea169
    const char *errmsg = NULL;
Packit 8ea169
    nvr = headerFormat(header, "%{name}-%{version}-%{release}", &errmsg);
Packit 8ea169
Packit 8ea169
    if (!nvr && errmsg)
Packit 8ea169
        error_msg("cannot get nvr. reason: %s", errmsg);
Packit 8ea169
Packit 8ea169
error:
Packit 8ea169
    rpmdbFreeIterator(iter);
Packit 8ea169
    rpmtsFree(ts);
Packit 8ea169
Packit 8ea169
    rpmFreeRpmrc();
Packit 8ea169
    rpmFreeCrypto();
Packit 8ea169
    rpmFreeMacros(NULL);
Packit 8ea169
Packit 8ea169
    return nvr;
Packit 8ea169
}
Packit 8ea169
Packit 8ea169
int main(int argc, char **argv)
Packit 8ea169
{
Packit 8ea169
    abrt_init(argv);
Packit 8ea169
    enum {
Packit 8ea169
        OPT_v = 1 << 0,
Packit 8ea169
        OPT_d = 1 << 1,
Packit 8ea169
        OPT_g = 1 << 2,
Packit 8ea169
        OPT_b = 1 << 3,
Packit 8ea169
        OPT_u = 1 << 4,
Packit 8ea169
        OPT_r = 1 << 5,
Packit 8ea169
    };
Packit 8ea169
Packit 8ea169
    const char *bugs = NULL, *release = NULL, *dump_dir_path = ".";
Packit 8ea169
    /* Keep enum above and order of options below in sync! */
Packit 8ea169
    struct options program_options[] = {
Packit 8ea169
        OPT__VERBOSE(&g_verbose),
Packit 8ea169
        OPT__DUMP_DIR(&dump_dir_path),
Packit 8ea169
        OPT_GROUP(""),
Packit 8ea169
        OPT_STRING('b', "bugs", &bugs, "ID1[,ID2,...]" , _("List of bug ids")),
Packit 8ea169
        OPT_STRING('u', "url", &bodhi_url, "URL", _("Specify a bodhi server url")),
Packit 8ea169
        OPT_OPTSTRING('r', "release", &release, "RELEASE", _("Specify a release")),
Packit 8ea169
        OPT_END()
Packit 8ea169
    };
Packit 8ea169
Packit 8ea169
    const char *program_usage_string = _(
Packit 8ea169
        "& [-v] [-r[RELEASE]] (-b ID1[,ID2,...] | PKG-NAME) [PKG-NAME]... \n"
Packit 8ea169
        "\n"
Packit 8ea169
        "Search for updates on bodhi server"
Packit 8ea169
    );
Packit 8ea169
Packit 8ea169
    unsigned opts =  parse_opts(argc, argv, program_options, program_usage_string);
Packit 8ea169
Packit 8ea169
    if (!bugs && !argv[optind])
Packit 8ea169
        show_usage_and_die(program_usage_string, program_options);
Packit 8ea169
Packit 8ea169
    struct strbuf *query = strbuf_new();
Packit 8ea169
    if (bugs)
Packit 8ea169
        query = strbuf_append_strf(query, "bugs=%s&", bugs);
Packit 8ea169
Packit 8ea169
    if (opts & OPT_r)
Packit 8ea169
    {
Packit 8ea169
        if (release)
Packit 8ea169
        {
Packit 8ea169
            /* There are no bodhi updates for Rawhide */
Packit 8ea169
            if (strcasecmp(release, "rawhide") == 0)
Packit 8ea169
                error_msg_and_die("Release \"%s\" is not supported",release);
Packit 8ea169
Packit 8ea169
            query = strbuf_append_strf(query, "releases=%s&", release);
Packit 8ea169
        }
Packit 8ea169
        else
Packit 8ea169
        {
Packit 8ea169
            struct dump_dir *dd = dd_opendir(dump_dir_path, DD_OPEN_READONLY);
Packit 8ea169
            if (!dd)
Packit 8ea169
                xfunc_die();
Packit 8ea169
Packit 8ea169
            problem_data_t *problem_data = create_problem_data_from_dump_dir(dd);
Packit 8ea169
            dd_close(dd);
Packit 8ea169
            if (!problem_data)
Packit 8ea169
                xfunc_die(); /* create_problem_data_for_reporting already emitted error msg */
Packit 8ea169
Packit 8ea169
            char *product, *version;
Packit 8ea169
            map_string_t *osinfo = new_map_string();
Packit 8ea169
            problem_data_get_osinfo(problem_data, osinfo);
Packit 8ea169
            parse_osinfo_for_rhts(osinfo, &product, &version);
Packit 8ea169
Packit 8ea169
            /* There are no bodhi updates for Rawhide */
Packit 8ea169
            bool rawhide = strcasecmp(version, "rawhide") == 0;
Packit 8ea169
            if (!rawhide)
Packit 8ea169
                query = strbuf_append_strf(query, "releases=f%s&", version);
Packit 8ea169
Packit 8ea169
            free(product);
Packit 8ea169
            free(version);
Packit 8ea169
            free_map_string(osinfo);
Packit 8ea169
Packit 8ea169
            if (rawhide)
Packit 8ea169
            {
Packit 8ea169
                strbuf_free(query);
Packit 8ea169
                error_msg_and_die("Release \"Rawhide\" is not supported");
Packit 8ea169
            }
Packit 8ea169
        }
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (argv[optind])
Packit 8ea169
    {
Packit 8ea169
        char *escaped = g_uri_escape_string(argv[optind], NULL, 0);
Packit 8ea169
        query = strbuf_append_strf(query, "packages=%s&", escaped);
Packit 8ea169
        free(escaped);
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    if (query->buf[query->len - 1] == '&')
Packit 8ea169
        query->buf[query->len - 1] = '\0';
Packit 8ea169
Packit 8ea169
    log_warning(_("Searching for updates"));
Packit 8ea169
    GHashTable *update_hash_tbl = bodhi_query_list(query->buf, release);
Packit 8ea169
    strbuf_free(query);
Packit 8ea169
Packit 8ea169
    if (!update_hash_tbl || !g_hash_table_size(update_hash_tbl))
Packit 8ea169
    {
Packit 8ea169
        log_warning(_("No updates for this package found"));
Packit 8ea169
        /*if (update_hash_tbl) g_hash_table_unref(update_hash_tbl);*/
Packit 8ea169
        return 0;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    GHashTableIter iter;
Packit 8ea169
    char *name;
Packit 8ea169
    struct bodhi *b;
Packit 8ea169
    struct strbuf *q = strbuf_new();
Packit 8ea169
    g_hash_table_iter_init(&iter, update_hash_tbl);
Packit 8ea169
    while (g_hash_table_iter_next(&iter, (void **) &name, (void **) &b))
Packit 8ea169
    {
Packit 8ea169
        char *installed_pkg_nvr = rpm_get_nvr_by_pkg_name(name);
Packit 8ea169
        if (installed_pkg_nvr && rpmvercmp(installed_pkg_nvr, b->nvr) >= 0)
Packit 8ea169
        {
Packit 8ea169
            log_info("Update %s is older or same as local version %s, skipping", b->nvr, installed_pkg_nvr);
Packit 8ea169
            free(installed_pkg_nvr);
Packit 8ea169
            continue;
Packit 8ea169
        }
Packit 8ea169
        free(installed_pkg_nvr);
Packit 8ea169
Packit 8ea169
        strbuf_append_strf(q, " %s", b->nvr);
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    /*g_hash_table_unref(update_hash_tbl);*/
Packit 8ea169
Packit 8ea169
    if (!q->len)
Packit 8ea169
    {
Packit 8ea169
        /*strbuf_free(q);*/
Packit 8ea169
        log_warning(_("Local version of the package is newer than available updates"));
Packit 8ea169
        return 0;
Packit 8ea169
    }
Packit 8ea169
Packit 8ea169
    /* Message is split into text and command in order to make
Packit 8ea169
     * translator's job easier
Packit 8ea169
     */
Packit 8ea169
Packit 8ea169
    /* We suggest the command which is most likely to exist on user's system,
Packit 8ea169
     * and which is familiar to the largest population of users.
Packit 8ea169
     * There are other tools (pkcon et al) which might be somewhat more
Packit 8ea169
     * convenient (for example, they might be usable from non-root), but they
Packit 8ea169
     * might be not present on the system, may evolve or be superseded,
Packit 8ea169
     * as it did happen to yum.
Packit 8ea169
     */
Packit 8ea169
Packit 8ea169
    map_string_t *settings = new_map_string();
Packit 8ea169
    load_abrt_plugin_conf_file("CCpp.conf", settings);
Packit 8ea169
Packit 8ea169
    const char *value;
Packit 8ea169
    strbuf_prepend_str(q, " update --enablerepo=fedora --enablerepo=updates --enablerepo=updates-testing");
Packit 8ea169
    value = get_map_string_item_or_NULL(settings, "PackageManager");
Packit 8ea169
    if (value)
Packit 8ea169
        strbuf_prepend_str(q, value);
Packit 8ea169
    else
Packit 8ea169
        strbuf_prepend_str(q, DEFAULT_PACKAGE_MANAGER);
Packit 8ea169
    free_map_string(settings);
Packit 8ea169
Packit 8ea169
    char *msg = xasprintf(_("An update exists which might fix your problem. "
Packit 8ea169
                "You can install it by running: %s. "
Packit 8ea169
                "Do you want to continue with reporting the bug?"),
Packit 8ea169
                q->buf
Packit 8ea169
    );
Packit 8ea169
    /*strbuf_free(q);*/
Packit 8ea169
Packit 8ea169
    return ask_yes_no(msg) ? 0 : EXIT_STOP_EVENT_RUN;
Packit 8ea169
}