90fe79779d9607f635b79684c4c3fb1fd57af47d
[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 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 /**
19  * @file gnunet-namestore.c
20  * @brief command line tool to manipulate the local zone
21  * @author Christian Grothoff
22  *
23  * TODO:
24  * - test
25  */
26 #include "platform.h"
27 #include <gnunet_util_lib.h>
28 #include <gnunet_dnsparser_lib.h>
29 #include <gnunet_identity_service.h>
30 #include <gnunet_gnsrecord_lib.h>
31 #include <gnunet_gns_service.h>
32 #include <gnunet_namestore_service.h>
33
34
35 /**
36  * Entry in record set for bulk processing.
37  */
38 struct RecordSetEntry
39 {
40   /**
41    * Kept in a linked list.
42    */
43   struct RecordSetEntry *next;
44
45   /**
46    * The record to add/remove.
47    */
48   struct GNUNET_GNSRECORD_Data record;
49   
50 };
51
52
53 /**
54  * Handle to the namestore.
55  */
56 static struct GNUNET_NAMESTORE_Handle *ns;
57
58 /**
59  * Private key for the our zone.
60  */
61 static struct GNUNET_CRYPTO_EcdsaPrivateKey zone_pkey;
62
63 /**
64  * Handle to identity lookup.
65  */
66 static struct GNUNET_IDENTITY_EgoLookup *el;
67
68 /**
69  * Identity service handle
70  */
71 static struct GNUNET_IDENTITY_Handle *idh;
72
73 /**
74  * Obtain default ego
75  */
76 struct GNUNET_IDENTITY_Operation *get_default;
77
78 /**
79  * Name of the ego controlling the zone.
80  */
81 static char *ego_name;
82
83 /**
84  * Desired action is to add a record.
85  */
86 static int add;
87
88 /**
89  * Queue entry for the 'add-uri' operation.
90  */
91 static struct GNUNET_NAMESTORE_QueueEntry *add_qe_uri;
92
93 /**
94  * Queue entry for the 'add' operation.
95  */
96 static struct GNUNET_NAMESTORE_QueueEntry *add_qe;
97
98 /**
99  * Queue entry for the 'lookup' operation.
100  */
101 static struct GNUNET_NAMESTORE_QueueEntry *get_qe;
102
103 /**
104  * Queue entry for the 'reverse lookup' operation (in combination with a name).
105  */
106 static struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
107
108 /**
109  * Desired action is to list records.
110  */
111 static int list;
112
113 /**
114  * List iterator for the 'list' operation.
115  */
116 static struct GNUNET_NAMESTORE_ZoneIterator *list_it;
117
118 /**
119  * Desired action is to remove a record.
120  */
121 static int del;
122
123 /**
124  * Is record public (opposite of #GNUNET_GNSRECORD_RF_PRIVATE)
125  */
126 static int is_public;
127
128 /**
129  * Is record a shadow record (#GNUNET_GNSRECORD_RF_SHADOW_RECORD)
130  */
131 static int is_shadow;
132
133 /**
134  * Queue entry for the 'del' operation.
135  */
136 static struct GNUNET_NAMESTORE_QueueEntry *del_qe;
137
138 /**
139  * Queue entry for the 'set/replace' operation.
140  */
141 static struct GNUNET_NAMESTORE_QueueEntry *set_qe;
142
143 /**
144  * Name of the records to add/list/remove.
145  */
146 static char *name;
147
148 /**
149  * Value of the record to add/remove.
150  */
151 static char *value;
152
153 /**
154  * URI to import.
155  */
156 static char *uri;
157
158 /**
159  * Reverse lookup to perform.
160  */
161 static char *reverse_pkey;
162
163 /**
164  * Type of the record to add/remove, NULL to remove all.
165  */
166 static char *typestring;
167
168 /**
169  * Desired expiration time.
170  */
171 static char *expirationstring;
172
173 /**
174  * Desired nick name.
175  */
176 static char *nickstring;
177
178 /**
179  * Global return value
180  */
181 static int ret;
182
183 /**
184  * Type string converted to DNS type value.
185  */
186 static uint32_t type;
187
188 /**
189  * Value in binary format.
190  */
191 static void *data;
192
193 /**
194  * Number of bytes in #data.
195  */
196 static size_t data_size;
197
198 /**
199  * Expiration string converted to numeric value.
200  */
201 static uint64_t etime;
202
203 /**
204  * Is expiration time relative or absolute time?
205  */
206 static int etime_is_rel = GNUNET_SYSERR;
207
208 /**
209  * Monitor handle.
210  */
211 static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
212
213 /**
214  * Enables monitor mode.
215  */
216 static int monitor;
217
218 /**
219  * Entry in record set for processing records in bulk.
220  */
221 static struct RecordSetEntry *recordset;
222
223
224 /**
225  * Task run on shutdown.  Cleans up everything.
226  *
227  * @param cls unused
228  */
229 static void
230 do_shutdown (void *cls)
231 {
232   (void) cls;
233   if (NULL != get_default)
234   {
235     GNUNET_IDENTITY_cancel (get_default);
236     get_default = NULL;
237   }
238   if (NULL != idh)
239   {
240     GNUNET_IDENTITY_disconnect (idh);
241     idh = NULL;
242   }
243   if (NULL != el)
244   {
245     GNUNET_IDENTITY_ego_lookup_cancel (el);
246     el = NULL;
247   }
248   if (NULL != list_it)
249   {
250     GNUNET_NAMESTORE_zone_iteration_stop (list_it);
251     list_it = NULL;
252   }
253   if (NULL != add_qe)
254   {
255     GNUNET_NAMESTORE_cancel (add_qe);
256     add_qe = NULL;
257   }
258   if (NULL != set_qe)
259   {
260     GNUNET_NAMESTORE_cancel (set_qe);
261     set_qe = NULL;
262   }
263   if (NULL != add_qe_uri)
264   {
265     GNUNET_NAMESTORE_cancel (add_qe_uri);
266     add_qe_uri = NULL;
267   }
268   if (NULL != get_qe)
269   {
270     GNUNET_NAMESTORE_cancel (get_qe);
271     get_qe = NULL;
272   }
273   if (NULL != del_qe)
274   {
275     GNUNET_NAMESTORE_cancel (del_qe);
276     del_qe = NULL;
277   }
278   if (NULL != ns)
279   {
280     GNUNET_NAMESTORE_disconnect (ns);
281     ns = NULL;
282   }
283   memset (&zone_pkey, 0, sizeof (zone_pkey));
284   if (NULL != uri)
285   {
286     GNUNET_free (uri);
287     uri = NULL;
288   }
289   if (NULL != zm)
290   {
291     GNUNET_NAMESTORE_zone_monitor_stop (zm);
292     zm = NULL;
293   }
294   if (NULL != data)
295   {
296     GNUNET_free (data);
297     data = NULL;
298   }
299 }
300
301
302 /**
303  * Check if we are finished, and if so, perform shutdown.
304  */
305 static void
306 test_finished ()
307 {
308   if ( (NULL == add_qe) &&
309        (NULL == add_qe_uri) &&
310        (NULL == get_qe) &&
311        (NULL == del_qe) &&
312        (NULL == reverse_qe) &&
313        (NULL == list_it) )
314     GNUNET_SCHEDULER_shutdown ();
315 }
316
317
318 /**
319  * Continuation called to notify client about result of the
320  * operation.
321  *
322  * @param cls closure, location of the QueueEntry pointer to NULL out
323  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
324  *                #GNUNET_NO if content was already there
325  *                #GNUNET_YES (or other positive value) on success
326  * @param emsg NULL on success, otherwise an error message
327  */
328 static void
329 add_continuation (void *cls,
330                   int32_t success,
331                   const char *emsg)
332 {
333   struct GNUNET_NAMESTORE_QueueEntry **qe = cls;
334
335   *qe = NULL;
336   if (GNUNET_YES != success)
337   {
338     fprintf (stderr,
339              _("Adding record failed: %s\n"),
340              (GNUNET_NO == success) ? "record exists" : emsg);
341     if (GNUNET_NO != success)
342       ret = 1;
343   }
344   ret = 0;
345   test_finished ();
346 }
347
348
349 /**
350  * Continuation called to notify client about result of the
351  * operation.
352  *
353  * @param cls closure, unused
354  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
355  *                #GNUNET_NO if content was already there
356  *                #GNUNET_YES (or other positive value) on success
357  * @param emsg NULL on success, otherwise an error message
358  */
359 static void
360 del_continuation (void *cls,
361                   int32_t success,
362                   const char *emsg)
363 {
364   (void) cls;
365   del_qe = NULL;
366   if (GNUNET_NO == success)
367   {
368     fprintf (stderr,
369              _("Deleting record failed, record does not exist%s%s\n"),
370              (NULL != emsg) ? ": " : "",
371              (NULL != emsg) ? emsg : "");
372   }
373   if (GNUNET_SYSERR == success)
374   {
375     fprintf (stderr,
376              _("Deleting record failed%s%s\n"),
377              (NULL != emsg) ? ": " : "",
378              (NULL != emsg) ? emsg : "");
379   }
380   test_finished ();
381 }
382
383
384 /**
385  * Function called when we are done with a zone iteration.
386  */
387 static void
388 zone_iteration_finished (void *cls)
389 {
390   (void) cls;
391   list_it = NULL;
392   test_finished ();
393 }
394
395
396 /**
397  * Function called when we encountered an error in a zone iteration.
398  */
399 static void
400 zone_iteration_error_cb (void *cls)
401 {
402   (void) cls;
403   list_it = NULL;
404   fprintf (stderr,
405            "Error iterating over zone\n");
406   ret = 1;
407   test_finished ();
408 }
409
410
411 /**
412  * Process a record that was stored in the namestore.
413  *
414  * @param rname name that is being mapped (at most 255 characters long)
415  * @param rd_len number of entries in @a rd array
416  * @param rd array of records with data to store
417  */
418 static void
419 display_record (const char *rname,
420                 unsigned int rd_len,
421                 const struct GNUNET_GNSRECORD_Data *rd)
422 {
423   const char *typestring;
424   char *s;
425   const char *ets;
426   struct GNUNET_TIME_Absolute at;
427   struct GNUNET_TIME_Relative rt;
428
429   if ( (NULL != name) &&
430        (0 != strcmp (name, rname)) )
431   {
432     GNUNET_NAMESTORE_zone_iterator_next (list_it,
433                                          1);
434     return;
435   }
436   FPRINTF (stdout,
437            "%s:\n",
438            rname);
439   for (unsigned int i=0;i<rd_len;i++)
440   {
441     if ( (GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
442          (0 != strcmp (rname,
443                        GNUNET_GNS_EMPTY_LABEL_AT)) )
444       continue;
445     typestring = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
446     s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
447                                           rd[i].data,
448                                           rd[i].data_size);
449     if (NULL == s)
450     {
451       FPRINTF (stdout,
452                _("\tCorrupt or unsupported record of type %u\n"),
453                (unsigned int) rd[i].record_type);
454       continue;
455     }
456     if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
457     {
458       rt.rel_value_us = rd[i].expiration_time;
459       ets = GNUNET_STRINGS_relative_time_to_string (rt, GNUNET_YES);
460     }
461     else
462     {
463       at.abs_value_us = rd[i].expiration_time;
464       ets = GNUNET_STRINGS_absolute_time_to_string (at);
465     }
466     FPRINTF (stdout,
467              "\t%s: %s (%s)\t%s\t%s\n",
468              typestring,
469              s,
470              ets,
471              (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)) ? "PRIVATE" : "PUBLIC",
472              (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)) ? "SHADOW" : "");
473     GNUNET_free (s);
474   }
475   FPRINTF (stdout, "%s", "\n");
476 }
477
478
479 /**
480  * Process a record that was stored in the namestore.
481  *
482  * @param cls closure
483  * @param zone_key private key of the zone
484  * @param rname name that is being mapped (at most 255 characters long)
485  * @param rd_len number of entries in @a rd array
486  * @param rd array of records with data to store
487  */
488 static void
489 display_record_iterator (void *cls,
490                          const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
491                          const char *rname,
492                          unsigned int rd_len,
493                          const struct GNUNET_GNSRECORD_Data *rd)
494 {
495   (void) cls;
496   (void) zone_key;
497   display_record (rname,
498                   rd_len,
499                   rd);
500   GNUNET_NAMESTORE_zone_iterator_next (list_it,
501                                        1);
502 }
503
504
505 /**
506  * Process a record that was stored in the namestore.
507  *
508  * @param cls closure
509  * @param zone_key private key of the zone
510  * @param rname name that is being mapped (at most 255 characters long)
511  * @param rd_len number of entries in @a rd array
512  * @param rd array of records with data to store
513  */
514 static void
515 display_record_monitor (void *cls,
516                         const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
517                         const char *rname,
518                         unsigned int rd_len,
519                         const struct GNUNET_GNSRECORD_Data *rd)
520 {
521   (void) cls;
522   (void) zone_key;
523   display_record (rname,
524                   rd_len,
525                   rd);
526   GNUNET_NAMESTORE_zone_monitor_next (zm,
527                                       1);
528 }
529
530
531 /**
532  * Process a record that was stored in the namestore.
533  *
534  * @param cls closure
535  * @param zone_key private key of the zone
536  * @param rname name that is being mapped (at most 255 characters long)
537  * @param rd_len number of entries in @a rd array
538  * @param rd array of records with data to store
539  */
540 static void
541 display_record_lookup (void *cls,
542                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
543                        const char *rname,
544                        unsigned int rd_len,
545                        const struct GNUNET_GNSRECORD_Data *rd)
546 {
547   (void) cls;
548   (void) zone_key;
549   get_qe = NULL;
550   display_record (rname,
551                   rd_len,
552                   rd);
553   test_finished ();
554 }
555
556
557 /**
558  * Function called once we are in sync in monitor mode.
559  *
560  * @param cls NULL
561  */
562 static void
563 sync_cb (void *cls)
564 {
565   (void) cls;
566   FPRINTF (stdout,
567            "%s",
568            "Monitor is now in sync.\n");
569 }
570
571
572 /**
573  * Function called on errors while monitoring.
574  *
575  * @param cls NULL
576  */
577 static void
578 monitor_error_cb (void *cls)
579 {
580   (void) cls;
581   FPRINTF (stderr,
582            "%s",
583            "Monitor disconnected and out of sync.\n");
584 }
585
586
587 /**
588  * Function called on errors while monitoring.
589  *
590  * @param cls NULL
591  */
592 static void
593 lookup_error_cb (void *cls)
594 {
595   (void) cls;
596   get_qe = NULL;
597   FPRINTF (stderr,
598            "%s",
599            "Failed to lookup record.\n");
600   test_finished ();
601 }
602
603
604 /**
605  * Function called if lookup fails.
606  */
607 static void
608 add_error_cb (void *cls)
609 {
610   (void) cls;
611   add_qe = NULL;
612   GNUNET_break (0);
613   ret = 1;
614   test_finished ();
615 }
616
617
618 /**
619  * We're storing a record; this function is given the existing record
620  * so that we can merge the information.
621  *
622  * @param cls closure, unused
623  * @param zone_key private key of the zone
624  * @param rec_name name that is being mapped (at most 255 characters long)
625  * @param rd_count number of entries in @a rd array
626  * @param rd array of records with data to store
627  */
628 static void
629 get_existing_record (void *cls,
630                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone_key,
631                      const char *rec_name,
632                      unsigned int rd_count,
633                      const struct GNUNET_GNSRECORD_Data *rd)
634 {
635   struct GNUNET_GNSRECORD_Data rdn[rd_count + 1];
636   struct GNUNET_GNSRECORD_Data *rde;
637
638   (void) cls;
639   (void) zone_key;
640   add_qe = NULL;
641   if (0 != strcmp (rec_name, name))
642   {
643     GNUNET_break (0);
644     ret = 1;
645     test_finished ();
646     return;
647   }
648
649   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
650               "Received %u records for name `%s'\n",
651               rd_count, rec_name);
652   for (unsigned int i=0;i<rd_count;i++)
653   {
654     switch (rd[i].record_type)
655     {
656     case GNUNET_DNSPARSER_TYPE_CNAME:
657       fprintf (stderr,
658                _("A %s record exists already under `%s', no other records can be added.\n"),
659                "CNAME",
660                rec_name);
661       ret = 1;
662       test_finished ();
663       return;
664     case GNUNET_GNSRECORD_TYPE_PKEY:
665       fprintf (stderr,
666                _("A %s record exists already under `%s', no other records can be added.\n"),
667                "PKEY",
668                rec_name);
669       ret = 1;
670       test_finished ();
671       return;
672     }
673   }
674   switch (type)
675   {
676   case GNUNET_DNSPARSER_TYPE_CNAME:
677     if (0 != rd_count)
678     {
679       fprintf (stderr,
680                _("Records already exist under `%s', cannot add `%s' record.\n"),
681                rec_name,
682                "CNAME");
683       ret = 1;
684       test_finished ();
685       return;
686     }
687     break;
688   case GNUNET_GNSRECORD_TYPE_PKEY:
689     if (0 != rd_count)
690     {
691       fprintf (stderr,
692                _("Records already exist under `%s', cannot add `%s' record.\n"),
693                rec_name,
694                "PKEY");
695       ret = 1;
696       test_finished ();
697       return;
698     }
699     break;
700   case GNUNET_GNSRECORD_TYPE_GNS2DNS:
701     for (unsigned int i=0;i<rd_count;i++)
702       if (GNUNET_GNSRECORD_TYPE_GNS2DNS != rd[i].record_type)
703       {
704         fprintf (stderr,
705                  _("Non-GNS2DNS records already exist under `%s', cannot add GNS2DNS record.\n"),
706                  rec_name);
707         ret = 1;
708         test_finished ();
709         return;
710       }
711     break;
712   }
713   memset (rdn,
714           0,
715           sizeof (struct GNUNET_GNSRECORD_Data));
716   GNUNET_memcpy (&rdn[1],
717                  rd,
718                  rd_count * sizeof (struct GNUNET_GNSRECORD_Data));
719   rde = &rdn[0];
720   rde->data = data;
721   rde->data_size = data_size;
722   rde->record_type = type;
723   if (1 == is_shadow)
724     rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
725   if (1 != is_public)
726     rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
727   rde->expiration_time = etime;
728   if (GNUNET_YES == etime_is_rel)
729     rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
730   else if (GNUNET_NO != etime_is_rel)
731     rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
732   GNUNET_assert (NULL != name);
733   add_qe = GNUNET_NAMESTORE_records_store (ns,
734                                            &zone_pkey,
735                                            name,
736                                            rd_count + 1,
737                                            rde,
738                                            &add_continuation,
739                                            &add_qe);
740 }
741
742
743 /**
744  * Function called if we encountered an error in zone-to-name.
745  */
746 static void
747 reverse_error_cb (void *cls)
748 {
749   (void) cls;
750   reverse_qe = NULL;
751   FPRINTF (stdout,
752            "%s.zkey\n",
753            reverse_pkey);
754 }
755
756
757 /**
758  * Function called with the result of our attempt to obtain a name for a given
759  * public key.
760  *
761  * @param cls NULL
762  * @param zone private key of the zone; NULL on disconnect
763  * @param label label of the records; NULL on disconnect
764  * @param rd_count number of entries in @a rd array, 0 if label was deleted
765  * @param rd array of records with data to store
766  */
767 static void
768 handle_reverse_lookup (void *cls,
769                        const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
770                        const char *label,
771                        unsigned int rd_count,
772                        const struct GNUNET_GNSRECORD_Data *rd)
773 {
774   (void) cls;
775   (void) zone;
776   (void) rd_count;
777   (void) rd;
778   reverse_qe = NULL;
779   if (NULL == label)
780     FPRINTF (stdout,
781              "%s\n",
782              reverse_pkey);
783   else
784     FPRINTF (stdout,
785              "%s.%s\n",
786              label,
787              ego_name);
788   test_finished ();
789 }
790
791
792 /**
793  * Function called if lookup for deletion fails.
794  */
795 static void
796 del_lookup_error_cb (void *cls)
797 {
798   (void) cls;
799   del_qe = NULL;
800   GNUNET_break (0);
801   ret = 1;
802   test_finished ();
803 }
804
805
806 /**
807  * We were asked to delete something; this function is called with
808  * the existing records. Now we should determine what should be
809  * deleted and then issue the deletion operation.
810  *
811  * @param cls NULL
812  * @param zone private key of the zone we are deleting from
813  * @param label name of the records we are editing
814  * @param rd_count size of the @a rd array
815  * @param rd existing records
816  */
817 static void
818 del_monitor (void *cls,
819              const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
820              const char *label,
821              unsigned int rd_count,
822              const struct GNUNET_GNSRECORD_Data *rd)
823 {
824   struct GNUNET_GNSRECORD_Data rdx[rd_count];
825   unsigned int rd_left;
826   uint32_t type;
827   char *vs;
828
829   (void) cls;
830   (void) zone;
831   del_qe = NULL;
832   if (0 == rd_count)
833   {
834     FPRINTF (stderr,
835              _("There are no records under label `%s' that could be deleted.\n"),
836              label);
837     ret = 1;
838     test_finished ();
839     return;
840   }
841   if ( (NULL == value) &&
842        (NULL == typestring) )
843   {
844     /* delete everything */
845     del_qe = GNUNET_NAMESTORE_records_store (ns,
846                                              &zone_pkey,
847                                              name,
848                                              0,
849                                              NULL,
850                                              &del_continuation,
851                                              NULL);
852     return;
853   }
854   rd_left = 0;
855   if (NULL != typestring)
856     type = GNUNET_GNSRECORD_typename_to_number (typestring);
857   else
858     type = GNUNET_GNSRECORD_TYPE_ANY;
859   for (unsigned int i=0;i<rd_count;i++)
860   {
861     vs = NULL;
862     if (! ( ( (GNUNET_GNSRECORD_TYPE_ANY == type) ||
863               (rd[i].record_type == type) ) &&
864             ( (NULL == value) ||
865               (NULL == (vs = (GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
866                                                                 rd[i].data,
867                                                                 rd[i].data_size)))) ||
868               (0 == strcmp (vs, value)) ) ) )
869       rdx[rd_left++] = rd[i];
870     GNUNET_free_non_null (vs);
871   }
872   if (rd_count == rd_left)
873   {
874     /* nothing got deleted */
875     FPRINTF (stderr,
876              _("There are no records under label `%s' that match the request for deletion.\n"),
877              label);
878     test_finished ();
879     return;
880   }
881   /* delete everything but what we copied to 'rdx' */
882   del_qe = GNUNET_NAMESTORE_records_store (ns,
883                                            &zone_pkey,
884                                            name,
885                                            rd_left,
886                                            rdx,
887                                            &del_continuation,
888                                            NULL);
889 }
890
891
892 /**
893  * Parse expiration time.
894  *
895  * @param expirationstring text to parse
896  * @param etime_is_rel[out] set to #GNUNET_YES if time is relative
897  * @param etime[out] set to expiration time (abs or rel)
898  * @return #GNUNET_OK on success
899  */
900 static int
901 parse_expiration (const char *expirationstring,
902                   int *etime_is_rel,
903                   uint64_t *etime)
904 {
905   struct GNUNET_TIME_Relative etime_rel;
906   struct GNUNET_TIME_Absolute etime_abs;
907   
908   if (0 == strcmp (expirationstring,
909                    "never"))
910   {
911     *etime = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
912     *etime_is_rel = GNUNET_NO;
913     return GNUNET_OK;
914   }
915   if (GNUNET_OK ==
916       GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
917                                              &etime_rel))
918   {
919     *etime_is_rel = GNUNET_YES;
920     *etime = etime_rel.rel_value_us;
921     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
922                 "Storing record with relative expiration time of %s\n",
923                 GNUNET_STRINGS_relative_time_to_string (etime_rel,
924                                                         GNUNET_NO));
925     return GNUNET_OK;
926   }
927   if (GNUNET_OK ==
928       GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
929                                              &etime_abs))
930   {
931     *etime_is_rel = GNUNET_NO;
932     *etime = etime_abs.abs_value_us;
933     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
934                 "Storing record with absolute expiration time of %s\n",
935                 GNUNET_STRINGS_absolute_time_to_string (etime_abs));
936     return GNUNET_OK;
937   }
938   return GNUNET_SYSERR;
939 }
940
941
942 /**
943  * Function called when namestore is done with the replace
944  * operation.
945  *
946  * @param cls NULL
947  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
948  *                #GNUNET_NO if content was already there or not found
949  *                #GNUNET_YES (or other positive value) on success
950  * @param emsg NULL on success, otherwise an error message
951  */
952 static void
953 replace_cont (void *cls,
954               int success,
955               const char *emsg)
956 {
957   (void) cls;
958   
959   set_qe = NULL;
960   if (GNUNET_OK != success)
961   {
962     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
963                 _("Failed to replace records: %s\n"),
964                 emsg);
965     ret = 1; /* fail from 'main' */
966   }
967   GNUNET_SCHEDULER_shutdown ();
968 }
969
970
971 /**
972  * Callback invoked from identity service with ego information.
973  * An @a ego of NULL means the ego was not found.
974  *
975  * @param cls closure with the configuration
976  * @param ego an ego known to identity service, or NULL
977  */
978 static void
979 identity_cb (void *cls,
980              const struct GNUNET_IDENTITY_Ego *ego)
981 {
982   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
983   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
984   struct GNUNET_GNSRECORD_Data rd;
985
986   el = NULL;
987   if (NULL == ego)
988   {
989     if (NULL != ego_name)
990     {
991       fprintf (stderr,
992                _("Ego `%s' not known to identity service\n"),
993                ego_name);
994     }
995     GNUNET_SCHEDULER_shutdown ();
996     ret = -1;
997     return;
998   }
999   zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1000   GNUNET_free_non_null (ego_name);
1001   ego_name = NULL;
1002
1003   if (! (add|del|list|(NULL != nickstring)|(NULL != uri)|(NULL != reverse_pkey))|(NULL != recordset) )
1004   {
1005     /* nothing more to be done */
1006     fprintf (stderr,
1007              _("No options given\n"));
1008     GNUNET_SCHEDULER_shutdown ();
1009     return;
1010   }
1011   GNUNET_CRYPTO_ecdsa_key_get_public (&zone_pkey,
1012                                       &pub);
1013   ns = GNUNET_NAMESTORE_connect (cfg);
1014   if (NULL == ns)
1015   {
1016     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1017                 _("Failed to connect to namestore\n"));
1018     return;
1019   }
1020
1021   if (NULL != recordset)
1022   {
1023     /* replace entire record set */
1024     unsigned int rd_count;
1025     struct GNUNET_GNSRECORD_Data *rd;
1026
1027     if (NULL == name)
1028     {
1029       fprintf (stderr,
1030                _("Missing option `%s' for operation `%s'\n"),
1031                "-n", _("replace"));
1032       GNUNET_SCHEDULER_shutdown ();
1033       ret = 1;
1034       return;
1035     }
1036     rd_count = 0;
1037     for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
1038       rd_count++;
1039     rd = GNUNET_new_array (rd_count,
1040                            struct GNUNET_GNSRECORD_Data);
1041     rd_count = 0;
1042     for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
1043     {
1044       rd[rd_count] = e->record;
1045       rd_count++;
1046     }
1047     set_qe = GNUNET_NAMESTORE_records_store (ns,
1048                                              &zone_pkey,
1049                                              name,
1050                                              rd_count,
1051                                              rd,
1052                                              &replace_cont,
1053                                              NULL);
1054     GNUNET_free (rd);
1055     return;
1056   }
1057   
1058   if (add)
1059   {
1060     if (NULL == name)
1061     {
1062       fprintf (stderr,
1063                _("Missing option `%s' for operation `%s'\n"),
1064                "-n", _("add"));
1065       GNUNET_SCHEDULER_shutdown ();
1066       ret = 1;
1067       return;
1068     }
1069     if (NULL == typestring)
1070     {
1071       fprintf (stderr,
1072                _("Missing option `%s' for operation `%s'\n"),
1073                "-t", _("add"));
1074       GNUNET_SCHEDULER_shutdown ();
1075       ret = 1;
1076       return;
1077     }
1078     type = GNUNET_GNSRECORD_typename_to_number (typestring);
1079     if (UINT32_MAX == type)
1080     {
1081       fprintf (stderr,
1082                _("Unsupported type `%s'\n"),
1083                typestring);
1084       GNUNET_SCHEDULER_shutdown ();
1085       ret = 1;
1086       return;
1087     }
1088     if (NULL == value)
1089     {
1090       fprintf (stderr,
1091                _("Missing option `%s' for operation `%s'\n"),
1092                "-V", _("add"));
1093       ret = 1;
1094       GNUNET_SCHEDULER_shutdown ();
1095       return;
1096     }
1097     if (GNUNET_OK !=
1098         GNUNET_GNSRECORD_string_to_value (type,
1099                                           value,
1100                                           &data,
1101                                           &data_size))
1102     {
1103       fprintf (stderr,
1104                _("Value `%s' invalid for record type `%s'\n"),
1105                value,
1106                typestring);
1107       GNUNET_SCHEDULER_shutdown ();
1108       ret = 1;
1109       return;
1110     }
1111     if (NULL == expirationstring)
1112     {
1113       fprintf (stderr,
1114                _("Missing option `%s' for operation `%s'\n"),
1115                "-e",
1116                _("add"));
1117       GNUNET_SCHEDULER_shutdown ();
1118       ret = 1;
1119       return;
1120     }
1121     if (GNUNET_OK !=
1122         parse_expiration (expirationstring,
1123                           &etime_is_rel,
1124                           &etime))
1125     {
1126       fprintf (stderr,
1127                _("Invalid time format `%s'\n"),
1128                expirationstring);
1129       GNUNET_SCHEDULER_shutdown ();
1130       ret = 1;
1131       return;
1132     }
1133     add_qe = GNUNET_NAMESTORE_records_lookup (ns,
1134                                               &zone_pkey,
1135                                               name,
1136                                               &add_error_cb,
1137                                               NULL,
1138                                               &get_existing_record,
1139                                               NULL);
1140   }
1141   if (del)
1142   {
1143     if (NULL == name)
1144     {
1145       fprintf (stderr,
1146                _("Missing option `%s' for operation `%s'\n"),
1147                "-n", _("del"));
1148       GNUNET_SCHEDULER_shutdown ();
1149       ret = 1;
1150       return;
1151     }
1152     del_qe = GNUNET_NAMESTORE_records_lookup (ns,
1153                                               &zone_pkey,
1154                                               name,
1155                                               &del_lookup_error_cb,
1156                                               NULL,
1157                                               &del_monitor,
1158                                               NULL);
1159   }
1160   if (list)
1161   {
1162     if (NULL != name)
1163       get_qe = GNUNET_NAMESTORE_records_lookup (ns,
1164                                                 &zone_pkey,
1165                                                 name,
1166                                                 &lookup_error_cb,
1167                                                 NULL,
1168                                                 &display_record_lookup,
1169                                                 NULL);
1170     else
1171       list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
1172                                                        &zone_pkey,
1173                                                        &zone_iteration_error_cb,
1174                                                        NULL,
1175                                                        &display_record_iterator,
1176                                                        NULL,
1177                                                        &zone_iteration_finished,
1178                                                        NULL);
1179   }
1180   if (NULL != reverse_pkey)
1181   {
1182     struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;
1183
1184     if (GNUNET_OK !=
1185         GNUNET_CRYPTO_ecdsa_public_key_from_string (reverse_pkey,
1186                                                     strlen (reverse_pkey),
1187                                                     &pubkey))
1188     {
1189       fprintf (stderr,
1190                _("Invalid public key for reverse lookup `%s'\n"),
1191                reverse_pkey);
1192       GNUNET_SCHEDULER_shutdown ();
1193     }
1194     reverse_qe = GNUNET_NAMESTORE_zone_to_name (ns,
1195                                                 &zone_pkey,
1196                                                 &pubkey,
1197                                                 &reverse_error_cb,
1198                                                 NULL,
1199                                                 &handle_reverse_lookup,
1200                                                 NULL);
1201   }
1202   if (NULL != uri)
1203   {
1204     char sh[105];
1205     char sname[64];
1206     struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
1207
1208     GNUNET_STRINGS_utf8_tolower (uri, uri);
1209     if ( (2 != (sscanf (uri,
1210                         "gnunet://gns/%52s/%63s",
1211                         sh,
1212                         sname)) ) ||
1213          (GNUNET_OK !=
1214           GNUNET_CRYPTO_ecdsa_public_key_from_string (sh,
1215                                                       strlen (sh),
1216                                                       &pkey)) )
1217     {
1218       fprintf (stderr,
1219                _("Invalid URI `%s'\n"),
1220                uri);
1221       GNUNET_SCHEDULER_shutdown ();
1222       ret = 1;
1223       return;
1224     }
1225     memset (&rd, 0, sizeof (rd));
1226     rd.data = &pkey;
1227     rd.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
1228     rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
1229     rd.expiration_time = etime;
1230     if (GNUNET_YES == etime_is_rel)    
1231       rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1232     if (1 == is_shadow)
1233       rd.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
1234     add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
1235                                                  &zone_pkey,
1236                                                  sname,
1237                                                  1,
1238                                                  &rd,
1239                                                  &add_continuation,
1240                                                  &add_qe_uri);
1241   }
1242   if (NULL != nickstring)
1243   {
1244     if (0 == strlen(nickstring))
1245     {
1246       fprintf (stderr,
1247                _("Invalid nick `%s'\n"),
1248                nickstring);
1249       GNUNET_SCHEDULER_shutdown ();
1250       ret = 1;
1251       return;
1252     }
1253     add_qe_uri = GNUNET_NAMESTORE_set_nick (ns,
1254                                             &zone_pkey,
1255                                             nickstring,
1256                                             &add_continuation,
1257                                             &add_qe_uri);
1258   }
1259   if (monitor)
1260   {
1261     zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
1262                                               &zone_pkey,
1263                                               GNUNET_YES,
1264                                               &monitor_error_cb,
1265                                               NULL,
1266                                               &display_record_monitor,
1267                                               NULL,
1268                                               &sync_cb,
1269                                               NULL);
1270   }
1271 }
1272
1273
1274 static void
1275 default_ego_cb (void *cls,
1276                 struct GNUNET_IDENTITY_Ego *ego,
1277                 void **ctx,
1278                 const char *name)
1279 {
1280   (void) cls;
1281   (void) ctx;
1282   (void) name;
1283   get_default = NULL;
1284   if (NULL == ego)
1285   {
1286     fprintf (stderr,
1287              _("No default ego configured in identity service\n"));
1288     GNUNET_SCHEDULER_shutdown ();
1289     ret = -1;
1290     return;
1291   }
1292   else
1293   {
1294     identity_cb (cls, ego);
1295   }
1296 }
1297
1298
1299 static void
1300 id_connect_cb (void *cls,
1301                struct GNUNET_IDENTITY_Ego *ego,
1302                void **ctx,
1303                const char *name)
1304 {
1305   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1306
1307   (void) cls;
1308   (void) ctx;
1309   (void) name;
1310   if (NULL == ego)
1311   {
1312     get_default = GNUNET_IDENTITY_get (idh,
1313                                        "namestore",
1314                                        &default_ego_cb,
1315                                        (void *) cfg);
1316   }
1317 }
1318
1319
1320 /**
1321  * Main function that will be run.
1322  *
1323  * @param cls closure
1324  * @param args remaining command-line arguments
1325  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1326  * @param cfg configuration
1327  */
1328 static void
1329 run (void *cls,
1330      char *const *args,
1331      const char *cfgfile,
1332      const struct GNUNET_CONFIGURATION_Handle *cfg)
1333 {
1334   (void) cls;
1335   (void) args;
1336   (void) cfgfile;
1337   if (NULL != args[0])
1338     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1339                 _("Superfluous command line arguments (starting with `%s') ignored\n"),
1340                 args[0]);
1341   if ( (NULL != args[0]) &&
1342        (NULL == uri) )
1343     uri = GNUNET_strdup (args[0]);
1344
1345   GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1346                                  (void *) cfg);
1347
1348   if (NULL == ego_name)
1349   {
1350     idh = GNUNET_IDENTITY_connect (cfg,
1351                                    &id_connect_cb,
1352                                    (void *) cfg);
1353     if (NULL == idh)
1354       fprintf (stderr,
1355                _("Cannot connect to identity service\n"));
1356     ret = -1;
1357     return;
1358   }
1359   el = GNUNET_IDENTITY_ego_lookup (cfg,
1360                                    ego_name,
1361                                    &identity_cb,
1362                                    (void *) cfg);
1363 }
1364
1365
1366 /**
1367  * Command-line option parser function that allows the user to specify
1368  * a complete record as one argument for adding/removing.  A pointer
1369  * to the head of the list of record sets must be passed as the "scls"
1370  * argument.
1371  *
1372  * @param ctx command line processor context
1373  * @param scls must be of type "struct GNUNET_FS_Uri **"
1374  * @param option name of the option (typically 'R')
1375  * @param value command line argument given; format is
1376  *        "TTL TYPE FLAGS VALUE" where TTL is an expiration time (rel or abs),
1377  *         TYPE is a DNS/GNS record type, FLAGS is either "n" for no flags or
1378  *         a combination of 's' (shadow) and 'p' (public) and VALUE is the 
1379  *         value (in human-readable format)
1380  * @return #GNUNET_OK on success
1381  */
1382 static int
1383 multirecord_process (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
1384                      void *scls,
1385                      const char *option,
1386                      const char *value)
1387 {
1388   struct RecordSetEntry **head = scls;
1389   struct RecordSetEntry *r;
1390   struct GNUNET_GNSRECORD_Data record;
1391   char *cp;
1392   char *tok;
1393   int etime_is_rel;
1394   void *raw_data;
1395
1396   (void) ctx;
1397   (void) option;
1398   cp = GNUNET_strdup (value);
1399   tok = strtok (cp, " ");
1400   if (NULL == tok)
1401   {
1402     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1403                 _("Empty record line argument is not allowed.\n"));
1404     GNUNET_free (cp);
1405     return GNUNET_SYSERR;
1406   }
1407   if (GNUNET_OK !=
1408       parse_expiration (tok,
1409                         &etime_is_rel,
1410                         &record.expiration_time))
1411   {
1412     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1413                 _("Invalid expiration time `%s'\n"),
1414                 tok);
1415     GNUNET_free (cp);
1416     return GNUNET_SYSERR;
1417   }
1418   tok = strtok (NULL, " ");
1419   if (NULL == tok)
1420   {
1421     GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
1422                 _("Missing entries in record line `%s'.\n"),
1423                 value);
1424     GNUNET_free (cp);
1425     return GNUNET_SYSERR;
1426   }
1427   record.record_type = GNUNET_GNSRECORD_typename_to_number (tok);
1428   if (UINT32_MAX == record.record_type)
1429   {
1430     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1431                 _("Unknown record type `%s'\n"),
1432                 tok);
1433     GNUNET_free (cp);
1434     return GNUNET_SYSERR;
1435   }
1436   tok = strtok (NULL, " ");
1437   if (NULL == tok)
1438   {
1439     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1440                 _("Missing entries in record line `%s'.\n"),
1441                 value);
1442     GNUNET_free (cp);
1443     return GNUNET_SYSERR;
1444   }
1445   record.flags = GNUNET_GNSRECORD_RF_NONE;
1446   if (etime_is_rel)
1447     record.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1448   if (NULL == strchr (tok, (unsigned char) 'p')) /* p = public */
1449     record.flags |= GNUNET_GNSRECORD_RF_PRIVATE; 
1450   if (NULL != strchr (tok, (unsigned char) 's'))
1451     record.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
1452   /* find beginning of record value */
1453   tok = strchr (&value[tok - cp], (unsigned char) ' ');
1454   if (NULL == tok)
1455   {
1456     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1457                 _("Missing entries in record line `%s'.\n"),
1458                 value);
1459     GNUNET_free (cp);
1460     return GNUNET_SYSERR;
1461   }
1462   GNUNET_free (cp);
1463   tok++; /* skip space */
1464   if (GNUNET_OK !=
1465       GNUNET_GNSRECORD_string_to_value (record.record_type,
1466                                         tok,
1467                                         &raw_data,
1468                                         &record.data_size))
1469   {
1470     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1471                 _("Invalid record data for type %s: `%s'.\n"),
1472                 GNUNET_GNSRECORD_number_to_typename (record.record_type),               
1473                 tok);
1474     return GNUNET_SYSERR;
1475   }
1476   
1477   r = GNUNET_malloc (sizeof (struct RecordSetEntry) + record.data_size);
1478   r->next = *head;
1479   record.data = &r[1];
1480   memcpy (&r[1],          
1481           raw_data,
1482           record.data_size);
1483   GNUNET_free (raw_data);
1484   r->record = record;  
1485   *head = r;
1486   return GNUNET_OK;
1487 }
1488
1489
1490 /**
1491  * Allow user to specify keywords.
1492  *
1493  * @param shortName short name of the option
1494  * @param name long name of the option
1495  * @param argumentHelp help text for the option argument
1496  * @param description long help text for the option
1497  * @param[out] topKeywords set to the desired value
1498  */
1499 struct GNUNET_GETOPT_CommandLineOption
1500 multirecord_option (char shortName,
1501                     const char *name,
1502                     const char *argumentHelp,
1503                     const char *description,
1504                     struct RecordSetEntry **rs)
1505 {
1506   struct GNUNET_GETOPT_CommandLineOption clo = {
1507     .shortName = shortName,
1508     .name = name,
1509     .argumentHelp = argumentHelp,
1510     .description = description,
1511     .require_argument = 1,
1512     .processor = &multirecord_process,
1513     .scls = (void *) rs  
1514   };
1515
1516   return clo;
1517 }
1518
1519
1520
1521 /**
1522  * The main function for gnunet-namestore.
1523  *
1524  * @param argc number of arguments from the command line
1525  * @param argv command line arguments
1526  * @return 0 ok, 1 on error
1527  */
1528 int
1529 main (int argc,
1530       char *const *argv)
1531 {
1532   struct GNUNET_GETOPT_CommandLineOption options[] = {
1533     GNUNET_GETOPT_option_flag ('a',
1534                                "add",
1535                                gettext_noop ("add record"),
1536                                &add),
1537     GNUNET_GETOPT_option_flag ('d',
1538                                "delete",
1539                                gettext_noop ("delete record"),
1540                                &del),
1541     GNUNET_GETOPT_option_flag ('D',
1542                                "display",
1543                                gettext_noop ("display records"),
1544                                &list),
1545     GNUNET_GETOPT_option_string ('e',
1546                                  "expiration",
1547                                  "TIME",
1548                                  gettext_noop ("expiration time for record to use (for adding only), \"never\" is possible"),
1549                                  &expirationstring),
1550     GNUNET_GETOPT_option_string ('i',
1551                                  "nick",
1552                                  "NICKNAME",
1553                                  gettext_noop ("set the desired nick name for the zone"),
1554                                  &nickstring),
1555     GNUNET_GETOPT_option_flag ('m',
1556                                "monitor",
1557                                gettext_noop ("monitor changes in the namestore"),
1558                                &monitor),
1559     GNUNET_GETOPT_option_string ('n',
1560                                  "name",
1561                                  "NAME",
1562                                  gettext_noop ("name of the record to add/delete/display"),
1563                                  &name),
1564     GNUNET_GETOPT_option_string ('r',
1565                                  "reverse",
1566                                  "PKEY",
1567                                  gettext_noop ("determine our name for the given PKEY"),
1568                                  &reverse_pkey),
1569     multirecord_option ('R',
1570                         "replace",
1571                         "RECORDLINE",
1572                         gettext_noop ("set record set to values given by (possibly multiple) RECORDLINES; can be specified multiple times"),
1573                         &recordset),
1574     GNUNET_GETOPT_option_string ('t',
1575                                  "type",
1576                                  "TYPE",
1577                                  gettext_noop ("type of the record to add/delete/display"),
1578                                  &typestring),
1579     GNUNET_GETOPT_option_string ('u',
1580                                  "uri",
1581                                  "URI",
1582                                  gettext_noop ("URI to import into our zone"),
1583                                  &uri),
1584     GNUNET_GETOPT_option_string ('V',
1585                                  "value",
1586                                  "VALUE",
1587                                  gettext_noop ("value of the record to add/delete"),
1588                                  &value),
1589     GNUNET_GETOPT_option_flag ('p',
1590                                "public",
1591                                gettext_noop ("create or list public record"),
1592                                &is_public),
1593     GNUNET_GETOPT_option_flag ('s',
1594                                "shadow",
1595                                gettext_noop ("create shadow record (only valid if all other records of the same type have expired"),
1596                                &is_shadow),
1597     GNUNET_GETOPT_option_string ('z',
1598                                  "zone",
1599                                  "EGO",
1600                                  gettext_noop ("name of the ego controlling the zone"),
1601                                  &ego_name),
1602     GNUNET_GETOPT_OPTION_END
1603   };
1604
1605   if (GNUNET_OK !=
1606       GNUNET_STRINGS_get_utf8_args (argc, argv,
1607                                     &argc, &argv))
1608     return 2;
1609
1610   is_public = -1;
1611   is_shadow = -1;
1612   GNUNET_log_setup ("gnunet-namestore",
1613                     "WARNING",
1614                     NULL);
1615   if (GNUNET_OK !=
1616       GNUNET_PROGRAM_run (argc,
1617                           argv,
1618                           "gnunet-namestore",
1619                           _("GNUnet zone manipulation tool"),
1620                           options,
1621                           &run, NULL))
1622   {
1623     GNUNET_free ((void*) argv);
1624     GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
1625     return 1;
1626   }
1627   GNUNET_free ((void*) argv);
1628   GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
1629   return ret;
1630 }
1631
1632 /* end of gnunet-namestore.c */