/** * This is the same as urn_get_sha1(), only the leading "urn:" part * is missing (typically a URN embedded in a GGEP "u"). * * `buf' MUST start with "sha1:" or "bitprint:" indications. Since the * leading "urn:" part is missing, we cannot be lenient. * * Extract the SHA1 out of it, placing it in the supplied `digest' buffer. * * @return whether we successfully extracted the SHA1. */ bool urn_get_sha1_no_prefix(const char *buf, struct sha1 *sha1) { const char *p; size_t len; /* * We handle both "sha1:" and "bitprint:". In the latter case, * the first 32 bytes of the bitprint is the SHA1. */ if ( NULL == (p = is_strcaseprefix(buf, "sha1:")) && NULL == (p = is_strcaseprefix(buf, "bitprint:")) ) return FALSE; len = clamp_strlen(p, SHA1_BASE32_SIZE); if (parse_base32_sha1(p, len, sha1)) return TRUE; /* * Maybe it was generated by clueless people who use an hexadecimal * representation? */ len = clamp_strlen(p, SHA1_BASE16_SIZE); return parse_base16_sha1(p, len, sha1); }
/** * Locate the start of "urn:bitprint:" indications and extract * the SHA1 and TTH out of it, placing them in the supplied buffers. * * @return whether we successfully extracted the bitprint, i.e. the two * hashes. */ bool urn_get_bitprint(const char *buf, size_t size, struct sha1 *sha1, struct tth *tth) { static const char prefix[] = "urn:bitprint:"; size_t len; const char *p; bool base16_tth = FALSE; g_assert(0 == size || NULL != buf); g_assert(sha1); g_assert(tth); /* * Because some clueless sites list magnets with hexadecimal-encoded * values, we attempt to parse both base32 and base16 encoded hashes. * * Note that we expect both hashes to be similarily encoded. */ if (size < CONST_STRLEN(prefix) + BITPRINT_BASE32_SIZE) return FALSE; p = is_strcaseprefix(buf, prefix); if (NULL == p) return FALSE; if (!parse_base32_sha1(p, SHA1_BASE32_SIZE, sha1)) { if ( size >= CONST_STRLEN(prefix) + BITPRINT_BASE16_SIZE && parse_base16_sha1(p, SHA1_BASE16_SIZE, sha1) ) { p += SHA1_BASE16_SIZE; base16_tth = TRUE; /* SHA1 was hexa, expects TTH as hexa */ } else { return FALSE; } } else { p += SHA1_BASE32_SIZE; } if ('.' != *p++) { return FALSE; } if (base16_tth) { len = base16_decode(tth, sizeof *tth, p, TTH_BASE16_SIZE); } else { len = base32_decode(tth, sizeof *tth, p, TTH_BASE32_SIZE); } if (len != TTH_RAW_SIZE) { return FALSE; } return TRUE; }
G_GNUC_COLD void upload_stats_load_history(void) { FILE *upload_stats_file; file_path_t fp; char line[FILENAME_MAX + 64]; guint lineno = 0; gcu_upload_stats_gui_freeze(); file_path_set(&fp, settings_config_dir(), ul_stats_file); /* open file for reading */ upload_stats_file = file_config_open_read(ul_stats_what, &fp, 1); if (upload_stats_file == NULL) goto done; /* parse, insert names into ul_stats_clist */ while (fgets(line, sizeof(line), upload_stats_file)) { static const struct ul_stats zero_item; struct ul_stats item; struct sha1 sha1_buf; const char *p; size_t i; lineno++; if (line[0] == '#' || line[0] == '\n') continue; p = strchr(line, '\t'); if (NULL == p) goto corrupted; line[p - line] = '\0'; /* line is now the URL-escaped file name */ p++; /* URL-unescape in-place */ if (!url_unescape(line, TRUE)) goto corrupted; item = zero_item; item.pathname = line; for (i = 0; i < 8; i++) { guint64 v; int error; const char *endptr; p = skip_ascii_spaces(p); /* SVN versions up to 15322 had only 6 fields in the history */ if (5 == i && '\0' == *p) break; switch (i) { case 7: /* We have a SHA1 or '*' if none known */ if ('*' != *p) { size_t len = clamp_strlen(p, SHA1_BASE32_SIZE); error = !parse_base32_sha1(p, len, &sha1_buf); item.sha1 = error ? NULL : &sha1_buf; } else { error = FALSE; } p = skip_ascii_non_spaces(p); v = 0; break; default: v = parse_uint64(p, &endptr, 10, &error); p = deconstify_gchar(endptr); } if (error || !is_ascii_space(*endptr)) goto corrupted; switch (i) { case 0: item.size = v; break; case 1: item.attempts = v; break; case 2: item.complete = v; break; case 3: item.bytes_sent |= ((guint64) (guint32) v) << 32; break; case 4: item.bytes_sent |= (guint32) v; break; case 5: item.rtime = MIN(v + (time_t) 0, TIME_T_MAX + (guint64) 0); case 6: item.dtime = MIN(v + (time_t) 0, TIME_T_MAX + (guint64) 0); case 7: break; /* Already stored above */ default: g_assert_not_reached(); goto corrupted; } } /* * We store the filenames UTF-8 encoded but the file might have been * edited or corrupted. */ if (is_absolute_path(item.pathname)) { item.filename = lazy_filename_to_utf8_normalized( filepath_basename(item.pathname), UNI_NORM_NFC); } else { item.filename = lazy_unknown_to_utf8_normalized( filepath_basename(item.pathname), UNI_NORM_NFC, NULL); } if (upload_stats_find(NULL, item.pathname, item.size)) { g_warning("upload_stats_load_history():" " Ignoring line %u due to duplicate file.", lineno); } else if (upload_stats_find(item.sha1, item.pathname, item.size)) { g_warning("upload_stats_load_history():" " Ignoring line %u due to duplicate file.", lineno); } else { upload_stats_add(item.pathname, item.size, item.filename, item.attempts, item.complete, item.bytes_sent, item.rtime, item.dtime, item.sha1); } continue; corrupted: g_warning("upload statistics file corrupted at line %u.", lineno); } /* close file */ fclose(upload_stats_file); done: gcu_upload_stats_gui_thaw(); return; }