unsigned rhbz_version(struct abrt_xmlrpc *ax) { func_entry(); xmlrpc_value *result; result = abrt_xmlrpc_call(ax, "Bugzilla.version", "()"); char *version = NULL; if (result) version = rhbz_bug_read_item("version", result, RHBZ_READ_STR); if (!result || !version) error_msg_and_die("Can't determine %s", "Bugzilla.version"); xmlrpc_DECREF(result); strchrnul(version, '-')[0] = '\0'; /* format must be x.y.z */ char *vp; int i = 0, v[3] = {0, 0, 0}; for (vp = version; i < 3; vp = NULL, ++i) { char *tok = strtok(vp, "."); if (!tok) break; v[i] = strtoul(tok, NULL, 10); } free(version); return BUGZILLA_VERSION(v[0], v[1], v[2]); }
/* die or return bug id; each bug must have bug id otherwise xml is corrupted */ int rhbz_get_bug_id_from_array0(xmlrpc_value* xml, unsigned ver) { func_entry(); xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_value *item = NULL; xmlrpc_array_read_item(&env, xml, 0, &item); if (env.fault_occurred) abrt_xmlrpc_die(&env); const char *id; if (ver >= BUGZILLA_VERSION(4,2,0)) id = "id"; else id = "bug_id"; xmlrpc_value *bug; bug = rhbz_get_member(id, item); xmlrpc_DECREF(item); if (!bug) error_msg_and_die("Can't get member '%s' from bug data", id); int bug_id = -1; xmlrpc_read_int(&env, bug, &bug_id); xmlrpc_DECREF(bug); if (env.fault_occurred) abrt_xmlrpc_die(&env); VERB3 log("found bug_id %i", bug_id); return bug_id; }
bool rhbz_login(struct abrt_xmlrpc *ax, const char *login, const char *password) { func_entry(); xmlrpc_env env; xmlrpc_value *result = abrt_xmlrpc_call_full(&env, ax, "User.login", "({s:s,s:s})", "login", login, "password", password); if (env.fault_occurred) { /* 300 (Invalid Username or Password) - https://wiki.mozilla.org/Bugzilla:WebServices:Errors */ if (env.fault_code != 300) abrt_xmlrpc_die(&env); VERB1 log("xmlrpc fault: (%d) %s", env.fault_code, env.fault_string); return false; } //TODO: with URL like http://bugzilla.redhat.com (that is, with http: instead of https:) //we are getting this error: //Logging into Bugzilla at http://bugzilla.redhat.com //Can't login. Server said: HTTP response code is 301, not 200 //But this is a 301 redirect! We _can_ follow it if we configure curl to understand that! xmlrpc_DECREF(result); return true; }
struct bug_info *new_bug_info() { func_entry(); struct bug_info *bi = xzalloc(sizeof(struct bug_info)); bi->bi_dup_id = -1; return bi; }
/* The only way this can fail is if arrayP is not actually an array XML-RPC * value. So it is usually not worth checking *envP. * die or return size of array */ unsigned rhbz_array_size(xmlrpc_value *xml) { func_entry(); xmlrpc_env env; xmlrpc_env_init(&env); unsigned size = xmlrpc_array_size(&env, xml); if (env.fault_occurred) abrt_xmlrpc_die(&env); return size; }
static char *trim_all_whitespace(const char *str) { func_entry(); char *trim = xzalloc(sizeof(char) * strlen(str) + 1); int i = 0; while (*str) { if (!isspace(*str)) trim[i++] = *str; str++; } return trim; }
void free_bug_info(struct bug_info *bi) { func_entry(); if (!bi) return; free(bi->bi_status); free(bi->bi_resolution); free(bi->bi_reporter); free(bi->bi_product); list_free_with_free(bi->bi_cc_list); free(bi); }
xmlrpc_value *rhbz_array_item_at(xmlrpc_value *xml, int pos) { func_entry(); xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_value* item = NULL; xmlrpc_array_read_item(&env, xml, pos, &item); if (env.fault_occurred) abrt_xmlrpc_die(&env); xmlrpc_env_clean(&env); return item; }
// TODO: npajkovs: add flag to read xmlrpc_read_array_item first void *rhbz_bug_read_item(const char *memb, xmlrpc_value *xml, int flags) { func_entry(); xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_value *member = rhbz_get_member(memb, xml); const char *string = NULL; if (!member) goto die; if (IS_READ_STR(flags)) { xmlrpc_read_string(&env, member, &string); xmlrpc_DECREF(member); if (env.fault_occurred) abrt_xmlrpc_die(&env); if (!*string) goto die; VERB3 log("found %s: '%s'", memb, string); return (void*)string; } if (IS_READ_INT(flags)) { int *integer = xmalloc(sizeof(int)); xmlrpc_read_int(&env, member, integer); xmlrpc_DECREF(member); if (env.fault_occurred) abrt_xmlrpc_die(&env); VERB3 log("found %s: '%i'", memb, *integer); return (void*)integer; } die: free((void*)string); if (IS_MANDATORY(flags)) error_msg_and_die(_("Looks like corrupted xml response, because '%s'" " member is missing."), memb); return NULL; }
int is_comment_dup(GList *comments, const char *comment) { func_entry(); char * const trim_comment = trim_all_whitespace(comment); bool same_comments = false; for (GList *l = comments; l && !same_comments; l = l->next) { const char * const comment_body = (const char *) l->data; char * const trim_comment_body = trim_all_whitespace(comment_body); same_comments = (strcmp(trim_comment_body, trim_comment) == 0); free(trim_comment_body); } free(trim_comment); return same_comments; }
GList *rhbz_bug_cc(xmlrpc_value* result_xml) { func_entry(); xmlrpc_env env; xmlrpc_env_init(&env); xmlrpc_value* cc_member = rhbz_get_member("cc", result_xml); if (!cc_member) return NULL; unsigned array_size = rhbz_array_size(cc_member); VERB3 log("count members on cc %i", array_size); GList *cc_list = NULL; for (unsigned i = 0; i < array_size; ++i) { xmlrpc_value* item = NULL; xmlrpc_array_read_item(&env, cc_member, i, &item); if (env.fault_occurred) abrt_xmlrpc_die(&env); if (!item) continue; const char* cc = NULL; xmlrpc_read_string(&env, item, &cc); xmlrpc_DECREF(item); if (env.fault_occurred) abrt_xmlrpc_die(&env); if (*cc != '\0') { cc_list = g_list_append(cc_list, (char*)cc); VERB3 log("member on cc is %s", cc); continue; } free((char*)cc); } xmlrpc_DECREF(cc_member); return cc_list; }
static unsigned find_best_bt_rating_in_comments(GList *comments) { func_entry(); if (!comments) return 0; int best_bt_rating = 0; for (GList *l = comments; l; l = l->next) { char *comment_body = (char *) l->data; char *start_rating_line = strstr(comment_body, FILENAME_RATING": "); if (!start_rating_line) { VERB3 error_msg("comment does not contain rating"); continue; } start_rating_line += strlen(FILENAME_RATING": "); errno = 0; char *e; long rating = strtoul(start_rating_line, &e, 10); /* * Note: we intentionally check for '\n'. Any other terminator * (even '\0') is not ok in this case. */ if (errno || e == start_rating_line || *e != '\n' || (unsigned long)rating > UINT_MAX) { /* error / no digits / illegal trailing chars */ continue; } if (rating > best_bt_rating) best_bt_rating = rating; } return best_bt_rating; }
/************************************************************************* HandleVendorRequest =================== **************************************************************************/ static BOOL HandleVendorRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData) { IAP func_entry; func_entry = (IAP) IAP_LOCATION; if (pSetup->wIndex != 0) { DBG("Invalid idx %X\n", pSetup->wIndex); return FALSE; } if (pSetup->wValue != 0) { DBG("Invalid val %X\n", pSetup->wValue); return FALSE; } switch (pSetup->bRequest) { // commands case REQ_IAP_COMMAND: /* fallthrough */ case REQ_ISP_COMMAND: /* fallthrough */ case REQ_BTL_COMMAND: if (pSetup->bRequest == REQ_IAP_COMMAND) func_entry = (IAP) IAP_LOCATION; if (pSetup->bRequest == REQ_ISP_COMMAND) func_entry = isp_entry; if (pSetup->bRequest == REQ_BTL_COMMAND) func_entry = btl_entry; if (REQTYPE_GET_DIR(pSetup->bmRequestType) == REQTYPE_DIR_TO_HOST) { // send result *ppbData = (U8*) rescmd; *piLen = 32; // TODO remove if (*piLen != 32) return FALSE; } else { // start command if (*piLen != 20) return FALSE; memcpy(&rescmd[3], *ppbData, 20); func_entry(&rescmd[3], rescmd); } break; // data transfer case REQ_DATA_TRANSFER: if (REQTYPE_GET_DIR(pSetup->bmRequestType) == REQTYPE_DIR_TO_HOST) { // check if data to read if (*piLen > read_mem_len) return FALSE; *ppbData = (U8*) read_mem_adr; read_mem_adr += *piLen; read_mem_len -= *piLen; } else { // data is already written, adjust pointers if (*piLen > write_ram_len) return FALSE; write_ram_adr += *piLen; write_ram_len -= *piLen; } break; default: DBG("Unhandled vendor\n"); return FALSE; } return TRUE; }
static GList *rhbz_comments(struct abrt_xmlrpc *ax, int bug_id) { func_entry(); /* http://www.bugzilla.org/docs/4.2/en/html/api/Bugzilla/WebService/Bug.html#comments */ /* * <methodResponse> * <params><param> * <value><struct> * <member><name>bugs</name> * <value><struct> * <member><name>BUG_ID</name> * <value><struct> * <member><name>comments</name> * <value><array> * ... */ xmlrpc_value *xml_response = abrt_xmlrpc_call(ax, "Bug.comments", "({s:(i)})", "ids", bug_id); /* bugs * This is used for bugs specified in ids. This is a hash, where the * keys are the numeric ids of the bugs, and the value is a hash with a * single key, comments, which is an array of comments. */ xmlrpc_value *bugs_memb = rhbz_get_member("bugs", xml_response); /* Get hash value assigned to bug_id key */ char *item = xasprintf("%d", bug_id); xmlrpc_value *item_memb = rhbz_get_member(item, bugs_memb); free(item); /* Get array of comments */ xmlrpc_value *comments_memb = rhbz_get_member("comments", item_memb); xmlrpc_env env; xmlrpc_env_init(&env); int comments_memb_size = rhbz_array_size(comments_memb); GList *comments = NULL; for (int i = 0; i < comments_memb_size; ++i) { xmlrpc_value* item = NULL; xmlrpc_array_read_item(&env, comments_memb, i, &item); if (env.fault_occurred) abrt_xmlrpc_die(&env); char *comment_body = rhbz_bug_read_item("text", item, RHBZ_READ_STR); /* attachments are sometimes without comments -- skip them */ if (comment_body) comments = g_list_prepend(comments, comment_body); xmlrpc_DECREF(item); } xmlrpc_env_clean(&env); xmlrpc_DECREF(comments_memb); xmlrpc_DECREF(item_memb); xmlrpc_DECREF(bugs_memb); xmlrpc_DECREF(xml_response); return g_list_reverse(comments); }
struct bug_info *rhbz_bug_info(struct abrt_xmlrpc *ax, int bug_id) { func_entry(); struct bug_info *bz = new_bug_info(); /* http://www.bugzilla.org/docs/4.2/en/html/api/Bugzilla/WebService/Bug.html#get * * <methodResponse> * <params> * <param><value><struct> * <member><name>faults</name><value><array><data/></array></value></member> * <member><name>bugs</name> * <value><array><data> * ... */ xmlrpc_value *xml_bug_response = abrt_xmlrpc_call(ax, "Bug.get", "({s:(i)})", "ids", bug_id); xmlrpc_value *bugs_memb = rhbz_get_member("bugs", xml_bug_response); xmlrpc_value *bug_item = rhbz_array_item_at(bugs_memb, 0); int *ret = (int*)rhbz_bug_read_item("id", bug_item, RHBZ_MANDATORY_MEMB | RHBZ_READ_INT); bz->bi_id = *ret; free(ret); bz->bi_product = rhbz_bug_read_item("product", bug_item, RHBZ_MANDATORY_MEMB | RHBZ_READ_STR); bz->bi_reporter = rhbz_bug_read_item("creator", bug_item, RHBZ_MANDATORY_MEMB | RHBZ_READ_STR); bz->bi_status = rhbz_bug_read_item("status", bug_item, RHBZ_MANDATORY_MEMB | RHBZ_READ_STR); bz->bi_resolution = rhbz_bug_read_item("resolution", bug_item, RHBZ_READ_STR); bz->bi_platform = rhbz_bug_read_item("platform", bug_item, RHBZ_READ_STR); if (strcmp(bz->bi_status, "CLOSED") == 0 && !bz->bi_resolution) error_msg_and_die(_("Bug %i is CLOSED, but it has no RESOLUTION"), bz->bi_id); ret = (int*)rhbz_bug_read_item("dupe_of", bug_item, RHBZ_READ_INT); if (strcmp(bz->bi_status, "CLOSED") == 0 && strcmp(bz->bi_resolution, "DUPLICATE") == 0 && !ret) { error_msg_and_die(_("Bug %i is CLOSED as DUPLICATE, but it has no DUP_ID"), bz->bi_id); } bz->bi_dup_id = (ret) ? *ret: -1; free(ret); bz->bi_cc_list = rhbz_bug_cc(bug_item); bz->bi_comments = rhbz_comments(ax, bug_id); bz->bi_best_bt_rating = find_best_bt_rating_in_comments(bz->bi_comments); xmlrpc_DECREF(bugs_memb); xmlrpc_DECREF(bug_item); xmlrpc_DECREF(xml_bug_response); return bz; }
/* * c_entries -- * read .c and .h files and call appropriate routines */ void c_entries(void) { int c; /* current character */ int level; /* brace level */ int token; /* if reading a token */ int t_def; /* if reading a typedef */ int t_level; /* typedef's brace level */ char *sp; /* buffer pointer */ char tok[MAXTOKEN]; /* token buffer */ lineftell = ftell(inf); sp = tok; token = t_def = NO; t_level = -1; level = 0; lineno = 1; while (GETC(!=, EOF)) { switch (c) { /* * Here's where it DOESN'T handle: { * foo(a) * { * #ifdef notdef * } * #endif * if (a) * puts("hello, world"); * } */ case '{': ++level; goto endtok; case '}': /* * if level goes below zero, try and fix * it, even though we've already messed up */ if (--level < 0) level = 0; goto endtok; case '\n': SETLINE; /* * the above 3 cases are similar in that they * are special characters that also end tokens. */ endtok: if (sp > tok) { *sp = EOS; token = YES; sp = tok; } else token = NO; continue; /* * We ignore quoted strings and character constants * completely. */ case '"': case '\'': skip_string(c); break; /* * comments can be fun; note the state is unchanged after * return, in case we found: * "foo() XX comment XX { int bar; }" */ case '/': if (GETC(==, '*') || c == '/') { skip_comment(c); continue; } (void)ungetc(c, inf); c = '/'; goto storec; /* hash marks flag #define's. */ case '#': if (sp == tok) { hash_entry(); break; } goto storec; /* * if we have a current token, parenthesis on * level zero indicates a function. */ case '(': if (!level && token) { int curline; if (sp != tok) *sp = EOS; /* * grab the line immediately, we may * already be wrong, for example, * foo\n * (arg1, */ getline(); curline = lineno; if (func_entry()) { ++level; pfnote(tok, curline); } break; } goto storec; /* * semi-colons indicate the end of a typedef; if we find a * typedef we search for the next semi-colon of the same * level as the typedef. Ignoring "structs", they are * tricky, since you can find: * * "typedef long time_t;" * "typedef unsigned int u_int;" * "typedef unsigned int u_int [10];" * * If looking at a typedef, we save a copy of the last token * found. Then, when we find the ';' we take the current * token if it starts with a valid token name, else we take * the one we saved. There's probably some reasonable * alternative to this... */ case ';': if (t_def && level == t_level) { t_def = NO; getline(); if (sp != tok) *sp = EOS; pfnote(tok, lineno); break; } goto storec; /* * store characters until one that can't be part of a token * comes along; check the current token against certain * reserved words. */ default: /* ignore whitespace */ if (c == ' ' || c == '\t') { int save = c; while (GETC(!=, EOF) && (c == ' ' || c == '\t')) ; if (c == EOF) return; (void)ungetc(c, inf); c = save; } storec: if (!intoken(c)) { if (sp == tok) break; *sp = EOS; if (tflag) { /* no typedefs inside typedefs */ if (!t_def && !memcmp(tok, "typedef",8)) { t_def = YES; t_level = level; break; } /* catch "typedef struct" */ if ((!t_def || t_level < level) && (!memcmp(tok, "struct", 7) || !memcmp(tok, "union", 6) || !memcmp(tok, "enum", 5))) { /* * get line immediately; * may change before '{' */ getline(); if (str_entry(c)) ++level; break; /* } */ } } sp = tok; } else if (sp != tok || begtoken(c)) { if (sp == tok + sizeof tok - 1) /* Too long -- truncate it */ *sp = EOS; else *sp++ = c; token = YES; } continue; } sp = tok; token = NO; }