X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=src%2Ffs%2Ffs_uri.c;h=48fabc1fbf24a73b87a02741f443654b6518a034;hb=83b19539f4d322b43683f5838b72e9ec2c8e6073;hp=863ab475d57d4bcc17a96afc134a87855bac3047;hpb=b80e650bad570e01b5600aab2a667d177fc17770;p=oweals%2Fgnunet.git diff --git a/src/fs/fs_uri.c b/src/fs/fs_uri.c index 863ab475d..48fabc1fb 100644 --- a/src/fs/fs_uri.c +++ b/src/fs/fs_uri.c @@ -4,7 +4,7 @@ GNUnet is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published - by the Free Software Foundation; either version 2, or (at your + by the Free Software Foundation; either version 3, or (at your option) any later version. GNUnet is distributed in the hope that it will be useful, but @@ -26,10 +26,10 @@ * GNUnet URIs are of the general form "gnunet://MODULE/IDENTIFIER". * The specific structure of "IDENTIFIER" depends on the module and * maybe differenciated into additional subcategories if applicable. - * This module only deals with ecrs identifiers (MODULE = "ecrs"). + * This module only deals with fs identifiers (MODULE = "fs"). *
* - * This module only parses URIs for the AFS module. The ECRS URIs fall + * This module only parses URIs for the AFS module. The FS URIs fall * into four categories, "chk", "sks", "ksk" and "loc". The first three * categories were named in analogy (!) to Freenet, but they do NOT * work in exactly the same way. They are very similar from the user's @@ -40,7 +40,7 @@ *
*/ #include "platform.h" -#include "gnunet_fs_lib.h" +#include "gnunet_fs_service.h" +#include "gnunet_signatures.h" #include "fs.h" @@ -90,55 +91,561 @@ * @param uri uri to convert to a unique key * @param key wherer to store the unique key */ -void -GNUNET_FS_uri_to_key (const struct GNUNET_FS_Uri *uri, - GNUNET_HashCode * key) +void +GNUNET_FS_uri_to_key (const struct GNUNET_FS_Uri *uri, GNUNET_HashCode * key) { switch (uri->type) + { + case chk: + *key = uri->data.chk.chk.query; + return; + case sks: + GNUNET_CRYPTO_hash (uri->data.sks.identifier, + strlen (uri->data.sks.identifier), key); + break; + case ksk: + if (uri->data.ksk.keywordCount > 0) + GNUNET_CRYPTO_hash (uri->data.ksk.keywords[0], + strlen (uri->data.ksk.keywords[0]), key); + break; + case loc: + GNUNET_CRYPTO_hash (&uri->data.loc.fi, + sizeof (struct FileIdentifier) + + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + key); + break; + default: + memset (key, 0, sizeof (GNUNET_HashCode)); + break; + } +} + + +/** + * Convert keyword URI to a human readable format + * (i.e. the search query that was used in the first place) + * + * @param uri ksk uri to convert to a string + * @return string with the keywords + */ +char * +GNUNET_FS_uri_ksk_to_string_fancy (const struct GNUNET_FS_Uri *uri) +{ + size_t n; + char *ret; + unsigned int i; + const char *keyword; + char **keywords; + unsigned int keywordCount; + + if ((uri == NULL) || (uri->type != ksk)) + { + GNUNET_break (0); + return NULL; + } + keywords = uri->data.ksk.keywords; + keywordCount = uri->data.ksk.keywordCount; + n = keywordCount + 1; + for (i = 0; i < keywordCount; i++) + { + keyword = keywords[i]; + n += strlen (keyword) - 1; + if (NULL != strstr (&keyword[1], " ")) + n += 2; + if (keyword[0] == '+') + n++; + } + ret = GNUNET_malloc (n); + strcpy (ret, ""); + for (i = 0; i < keywordCount; i++) + { + keyword = keywords[i]; + if (NULL != strstr (&keyword[1], " ")) { - case chk: - *key = uri->data.fi.chk.query; - return; - case sks: - GNUNET_hash (uri->data.sks.identifier, - strlen (uri->data.sks.identifier), key); - break; - case ksk: - if (uri->data.ksk.keywordCount > 0) - GNUNET_hash (uri->data.ksk.keywords[0], - strlen (uri->data.ksk.keywords[0]), key); - break; - case loc: - GNUNET_hash (&uri->data.loc.fi, - sizeof (GNUNET_EC_FileIdentifier) + - sizeof (GNUNET_RSA_PublicKey), key); - break; - default: - memset (key, 0, sizeof (GNUNET_HashCode)); - break; + strcat (ret, "\""); + if (keyword[0] == '+') + strcat (ret, keyword); + else + strcat (ret, &keyword[1]); + strcat (ret, "\""); + } + else + { + if (keyword[0] == '+') + strcat (ret, keyword); + else + strcat (ret, &keyword[1]); } + strcat (ret, " "); + } + return ret; } /** - * Convert a URI to a UTF-8 String. + * Given a keyword with %-encoding (and possibly quotes to protect + * spaces), return a copy of the keyword without %-encoding and + * without double-quotes (%22). Also, add a space at the beginning + * if there is not a '+'. * - * @param uri uri to convert to a string - * @return the UTF-8 string + * @param in string with %-encoding + * @param emsg where to store the parser error message (if any) + * @return decodded string with leading space (or preserved plus) */ -char * -GNUNET_FS_uri_to_string (const struct GNUNET_FS_Uri *uri); +static char * +percent_decode_keyword (const char *in, char **emsg) +{ + char *out; + char *ret; + unsigned int rpos; + unsigned int wpos; + unsigned int hx; + + out = GNUNET_strdup (in); + rpos = 0; + wpos = 0; + while (out[rpos] != '\0') + { + if (out[rpos] == '%') + { + if (1 != sscanf (&out[rpos + 1], "%2X", &hx)) + { + GNUNET_free (out); + *emsg = GNUNET_strdup (_("`%' must be followed by HEX number")); + return NULL; + } + rpos += 3; + if (hx == '"') + continue; /* skip double quote */ + out[wpos++] = (char) hx; + } + else + { + out[wpos++] = out[rpos++]; + } + } + out[wpos] = '\0'; + if (out[0] == '+') + { + ret = GNUNET_strdup (out); + } + else + { + /* need to prefix with space */ + ret = GNUNET_malloc (strlen (out) + 2); + strcpy (ret, " "); + strcat (ret, out); + } + GNUNET_free (out); + return ret; +} +#define GNUNET_FS_URI_KSK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_KSK_INFIX /** - * Convert keyword URI to a human readable format - * (i.e. the search query that was used in the first place) + * Parse a KSK URI. * - * @param uri ksk uri to convert to a string - * @return string with the keywords + * @param s an uri string + * @param emsg where to store the parser error message (if any) + * @return NULL on error, otherwise the KSK URI */ -char * -GNUNET_FS_uri_ksk_to_string_fancy (const struct GNUNET_FS_Uri *uri); +static struct GNUNET_FS_Uri * +uri_ksk_parse (const char *s, char **emsg) +{ + struct GNUNET_FS_Uri *ret; + char **keywords; + unsigned int pos; + int max; + int iret; + int i; + size_t slen; + char *dup; + int saw_quote; + + GNUNET_assert (s != NULL); + slen = strlen (s); + pos = strlen (GNUNET_FS_URI_KSK_PREFIX); + if ((slen <= pos) || (0 != strncmp (s, GNUNET_FS_URI_KSK_PREFIX, pos))) + return NULL; /* not KSK URI */ + if ((s[slen - 1] == '+') || (s[pos] == '+')) + { + *emsg = + GNUNET_strdup (_("Malformed KSK URI (must not begin or end with `+')")); + return NULL; + } + max = 1; + saw_quote = 0; + for (i = pos; i < slen; i++) + { + if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22"))) + { + saw_quote = (saw_quote + 1) % 2; + i += 3; + continue; + } + if ((s[i] == '+') && (saw_quote == 0)) + { + max++; + if (s[i - 1] == '+') + { + *emsg = GNUNET_strdup (_("`++' not allowed in KSK URI")); + return NULL; + } + } + } + if (saw_quote == 1) + { + *emsg = GNUNET_strdup (_("Quotes not balanced in KSK URI")); + return NULL; + } + iret = max; + dup = GNUNET_strdup (s); + keywords = GNUNET_malloc (max * sizeof (char *)); + for (i = slen - 1; i >= pos; i--) + { + if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22"))) + { + saw_quote = (saw_quote + 1) % 2; + i += 3; + continue; + } + if ((dup[i] == '+') && (saw_quote == 0)) + { + keywords[--max] = percent_decode_keyword (&dup[i + 1], emsg); + if (NULL == keywords[max]) + goto CLEANUP; + dup[i] = '\0'; + } + } + keywords[--max] = percent_decode_keyword (&dup[pos], emsg); + if (NULL == keywords[max]) + goto CLEANUP; + GNUNET_assert (max == 0); + GNUNET_free (dup); + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ret->type = ksk; + ret->data.ksk.keywordCount = iret; + ret->data.ksk.keywords = keywords; + return ret; +CLEANUP: + for (i = 0; i < max; i++) + GNUNET_free_non_null (keywords[i]); + GNUNET_free (keywords); + GNUNET_free (dup); + return NULL; +} + + +#define GNUNET_FS_URI_SKS_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_SKS_INFIX + +/** + * Parse an SKS URI. + * + * @param s an uri string + * @param emsg where to store the parser error message (if any) + * @return NULL on error, SKS URI otherwise + */ +static struct GNUNET_FS_Uri * +uri_sks_parse (const char *s, char **emsg) +{ + struct GNUNET_FS_Uri *ret; + GNUNET_HashCode namespace; + char *identifier; + unsigned int pos; + size_t slen; + char enc[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; + + GNUNET_assert (s != NULL); + slen = strlen (s); + pos = strlen (GNUNET_FS_URI_SKS_PREFIX); + if ((slen <= pos) || (0 != strncmp (s, GNUNET_FS_URI_SKS_PREFIX, pos))) + return NULL; /* not an SKS URI */ + if ((slen < pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) || + (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '/')) + { + *emsg = GNUNET_strdup (_("Malformed SKS URI")); + return NULL; + } + memcpy (enc, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); + enc[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; + if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (enc, &namespace)) + { + *emsg = GNUNET_strdup (_("Malformed SKS URI")); + return NULL; + } + identifier = + GNUNET_strdup (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]); + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ret->type = sks; + ret->data.sks.namespace = namespace; + ret->data.sks.identifier = identifier; + return ret; +} + +#define GNUNET_FS_URI_CHK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX + + +/** + * Parse a CHK URI. + * + * @param s an uri string + * @param emsg where to store the parser error message (if any) + * @return NULL on error, CHK URI otherwise + */ +static struct GNUNET_FS_Uri * +uri_chk_parse (const char *s, char **emsg) +{ + struct GNUNET_FS_Uri *ret; + struct FileIdentifier fi; + unsigned int pos; + unsigned long long flen; + size_t slen; + char h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; + char h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; + + if (NULL == s) + return NULL; + GNUNET_assert (s != NULL); + slen = strlen (s); + pos = strlen (GNUNET_FS_URI_CHK_PREFIX); + if ((slen < pos + 2 * sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) || + (0 != strncmp (s, GNUNET_FS_URI_CHK_PREFIX, pos))) + return NULL; /* not a CHK URI */ + if ((s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') || + (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.')) + { + *emsg = GNUNET_strdup (_("Malformed CHK URI")); + return NULL; + } + memcpy (h1, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); + h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; + memcpy (h2, &s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)], + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); + h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; + + if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h1, &fi.chk.key)) || + (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h2, &fi.chk.query)) || + (1 != + SSCANF (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2], + "%llu", &flen))) + { + *emsg = GNUNET_strdup (_("Malformed CHK URI")); + return NULL; + } + fi.file_length = GNUNET_htonll (flen); + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ret->type = chk; + ret->data.chk = fi; + return ret; +} + + +/** + * Convert a character back to the binary value + * that it represents (given base64-encoding). + * + * @param a character to convert + * @return offset in the "tbl" array + */ +static unsigned int +c2v (unsigned char a) +{ + if ((a >= '0') && (a <= '9')) + return a - '0'; + if ((a >= 'A') && (a <= 'Z')) + return (a - 'A' + 10); + if ((a >= 'a') && (a <= 'z')) + return (a - 'a' + 36); + if (a == '_') + return 62; + if (a == '=') + return 63; + return -1; +} + + +/** + * Convert string back to binary data. + * + * @param input '\\0'-terminated string + * @param data where to write binary data + * @param size how much data should be converted + * @return number of characters processed from input, + * -1 on error + */ +static int +enc2bin (const char *input, void *data, size_t size) +{ + size_t len; + size_t pos; + unsigned int bits; + unsigned int hbits; + + len = size * 8 / 6; + if (((size * 8) % 6) != 0) + len++; + if (strlen (input) < len) + return -1; /* error! */ + bits = 0; + hbits = 0; + len = 0; + for (pos = 0; pos < size; pos++) + { + while (hbits < 8) + { + bits |= (c2v (input[len++]) << hbits); + hbits += 6; + } + (((unsigned char *) data)[pos]) = (unsigned char) bits; + bits >>= 8; + hbits -= 8; + } + return len; +} + + +/** + * Structure that defines how the + * contents of a location URI must be + * assembled in memory to create or + * verify the signature of a location + * URI. + */ +struct LocUriAssembly +{ + struct GNUNET_CRYPTO_RsaSignaturePurpose purpose; + + struct GNUNET_TIME_AbsoluteNBO exptime; + + struct FileIdentifier fi; + + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded peer; + +}; + + +#define GNUNET_FS_URI_LOC_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_LOC_INFIX + +/** + * Parse a LOC URI. + * Also verifies validity of the location URI. + * + * @param s an uri string + * @param emsg where to store the parser error message (if any) + * @return NULL on error, valid LOC URI otherwise + */ +static struct GNUNET_FS_Uri * +uri_loc_parse (const char *s, char **emsg) +{ + struct GNUNET_FS_Uri *uri; + char h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; + char h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)]; + unsigned int pos; + unsigned int npos; + unsigned long long exptime; + unsigned long long flen; + struct GNUNET_TIME_Absolute et; + struct GNUNET_CRYPTO_RsaSignature sig; + struct LocUriAssembly ass; + int ret; + size_t slen; + + GNUNET_assert (s != NULL); + slen = strlen (s); + pos = strlen (GNUNET_FS_URI_LOC_PREFIX); + if ((slen < pos + 2 * sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) || + (0 != strncmp (s, GNUNET_FS_URI_LOC_PREFIX, pos))) + return NULL; /* not an SKS URI */ + if ((s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') || + (s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.')) + { + *emsg = GNUNET_strdup (_("SKS URI malformed")); + return NULL; + } + memcpy (h1, &s[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); + h1[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; + memcpy (h2, &s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)], + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)); + h2[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0'; + + if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h1, &ass.fi.chk.key)) || + (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h2, &ass.fi.chk.query)) || + (1 != + SSCANF (&s[pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2], + "%llu", &flen))) + { + *emsg = GNUNET_strdup (_("SKS URI malformed")); + return NULL; + } + ass.fi.file_length = GNUNET_htonll (flen); + + npos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) * 2; + while ((s[npos] != '\0') && (s[npos] != '.')) + npos++; + if (s[npos] == '\0') + { + *emsg = GNUNET_strdup (_("SKS URI malformed")); + goto ERR; + } + npos++; + ret = + enc2bin (&s[npos], &ass.peer, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + if (ret == -1) + { + *emsg = + GNUNET_strdup (_("SKS URI malformed (could not decode public key)")); + goto ERR; + } + npos += ret; + if (s[npos++] != '.') + { + *emsg = GNUNET_strdup (_("SKS URI malformed (could not find signature)")); + goto ERR; + } + ret = enc2bin (&s[npos], &sig, sizeof (struct GNUNET_CRYPTO_RsaSignature)); + if (ret == -1) + { + *emsg = GNUNET_strdup (_("SKS URI malformed (could not decode signature)")); + goto ERR; + } + npos += ret; + if (s[npos++] != '.') + { + *emsg = GNUNET_strdup (_("SKS URI malformed")); + goto ERR; + } + if (1 != SSCANF (&s[npos], "%llu", &exptime)) + { + *emsg = + GNUNET_strdup (_ + ("SKS URI malformed (could not parse expiration time)")); + goto ERR; + } + ass.purpose.size = htonl (sizeof (struct LocUriAssembly)); + ass.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT); + et.abs_value = exptime; + ass.exptime = GNUNET_TIME_absolute_hton (et); + if (GNUNET_OK != + GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT, + &ass.purpose, &sig, &ass.peer)) + { + *emsg = + GNUNET_strdup (_("SKS URI malformed (signature failed validation)")); + goto ERR; + } + uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + uri->type = loc; + uri->data.loc.fi = ass.fi; + uri->data.loc.peer = ass.peer; + uri->data.loc.expirationTime = et; + uri->data.loc.contentSignature = sig; + + return uri; +ERR: + return NULL; +} + /** * Convert a UTF-8 String to a URI. @@ -148,37 +655,54 @@ GNUNET_FS_uri_ksk_to_string_fancy (const struct GNUNET_FS_Uri *uri); * @return NULL on error */ struct GNUNET_FS_Uri * -GNUNET_FS_uri_parse (const char *uri, - char **emsg); +GNUNET_FS_uri_parse (const char *uri, char **emsg) +{ + struct GNUNET_FS_Uri *ret; + char *msg; + + if (NULL == emsg) + emsg = &msg; + *emsg = NULL; + if ((NULL != (ret = uri_chk_parse (uri, emsg))) || + (NULL != (ret = uri_ksk_parse (uri, emsg))) || + (NULL != (ret = uri_sks_parse (uri, emsg))) || + (NULL != (ret = uri_loc_parse (uri, emsg)))) + return ret; + if (NULL == *emsg) + *emsg = GNUNET_strdup (_("Unrecognized URI type")); + if (emsg == &msg) + GNUNET_free (msg); + return NULL; +} + /** * Free URI. * * @param uri uri to free */ -void +void GNUNET_FS_uri_destroy (struct GNUNET_FS_Uri *uri) { unsigned int i; GNUNET_assert (uri != NULL); switch (uri->type) - { - case ksk: - for (i = 0; i < uri->data.ksk.keywordCount; i++) - GNUNET_free (uri->data.ksk.keywords[i]); - GNUNET_array_grow (uri->data.ksk.keywords, uri->data.ksk.keywordCount, - 0); - break; - case sks: - GNUNET_free (uri->data.sks.identifier); - break; - case loc: - break; - default: - /* do nothing */ - break; - } + { + case ksk: + for (i = 0; i < uri->data.ksk.keywordCount; i++) + GNUNET_free (uri->data.ksk.keywords[i]); + GNUNET_array_grow (uri->data.ksk.keywords, uri->data.ksk.keywordCount, 0); + break; + case sks: + GNUNET_free (uri->data.sks.identifier); + break; + case loc: + break; + default: + /* do nothing */ + break; + } GNUNET_free (uri); } @@ -188,7 +712,7 @@ GNUNET_FS_uri_destroy (struct GNUNET_FS_Uri *uri) * @param uri ksk uri to get the number of keywords from * @return 0 if this is not a keyword URI */ -unsigned int +unsigned int GNUNET_FS_uri_ksk_get_keyword_count (const struct GNUNET_FS_Uri *uri) { if (uri->type != ksk) @@ -206,10 +730,10 @@ GNUNET_FS_uri_ksk_get_keyword_count (const struct GNUNET_FS_Uri *uri) * @return -1 if this is not a keyword URI, otherwise number of * keywords iterated over until iterator aborted */ -int +int GNUNET_FS_uri_ksk_get_keywords (const struct GNUNET_FS_Uri *uri, - GNUNET_FS_KeywordIterator iterator, - void *iterator_cls) + GNUNET_FS_KeywordIterator iterator, + void *iterator_cls) { unsigned int i; char *keyword; @@ -219,14 +743,73 @@ GNUNET_FS_uri_ksk_get_keywords (const struct GNUNET_FS_Uri *uri, if (iterator == NULL) return uri->data.ksk.keywordCount; for (i = 0; i < uri->data.ksk.keywordCount; i++) + { + keyword = uri->data.ksk.keywords[i]; + /* first character of keyword indicates + * if it is mandatory or not */ + if (GNUNET_OK != iterator (iterator_cls, &keyword[1], keyword[0] == '+')) + return i; + } + return i; +} + + +/** + * Add the given keyword to the set of keywords represented by the URI. + * Does nothing if the keyword is already present. + * + * @param uri ksk uri to modify + * @param keyword keyword to add + * @param is_mandatory is this keyword mandatory? + */ +void +GNUNET_FS_uri_ksk_add_keyword (struct GNUNET_FS_Uri *uri, const char *keyword, + int is_mandatory) +{ + unsigned int i; + const char *old; + char *n; + + GNUNET_assert (uri->type == ksk); + for (i = 0; i < uri->data.ksk.keywordCount; i++) + { + old = uri->data.ksk.keywords[i]; + if (0 == strcmp (&old[1], keyword)) + return; + } + GNUNET_asprintf (&n, is_mandatory ? "+%s" : " %s", keyword); + GNUNET_array_append (uri->data.ksk.keywords, uri->data.ksk.keywordCount, n); +} + + +/** + * Remove the given keyword from the set of keywords represented by the URI. + * Does nothing if the keyword is not present. + * + * @param uri ksk uri to modify + * @param keyword keyword to add + */ +void +GNUNET_FS_uri_ksk_remove_keyword (struct GNUNET_FS_Uri *uri, + const char *keyword) +{ + unsigned int i; + char *old; + + GNUNET_assert (uri->type == ksk); + for (i = 0; i < uri->data.ksk.keywordCount; i++) + { + old = uri->data.ksk.keywords[i]; + if (0 == strcmp (&old[1], keyword)) { - keyword = uri->data.ksk.keywords[i]; - /* first character of keyword indicates - if it is mandatory or not */ - if (GNUNET_OK != iterator (&keyword[1], keyword[0] == '+', cls)) - return i; + uri->data.ksk.keywords[i] = + uri->data.ksk.keywords[uri->data.ksk.keywordCount - 1]; + GNUNET_array_grow (uri->data.ksk.keywords, uri->data.ksk.keywordCount, + uri->data.ksk.keywordCount - 1); + GNUNET_free (old); + return; } - return i; + } } @@ -239,16 +822,32 @@ GNUNET_FS_uri_ksk_get_keywords (const struct GNUNET_FS_Uri *uri, */ int GNUNET_FS_uri_loc_get_peer_identity (const struct GNUNET_FS_Uri *uri, - struct GNUNET_PeerIdentity * peer) + struct GNUNET_PeerIdentity *peer) { if (uri->type != loc) return GNUNET_SYSERR; - GNUNET_hash (&uri->data.loc.peer, sizeof (GNUNET_RSA_PublicKey), - &peer->hashPubKey); + GNUNET_CRYPTO_hash (&uri->data.loc.peer, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), + &peer->hashPubKey); return GNUNET_OK; } +/** + * Obtain the expiration of the LOC URI. + * + * @param uri location URI to get the expiration from + * @return expiration time of the URI + */ +struct GNUNET_TIME_Absolute +GNUNET_FS_uri_loc_get_expiration (const struct GNUNET_FS_Uri *uri) +{ + GNUNET_assert (uri->type == loc); + return uri->data.loc.expirationTime; +} + + + /** * Obtain the URI of the content itself. * @@ -258,11 +857,11 @@ GNUNET_FS_uri_loc_get_peer_identity (const struct GNUNET_FS_Uri *uri, struct GNUNET_FS_Uri * GNUNET_FS_uri_loc_get_uri (const struct GNUNET_FS_Uri *uri) { - struct GNUNET_ECRS_Uri *ret; + struct GNUNET_FS_Uri *ret; if (uri->type != loc) return NULL; - ret = GNUNET_malloc (sizeof (struct GNUNET_ECRS_Uri)); + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); ret->type = chk; ret->data.chk = uri->data.loc.fi; return ret; @@ -272,27 +871,225 @@ GNUNET_FS_uri_loc_get_uri (const struct GNUNET_FS_Uri *uri) /** * Construct a location URI (this peer will be used for the location). * - * @param baseURI content offered by the sender + * @param baseUri content offered by the sender * @param cfg configuration information (used to find our hostkey) * @param expiration_time how long will the content be offered? * @return the location URI, NULL on error */ struct GNUNET_FS_Uri * GNUNET_FS_uri_loc_create (const struct GNUNET_FS_Uri *baseUri, - struct GNUNET_CONFIGURATION_Handle *cfg, - struct GNUNET_TIME_Absolute expiration_time); - + const struct GNUNET_CONFIGURATION_Handle *cfg, + struct GNUNET_TIME_Absolute expiration_time) +{ + struct GNUNET_FS_Uri *uri; + struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; + char *keyfile; + struct LocUriAssembly ass; -/** + if (baseUri->type != chk) + return NULL; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, "GNUNETD", "HOSTKEY", + &keyfile)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Lacking key configuration settings.\n")); + return NULL; + } + my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile); + if (my_private_key == NULL) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Could not access hostkey file `%s'.\n"), keyfile); + GNUNET_free (keyfile); + return NULL; + } + GNUNET_free (keyfile); + GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key); + ass.purpose.size = htonl (sizeof (struct LocUriAssembly)); + ass.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT); + ass.exptime = GNUNET_TIME_absolute_hton (expiration_time); + ass.fi = baseUri->data.chk; + ass.peer = my_public_key; + uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + uri->type = loc; + uri->data.loc.fi = baseUri->data.chk; + uri->data.loc.expirationTime = expiration_time; + uri->data.loc.peer = my_public_key; + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_rsa_sign (my_private_key, &ass.purpose, + &uri->data.loc.contentSignature)); + GNUNET_CRYPTO_rsa_key_free (my_private_key); + return uri; +} + + +/** + * Create an SKS URI from a namespace and an identifier. + * + * @param ns namespace + * @param id identifier + * @param emsg where to store an error message + * @return an FS URI for the given namespace and identifier + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_sks_create (struct GNUNET_FS_Namespace *ns, const char *id, + char **emsg) +{ + struct GNUNET_FS_Uri *ns_uri; + struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk; + + ns_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ns_uri->type = sks; + GNUNET_CRYPTO_rsa_key_get_public (ns->key, &pk); + GNUNET_CRYPTO_hash (&pk, sizeof (pk), &ns_uri->data.sks.namespace); + ns_uri->data.sks.identifier = GNUNET_strdup (id); + return ns_uri; +} + + +/** + * Create an SKS URI from a namespace ID and an identifier. + * + * @param nsid namespace ID + * @param id identifier + * @return an FS URI for the given namespace and identifier + */ +struct GNUNET_FS_Uri * +GNUNET_FS_uri_sks_create_from_nsid (GNUNET_HashCode * nsid, const char *id) +{ + struct GNUNET_FS_Uri *ns_uri; + + ns_uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ns_uri->type = sks; + ns_uri->data.sks.namespace = *nsid; + ns_uri->data.sks.identifier = GNUNET_strdup (id); + return ns_uri; +} + + +/** + * Canonicalize a keyword. + * + * @param in input string (the keyword) + * @return canonicalized keyword + */ +static char * +canonicalize_keyword (const char *in) +{ + char *ret; + char *wpos; + const char *rpos; + + ret = GNUNET_strdup (in); + wpos = ret; + rpos = in; + while ('\0' != *rpos) + { + switch (tolower ((unsigned char) *rpos)) + { + case 'a': + case 'e': + case 'i': + case 'o': + case 'u': + case ' ': + case '\t': + case '\n': + case '\r': + /* skip characters listed above */ + break; + case 'b': + case 'c': + case 'd': + case 'f': + case 'g': + case 'h': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'p': + case 'r': + case 's': + case 't': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + /* convert characters listed above to lower case */ + *wpos = tolower ((unsigned char) *rpos); + wpos++; + break; + case '!': + case '.': + case '?': + case '-': + /* keep characters listed above without changes */ + *wpos = *rpos; + wpos++; + break; + default: + if (isspace ((unsigned char) *rpos) || isdigit ((unsigned char) *rpos)) + break; + /* replace characters listed above with '_' */ + *wpos = '_'; + wpos++; + break; + } + rpos++; + } + *wpos = '\0'; + return ret; +} + + +/** * Canonicalize keyword URI. Performs operations such * as decapitalization and removal of certain characters. * (useful for search). * - * @param uri the URI to canonicalize + * @param uri the URI to canonicalize * @return canonicalized version of the URI, NULL on error */ struct GNUNET_FS_Uri * -GNUNET_FS_uri_ksk_canonicalize (const struct GNUNET_FS_Uri *uri); +GNUNET_FS_uri_ksk_canonicalize (const struct GNUNET_FS_Uri *uri) +{ + struct GNUNET_FS_Uri *ret; + unsigned int kc; + unsigned int i; + const char *in; + char *sb; + char *cc; + const char *tok; + + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ret->type = ksk; + kc = uri->data.ksk.keywordCount; + for (i = 0; i < kc; i++) + { + in = uri->data.ksk.keywords[i]; + GNUNET_FS_uri_ksk_add_keyword (ret, &in[1], + (in[0] == '+') ? GNUNET_YES : GNUNET_NO); + sb = GNUNET_strdup (&in[1]); +#define DELIMS " \\|\"'`/&@-_,.;!?+-*^$#~=[]{}()<>" + for (tok = strtok (sb, DELIMS); NULL != tok; tok = strtok (NULL, DELIMS)) +#undef DELIMS + { + if (strlen (tok) < 3) + continue; + GNUNET_FS_uri_ksk_add_keyword (ret, tok, GNUNET_NO); + cc = canonicalize_keyword (tok); + if (strlen (cc) > 2) + GNUNET_FS_uri_ksk_add_keyword (ret, cc, GNUNET_NO); + } + GNUNET_free (sb); + } + return ret; +} /** @@ -306,7 +1103,52 @@ GNUNET_FS_uri_ksk_canonicalize (const struct GNUNET_FS_Uri *uri); */ struct GNUNET_FS_Uri * GNUNET_FS_uri_ksk_merge (const struct GNUNET_FS_Uri *u1, - const struct GNUNET_FS_Uri *u2); + const struct GNUNET_FS_Uri *u2) +{ + struct GNUNET_FS_Uri *ret; + unsigned int kc; + unsigned int i; + unsigned int j; + int found; + const char *kp; + char **kl; + + if ((u1 == NULL) && (u2 == NULL)) + return NULL; + if (u1 == NULL) + return GNUNET_FS_uri_dup (u2); + if (u2 == NULL) + return GNUNET_FS_uri_dup (u1); + if ((u1->type != ksk) || (u2->type != ksk)) + { + GNUNET_break (0); + return NULL; + } + kc = u1->data.ksk.keywordCount; + kl = GNUNET_malloc ((kc + u2->data.ksk.keywordCount) * sizeof (char *)); + for (i = 0; i < u1->data.ksk.keywordCount; i++) + kl[i] = GNUNET_strdup (u1->data.ksk.keywords[i]); + for (i = 0; i < u2->data.ksk.keywordCount; i++) + { + kp = u2->data.ksk.keywords[i]; + found = 0; + for (j = 0; j < u1->data.ksk.keywordCount; j++) + if (0 == strcmp (kp + 1, kl[j] + 1)) + { + found = 1; + if (kp[0] == '+') + kl[j][0] = '+'; + break; + } + if (0 == found) + kl[kc++] = GNUNET_strdup (kp); + } + ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + ret->type = ksk; + ret->data.ksk.keywordCount = kc; + ret->data.ksk.keywords = kl; + return ret; +} /** @@ -318,33 +1160,41 @@ GNUNET_FS_uri_ksk_merge (const struct GNUNET_FS_Uri *u1, struct GNUNET_FS_Uri * GNUNET_FS_uri_dup (const struct GNUNET_FS_Uri *uri) { - struct GNUNET_ECRS_URI *ret; + struct GNUNET_FS_Uri *ret; unsigned int i; + if (uri == NULL) + return NULL; ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); memcpy (ret, uri, sizeof (struct GNUNET_FS_Uri)); switch (ret->type) + { + case ksk: + if (ret->data.ksk.keywordCount >= + GNUNET_MAX_MALLOC_CHECKED / sizeof (char *)) { - case ksk: - if (ret->data.ksk.keywordCount > 0) - { - ret->data.ksk.keywords - = GNUNET_malloc (ret->data.ksk.keywordCount * sizeof (char *)); - for (i = 0; i < ret->data.ksk.keywordCount; i++) - ret->data.ksk.keywords[i] = - GNUNET_strdup (uri->data.ksk.keywords[i]); - } - else - ret->data.ksk.keywords = NULL; /* just to be sure */ - break; - case sks: - ret->data.sks.identifier = GNUNET_strdup (uri->data.sks.identifier); - break; - case loc: - break; - default: - break; + GNUNET_break (0); + GNUNET_free (ret); + return NULL; + } + if (ret->data.ksk.keywordCount > 0) + { + ret->data.ksk.keywords = + GNUNET_malloc (ret->data.ksk.keywordCount * sizeof (char *)); + for (i = 0; i < ret->data.ksk.keywordCount; i++) + ret->data.ksk.keywords[i] = GNUNET_strdup (uri->data.ksk.keywords[i]); } + else + ret->data.ksk.keywords = NULL; /* just to be sure */ + break; + case sks: + ret->data.sks.identifier = GNUNET_strdup (uri->data.sks.identifier); + break; + case loc: + break; + default: + break; + } return ret; } @@ -362,11 +1212,87 @@ GNUNET_FS_uri_dup (const struct GNUNET_FS_Uri *uri) * "OR"ed keywords 'foo' and 'bar', not into '"foo bar"'. * * @param keywords the keyword string + * @param emsg where to store an error message * @return an FS URI for the given keywords, NULL * if keywords is not legal (i.e. empty). */ struct GNUNET_FS_Uri * -GNUNET_FS_uri_ksk_create (const char *keywords); +GNUNET_FS_uri_ksk_create (const char *keywords, char **emsg) +{ + char **keywordarr; + unsigned int num_Words; + int inWord; + char *pos; + struct GNUNET_FS_Uri *uri; + char *searchString; + int saw_quote; + + if (keywords == NULL) + { + *emsg = GNUNET_strdup (_("No keywords specified!\n")); + GNUNET_break (0); + return NULL; + } + searchString = GNUNET_strdup (keywords); + num_Words = 0; + inWord = 0; + saw_quote = 0; + pos = searchString; + while ('\0' != *pos) + { + if ((saw_quote == 0) && (isspace ((unsigned char) *pos))) + { + inWord = 0; + } + else if (0 == inWord) + { + inWord = 1; + ++num_Words; + } + if ('"' == *pos) + saw_quote = (saw_quote + 1) % 2; + pos++; + } + if (num_Words == 0) + { + GNUNET_free (searchString); + *emsg = GNUNET_strdup (_("No keywords specified!\n")); + return NULL; + } + if (saw_quote != 0) + { + GNUNET_free (searchString); + *emsg = GNUNET_strdup (_("Number of double-quotes not balanced!\n")); + return NULL; + } + keywordarr = GNUNET_malloc (num_Words * sizeof (char *)); + num_Words = 0; + inWord = 0; + pos = searchString; + while ('\0' != *pos) + { + if ((saw_quote == 0) && (isspace ((unsigned char) *pos))) + { + inWord = 0; + *pos = '\0'; + } + else if (0 == inWord) + { + keywordarr[num_Words] = pos; + inWord = 1; + ++num_Words; + } + if ('"' == *pos) + saw_quote = (saw_quote + 1) % 2; + pos++; + } + uri = + GNUNET_FS_uri_ksk_create_from_args (num_Words, + (const char **) keywordarr); + GNUNET_free (keywordarr); + GNUNET_free (searchString); + return uri; +} /** @@ -387,8 +1313,52 @@ GNUNET_FS_uri_ksk_create (const char *keywords); * if keywords is not legal (i.e. empty). */ struct GNUNET_FS_Uri * -GNUNET_FS_uri_ksk_create_from_args (unsigned int argc, - const char **argv); +GNUNET_FS_uri_ksk_create_from_args (unsigned int argc, const char **argv) +{ + unsigned int i; + struct GNUNET_FS_Uri *uri; + const char *keyword; + char *val; + const char *r; + char *w; + char *emsg; + + if (argc == 0) + return NULL; + /* allow URI to be given as one and only keyword and + * handle accordingly */ + emsg = NULL; + if ((argc == 1) && (strlen (argv[0]) > strlen (GNUNET_FS_URI_PREFIX)) && + (0 == + strncmp (argv[0], GNUNET_FS_URI_PREFIX, strlen (GNUNET_FS_URI_PREFIX))) + && (NULL != (uri = GNUNET_FS_uri_parse (argv[0], &emsg)))) + return uri; + GNUNET_free_non_null (emsg); + uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); + uri->type = ksk; + uri->data.ksk.keywordCount = argc; + uri->data.ksk.keywords = GNUNET_malloc (argc * sizeof (char *)); + for (i = 0; i < argc; i++) + { + keyword = argv[i]; + if (keyword[0] == '+') + val = GNUNET_strdup (keyword); + else + GNUNET_asprintf (&val, " %s", keyword); + r = val; + w = val; + while ('\0' != *r) + { + if ('"' == *r) + r++; + else + *(w++) = *(r++); + } + *w = '\0'; + uri->data.ksk.keywords[i] = val; + } + return uri; +} /** @@ -398,66 +1368,63 @@ GNUNET_FS_uri_ksk_create_from_args (unsigned int argc, * @param u2 the other URI * @return GNUNET_YES if the URIs are equal */ -int +int GNUNET_FS_uri_test_equal (const struct GNUNET_FS_Uri *u1, - const struct GNUNET_FS_Uri *u2) + const struct GNUNET_FS_Uri *u2) { int ret; unsigned int i; unsigned int j; - GNUNET_assert (uri1 != NULL); - GNUNET_assert (uri2 != NULL); - if (uri1->type != uri2->type) + GNUNET_assert (u1 != NULL); + GNUNET_assert (u2 != NULL); + if (u1->type != u2->type) return GNUNET_NO; - switch (uri1->type) - { - case chk: - if (0 == memcmp (&uri1->data.chk, - &uri2->data.chk, - sizeof (struct FileIdentifier))) - return GNUNET_YES; - return GNUNET_NO; - case sks: - if ((0 == memcmp (&uri1->data.sks.namespace, - &uri2->data.sks.namespace, - sizeof (GNUNET_HashCode))) && - (0 == strcmp (uri1->data.sks.identifier, - uri2->data.sks.identifier))) - - return GNUNET_YES; + switch (u1->type) + { + case chk: + if (0 == + memcmp (&u1->data.chk, &u2->data.chk, sizeof (struct FileIdentifier))) + return GNUNET_YES; + return GNUNET_NO; + case sks: + if ((0 == + memcmp (&u1->data.sks.namespace, &u2->data.sks.namespace, + sizeof (GNUNET_HashCode))) && + (0 == strcmp (u1->data.sks.identifier, u2->data.sks.identifier))) + + return GNUNET_YES; + return GNUNET_NO; + case ksk: + if (u1->data.ksk.keywordCount != u2->data.ksk.keywordCount) return GNUNET_NO; - case ksk: - if (uri1->data.ksk.keywordCount != uri2->data.ksk.keywordCount) - return GNUNET_NO; - for (i = 0; i < uri1->data.ksk.keywordCount; i++) + for (i = 0; i < u1->data.ksk.keywordCount; i++) + { + ret = GNUNET_NO; + for (j = 0; j < u2->data.ksk.keywordCount; j++) + { + if (0 == strcmp (u1->data.ksk.keywords[i], u2->data.ksk.keywords[j])) { - ret = GNUNET_NO; - for (j = 0; j < uri2->data.ksk.keywordCount; j++) - { - if (0 == strcmp (uri1->data.ksk.keywords[i], - uri2->data.ksk.keywords[j])) - { - ret = GNUNET_YES; - break; - } - } - if (ret == GNUNET_NO) - return GNUNET_NO; + ret = GNUNET_YES; + break; } - return GNUNET_YES; - case loc: - if (memcmp (&uri1->data.loc, - &uri2->data.loc, - sizeof (struct FileIdentifier) + - sizeof (GNUNET_RSA_PublicKey) + - sizeof (struct GNUNET_TIME_Absolute) + - sizeof (unsigned short) + sizeof (unsigned short)) != 0) + } + if (ret == GNUNET_NO) return GNUNET_NO; - return GNUNET_YES; - default: - return GNUNET_NO; } + return GNUNET_YES; + case loc: + if (memcmp + (&u1->data.loc, &u2->data.loc, + sizeof (struct FileIdentifier) + + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + + sizeof (struct GNUNET_TIME_Absolute) + sizeof (unsigned short) + + sizeof (unsigned short)) != 0) + return GNUNET_NO; + return GNUNET_YES; + default: + return GNUNET_NO; + } } @@ -482,16 +1449,16 @@ GNUNET_FS_uri_test_sks (const struct GNUNET_FS_Uri *uri) * @param nsid where to store the ID of the namespace * @return GNUNET_OK on success */ -int +int GNUNET_FS_uri_sks_get_namespace (const struct GNUNET_FS_Uri *uri, - GNUNET_HashCode * nsid) + GNUNET_HashCode * nsid) { - if (! GNUNET_FS_uri_test_sks (uri)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - *id = uri->data.sks.namespace; + if (!GNUNET_FS_uri_test_sks (uri)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + *nsid = uri->data.sks.namespace; return GNUNET_OK; } @@ -506,10 +1473,10 @@ char * GNUNET_FS_uri_sks_get_content_id (const struct GNUNET_FS_Uri *uri) { if (!GNUNET_FS_uri_test_sks (uri)) - { - GNUNET_break (0); - return NULL; - } + { + GNUNET_break (0); + return NULL; + } return GNUNET_strdup (uri->data.sks.identifier); } @@ -524,7 +1491,20 @@ GNUNET_FS_uri_sks_get_content_id (const struct GNUNET_FS_Uri *uri) */ char * GNUNET_FS_uri_sks_to_string_fancy (struct GNUNET_CONFIGURATION_Handle *cfg, - const struct GNUNET_FS_Uri *uri); + const struct GNUNET_FS_Uri *uri) +{ + char *ret; + char *name; + + if (uri->type != sks) + return NULL; + name = GNUNET_PSEUDONYM_id_to_name (cfg, &uri->data.sks.namespace); + if (name == NULL) + return GNUNET_FS_uri_to_string (uri); + GNUNET_asprintf (&ret, "%s: %s", name, uri->data.sks.identifier); + GNUNET_free (name); + return ret; +} /** @@ -533,17 +1513,17 @@ GNUNET_FS_uri_sks_to_string_fancy (struct GNUNET_CONFIGURATION_Handle *cfg, * @param uri the uri * @return GNUNET_YES if this is a KSK uri */ -int +int GNUNET_FS_uri_test_ksk (const struct GNUNET_FS_Uri *uri) { #if EXTRA_CHECKS unsigned int i; if (uri->type == ksk) - { - for (i = uri->data.ksk.keywordCount - 1; i >= 0; i--) - GNUNET_assert (uri->data.ksk.keywords[i] != NULL); - } + { + for (i = uri->data.ksk.keywordCount - 1; i >= 0; i--) + GNUNET_assert (uri->data.ksk.keywords[i] != NULL); + } #endif return uri->type == ksk; } @@ -555,7 +1535,7 @@ GNUNET_FS_uri_test_ksk (const struct GNUNET_FS_Uri *uri) * @param uri the uri to check * @return GNUNET_YES if this is a CHK uri */ -int +int GNUNET_FS_uri_test_chk (const struct GNUNET_FS_Uri *uri) { return uri->type == chk; @@ -569,18 +1549,18 @@ GNUNET_FS_uri_test_chk (const struct GNUNET_FS_Uri *uri) * @param uri the CHK URI to inspect * @return size of the file as specified in the CHK URI */ -uint64_t -GNUNET_FS_uri_chk_get_file_size (const struct GNUNET_FS_Uri *uri) +uint64_t +GNUNET_FS_uri_chk_get_file_size (const struct GNUNET_FS_Uri * uri) { switch (uri->type) - { - case chk: - return GNUNET_ntohll (uri->data.chk.file_length); - case loc: - return GNUNET_ntohll (uri->data.loc.fi.file_length); - default: - GNUNET_assert (0); - } + { + case chk: + return GNUNET_ntohll (uri->data.chk.file_length); + case loc: + return GNUNET_ntohll (uri->data.loc.fi.file_length); + default: + GNUNET_assert (0); + } return 0; /* unreachable */ } @@ -591,7 +1571,7 @@ GNUNET_FS_uri_chk_get_file_size (const struct GNUNET_FS_Uri *uri) * @param uri the uri to check * @return GNUNET_YES if this is a LOC uri */ -int +int GNUNET_FS_uri_test_loc (const struct GNUNET_FS_Uri *uri) { return uri->type == loc; @@ -603,27 +1583,37 @@ GNUNET_FS_uri_test_loc (const struct GNUNET_FS_Uri *uri) * Adds it to the URI. * * @param cls URI to update - * @param type type of the meta data - * @param data value of the meta data - * @return GNUNET_OK (always) + * @param plugin_name name of the plugin that produced this value; + * special values can be used (i.e. '<zlib>' for zlib being + * used in the main libextractor library and yielding + * meta data). + * @param type libextractor-type describing the meta data + * @param format basic format information about data + * @param data_mime_type mime-type of data (not of the original file); + * can be NULL (if mime-type is not known) + * @param data actual meta-data found + * @param data_len number of bytes in data + * @return 0 (always) */ static int -gather_uri_data (void *cls, - EXTRACTOR_KeywordType type, - const char *data) +gather_uri_data (void *cls, const char *plugin_name, + enum EXTRACTOR_MetaType type, enum EXTRACTOR_MetaFormat format, + const char *data_mime_type, const char *data, size_t data_len) { struct GNUNET_FS_Uri *uri = cls; char *nkword; int j; - + + if ((format != EXTRACTOR_METAFORMAT_UTF8) && + (format != EXTRACTOR_METAFORMAT_C_STRING)) + return 0; for (j = uri->data.ksk.keywordCount - 1; j >= 0; j--) if (0 == strcmp (&uri->data.ksk.keywords[j][1], data)) return GNUNET_OK; - nkword = GNUNET_malloc (strlen (data) + 2); - strcpy (nkword, " "); /* not mandatory */ - strcat (nkword, data); + GNUNET_asprintf (&nkword, " %s", /* space to mark as 'non mandatory' */ + data); uri->data.ksk.keywords[uri->data.ksk.keywordCount++] = nkword; - return GNUNET_OK; + return 0; } @@ -631,32 +1621,30 @@ gather_uri_data (void *cls, * Construct a keyword-URI from meta-data (take all entries * in the meta-data and construct one large keyword URI * that lists all keywords that can be found in the meta-data). - * @deprecated + * + * @param md metadata to use + * @return NULL on error, otherwise a KSK URI */ struct GNUNET_FS_Uri * -GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_MetaData *md) +GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_CONTAINER_MetaData + *md) { struct GNUNET_FS_Uri *ret; + int ent; if (md == NULL) return NULL; ret = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri)); ret->type = ksk; - ret->data.ksk.keywordCount = 0; - ret->data.ksk.keywords = NULL; - ret->data.ksk.keywords - = GNUNET_malloc (sizeof (char *) * - GNUNET_meta_data_get_contents (md, NULL, NULL)); - GNUNET_meta_data_get_contents (md, &gather_uri_data, ret); + ent = GNUNET_CONTAINER_meta_data_iterate (md, NULL, NULL); + if (ent > 0) + { + ret->data.ksk.keywords = GNUNET_malloc (sizeof (char *) * ent); + GNUNET_CONTAINER_meta_data_iterate (md, &gather_uri_data, ret); + } return ret; - } -#if 0 - -// old code... - - /** * In URI-encoding, does the given character @@ -665,17 +1653,23 @@ GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_MetaData *md) static int needs_percent (char c) { - return (!((isalnum (c)) || - (c == '-') || (c == '_') || (c == '.') || (c == '~'))); + return (! + ((isalnum ((unsigned char) c)) || (c == '-') || (c == '_') || + (c == '.') || (c == '~'))); } + /** - * Generate a keyword URI. + * Convert a KSK URI to a string. + * + * @param uri the URI to convert * @return NULL on error (i.e. keywordCount == 0) */ static char * -createKeywordURI (char **keywords, unsigned int keywordCount) +uri_ksk_to_string (const struct GNUNET_FS_Uri *uri) { + char **keywords; + unsigned int keywordCount; size_t n; char *ret; unsigned int i; @@ -684,634 +1678,220 @@ createKeywordURI (char **keywords, unsigned int keywordCount) size_t slen; const char *keyword; - n = - keywordCount + strlen (GNUNET_ECRS_URI_PREFIX) + - strlen (GNUNET_ECRS_SEARCH_INFIX) + 1; + if (uri->type != ksk) + return NULL; + keywords = uri->data.ksk.keywords; + keywordCount = uri->data.ksk.keywordCount; + n = keywordCount + strlen (GNUNET_FS_URI_PREFIX) + + strlen (GNUNET_FS_URI_KSK_INFIX) + 1; for (i = 0; i < keywordCount; i++) + { + keyword = keywords[i]; + slen = strlen (keyword); + n += slen; + for (j = 0; j < slen; j++) { - keyword = keywords[i]; - slen = strlen (keyword); - n += slen; - for (j = 0; j < slen; j++) - { - if ((j == 0) && (keyword[j] == ' ')) - { - n--; - continue; /* skip leading space */ - } - if (needs_percent (keyword[j])) - n += 2; /* will use %-encoding */ - } + if ((j == 0) && (keyword[j] == ' ')) + { + n--; + continue; /* skip leading space */ + } + if (needs_percent (keyword[j])) + n += 2; /* will use %-encoding */ } + } ret = GNUNET_malloc (n); - strcpy (ret, GNUNET_ECRS_URI_PREFIX); - strcat (ret, GNUNET_ECRS_SEARCH_INFIX); + strcpy (ret, GNUNET_FS_URI_PREFIX); + strcat (ret, GNUNET_FS_URI_KSK_INFIX); wpos = strlen (ret); for (i = 0; i < keywordCount; i++) + { + keyword = keywords[i]; + slen = strlen (keyword); + for (j = 0; j < slen; j++) { - keyword = keywords[i]; - slen = strlen (keyword); - for (j = 0; j < slen; j++) - { - if ((j == 0) && (keyword[j] == ' ')) - continue; /* skip leading space */ - if (needs_percent (keyword[j])) - { - sprintf (&ret[wpos], "%%%02X", keyword[j]); - wpos += 3; - } - else - { - ret[wpos++] = keyword[j]; - } - } - if (i != keywordCount - 1) - ret[wpos++] = '+'; + if ((j == 0) && (keyword[j] == ' ')) + continue; /* skip leading space */ + if (needs_percent (keyword[j])) + { + sprintf (&ret[wpos], "%%%02X", keyword[j]); + wpos += 3; + } + else + { + ret[wpos++] = keyword[j]; + } } + if (i != keywordCount - 1) + ret[wpos++] = '+'; + } return ret; } -/** - * Generate a subspace URI. - */ -static char * -createSubspaceURI (const GNUNET_HashCode * namespace, const char *identifier) -{ - size_t n; - char *ret; - GNUNET_EncName ns; - - n = - sizeof (GNUNET_EncName) + strlen (GNUNET_ECRS_URI_PREFIX) + - strlen (GNUNET_ECRS_SUBSPACE_INFIX) + 1 + strlen (identifier); - ret = GNUNET_malloc (n); - GNUNET_hash_to_enc (namespace, &ns); - GNUNET_snprintf (ret, n, - "%s%s%s/%s", - GNUNET_ECRS_URI_PREFIX, GNUNET_ECRS_SUBSPACE_INFIX, - (const char *) &ns, identifier); - return ret; -} /** - * Generate a file URI. + * Convert SKS URI to a string. + * + * @param uri sks uri to convert + * @return NULL on error */ static char * -createFileURI (const GNUNET_EC_FileIdentifier * fi) +uri_sks_to_string (const struct GNUNET_FS_Uri *uri) { + const GNUNET_HashCode *namespace; + const char *identifier; char *ret; - GNUNET_EncName keyhash; - GNUNET_EncName queryhash; - size_t n; - - GNUNET_hash_to_enc (&fi->chk.key, &keyhash); - GNUNET_hash_to_enc (&fi->chk.query, &queryhash); + struct GNUNET_CRYPTO_HashAsciiEncoded ns; - n = - strlen (GNUNET_ECRS_URI_PREFIX) + 2 * sizeof (GNUNET_EncName) + 8 + 16 + - 32 + strlen (GNUNET_ECRS_FILE_INFIX); - ret = GNUNET_malloc (n); - GNUNET_snprintf (ret, - n, - "%s%s%s.%s.%llu", - GNUNET_ECRS_URI_PREFIX, - GNUNET_ECRS_FILE_INFIX, - (char *) &keyhash, (char *) &queryhash, - GNUNET_ntohll (fi->file_length)); + if (uri->type != sks) + return NULL; + namespace = &uri->data.sks.namespace; + identifier = uri->data.sks.identifier; + GNUNET_CRYPTO_hash_to_enc (namespace, &ns); + GNUNET_asprintf (&ret, "%s%s%s/%s", GNUNET_FS_URI_PREFIX, + GNUNET_FS_URI_SKS_INFIX, (const char *) &ns, identifier); return ret; } -#include "bincoder.c" /** - * Create a (string) location URI from a Location. + * Convert a CHK URI to a string. + * + * @param uri chk uri to convert + * @return NULL on error */ static char * -createLocURI (const Location * loc) +uri_chk_to_string (const struct GNUNET_FS_Uri *uri) { - size_t n; + const struct FileIdentifier *fi; char *ret; - GNUNET_EncName keyhash; - GNUNET_EncName queryhash; - char *peerId; - char *peerSig; - - GNUNET_hash_to_enc (&loc->fi.chk.key, &keyhash); - GNUNET_hash_to_enc (&loc->fi.chk.query, &queryhash); - n = 2148; - peerId = bin2enc (&loc->peer, sizeof (GNUNET_RSA_PublicKey)); - peerSig = bin2enc (&loc->contentSignature, sizeof (GNUNET_RSA_Signature)); - ret = GNUNET_malloc (n); - GNUNET_snprintf (ret, - n, - "%s%s%s.%s.%llu.%s.%s.%u", - GNUNET_ECRS_URI_PREFIX, - GNUNET_ECRS_LOCATION_INFIX, - (char *) &keyhash, - (char *) &queryhash, - GNUNET_ntohll (loc->fi.file_length), - peerId, peerSig, loc->expirationTime); - GNUNET_free (peerSig); - GNUNET_free (peerId); - return ret; -} - -/** - * Convert a URI to a UTF-8 String. - */ -char * -GNUNET_ECRS_uri_to_string (const struct GNUNET_ECRS_URI *uri) -{ - if (uri == NULL) - { - GNUNET_GE_BREAK (NULL, 0); - return NULL; - } - switch (uri->type) - { - case ksk: - return createKeywordURI (uri->data.ksk.keywords, - uri->data.ksk.keywordCount); - case sks: - return createSubspaceURI (&uri->data.sks.namespace, - uri->data.sks.identifier); - case chk: - return createFileURI (&uri->data.fi); - case loc: - return createLocURI (&uri->data.loc); - default: - GNUNET_GE_BREAK (NULL, 0); - return NULL; - } -} + struct GNUNET_CRYPTO_HashAsciiEncoded keyhash; + struct GNUNET_CRYPTO_HashAsciiEncoded queryhash; -/** - * Convert keyword URI to a human readable format - * (i.e. the search query that was used in the first place) - */ -char * -GNUNET_ECRS_ksk_uri_to_human_readable_string (const struct GNUNET_ECRS_URI - *uri) -{ - size_t n; - char *ret; - unsigned int i; - const char *keyword; - char **keywords; - unsigned int keywordCount; + if (uri->type != chk) + return NULL; + fi = &uri->data.chk; + GNUNET_CRYPTO_hash_to_enc (&fi->chk.key, &keyhash); + GNUNET_CRYPTO_hash_to_enc (&fi->chk.query, &queryhash); - if ((uri == NULL) || (uri->type != ksk)) - { - GNUNET_GE_BREAK (NULL, 0); - return NULL; - } - keywords = uri->data.ksk.keywords; - keywordCount = uri->data.ksk.keywordCount; - n = keywordCount + 1; - for (i = 0; i < keywordCount; i++) - { - keyword = keywords[i]; - n += strlen (keyword) - 1; - if (NULL != strstr (&keyword[1], " ")) - n += 2; - if (keyword[0] == '+') - n++; - } - ret = GNUNET_malloc (n); - strcpy (ret, ""); - for (i = 0; i < keywordCount; i++) - { - keyword = keywords[i]; - if (NULL != strstr (&keyword[1], " ")) - { - strcat (ret, "\""); - if (keyword[0] == '+') - strcat (ret, keyword); - else - strcat (ret, &keyword[1]); - strcat (ret, "\""); - } - else - { - if (keyword[0] == '+') - strcat (ret, keyword); - else - strcat (ret, &keyword[1]); - } - strcat (ret, " "); - } + GNUNET_asprintf (&ret, "%s%s%s.%s.%llu", GNUNET_FS_URI_PREFIX, + GNUNET_FS_URI_CHK_INFIX, (const char *) &keyhash, + (const char *) &queryhash, GNUNET_ntohll (fi->file_length)); return ret; } /** - * Given a keyword with %-encoding (and possibly quotes to protect - * spaces), return a copy of the keyword without %-encoding and - * without double-quotes (%22). Also, add a space at the beginning - * if there is not a '+'. + * Convert binary data to a string. + * + * @param data binary data to convert + * @param size number of bytes in data + * @return converted data */ static char * -percent_decode_keyword (const char *in) +bin2enc (const void *data, size_t size) { - char *out; + /** + * 64 characters for encoding, 6 bits per character + */ + static char *tbl = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_="; + + size_t len; + size_t pos; + unsigned int bits; + unsigned int hbits; char *ret; - unsigned int rpos; - unsigned int wpos; - unsigned int hx; - out = GNUNET_strdup (in); - rpos = 0; - wpos = 0; - while (out[rpos] != '\0') + GNUNET_assert (strlen (tbl) == 64); + len = size * 8 / 6; + if (((size * 8) % 6) != 0) + len++; + ret = GNUNET_malloc (len + 1); + ret[len] = '\0'; + len = 0; + bits = 0; + hbits = 0; + for (pos = 0; pos < size; pos++) + { + bits |= ((((const unsigned char *) data)[pos]) << hbits); + hbits += 8; + while (hbits >= 6) { - if (out[rpos] == '%') - { - if (1 != sscanf (&out[rpos + 1], "%2X", &hx)) - { - GNUNET_free (out); - return NULL; - } - rpos += 3; - if (hx == '"') - continue; /* skip double quote */ - out[wpos++] = (char) hx; - } - else - { - out[wpos++] = out[rpos++]; - } + ret[len++] = tbl[bits & 63]; + bits >>= 6; + hbits -= 6; } - out[wpos] = '\0'; - if (out[0] == '+') - { - ret = GNUNET_strdup (out); - } - else - { - /* need to prefix with space */ - ret = GNUNET_malloc (strlen (out) + 2); - strcpy (ret, " "); - strcat (ret, out); - } - GNUNET_free (out); + } + if (hbits > 0) + ret[len] = tbl[bits & 63]; return ret; } -/** - * Parses an ECRS search URI. - * - * @param uri an uri string - * @param keyword will be set to an array with the keywords - * @return GNUNET_SYSERR if this is not a search URI, otherwise - * the number of keywords placed in the array - */ -static int -parseKeywordURI (struct GNUNET_GE_Context *ectx, const char *uri, - char ***keywords) -{ - unsigned int pos; - int ret; - int iret; - int i; - size_t slen; - char *dup; - int saw_quote; - - GNUNET_GE_ASSERT (ectx, uri != NULL); - - slen = strlen (uri); - pos = strlen (GNUNET_ECRS_URI_PREFIX); - - if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos)) - return GNUNET_SYSERR; - if (0 != - strncmp (&uri[pos], GNUNET_ECRS_SEARCH_INFIX, - strlen (GNUNET_ECRS_SEARCH_INFIX))) - return GNUNET_SYSERR; - pos += strlen (GNUNET_ECRS_SEARCH_INFIX); - if (slen == pos) - { - /* no keywords */ - (*keywords) = NULL; - return 0; - } - if ((uri[slen - 1] == '+') || (uri[pos] == '+')) - return GNUNET_SYSERR; /* no keywords / malformed */ - - ret = 1; - saw_quote = 0; - for (i = pos; i < slen; i++) - { - if ((uri[i] == '%') && (&uri[i] == strstr (&uri[i], "%22"))) - { - saw_quote = (saw_quote + 1) % 2; - i += 3; - continue; - } - if ((uri[i] == '+') && (saw_quote == 0)) - { - ret++; - if (uri[i - 1] == '+') - return GNUNET_SYSERR; /* "++" not allowed */ - } - } - if (saw_quote == 1) - return GNUNET_SYSERR; /* quotes not balanced */ - iret = ret; - dup = GNUNET_strdup (uri); - (*keywords) = GNUNET_malloc (ret * sizeof (char *)); - for (i = 0; i < ret; i++) - (*keywords)[i] = NULL; - for (i = slen - 1; i >= pos; i--) - { - if ((uri[i] == '%') && (&uri[i] == strstr (&uri[i], "%22"))) - { - saw_quote = (saw_quote + 1) % 2; - i += 3; - continue; - } - if ((dup[i] == '+') && (saw_quote == 0)) - { - (*keywords)[--ret] = percent_decode_keyword (&dup[i + 1]); - if (NULL == (*keywords)[ret]) - goto CLEANUP; - dup[i] = '\0'; - } - } - (*keywords)[--ret] = percent_decode_keyword (&dup[pos]); - if (NULL == (*keywords)[ret]) - goto CLEANUP; - GNUNET_GE_ASSERT (ectx, ret == 0); - GNUNET_free (dup); - return iret; -CLEANUP: - for (i = 0; i < ret; i++) - GNUNET_free_non_null ((*keywords)[i]); - GNUNET_free (*keywords); - *keywords = NULL; - GNUNET_free (dup); - return GNUNET_SYSERR; -} /** - * Parses an AFS namespace / subspace identifier URI. + * Convert a LOC URI to a string. * - * @param uri an uri string - * @param namespace set to the namespace ID - * @param identifier set to the ID in the namespace - * @return GNUNET_OK on success, GNUNET_SYSERR if this is not a namespace URI - */ -static int -parseSubspaceURI (struct GNUNET_GE_Context *ectx, - const char *uri, - GNUNET_HashCode * namespace, char **identifier) -{ - unsigned int pos; - size_t slen; - char *up; - - GNUNET_GE_ASSERT (ectx, uri != NULL); - - slen = strlen (uri); - pos = strlen (GNUNET_ECRS_URI_PREFIX); - - if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos)) - return GNUNET_SYSERR; - if (0 != strncmp (&uri[pos], - GNUNET_ECRS_SUBSPACE_INFIX, - strlen (GNUNET_ECRS_SUBSPACE_INFIX))) - return GNUNET_SYSERR; - pos += strlen (GNUNET_ECRS_SUBSPACE_INFIX); - if ((slen < pos + sizeof (GNUNET_EncName) + 1) || - (!((uri[pos + sizeof (GNUNET_EncName) - 1] == '/') || - (uri[pos + sizeof (GNUNET_EncName) - 1] == '\\')))) - return GNUNET_SYSERR; - - up = GNUNET_strdup (uri); - up[pos + sizeof (GNUNET_EncName) - 1] = '\0'; - if ((GNUNET_OK != GNUNET_enc_to_hash (&up[pos], namespace))) - { - GNUNET_free (up); - return GNUNET_SYSERR; - } - *identifier = GNUNET_strdup (&up[pos + sizeof (GNUNET_EncName)]); - GNUNET_free (up); - return GNUNET_OK; -} - -/** - * Parses an URI that identifies a file - * - * @param uri an uri string - * @param fi the file identifier - * @return GNUNET_OK on success, GNUNET_SYSERR if this is not a file URI - */ -static int -parseFileURI (struct GNUNET_GE_Context *ectx, const char *uri, - GNUNET_EC_FileIdentifier * fi) -{ - unsigned int pos; - size_t slen; - char *dup; - - GNUNET_GE_ASSERT (ectx, uri != NULL); - - slen = strlen (uri); - pos = strlen (GNUNET_ECRS_URI_PREFIX); - - if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos)) - return GNUNET_SYSERR; - if (0 != - strncmp (&uri[pos], GNUNET_ECRS_FILE_INFIX, - strlen (GNUNET_ECRS_FILE_INFIX))) - return GNUNET_SYSERR; - pos += strlen (GNUNET_ECRS_FILE_INFIX); - if ((slen < pos + 2 * sizeof (GNUNET_EncName) + 1) || - (uri[pos + sizeof (GNUNET_EncName) - 1] != '.') || - (uri[pos + sizeof (GNUNET_EncName) * 2 - 1] != '.')) - return GNUNET_SYSERR; - - dup = GNUNET_strdup (uri); - dup[pos + sizeof (GNUNET_EncName) - 1] = '\0'; - dup[pos + sizeof (GNUNET_EncName) * 2 - 1] = '\0'; - if ((GNUNET_OK != GNUNET_enc_to_hash (&dup[pos], - &fi->chk.key)) || - (GNUNET_OK != GNUNET_enc_to_hash (&dup[pos + sizeof (GNUNET_EncName)], - &fi->chk.query)) || - (1 != SSCANF (&dup[pos + sizeof (GNUNET_EncName) * 2], - "%llu", &fi->file_length))) - { - GNUNET_free (dup); - return GNUNET_SYSERR; - } - GNUNET_free (dup); - fi->file_length = GNUNET_htonll (fi->file_length); - return GNUNET_OK; -} - -/** - * Parses an URI that identifies a location (and file). - * Also verifies validity of the location URI. - * - * @param uri an uri string - * @param loc where to store the location - * @return GNUNET_OK on success, GNUNET_SYSERR if this is not a file URI - */ -static int -parseLocationURI (struct GNUNET_GE_Context *ectx, const char *uri, - Location * loc) -{ - unsigned int pos; - unsigned int npos; - int ret; - size_t slen; - char *dup; - char *addr; - - - GNUNET_GE_ASSERT (ectx, uri != NULL); - addr = NULL; - slen = strlen (uri); - pos = strlen (GNUNET_ECRS_URI_PREFIX); - - if (0 != strncmp (uri, GNUNET_ECRS_URI_PREFIX, pos)) - return GNUNET_SYSERR; - if (0 != strncmp (&uri[pos], - GNUNET_ECRS_LOCATION_INFIX, - strlen (GNUNET_ECRS_LOCATION_INFIX))) - return GNUNET_SYSERR; - pos += strlen (GNUNET_ECRS_LOCATION_INFIX); - if ((slen < pos + 2 * sizeof (GNUNET_EncName) + 1) || - (uri[pos + sizeof (GNUNET_EncName) - 1] != '.') || - (uri[pos + sizeof (GNUNET_EncName) * 2 - 1] != '.')) - return GNUNET_SYSERR; - - dup = GNUNET_strdup (uri); - dup[pos + sizeof (GNUNET_EncName) - 1] = '\0'; - dup[pos + sizeof (GNUNET_EncName) * 2 - 1] = '\0'; - npos = pos + sizeof (GNUNET_EncName) * 2; - while ((uri[npos] != '\0') && (uri[npos] != '.')) - npos++; - if (dup[npos] == '\0') - goto ERR; - dup[npos++] = '\0'; - if ((GNUNET_OK != GNUNET_enc_to_hash (&dup[pos], - &loc->fi.chk.key)) || - (GNUNET_OK != GNUNET_enc_to_hash (&dup[pos + sizeof (GNUNET_EncName)], - &loc->fi.chk.query)) || - (1 != SSCANF (&dup[pos + sizeof (GNUNET_EncName) * 2], - "%llu", &loc->fi.file_length))) - goto ERR; - loc->fi.file_length = GNUNET_htonll (loc->fi.file_length); - ret = enc2bin (&dup[npos], &loc->peer, sizeof (GNUNET_RSA_PublicKey)); - if (ret == -1) - goto ERR; - npos += ret; - if (dup[npos++] != '.') - goto ERR; - ret = - enc2bin (&dup[npos], &loc->contentSignature, - sizeof (GNUNET_RSA_Signature)); - if (ret == -1) - goto ERR; - npos += ret; - if (dup[npos++] != '.') - goto ERR; - if (1 != SSCANF (&dup[npos], "%u", &loc->expirationTime)) - goto ERR; - /* Finally: verify sigs! */ - if (GNUNET_OK != GNUNET_RSA_verify (&loc->fi, - sizeof (GNUNET_EC_FileIdentifier) + - sizeof (GNUNET_PeerIdentity) + - sizeof (GNUNET_Int32Time), - &loc->contentSignature, &loc->peer)) - goto ERR; - GNUNET_free (dup); - return GNUNET_OK; -ERR: - GNUNET_free (dup); - GNUNET_free_non_null (addr); - return GNUNET_SYSERR; -} - -/** - * Convert a UTF-8 String to a URI. + * @param uri loc uri to convert + * @return NULL on error */ -URI * -GNUNET_ECRS_string_to_uri (struct GNUNET_GE_Context * ectx, const char *uri) +static char * +uri_loc_to_string (const struct GNUNET_FS_Uri *uri) { - URI *ret; - int len; + char *ret; + struct GNUNET_CRYPTO_HashAsciiEncoded keyhash; + struct GNUNET_CRYPTO_HashAsciiEncoded queryhash; + char *peerId; + char *peerSig; - ret = GNUNET_malloc (sizeof (URI)); - if (GNUNET_OK == parseFileURI (ectx, uri, &ret->data.fi)) - { - ret->type = chk; - return ret; - } - if (GNUNET_OK == parseSubspaceURI (ectx, - uri, - &ret->data.sks.namespace, - &ret->data.sks.identifier)) - { - ret->type = sks; - return ret; - } - if (GNUNET_OK == parseLocationURI (ectx, uri, &ret->data.loc)) - { - ret->type = loc; - return ret; - } - len = parseKeywordURI (ectx, uri, &ret->data.ksk.keywords); - if (len < 0) - { - GNUNET_free (ret); - return NULL; - } - ret->type = ksk; - ret->data.ksk.keywordCount = len; + GNUNET_CRYPTO_hash_to_enc (&uri->data.loc.fi.chk.key, &keyhash); + GNUNET_CRYPTO_hash_to_enc (&uri->data.loc.fi.chk.query, &queryhash); + peerId = + bin2enc (&uri->data.loc.peer, + sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); + peerSig = + bin2enc (&uri->data.loc.contentSignature, + sizeof (struct GNUNET_CRYPTO_RsaSignature)); + GNUNET_asprintf (&ret, "%s%s%s.%s.%llu.%s.%s.%llu", GNUNET_FS_URI_PREFIX, + GNUNET_FS_URI_LOC_INFIX, (const char *) &keyhash, + (const char *) &queryhash, + (unsigned long long) GNUNET_ntohll (uri->data.loc. + fi.file_length), peerId, + peerSig, + (unsigned long long) uri->data.loc.expirationTime.abs_value); + GNUNET_free (peerSig); + GNUNET_free (peerId); return ret; } - /** - * Construct a location URI. + * Convert a URI to a UTF-8 String. * - * @param baseURI content offered by the sender - * @param sender identity of the peer with the content - * @param expiration_time how long will the content be offered? - * @param proto transport protocol to reach the peer - * @param sas sender address size (for HELLO) - * @param address sas bytes of address information - * @param signer function to call for obtaining - * RSA signatures for "sender". - * @return the location URI + * @param uri uri to convert to a string + * @return the UTF-8 string */ -struct GNUNET_ECRS_URI * -GNUNET_ECRS_location_to_uri (const struct GNUNET_ECRS_URI *baseUri, - const GNUNET_RSA_PublicKey * sender, - GNUNET_Int32Time expirationTime, - GNUNET_ECRS_SignFunction signer, - void *signer_cls) +char * +GNUNET_FS_uri_to_string (const struct GNUNET_FS_Uri *uri) { - struct GNUNET_ECRS_URI *uri; - - if (baseUri->type != chk) + if (uri == NULL) + { + GNUNET_break (0); return NULL; - - uri = GNUNET_malloc (sizeof (struct GNUNET_ECRS_URI)); - uri->type = loc; - uri->data.loc.fi = baseUri->data.fi; - uri->data.loc.peer = *sender; - uri->data.loc.expirationTime = expirationTime; - signer (signer_cls, - sizeof (GNUNET_EC_FileIdentifier) + - sizeof (GNUNET_PeerIdentity) + - sizeof (GNUNET_Int32Time), - &uri->data.loc.fi, &uri->data.loc.contentSignature); - return uri; + } + switch (uri->type) + { + case ksk: + return uri_ksk_to_string (uri); + case sks: + return uri_sks_to_string (uri); + case chk: + return uri_chk_to_string (uri); + case loc: + return uri_loc_to_string (uri); + default: + GNUNET_break (0); + return NULL; + } } -#endif - -/* end of uri.c */ +/* end of fs_uri.c */