/* This file is part of GNUnet. (C) 2003, 2004 Christian Grothoff (and other contributing authors) 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 option) any later version. GNUnet is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file applications/afs/module/uri.c * @brief Parses and produces uri strings. * @author Igor Wronsky, Christian Grothoff * * 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 parses URIs for the AFS module. The AFS URIs fall * into three categories. Note that the IDENTIFIER format of the * three categories is sufficiently different to not require an explicit * sub-module structure; nevertheless, an optional explicit qualifier * is supported. The concrete categories are the following: * *

* * The encoding for hexadecimal values is defined in the hashing.c * module (EncName) in the gnunet-util library and discussed there. *

* */ #include "gnunet_afs_esed2.h" #include "platform.h" #define SEARCH_INFIX "search/" #define SUBSPACE_INFIX "subspace/" #define FILE_INFIX "file/" /** * Do the create functions generate the short URI form by default? * (otherwise the URI type is included in the URI, * i.e. "gnunet://afs/search/foo"). Assuming that users want * URIs that are as short as possible YES is the right choice. * NO results in more verbose output. */ #define CREATE_SHORT_URIS YES /** * Parses an AFS search URI. * * @param uri an uri string * @param keyword will be set to an array with the keywords * @return SYSERR if this is not a search URI, otherwise * the number of keywords placed in the array */ int parseKeywordURI(const char * uri, char *** keywords) { unsigned int pos; int ret; int iret; int i; size_t slen; char * dup; GNUNET_ASSERT(uri != NULL); slen = strlen(uri); pos = strlen(AFS_URI_PREFIX); if (0 != strncmp(uri, AFS_URI_PREFIX, pos)) return SYSERR; if (0 == strncmp(&uri[pos], SEARCH_INFIX, strlen(SEARCH_INFIX))) pos += strlen(SEARCH_INFIX); if ( (slen == pos) || (uri[slen-1] == '+') || (uri[pos] == '+') ) return SYSERR; /* no keywords / malformed */ ret = 1; for (i=pos;i=pos;i--) { if (dup[i] == '+') { (*keywords)[--ret] = STRDUP(&dup[i+1]); dup[i] = '\0'; } } (*keywords)[--ret] = STRDUP(&dup[pos]); FREE(dup); return iret; } /** * Parses an AFS namespace / subspace identifier URI. * * @param uri an uri string * @param namespace set to the namespace ID * @param identifier set to the ID in the namespace * @return OK on success, SYSERR if this is not a namespace URI */ int parseSubspaceURI(const char * uri, HashCode160 * namespace, HashCode160 * identifier) { unsigned int pos; size_t slen; char * up; GNUNET_ASSERT(uri != NULL); slen = strlen(uri); pos = strlen(AFS_URI_PREFIX); if (0 != strncmp(uri, AFS_URI_PREFIX, pos)) return SYSERR; if (0 == strncmp(&uri[pos], SUBSPACE_INFIX, strlen(SUBSPACE_INFIX))) pos += strlen(SUBSPACE_INFIX); if ( (slen != pos+2*sizeof(EncName)-1) || (uri[pos+sizeof(EncName)-1] != '/') ) return SYSERR; up = STRDUP(uri); up[pos+sizeof(EncName)-1] = '\0'; if ( (OK != enc2hash(&up[pos], namespace)) || (OK != enc2hash(&up[pos+sizeof(EncName)], identifier)) ) { FREE(up); return SYSERR; } FREE(up); return OK; } /** * Parses an URI that identifies a file * * @param uri an uri string * @param fi the file identifier * @return OK on success, SYSERR if this is not a file URI */ int parseFileURI(const char * uri, FileIdentifier * fi) { unsigned int pos; size_t slen; char * dup; GNUNET_ASSERT(uri != NULL); slen = strlen(uri); pos = strlen(AFS_URI_PREFIX); if (0 != strncmp(uri, AFS_URI_PREFIX, pos)) return SYSERR; if (0 == strncmp(&uri[pos], FILE_INFIX, strlen(FILE_INFIX))) pos += strlen(FILE_INFIX); if ( (slen < pos+2*sizeof(EncName)+2) || (uri[pos+sizeof(EncName)-1] != '.') || (uri[pos+sizeof(EncName)*2-1] != '.') ) return SYSERR; dup = STRDUP(uri); dup[pos+sizeof(EncName)-1] = '\0'; dup[pos+sizeof(EncName)*2-1] = '\0'; if ( (OK != enc2hash(&dup[pos], &fi->chk.key)) || (OK != enc2hash(&dup[pos+sizeof(EncName)], &fi->chk.query)) || (2 != sscanf(&dup[pos+sizeof(EncName)*2], "%X.%u", &fi->crc, &fi->file_length)) ) { FREE(dup); return SYSERR; } FREE(dup); fi->crc = htonl(fi->crc); fi->file_length = htonl(fi->file_length); return OK; } /** * Generate a keyword URI. * @return NULL on error (i.e. keywordCount == 0) */ char * createKeywordURI(char ** keywords, unsigned int keywordCount) { size_t n; char * ret; unsigned int i; #if CREATE_SHORT_URIS n = keywordCount + strlen(AFS_URI_PREFIX); #else n = keywordCount + strlen(AFS_URI_PREFIX) + strlen(SEARCH_INFIX); #endif for (i=0;ichk.key, &keyhash); hash2enc(&fi->chk.query, &queryhash); #if CREATE_SHORT_URIS n = strlen(AFS_URI_PREFIX)+2*sizeof(EncName)+8+16+32; #else n = strlen(AFS_URI_PREFIX)+2*sizeof(EncName)+8+16+32+strlen(FILE_INFIX); #endif ret = MALLOC(n); #if CREATE_SHORT_URIS SNPRINTF(ret, n, "%s%s.%s.%08X.%u", AFS_URI_PREFIX, (char*)&keyhash, (char*)&queryhash, ntohl(fi->crc), ntohl(fi->file_length)); #else SNPRINTF(ret, n, "%s%s%s.%s.%08X.%u", AFS_URI_PREFIX, FILE_INFIX, (char*)&keyhash, (char*)&queryhash, ntohl(fi->crc), ntohl(fi->file_length)); #endif return ret; } /* end of uri.c */