GNUnet  0.11.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:
134  GNUNET_CRYPTO_hash (&uri->data.loc.fi,
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 
269 #define GNUNET_FS_URI_KSK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_KSK_INFIX
270 
278 static struct GNUNET_FS_Uri *
279 uri_ksk_parse (const char *s, char **emsg)
280 {
281  struct GNUNET_FS_Uri *ret;
282  char **keywords;
283  unsigned int pos;
284  int max;
285  int iret;
286  int i;
287  size_t slen;
288  char *dup;
289  int saw_quote;
290 
291  slen = strlen (s);
292  pos = strlen (GNUNET_FS_URI_KSK_PREFIX);
293  if ((slen <= pos) || (0 != strncmp (s, GNUNET_FS_URI_KSK_PREFIX, pos)))
294  return NULL; /* not KSK URI */
295  if ((s[slen - 1] == '+') || (s[pos] == '+'))
296  {
297  *emsg =
298  GNUNET_strdup (_ ("Malformed KSK URI (must not begin or end with `+')"));
299  return NULL;
300  }
301  max = 1;
302  saw_quote = 0;
303  for (i = pos; i < slen; i++)
304  {
305  if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22")))
306  {
307  saw_quote = (saw_quote + 1) % 2;
308  i += 3;
309  continue;
310  }
311  if ((s[i] == '+') && (saw_quote == 0))
312  {
313  max++;
314  if (s[i - 1] == '+')
315  {
316  *emsg = GNUNET_strdup (_ ("Malformed KSK URI (`++' not allowed)"));
317  return NULL;
318  }
319  }
320  }
321  if (saw_quote == 1)
322  {
323  *emsg = GNUNET_strdup (_ ("Malformed KSK URI (quotes not balanced)"));
324  return NULL;
325  }
326  iret = max;
327  dup = GNUNET_strdup (s);
328  keywords = GNUNET_new_array (max, char *);
329  for (i = slen - 1; i >= (int) pos; i--)
330  {
331  if ((s[i] == '%') && (&s[i] == strstr (&s[i], "%22")))
332  {
333  saw_quote = (saw_quote + 1) % 2;
334  continue;
335  }
336  if ((dup[i] == '+') && (saw_quote == 0))
337  {
338  keywords[--max] = percent_decode_keyword (&dup[i + 1], emsg);
339  if (NULL == keywords[max])
340  goto CLEANUP;
341  dup[i] = '\0';
342  }
343  }
344  keywords[--max] = percent_decode_keyword (&dup[pos], emsg);
345  if (NULL == keywords[max])
346  goto CLEANUP;
347  GNUNET_assert (0 == max);
348  GNUNET_free (dup);
349  ret = GNUNET_new (struct GNUNET_FS_Uri);
350  ret->type = GNUNET_FS_URI_KSK;
351  ret->data.ksk.keywordCount = iret;
352  ret->data.ksk.keywords = keywords;
353  return ret;
354 CLEANUP:
355  for (i = 0; i < max; i++)
356  GNUNET_free_non_null (keywords[i]);
357  GNUNET_free (keywords);
358  GNUNET_free (dup);
359  return NULL;
360 }
361 
362 
363 #define GNUNET_FS_URI_SKS_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_SKS_INFIX
364 
372 static struct GNUNET_FS_Uri *
373 uri_sks_parse (const char *s, char **emsg)
374 {
375  struct GNUNET_FS_Uri *ret;
377  size_t pos;
378  char *end;
379 
380  pos = strlen (GNUNET_FS_URI_SKS_PREFIX);
381  if ((strlen (s) <= pos) || (0 != strncmp (s, GNUNET_FS_URI_SKS_PREFIX, pos)))
382  return NULL; /* not an SKS URI */
383  end = strchr (&s[pos], '/');
384  if ((NULL == end) ||
386  end - &s[pos],
387  &ns,
388  sizeof(ns))))
389  {
390  *emsg = GNUNET_strdup (_ ("Malformed SKS URI (wrong syntax)"));
391  return NULL; /* malformed */
392  }
393  end++; /* skip over '/' */
394  ret = GNUNET_new (struct GNUNET_FS_Uri);
395  ret->type = GNUNET_FS_URI_SKS;
396  ret->data.sks.ns = ns;
397  ret->data.sks.identifier = GNUNET_strdup (end);
398  return ret;
399 }
400 
401 
402 #define GNUNET_FS_URI_CHK_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_CHK_INFIX
403 
404 
412 static struct GNUNET_FS_Uri *
413 uri_chk_parse (const char *s, char **emsg)
414 {
415  struct GNUNET_FS_Uri *ret;
416  struct FileIdentifier fi;
417  unsigned int pos;
418  unsigned long long flen;
419  size_t slen;
420  char h1[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)];
421  char h2[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)];
422 
423  slen = strlen (s);
424  pos = strlen (GNUNET_FS_URI_CHK_PREFIX);
425  if ((slen < pos + 2 * sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) ||
426  (0 != strncmp (s, GNUNET_FS_URI_CHK_PREFIX, pos)))
427  return NULL; /* not a CHK URI */
428  if ((s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') ||
429  (s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.'))
430  {
431  *emsg = GNUNET_strdup (_ ("Malformed CHK URI (wrong syntax)"));
432  return NULL;
433  }
434  GNUNET_memcpy (h1, &s[pos], sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded));
435  h1[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
436  GNUNET_memcpy (h2,
437  &s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)],
438  sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded));
439  h2[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
440 
441  if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h1, &fi.chk.key)) ||
443  (1 !=
444  sscanf (&s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2],
445  "%llu",
446  &flen)))
447  {
448  *emsg = GNUNET_strdup (_ ("Malformed CHK URI (failed to decode CHK)"));
449  return NULL;
450  }
451  fi.file_length = GNUNET_htonll (flen);
452  ret = GNUNET_new (struct GNUNET_FS_Uri);
453  ret->type = GNUNET_FS_URI_CHK;
454  ret->data.chk = fi;
455  return ret;
456 }
457 
458 
466 {
471 
476 
481 
486 };
488 
489 
490 #define GNUNET_FS_URI_LOC_PREFIX GNUNET_FS_URI_PREFIX GNUNET_FS_URI_LOC_INFIX
491 
492 #define SIGNATURE_ASCII_LENGTH 103
493 
502 static struct GNUNET_FS_Uri *
503 uri_loc_parse (const char *s, char **emsg)
504 {
505  struct GNUNET_FS_Uri *uri;
506  char h1[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)];
507  char h2[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)];
508  unsigned int pos;
509  unsigned int npos;
510  unsigned long long exptime;
511  unsigned long long flen;
512  struct GNUNET_TIME_Absolute et;
513  struct GNUNET_CRYPTO_EddsaSignature sig;
514  struct LocUriAssembly ass;
515  size_t slen;
516 
517  slen = strlen (s);
518  pos = strlen (GNUNET_FS_URI_LOC_PREFIX);
519  if ((slen < pos + 2 * sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) + 1) ||
520  (0 != strncmp (s, GNUNET_FS_URI_LOC_PREFIX, pos)))
521  return NULL; /* not a LOC URI */
522  if ((s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] != '.') ||
523  (s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2 - 1] != '.'))
524  {
525  *emsg = GNUNET_strdup (_ ("LOC URI malformed (wrong syntax)"));
526  return NULL;
527  }
528  GNUNET_memcpy (h1, &s[pos], sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded));
529  h1[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
530  GNUNET_memcpy (h2,
531  &s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded)],
532  sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded));
533  h2[sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
534 
535  if ((GNUNET_OK != GNUNET_CRYPTO_hash_from_string (h1, &ass.fi.chk.key)) ||
537  (1 !=
538  sscanf (&s[pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2],
539  "%llu",
540  &flen)))
541  {
542  *emsg = GNUNET_strdup (_ ("LOC URI malformed (no CHK)"));
543  return NULL;
544  }
545  ass.fi.file_length = GNUNET_htonll (flen);
546 
547  npos = pos + sizeof(struct GNUNET_CRYPTO_HashAsciiEncoded) * 2;
548  while ((s[npos] != '\0') && (s[npos] != '.'))
549  npos++;
550  if (s[npos] == '\0')
551  {
552  *emsg = GNUNET_strdup (_ ("LOC URI malformed (missing LOC)"));
553  goto ERR;
554  }
555  npos++;
556  if ((strlen (&s[npos]) <= GNUNET_CRYPTO_PKEY_ASCII_LENGTH + 1) ||
557  ('.' != s[npos + GNUNET_CRYPTO_PKEY_ASCII_LENGTH]))
558  {
559  *emsg =
560  GNUNET_strdup (_ ("LOC URI malformed (wrong syntax for public key)"));
561  }
562  if (
563  GNUNET_OK !=
566  &ass.peer.public_key))
567  {
568  *emsg =
569  GNUNET_strdup (_ ("LOC URI malformed (could not decode public key)"));
570  goto ERR;
571  }
573  if (s[npos++] != '.')
574  {
575  *emsg = GNUNET_strdup (_ ("LOC URI malformed (could not find signature)"));
576  goto ERR;
577  }
578  if ((strlen (&s[npos]) <= SIGNATURE_ASCII_LENGTH + 1) ||
579  ('.' != s[npos + SIGNATURE_ASCII_LENGTH]))
580  {
581  *emsg =
582  GNUNET_strdup (_ ("LOC URI malformed (wrong syntax for signature)"));
583  goto ERR;
584  }
585  if (GNUNET_OK !=
588  &sig,
589  sizeof(
591  {
592  *emsg =
593  GNUNET_strdup (_ ("LOC URI malformed (could not decode signature)"));
594  goto ERR;
595  }
596  npos += SIGNATURE_ASCII_LENGTH;
597  if (s[npos++] != '.')
598  {
599  *emsg = GNUNET_strdup (
600  _ ("LOC URI malformed (wrong syntax for expiration time)"));
601  goto ERR;
602  }
603  if (1 != sscanf (&s[npos], "%llu", &exptime))
604  {
605  *emsg =
606  GNUNET_strdup (_ ("LOC URI malformed (could not parse expiration time)"));
607  goto ERR;
608  }
609  ass.purpose.size = htonl (sizeof(struct LocUriAssembly));
611  et.abs_value_us = exptime * 1000LL * 1000LL;
613  if (GNUNET_OK !=
615  &ass.purpose,
616  &sig,
617  &ass.peer.public_key))
618  {
619  *emsg =
620  GNUNET_strdup (_ ("LOC URI malformed (signature failed validation)"));
621  goto ERR;
622  }
623  uri = GNUNET_new (struct GNUNET_FS_Uri);
624  uri->type = GNUNET_FS_URI_LOC;
625  uri->data.loc.fi = ass.fi;
626  uri->data.loc.peer = ass.peer;
627  uri->data.loc.expirationTime = et;
628  uri->data.loc.contentSignature = sig;
629 
630  return uri;
631 ERR:
632  return NULL;
633 }
634 
635 
643 struct GNUNET_FS_Uri *
644 GNUNET_FS_uri_parse (const char *uri, char **emsg)
645 {
646  struct GNUNET_FS_Uri *ret;
647  char *msg;
648 
649  if (NULL == uri)
650  {
651  GNUNET_break (0);
652  if (NULL != emsg)
653  *emsg = GNUNET_strdup (_ ("invalid argument"));
654  return NULL;
655  }
656  if (NULL == emsg)
657  emsg = &msg;
658  *emsg = NULL;
659  if ((NULL != (ret = uri_chk_parse (uri, emsg))) ||
660  (NULL != (ret = uri_ksk_parse (uri, emsg))) ||
661  (NULL != (ret = uri_sks_parse (uri, emsg))) ||
662  (NULL != (ret = uri_loc_parse (uri, emsg))))
663  return ret;
664  if (NULL == *emsg)
665  *emsg = GNUNET_strdup (_ ("Unrecognized URI type"));
666  if (emsg == &msg)
667  GNUNET_free (msg);
668  return NULL;
669 }
670 
671 
677 void
679 {
680  unsigned int i;
681 
682  switch (uri->type)
683  {
684  case GNUNET_FS_URI_KSK:
685  for (i = 0; i < uri->data.ksk.keywordCount; i++)
686  GNUNET_free (uri->data.ksk.keywords[i]);
687  GNUNET_array_grow (uri->data.ksk.keywords, uri->data.ksk.keywordCount, 0);
688  break;
689 
690  case GNUNET_FS_URI_SKS:
691  GNUNET_free (uri->data.sks.identifier);
692  break;
693 
694  case GNUNET_FS_URI_LOC:
695  break;
696 
697  default:
698  /* do nothing */
699  break;
700  }
701  GNUNET_free (uri);
702 }
703 
704 
711 unsigned int
713 {
714  if (uri->type != GNUNET_FS_URI_KSK)
715  return 0;
716  return uri->data.ksk.keywordCount;
717 }
718 
719 
729 int
732  void *iterator_cls)
733 {
734  unsigned int i;
735  char *keyword;
736 
737  if (uri->type != GNUNET_FS_URI_KSK)
738  return -1;
739  if (NULL == iterator)
740  return uri->data.ksk.keywordCount;
741  for (i = 0; i < uri->data.ksk.keywordCount; i++)
742  {
743  keyword = uri->data.ksk.keywords[i];
744  /* first character of keyword indicates
745  * if it is mandatory or not */
746  if (GNUNET_OK != iterator (iterator_cls, &keyword[1],(keyword[0] == '+') ))
747  return i;
748  }
749  return i;
750 }
751 
752 
761 void
763  const char *keyword,
764  int is_mandatory)
765 {
766  unsigned int i;
767  const char *old;
768  char *n;
769 
771  for (i = 0; i < uri->data.ksk.keywordCount; i++)
772  {
773  old = uri->data.ksk.keywords[i];
774  if (0 == strcmp (&old[1], keyword))
775  return;
776  }
777  GNUNET_asprintf (&n, is_mandatory ? "+%s" : " %s", keyword);
778  GNUNET_array_append (uri->data.ksk.keywords, uri->data.ksk.keywordCount, n);
779 }
780 
781 
789 void
791  const char *keyword)
792 {
793  unsigned int i;
794  char *old;
795 
797  for (i = 0; i < uri->data.ksk.keywordCount; i++)
798  {
799  old = uri->data.ksk.keywords[i];
800  if (0 == strcmp (&old[1], keyword))
801  {
802  uri->data.ksk.keywords[i] =
803  uri->data.ksk.keywords[uri->data.ksk.keywordCount - 1];
804  GNUNET_array_grow (uri->data.ksk.keywords,
805  uri->data.ksk.keywordCount,
806  uri->data.ksk.keywordCount - 1);
807  GNUNET_free (old);
808  return;
809  }
810  }
811 }
812 
813 
821 int
823  struct GNUNET_PeerIdentity *peer)
824 {
825  if (uri->type != GNUNET_FS_URI_LOC)
826  return GNUNET_SYSERR;
827  *peer = uri->data.loc.peer;
828  return GNUNET_OK;
829 }
830 
831 
840 {
842  return uri->data.loc.expirationTime;
843 }
844 
845 
852 struct GNUNET_FS_Uri *
854 {
855  struct GNUNET_FS_Uri *ret;
856 
857  if (uri->type != GNUNET_FS_URI_LOC)
858  return NULL;
859  ret = GNUNET_new (struct GNUNET_FS_Uri);
860  ret->type = GNUNET_FS_URI_CHK;
861  ret->data.chk = uri->data.loc.fi;
862  return ret;
863 }
864 
865 
878 struct GNUNET_FS_Uri *
879 GNUNET_FS_uri_loc_create (const struct GNUNET_FS_Uri *base_uri,
880  const struct GNUNET_CRYPTO_EddsaPrivateKey *sign_key,
881  struct GNUNET_TIME_Absolute expiration_time)
882 {
883  struct GNUNET_FS_Uri *uri;
884  struct GNUNET_CRYPTO_EddsaPublicKey my_public_key;
885  struct LocUriAssembly ass;
886  struct GNUNET_TIME_Absolute et;
887 
888  if (GNUNET_FS_URI_CHK != base_uri->type)
889  return NULL;
890  /* we round expiration time to full seconds for SKS URIs */
891  et.abs_value_us = (expiration_time.abs_value_us / 1000000LL) * 1000000LL;
892  GNUNET_CRYPTO_eddsa_key_get_public (sign_key, &my_public_key);
893  ass.purpose.size = htonl (sizeof(struct LocUriAssembly));
896  ass.fi = base_uri->data.chk;
897  ass.peer.public_key = my_public_key;
898  uri = GNUNET_new (struct GNUNET_FS_Uri);
899  uri->type = GNUNET_FS_URI_LOC;
900  uri->data.loc.fi = base_uri->data.chk;
901  uri->data.loc.expirationTime = et;
902  uri->data.loc.peer.public_key = my_public_key;
904  GNUNET_CRYPTO_eddsa_sign (sign_key,
905  &ass.purpose,
906  &uri->data.loc.contentSignature));
907  return uri;
908 }
909 
910 
918 struct GNUNET_FS_Uri *
920  const char *id)
921 {
922  struct GNUNET_FS_Uri *ns_uri;
923 
924  ns_uri = GNUNET_new (struct GNUNET_FS_Uri);
925  ns_uri->type = GNUNET_FS_URI_SKS;
926  ns_uri->data.sks.ns = *ns;
927  ns_uri->data.sks.identifier = GNUNET_strdup (id);
928  return ns_uri;
929 }
930 
931 
941 struct GNUNET_FS_Uri *
943  const struct GNUNET_FS_Uri *u2)
944 {
945  struct GNUNET_FS_Uri *ret;
946  unsigned int kc;
947  unsigned int i;
948  unsigned int j;
949  int found;
950  const char *kp;
951  char **kl;
952 
953  if ((u1 == NULL) && (u2 == NULL))
954  return NULL;
955  if (u1 == NULL)
956  return GNUNET_FS_uri_dup (u2);
957  if (u2 == NULL)
958  return GNUNET_FS_uri_dup (u1);
959  if ((u1->type != GNUNET_FS_URI_KSK) || (u2->type != GNUNET_FS_URI_KSK))
960  {
961  GNUNET_break (0);
962  return NULL;
963  }
964  kc = u1->data.ksk.keywordCount;
965  kl = GNUNET_new_array (kc + u2->data.ksk.keywordCount, char *);
966  for (i = 0; i < u1->data.ksk.keywordCount; i++)
967  kl[i] = GNUNET_strdup (u1->data.ksk.keywords[i]);
968  for (i = 0; i < u2->data.ksk.keywordCount; i++)
969  {
970  kp = u2->data.ksk.keywords[i];
971  found = 0;
972  for (j = 0; j < u1->data.ksk.keywordCount; j++)
973  if (0 == strcmp (kp + 1, kl[j] + 1))
974  {
975  found = 1;
976  if (kp[0] == '+')
977  kl[j][0] = '+';
978  break;
979  }
980  if (0 == found)
981  kl[kc++] = GNUNET_strdup (kp);
982  }
983  ret = GNUNET_new (struct GNUNET_FS_Uri);
984  ret->type = GNUNET_FS_URI_KSK;
985  ret->data.ksk.keywordCount = kc;
986  ret->data.ksk.keywords = kl;
987  return ret;
988 }
989 
990 
997 struct GNUNET_FS_Uri *
999 {
1000  struct GNUNET_FS_Uri *ret;
1001  unsigned int i;
1002 
1003  if (uri == NULL)
1004  return NULL;
1005  ret = GNUNET_new (struct GNUNET_FS_Uri);
1006  GNUNET_memcpy (ret, uri, sizeof(struct GNUNET_FS_Uri));
1007  switch (ret->type)
1008  {
1009  case GNUNET_FS_URI_KSK:
1010  if (ret->data.ksk.keywordCount >=
1011  GNUNET_MAX_MALLOC_CHECKED / sizeof(char *))
1012  {
1013  GNUNET_break (0);
1014  GNUNET_free (ret);
1015  return NULL;
1016  }
1017  if (ret->data.ksk.keywordCount > 0)
1018  {
1019  ret->data.ksk.keywords =
1020  GNUNET_new_array (ret->data.ksk.keywordCount, char *);
1021  for (i = 0; i < ret->data.ksk.keywordCount; i++)
1022  ret->data.ksk.keywords[i] = GNUNET_strdup (uri->data.ksk.keywords[i]);
1023  }
1024  else
1025  ret->data.ksk.keywords = NULL; /* just to be sure */
1026  break;
1027 
1028  case GNUNET_FS_URI_SKS:
1029  ret->data.sks.identifier = GNUNET_strdup (uri->data.sks.identifier);
1030  break;
1031 
1032  case GNUNET_FS_URI_LOC:
1033  break;
1034 
1035  default:
1036  break;
1037  }
1038  return ret;
1039 }
1040 
1041 
1059 struct GNUNET_FS_Uri *
1060 GNUNET_FS_uri_ksk_create (const char *keywords, char **emsg)
1061 {
1062  char **keywordarr;
1063  unsigned int num_Words;
1064  int inWord;
1065  char *pos;
1066  struct GNUNET_FS_Uri *uri;
1067  char *searchString;
1068  int saw_quote;
1069 
1070  if (keywords == NULL)
1071  {
1072  *emsg = GNUNET_strdup (_ ("No keywords specified!\n"));
1073  GNUNET_break (0);
1074  return NULL;
1075  }
1076  searchString = GNUNET_strdup (keywords);
1077  num_Words = 0;
1078  inWord = 0;
1079  saw_quote = 0;
1080  pos = searchString;
1081  while ('\0' != *pos)
1082  {
1083  if ((saw_quote == 0) && (isspace ((unsigned char) *pos)))
1084  {
1085  inWord = 0;
1086  }
1087  else if (0 == inWord)
1088  {
1089  inWord = 1;
1090  ++num_Words;
1091  }
1092  if ('"' == *pos)
1093  saw_quote = (saw_quote + 1) % 2;
1094  pos++;
1095  }
1096  if (num_Words == 0)
1097  {
1098  GNUNET_free (searchString);
1099  *emsg = GNUNET_strdup (_ ("No keywords specified!\n"));
1100  return NULL;
1101  }
1102  if (saw_quote != 0)
1103  {
1104  GNUNET_free (searchString);
1105  *emsg = GNUNET_strdup (_ ("Number of double-quotes not balanced!\n"));
1106  return NULL;
1107  }
1108  keywordarr = GNUNET_new_array (num_Words, char *);
1109  num_Words = 0;
1110  inWord = 0;
1111  pos = searchString;
1112  while ('\0' != *pos)
1113  {
1114  if ((saw_quote == 0) && (isspace ((unsigned char) *pos)))
1115  {
1116  inWord = 0;
1117  *pos = '\0';
1118  }
1119  else if (0 == inWord)
1120  {
1121  keywordarr[num_Words] = pos;
1122  inWord = 1;
1123  ++num_Words;
1124  }
1125  if ('"' == *pos)
1126  saw_quote = (saw_quote + 1) % 2;
1127  pos++;
1128  }
1129  uri =
1130  GNUNET_FS_uri_ksk_create_from_args (num_Words, (const char **) keywordarr);
1131  GNUNET_free (keywordarr);
1132  GNUNET_free (searchString);
1133  return uri;
1134 }
1135 
1136 
1154 struct GNUNET_FS_Uri *
1155 GNUNET_FS_uri_ksk_create_from_args (unsigned int argc, const char **argv)
1156 {
1157  unsigned int i;
1158  struct GNUNET_FS_Uri *uri;
1159  const char *keyword;
1160  char *val;
1161  const char *r;
1162  char *w;
1163  char *emsg;
1164 
1165  if (argc == 0)
1166  return NULL;
1167  /* allow URI to be given as one and only keyword and
1168  * handle accordingly */
1169  emsg = NULL;
1170  if ((argc == 1) && (strlen (argv[0]) > strlen (GNUNET_FS_URI_PREFIX)) &&
1171  (0 == strncmp (argv[0],
1173  strlen (GNUNET_FS_URI_PREFIX))) &&
1174  (NULL != (uri = GNUNET_FS_uri_parse (argv[0], &emsg))))
1175  return uri;
1176  GNUNET_free_non_null (emsg);
1177  uri = GNUNET_new (struct GNUNET_FS_Uri);
1178  uri->type = GNUNET_FS_URI_KSK;
1179  uri->data.ksk.keywordCount = argc;
1180  uri->data.ksk.keywords = GNUNET_new_array (argc, char *);
1181  for (i = 0; i < argc; i++)
1182  {
1183  keyword = argv[i];
1184  if (keyword[0] == '+')
1185  val = GNUNET_strdup (keyword);
1186  else
1187  GNUNET_asprintf (&val, " %s", keyword);
1188  r = val;
1189  w = val;
1190  while ('\0' != *r)
1191  {
1192  if ('"' == *r)
1193  r++;
1194  else
1195  *(w++) = *(r++);
1196  }
1197  *w = '\0';
1198  uri->data.ksk.keywords[i] = val;
1199  }
1200  return uri;
1201 }
1202 
1203 
1211 int
1213  const struct GNUNET_FS_Uri *u2)
1214 {
1215  int ret;
1216  unsigned int i;
1217  unsigned int j;
1218 
1219  GNUNET_assert (u1 != NULL);
1220  GNUNET_assert (u2 != NULL);
1221  if (u1->type != u2->type)
1222  return GNUNET_NO;
1223  switch (u1->type)
1224  {
1225  case GNUNET_FS_URI_CHK:
1226  if (0 ==
1227  memcmp (&u1->data.chk, &u2->data.chk, sizeof(struct FileIdentifier)))
1228  return GNUNET_YES;
1229  return GNUNET_NO;
1230 
1231  case GNUNET_FS_URI_SKS:
1232  if ((0 == memcmp (&u1->data.sks.ns,
1233  &u2->data.sks.ns,
1234  sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey))) &&
1235  (0 == strcmp (u1->data.sks.identifier, u2->data.sks.identifier)))
1236 
1237  return GNUNET_YES;
1238  return GNUNET_NO;
1239 
1240  case GNUNET_FS_URI_KSK:
1241  if (u1->data.ksk.keywordCount != u2->data.ksk.keywordCount)
1242  return GNUNET_NO;
1243  for (i = 0; i < u1->data.ksk.keywordCount; i++)
1244  {
1245  ret = GNUNET_NO;
1246  for (j = 0; j < u2->data.ksk.keywordCount; j++)
1247  {
1248  if (0 == strcmp (u1->data.ksk.keywords[i], u2->data.ksk.keywords[j]))
1249  {
1250  ret = GNUNET_YES;
1251  break;
1252  }
1253  }
1254  if (ret == GNUNET_NO)
1255  return GNUNET_NO;
1256  }
1257  return GNUNET_YES;
1258 
1259  case GNUNET_FS_URI_LOC:
1260  if (memcmp (&u1->data.loc,
1261  &u2->data.loc,
1262  sizeof(struct FileIdentifier)
1263  + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
1264  + sizeof(struct GNUNET_TIME_Absolute)
1265  + sizeof(unsigned short) + sizeof(unsigned short)) != 0)
1266  return GNUNET_NO;
1267  return GNUNET_YES;
1268 
1269  default:
1270  return GNUNET_NO;
1271  }
1272 }
1273 
1274 
1281 int
1283 {
1284  return uri->type == GNUNET_FS_URI_SKS;
1285 }
1286 
1287 
1296 int
1299 {
1300  if (! GNUNET_FS_uri_test_sks (uri))
1301  {
1302  GNUNET_break (0);
1303  return GNUNET_SYSERR;
1304  }
1305  *pseudonym = uri->data.sks.ns;
1306  return GNUNET_OK;
1307 }
1308 
1309 
1316 char *
1318 {
1319  if (! GNUNET_FS_uri_test_sks (uri))
1320  {
1321  GNUNET_break (0);
1322  return NULL;
1323  }
1324  return GNUNET_strdup (uri->data.sks.identifier);
1325 }
1326 
1327 
1334 int
1336 {
1337 #if EXTRA_CHECKS
1338  unsigned int i;
1339 
1340  if (uri->type == GNUNET_FS_URI_KSK)
1341  {
1342  for (i = 0; i < uri->data.ksk.keywordCount; i++)
1343  GNUNET_assert (uri->data.ksk.keywords[i] != NULL);
1344  }
1345 #endif
1346  return uri->type == GNUNET_FS_URI_KSK;
1347 }
1348 
1349 
1356 int
1358 {
1359  return uri->type == GNUNET_FS_URI_CHK;
1360 }
1361 
1362 
1370 uint64_t
1372 {
1373  switch (uri->type)
1374  {
1375  case GNUNET_FS_URI_CHK:
1376  return GNUNET_ntohll (uri->data.chk.file_length);
1377 
1378  case GNUNET_FS_URI_LOC:
1379  return GNUNET_ntohll (uri->data.loc.fi.file_length);
1380 
1381  default:
1382  GNUNET_assert (0);
1383  }
1384  return 0; /* unreachable */
1385 }
1386 
1387 
1394 int
1396 {
1397  return uri->type == GNUNET_FS_URI_LOC;
1398 }
1399 
1400 
1410 static void
1411 insert_non_mandatory_keyword (const char *s, char **array, int index)
1412 {
1413  char *nkword;
1414 
1415  GNUNET_asprintf (&nkword,
1416  " %s", /* space to mark as 'non mandatory' */
1417  s);
1418  array[index] = nkword;
1419 }
1420 
1421 
1431 static int
1432 find_duplicate (const char *s, const char **array, int array_length)
1433 {
1434  int j;
1435 
1436  for (j = array_length - 1; j >= 0; j--)
1437  if (0 == strcmp (&array[j][1], s))
1438  return GNUNET_YES;
1439  return GNUNET_NO;
1440 }
1441 
1442 
1446 static char *
1448  const char *data,
1449  size_t data_len)
1450 {
1451  uint8_t *free_str = NULL;
1452  uint8_t *str_to_normalize = (uint8_t *) data;
1453  uint8_t *normalized;
1454  size_t r_len;
1455 
1456  if (str_to_normalize == NULL)
1457  return NULL;
1458  /* Don't trust libextractor */
1459  if (format == EXTRACTOR_METAFORMAT_UTF8)
1460  {
1461  free_str = (uint8_t *) u8_check ((const uint8_t *) data, data_len);
1462  if (free_str == NULL)
1463  free_str = NULL;
1464  else
1466  }
1467  if (format == EXTRACTOR_METAFORMAT_C_STRING)
1468  {
1469  free_str = u8_strconv_from_encoding (data,
1470  locale_charset (),
1471  iconveh_escape_sequence);
1472  if (free_str == NULL)
1473  return NULL;
1474  }
1475 
1476  normalized = u8_tolower (str_to_normalize,
1477  strlen ((char *) str_to_normalize),
1478  NULL,
1479  UNINORM_NFD,
1480  NULL,
1481  &r_len);
1482  /* free_str is allocated by libunistring internally, use free() */
1483  if (free_str != NULL)
1484  free (free_str);
1485  if (normalized != NULL)
1486  {
1487  /* u8_tolower allocates a non-NULL-terminated string! */
1488  free_str = GNUNET_malloc (r_len + 1);
1489  GNUNET_memcpy (free_str, normalized, r_len);
1490  free_str[r_len] = '\0';
1491  free (normalized);
1492  normalized = free_str;
1493  }
1494  return (char *) normalized;
1495 }
1496 
1497 
1502 static size_t
1503 u8_strcount (const uint8_t *s)
1504 {
1505  size_t count;
1506  ucs4_t c;
1507 
1508  GNUNET_assert (s != NULL);
1509  if (s[0] == 0)
1510  return 0;
1511  for (count = 0; s != NULL; count++)
1512  s = u8_next (&c, s);
1513  return count - 1;
1514 }
1515 
1516 
1533 static int
1534 get_keywords_from_parens (const char *s, char **array, int index)
1535 {
1536  int count = 0;
1537  char *open_paren;
1538  char *close_paren;
1539  char *ss;
1540  char tmp;
1541 
1542  if (NULL == s)
1543  return 0;
1544  ss = GNUNET_strdup (s);
1545  open_paren = ss - 1;
1546  while (NULL != (open_paren = strpbrk (open_paren + 1, "[{(")))
1547  {
1548  int match = 0;
1549 
1550  close_paren = strpbrk (open_paren + 1, "]})");
1551  if (NULL == close_paren)
1552  continue;
1553  switch (open_paren[0])
1554  {
1555  case '[':
1556  if (']' == close_paren[0])
1557  match = 1;
1558  break;
1559 
1560  case '{':
1561  if ('}' == close_paren[0])
1562  match = 1;
1563  break;
1564 
1565  case '(':
1566  if (')' == close_paren[0])
1567  match = 1;
1568  break;
1569 
1570  default:
1571  break;
1572  }
1573  if (match && (close_paren - open_paren > 1))
1574  {
1575  tmp = close_paren[0];
1576  close_paren[0] = '\0';
1577  /* Keywords must be at least 3 characters long */
1578  if (u8_strcount ((const uint8_t *) &open_paren[1]) <= 2)
1579  {
1580  close_paren[0] = tmp;
1581  continue;
1582  }
1583  if (NULL != array)
1584  {
1585  char *normalized;
1586  if (GNUNET_NO == find_duplicate ((const char *) &open_paren[1],
1587  (const char **) array,
1588  index + count))
1589  {
1590  insert_non_mandatory_keyword ((const char *) &open_paren[1],
1591  array,
1592  index + count);
1593  count++;
1594  }
1596  &open_paren[1],
1597  close_paren - &open_paren[1]);
1598  if (normalized != NULL)
1599  {
1600  if (GNUNET_NO == find_duplicate ((const char *) normalized,
1601  (const char **) array,
1602  index + count))
1603  {
1604  insert_non_mandatory_keyword ((const char *) normalized,
1605  array,
1606  index + count);
1607  count++;
1608  }
1609  GNUNET_free (normalized);
1610  }
1611  }
1612  else
1613  count++;
1614  close_paren[0] = tmp;
1615  }
1616  }
1617  GNUNET_free (ss);
1618  return count;
1619 }
1620 
1621 
1625 #define TOKENS "_. /-!?#&+@\"\'\\;:,()[]{}$<>|"
1626 
1641 static int
1642 get_keywords_from_tokens (const char *s, char **array, int index)
1643 {
1644  char *p;
1645  char *ss;
1646  int seps = 0;
1647 
1648  ss = GNUNET_strdup (s);
1649  for (p = strtok (ss, TOKENS); p != NULL; p = strtok (NULL, TOKENS))
1650  {
1651  /* Keywords must be at least 3 characters long */
1652  if (u8_strcount ((const uint8_t *) p) <= 2)
1653  continue;
1654  if (NULL != array)
1655  {
1656  char *normalized;
1657  if (GNUNET_NO == find_duplicate (p, (const char **) array, index + seps))
1658  {
1659  insert_non_mandatory_keyword (p, array, index + seps);
1660  seps++;
1661  }
1662  normalized =
1664  if (normalized != NULL)
1665  {
1666  if (GNUNET_NO == find_duplicate ((const char *) normalized,
1667  (const char **) array,
1668  index + seps))
1669  {
1670  insert_non_mandatory_keyword ((const char *) normalized,
1671  array,
1672  index + seps);
1673  seps++;
1674  }
1675  GNUNET_free (normalized);
1676  }
1677  }
1678  else
1679  seps++;
1680  }
1681  GNUNET_free (ss);
1682  return seps;
1683 }
1684 
1685 
1686 #undef TOKENS
1687 
1688 
1706 static int
1707 gather_uri_data (void *cls,
1708  const char *plugin_name,
1709  enum EXTRACTOR_MetaType type,
1710  enum EXTRACTOR_MetaFormat format,
1711  const char *data_mime_type,
1712  const char *data,
1713  size_t data_len)
1714 {
1715  struct GNUNET_FS_Uri *uri = cls;
1716  char *normalized_data;
1717  const char *sep;
1718 
1719  if ((format != EXTRACTOR_METAFORMAT_UTF8) &&
1720  (format != EXTRACTOR_METAFORMAT_C_STRING))
1721  return 0;
1722  /* Keywords must be at least 3 characters long
1723  * If given non-utf8 string it will, most likely, find it to be invalid,
1724  * and will return the length of its valid part, skipping the keyword.
1725  * If it does - fix the extractor, not this check!
1726  */if (u8_strcount ((const uint8_t *) data) <= 2)
1727  return 0;
1728  if ((EXTRACTOR_METATYPE_MIMETYPE == type) &&
1729  (NULL != (sep = memchr (data, '/', data_len))) && (sep != data))
1730  {
1731  char *xtra;
1732 
1733  GNUNET_asprintf (&xtra, "mimetype:%.*s", (int) (sep - data), data);
1734  if (! find_duplicate (xtra,
1735  (const char **) uri->data.ksk.keywords,
1736  uri->data.ksk.keywordCount))
1737  {
1739  uri->data.ksk.keywords,
1740  uri->data.ksk.keywordCount);
1741  uri->data.ksk.keywordCount++;
1742  }
1743  GNUNET_free (xtra);
1744  }
1745 
1746  normalized_data = normalize_metadata (format, data, data_len);
1747  if (! find_duplicate (data,
1748  (const char **) uri->data.ksk.keywords,
1749  uri->data.ksk.keywordCount))
1750  {
1752  uri->data.ksk.keywords,
1753  uri->data.ksk.keywordCount);
1754  uri->data.ksk.keywordCount++;
1755  }
1756  if (NULL != normalized_data)
1757  {
1758  if (! find_duplicate (normalized_data,
1759  (const char **) uri->data.ksk.keywords,
1760  uri->data.ksk.keywordCount))
1761  {
1762  insert_non_mandatory_keyword (normalized_data,
1763  uri->data.ksk.keywords,
1764  uri->data.ksk.keywordCount);
1765  uri->data.ksk.keywordCount++;
1766  }
1767  GNUNET_free (normalized_data);
1768  }
1769  return 0;
1770 }
1771 
1772 
1781 struct GNUNET_FS_Uri *
1783  const struct GNUNET_CONTAINER_MetaData *md)
1784 {
1785  struct GNUNET_FS_Uri *ret;
1786  char *filename;
1787  char *full_name = NULL;
1788  char *ss;
1789  int ent;
1790  int tok_keywords = 0;
1791  int paren_keywords = 0;
1792 
1793  if (NULL == md)
1794  return NULL;
1795  ret = GNUNET_new (struct GNUNET_FS_Uri);
1796  ret->type = GNUNET_FS_URI_KSK;
1797  ent = GNUNET_CONTAINER_meta_data_iterate (md, NULL, NULL);
1798  if (ent > 0)
1799  {
1801  md,
1803  -1);
1804  if (NULL != full_name)
1805  {
1806  filename = full_name;
1807  while (NULL != (ss = strstr (filename, DIR_SEPARATOR_STR)))
1808  filename = ss + 1;
1809  tok_keywords = get_keywords_from_tokens (filename, NULL, 0);
1810  paren_keywords = get_keywords_from_parens (filename, NULL, 0);
1811  }
1812  /* x3 because there might be a normalized variant of every keyword,
1813  plus theoretically one more for mime... */
1814  ret->data.ksk.keywords =
1815  GNUNET_new_array ((ent + tok_keywords + paren_keywords) * 3, char *);
1817  }
1818  if (tok_keywords > 0)
1819  ret->data.ksk.keywordCount +=
1820  get_keywords_from_tokens (filename,
1821  ret->data.ksk.keywords,
1822  ret->data.ksk.keywordCount);
1823  if (paren_keywords > 0)
1824  ret->data.ksk.keywordCount +=
1825  get_keywords_from_parens (filename,
1826  ret->data.ksk.keywords,
1827  ret->data.ksk.keywordCount);
1828  if (ent > 0)
1829  GNUNET_free_non_null (full_name);
1830  return ret;
1831 }
1832 
1833 
1838 static int
1840 {
1841  return(! ((isalnum ((unsigned char) c)) || (c == '-') || (c == '_') ||
1842  (c == '.') || (c == '~')));
1843 }
1844 
1845 
1852 static char *
1854 {
1855  char **keywords;
1856  unsigned int keywordCount;
1857  size_t n;
1858  char *ret;
1859  unsigned int i;
1860  unsigned int j;
1861  unsigned int wpos;
1862  size_t slen;
1863  const char *keyword;
1864 
1865  if (uri->type != GNUNET_FS_URI_KSK)
1866  return NULL;
1867  keywords = uri->data.ksk.keywords;
1868  keywordCount = uri->data.ksk.keywordCount;
1869  n = keywordCount + strlen (GNUNET_FS_URI_PREFIX)
1870  + strlen (GNUNET_FS_URI_KSK_INFIX) + 1;
1871  for (i = 0; i < keywordCount; i++)
1872  {
1873  keyword = keywords[i];
1874  slen = strlen (keyword);
1875  n += slen;
1876  for (j = 0; j < slen; j++)
1877  {
1878  if ((j == 0) && (keyword[j] == ' '))
1879  {
1880  n--;
1881  continue; /* skip leading space */
1882  }
1883  if (needs_percent (keyword[j]))
1884  n += 2; /* will use %-encoding */
1885  }
1886  }
1887  ret = GNUNET_malloc (n);
1888  strcpy (ret, GNUNET_FS_URI_PREFIX);
1889  strcat (ret, GNUNET_FS_URI_KSK_INFIX);
1890  wpos = strlen (ret);
1891  for (i = 0; i < keywordCount; i++)
1892  {
1893  keyword = keywords[i];
1894  slen = strlen (keyword);
1895  for (j = 0; j < slen; j++)
1896  {
1897  if ((j == 0) && (keyword[j] == ' '))
1898  continue; /* skip leading space */
1899  if (needs_percent (keyword[j]))
1900  {
1901  sprintf (&ret[wpos], "%%%02X", (unsigned char) keyword[j]);
1902  wpos += 3;
1903  }
1904  else
1905  {
1906  ret[wpos++] = keyword[j];
1907  }
1908  }
1909  if (i != keywordCount - 1)
1910  ret[wpos++] = '+';
1911  }
1912  return ret;
1913 }
1914 
1915 
1922 static char *
1924 {
1925  char *ret;
1926  char buf[1024];
1927 
1928  if (GNUNET_FS_URI_SKS != uri->type)
1929  return NULL;
1930  ret =
1932  sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
1933  buf,
1934  sizeof(buf));
1935  GNUNET_assert (NULL != ret);
1936  ret[0] = '\0';
1937  GNUNET_asprintf (&ret,
1938  "%s%s%s/%s",
1941  buf,
1942  uri->data.sks.identifier);
1943  return ret;
1944 }
1945 
1946 
1953 static char *
1955 {
1956  const struct FileIdentifier *fi;
1957  char *ret;
1958  struct GNUNET_CRYPTO_HashAsciiEncoded keyhash;
1959  struct GNUNET_CRYPTO_HashAsciiEncoded queryhash;
1960 
1961  if (uri->type != GNUNET_FS_URI_CHK)
1962  return NULL;
1963  fi = &uri->data.chk;
1964  GNUNET_CRYPTO_hash_to_enc (&fi->chk.key, &keyhash);
1965  GNUNET_CRYPTO_hash_to_enc (&fi->chk.query, &queryhash);
1966 
1967  GNUNET_asprintf (&ret,
1968  "%s%s%s.%s.%llu",
1971  (const char *) &keyhash,
1972  (const char *) &queryhash,
1973  GNUNET_ntohll (fi->file_length));
1974  return ret;
1975 }
1976 
1977 
1984 static char *
1986 {
1987  char *ret;
1988  struct GNUNET_CRYPTO_HashAsciiEncoded keyhash;
1989  struct GNUNET_CRYPTO_HashAsciiEncoded queryhash;
1990  char *peer_id;
1991  char peer_sig[SIGNATURE_ASCII_LENGTH + 1];
1992 
1993  GNUNET_CRYPTO_hash_to_enc (&uri->data.loc.fi.chk.key, &keyhash);
1994  GNUNET_CRYPTO_hash_to_enc (&uri->data.loc.fi.chk.query, &queryhash);
1995  peer_id =
1997  GNUNET_assert (
1998  NULL !=
2000  sizeof(struct GNUNET_CRYPTO_EddsaSignature),
2001  peer_sig,
2002  sizeof(peer_sig)));
2003  GNUNET_asprintf (&ret,
2004  "%s%s%s.%s.%llu.%s.%s.%llu",
2007  (const char *) &keyhash,
2008  (const char *) &queryhash,
2009  (unsigned long long) GNUNET_ntohll (
2010  uri->data.loc.fi.file_length),
2011  peer_id,
2012  peer_sig,
2013  (unsigned long long)
2015  / 1000000LL);
2016  GNUNET_free (peer_id);
2017  return ret;
2018 }
2019 
2020 
2027 char *
2029 {
2030  if (uri == NULL)
2031  {
2032  GNUNET_break (0);
2033  return NULL;
2034  }
2035  switch (uri->type)
2036  {
2037  case GNUNET_FS_URI_KSK:
2038  return uri_ksk_to_string (uri);
2039 
2040  case GNUNET_FS_URI_SKS:
2041  return uri_sks_to_string (uri);
2042 
2043  case GNUNET_FS_URI_CHK:
2044  return uri_chk_to_string (uri);
2045 
2046  case GNUNET_FS_URI_LOC:
2047  return uri_loc_to_string (uri);
2048 
2049  default:
2050  GNUNET_break (0);
2051  return NULL;
2052  }
2053 }
2054 
2055 
2056 /* 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:822
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:269
#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:1335
struct ContentHashKey chk
Query and key of the top GNUNET_EC_IBlock.
Definition: fs_api.h:103
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:485
struct FileIdentifier chk
Information needed to retrieve a file (content-hash-key plus file size).
Definition: fs_api.h:211
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:839
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:1155
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:879
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:762
static char * uri_chk_to_string(const struct GNUNET_FS_Uri *uri)
Convert a CHK URI to a string.
Definition: fs_uri.c:1954
uint32_t purpose
What does this signature vouch for? This must contain a GNUNET_SIGNATURE_PURPOSE_XXX constant (from g...
struct GNUNET_FS_Uri::@13::@15 sks
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:644
static struct GNUNET_FS_Uri * uri_loc_parse(const char *s, char **emsg)
Parse a LOC URI.
Definition: fs_uri.c:503
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:1503
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:1411
#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:475
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:1853
static struct GNUNET_FS_Uri * uri_ksk_parse(const char *s, char **emsg)
Parse a KSK URI.
Definition: fs_uri.c:279
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:986
Keyword search key (query with keywords).
Definition: fs_api.h:153
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
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:1642
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:1212
#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:1923
struct GNUNET_PeerIdentity peer
Identity of the peer sharing the file.
Definition: fs_api.h:121
int GNUNET_FS_uri_test_sks(const struct GNUNET_FS_Uri *uri)
Is this a namespace URI?
Definition: fs_uri.c:1282
EXTRACTOR_MetaType
Enumeration defining various sources of keywords.
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:1297
#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:919
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:998
#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:1395
char * GNUNET_FS_uri_to_string(const struct GNUNET_FS_Uri *uri)
Convert a URI to a UTF-8 String.
Definition: fs_uri.c:2028
static struct GNUNET_FS_Uri * uri_sks_parse(const char *s, char **emsg)
Parse an SKS URI.
Definition: fs_uri.c:373
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:1432
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:730
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:185
struct GNUNET_CRYPTO_EccSignaturePurpose purpose
What is being signed (rest of this struct).
Definition: fs_uri.c:470
#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:1113
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:48
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:365
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:1707
#define DIR_SEPARATOR_STR
Definition: platform.h:168
struct GNUNET_HashCode query
Hash of the encrypted content, used for querying.
Definition: fs.h:63
static struct GNUNET_NAMESTORE_Handle * ns
Handle to the namestore.
Definition: gnunet-abd.c:41
#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
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:1534
void GNUNET_FS_uri_destroy(struct GNUNET_FS_Uri *uri)
Free URI.
Definition: fs_uri.c:678
A 512-bit hashcode.
unsigned int keywordCount
Size of the keywords array.
Definition: fs_api.h:190
int GNUNET_FS_uri_test_chk(const struct GNUNET_FS_Uri *uri)
Is this a file (or directory) URI?
Definition: fs_uri.c:1357
#define TOKENS
Where to break up keywords.
Definition: fs_uri.c:1625
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:143
struct FileIdentifier fi
File being offered.
Definition: fs_uri.c:480
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:73
#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:413
#define GNUNET_FS_URI_SKS_PREFIX
Definition: fs_uri.c:363
struct GNUNET_TIME_Absolute expirationTime
Time when this location URI expires.
Definition: fs_api.h:126
enum GNUNET_FS_UriType type
Type of the URI.
Definition: fs_api.h:170
#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:270
union GNUNET_FS_Uri::@13 data
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:1060
0-terminated ASCII encoding of a struct GNUNET_HashCode.
Signed key space (file in namespace).
Definition: fs_api.h:148
struct GNUNET_HashCode key
Hash of the original content, used for encryption.
Definition: fs.h:58
#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:1782
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:499
#define GNUNET_array_append(arr, size, element)
Append an element to a list (growing the list by one).
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:1371
shared definitions for the FS library
A Universal Resource Identifier (URI), opaque.
Definition: fs_api.h:165
#define GNUNET_FS_URI_PREFIX
uint64_t file_length
Total size of the file in bytes.
Definition: fs_api.h:98
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:132
struct GNUNET_FS_Uri::@13::@14 ksk
struct FileIdentifier fi
Information about the shared file.
Definition: fs_api.h:116
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:853
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:712
Location (chk with identity of hosting peer).
Definition: fs_api.h:158
struct Location loc
Information needed to retrieve a file including signed location (identity of a peer) of the content...
Definition: fs_api.h:217
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:942
static int needs_percent(char c)
In URI-encoding, does the given character need to be encoded using %-encoding?
Definition: fs_uri.c:1839
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:1317
static char * normalize_metadata(enum EXTRACTOR_MetaFormat format, const char *data, size_t data_len)
FIXME: comment.
Definition: fs_uri.c:1447
#define SIGNATURE_ASCII_LENGTH
Definition: fs_uri.c:492
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:790
#define GNUNET_FS_URI_LOC_PREFIX
Definition: fs_uri.c:490
#define GNUNET_FS_URI_LOC_INFIX
#define GNUNET_FS_URI_CHK_PREFIX
Definition: fs_uri.c:402
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:1985
struct GNUNET_TIME_AbsoluteNBO GNUNET_TIME_absolute_hton(struct GNUNET_TIME_Absolute a)
Convert absolute time to network byte order.
Definition: time.c:657
#define GNUNET_CRYPTO_hash_from_string(enc, result)
Convert ASCII encoding back to struct GNUNET_HashCode
static char * plugin_name
Name of our plugin.
#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:952
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:856
Structure that defines how the contents of a location URI must be assembled in memory to create or ve...
Definition: fs_uri.c:465
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...