- add subdirectory gitignore files
[oweals/gnunet.git] / src / namestore / gnunet-namestore.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2012, 2013, 2014 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20 /**
21  * @file gnunet-namestore.c
22  * @brief command line tool to manipulate the local zone
23  * @author Christian Grothoff
24  *
25  * TODO:
26  * - test
27  */
28 #include "platform.h"
29 #include <gnunet_util_lib.h>
30 #include <gnunet_dnsparser_lib.h>
31 #include <gnunet_identity_service.h>
32 #include <gnunet_gnsrecord_lib.h>
33 #include <gnunet_gns_service.h>
34 #include <gnunet_namestore_service.h>
35
36
37 /**
38  * Handle to the namestore.
39  */
40 static struct GNUNET_NAMESTORE_Handle *ns;
41
42 /**
43  * Private key for the our zone.
44  */
45 static struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
46
47 /**
48  * Handle to identity lookup.
49  */
50 static struct GNUNET_IDENTITY_EgoLookup *el;
51
52 /**
53  * Identity service handle
54  */
55 static struct GNUNET_IDENTITY_Handle *idh;
56
57 /**
58  * Obtain default ego
59  */
60 struct GNUNET_IDENTITY_Operation *get_default;
61
62 /**
63  * Name of the ego controlling the zone.
64  */
65 static char *ego_name;
66
67 /**
68  * Desired action is to add a record.
69  */
70 static int add;
71
72 /**
73  * Queue entry for the 'add-uri' operation.
74  */
75 static struct GNUNET_NAMESTORE_QueueEntry *add_qe_uri;
76
77 /**
78  * Queue entry for the 'add' operation.
79  */
80 static struct GNUNET_NAMESTORE_QueueEntry *add_qe;
81
82 /**
83  * Queue entry for the 'reverse lookup' operation (in combination with a name).
84  */
85 static struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
86
87 /**
88  * Desired action is to list records.
89  */
90 static int list;
91
92 /**
93  * List iterator for the 'list' operation.
94  */
95 static struct GNUNET_NAMESTORE_ZoneIterator *list_it;
96
97 /**
98  * Desired action is to remove a record.
99  */
100 static int del;
101
102 /**
103  * Is record public (opposite of #GNUNET_GNSRECORD_RF_PRIVATE)
104  */
105 static int is_public;
106
107 /**
108  * Is record a shadow record (#GNUNET_GNSRECORD_RF_SHADOW_RECORD)
109  */
110 static int is_shadow;
111
112 /**
113  * Queue entry for the 'del' operation.
114  */
115 static struct GNUNET_NAMESTORE_QueueEntry *del_qe;
116
117 /**
118  * Name of the records to add/list/remove.
119  */
120 static char *name;
121
122 /**
123  * Value of the record to add/remove.
124  */
125 static char *value;
126
127 /**
128  * URI to import.
129  */
130 static char *uri;
131
132 /**
133  * Reverse lookup to perform.
134  */
135 static char *reverse_pkey;
136
137 /**
138  * Type of the record to add/remove, NULL to remove all.
139  */
140 static char *typestring;
141
142 /**
143  * Desired expiration time.
144  */
145 static char *expirationstring;
146
147 /**
148  * Desired nick name.
149  */
150 static char *nickstring;
151
152 /**
153  * Global return value
154  */
155 static int ret;
156
157 /**
158  * Type string converted to DNS type value.
159  */
160 static uint32_t type;
161
162 /**
163  * Value in binary format.
164  */
165 static void *data;
166
167 /**
168  * Number of bytes in #data.
169  */
170 static size_t data_size;
171
172 /**
173  * Expirationstring converted to relative time.
174  */
175 static struct GNUNET_TIME_Relative etime_rel;
176
177 /**
178  * Expirationstring converted to absolute time.
179  */
180 static struct GNUNET_TIME_Absolute etime_abs;
181
182 /**
183  * Is expiration time relative or absolute time?
184  */
185 static int etime_is_rel = GNUNET_SYSERR;
186
187 /**
188  * Monitor handle.
189  */
190 static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
191
192 /**
193  * Enables monitor mode.
194  */
195 static int monitor;
196
197
198 /**
199  * Task run on shutdown.  Cleans up everything.
200  *
201  * @param cls unused
202  */
203 static void
204 do_shutdown (void *cls)
205 {
206   if (NULL != get_default)
207   {
208     GNUNET_IDENTITY_cancel (get_default);
209     get_default = NULL;
210   }
211   if (NULL != idh)
212   {
213     GNUNET_IDENTITY_disconnect (idh);
214     idh = NULL;
215   }
216   if (NULL != el)
217   {
218     GNUNET_IDENTITY_ego_lookup_cancel (el);
219     el = NULL;
220   }
221   if (NULL != list_it)
222   {
223     GNUNET_NAMESTORE_zone_iteration_stop (list_it);
224     list_it = NULL;
225   }
226   if (NULL != add_qe)
227   {
228     GNUNET_NAMESTORE_cancel (add_qe);
229     add_qe = NULL;
230   }
231   if (NULL != add_qe_uri)
232   {
233     GNUNET_NAMESTORE_cancel (add_qe_uri);
234     add_qe_uri = NULL;
235   }
236   if (NULL != del_qe)
237   {
238     GNUNET_NAMESTORE_cancel (del_qe);
239     del_qe = NULL;
240   }
241   if (NULL != ns)
242   {
243     GNUNET_NAMESTORE_disconnect (ns);
244     ns = NULL;
245   }
246   memset (&zone_pkey, 0, sizeof (zone_pkey));
247   if (NULL != uri)
248   {
249     GNUNET_free (uri);
250     uri = NULL;
251   }
252   if (NULL != zm)
253   {
254     GNUNET_NAMESTORE_zone_monitor_stop (zm);
255     zm = NULL;
256   }
257   if (NULL != data)
258   {
259     GNUNET_free (data);
260     data = NULL;
261   }
262 }
263
264
265 /**
266  * Check if we are finished, and if so, perform shutdown.
267  */
268 static void
269 test_finished ()
270 {
271   if ( (NULL == add_qe) &&
272        (NULL == add_qe_uri) &&
273        (NULL == del_qe) &&
274        (NULL == reverse_qe) &&
275        (NULL == list_it) )
276     GNUNET_SCHEDULER_shutdown ();
277 }
278
279
280 /**
281  * Continuation called to notify client about result of the
282  * operation.
283  *
284  * @param cls closure, location of the QueueEntry pointer to NULL out
285  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
286  *                #GNUNET_NO if content was already there
287  *                #GNUNET_YES (or other positive value) on success
288  * @param emsg NULL on success, otherwise an error message
289  */
290 static void
291 add_continuation (void *cls,
292                   int32_t success,
293                   const char *emsg)
294 {
295   struct GNUNET_NAMESTORE_QueueEntry **qe = cls;
296
297   *qe = NULL;
298   if (GNUNET_YES != success)
299   {
300     fprintf (stderr,
301              _("Adding record failed: %s\n"),
302              (GNUNET_NO == success) ? "record exists" : emsg);
303     if (GNUNET_NO != success)
304       ret = 1;
305   }
306   ret = 0;
307   test_finished ();
308 }
309
310
311 /**
312  * Continuation called to notify client about result of the
313  * operation.
314  *
315  * @param cls closure, unused
316  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
317  *                #GNUNET_NO if content was already there
318  *                #GNUNET_YES (or other positive value) on success
319  * @param emsg NULL on success, otherwise an error message
320  */
321 static void
322 del_continuation (void *cls,
323                   int32_t success,
324                   const char *emsg)
325 {
326   del_qe = NULL;
327   if (GNUNET_NO == success)
328   {
329     fprintf (stderr,
330              _("Deleting record failed, record does not exist%s%s\n"),
331              (NULL != emsg) ? ": " : "",
332              (NULL != emsg) ? emsg : "");
333   }
334   if (GNUNET_SYSERR == success)
335   {
336     fprintf (stderr,
337              _("Deleting record failed%s%s\n"),
338              (NULL != emsg) ? ": " : "",
339              (NULL != emsg) ? emsg : "");
340   }
341   test_finished ();
342 }
343
344
345 /**
346  * Function called when we are done with a zone iteration.
347  */
348 static void
349 zone_iteration_finished (void *cls)
350 {
351   list_it = NULL;
352   test_finished ();
353 }
354
355
356 /**
357  * Function called when we encountered an error in a zone iteration.
358  */
359 static void
360 zone_iteration_error_cb (void *cls)
361 {
362   list_it = NULL;
363   fprintf (stderr,
364            "Error iterating over zone\n");
365   ret = 1;
366   test_finished ();
367 }
368
369
370 /**
371  * Process a record that was stored in the namestore.
372  *
373  * @param cls closure
374  * @param zone_key private key of the zone
375  * @param rname name that is being mapped (at most 255 characters long)
376  * @param rd_len number of entries in @a rd array
377  * @param rd array of records with data to store
378  */
379 static void
380 display_record (void *cls,
381                 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
382                 const char *rname,
383                 unsigned int rd_len,
384                 const struct GNUNET_GNSRECORD_Data *rd)
385 {
386   const char *typestring;
387   char *s;
388   unsigned int i;
389   const char *ets;
390   struct GNUNET_TIME_Absolute at;
391   struct GNUNET_TIME_Relative rt;
392
393   if ( (NULL != name) &&
394        (0 != strcmp (name, rname)) )
395   {
396     GNUNET_NAMESTORE_zone_iterator_next (list_it);
397     return;
398   }
399   FPRINTF (stdout,
400            "%s:\n",
401            rname);
402   for (i=0;i<rd_len;i++)
403   {
404     if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
405          (0 != strcmp (rname,
406                        "+")) )
407       continue;
408     typestring = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
409     s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
410                                           rd[i].data,
411                                           rd[i].data_size);
412     if (NULL == s)
413     {
414       FPRINTF (stdout,
415                _("\tCorrupt or unsupported record of type %u\n"),
416                (unsigned int) rd[i].record_type);
417       continue;
418     }
419     if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
420     {
421       rt.rel_value_us = rd[i].expiration_time;
422       ets = GNUNET_STRINGS_relative_time_to_string (rt, GNUNET_YES);
423     }
424     else
425     {
426       at.abs_value_us = rd[i].expiration_time;
427       ets = GNUNET_STRINGS_absolute_time_to_string (at);
428     }
429     FPRINTF (stdout,
430              "\t%s: %s (%s)\t%s\t%s\n",
431              typestring,
432              s,
433              ets,
434              (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)) ? "PRIVATE" : "PUBLIC",
435              (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)) ? "SHADOW" : "");
436     GNUNET_free (s);
437   }
438   FPRINTF (stdout, "%s", "\n");
439   GNUNET_NAMESTORE_zone_iterator_next (list_it);
440 }
441
442
443 /**
444  * Function called once we are in sync in monitor mode.
445  *
446  * @param cls NULL
447  */
448 static void
449 sync_cb (void *cls)
450 {
451   FPRINTF (stdout, "%s", "Monitor is now in sync.\n");
452 }
453
454
455 /**
456  * Function called on errors while monitoring.
457  *
458  * @param cls NULL
459  */
460 static void
461 monitor_error_cb (void *cls)
462 {
463   FPRINTF (stderr, "%s", "Monitor disconnected and out of sync.\n");
464 }
465
466
467 /**
468  * Function called if lookup fails.
469  */
470 static void
471 lookup_error_cb (void *cls)
472 {
473   add_qe = NULL;
474   GNUNET_break (0);
475   ret = 1;
476   test_finished ();
477 }
478
479
480 /**
481  * We're storing a record; this function is given the existing record
482  * so that we can merge the information.
483  *
484  * @param cls closure, unused
485  * @param zone_key private key of the zone
486  * @param rec_name name that is being mapped (at most 255 characters long)
487  * @param rd_count number of entries in @a rd array
488  * @param rd array of records with data to store
489  */
490 static void
491 get_existing_record (void *cls,
492                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
493                      const char *rec_name,
494                      unsigned int rd_count,
495                      const struct GNUNET_GNSRECORD_Data *rd)
496 {
497   struct GNUNET_GNSRECORD_Data rdn[rd_count + 1];
498   struct GNUNET_GNSRECORD_Data *rde;
499   unsigned int i;
500
501   add_qe = NULL;
502   if (0 != strcmp (rec_name, name))
503   {
504     GNUNET_break (0);
505     ret = 1;
506     test_finished ();
507     return;
508   }
509
510   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
511               "Received %u records for name `%s'\n",
512               rd_count, rec_name);
513   for (i=0;i<rd_count;i++)
514   {
515     switch (rd[i].record_type)
516     {
517     case GNUNET_DNSPARSER_TYPE_CNAME:
518       fprintf (stderr,
519                _("A %s record exists already under `%s', no other records can be added.\n"),
520                "CNAME",
521                rec_name);
522       ret = 1;
523       test_finished ();
524       return;
525     case GNUNET_GNSRECORD_TYPE_PKEY:
526       fprintf (stderr,
527                _("A %s record exists already under `%s', no other records can be added.\n"),
528                "PKEY",
529                rec_name);
530       ret = 1;
531       test_finished ();
532       return;
533     case GNUNET_GNSRECORD_TYPE_GNS2DNS:
534       fprintf (stderr,
535                _("A %s record exists already under `%s', no other records can be added.\n"),
536                "GNS2DNS",
537                rec_name);
538       ret = 1;
539       test_finished ();
540       return;
541     }
542   }
543   switch (type)
544   {
545   case GNUNET_DNSPARSER_TYPE_CNAME:
546     if (0 != rd_count)
547     {
548       fprintf (stderr,
549                _("Records already exist under `%s', cannot add `%s' record.\n"),
550                rec_name,
551                "CNAME");
552       ret = 1;
553       test_finished ();
554       return;
555     }
556     break;
557   case GNUNET_GNSRECORD_TYPE_PKEY:
558     if (0 != rd_count)
559     {
560       fprintf (stderr,
561                _("Records already exist under `%s', cannot add `%s' record.\n"),
562                rec_name,
563                "PKEY");
564       ret = 1;
565       test_finished ();
566       return;
567     }
568     break;
569   case GNUNET_GNSRECORD_TYPE_GNS2DNS:
570     if (0 != rd_count)
571     {
572       fprintf (stderr,
573                _("Records already exist under `%s', cannot add `%s' record.\n"),
574                rec_name,
575                "GNS2DNS");
576       ret = 1;
577       test_finished ();
578       return;
579     }
580     break;
581   }
582   memset (rdn, 0, sizeof (struct GNUNET_GNSRECORD_Data));
583   GNUNET_memcpy (&rdn[1],
584                  rd,
585                  rd_count * sizeof (struct GNUNET_GNSRECORD_Data));
586   rde = &rdn[0];
587   rde->data = data;
588   rde->data_size = data_size;
589   rde->record_type = type;
590   if (1 == is_shadow)
591     rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
592   if (1 != is_public)
593     rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
594   if (GNUNET_YES == etime_is_rel)
595   {
596     rde->expiration_time = etime_rel.rel_value_us;
597     rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
598   }
599   else if (GNUNET_NO == etime_is_rel)
600     rde->expiration_time = etime_abs.abs_value_us;
601   else
602     rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
603   GNUNET_assert (NULL != name);
604   add_qe = GNUNET_NAMESTORE_records_store (ns,
605                                            &zone_pkey,
606                                            name,
607                                            rd_count + 1,
608                                            rde,
609                                            &add_continuation,
610                                            &add_qe);
611 }
612
613
614 /**
615  * Function called if we encountered an error in zone-to-name.
616  */
617 static void
618 reverse_error_cb (void *cls)
619 {
620   reverse_qe = NULL;
621   FPRINTF (stdout,
622            "%s.zkey\n",
623            reverse_pkey);
624 }
625
626
627 /**
628  * Function called with the result of our attempt to obtain a name for a given
629  * public key.
630  *
631  * @param cls NULL
632  * @param zone private key of the zone; NULL on disconnect
633  * @param label label of the records; NULL on disconnect
634  * @param rd_count number of entries in @a rd array, 0 if label was deleted
635  * @param rd array of records with data to store
636  */
637 static void
638 handle_reverse_lookup (void *cls,
639                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
640                        const char *label,
641                        unsigned int rd_count,
642                        const struct GNUNET_GNSRECORD_Data *rd)
643 {
644   reverse_qe = NULL;
645   if (NULL == label)
646     FPRINTF (stdout,
647              "%s.zkey\n",
648              reverse_pkey);
649   else
650     FPRINTF (stdout,
651              "%s.gnu\n",
652              label);
653   test_finished ();
654 }
655
656
657 /**
658  * Function called if lookup for deletion fails.
659  */
660 static void
661 del_lookup_error_cb (void *cls)
662 {
663   del_qe = NULL;
664   GNUNET_break (0);
665   ret = 1;
666   test_finished ();
667 }
668
669
670 /**
671  * We were asked to delete something; this function is called with
672  * the existing records. Now we should determine what should be
673  * deleted and then issue the deletion operation.
674  *
675  * @param cls NULL
676  * @param zone private key of the zone we are deleting from
677  * @param label name of the records we are editing
678  * @param rd_count size of the @a rd array
679  * @param rd existing records
680  */
681 static void
682 del_monitor (void *cls,
683              const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
684              const char *label,
685              unsigned int rd_count,
686              const struct GNUNET_GNSRECORD_Data *rd)
687 {
688   struct GNUNET_GNSRECORD_Data rdx[rd_count];
689   unsigned int rd_left;
690   unsigned int i;
691   uint32_t type;
692   char *vs;
693
694   del_qe = NULL;
695   if (0 == rd_count)
696   {
697     FPRINTF (stderr,
698              _("There are no records under label `%s' that could be deleted.\n"),
699              label);
700     ret = 1;
701     test_finished ();
702     return;
703   }
704   if ( (NULL == value) &&
705        (NULL == typestring) )
706   {
707     /* delete everything */
708     del_qe = GNUNET_NAMESTORE_records_store (ns,
709                                              &zone_pkey,
710                                              name,
711                                              0,
712                                              NULL,
713                                              &del_continuation,
714                                              NULL);
715     return;
716   }
717   rd_left = 0;
718   if (NULL != typestring)
719     type = GNUNET_GNSRECORD_typename_to_number (typestring);
720   else
721     type = GNUNET_GNSRECORD_TYPE_ANY;
722   for (i=0;i<rd_count;i++)
723   {
724     vs = NULL;
725     if (! ( ( (GNUNET_GNSRECORD_TYPE_ANY == type) ||
726               (rd[i].record_type == type) ) &&
727             ( (NULL == value) ||
728               (NULL == (vs = (GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
729                                                                 rd[i].data,
730                                                                 rd[i].data_size)))) ||
731               (0 == strcmp (vs, value)) ) ) )
732       rdx[rd_left++] = rd[i];
733     GNUNET_free_non_null (vs);
734   }
735   if (rd_count == rd_left)
736   {
737     /* nothing got deleted */
738     FPRINTF (stderr,
739              _("There are no records under label `%s' that match the request for deletion.\n"),
740              label);
741     test_finished ();
742     return;
743   }
744   /* delete everything but what we copied to 'rdx' */
745   del_qe = GNUNET_NAMESTORE_records_store (ns,
746                                            &zone_pkey,
747                                            name,
748                                            rd_left,
749                                            rdx,
750                                            &del_continuation,
751                                            NULL);
752 }
753
754
755 /**
756  * Callback invoked from identity service with ego information.
757  * An @a ego of NULL means the ego was not found.
758  *
759  * @param cls closure with the configuration
760  * @param ego an ego known to identity service, or NULL
761  */
762 static void
763 identity_cb (void *cls,
764              const struct GNUNET_IDENTITY_Ego *ego)
765 {
766   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
767   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
768   struct GNUNET_GNSRECORD_Data rd;
769
770   el = NULL;
771   if (NULL == ego)
772   {
773     if (NULL != ego_name)
774     {
775       fprintf (stderr,
776                _("Ego `%s' not known to identity service\n"),
777                ego_name);
778     }
779     GNUNET_SCHEDULER_shutdown ();
780     ret = -1;
781     return;
782   }
783   zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
784   GNUNET_free_non_null (ego_name);
785   ego_name = NULL;
786
787   if (! (add|del|list|(NULL != nickstring)|(NULL != uri)|(NULL != reverse_pkey)) )
788   {
789     /* nothing more to be done */
790     fprintf (stderr,
791              _("No options given\n"));
792     GNUNET_SCHEDULER_shutdown ();
793     return;
794   }
795   GNUNET_CRYPTO_ecdsa_key_get_public (&zone_pkey,
796                                     &pub);
797
798   ns = GNUNET_NAMESTORE_connect (cfg);
799   if (NULL == ns)
800   {
801     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
802                 _("Failed to connect to namestore\n"));
803     return;
804   }
805   if (add)
806   {
807     if (NULL == name)
808     {
809       fprintf (stderr,
810                _("Missing option `%s' for operation `%s'\n"),
811                "-n", _("add"));
812       GNUNET_SCHEDULER_shutdown ();
813       ret = 1;
814       return;
815     }
816     if (NULL == typestring)
817     {
818       fprintf (stderr,
819                _("Missing option `%s' for operation `%s'\n"),
820                "-t", _("add"));
821       GNUNET_SCHEDULER_shutdown ();
822       ret = 1;
823       return;
824     }
825     type = GNUNET_GNSRECORD_typename_to_number (typestring);
826     if (UINT32_MAX == type)
827     {
828       fprintf (stderr,
829                _("Unsupported type `%s'\n"),
830                typestring);
831       GNUNET_SCHEDULER_shutdown ();
832       ret = 1;
833       return;
834     }
835     if (NULL == value)
836     {
837       fprintf (stderr,
838                _("Missing option `%s' for operation `%s'\n"),
839                "-V", _("add"));
840       ret = 1;
841       GNUNET_SCHEDULER_shutdown ();
842       return;
843     }
844     if (GNUNET_OK !=
845         GNUNET_GNSRECORD_string_to_value (type,
846                                           value,
847                                           &data,
848                                           &data_size))
849     {
850       fprintf (stderr,
851                _("Value `%s' invalid for record type `%s'\n"),
852                value,
853                typestring);
854       GNUNET_SCHEDULER_shutdown ();
855       ret = 1;
856       return;
857     }
858     if (NULL == expirationstring)
859     {
860       fprintf (stderr,
861                _("Missing option `%s' for operation `%s'\n"),
862                "-e",
863                _("add"));
864       GNUNET_SCHEDULER_shutdown ();
865       ret = 1;
866       return;
867     }
868     if (0 == strcmp (expirationstring,
869                      "never"))
870     {
871       etime_abs = GNUNET_TIME_UNIT_FOREVER_ABS;
872       etime_is_rel = GNUNET_NO;
873     }
874     else if (GNUNET_OK ==
875              GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
876                                                     &etime_rel))
877     {
878       etime_is_rel = GNUNET_YES;
879       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
880                   "Storing record with relative expiration time of %s\n",
881                   GNUNET_STRINGS_relative_time_to_string (etime_rel,
882                                                           GNUNET_NO));
883     }
884     else if (GNUNET_OK ==
885              GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
886                                                     &etime_abs))
887     {
888       etime_is_rel = GNUNET_NO;
889       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
890                   "Storing record with absolute expiration time of %s\n",
891                   GNUNET_STRINGS_absolute_time_to_string (etime_abs));
892     }
893     else
894     {
895       fprintf (stderr,
896                _("Invalid time format `%s'\n"),
897                expirationstring);
898       GNUNET_SCHEDULER_shutdown ();
899       ret = 1;
900       return;
901     }
902     add_qe = GNUNET_NAMESTORE_records_lookup (ns,
903                                               &zone_pkey,
904                                               name,
905                                               &lookup_error_cb,
906                                               NULL,
907                                               &get_existing_record,
908                                               NULL);
909   }
910   if (del)
911   {
912     if (NULL == name)
913     {
914       fprintf (stderr,
915                _("Missing option `%s' for operation `%s'\n"),
916                "-n", _("del"));
917       GNUNET_SCHEDULER_shutdown ();
918       ret = 1;
919       return;
920     }
921     del_qe = GNUNET_NAMESTORE_records_lookup (ns,
922                                               &zone_pkey,
923                                               name,
924                                               &del_lookup_error_cb,
925                                               NULL,
926                                               &del_monitor,
927                                               NULL);
928   }
929   if (list)
930   {
931     list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
932                                                      &zone_pkey,
933                                                      &zone_iteration_error_cb,
934                                                      NULL,
935                                                      &display_record,
936                                                      NULL,
937                                                      &zone_iteration_finished,
938                                                      NULL);
939   }
940   if (NULL != reverse_pkey)
941   {
942     struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
943
944     if (GNUNET_OK !=
945         GNUNET_CRYPTO_ecdsa_public_key_from_string (reverse_pkey,
946                                                     strlen (reverse_pkey),
947                                                     &pubkey))
948     {
949       fprintf (stderr,
950                _("Invalid public key for reverse lookup `%s'\n"),
951                reverse_pkey);
952       GNUNET_SCHEDULER_shutdown ();
953     }
954     reverse_qe = GNUNET_NAMESTORE_zone_to_name (ns,
955                                                 &zone_pkey,
956                                                 &pubkey,
957                                                 &reverse_error_cb,
958                                                 NULL,
959                                                 &handle_reverse_lookup,
960                                                 NULL);
961   }
962   if (NULL != uri)
963   {
964     char sh[105];
965     char sname[64];
966     struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
967
968     GNUNET_STRINGS_utf8_tolower (uri, uri);
969     if ( (2 != (sscanf (uri,
970                         "gnunet://gns/%52s/%63s",
971                         sh,
972                         sname)) ) ||
973          (GNUNET_OK !=
974           GNUNET_CRYPTO_ecdsa_public_key_from_string (sh,
975                                                       strlen (sh),
976                                                       &pkey)) )
977     {
978       fprintf (stderr,
979                _("Invalid URI `%s'\n"),
980                uri);
981       GNUNET_SCHEDULER_shutdown ();
982       ret = 1;
983       return;
984     }
985     memset (&rd, 0, sizeof (rd));
986     rd.data = &pkey;
987     rd.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
988     rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
989     if (GNUNET_YES == etime_is_rel)
990     {
991       rd.expiration_time = etime_rel.rel_value_us;
992       rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
993     }
994     else if (GNUNET_NO == etime_is_rel)
995       rd.expiration_time = etime_abs.abs_value_us;
996     else
997       rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
998
999     if (1 == is_shadow)
1000       rd.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
1001     add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
1002                                                  &zone_pkey,
1003                                                  sname,
1004                                                  1,
1005                                                  &rd,
1006                                                  &add_continuation,
1007                                                  &add_qe_uri);
1008   }
1009   if (NULL != nickstring)
1010   {
1011     if (0 == strlen(nickstring))
1012     {
1013       fprintf (stderr,
1014                _("Invalid nick `%s'\n"),
1015                nickstring);
1016       GNUNET_SCHEDULER_shutdown ();
1017       ret = 1;
1018       return;
1019     }
1020     add_qe_uri = GNUNET_NAMESTORE_set_nick (ns,
1021                                             &zone_pkey,
1022                                             nickstring,
1023                                             &add_continuation,
1024                                             &add_qe_uri);
1025   }
1026   if (monitor)
1027   {
1028     zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
1029                                               &zone_pkey,
1030                                               GNUNET_YES,
1031                                               &monitor_error_cb,
1032                                               NULL,
1033                                               &display_record,
1034                                               NULL,
1035                                               &sync_cb,
1036                                               NULL);
1037   }
1038 }
1039
1040
1041 static void
1042 default_ego_cb (void *cls,
1043                 struct GNUNET_IDENTITY_Ego *ego,
1044                 void **ctx,
1045                 const char *name)
1046 {
1047   get_default = NULL;
1048   if (NULL == ego)
1049   {
1050     fprintf (stderr,
1051              _("No default ego configured in identity service\n"));
1052     GNUNET_SCHEDULER_shutdown ();
1053     ret = -1;
1054     return;
1055   }
1056   else
1057   {
1058     identity_cb (cls, ego);
1059   }
1060 }
1061
1062
1063 static void
1064 id_connect_cb (void *cls,
1065                struct GNUNET_IDENTITY_Ego *ego,
1066                void **ctx,
1067                const char *name)
1068 {
1069   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1070
1071   if (NULL == ego)
1072   {
1073     get_default = GNUNET_IDENTITY_get (idh,
1074                                        "namestore",
1075                                        &default_ego_cb,
1076                                        (void *) cfg);
1077   }
1078 }
1079
1080
1081 /**
1082  * Main function that will be run.
1083  *
1084  * @param cls closure
1085  * @param args remaining command-line arguments
1086  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1087  * @param cfg configuration
1088  */
1089 static void
1090 run (void *cls,
1091      char *const *args,
1092      const char *cfgfile,
1093      const struct GNUNET_CONFIGURATION_Handle *cfg)
1094 {
1095   if ( (NULL != args[0]) && (NULL == uri) )
1096     uri = GNUNET_strdup (args[0]);
1097
1098   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1099                                  (void *) cfg);
1100
1101   if (NULL == ego_name)
1102   {
1103     idh = GNUNET_IDENTITY_connect (cfg,
1104                                    &id_connect_cb,
1105                                    (void *) cfg);
1106     if (NULL == idh)
1107       fprintf (stderr,
1108                _("Cannot connect to identity service\n"));
1109     ret = -1;
1110     return;
1111   }
1112   el = GNUNET_IDENTITY_ego_lookup (cfg,
1113                                    ego_name,
1114                                    &identity_cb,
1115                                    (void *) cfg);
1116 }
1117
1118
1119 /**
1120  * The main function for gnunet-namestore.
1121  *
1122  * @param argc number of arguments from the command line
1123  * @param argv command line arguments
1124  * @return 0 ok, 1 on error
1125  */
1126 int
1127 main (int argc,
1128       char *const *argv)
1129 {
1130   is_public = -1;
1131   is_shadow = -1;
1132
1133   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1134     {'a', "add", NULL,
1135      gettext_noop ("add record"), 0,
1136      &GNUNET_GETOPT_set_one, &add},
1137     {'d', "delete", NULL,
1138      gettext_noop ("delete record"), 0,
1139      &GNUNET_GETOPT_set_one, &del},
1140     {'D', "display", NULL,
1141      gettext_noop ("display records"), 0,
1142      &GNUNET_GETOPT_set_one, &list},
1143     {'e', "expiration", "TIME",
1144      gettext_noop ("expiration time for record to use (for adding only), \"never\" is possible"), 1,
1145      &GNUNET_GETOPT_set_string, &expirationstring},
1146     {'i', "nick", "NICKNAME",
1147      gettext_noop ("set the desired nick name for the zone"), 1,
1148      &GNUNET_GETOPT_set_string, &nickstring},
1149     {'m', "monitor", NULL,
1150      gettext_noop ("monitor changes in the namestore"), 0,
1151      &GNUNET_GETOPT_set_one, &monitor},
1152     {'n', "name", "NAME",
1153      gettext_noop ("name of the record to add/delete/display"), 1,
1154      &GNUNET_GETOPT_set_string, &name},
1155     {'r', "reverse", "PKEY",
1156      gettext_noop ("determine our name for the given PKEY"), 1,
1157      &GNUNET_GETOPT_set_string, &reverse_pkey},
1158     {'t', "type", "TYPE",
1159      gettext_noop ("type of the record to add/delete/display"), 1,
1160      &GNUNET_GETOPT_set_string, &typestring},
1161     {'u', "uri", "URI",
1162      gettext_noop ("URI to import into our zone"), 1,
1163      &GNUNET_GETOPT_set_string, &uri},
1164     {'V', "value", "VALUE",
1165      gettext_noop ("value of the record to add/delete"), 1,
1166      &GNUNET_GETOPT_set_string, &value},
1167     {'p', "public", NULL,
1168      gettext_noop ("create or list public record"), 0,
1169      &GNUNET_GETOPT_set_one, &is_public},
1170     {'s', "shadow", NULL,
1171      gettext_noop ("create shadow record (only valid if all other records of the same type have expired"), 0,
1172      &GNUNET_GETOPT_set_one, &is_shadow},
1173     {'z', "zone", "EGO",
1174      gettext_noop ("name of the ego controlling the zone"), 1,
1175      &GNUNET_GETOPT_set_string, &ego_name},
1176     GNUNET_GETOPT_OPTION_END
1177   };
1178
1179   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1180     return 2;
1181
1182   GNUNET_log_setup ("gnunet-namestore",
1183                     "WARNING",
1184                     NULL);
1185   if (GNUNET_OK !=
1186       GNUNET_PROGRAM_run (argc,
1187                           argv,
1188                           "gnunet-namestore",
1189                           _("GNUnet zone manipulation tool"),
1190                           options,
1191                           &run, NULL))
1192   {
1193     GNUNET_free ((void*) argv);
1194     GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
1195     return 1;
1196   }
1197   GNUNET_free ((void*) argv);
1198   GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
1199   return ret;
1200 }
1201
1202 /* end of gnunet-namestore.c */