-fixes
[oweals/gnunet.git] / src / namestore / gnunet-namestore.c
1
2 /*
3      This file is part of GNUnet.
4      (C) 2012, 2013 Christian Grothoff (and other contributing authors)
5
6      GNUnet is free software; you can redistribute it and/or modify
7      it under the terms of the GNU General Public License as published
8      by the Free Software Foundation; either version 3, or (at your
9      option) any later version.
10
11      GNUnet is distributed in the hope that it will be useful, but
12      WITHOUT ANY WARRANTY; without even the implied warranty of
13      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14      General Public License for more details.
15
16      You should have received a copy of the GNU General Public License
17      along with GNUnet; see the file COPYING.  If not, write to the
18      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19      Boston, MA 02111-1307, USA.
20 */
21 /**
22  * @file gnunet-namestore.c
23  * @brief command line tool to manipulate the local zone
24  * @author Christian Grothoff
25  *
26  * TODO:
27  * - test
28  */
29 #include "platform.h"
30 #include <gnunet_util_lib.h>
31 #include <gnunet_dnsparser_lib.h>
32 #include <gnunet_identity_service.h>
33 #include <gnunet_gnsrecord_lib.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  * Name of the ego controlling the zone.
54  */
55 static char *ego_name;
56
57 /**
58  * Desired action is to add a record.
59  */
60 static int add;
61
62 /**
63  * Iterator for the 'add' operation.
64  */
65 static struct GNUNET_NAMESTORE_ZoneIterator *add_zit;
66
67 /**
68  * Queue entry for the 'add-uri' operation.
69  */
70 static struct GNUNET_NAMESTORE_QueueEntry *add_qe_uri;
71
72 /**
73  * Queue entry for the 'add' operation.
74  */
75 static struct GNUNET_NAMESTORE_QueueEntry *add_qe;
76
77 /**
78  * Queue entry for the 'reverse lookup' operation (in combination with a name).
79  */
80 static struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
81
82 /**
83  * Desired action is to list records.
84  */
85 static int list;
86
87 /**
88  * List iterator for the 'list' operation.
89  */
90 static struct GNUNET_NAMESTORE_ZoneIterator *list_it;
91
92 /**
93  * Desired action is to remove a record.
94  */
95 static int del;
96
97 /**
98  * Is record public (opposite of #GNUNET_GNSRECORD_RF_PRIVATE)
99  */
100 static int public;
101
102 /**
103  * Is record a shadow record (#GNUNET_GNSRECORD_RF_SHADOW_RECORD)
104  */
105 static int shadow;
106
107 /**
108  * Queue entry for the 'del' operation.
109  */
110 static struct GNUNET_NAMESTORE_QueueEntry *del_qe;
111
112 /**
113  * Name of the records to add/list/remove.
114  */
115 static char *name;
116
117 /**
118  * Value of the record to add/remove.
119  */
120 static char *value;
121
122 /**
123  * URI to import.
124  */
125 static char *uri;
126
127 /**
128  * Reverse lookup to perform.
129  */
130 static char *reverse_pkey;
131
132 /**
133  * Type of the record to add/remove, NULL to remove all.
134  */
135 static char *typestring;
136
137 /**
138  * Desired expiration time.
139  */
140 static char *expirationstring;
141
142 /**
143  * Global return value
144  */
145 static int ret;
146
147 /**
148  * Type string converted to DNS type value.
149  */
150 static uint32_t type;
151
152 /**
153  * Value in binary format.
154  */
155 static void *data;
156
157 /**
158  * Number of bytes in 'data'.
159  */
160 static size_t data_size;
161
162 /**
163  * Expirationstring converted to relative time.
164  */
165 static struct GNUNET_TIME_Relative etime_rel;
166
167 /**
168  * Expirationstring converted to absolute time.
169  */
170 static struct GNUNET_TIME_Absolute etime_abs;
171
172 /**
173  * Is expiration time relative or absolute time?
174  */
175 static int etime_is_rel = GNUNET_SYSERR;
176
177 /**
178  * Monitor handle.
179  */
180 static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
181
182 /**
183  * Enables monitor mode.
184  */
185 static int monitor;
186
187
188 /**
189  * Task run on shutdown.  Cleans up everything.
190  *
191  * @param cls unused
192  * @param tc scheduler context
193  */
194 static void
195 do_shutdown (void *cls,
196              const struct GNUNET_SCHEDULER_TaskContext *tc)
197 {
198   if (NULL != el)
199   {
200     GNUNET_IDENTITY_ego_lookup_cancel (el);
201     el = NULL;
202   }
203   if (NULL != list_it)
204   {
205     GNUNET_NAMESTORE_zone_iteration_stop (list_it);
206     list_it = NULL;
207   }
208   if (NULL != add_qe)
209   {
210     GNUNET_NAMESTORE_cancel (add_qe);
211     add_qe = NULL;
212   }
213   if (NULL != add_qe_uri)
214   {
215     GNUNET_NAMESTORE_cancel (add_qe_uri);
216     add_qe_uri = NULL;
217   }
218   if (NULL != del_qe)
219   {
220     GNUNET_NAMESTORE_cancel (del_qe);
221     del_qe = NULL;
222   }
223   if (NULL != ns)
224   {
225     GNUNET_NAMESTORE_disconnect (ns);
226     ns = NULL;
227   }
228   memset (&zone_pkey, 0, sizeof (zone_pkey));
229   if (NULL != uri)
230   {
231     GNUNET_free (uri);
232     uri = NULL;
233   }
234   if (NULL != zm)
235   {
236     GNUNET_NAMESTORE_zone_monitor_stop (zm);
237     zm = NULL;
238   }
239   if (NULL != data)
240   {
241     GNUNET_free (data);
242     data = NULL;
243   }
244 }
245
246
247 /**
248  * Check if we are finished, and if so, perform shutdown.
249  */
250 static void
251 test_finished ()
252 {
253   if ( (NULL == add_qe) &&
254        (NULL == add_qe_uri) &&
255        (NULL == del_qe) &&
256        (NULL == reverse_qe) &&
257        (NULL == list_it) )
258     GNUNET_SCHEDULER_shutdown ();
259 }
260
261
262 /**
263  * Continuation called to notify client about result of the
264  * operation.
265  *
266  * @param cls closure, location of the QueueEntry pointer to NULL out
267  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
268  *                #GNUNET_NO if content was already there
269  *                #GNUNET_YES (or other positive value) on success
270  * @param emsg NULL on success, otherwise an error message
271  */
272 static void
273 add_continuation (void *cls,
274                   int32_t success,
275                   const char *emsg)
276 {
277   struct GNUNET_NAMESTORE_QueueEntry **qe = cls;
278
279   *qe = NULL;
280   if (GNUNET_YES != success)
281   {
282     fprintf (stderr,
283              _("Adding record failed: %s\n"),
284              (GNUNET_NO == success) ? "record exists" : emsg);
285     if (GNUNET_NO != success)
286       ret = 1;
287   }
288   test_finished ();
289 }
290
291
292 /**
293  * Continuation called to notify client about result of the
294  * operation.
295  *
296  * @param cls closure, unused
297  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
298  *                #GNUNET_NO if content was already there
299  *                #GNUNET_YES (or other positive value) on success
300  * @param emsg NULL on success, otherwise an error message
301  */
302 static void
303 del_continuation (void *cls,
304                   int32_t success,
305                   const char *emsg)
306 {
307   del_qe = NULL;
308   if (success != GNUNET_YES)
309     fprintf (stderr,
310              _("Deleting record failed: %s\n"),
311              emsg);
312   test_finished ();
313 }
314
315
316 /**
317  * Process a record that was stored in the namestore.
318  *
319  * @param cls closure
320  * @param zone_key private key of the zone
321  * @param rname name that is being mapped (at most 255 characters long)
322  * @param rd_len number of entries in @a rd array
323  * @param rd array of records with data to store
324  */
325 static void
326 display_record (void *cls,
327                 const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
328                 const char *rname,
329                 unsigned int rd_len,
330                 const struct GNUNET_GNSRECORD_Data *rd)
331 {
332   const char *typestring;
333   char *s;
334   unsigned int i;
335   const char *ets;
336   struct GNUNET_TIME_Absolute at;
337   struct GNUNET_TIME_Relative rt;
338
339   if (NULL == rname)
340   {
341     list_it = NULL;
342     test_finished ();
343     return;
344   }
345   if ( (NULL != name) &&
346        (0 != strcmp (name, rname)) )
347   {
348     GNUNET_NAMESTORE_zone_iterator_next (list_it);
349     return;
350   }
351   FPRINTF (stdout,
352            "%s:\n",
353            rname);
354   for (i=0;i<rd_len;i++)
355   {
356     typestring = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
357     s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
358                                           rd[i].data,
359                                           rd[i].data_size);
360     if (NULL == s)
361     {
362       FPRINTF (stdout, _("\tCorrupt or unsupported record of type %u\n"),
363                (unsigned int) rd[i].record_type);
364       continue;
365     }
366     if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
367     {
368       rt.rel_value_us = rd[i].expiration_time;
369       ets = GNUNET_STRINGS_relative_time_to_string (rt, GNUNET_YES);
370     }
371     else
372     {
373       at.abs_value_us = rd[i].expiration_time;
374       ets = GNUNET_STRINGS_absolute_time_to_string (at);
375     }
376     FPRINTF (stdout,
377              "\t%s: %s (%s)\n",
378              typestring,
379              s,
380              ets);
381     GNUNET_free (s);
382   }
383   FPRINTF (stdout, "%s", "\n");
384   GNUNET_NAMESTORE_zone_iterator_next (list_it);
385 }
386
387
388 /**
389  * Function called once we are in sync in monitor mode.
390  *
391  * @param cls NULL
392  */
393 static void
394 sync_cb (void *cls)
395 {
396   FPRINTF (stdout, "%s", "Monitor is now in sync.\n");
397 }
398
399
400 /**
401  * We're storing a record; this function is given the existing record
402  * so that we can merge the information.
403  *
404  * @param cls closure, unused
405  * @param zone_key private key of the zone
406  * @param rec_name name that is being mapped (at most 255 characters long)
407  * @param rd_count number of entries in @a rd array
408  * @param rd array of records with data to store
409  */
410 static void
411 get_existing_record (void *cls,
412                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
413                      const char *rec_name,
414                      unsigned int rd_count,
415                      const struct GNUNET_GNSRECORD_Data *rd)
416 {
417   struct GNUNET_GNSRECORD_Data rdn[rd_count + 1];
418   struct GNUNET_GNSRECORD_Data *rde;
419
420   if ( (NULL != zone_key) &&
421        (0 != strcmp (rec_name, name)) )
422   {
423     GNUNET_NAMESTORE_zone_iterator_next (add_zit);
424     return;
425   }
426   memset (rdn, 0, sizeof (struct GNUNET_GNSRECORD_Data));
427   memcpy (&rdn[1], rd, rd_count * sizeof (struct GNUNET_GNSRECORD_Data));
428   /* FIXME: should add some logic to overwrite records if there
429      can only be one record of a particular type, and to check
430      if the combination of records is valid to begin with... */
431   rde = &rdn[0];
432   rde->data = data;
433   rde->data_size = data_size;
434   rde->record_type = type;
435   if (1 != shadow)
436     rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
437   if (1 != public)
438     rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
439   if (GNUNET_YES == etime_is_rel)
440   {
441     rde->expiration_time = etime_rel.rel_value_us;
442     rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
443   }
444   else if (GNUNET_NO == etime_is_rel)
445     rde->expiration_time = etime_abs.abs_value_us;
446   else
447     rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
448   GNUNET_assert (NULL != name);
449   add_qe = GNUNET_NAMESTORE_records_store (ns,
450                                            &zone_pkey,
451                                            name,
452                                            rd_count + 1,
453                                            rde,
454                                            &add_continuation,
455                                            &add_qe);
456   /* only cancel if we were not told that this
457      was the end of the iteration already */
458   if (NULL != rec_name)
459     GNUNET_NAMESTORE_zone_iteration_stop (add_zit);
460   add_zit = NULL;
461 }
462
463
464 /**
465  * Function called with the result of our attempt to obtain a name for a given
466  * public key.
467  *
468  * @param cls NULL
469  * @param zone private key of the zone; NULL on disconnect
470  * @param label label of the records; NULL on disconnect
471  * @param rd_count number of entries in @a rd array, 0 if label was deleted
472  * @param rd array of records with data to store
473  */
474 static void
475 handle_reverse_lookup (void *cls,
476                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
477                        const char *label,
478                        unsigned int rd_count,
479                        const struct GNUNET_GNSRECORD_Data *rd)
480 {
481   reverse_qe = NULL;
482   if (NULL == label)
483     FPRINTF (stdout,
484              "%s.zkey\n",
485              reverse_pkey);
486   else
487     FPRINTF (stdout,
488              "%s.gnu\n",
489              label);
490   test_finished ();
491 }
492
493
494 /**
495  * Function called with the result from the check if the namestore
496  * service is actually running.  If it is, we start the actual
497  * operation.
498  *
499  * @param cls closure with our configuration
500  * @param result #GNUNET_YES if the namestore service is running
501  */
502 static void
503 testservice_task (void *cls,
504                   int result)
505 {
506   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
507   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
508   struct GNUNET_GNSRECORD_Data rd;
509
510   if (GNUNET_YES != result)
511   {
512     FPRINTF (stderr, _("Service `%s' is not running\n"),
513              "namestore");
514     return;
515   }
516   if (! (add|del|list|(NULL != uri)|(NULL != reverse_pkey)) )
517   {
518     /* nothing more to be done */
519     fprintf (stderr,
520              _("No options given\n"));
521     GNUNET_SCHEDULER_shutdown ();
522     return;
523   }
524   GNUNET_CRYPTO_ecdsa_key_get_public (&zone_pkey,
525                                     &pub);
526
527   ns = GNUNET_NAMESTORE_connect (cfg);
528   if (NULL == ns)
529   {
530     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
531                 _("Failed to connect to namestore\n"));
532     return;
533   }
534   if (add)
535   {
536     if (NULL == name)
537     {
538       fprintf (stderr,
539                _("Missing option `%s' for operation `%s'\n"),
540                "-n", _("add"));
541       GNUNET_SCHEDULER_shutdown ();
542       ret = 1;
543       return;
544     }
545     if (NULL == typestring)
546     {
547       fprintf (stderr,
548                _("Missing option `%s' for operation `%s'\n"),
549                "-t", _("add"));
550       GNUNET_SCHEDULER_shutdown ();
551       ret = 1;
552       return;
553     }
554     type = GNUNET_GNSRECORD_typename_to_number (typestring);
555     if (UINT32_MAX == type)
556     {
557       fprintf (stderr, _("Unsupported type `%s'\n"), typestring);
558       GNUNET_SCHEDULER_shutdown ();
559       ret = 1;
560       return;
561     }
562     if (NULL == value)
563     {
564       fprintf (stderr,
565                _("Missing option `%s' for operation `%s'\n"),
566                "-V", _("add"));
567       ret = 1;
568       GNUNET_SCHEDULER_shutdown ();
569       return;
570     }
571     if (GNUNET_OK !=
572         GNUNET_GNSRECORD_string_to_value (type,
573                                           value,
574                                           &data,
575                                           &data_size))
576     {
577       fprintf (stderr, _("Value `%s' invalid for record type `%s'\n"),
578                value,
579                typestring);
580       GNUNET_SCHEDULER_shutdown ();
581       ret = 1;
582       return;
583     }
584     if (NULL == expirationstring)
585     {
586       fprintf (stderr,
587                _("Missing option `%s' for operation `%s'\n"),
588                "-e", _("add"));
589       GNUNET_SCHEDULER_shutdown ();
590       ret = 1;
591       return;
592     }
593     if (0 == strcmp (expirationstring, "never"))
594     {
595       etime_abs = GNUNET_TIME_UNIT_FOREVER_ABS;
596       etime_is_rel = GNUNET_NO;
597     }
598     else if (GNUNET_OK ==
599              GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
600                                                     &etime_rel))
601     {
602       etime_is_rel = GNUNET_YES;
603     }
604     else if (GNUNET_OK ==
605              GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
606                                                     &etime_abs))
607     {
608       etime_is_rel = GNUNET_NO;
609     }
610     else
611     {
612       fprintf (stderr,
613                _("Invalid time format `%s'\n"),
614                expirationstring);
615       GNUNET_SCHEDULER_shutdown ();
616       ret = 1;
617       return;
618     }
619     add_zit = GNUNET_NAMESTORE_zone_iteration_start (ns,
620                                                      &zone_pkey,
621                                                      &get_existing_record,
622                                                      NULL);
623   }
624   if (del)
625   {
626     if (NULL == name)
627     {
628       fprintf (stderr,
629                _("Missing option `%s' for operation `%s'\n"),
630                "-n", _("del"));
631       GNUNET_SCHEDULER_shutdown ();
632       ret = 1;
633       return;
634     }
635     del_qe = GNUNET_NAMESTORE_records_store (ns,
636                                              &zone_pkey,
637                                              name,
638                                              0, NULL,
639                                              &del_continuation,
640                                              NULL);
641   }
642   if (list)
643   {
644     list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
645                                                      &zone_pkey,
646                                                      &display_record,
647                                                      NULL);
648   }
649   if (NULL != reverse_pkey)
650   {
651     struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
652
653     if (GNUNET_OK !=
654         GNUNET_CRYPTO_ecdsa_public_key_from_string (reverse_pkey,
655                                                        strlen (reverse_pkey),
656                                                        &pubkey))
657     {
658       fprintf (stderr,
659                _("Invalid public key for reverse lookup `%s'\n"),
660                reverse_pkey);
661       GNUNET_SCHEDULER_shutdown ();
662     }
663     reverse_qe = GNUNET_NAMESTORE_zone_to_name (ns,
664                                                 &zone_pkey,
665                                                 &pubkey,
666                                                 &handle_reverse_lookup,
667                                                 NULL);
668   }
669   if (NULL != uri)
670   {
671     char sh[105];
672     char sname[64];
673     struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
674
675     if ( (2 != (sscanf (uri,
676                         "gnunet://gns/%104s/%63s",
677                         sh,
678                         sname)) ) ||
679          (GNUNET_OK !=
680           GNUNET_CRYPTO_ecdsa_public_key_from_string (sh, strlen (sh), &pkey)) )
681     {
682       fprintf (stderr,
683                _("Invalid URI `%s'\n"),
684                uri);
685       GNUNET_SCHEDULER_shutdown ();
686       ret = 1;
687       return;
688     }
689     memset (&rd, 0, sizeof (rd));
690     rd.data = &pkey;
691     rd.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
692     rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
693     if (GNUNET_YES == etime_is_rel)
694     {
695       rd.expiration_time = etime_rel.rel_value_us;
696       rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
697     }
698     else if (GNUNET_NO == etime_is_rel)
699       rd.expiration_time = etime_abs.abs_value_us;
700     else
701       rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
702     if (1 != shadow)
703       rd.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
704     add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
705                                                  &zone_pkey,
706                                                  sname,
707                                                  1,
708                                                  &rd,
709                                                  &add_continuation,
710                                                  &add_qe_uri);
711   }
712   if (monitor)
713   {
714     zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
715                                               &zone_pkey,
716                                               &display_record,
717                                               &sync_cb,
718                                               NULL);
719   }
720 }
721
722
723 /**
724  * Callback invoked from identity service with ego information.
725  * An @a ego of NULL means the ego was not found.
726  *
727  * @param cls closure with the configuration
728  * @param ego an ego known to identity service, or NULL
729  */
730 static void
731 identity_cb (void *cls,
732              const struct GNUNET_IDENTITY_Ego *ego)
733 {
734   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
735
736   el = NULL;
737   if (NULL == ego)
738   {
739     fprintf (stderr,
740              _("Ego `%s' not known to identity service\n"),
741              ego_name);
742     GNUNET_SCHEDULER_shutdown ();
743     return;
744   }
745   zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
746   GNUNET_free (ego_name);
747   ego_name = NULL;
748   GNUNET_CLIENT_service_test ("namestore", cfg,
749                               GNUNET_TIME_UNIT_SECONDS,
750                               &testservice_task,
751                               (void *) cfg);
752 }
753
754
755 /**
756  * Main function that will be run.
757  *
758  * @param cls closure
759  * @param args remaining command-line arguments
760  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
761  * @param cfg configuration
762  */
763 static void
764 run (void *cls, char *const *args, const char *cfgfile,
765      const struct GNUNET_CONFIGURATION_Handle *cfg)
766 {
767   if (NULL == ego_name)
768   {
769     fprintf (stderr,
770              _("You must specify which zone should be accessed\n"));
771     return;
772   }
773   if ( (NULL != args[0]) && (NULL == uri) )
774     uri = GNUNET_strdup (args[0]);
775   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
776                                 &do_shutdown, NULL);
777   el = GNUNET_IDENTITY_ego_lookup (cfg,
778                                    ego_name,
779                                    &identity_cb,
780                                    (void *) cfg);
781 }
782
783
784 /**
785  * The main function for gnunet-namestore.
786  *
787  * @param argc number of arguments from the command line
788  * @param argv command line arguments
789  * @return 0 ok, 1 on error
790  */
791 int
792 main (int argc, char *const *argv)
793 {
794   public = -1;
795
796   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
797     {'a', "add", NULL,
798      gettext_noop ("add record"), 0,
799      &GNUNET_GETOPT_set_one, &add},
800     {'d', "delete", NULL,
801      gettext_noop ("delete record"), 0,
802      &GNUNET_GETOPT_set_one, &del},
803     {'D', "display", NULL,
804      gettext_noop ("display records"), 0,
805      &GNUNET_GETOPT_set_one, &list},
806     {'e', "expiration", "TIME",
807      gettext_noop ("expiration time for record to use (for adding only), \"never\" is possible"), 1,
808      &GNUNET_GETOPT_set_string, &expirationstring},
809     {'m', "monitor", NULL,
810      gettext_noop ("monitor changes in the namestore"), 0,
811      &GNUNET_GETOPT_set_one, &monitor},
812     {'n', "name", "NAME",
813      gettext_noop ("name of the record to add/delete/display"), 1,
814      &GNUNET_GETOPT_set_string, &name},
815     {'r', "reverse", "PKEY",
816      gettext_noop ("determine our name for the given PKEY"), 1,
817      &GNUNET_GETOPT_set_string, &reverse_pkey},
818     {'t', "type", "TYPE",
819      gettext_noop ("type of the record to add/delete/display"), 1,
820      &GNUNET_GETOPT_set_string, &typestring},
821     {'u', "uri", "URI",
822      gettext_noop ("URI to import into our zone"), 1,
823      &GNUNET_GETOPT_set_string, &uri},
824     {'V', "value", "VALUE",
825      gettext_noop ("value of the record to add/delete"), 1,
826      &GNUNET_GETOPT_set_string, &value},
827     {'p', "public", NULL,
828      gettext_noop ("create or list public record"), 0,
829      &GNUNET_GETOPT_set_one, &public},
830     {'s', "shadow", NULL,
831      gettext_noop ("create shadow record (only valid if all other records of the same type have expired"), 0,
832      &GNUNET_GETOPT_set_one, &shadow},
833     {'z', "zone", "EGO",
834      gettext_noop ("name of the ego controlling the zone"), 1,
835      &GNUNET_GETOPT_set_string, &ego_name},
836     GNUNET_GETOPT_OPTION_END
837   };
838
839   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
840     return 2;
841
842   GNUNET_log_setup ("gnunet-namestore", "WARNING", NULL);
843   if (GNUNET_OK !=
844       GNUNET_PROGRAM_run (argc, argv, "gnunet-namestore",
845                           _("GNUnet zone manipulation tool"),
846                           options,
847                           &run, NULL))
848   {
849     GNUNET_free ((void*) argv);
850     GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
851     return 1;
852   }
853   GNUNET_free ((void*) argv);
854   GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
855   return ret;
856 }
857
858 /* end of gnunet-namestore.c */