GNUnet  0.10.x
fs_uri.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2003--2014 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
20 
83 #include "platform.h"
84 #include "gnunet_fs_service.h"
85 #include "gnunet_signatures.h"
86 #include "fs_api.h"
87 #include <unitypes.h>
88 #include <unicase.h>
89 #include <uniconv.h>
90 #include <unistr.h>
91 #include <unistdio.h>
92 
93 
102 int
104  struct GNUNET_HashCode *key)
105 {
106  switch (uri->type)
107  {
108  case GNUNET_FS_URI_CHK:
109  *key = uri->data.chk.chk.query;
110  return GNUNET_OK;
111 
112  case GNUNET_FS_URI_SKS:
113  GNUNET_CRYPTO_hash(uri->data.sks.identifier,
114  strlen(uri->data.sks.identifier),
115  key);
116  return GNUNET_OK;
117 
118  case GNUNET_FS_URI_KSK:
119  if (uri->data.ksk.keywordCount > 0)
120  {
121  GNUNET_CRYPTO_hash(uri->data.ksk.keywords[0],
122  strlen(uri->data.ksk.keywords[0]),
123  key);
124  return GNUNET_OK;
125  }
126  else
127  {
128  memset(key, 0, sizeof(struct GNUNET_HashCode));
129  return GNUNET_SYSERR;
130  }
131  break;
132 
133  case GNUNET_FS_URI_LOC:
135  sizeof(struct FileIdentifier) +
136  sizeof(struct GNUNET_PeerIdentity),
137  key);
138  return GNUNET_OK;
139 
140  default:
141  memset(key, 0, sizeof(struct GNUNET_HashCode));
142  return GNUNET_SYSERR;
143  }
144 }
145 
146 
154 char *
156 {
157  size_t n;
158  char *ret;
159  unsigned int i;
160  const char *keyword;
161  char **keywords;
162  unsigned int keywordCount;
163 
164  if ((NULL == uri) || (GNUNET_FS_URI_KSK != uri->type))
165  {
166  GNUNET_break(0);
167  return NULL;
168  }
169  keywords = uri->data.ksk.keywords;
170  keywordCount = uri->data.ksk.keywordCount;
171  n = keywordCount + 1;
172  for (i = 0; i < keywordCount; i++)
173  {
174  keyword = keywords[i];
175  n += strlen(keyword) - 1;
176  if (NULL != strstr(&keyword[1], " "))
177  n += 2;
178  if (keyword[0] == '+')
179  n++;
180  }
181  ret = GNUNET_malloc(n);
182  strcpy(ret, "");
183  for (i = 0; i < keywordCount; i++)
184  {
185  keyword = keywords[i];
186  if (NULL != strstr(&keyword[1], " "))
187  {
188  strcat(ret, "\"");
189  if (keyword[0] == '+')
190  strcat(ret, keyword);
191  else
192  strcat(ret, &keyword[1]);
193  strcat(ret, "\"");
194  }
195  else
196  {
197  if (keyword[0] == '+')
198  strcat(ret, keyword);
199  else
200  strcat(ret, &keyword[1]);
201  }
202  strcat(ret, " ");
203  }
204  return ret;
205 }
206 
207 
218 static char *
219 percent_decode_keyword(const char *in, char **emsg)
220 {
221  char *out;
222  char *ret;
223  unsigned int rpos;
224  unsigned int wpos;
225  unsigned int hx;
226 
227  out = GNUNET_strdup(in);
228  rpos = 0;
229  wpos = 0;
230  while (out[rpos] != '\0')
231  {
232  if (out[rpos] == '%')
233  {
234  if (1 != sscanf(&out[rpos + 1], "%2X", &hx))
235  {
236  GNUNET_free(out);
237  *emsg = GNUNET_strdup(
238  _(/* xgettext:no-c-format */
239  "Malformed KSK URI (`%' must be followed by HEX number)"));
240  return NULL;
241  }
242  rpos += 3;
243  if (hx == '"')
244  continue; /* skip double quote */
245  out[wpos++] = (char)hx;
246  }
247  else
248  {
249  out[wpos++] = out[rpos++];
250  }
251  }
252  out[wpos] = '\0';
253  if (out[0] == '+')
254  {
255  ret = GNUNET_strdup(out);
256  }
257  else
258  {
259  /* need to prefix with space */
260  ret = GNUNET_malloc(strlen(out) + 2);
261  strcpy(ret, " ");
262  strcat(ret, out);
263  }
264  GNUNET_free(out);
265  return ret;
266 }
267 
268 #define GNUNET_FS_URI_KSK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_KSK_INFIX
269 
277 static struct GNUNET_FS_Uri *
278 uri_ksk_parse(const char *s, char **emsg)
279 {
280  struct GNUNET_FS_Uri *ret;
281  char **keywords;
282  unsigned int pos;
283  int max;
284  int iret;
285  int i;
286  size_t slen;
287  char *dup;
288  int saw_quote;
289 
290  slen = strlen(s);
291  pos = strlen(GNUNET_FS_URI_KSK_PREFIX);
292  if ((slen <= pos) || (0 != strncmp(s, GNUNET_FS_URI_KSK_PREFIX, pos)))
293  return NULL; /* not KSK URI */
294  if ((s[slen - 1] == '+') || (s[pos] == '+'))
295  {
296  *emsg =
297  GNUNET_strdup(_("Malformed KSK URI (must not begin or end with `+')"));
298  return NULL;
299  }
300  max = 1;
301  saw_quote = 0;
302  for (i = pos; i < slen; i++)
303  {
304  if ((s[i] == '%') && (&s[i] == strstr(&s[i], "%22")))
305  {
306  saw_quote = (saw_quote + 1) % 2;
307  i += 3;
308  continue;
309  }
310  if ((s[i] == '+') && (saw_quote == 0))
311  {
312  max++;
313  if (s[i - 1] == '+')
314  {
315  *emsg = GNUNET_strdup(_("Malformed KSK URI (`++' not allowed)"));
316  return NULL;
317  }
318  }
319  }
320  if (saw_quote == 1)
321  {
322  *emsg = GNUNET_strdup(_("Malformed KSK URI (quotes not balanced)"));
323  return NULL;
324  }
325  iret = max;
326  dup = GNUNET_strdup(s);
327  keywords = GNUNET_new_array(max, char *);
328  for (i = slen - 1; i >= (int)pos; i--)
329  {
330  if ((s[i] == '%') && (&s[i] == strstr(&s[i], "%22")))
331  {
332  saw_quote = (saw_quote + 1) % 2;
333  continue;
334  }
335  if ((dup[i] == '+') && (saw_quote == 0))
336  {
337  keywords[--max] = percent_decode_keyword(&dup[i + 1], emsg);
338  if (NULL == keywords[max])
339  goto CLEANUP;
340  dup[i] = '\0';
341  }
342  }
343  keywords[--max] = percent_decode_keyword(&dup[pos], emsg);
344  if (NULL == keywords[max])
345  goto CLEANUP;
346  GNUNET_assert(0 == max);
347  GNUNET_free(dup);
348  ret = GNUNET_new(struct GNUNET_FS_Uri);
349  ret->type = GNUNET_FS_URI_KSK;
350  ret->data.ksk.keywordCount = iret;
351  ret->data.ksk.keywords = keywords;
352  return ret;
353 CLEANUP:
354  for (i = 0; i < max; i++)
355  GNUNET_free_non_null(keywords[i]);
356  GNUNET_free(keywords);
357  GNUNET_free(dup);
358  return NULL;
359 }
360 
361 
362 #define GNUNET_FS_URI_SKS_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_SKS_INFIX
363 
371 static struct GNUNET_FS_Uri *
372 uri_sks_parse(const char *s, char **emsg)
373 {
374  struct GNUNET_FS_Uri *ret;
376  size_t pos;
377  char *end;
378 
379  pos = strlen(GNUNET_FS_URI_SKS_PREFIX);
380  if ((strlen(s) <= pos) || (0 != strncmp(s, GNUNET_FS_URI_SKS_PREFIX, pos)))
381  return NULL; /* not an SKS URI */
382  end = strchr(&s[pos], '/');
383  if ((NULL == end) ||
385  end - &s[pos],
386  &ns,
387  sizeof(ns))))
388  {
389  *emsg = GNUNET_strdup(_("Malformed SKS URI (wrong syntax)"));
390  return NULL; /* malformed */
391  }
392  end++; /* skip over '/' */
393  ret = GNUNET_new(struct GNUNET_FS_Uri);
394  ret->type = GNUNET_FS_URI_SKS;
395  ret->data.sks.ns = ns;
396  ret->data.sks.identifier = GNUNET_strdup(end);
397  return ret;
398 }
399 
400 #define GNUNET_FS_URI_CHK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX
401 
402 
410 static struct GNUNET_FS_Uri *
411 uri_chk_parse(const char *s, char **emsg)
412 {
413  struct GNUNET_FS_Uri *ret;
414  struct FileIdentifier fi;
415  unsigned int pos;
416  unsigned long long flen;
417  size_t slen;
418  char h1[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)];
419  char h2[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)];
420 
421  slen = strlen(s);
422  pos = strlen(GNUNET_FS_URI_CHK_PREFIX);
423  if ((slen < pos + 2 * sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) ||
424  (0 != strncmp(s, GNUNET_FS_URI_CHK_PREFIX, pos)))
425  return NULL; /* not a CHK URI */
426  if ((s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') ||
427  (s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.'))
428  {
429  *emsg = GNUNET_strdup(_("Malformed CHK URI (wrong syntax)"));
430  return NULL;
431  }
432  GNUNET_memcpy(h1, &s[pos], sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded));
433  h1[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
434  GNUNET_memcpy(h2,
435  &s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)],
436  sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded));
437  h2[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
438 
439  if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string(h1, &fi.chk.key)) ||
441  (1 !=
442  sscanf(&s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2],
443  "%llu",
444  &flen)))
445  {
446  *emsg = GNUNET_strdup(_("Malformed CHK URI (failed to decode CHK)"));
447  return NULL;
448  }
449  fi.file_length = GNUNET_htonll(flen);
450  ret = GNUNET_new(struct GNUNET_FS_Uri);
451  ret->type = GNUNET_FS_URI_CHK;
452  ret->data.chk = fi;
453  return ret;
454 }
455 
456 
468 
473 
478 
483 };
485 
486 
487 #define GNUNET_FS_URI_LOC_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_LOC_INFIX
488 
489 #define SIGNATURE_ASCII_LENGTH 103
490 
499 static struct GNUNET_FS_Uri *
500 uri_loc_parse(const char *s, char **emsg)
501 {
502  struct GNUNET_FS_Uri *uri;
503  char h1[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)];
504  char h2[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)];
505  unsigned int pos;
506  unsigned int npos;
507  unsigned long long exptime;
508  unsigned long long flen;
509  struct GNUNET_TIME_Absolute et;
510  struct GNUNET_CRYPTO_EddsaSignature sig;
511  struct LocUriAssembly ass;
512  size_t slen;
513 
514  slen = strlen(s);
515  pos = strlen(GNUNET_FS_URI_LOC_PREFIX);
516  if ((slen < pos + 2 * sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) ||
517  (0 != strncmp(s, GNUNET_FS_URI_LOC_PREFIX, pos)))
518  return NULL; /* not a LOC URI */
519  if ((s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') ||
520  (s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.'))
521  {
522  *emsg = GNUNET_strdup(_("LOC URI malformed (wrong syntax)"));
523  return NULL;
524  }
525  GNUNET_memcpy(h1, &s[pos], sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded));
526  h1[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
527  GNUNET_memcpy(h2,
528  &s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)],
529  sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded));
530  h2[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
531 
532  if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string(h1, &ass.fi.chk.key)) ||
534  (1 !=
535  sscanf(&s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2],
536  "%llu",
537  &flen)))
538  {
539  *emsg = GNUNET_strdup(_("LOC URI malformed (no CHK)"));
540  return NULL;
541  }
542  ass.fi.file_length = GNUNET_htonll(flen);
543 
544  npos = pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2;
545  while ((s[npos] != '\0') && (s[npos] != '.'))
546  npos++;
547  if (s[npos] == '\0')
548  {
549  *emsg = GNUNET_strdup(_("LOC URI malformed (missing LOC)"));
550  goto ERR;
551  }
552  npos++;
553  if ((strlen(&s[npos]) <= GNUNET_CRYPTO_PKEY_ASCII_LENGTH + 1) ||
554  ('.' != s[npos + GNUNET_CRYPTO_PKEY_ASCII_LENGTH]))
555  {
556  *emsg =
557  GNUNET_strdup(_("LOC URI malformed (wrong syntax for public key)"));
558  }
559  if (
560  GNUNET_OK !=
563  &ass.peer.public_key))
564  {
565  *emsg =
566  GNUNET_strdup(_("LOC URI malformed (could not decode public key)"));
567  goto ERR;
568  }
570  if (s[npos++] != '.')
571  {
572  *emsg = GNUNET_strdup(_("LOC URI malformed (could not find signature)"));
573  goto ERR;
574  }
575  if ((strlen(&s[npos]) <= SIGNATURE_ASCII_LENGTH + 1) ||
576  ('.' != s[npos + SIGNATURE_ASCII_LENGTH]))
577  {
578  *emsg =
579  GNUNET_strdup(_("LOC URI malformed (wrong syntax for signature)"));
580  goto ERR;
581  }
582  if (GNUNET_OK !=
585  &sig,
586  sizeof(
588  {
589  *emsg =
590  GNUNET_strdup(_("LOC URI malformed (could not decode signature)"));
591  goto ERR;
592  }
593  npos += SIGNATURE_ASCII_LENGTH;
594  if (s[npos++] != '.')
595  {
596  *emsg = GNUNET_strdup(
597  _("LOC URI malformed (wrong syntax for expiration time)"));
598  goto ERR;
599  }
600  if (1 != sscanf(&s[npos], "%llu", &exptime))
601  {
602  *emsg =
603  GNUNET_strdup(_("LOC URI malformed (could not parse expiration time)"));
604  goto ERR;
605  }
606  ass.purpose.size = htonl(sizeof(struct LocUriAssembly));
608  et.abs_value_us = exptime * 1000LL * 1000LL;
610  if (GNUNET_OK !=
612  &ass.purpose,
613  &sig,
614  &ass.peer.public_key))
615  {
616  *emsg =
617  GNUNET_strdup(_("LOC URI malformed (signature failed validation)"));
618  goto ERR;
619  }
620  uri = GNUNET_new(struct GNUNET_FS_Uri);
621  uri->type = GNUNET_FS_URI_LOC;
622  uri->data.loc.fi = ass.fi;
623  uri->data.loc.peer = ass.peer;
624  uri->data.loc.expirationTime = et;
625  uri->data.loc.contentSignature = sig;
626 
627  return uri;
628 ERR:
629  return NULL;
630 }
631 
632 
640 struct GNUNET_FS_Uri *
641 GNUNET_FS_uri_parse(const char *uri, char **emsg)
642 {
643  struct GNUNET_FS_Uri *ret;
644  char *msg;
645 
646  if (NULL == uri)
647  {
648  GNUNET_break(0);
649  if (NULL != emsg)
650  *emsg = GNUNET_strdup(_("invalid argument"));
651  return NULL;
652  }
653  if (NULL == emsg)
654  emsg = &msg;
655  *emsg = NULL;
656  if ((NULL != (ret = uri_chk_parse(uri, emsg))) ||
657  (NULL != (ret = uri_ksk_parse(uri, emsg))) ||
658  (NULL != (ret = uri_sks_parse(uri, emsg))) ||
659  (NULL != (ret = uri_loc_parse(uri, emsg))))
660  return ret;
661  if (NULL == *emsg)
662  *emsg = GNUNET_strdup(_("Unrecognized URI type"));
663  if (emsg == &msg)
664  GNUNET_free(msg);
665  return NULL;
666 }
667 
668 
674 void
676 {
677  unsigned int i;
678 
679  switch (uri->type)
680  {
681  case GNUNET_FS_URI_KSK:
682  for (i = 0; i < uri->data.ksk.keywordCount; i++)
683  GNUNET_free(uri->data.ksk.keywords[i]);
684  GNUNET_array_grow(uri->data.ksk.keywords, uri->data.ksk.keywordCount, 0);
685  break;
686 
687  case GNUNET_FS_URI_SKS:
688  GNUNET_free(uri->data.sks.identifier);
689  break;
690 
691  case GNUNET_FS_URI_LOC:
692  break;
693 
694  default:
695  /* do nothing */
696  break;
697  }
698  GNUNET_free(uri);
699 }
700 
701 
708 unsigned int
710 {
711  if (uri->type != GNUNET_FS_URI_KSK)
712  return 0;
713  return uri->data.ksk.keywordCount;
714 }
715 
716 
726 int
729  void *iterator_cls)
730 {
731  unsigned int i;
732  char *keyword;
733 
734  if (uri->type != GNUNET_FS_URI_KSK)
735  return -1;
736  if (NULL == iterator)
737  return uri->data.ksk.keywordCount;
738  for (i = 0; i < uri->data.ksk.keywordCount; i++)
739  {
740  keyword = uri->data.ksk.keywords[i];
741  /* first character of keyword indicates
742  * if it is mandatory or not */
743  if (GNUNET_OK != iterator(iterator_cls, &keyword[1], keyword[0] == '+'))
744  return i;
745  }
746  return i;
747 }
748 
749 
758 void
760  const char *keyword,
761  int is_mandatory)
762 {
763  unsigned int i;
764  const char *old;
765  char *n;
766 
768  for (i = 0; i < uri->data.ksk.keywordCount; i++)
769  {
770  old = uri->data.ksk.keywords[i];
771  if (0 == strcmp(&old[1], keyword))
772  return;
773  }
774  GNUNET_asprintf(&n, is_mandatory ? "+%s" : " %s", keyword);
775  GNUNET_array_append(uri->data.ksk.keywords, uri->data.ksk.keywordCount, n);
776 }
777 
778 
786 void
788  const char *keyword)
789 {
790  unsigned int i;
791  char *old;
792 
794  for (i = 0; i < uri->data.ksk.keywordCount; i++)
795  {
796  old = uri->data.ksk.keywords[i];
797  if (0 == strcmp(&old[1], keyword))
798  {
799  uri->data.ksk.keywords[i] =
800  uri->data.ksk.keywords[uri->data.ksk.keywordCount - 1];
801  GNUNET_array_grow(uri->data.ksk.keywords,
802  uri->data.ksk.keywordCount,
803  uri->data.ksk.keywordCount - 1);
804  GNUNET_free(old);
805  return;
806  }
807  }
808 }
809 
810 
818 int
820  struct GNUNET_PeerIdentity *peer)
821 {
822  if (uri->type != GNUNET_FS_URI_LOC)
823  return GNUNET_SYSERR;
824  *peer = uri->data.loc.peer;
825  return GNUNET_OK;
826 }
827 
828 
837 {
839  return uri->data.loc.expirationTime;
840 }
841 
842 
849 struct GNUNET_FS_Uri *
851 {
852  struct GNUNET_FS_Uri *ret;
853 
854  if (uri->type != GNUNET_FS_URI_LOC)
855  return NULL;
856  ret = GNUNET_new(struct GNUNET_FS_Uri);
857  ret->type = GNUNET_FS_URI_CHK;
858  ret->data.chk = uri->data.loc.fi;
859  return ret;
860 }
861 
862 
875 struct GNUNET_FS_Uri *
877  const struct GNUNET_CRYPTO_EddsaPrivateKey *sign_key,
878  struct GNUNET_TIME_Absolute expiration_time)
879 {
880  struct GNUNET_FS_Uri *uri;
881  struct GNUNET_CRYPTO_EddsaPublicKey my_public_key;
882  struct LocUriAssembly ass;
883  struct GNUNET_TIME_Absolute et;
884 
885  if (GNUNET_FS_URI_CHK != base_uri->type)
886  return NULL;
887  /* we round expiration time to full seconds for SKS URIs */
888  et.abs_value_us = (expiration_time.abs_value_us / 1000000LL) * 1000000LL;
889  GNUNET_CRYPTO_eddsa_key_get_public(sign_key, &my_public_key);
890  ass.purpose.size = htonl(sizeof(struct LocUriAssembly));
893  ass.fi = base_uri->data.chk;
894  ass.peer.public_key = my_public_key;
895  uri = GNUNET_new(struct GNUNET_FS_Uri);
896  uri->type = GNUNET_FS_URI_LOC;
897  uri->data.loc.fi = base_uri->data.chk;
898  uri->data.loc.expirationTime = et;
899  uri->data.loc.peer.public_key = my_public_key;
901  GNUNET_CRYPTO_eddsa_sign(sign_key,
902  &ass.purpose,
903  &uri->data.loc.contentSignature));
904  return uri;
905 }
906 
907 
915 struct GNUNET_FS_Uri *
917  const char *id)
918 {
919  struct GNUNET_FS_Uri *ns_uri;
920 
921  ns_uri = GNUNET_new(struct GNUNET_FS_Uri);
922  ns_uri->type = GNUNET_FS_URI_SKS;
923  ns_uri->data.sks.ns = *ns;
924  ns_uri->data.sks.identifier = GNUNET_strdup(id);
925  return ns_uri;
926 }
927 
928 
938 struct GNUNET_FS_Uri *
940  const struct GNUNET_FS_Uri *u2)
941 {
942  struct GNUNET_FS_Uri *ret;
943  unsigned int kc;
944  unsigned int i;
945  unsigned int j;
946  int found;
947  const char *kp;
948  char **kl;
949 
950  if ((u1 == NULL) && (u2 == NULL))
951  return NULL;
952  if (u1 == NULL)
953  return GNUNET_FS_uri_dup(u2);
954  if (u2 == NULL)
955  return GNUNET_FS_uri_dup(u1);
956  if ((u1->type != GNUNET_FS_URI_KSK) || (u2->type != GNUNET_FS_URI_KSK))
957  {
958  GNUNET_break(0);
959  return NULL;
960  }
961  kc = u1->data.ksk.keywordCount;
962  kl = GNUNET_new_array(kc + u2->data.ksk.keywordCount, char *);
963  for (i = 0; i < u1->data.ksk.keywordCount; i++)
964  kl[i] = GNUNET_strdup(u1->data.ksk.keywords[i]);
965  for (i = 0; i < u2->data.ksk.keywordCount; i++)
966  {
967  kp = u2->data.ksk.keywords[i];
968  found = 0;
969  for (j = 0; j < u1->data.ksk.keywordCount; j++)
970  if (0 == strcmp(kp + 1, kl[j] + 1))
971  {
972  found = 1;
973  if (kp[0] == '+')
974  kl[j][0] = '+';
975  break;
976  }
977  if (0 == found)
978  kl[kc++] = GNUNET_strdup(kp);
979  }
980  ret = GNUNET_new(struct GNUNET_FS_Uri);
981  ret->type = GNUNET_FS_URI_KSK;
982  ret->data.ksk.keywordCount = kc;
983  ret->data.ksk.keywords = kl;
984  return ret;
985 }
986 
987 
994 struct GNUNET_FS_Uri *
996 {
997  struct GNUNET_FS_Uri *ret;
998  unsigned int i;
999 
1000  if (uri == NULL)
1001  return NULL;
1002  ret = GNUNET_new(struct GNUNET_FS_Uri);
1003  GNUNET_memcpy(ret, uri, sizeof(struct GNUNET_FS_Uri));
1004  switch (ret->type)
1005  {
1006  case GNUNET_FS_URI_KSK:
1007  if (ret->data.ksk.keywordCount >=
1008  GNUNET_MAX_MALLOC_CHECKED / sizeof(char *))
1009  {
1010  GNUNET_break(0);
1011  GNUNET_free(ret);
1012  return NULL;
1013  }
1014  if (ret->data.ksk.keywordCount > 0)
1015  {
1016  ret->data.ksk.keywords =
1017  GNUNET_new_array(ret->data.ksk.keywordCount, char *);
1018  for (i = 0; i < ret->data.ksk.keywordCount; i++)
1019  ret->data.ksk.keywords[i] = GNUNET_strdup(uri->data.ksk.keywords[i]);
1020  }
1021  else
1022  ret->data.ksk.keywords = NULL; /* just to be sure */
1023  break;
1024 
1025  case GNUNET_FS_URI_SKS:
1026  ret->data.sks.identifier = GNUNET_strdup(uri->data.sks.identifier);
1027  break;
1028 
1029  case GNUNET_FS_URI_LOC:
1030  break;
1031 
1032  default:
1033  break;
1034  }
1035  return ret;
1036 }
1037 
1038 
1056 struct GNUNET_FS_Uri *
1057 GNUNET_FS_uri_ksk_create(const char *keywords, char **emsg)
1058 {
1059  char **keywordarr;
1060  unsigned int num_Words;
1061  int inWord;
1062  char *pos;
1063  struct GNUNET_FS_Uri *uri;
1064  char *searchString;
1065  int saw_quote;
1066 
1067  if (keywords == NULL)
1068  {
1069  *emsg = GNUNET_strdup(_("No keywords specified!\n"));
1070  GNUNET_break(0);
1071  return NULL;
1072  }
1073  searchString = GNUNET_strdup(keywords);
1074  num_Words = 0;
1075  inWord = 0;
1076  saw_quote = 0;
1077  pos = searchString;
1078  while ('\0' != *pos)
1079  {
1080  if ((saw_quote == 0) && (isspace((unsigned char)*pos)))
1081  {
1082  inWord = 0;
1083  }
1084  else if (0 == inWord)
1085  {
1086  inWord = 1;
1087  ++num_Words;
1088  }
1089  if ('"' == *pos)
1090  saw_quote = (saw_quote + 1) % 2;
1091  pos++;
1092  }
1093  if (num_Words == 0)
1094  {
1095  GNUNET_free(searchString);
1096  *emsg = GNUNET_strdup(_("No keywords specified!\n"));
1097  return NULL;
1098  }
1099  if (saw_quote != 0)
1100  {
1101  GNUNET_free(searchString);
1102  *emsg = GNUNET_strdup(_("Number of double-quotes not balanced!\n"));
1103  return NULL;
1104  }
1105  keywordarr = GNUNET_new_array(num_Words, char *);
1106  num_Words = 0;
1107  inWord = 0;
1108  pos = searchString;
1109  while ('\0' != *pos)
1110  {
1111  if ((saw_quote == 0) && (isspace((unsigned char)*pos)))
1112  {
1113  inWord = 0;
1114  *pos = '\0';
1115  }
1116  else if (0 == inWord)
1117  {
1118  keywordarr[num_Words] = pos;
1119  inWord = 1;
1120  ++num_Words;
1121  }
1122  if ('"' == *pos)
1123  saw_quote = (saw_quote + 1) % 2;
1124  pos++;
1125  }
1126  uri =
1127  GNUNET_FS_uri_ksk_create_from_args(num_Words, (const char **)keywordarr);
1128  GNUNET_free(keywordarr);
1129  GNUNET_free(searchString);
1130  return uri;
1131 }
1132 
1133 
1151 struct GNUNET_FS_Uri *
1152 GNUNET_FS_uri_ksk_create_from_args(unsigned int argc, const char **argv)
1153 {
1154  unsigned int i;
1155  struct GNUNET_FS_Uri *uri;
1156  const char *keyword;
1157  char *val;
1158  const char *r;
1159  char *w;
1160  char *emsg;
1161 
1162  if (argc == 0)
1163  return NULL;
1164  /* allow URI to be given as one and only keyword and
1165  * handle accordingly */
1166  emsg = NULL;
1167  if ((argc == 1) && (strlen(argv[0]) > strlen(GNUNET_FS_URI_PREFIX)) &&
1168  (0 == strncmp(argv[0],
1170  strlen(GNUNET_FS_URI_PREFIX))) &&
1171  (NULL != (uri = GNUNET_FS_uri_parse(argv[0], &emsg))))
1172  return uri;
1173  GNUNET_free_non_null(emsg);
1174  uri = GNUNET_new(struct GNUNET_FS_Uri);
1175  uri->type = GNUNET_FS_URI_KSK;
1176  uri->data.ksk.keywordCount = argc;
1177  uri->data.ksk.keywords = GNUNET_new_array(argc, char *);
1178  for (i = 0; i < argc; i++)
1179  {
1180  keyword = argv[i];
1181  if (keyword[0] == '+')
1182  val = GNUNET_strdup(keyword);
1183  else
1184  GNUNET_asprintf(&val, " %s", keyword);
1185  r = val;
1186  w = val;
1187  while ('\0' != *r)
1188  {
1189  if ('"' == *r)
1190  r++;
1191  else
1192  *(w++) = *(r++);
1193  }
1194  *w = '\0';
1195  uri->data.ksk.keywords[i] = val;
1196  }
1197  return uri;
1198 }
1199 
1200 
1208 int
1210  const struct GNUNET_FS_Uri *u2)
1211 {
1212  int ret;
1213  unsigned int i;
1214  unsigned int j;
1215 
1216  GNUNET_assert(u1 != NULL);
1217  GNUNET_assert(u2 != NULL);
1218  if (u1->type != u2->type)
1219  return GNUNET_NO;
1220  switch (u1->type)
1221  {
1222  case GNUNET_FS_URI_CHK:
1223  if (0 ==
1224  memcmp(&u1->data.chk, &u2->data.chk, sizeof(struct FileIdentifier)))
1225  return GNUNET_YES;
1226  return GNUNET_NO;
1227 
1228  case GNUNET_FS_URI_SKS:
1229  if ((0 == memcmp(&u1->data.sks.ns,
1230  &u2->data.sks.ns,
1231  sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) &&
1232  (0 == strcmp(u1->data.sks.identifier, u2->data.sks.identifier)))
1233 
1234  return GNUNET_YES;
1235  return GNUNET_NO;
1236 
1237  case GNUNET_FS_URI_KSK:
1238  if (u1->data.ksk.keywordCount != u2->data.ksk.keywordCount)
1239  return GNUNET_NO;
1240  for (i = 0; i < u1->data.ksk.keywordCount; i++)
1241  {
1242  ret = GNUNET_NO;
1243  for (j = 0; j < u2->data.ksk.keywordCount; j++)
1244  {
1245  if (0 == strcmp(u1->data.ksk.keywords[i], u2->data.ksk.keywords[j]))
1246  {
1247  ret = GNUNET_YES;
1248  break;
1249  }
1250  }
1251  if (ret == GNUNET_NO)
1252  return GNUNET_NO;
1253  }
1254  return GNUNET_YES;
1255 
1256  case GNUNET_FS_URI_LOC:
1257  if (memcmp(&u1->data.loc,
1258  &u2->data.loc,
1259  sizeof(struct FileIdentifier) +
1260  sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey) +
1261  sizeof(struct GNUNET_TIME_Absolute) +
1262  sizeof(unsigned short) + sizeof(unsigned short)) != 0)
1263  return GNUNET_NO;
1264  return GNUNET_YES;
1265 
1266  default:
1267  return GNUNET_NO;
1268  }
1269 }
1270 
1271 
1278 int
1280 {
1281  return uri->type == GNUNET_FS_URI_SKS;
1282 }
1283 
1284 
1293 int
1296 {
1297  if (!GNUNET_FS_uri_test_sks(uri))
1298  {
1299  GNUNET_break(0);
1300  return GNUNET_SYSERR;
1301  }
1302  *pseudonym = uri->data.sks.ns;
1303  return GNUNET_OK;
1304 }
1305 
1306 
1313 char *
1315 {
1316  if (!GNUNET_FS_uri_test_sks(uri))
1317  {
1318  GNUNET_break(0);
1319  return NULL;
1320  }
1321  return GNUNET_strdup(uri->data.sks.identifier);
1322 }
1323 
1324 
1331 int
1333 {
1334 #if EXTRA_CHECKS
1335  unsigned int i;
1336 
1337  if (uri->type == GNUNET_FS_URI_KSK)
1338  {
1339  for (i = 0; i < uri->data.ksk.keywordCount; i++)
1340  GNUNET_assert(uri->data.ksk.keywords[i] != NULL);
1341  }
1342 #endif
1343  return uri->type == GNUNET_FS_URI_KSK;
1344 }
1345 
1346 
1353 int
1355 {
1356  return uri->type == GNUNET_FS_URI_CHK;
1357 }
1358 
1359 
1367 uint64_t
1369 {
1370  switch (uri->type)
1371  {
1372  case GNUNET_FS_URI_CHK:
1373  return GNUNET_ntohll(uri->data.chk.file_length);
1374 
1375  case GNUNET_FS_URI_LOC:
1376  return GNUNET_ntohll(uri->data.loc.fi.file_length);
1377 
1378  default:
1379  GNUNET_assert(0);
1380  }
1381  return 0; /* unreachable */
1382 }
1383 
1384 
1391 int
1393 {
1394  return uri->type == GNUNET_FS_URI_LOC;
1395 }
1396 
1397 
1407 static void
1408 insert_non_mandatory_keyword(const char *s, char **array, int index)
1409 {
1410  char *nkword;
1411 
1412  GNUNET_asprintf(&nkword,
1413  " %s", /* space to mark as 'non mandatory' */
1414  s);
1415  array[index] = nkword;
1416 }
1417 
1418 
1428 static int
1429 find_duplicate(const char *s, const char **array, int array_length)
1430 {
1431  int j;
1432 
1433  for (j = array_length - 1; j >= 0; j--)
1434  if (0 == strcmp(&array[j][1], s))
1435  return GNUNET_YES;
1436  return GNUNET_NO;
1437 }
1438 
1439 
1443 static char *
1445  const char *data,
1446  size_t data_len)
1447 {
1448  uint8_t *free_str = NULL;
1449  uint8_t *str_to_normalize = (uint8_t *)data;
1450  uint8_t *normalized;
1451  size_t r_len;
1452 
1453  if (str_to_normalize == NULL)
1454  return NULL;
1455  /* Don't trust libextractor */
1456  if (format == EXTRACTOR_METAFORMAT_UTF8)
1457  {
1458  free_str = (uint8_t *)u8_check((const uint8_t *)data, data_len);
1459  if (free_str == NULL)
1460  free_str = NULL;
1461  else
1463  }
1464  if (format == EXTRACTOR_METAFORMAT_C_STRING)
1465  {
1466  free_str = u8_strconv_from_encoding(data,
1467  locale_charset(),
1468  iconveh_escape_sequence);
1469  if (free_str == NULL)
1470  return NULL;
1471  }
1472 
1473  normalized = u8_tolower(str_to_normalize,
1474  strlen((char *)str_to_normalize),
1475  NULL,
1476  UNINORM_NFD,
1477  NULL,
1478  &r_len);
1479  /* free_str is allocated by libunistring internally, use free() */
1480  if (free_str != NULL)
1481  free(free_str);
1482  if (normalized != NULL)
1483  {
1484  /* u8_tolower allocates a non-NULL-terminated string! */
1485  free_str = GNUNET_malloc(r_len + 1);
1486  GNUNET_memcpy(free_str, normalized, r_len);
1487  free_str[r_len] = '\0';
1488  free(normalized);
1489  normalized = free_str;
1490  }
1491  return (char *)normalized;
1492 }
1493 
1494 
1499 static size_t
1500 u8_strcount(const uint8_t *s)
1501 {
1502  size_t count;
1503  ucs4_t c;
1504 
1505  GNUNET_assert(s != NULL);
1506  if (s[0] == 0)
1507  return 0;
1508  for (count = 0; s != NULL; count++)
1509  s = u8_next(&c, s);
1510  return count - 1;
1511 }
1512 
1513 
1530 static int
1531 get_keywords_from_parens(const char *s, char **array, int index)
1532 {
1533  int count = 0;
1534  char *open_paren;
1535  char *close_paren;
1536  char *ss;
1537  char tmp;
1538 
1539  if (NULL == s)
1540  return 0;
1541  ss = GNUNET_strdup(s);
1542  open_paren = ss - 1;
1543  while (NULL != (open_paren = strpbrk(open_paren + 1, "[{(")))
1544  {
1545  int match = 0;
1546 
1547  close_paren = strpbrk(open_paren + 1, "]})");
1548  if (NULL == close_paren)
1549  continue;
1550  switch (open_paren[0])
1551  {
1552  case '[':
1553  if (']' == close_paren[0])
1554  match = 1;
1555  break;
1556 
1557  case '{':
1558  if ('}' == close_paren[0])
1559  match = 1;
1560  break;
1561 
1562  case '(':
1563  if (')' == close_paren[0])
1564  match = 1;
1565  break;
1566 
1567  default:
1568  break;
1569  }
1570  if (match && (close_paren - open_paren > 1))
1571  {
1572  tmp = close_paren[0];
1573  close_paren[0] = '\0';
1574  /* Keywords must be at least 3 characters long */
1575  if (u8_strcount((const uint8_t *)&open_paren[1]) <= 2)
1576  {
1577  close_paren[0] = tmp;
1578  continue;
1579  }
1580  if (NULL != array)
1581  {
1582  char *normalized;
1583  if (GNUNET_NO == find_duplicate((const char *)&open_paren[1],
1584  (const char **)array,
1585  index + count))
1586  {
1587  insert_non_mandatory_keyword((const char *)&open_paren[1],
1588  array,
1589  index + count);
1590  count++;
1591  }
1593  &open_paren[1],
1594  close_paren - &open_paren[1]);
1595  if (normalized != NULL)
1596  {
1597  if (GNUNET_NO == find_duplicate((const char *)normalized,
1598  (const char **)array,
1599  index + count))
1600  {
1601  insert_non_mandatory_keyword((const char *)normalized,
1602  array,
1603  index + count);
1604  count++;
1605  }
1606  GNUNET_free(normalized);
1607  }
1608  }
1609  else
1610  count++;
1611  close_paren[0] = tmp;
1612  }
1613  }
1614  GNUNET_free(ss);
1615  return count;
1616 }
1617 
1618 
1622 #define TOKENS "_. /-!?#&+@\"\'\\;:,()[]{}$<>|"
1623 
1638 static int
1639 get_keywords_from_tokens(const char *s, char **array, int index)
1640 {
1641  char *p;
1642  char *ss;
1643  int seps = 0;
1644 
1645  ss = GNUNET_strdup(s);
1646  for (p = strtok(ss, TOKENS); p != NULL; p = strtok(NULL, TOKENS))
1647  {
1648  /* Keywords must be at least 3 characters long */
1649  if (u8_strcount((const uint8_t *)p) <= 2)
1650  continue;
1651  if (NULL != array)
1652  {
1653  char *normalized;
1654  if (GNUNET_NO == find_duplicate(p, (const char **)array, index + seps))
1655  {
1656  insert_non_mandatory_keyword(p, array, index + seps);
1657  seps++;
1658  }
1659  normalized =
1661  if (normalized != NULL)
1662  {
1663  if (GNUNET_NO == find_duplicate((const char *)normalized,
1664  (const char **)array,
1665  index + seps))
1666  {
1667  insert_non_mandatory_keyword((const char *)normalized,
1668  array,
1669  index + seps);
1670  seps++;
1671  }
1672  GNUNET_free(normalized);
1673  }
1674  }
1675  else
1676  seps++;
1677  }
1678  GNUNET_free(ss);
1679  return seps;
1680 }
1681 #undef TOKENS
1682 
1683 
1701 static int
1703  const char *plugin_name,
1704  enum EXTRACTOR_MetaType type,
1705  enum EXTRACTOR_MetaFormat format,
1706  const char *data_mime_type,
1707  const char *data,
1708  size_t data_len)
1709 {
1710  struct GNUNET_FS_Uri *uri = cls;
1711  char *normalized_data;
1712  const char *sep;
1713 
1714  if ((format != EXTRACTOR_METAFORMAT_UTF8) &&
1715  (format != EXTRACTOR_METAFORMAT_C_STRING))
1716  return 0;
1717  /* Keywords must be at least 3 characters long
1718  * If given non-utf8 string it will, most likely, find it to be invalid,
1719  * and will return the length of its valid part, skipping the keyword.
1720  * If it does - fix the extractor, not this check!
1721  */
1722  if (u8_strcount((const uint8_t *)data) <= 2)
1723  return 0;
1724  if ((EXTRACTOR_METATYPE_MIMETYPE == type) &&
1725  (NULL != (sep = memchr(data, '/', data_len))) && (sep != data))
1726  {
1727  char *xtra;
1728 
1729  GNUNET_asprintf(&xtra, "mimetype:%.*s", (int)(sep - data), data);
1730  if (!find_duplicate(xtra,
1731  (const char **)uri->data.ksk.keywords,
1732  uri->data.ksk.keywordCount))
1733  {
1735  uri->data.ksk.keywords,
1736  uri->data.ksk.keywordCount);
1737  uri->data.ksk.keywordCount++;
1738  }
1739  GNUNET_free(xtra);
1740  }
1741 
1742  normalized_data = normalize_metadata(format, data, data_len);
1743  if (!find_duplicate(data,
1744  (const char **)uri->data.ksk.keywords,
1745  uri->data.ksk.keywordCount))
1746  {
1748  uri->data.ksk.keywords,
1749  uri->data.ksk.keywordCount);
1750  uri->data.ksk.keywordCount++;
1751  }
1752  if (NULL != normalized_data)
1753  {
1754  if (!find_duplicate(normalized_data,
1755  (const char **)uri->data.ksk.keywords,
1756  uri->data.ksk.keywordCount))
1757  {
1758  insert_non_mandatory_keyword(normalized_data,
1759  uri->data.ksk.keywords,
1760  uri->data.ksk.keywordCount);
1761  uri->data.ksk.keywordCount++;
1762  }
1763  GNUNET_free(normalized_data);
1764  }
1765  return 0;
1766 }
1767 
1768 
1777 struct GNUNET_FS_Uri *
1779  const struct GNUNET_CONTAINER_MetaData *md)
1780 {
1781  struct GNUNET_FS_Uri *ret;
1782  char *filename;
1783  char *full_name = NULL;
1784  char *ss;
1785  int ent;
1786  int tok_keywords = 0;
1787  int paren_keywords = 0;
1788 
1789  if (NULL == md)
1790  return NULL;
1791  ret = GNUNET_new(struct GNUNET_FS_Uri);
1792  ret->type = GNUNET_FS_URI_KSK;
1793  ent = GNUNET_CONTAINER_meta_data_iterate(md, NULL, NULL);
1794  if (ent > 0)
1795  {
1797  md,
1799  -1);
1800  if (NULL != full_name)
1801  {
1802  filename = full_name;
1803  while (NULL != (ss = strstr(filename, DIR_SEPARATOR_STR)))
1804  filename = ss + 1;
1805  tok_keywords = get_keywords_from_tokens(filename, NULL, 0);
1806  paren_keywords = get_keywords_from_parens(filename, NULL, 0);
1807  }
1808  /* x3 because there might be a normalized variant of every keyword,
1809  plus theoretically one more for mime... */
1810  ret->data.ksk.keywords =
1811  GNUNET_new_array((ent + tok_keywords + paren_keywords) * 3, char *);
1813  }
1814  if (tok_keywords > 0)
1815  ret->data.ksk.keywordCount +=
1816  get_keywords_from_tokens(filename,
1817  ret->data.ksk.keywords,
1818  ret->data.ksk.keywordCount);
1819  if (paren_keywords > 0)
1820  ret->data.ksk.keywordCount +=
1821  get_keywords_from_parens(filename,
1822  ret->data.ksk.keywords,
1823  ret->data.ksk.keywordCount);
1824  if (ent > 0)
1825  GNUNET_free_non_null(full_name);
1826  return ret;
1827 }
1828 
1829 
1834 static int
1836 {
1837  return(!((isalnum((unsigned char)c)) || (c == '-') || (c == '_') ||
1838  (c == '.') || (c == '~')));
1839 }
1840 
1841 
1848 static char *
1850 {
1851  char **keywords;
1852  unsigned int keywordCount;
1853  size_t n;
1854  char *ret;
1855  unsigned int i;
1856  unsigned int j;
1857  unsigned int wpos;
1858  size_t slen;
1859  const char *keyword;
1860 
1861  if (uri->type != GNUNET_FS_URI_KSK)
1862  return NULL;
1863  keywords = uri->data.ksk.keywords;
1864  keywordCount = uri->data.ksk.keywordCount;
1865  n = keywordCount + strlen(GNUNET_FS_URI_PREFIX) +
1866  strlen(GNUNET_FS_URI_KSK_INFIX) + 1;
1867  for (i = 0; i < keywordCount; i++)
1868  {
1869  keyword = keywords[i];
1870  slen = strlen(keyword);
1871  n += slen;
1872  for (j = 0; j < slen; j++)
1873  {
1874  if ((j == 0) && (keyword[j] == ' '))
1875  {
1876  n--;
1877  continue; /* skip leading space */
1878  }
1879  if (needs_percent(keyword[j]))
1880  n += 2; /* will use %-encoding */
1881  }
1882  }
1883  ret = GNUNET_malloc(n);
1884  strcpy(ret, GNUNET_FS_URI_PREFIX);
1885  strcat(ret, GNUNET_FS_URI_KSK_INFIX);
1886  wpos = strlen(ret);
1887  for (i = 0; i < keywordCount; i++)
1888  {
1889  keyword = keywords[i];
1890  slen = strlen(keyword);
1891  for (j = 0; j < slen; j++)
1892  {
1893  if ((j == 0) && (keyword[j] == ' '))
1894  continue; /* skip leading space */
1895  if (needs_percent(keyword[j]))
1896  {
1897  sprintf(&ret[wpos], "%%%02X", (unsigned char)keyword[j]);
1898  wpos += 3;
1899  }
1900  else
1901  {
1902  ret[wpos++] = keyword[j];
1903  }
1904  }
1905  if (i != keywordCount - 1)
1906  ret[wpos++] = '+';
1907  }
1908  return ret;
1909 }
1910 
1911 
1918 static char *
1920 {
1921  char *ret;
1922  char buf[1024];
1923 
1924  if (GNUNET_FS_URI_SKS != uri->type)
1925  return NULL;
1926  ret =
1928  sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
1929  buf,
1930  sizeof(buf));
1931  GNUNET_assert(NULL != ret);
1932  ret[0] = '\0';
1933  GNUNET_asprintf(&ret,
1934  "%s%s%s/%s",
1937  buf,
1938  uri->data.sks.identifier);
1939  return ret;
1940 }
1941 
1942 
1949 static char *
1951 {
1952  const struct FileIdentifier *fi;
1953  char *ret;
1954  struct GNUNET_CRYPTO_HashAsciiEncoded keyhash;
1955  struct GNUNET_CRYPTO_HashAsciiEncoded queryhash;
1956 
1957  if (uri->type != GNUNET_FS_URI_CHK)
1958  return NULL;
1959  fi = &uri->data.chk;
1960  GNUNET_CRYPTO_hash_to_enc(&fi->chk.key, &keyhash);
1961  GNUNET_CRYPTO_hash_to_enc(&fi->chk.query, &queryhash);
1962 
1963  GNUNET_asprintf(&ret,
1964  "%s%s%s.%s.%llu",
1967  (const char *)&keyhash,
1968  (const char *)&queryhash,
1969  GNUNET_ntohll(fi->file_length));
1970  return ret;
1971 }
1972 
1973 
1980 static char *
1982 {
1983  char *ret;
1984  struct GNUNET_CRYPTO_HashAsciiEncoded keyhash;
1985  struct GNUNET_CRYPTO_HashAsciiEncoded queryhash;
1986  char *peer_id;
1987  char peer_sig[SIGNATURE_ASCII_LENGTH + 1];
1988 
1989  GNUNET_CRYPTO_hash_to_enc(&uri->data.loc.fi.chk.key, &keyhash);
1990  GNUNET_CRYPTO_hash_to_enc(&uri->data.loc.fi.chk.query, &queryhash);
1991  peer_id =
1993  GNUNET_assert(
1994  NULL !=
1996  sizeof(struct GNUNET_CRYPTO_EddsaSignature),
1997  peer_sig,
1998  sizeof(peer_sig)));
1999  GNUNET_asprintf(&ret,
2000  "%s%s%s.%s.%llu.%s.%s.%llu",
2003  (const char *)&keyhash,
2004  (const char *)&queryhash,
2005  (unsigned long long)GNUNET_ntohll(
2006  uri->data.loc.fi.file_length),
2007  peer_id,
2008  peer_sig,
2009  (unsigned long long)
2011  1000000LL);
2012  GNUNET_free(peer_id);
2013  return ret;
2014 }
2015 
2016 
2023 char *
2025 {
2026  if (uri == NULL)
2027  {
2028  GNUNET_break(0);
2029  return NULL;
2030  }
2031  switch (uri->type)
2032  {
2033  case GNUNET_FS_URI_KSK:
2034  return uri_ksk_to_string(uri);
2035 
2036  case GNUNET_FS_URI_SKS:
2037  return uri_sks_to_string(uri);
2038 
2039  case GNUNET_FS_URI_CHK:
2040  return uri_chk_to_string(uri);
2041 
2042  case GNUNET_FS_URI_LOC:
2043  return uri_loc_to_string(uri);
2044 
2045  default:
2046  GNUNET_break(0);
2047  return NULL;
2048  }
2049 }
2050 
2051 /* end of fs_uri.c */
int GNUNET_FS_uri_loc_get_peer_identity(const struct GNUNET_FS_Uri *uri, struct GNUNET_PeerIdentity *peer)
Obtain the identity of the peer offering the data.
Definition: fs_uri.c:819
static int iterator(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Iterator over hash map entries.
#define GNUNET_FS_URI_KSK_PREFIX
Definition: fs_uri.c:268
#define GNUNET_FS_URI_SKS_INFIX
int GNUNET_FS_uri_test_ksk(const struct GNUNET_FS_Uri *uri)
Is this a keyword URI?
Definition: fs_uri.c:1332
struct ContentHashKey chk
Query and key of the top GNUNET_EC_IBlock.
Definition: fs_api.h:102
EXTRACTOR_MetaFormat
Format in which the extracted meta data is presented.
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
struct GNUNET_PeerIdentity peer
Peer offering the file.
Definition: fs_uri.c:482
struct FileIdentifier chk
Information needed to retrieve a file (content-hash-key plus file size).
Definition: fs_api.h:204
struct GNUNET_TIME_Absolute GNUNET_FS_uri_loc_get_expiration(const struct GNUNET_FS_Uri *uri)
Obtain the expiration of the LOC URI.
Definition: fs_uri.c:836
static int end
Set if we are to shutdown all services (including ARM).
Definition: gnunet-arm.c:34
struct GNUNET_FS_Uri * GNUNET_FS_uri_ksk_create_from_args(unsigned int argc, const char **argv)
Create an FS URI from a user-supplied command line of keywords.
Definition: fs_uri.c:1152
struct GNUNET_FS_Uri * GNUNET_FS_uri_loc_create(const struct GNUNET_FS_Uri *base_uri, const struct GNUNET_CRYPTO_EddsaPrivateKey *sign_key, struct GNUNET_TIME_Absolute expiration_time)
Construct a location URI (this peer will be used for the location).
Definition: fs_uri.c:876
void GNUNET_FS_uri_ksk_add_keyword(struct GNUNET_FS_Uri *uri, const char *keyword, int is_mandatory)
Add the given keyword to the set of keywords represented by the URI.
Definition: fs_uri.c:759
static char * uri_chk_to_string(const struct GNUNET_FS_Uri *uri)
Convert a CHK URI to a string.
Definition: fs_uri.c:1950
uint32_t purpose
What does this signature vouch for? This must contain a GNUNET_SIGNATURE_PURPOSE_XXX constant (from g...
struct GNUNET_FS_Uri * GNUNET_FS_uri_parse(const char *uri, char **emsg)
Convert a UTF-8 String to a URI.
Definition: fs_uri.c:641
static struct GNUNET_FS_Uri * uri_loc_parse(const char *s, char **emsg)
Parse a LOC URI.
Definition: fs_uri.c:500
static size_t u8_strcount(const uint8_t *s)
Counts the number of UTF-8 characters (not bytes) in the string, returns that count.
Definition: fs_uri.c:1500
static void insert_non_mandatory_keyword(const char *s, char **array, int index)
Add a keyword as non-mandatory (with &#39; &#39;-prefix) to the given keyword list at offset &#39;index&#39;...
Definition: fs_uri.c:1408
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
struct GNUNET_TIME_AbsoluteNBO exptime
Expiration time of the offer.
Definition: fs_uri.c:472
int(* GNUNET_FS_KeywordIterator)(void *cls, const char *keyword, int is_mandatory)
Iterator over keywords.
static char * uri_ksk_to_string(const struct GNUNET_FS_Uri *uri)
Convert a KSK URI to a string.
Definition: fs_uri.c:1849
static struct GNUNET_FS_Uri * uri_ksk_parse(const char *s, char **emsg)
Parse a KSK URI.
Definition: fs_uri.c:278
int GNUNET_CRYPTO_eddsa_sign(const struct GNUNET_CRYPTO_EddsaPrivateKey *priv, const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, struct GNUNET_CRYPTO_EddsaSignature *sig)
EdDSA sign a given block.
Definition: crypto_ecc.c:989
Keyword search key (query with keywords).
Definition: fs_api.h:150
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
static char * percent_decode_keyword(const char *in, char **emsg)
Given a keyword with %-encoding (and possibly quotes to protect spaces), return a copy of the keyword...
Definition: fs_uri.c:219
static char * peer_id
Option –peer.
Definition: gnunet-cadet.c:42
0-terminated, UTF-8 encoded string.
#define GNUNET_NO
Definition: gnunet_common.h:78
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:75
static int get_keywords_from_tokens(const char *s, char **array, int index)
Break the filename up by TOKENS to make keywords.
Definition: fs_uri.c:1639
char * GNUNET_FS_uri_ksk_to_string_fancy(const struct GNUNET_FS_Uri *uri)
Convert keyword URI to a human readable format (i.e.
Definition: fs_uri.c:155
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
int GNUNET_FS_uri_test_equal(const struct GNUNET_FS_Uri *u1, const struct GNUNET_FS_Uri *u2)
Test if two URIs are equal.
Definition: fs_uri.c:1209
#define GNUNET_new(type)
Allocate a struct or union of the given type.
static char * uri_sks_to_string(const struct GNUNET_FS_Uri *uri)
Convert SKS URI to a string.
Definition: fs_uri.c:1919
struct GNUNET_PeerIdentity peer
Identity of the peer sharing the file.
Definition: fs_api.h:119
int GNUNET_FS_uri_test_sks(const struct GNUNET_FS_Uri *uri)
Is this a namespace URI?
Definition: fs_uri.c:1279
EXTRACTOR_MetaType
Enumeration defining various sources of keywords.
static int ret
Final status code.
Definition: gnunet-arm.c:89
int GNUNET_FS_uri_sks_get_namespace(const struct GNUNET_FS_Uri *uri, struct GNUNET_CRYPTO_EcdsaPublicKey *pseudonym)
Get the ID of a namespace from the given namespace URI.
Definition: fs_uri.c:1294
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
Time for absolute time used by GNUnet, in microseconds and in network byte order. ...
struct GNUNET_FS_Uri * GNUNET_FS_uri_sks_create(const struct GNUNET_CRYPTO_EcdsaPublicKey *ns, const char *id)
Create an SKS URI from a namespace ID and an identifier.
Definition: fs_uri.c:916
uint64_t abs_value_us
The actual value.
struct GNUNET_FS_Uri * GNUNET_FS_uri_dup(const struct GNUNET_FS_Uri *uri)
Duplicate URI.
Definition: fs_uri.c:995
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
#define GNUNET_NETWORK_STRUCT_BEGIN
Define as empty, GNUNET_PACKED should suffice, but this won&#39;t work on W32.
char * GNUNET_CONTAINER_meta_data_get_first_by_types(const struct GNUNET_CONTAINER_MetaData *md,...)
Get the first matching MD entry of the given types.
int GNUNET_FS_uri_to_key(const struct GNUNET_FS_Uri *uri, struct GNUNET_HashCode *key)
Get a unique key from a URI.
Definition: fs_uri.c:103
#define _(String)
GNU gettext support macro.
Definition: platform.h:181
int GNUNET_FS_uri_test_loc(const struct GNUNET_FS_Uri *uri)
Is this a location URI?
Definition: fs_uri.c:1392
char * GNUNET_FS_uri_to_string(const struct GNUNET_FS_Uri *uri)
Convert a URI to a UTF-8 String.
Definition: fs_uri.c:2024
static struct GNUNET_FS_Uri * uri_sks_parse(const char *s, char **emsg)
Parse an SKS URI.
Definition: fs_uri.c:372
static int find_duplicate(const char *s, const char **array, int array_length)
Test if the given keyword s is already present in the given array, ignoring the &#39;+&#39;-mandatory prefix ...
Definition: fs_uri.c:1429
header of what an ECC signature signs this must be followed by "size - 8" bytes of the actual signed ...
#define GNUNET_CRYPTO_PKEY_ASCII_LENGTH
How many characters (without 0-terminator) are our ASCII-encoded public keys (ECDSA/EDDSA/ECDHE).
static struct GNUNET_FS_Uri * uri
Value of URI provided on command-line (when not publishing a file but just creating UBlocks to refer ...
int GNUNET_FS_uri_ksk_get_keywords(const struct GNUNET_FS_Uri *uri, GNUNET_FS_KeywordIterator iterator, void *iterator_cls)
Iterate over all keywords in this keyword URI.
Definition: fs_uri.c:727
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
Meta data to associate with a file, directory or namespace.
#define GNUNET_SIGNATURE_PURPOSE_PEER_PLACEMENT
Signature by which a peer affirms that it is providing a certain bit of content (used in LOCation URI...
char ** keywords
Keywords start with a &#39;+&#39; if they are mandatory (in which case the &#39;+&#39; is NOT part of the keyword) an...
Definition: fs_api.h:179
struct GNUNET_CRYPTO_EccSignaturePurpose purpose
What is being signed (rest of this struct).
Definition: fs_uri.c:467
#define GNUNET_array_grow(arr, size, tsize)
Grow a well-typed (!) array.
int GNUNET_CRYPTO_eddsa_verify(uint32_t purpose, const struct GNUNET_CRYPTO_EccSignaturePurpose *validate, const struct GNUNET_CRYPTO_EddsaSignature *sig, const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
Verify EdDSA signature.
Definition: crypto_ecc.c:1116
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:44
struct GNUNET_FS_Uri::@16::@17 ksk
char * GNUNET_CRYPTO_eddsa_public_key_to_string(const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
Convert a public key to a string.
Definition: crypto_ecc.c:367
static int 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)
Function called on each value in the meta data.
Definition: fs_uri.c:1702
#define DIR_SEPARATOR_STR
Definition: platform.h:168
struct GNUNET_HashCode query
Hash of the encrypted content, used for querying.
Definition: fs.h:62
union GNUNET_FS_Uri::@16 data
#define GNUNET_FS_URI_CHK_INFIX
static char buf[2048]
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
static char * filename
complete information needed to download a file.
Definition: fs_api.h:93
static char * plugin_name
Solver plugin name as string.
uint32_t size
How many bytes does this signature sign? (including this purpose header); in network byte order (!)...
static int get_keywords_from_parens(const char *s, char **array, int index)
Break the filename up by matching [], () and {} pairs to make keywords.
Definition: fs_uri.c:1531
void GNUNET_FS_uri_destroy(struct GNUNET_FS_Uri *uri)
Free URI.
Definition: fs_uri.c:675
A 512-bit hashcode.
unsigned int keywordCount
Size of the keywords array.
Definition: fs_api.h:184
int GNUNET_FS_uri_test_chk(const struct GNUNET_FS_Uri *uri)
Is this a file (or directory) URI?
Definition: fs_uri.c:1354
#define TOKENS
Where to break up keywords.
Definition: fs_uri.c:1622
uint64_t GNUNET_htonll(uint64_t n)
Convert unsigned 64-bit integer to network byte order.
Definition: common_endian.c:35
Content-hash-key (simple file).
Definition: fs_api.h:140
struct FileIdentifier fi
File being offered.
Definition: fs_uri.c:477
struct GNUNET_HashCode key
The key used in the DHT.
void GNUNET_CRYPTO_hash_to_enc(const struct GNUNET_HashCode *block, struct GNUNET_CRYPTO_HashAsciiEncoded *result)
Convert hash to ASCII encoding.
Definition: crypto_hash.c:69
#define GNUNET_SYSERR
Definition: gnunet_common.h:76
static struct GNUNET_FS_Uri * uri_chk_parse(const char *s, char **emsg)
Parse a CHK URI.
Definition: fs_uri.c:411
#define GNUNET_FS_URI_SKS_PREFIX
Definition: fs_uri.c:362
struct GNUNET_TIME_Absolute expirationTime
Time when this location URI expires.
Definition: fs_api.h:124
static struct GNUNET_NAMESTORE_Handle * ns
Handle to the namestore.
enum GNUNET_FS_UriType type
Type of the URI.
Definition: fs_api.h:166
#define GNUNET_FS_URI_KSK_INFIX
#define GNUNET_MAX_MALLOC_CHECKED
Maximum allocation with GNUNET_malloc macro.
an ECC signature using EdDSA.
void GNUNET_CRYPTO_eddsa_key_get_public(const struct GNUNET_CRYPTO_EddsaPrivateKey *priv, struct GNUNET_CRYPTO_EddsaPublicKey *pub)
Extract the public key for the given private key.
Definition: crypto_ecc.c:272
struct GNUNET_FS_Uri * GNUNET_FS_uri_ksk_create(const char *keywords, char **emsg)
Create an FS URI from a single user-supplied string of keywords.
Definition: fs_uri.c:1057
0-terminated ASCII encoding of a struct GNUNET_HashCode.
Signed key space (file in namespace).
Definition: fs_api.h:145
struct GNUNET_HashCode key
Hash of the original content, used for encryption.
Definition: fs.h:57
#define GNUNET_NETWORK_STRUCT_END
Define as empty, GNUNET_PACKED should suffice, but this won&#39;t work on W32;.
struct GNUNET_FS_Uri * GNUNET_FS_uri_ksk_create_from_meta_data(const struct GNUNET_CONTAINER_MetaData *md)
Construct a keyword-URI from meta-data (take all entries in the meta-data and construct one large key...
Definition: fs_uri.c:1778
Private ECC key encoded for transmission.
int GNUNET_CRYPTO_eddsa_public_key_from_string(const char *enc, size_t enclen, struct GNUNET_CRYPTO_EddsaPublicKey *pub)
Convert a string representing a public key to a public key.
Definition: crypto_ecc.c:501
#define GNUNET_array_append(arr, size, element)
Append an element to a list (growing the list by one).
struct GNUNET_FS_Uri::@16::@18 sks
The identity of the host (wraps the signing key of the peer).
uint64_t GNUNET_FS_uri_chk_get_file_size(const struct GNUNET_FS_Uri *uri)
What is the size of the file that this URI refers to?
Definition: fs_uri.c:1368
shared definitions for the FS library
A Universal Resource Identifier (URI), opaque.
Definition: fs_api.h:162
#define GNUNET_FS_URI_PREFIX
uint64_t file_length
Total size of the file in bytes.
Definition: fs_api.h:97
Public ECC key (always for Curve25519) encoded in a format suitable for network transmission and ECDS...
struct GNUNET_CRYPTO_EddsaSignature contentSignature
Signature over the GNUNET_EC_FileIdentifier, peer identity and expiration time.
Definition: fs_api.h:130
struct FileIdentifier fi
Information about the shared file.
Definition: fs_api.h:114
int GNUNET_CONTAINER_meta_data_iterate(const struct GNUNET_CONTAINER_MetaData *md, EXTRACTOR_MetaDataProcessor iter, void *iter_cls)
Iterate over MD entries.
struct GNUNET_FS_Uri * GNUNET_FS_uri_loc_get_uri(const struct GNUNET_FS_Uri *uri)
Obtain the URI of the content itself.
Definition: fs_uri.c:850
unsigned int GNUNET_FS_uri_ksk_get_keyword_count(const struct GNUNET_FS_Uri *uri)
How many keywords are ANDed in this keyword URI?
Definition: fs_uri.c:709
Location (chk with identity of hosting peer).
Definition: fs_api.h:155
struct Location loc
Information needed to retrieve a file including signed location (identity of a peer) of the content...
Definition: fs_api.h:210
struct GNUNET_FS_Uri * GNUNET_FS_uri_ksk_merge(const struct GNUNET_FS_Uri *u1, const struct GNUNET_FS_Uri *u2)
Merge the sets of keywords from two KSK URIs.
Definition: fs_uri.c:939
static int needs_percent(char c)
In URI-encoding, does the given character need to be encoded using %-encoding?
Definition: fs_uri.c:1835
enum GNUNET_TESTBED_UnderlayLinkModelType type
the type of this model
Time for absolute times used by GNUnet, in microseconds.
#define GNUNET_YES
Definition: gnunet_common.h:77
char * GNUNET_FS_uri_sks_get_content_id(const struct GNUNET_FS_Uri *uri)
Get the content identifier of an SKS URI.
Definition: fs_uri.c:1314
static char * normalize_metadata(enum EXTRACTOR_MetaFormat format, const char *data, size_t data_len)
FIXME: comment.
Definition: fs_uri.c:1444
#define SIGNATURE_ASCII_LENGTH
Definition: fs_uri.c:489
void GNUNET_FS_uri_ksk_remove_keyword(struct GNUNET_FS_Uri *uri, const char *keyword)
Remove the given keyword from the set of keywords represented by the URI.
Definition: fs_uri.c:787
#define GNUNET_FS_URI_LOC_PREFIX
Definition: fs_uri.c:487
#define GNUNET_FS_URI_LOC_INFIX
#define GNUNET_FS_URI_CHK_PREFIX
Definition: fs_uri.c:400
uint32_t data
The data value.
static char * uri_loc_to_string(const struct GNUNET_FS_Uri *uri)
Convert a LOC URI to a string.
Definition: fs_uri.c:1981
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition: time.c:655
#define GNUNET_CRYPTO_hash_from_string(enc, result)
Convert ASCII encoding back to struct GNUNET_HashCode
#define GNUNET_malloc(size)
Wrapper around malloc.
int GNUNET_STRINGS_string_to_data(const char *enc, size_t enclen, void *out, size_t out_size)
Convert CrockfordBase32 encoding back to data.
Definition: strings.c:953
char * GNUNET_STRINGS_data_to_string(const void *data, size_t size, char *out, size_t out_size)
Convert binary data to ASCII encoding using CrockfordBase32.
Definition: strings.c:857
Structure that defines how the contents of a location URI must be assembled in memory to create or ve...
Definition: fs_uri.c:463
uint64_t GNUNET_ntohll(uint64_t n)
Convert unsigned 64-bit integer to host byte order.
Definition: common_endian.c:48
static char * pseudonym
Command-line option identifying the pseudonym to use for the publication.
#define GNUNET_free(ptr)
Wrapper around free.
struct GNUNET_CRYPTO_EddsaPublicKey public_key
Public ECC key (always for curve Ed25519) encoded in a format suitable for network transmission and E...