/** * Parse gtk-gnutella's version number in User-Agent/Server string `str' * and extract timestamp into `ver'. */ static void version_stamp(const char *str, version_t *ver) { static char stamp[256]; const char *p; ver->timestamp = 0; /* * A typical vendor string with a timestamp would look like: * * gtk-gnutella/0.85 (04/04/2002; X11; FreeBSD 4.6-STABLE i386) * * The date stamp is formattted as DD/MM/YYYY here, but the date2time() * routine is also able to parse the ISO format YYYY-MM-DD which is * being used starting 2004-03-02. */ p = strchr(str, '('); if (p) { const char *end; p++; end = strchr(p, ';'); if (end == NULL) end = strchr(p, ')'); /* Only date present: short version */ if (end) { size_t size = end - p + 1; /* * Using date2time() will allow us to possibly change the date * format in the future, without impacting the ability of older * servents to parse it. */ g_strlcpy(stamp, p, MIN(size, sizeof(stamp))); ver->timestamp = date2time(stamp, tm_time()); if (ver->timestamp == -1) { ver->timestamp = 0; g_warning("could not parse timestamp \"%s\" in \"%s\"", p, str); } } else g_warning("no timestamp in \"%s\"", str); } }
/** * Load spam database from the supplied FILE. * * The current file format is as follows: * * # Comment * SHA1 <SHA-1> * ADDED <date> * END * * @returns the amount of entries loaded or -1 on failure. */ static G_GNUC_COLD gulong spam_load(FILE *f) { static const struct spam_item zero_item; struct spam_item item; char line[1024]; guint line_no = 0; bit_array_t tag_used[BIT_ARRAY_SIZE(NUM_SPAM_TAGS)]; gulong item_count = 0; g_assert(f); /* Reset state */ item = zero_item; bit_array_init(tag_used, NUM_SPAM_TAGS); while (fgets(line, sizeof line, f)) { const char *tag_name, *value; char *sp, *nl; spam_tag_t tag; line_no++; nl = strchr(line, '\n'); if (!nl) { /* * If the line is too long or unterminated the file is either * corrupt or was manually edited without respecting the * exact format. If we continued, we would read from the * middle of a line which could be the filename or ID. */ g_warning("spam_load(): " "line too long or missing newline in line %u", line_no); break; } *nl = '\0'; /* Skip comments and empty lines */ if (*line == '#' || *line == '\0') continue; sp = strchr(line, ' '); if (sp) { *sp = '\0'; value = &sp[1]; } else { value = strchr(line, '\0'); } tag_name = line; tag = spam_string_to_tag(tag_name); g_assert(UNSIGNED(tag) < UNSIGNED(NUM_SPAM_TAGS)); if (SPAM_TAG_UNKNOWN != tag && !bit_array_flip(tag_used, tag)) { g_warning("spam_load(): duplicate tag \"%s\" in entry in line %u", tag_name, line_no); continue; } switch (tag) { case SPAM_TAG_ADDED: { time_t t; t = date2time(value, tm_time()); if ((time_t) -1 == t) { item.damaged = TRUE; } } break; case SPAM_TAG_SHA1: { if (strlen(value) != SHA1_BASE32_SIZE) { item.damaged = TRUE; g_warning("spam_load(): SHA-1 has wrong length."); } else { const struct sha1 *raw; raw = base32_sha1(value); if (raw) item.sha1 = *raw; else item.damaged = TRUE; } } break; case SPAM_TAG_NAME: { if ('\0' == value[0]) { item.damaged = TRUE; g_warning("spam_load(): Missing filename pattern."); } else if (!utf8_is_valid_string(value)) { item.damaged = TRUE; g_warning("spam_load(): Filename pattern is not UTF-8."); } else { item.name = h_strdup(value); } } break; case SPAM_TAG_SIZE: { const char *endptr; guint64 u; int error; u = parse_uint64(value, &endptr, 10, &error); if (error) { item.damaged = TRUE; g_warning("spam_load(): Cannot parse SIZE: %s", value); } else { item.min_size = u; item.max_size = u; if ('-' == endptr[0]) { u = parse_uint64(&endptr[1], &endptr, 10, &error); if (error) { item.damaged = TRUE; g_warning("spam_load(): Cannot parse SIZE: %s", value); } if (u < item.min_size) { item.damaged = TRUE; g_warning("spam_load(): " "Maximum size below minimum size"); } else { item.max_size = u; } } } } break; case SPAM_TAG_END: if ( !bit_array_get(tag_used, SPAM_TAG_SHA1) && !bit_array_get(tag_used, SPAM_TAG_NAME) ) { g_warning("spam_load(): missing SHA1 or NAME tag"); item.damaged = TRUE; } if (!bit_array_get(tag_used, SPAM_TAG_ADDED)) { g_warning("spam_load(): missing ADDED tag"); item.damaged = TRUE; } item.done = TRUE; break; case SPAM_TAG_UNKNOWN: /* Ignore */ break; case NUM_SPAM_TAGS: g_assert_not_reached(); break; } if (item.done && !item.damaged) { if (bit_array_get(tag_used, SPAM_TAG_SHA1)) { spam_sha1_add(&item.sha1); item_count++; } if (bit_array_get(tag_used, SPAM_TAG_NAME)) { if (!bit_array_get(tag_used, SPAM_TAG_SIZE)) { item.min_size = 0; item.max_size = MAX_INT_VAL(filesize_t); } if ( spam_add_name_and_size(item.name, item.min_size, item.max_size) ) { item.damaged = TRUE; } else { item_count++; } } } if (item.damaged) { g_warning("Damaged spam entry in line %u: " "tag_name=\"%s\", value=\"%s\"", line_no, tag_name, value); } if (item.done) { /* Reset state */ HFREE_NULL(item.name); item = zero_item; bit_array_clear_range(tag_used, 0, NUM_SPAM_TAGS - 1U); } } spam_sha1_sync(); return item_count; }