-enable looking up individual records
[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  * - add options to list/lookup individual records
29  */
30 #include "platform.h"
31 #include <gnunet_util_lib.h>
32 #include <gnunet_dnsparser_lib.h>
33 #include <gnunet_identity_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_EccPrivateKey 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 'list' operation (in combination with a name).
79  */
80 static struct GNUNET_NAMESTORE_QueueEntry *list_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_NAMESTORE_RF_PRIVATE)
99  */
100 static int public;
101
102 /**
103  * Is record a shadow record (#GNUNET_NAMESTORE_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  * Type of the record to add/remove, NULL to remove all.
129  */
130 static char *typestring;
131
132 /**
133  * Desired expiration time.
134  */
135 static char *expirationstring;
136
137 /**
138  * Global return value
139  */
140 static int ret;
141
142 /**
143  * Type string converted to DNS type value.
144  */
145 static uint32_t type;
146
147 /**
148  * Value in binary format.
149  */
150 static void *data;
151
152 /**
153  * Number of bytes in 'data'.
154  */
155 static size_t data_size;
156
157 /**
158  * Expirationstring converted to relative time.
159  */
160 static struct GNUNET_TIME_Relative etime_rel;
161
162 /**
163  * Expirationstring converted to absolute time.
164  */
165 static struct GNUNET_TIME_Absolute etime_abs;
166
167 /**
168  * Is expiration time relative or absolute time?
169  */
170 static int etime_is_rel = GNUNET_SYSERR;
171
172 /**
173  * Monitor handle.
174  */
175 static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
176
177 /**
178  * Enables monitor mode.
179  */
180 static int monitor;
181
182
183 /**
184  * Task run on shutdown.  Cleans up everything.
185  *
186  * @param cls unused
187  * @param tc scheduler context
188  */
189 static void
190 do_shutdown (void *cls,
191              const struct GNUNET_SCHEDULER_TaskContext *tc)
192 {
193   if (NULL != el)
194   {
195     GNUNET_IDENTITY_ego_lookup_cancel (el);
196     el = NULL;
197   }
198   if (NULL != list_it)
199   {
200     GNUNET_NAMESTORE_zone_iteration_stop (list_it);
201     list_it = NULL;
202   }
203   if (NULL != add_qe)
204   {
205     GNUNET_NAMESTORE_cancel (add_qe);
206     add_qe = NULL;
207   }
208   if (NULL != list_qe)
209   {
210     GNUNET_NAMESTORE_cancel (list_qe);
211     list_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  * Continuation called to notify client about result of the
249  * operation.
250  *
251  * @param cls closure, location of the QueueEntry pointer to NULL out
252  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
253  *                #GNUNET_NO if content was already there
254  *                #GNUNET_YES (or other positive value) on success
255  * @param emsg NULL on success, otherwise an error message
256  */
257 static void
258 add_continuation (void *cls,
259                   int32_t success,
260                   const char *emsg)
261 {
262   struct GNUNET_NAMESTORE_QueueEntry **qe = cls;
263
264   *qe = NULL;
265   if (GNUNET_YES != success)
266   {
267     fprintf (stderr,
268              _("Adding record failed: %s\n"),
269              (GNUNET_NO == success) ? "record exists" : emsg);
270     if (GNUNET_NO != success)
271       ret = 1;
272   }
273   if ( (NULL == add_qe) &&
274        (NULL == list_qe) &&
275        (NULL == add_qe_uri) &&
276        (NULL == del_qe) &&
277        (NULL == list_it) )
278     GNUNET_SCHEDULER_shutdown ();
279 }
280
281
282 /**
283  * Continuation called to notify client about result of the
284  * operation.
285  *
286  * @param cls closure, unused
287  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
288  *                #GNUNET_NO if content was already there
289  *                #GNUNET_YES (or other positive value) on success
290  * @param emsg NULL on success, otherwise an error message
291  */
292 static void
293 del_continuation (void *cls,
294                   int32_t success,
295                   const char *emsg)
296 {
297   del_qe = NULL;
298   if (success != GNUNET_YES)
299     fprintf (stderr,
300              _("Deleting record failed: %s\n"),
301              emsg);
302   if ( (NULL == add_qe) &&
303        (NULL == list_qe) &&
304        (NULL == add_qe_uri) &&
305        (NULL == list_it) )
306     GNUNET_SCHEDULER_shutdown ();
307 }
308
309
310 /**
311  * Process a record that was stored in the namestore.
312  *
313  * @param cls closure
314  * @param zone_key private key of the zone
315  * @param name name that is being mapped (at most 255 characters long)
316  * @param rd_len number of entries in @a rd array
317  * @param rd array of records with data to store
318  */
319 static void
320 display_record (void *cls,
321                 const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
322                 const char *name,
323                 unsigned int rd_len,
324                 const struct GNUNET_NAMESTORE_RecordData *rd)
325 {
326   const char *typestring;
327   char *s;
328   unsigned int i;
329
330   if (NULL == name)
331   {
332     list_it = NULL;
333     if ( (NULL == del_qe) &&
334          (NULL == list_qe) &&
335          (NULL == add_qe_uri) &&
336          (NULL == add_qe) )    
337       GNUNET_SCHEDULER_shutdown ();
338     return;
339   }
340   FPRINTF (stdout,
341            "%s:\n",
342            name);
343   for (i=0;i<rd_len;i++)
344   {
345     typestring = GNUNET_NAMESTORE_number_to_typename (rd[i].record_type);
346     s = GNUNET_NAMESTORE_value_to_string (rd[i].record_type,
347                                           rd[i].data,
348                                           rd[i].data_size);
349     if (NULL == s)
350     {
351       FPRINTF (stdout, _("\tCorrupt or unsupported record of type %u\n"),
352                (unsigned int) rd[i].record_type);
353       continue;
354     }
355     FPRINTF (stdout, 
356              "\t%s: %s\n",
357              typestring, 
358              s);
359     GNUNET_free (s);    
360   }
361   FPRINTF (stdout, "%s", "\n");
362   GNUNET_NAMESTORE_zone_iterator_next (list_it);
363 }
364
365
366 /**
367  * Function called once we are in sync in monitor mode.
368  *
369  * @param cls NULL
370  */
371 static void
372 sync_cb (void *cls)
373 {
374   FPRINTF (stdout, "%s", "Monitor is now in sync.\n");
375 }
376
377
378 /**
379  * We're storing a record; this function is given the existing record
380  * so that we can merge the information.
381  *
382  * @param cls closure, unused
383  * @param zone_key private key of the zone
384  * @param rec_name name that is being mapped (at most 255 characters long)
385  * @param rd_count number of entries in @a rd array
386  * @param rd array of records with data to store
387  */
388 static void
389 get_existing_record (void *cls,
390                      const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
391                      const char *rec_name,
392                      unsigned int rd_count,
393                      const struct GNUNET_NAMESTORE_RecordData *rd)
394 {
395   struct GNUNET_NAMESTORE_RecordData rdn[rd_count + 1];
396   struct GNUNET_NAMESTORE_RecordData *rde;
397
398   if ( (NULL != zone_key) &&
399        (0 != strcmp (rec_name, name)) )
400   {
401     GNUNET_NAMESTORE_zone_iterator_next (add_zit);
402     return;
403   }
404   memset (rdn, 0, sizeof (struct GNUNET_NAMESTORE_RecordData));
405   memcpy (&rdn[1], rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
406   /* FIXME: should add some logic to overwrite records if there
407      can only be one record of a particular type, and to check
408      if the combination of records is valid to begin with... */
409   rde = &rdn[0];
410   rde->data = data;
411   rde->data_size = data_size;
412   rde->record_type = type;
413   if (1 != shadow)
414     rde->flags |= GNUNET_NAMESTORE_RF_SHADOW_RECORD;
415   if (1 != public)
416     rde->flags |= GNUNET_NAMESTORE_RF_PRIVATE;
417   GNUNET_assert (NULL != name);
418   add_qe = GNUNET_NAMESTORE_records_store (ns,
419                                            &zone_pkey,
420                                            name,
421                                            rd_count + 1,
422                                            rde,
423                                            &add_continuation,
424                                            &add_qe);
425   /* only cancel if we were not told that this
426      was the end of the iteration already */
427   if (NULL != rec_name)
428     GNUNET_NAMESTORE_zone_iteration_stop (add_zit);
429   add_zit = NULL;
430 }
431
432
433
434 /**
435  * Process a record that was stored in the namestore in a block.
436  *
437  * @param cls closure, NULL
438  * @param rd_len number of entries in @a rd array
439  * @param rd array of records with data to store
440  */
441 static void
442 display_records_from_block (void *cls,
443                             unsigned int rd_len,
444                             const struct GNUNET_NAMESTORE_RecordData *rd)
445 {
446   const char *typestring;
447   char *s;
448   unsigned int i;
449
450   if (0 == rd_len)
451   {
452     FPRINTF (stdout,
453              _("No records found for `%s'"),
454              name);
455     return;
456   }
457   FPRINTF (stdout,
458            "%s:\n",
459            name);  
460   for (i=0;i<rd_len;i++)
461   {
462     typestring = GNUNET_NAMESTORE_number_to_typename (rd[i].record_type);
463     s = GNUNET_NAMESTORE_value_to_string (rd[i].record_type,
464                                           rd[i].data,
465                                           rd[i].data_size);
466     if (NULL == s)
467     {
468       FPRINTF (stdout, _("\tCorrupt or unsupported record of type %u\n"),
469                (unsigned int) rd[i].record_type);
470       continue;
471     }
472     FPRINTF (stdout, 
473              "\t%s: %s\n",
474              typestring, 
475              s);
476     GNUNET_free (s);    
477   }
478   FPRINTF (stdout, "%s", "\n");
479 }
480
481
482 /**
483  * Display block obtained from listing (by name).
484  *
485  * @param cls NULL
486  * @param block NULL if not found
487  */
488 static void
489 handle_block (void *cls,
490               const struct GNUNET_NAMESTORE_Block *block)
491 {
492   struct GNUNET_CRYPTO_EccPublicSignKey zone_pubkey;
493
494   list_qe = NULL;
495   GNUNET_CRYPTO_ecc_key_get_public_for_signature (&zone_pkey,
496                                                   &zone_pubkey);
497   if (NULL == block)
498   {
499     fprintf (stderr,
500              "No matching block found\n");
501   } 
502   else if (GNUNET_OK !=
503            GNUNET_NAMESTORE_block_decrypt (block,
504                                            &zone_pubkey,
505                                            name,
506                                            &display_records_from_block,
507                                            NULL))
508   {
509     fprintf (stderr,
510              "Failed to decrypt block!\n");
511   }
512   if ( (NULL == del_qe) &&
513        (NULL == list_it) &&
514        (NULL == add_qe_uri) &&
515        (NULL == add_qe) )    
516     GNUNET_SCHEDULER_shutdown ();
517 }
518
519
520 /**
521  * Function called with the result from the check if the namestore
522  * service is actually running.  If it is, we start the actual
523  * operation.
524  *
525  * @param cls closure with our configuration
526  * @param result #GNUNET_YES if the namestore service is running
527  */
528 static void
529 testservice_task (void *cls,
530                   int result)
531 {
532   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
533   struct GNUNET_CRYPTO_EccPublicSignKey pub;
534   struct GNUNET_NAMESTORE_RecordData rd;
535
536   if (GNUNET_YES != result)
537   {
538     FPRINTF (stderr, _("Service `%s' is not running\n"), 
539              "namestore");
540     return;
541   }
542   if (! (add|del|list|(NULL != uri)))
543   {
544     /* nothing more to be done */  
545     fprintf (stderr,
546              _("No options given\n"));
547     GNUNET_SCHEDULER_shutdown ();
548     return; 
549   }
550   GNUNET_CRYPTO_ecc_key_get_public_for_signature (&zone_pkey,
551                                     &pub);
552
553   ns = GNUNET_NAMESTORE_connect (cfg);
554   if (NULL == ns)
555   {
556     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
557                 _("Failed to connect to namestore\n"));
558     return;
559   }
560   if (add)
561   {
562     if (NULL == name)
563     {
564       fprintf (stderr,
565                _("Missing option `%s' for operation `%s'\n"),
566                "-n", _("add"));
567       GNUNET_SCHEDULER_shutdown ();
568       ret = 1;    
569       return;     
570     }
571     if (NULL == typestring)
572     {
573       fprintf (stderr,
574                _("Missing option `%s' for operation `%s'\n"),
575                "-t", _("add"));
576       GNUNET_SCHEDULER_shutdown ();
577       ret = 1;
578       return;     
579     }
580     type = GNUNET_NAMESTORE_typename_to_number (typestring);
581     if (UINT32_MAX == type)
582     {
583       fprintf (stderr, _("Unsupported type `%s'\n"), typestring);
584       GNUNET_SCHEDULER_shutdown ();
585       ret = 1;
586       return;
587     }
588     if (NULL == value)
589     {
590       fprintf (stderr,
591                _("Missing option `%s' for operation `%s'\n"),
592                "-V", _("add"));
593       ret = 1;   
594       GNUNET_SCHEDULER_shutdown ();
595       return;     
596     }
597     if (GNUNET_OK !=
598         GNUNET_NAMESTORE_string_to_value (type,
599                                           value,
600                                           &data,
601                                           &data_size))
602     {
603       fprintf (stderr, _("Value `%s' invalid for record type `%s'\n"),
604                value,
605                typestring);
606       GNUNET_SCHEDULER_shutdown ();
607       ret = 1;
608       return;
609     }
610     if (NULL == expirationstring)
611     {
612       fprintf (stderr,
613                _("Missing option `%s' for operation `%s'\n"),
614                "-e", _("add"));
615       GNUNET_SCHEDULER_shutdown ();
616       ret = 1;    
617       return;     
618     }
619     if (0 == strcmp (expirationstring, "never"))
620     {
621       etime_abs = GNUNET_TIME_UNIT_FOREVER_ABS;
622       etime_is_rel = GNUNET_NO;
623     }
624     else if (GNUNET_OK ==
625              GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
626                                                     &etime_rel))
627     {
628       etime_is_rel = GNUNET_YES;
629     }
630     else if (GNUNET_OK == 
631              GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
632                                                     &etime_abs))
633     {
634       etime_is_rel = GNUNET_NO;
635     }
636     else
637     {
638       fprintf (stderr,
639                _("Invalid time format `%s'\n"),
640                expirationstring);
641       GNUNET_SCHEDULER_shutdown ();
642       ret = 1;
643       return;     
644     }
645     add_zit = GNUNET_NAMESTORE_zone_iteration_start (ns,
646                                                      &zone_pkey,
647                                                      &get_existing_record,
648                                                      NULL);
649   }
650   if (del)
651   {
652     if (NULL == name)
653     {
654       fprintf (stderr,
655                _("Missing option `%s' for operation `%s'\n"),
656                "-n", _("del"));
657       GNUNET_SCHEDULER_shutdown ();
658       ret = 1;
659       return;     
660     }
661     del_qe = GNUNET_NAMESTORE_records_store (ns,
662                                              &zone_pkey,
663                                              name,
664                                              0, NULL,
665                                              &del_continuation,
666                                              NULL);
667   }
668   if (list)
669   {
670     if (NULL == name)
671     {
672       list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
673                                                        &zone_pkey,
674                                                        &display_record,
675                                                        NULL);
676     }
677     else
678     {
679       struct GNUNET_HashCode query;
680       struct GNUNET_CRYPTO_EccPublicSignKey zone_pubkey;
681
682       GNUNET_CRYPTO_ecc_key_get_public_for_signature (&zone_pkey,
683                                                       &zone_pubkey);
684       GNUNET_NAMESTORE_query_from_public_key (&zone_pubkey,
685                                               name,
686                                               &query);
687       list_qe = GNUNET_NAMESTORE_lookup_block (ns,
688                                                &query,
689                                                handle_block,
690                                                NULL);
691     }
692   }
693   if (NULL != uri)
694   {
695     char sh[105];
696     char sname[64];
697     struct GNUNET_CRYPTO_EccPublicSignKey pkey;
698
699     if ( (2 != (sscanf (uri,
700                         "gnunet://gns/%104s/%63s",
701                         sh,
702                         sname)) ) ||
703          (GNUNET_OK !=
704           GNUNET_CRYPTO_ecc_public_sign_key_from_string (sh, strlen (sh), &pkey)) )
705     {
706       fprintf (stderr, 
707                _("Invalid URI `%s'\n"),
708                uri);
709       GNUNET_SCHEDULER_shutdown ();
710       ret = 1;
711       return;
712     }
713     memset (&rd, 0, sizeof (rd));
714     rd.data = &pkey;
715     rd.data_size = sizeof (struct GNUNET_CRYPTO_EccPublicSignKey);
716     rd.record_type = GNUNET_NAMESTORE_TYPE_PKEY;
717     if (GNUNET_YES == etime_is_rel)
718     {
719       rd.expiration_time = etime_rel.rel_value_us;
720       rd.flags |= GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION;
721     }
722     else if (GNUNET_NO == etime_is_rel)
723       rd.expiration_time = etime_abs.abs_value_us;
724     else    
725       rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
726     if (1 != shadow)
727       rd.flags |= GNUNET_NAMESTORE_RF_SHADOW_RECORD;
728     add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
729                                                  &zone_pkey,
730                                                  sname,
731                                                  1,
732                                                  &rd,
733                                                  &add_continuation,
734                                                  &add_qe_uri);
735   }
736   if (monitor)
737   {
738     zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
739                                               &zone_pkey,
740                                               &display_record,
741                                               &sync_cb,
742                                               NULL);
743   }
744 }
745
746
747 /**
748  * Callback invoked from identity service with ego information.
749  * An @a ego of NULL means the ego was not found.
750  *
751  * @param cls closure with the configuration
752  * @param ego an ego known to identity service, or NULL 
753  */
754 static void
755 identity_cb (void *cls,
756              const struct GNUNET_IDENTITY_Ego *ego)
757 {
758   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
759
760   el = NULL;
761   if (NULL == ego)
762   {
763     fprintf (stderr, 
764              _("Ego `%s' not known to identity service\n"),
765              ego_name);
766     GNUNET_SCHEDULER_shutdown ();
767     return;
768   }
769   zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
770   GNUNET_free (ego_name);
771   ego_name = NULL;
772   GNUNET_CLIENT_service_test ("namestore", cfg,
773                               GNUNET_TIME_UNIT_SECONDS,
774                               &testservice_task,
775                               (void *) cfg);
776 }
777
778
779 /**
780  * Main function that will be run.
781  *
782  * @param cls closure
783  * @param args remaining command-line arguments
784  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
785  * @param cfg configuration
786  */
787 static void
788 run (void *cls, char *const *args, const char *cfgfile,
789      const struct GNUNET_CONFIGURATION_Handle *cfg)
790 {
791   if (NULL == ego_name)
792   {
793     fprintf (stderr, 
794              _("You must specify which zone should be accessed\n"));
795     return;
796   }
797   if ( (NULL != args[0]) && (NULL == uri) )
798     uri = GNUNET_strdup (args[0]);
799   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
800                                 &do_shutdown, NULL);
801   el = GNUNET_IDENTITY_ego_lookup (cfg,
802                                    ego_name,
803                                    &identity_cb,
804                                    (void *) cfg);
805 }
806
807
808 /**
809  * The main function for gnunet-namestore.
810  *
811  * @param argc number of arguments from the command line
812  * @param argv command line arguments
813  * @return 0 ok, 1 on error
814  */
815 int
816 main (int argc, char *const *argv)
817 {
818   public = -1;
819
820   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
821     {'a', "add", NULL,
822      gettext_noop ("add record"), 0,
823      &GNUNET_GETOPT_set_one, &add},
824     {'d', "delete", NULL,
825      gettext_noop ("delete record"), 0,
826      &GNUNET_GETOPT_set_one, &del},   
827     {'D', "display", NULL,
828      gettext_noop ("display records"), 0,
829      &GNUNET_GETOPT_set_one, &list},   
830     {'e', "expiration", "TIME",
831      gettext_noop ("expiration time for record to use (for adding only), \"never\" is possible"), 1,
832      &GNUNET_GETOPT_set_string, &expirationstring},   
833     {'m', "monitor", NULL,
834      gettext_noop ("monitor changes in the namestore"), 0,
835      &GNUNET_GETOPT_set_one, &monitor},   
836     {'n', "name", "NAME",
837      gettext_noop ("name of the record to add/delete/display"), 1,
838      &GNUNET_GETOPT_set_string, &name},   
839     {'t', "type", "TYPE",
840      gettext_noop ("type of the record to add/delete/display"), 1,
841      &GNUNET_GETOPT_set_string, &typestring},   
842     {'u', "uri", "URI",
843      gettext_noop ("URI to import into our zone"), 1,
844      &GNUNET_GETOPT_set_string, &uri},   
845     {'V', "value", "VALUE",
846      gettext_noop ("value of the record to add/delete"), 1,
847      &GNUNET_GETOPT_set_string, &value},   
848     {'p', "public", NULL,
849      gettext_noop ("create or list public record"), 0,
850      &GNUNET_GETOPT_set_one, &public},
851     {'s', "shadow", NULL,
852      gettext_noop ("create shadow record (only valid if all other records of the same type have expired"), 0,
853      &GNUNET_GETOPT_set_one, &shadow},
854     {'z', "zone", "EGO",
855      gettext_noop ("name of the ego controlling the zone"), 1,
856      &GNUNET_GETOPT_set_string, &ego_name},   
857     GNUNET_GETOPT_OPTION_END
858   };
859
860   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
861     return 2;
862
863   GNUNET_log_setup ("gnunet-namestore", "WARNING", NULL);
864   if (GNUNET_OK !=
865       GNUNET_PROGRAM_run (argc, argv, "gnunet-namestore",
866                           _("GNUnet zone manipulation tool"), 
867                           options,
868                           &run, NULL))
869   {
870     GNUNET_free ((void*) argv);
871     GNUNET_CRYPTO_ecc_key_clear (&zone_pkey);
872     return 1;
873   }
874   GNUNET_free ((void*) argv);
875   GNUNET_CRYPTO_ecc_key_clear (&zone_pkey);
876   return ret;
877 }
878
879 /* end of gnunet-namestore.c */