/** * 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); }
/** * Is the X-Alt header really holding a collection of IP:port (with possible * push alt-locs containing a prefixing GUID) or is it mistakenly called * X-Alt but is really an old X-Gnutella-Alternate-Location containing a * list of HTTP URLs. */ static bool huge_is_pure_xalt(const char *value, size_t len) { host_addr_t addr; /* * This is pure heuristics, knowing that if we return TRUE, we'll parse * the X-Alt header in the format that is emitted by the majority of * vendors. * * We try to avoid the more costly pattern_qsearch() call if we can, * and our heuristic should catch 99% of the cases. And pattern_qsearch() * should quickly return true if the X-Alt is not a collection of IP:port. */ if (is_strcaseprefix(value, "tls=")) return TRUE; if (string_to_host_addr(value, NULL, &addr)) return TRUE; if (pattern_qsearch(has_http_urls, value, len, 0, qs_any)) return FALSE; return TRUE; }
/** * Extract the TTH out of a "urn:tree:tiger" URN. * Note that the TTH is expected to be solely base32-encoded here. * * @return whether TTH was successfully extracted. */ bool urn_get_tth(const char *buf, size_t size, struct tth *tth) { static const char prefix[] = "urn:tree:tiger"; size_t len; const char *p; g_assert(0 == size || NULL != buf); g_assert(tth); if (size < CONST_STRLEN(prefix) + 1 /* ":" */ + TTH_BASE32_SIZE) { return FALSE; } p = is_strcaseprefix(buf, prefix); if (NULL == p) { return FALSE; } if ('/' == *p) { /* RAZA puts a slash after "tiger" */ if (size < CONST_STRLEN(prefix) + 2 /* "/:" */ + TTH_BASE32_SIZE){ return FALSE; } p++; } if (':' != *p++) { return FALSE; } len = base32_decode(tth->data, TTH_RAW_SIZE, p, TTH_BASE32_SIZE); if (len != TTH_RAW_SIZE) { return FALSE; } return TRUE; }
struct magnet_source * magnet_parse_exact_source(const char *uri, const char **error_str) { clear_error_str(&error_str); g_return_val_if_fail(uri, NULL); /* TODO: This should be handled elsewhere e.g., downloads.c in * a generic way. */ if (is_strcaseprefix(uri, "http://")) { return magnet_parse_http_source(uri, error_str); } else if (is_strcaseprefix(uri, "push://")) { return magnet_parse_push_source(uri, error_str); } else { *error_str = _("MAGNET URI contained source URL for an unsupported protocol"); /* Skip this parameter */ return NULL; } }
static struct magnet_source * magnet_parse_http_source(const char *uri, const char **error_str) { const char *p; clear_error_str(&error_str); g_return_val_if_fail(uri, NULL); p = is_strcaseprefix(uri, "http://"); g_return_val_if_fail(p, NULL); return magnet_parse_location(p, error_str); }
/** * 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; }
static enum shell_reply shell_exec_download_add(struct gnutella_shell *sh, int argc, const char *argv[]) { const char *url; gboolean success; shell_check(sh); g_assert(argv); g_assert(argc > 0); if (argc < 3) { shell_set_msg(sh, _("URL missing")); goto error; } url = argv[2]; if (is_strcaseprefix(url, "http://")) { success = download_handle_http(url); } else if (is_strcaseprefix(url, "magnet:?")) { unsigned n_downloads, n_searches; n_downloads = download_handle_magnet(url); n_searches = search_handle_magnet(url); success = n_downloads > 0 || n_searches > 0; } else { success = FALSE; } if (!success) { shell_set_msg(sh, _("The download could not be created")); goto error; } shell_set_msg(sh, _("Download added")); return REPLY_READY; error: return REPLY_ERROR; }
static bool filename_is_reserved(const char *filename) { const char *endptr; if ('\0' == filename[0]) return TRUE; /** * FIXME: Doesn't this apply to CYGWIN, too? */ if (!is_running_on_mingw()) return FALSE; /** * The following may be a superset because PRN1 is (probably) not reserved. */ if (!( (endptr = is_strcaseprefix(filename, "aux")) || (endptr = is_strcaseprefix(filename, "com")) || (endptr = is_strcaseprefix(filename, "con")) || (endptr = is_strcaseprefix(filename, "lpt")) || (endptr = is_strcaseprefix(filename, "nul")) || (endptr = is_strcaseprefix(filename, "prn")) )) return FALSE; switch (*endptr) { case '\0': return TRUE; case '.': /* con.txt is reserved con.blah.txt isn't */ return NULL == strchr(&endptr[1], '.'); case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* lpt0, com0 are not reserved */ endptr++; switch (*endptr) { case '\0': return TRUE; case '.': /* com1.txt is reserved com1.blah.txt isn't */ return NULL == strchr(&endptr[1], '.'); } break; } /* com1blah.txt is not reserved */ return FALSE; }
/** * Try to connect to the list of nodes given by in following form: * * list = <node> | <node>, 1*<node> * port = 1..65535 * hostname = 1*[a-zA-Z0-9.-] * node = hostname [":" <port>] * | <IPv4 address>[":" <port>] * | <IPv6 address> * | "[" <IPv6 address> "]:" <port> * peer = ["tls:"]["g2:"]<node> * * If the port is omitted, the default port (GTA_PORT: 6346) is used. * The case-insensitive prefix "tls:" requests a TLS (encrypted) connection. */ void nodes_gui_common_connect_by_name(const gchar *line) { const gchar *q; g_assert(line); q = line; while ('\0' != *q) { const gchar *endptr, *hostname; size_t hostname_len; host_addr_t addr; guint32 flags; guint16 port; bool g2; q = skip_ascii_spaces(q); if (',' == *q) { q++; continue; } addr = zero_host_addr; port = GTA_PORT; flags = SOCK_F_FORCE; endptr = NULL; hostname = NULL; hostname_len = 0; endptr = is_strcaseprefix(q, "tls:"); if (endptr) { flags |= SOCK_F_TLS; q = endptr; } endptr = is_strcaseprefix(q, "g2:"); if (endptr) { g2 = TRUE; q = endptr; } else { g2 = FALSE; } if (!string_to_host_or_addr(q, &endptr, &addr)) { g_message("expected hostname or IP address"); break; } if (!is_host_addr(addr)) { hostname = q; hostname_len = endptr - q; } q = endptr; if (':' == *q) { gint error; port = parse_uint16(&q[1], &endptr, 10, &error); if (error || 0 == port) { g_message("cannot parse port"); break; } q = skip_ascii_spaces(endptr); } else { q = skip_ascii_spaces(endptr); if ('\0' != *q && ',' != *q) { g_message("expected \",\" or \":\""); break; } } if (!hostname) { if (g2) { guc_node_g2_add(addr, port, flags); } else { guc_node_add(addr, port, flags); } } else { struct add_node_context *ctx; gchar *p; if ('\0' == hostname[hostname_len]) { p = NULL; } else { size_t n = 1 + hostname_len; g_assert(n > hostname_len); p = halloc(n); g_strlcpy(p, hostname, n); hostname = p; } WALLOC(ctx); ctx->port = port; ctx->flags = flags; ctx->g2 = g2; guc_adns_resolve(hostname, add_node_helper, ctx); HFREE_NULL(p); } } }
struct magnet_resource * magnet_parse(const char *url, const char **error_str) { static const struct magnet_resource zero_resource; struct magnet_resource res; const char *p, *next; res = zero_resource; clear_error_str(&error_str); p = is_strcaseprefix(url, "magnet:"); if (!p) { *error_str = "Not a MAGNET URI"; return NULL; } if ('?' != p[0]) { *error_str = "Invalid MAGNET URI"; return NULL; } p++; for (/* NOTHING */; p && '\0' != p[0]; p = next) { enum magnet_key key; const char *endptr; char name[16]; /* Large enough to hold longest key we know */ name[0] = '\0'; endptr = strchr(p, '='); if (endptr && p != endptr) { size_t name_len; name_len = endptr - p; g_assert(size_is_positive(name_len)); if (name_len < sizeof name) { /* Ignore overlong key */ strncat(name, p, name_len); } p = &endptr[1]; /* Point behind the '=' */ } endptr = strchr(p, '&'); if (!endptr) { endptr = strchr(p, '\0'); } key = magnet_key_get(name); if (MAGNET_KEY_NONE == key) { g_message("skipping unknown key \"%s\" in MAGNET URI", name); } else { char *value; size_t value_len; value_len = endptr - p; value = h_strndup(p, value_len); plus_to_space(value); if (url_unescape(value, TRUE)) { magnet_handle_key(&res, name, value); } else { g_message("badly encoded value in MAGNET URI: \"%s\"", value); } HFREE_NULL(value); } while ('&' == endptr[0]) { endptr++; } next = endptr; } res.sources = g_slist_reverse(res.sources); res.searches = g_slist_reverse(res.searches); return wcopy(&res, sizeof res); }