- cleanup dead code
[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   const char *ets;
330   struct GNUNET_TIME_Absolute at;
331   struct GNUNET_TIME_Relative rt;
332
333   if (NULL == name)
334   {
335     list_it = NULL;
336     if ( (NULL == del_qe) &&
337          (NULL == list_qe) &&
338          (NULL == add_qe_uri) &&
339          (NULL == add_qe) )
340       GNUNET_SCHEDULER_shutdown ();
341     return;
342   }
343   FPRINTF (stdout,
344            "%s:\n",
345            name);
346   for (i=0;i<rd_len;i++)
347   {
348     typestring = GNUNET_NAMESTORE_number_to_typename (rd[i].record_type);
349     s = GNUNET_NAMESTORE_value_to_string (rd[i].record_type,
350                                           rd[i].data,
351                                           rd[i].data_size);
352     if (NULL == s)
353     {
354       FPRINTF (stdout, _("\tCorrupt or unsupported record of type %u\n"),
355                (unsigned int) rd[i].record_type);
356       continue;
357     }
358     if (0 != (rd[i].flags & GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION))
359     {
360       rt.rel_value_us = rd[i].expiration_time;
361       ets = GNUNET_STRINGS_relative_time_to_string (rt, GNUNET_YES);
362     }
363     else
364     {
365       at.abs_value_us = rd[i].expiration_time;
366       ets = GNUNET_STRINGS_absolute_time_to_string (at);
367     }
368     FPRINTF (stdout,
369              "\t%s: %s (%s)\n",
370              typestring,
371              s,
372              ets);
373     GNUNET_free (s);
374   }
375   FPRINTF (stdout, "%s", "\n");
376   GNUNET_NAMESTORE_zone_iterator_next (list_it);
377 }
378
379
380 /**
381  * Function called once we are in sync in monitor mode.
382  *
383  * @param cls NULL
384  */
385 static void
386 sync_cb (void *cls)
387 {
388   FPRINTF (stdout, "%s", "Monitor is now in sync.\n");
389 }
390
391
392 /**
393  * We're storing a record; this function is given the existing record
394  * so that we can merge the information.
395  *
396  * @param cls closure, unused
397  * @param zone_key private key of the zone
398  * @param rec_name name that is being mapped (at most 255 characters long)
399  * @param rd_count number of entries in @a rd array
400  * @param rd array of records with data to store
401  */
402 static void
403 get_existing_record (void *cls,
404                      const struct GNUNET_CRYPTO_EccPrivateKey *zone_key,
405                      const char *rec_name,
406                      unsigned int rd_count,
407                      const struct GNUNET_NAMESTORE_RecordData *rd)
408 {
409   struct GNUNET_NAMESTORE_RecordData rdn[rd_count + 1];
410   struct GNUNET_NAMESTORE_RecordData *rde;
411
412   if ( (NULL != zone_key) &&
413        (0 != strcmp (rec_name, name)) )
414   {
415     GNUNET_NAMESTORE_zone_iterator_next (add_zit);
416     return;
417   }
418   memset (rdn, 0, sizeof (struct GNUNET_NAMESTORE_RecordData));
419   memcpy (&rdn[1], rd, rd_count * sizeof (struct GNUNET_NAMESTORE_RecordData));
420   /* FIXME: should add some logic to overwrite records if there
421      can only be one record of a particular type, and to check
422      if the combination of records is valid to begin with... */
423   rde = &rdn[0];
424   rde->data = data;
425   rde->data_size = data_size;
426   rde->record_type = type;
427   if (1 != shadow)
428     rde->flags |= GNUNET_NAMESTORE_RF_SHADOW_RECORD;
429   if (1 != public)
430     rde->flags |= GNUNET_NAMESTORE_RF_PRIVATE;
431   if (GNUNET_YES == etime_is_rel)
432   {
433     rde->expiration_time = etime_rel.rel_value_us;
434     rde->flags |= GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION;
435   }
436   else if (GNUNET_NO == etime_is_rel)
437     rde->expiration_time = etime_abs.abs_value_us;
438   else
439     rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
440   GNUNET_assert (NULL != name);
441   add_qe = GNUNET_NAMESTORE_records_store (ns,
442                                            &zone_pkey,
443                                            name,
444                                            rd_count + 1,
445                                            rde,
446                                            &add_continuation,
447                                            &add_qe);
448   /* only cancel if we were not told that this
449      was the end of the iteration already */
450   if (NULL != rec_name)
451     GNUNET_NAMESTORE_zone_iteration_stop (add_zit);
452   add_zit = NULL;
453 }
454
455
456
457 /**
458  * Process a record that was stored in the namestore in a block.
459  *
460  * @param cls closure, NULL
461  * @param rd_len number of entries in @a rd array
462  * @param rd array of records with data to store
463  */
464 static void
465 display_records_from_block (void *cls,
466                             unsigned int rd_len,
467                             const struct GNUNET_NAMESTORE_RecordData *rd)
468 {
469   const char *typestring;
470   char *s;
471   unsigned int i;
472
473   if (0 == rd_len)
474   {
475     FPRINTF (stdout,
476              _("No records found for `%s'"),
477              name);
478     return;
479   }
480   FPRINTF (stdout,
481            "%s:\n",
482            name);
483   for (i=0;i<rd_len;i++)
484   {
485     typestring = GNUNET_NAMESTORE_number_to_typename (rd[i].record_type);
486     s = GNUNET_NAMESTORE_value_to_string (rd[i].record_type,
487                                           rd[i].data,
488                                           rd[i].data_size);
489     if (NULL == s)
490     {
491       FPRINTF (stdout, _("\tCorrupt or unsupported record of type %u\n"),
492                (unsigned int) rd[i].record_type);
493       continue;
494     }
495     FPRINTF (stdout,
496              "\t%s: %s\n",
497              typestring,
498              s);
499     GNUNET_free (s);
500   }
501   FPRINTF (stdout, "%s", "\n");
502 }
503
504
505 /**
506  * Display block obtained from listing (by name).
507  *
508  * @param cls NULL
509  * @param block NULL if not found
510  */
511 static void
512 handle_block (void *cls,
513               const struct GNUNET_NAMESTORE_Block *block)
514 {
515   struct GNUNET_CRYPTO_EccPublicSignKey zone_pubkey;
516
517   list_qe = NULL;
518   GNUNET_CRYPTO_ecc_key_get_public_for_signature (&zone_pkey,
519                                                   &zone_pubkey);
520   if (NULL == block)
521   {
522     fprintf (stderr,
523              "No matching block found\n");
524   }
525   else if (GNUNET_OK !=
526            GNUNET_NAMESTORE_block_decrypt (block,
527                                            &zone_pubkey,
528                                            name,
529                                            &display_records_from_block,
530                                            NULL))
531   {
532     fprintf (stderr,
533              "Failed to decrypt block!\n");
534   }
535   if ( (NULL == del_qe) &&
536        (NULL == list_it) &&
537        (NULL == add_qe_uri) &&
538        (NULL == add_qe) )
539     GNUNET_SCHEDULER_shutdown ();
540 }
541
542
543 /**
544  * Function called with the result from the check if the namestore
545  * service is actually running.  If it is, we start the actual
546  * operation.
547  *
548  * @param cls closure with our configuration
549  * @param result #GNUNET_YES if the namestore service is running
550  */
551 static void
552 testservice_task (void *cls,
553                   int result)
554 {
555   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
556   struct GNUNET_CRYPTO_EccPublicSignKey pub;
557   struct GNUNET_NAMESTORE_RecordData rd;
558
559   if (GNUNET_YES != result)
560   {
561     FPRINTF (stderr, _("Service `%s' is not running\n"),
562              "namestore");
563     return;
564   }
565   if (! (add|del|list|(NULL != uri)))
566   {
567     /* nothing more to be done */
568     fprintf (stderr,
569              _("No options given\n"));
570     GNUNET_SCHEDULER_shutdown ();
571     return;
572   }
573   GNUNET_CRYPTO_ecc_key_get_public_for_signature (&zone_pkey,
574                                     &pub);
575
576   ns = GNUNET_NAMESTORE_connect (cfg);
577   if (NULL == ns)
578   {
579     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
580                 _("Failed to connect to namestore\n"));
581     return;
582   }
583   if (add)
584   {
585     if (NULL == name)
586     {
587       fprintf (stderr,
588                _("Missing option `%s' for operation `%s'\n"),
589                "-n", _("add"));
590       GNUNET_SCHEDULER_shutdown ();
591       ret = 1;
592       return;
593     }
594     if (NULL == typestring)
595     {
596       fprintf (stderr,
597                _("Missing option `%s' for operation `%s'\n"),
598                "-t", _("add"));
599       GNUNET_SCHEDULER_shutdown ();
600       ret = 1;
601       return;
602     }
603     type = GNUNET_NAMESTORE_typename_to_number (typestring);
604     if (UINT32_MAX == type)
605     {
606       fprintf (stderr, _("Unsupported type `%s'\n"), typestring);
607       GNUNET_SCHEDULER_shutdown ();
608       ret = 1;
609       return;
610     }
611     if (NULL == value)
612     {
613       fprintf (stderr,
614                _("Missing option `%s' for operation `%s'\n"),
615                "-V", _("add"));
616       ret = 1;
617       GNUNET_SCHEDULER_shutdown ();
618       return;
619     }
620     if (GNUNET_OK !=
621         GNUNET_NAMESTORE_string_to_value (type,
622                                           value,
623                                           &data,
624                                           &data_size))
625     {
626       fprintf (stderr, _("Value `%s' invalid for record type `%s'\n"),
627                value,
628                typestring);
629       GNUNET_SCHEDULER_shutdown ();
630       ret = 1;
631       return;
632     }
633     if (NULL == expirationstring)
634     {
635       fprintf (stderr,
636                _("Missing option `%s' for operation `%s'\n"),
637                "-e", _("add"));
638       GNUNET_SCHEDULER_shutdown ();
639       ret = 1;
640       return;
641     }
642     if (0 == strcmp (expirationstring, "never"))
643     {
644       etime_abs = GNUNET_TIME_UNIT_FOREVER_ABS;
645       etime_is_rel = GNUNET_NO;
646     }
647     else if (GNUNET_OK ==
648              GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
649                                                     &etime_rel))
650     {
651       etime_is_rel = GNUNET_YES;
652     }
653     else if (GNUNET_OK ==
654              GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
655                                                     &etime_abs))
656     {
657       etime_is_rel = GNUNET_NO;
658     }
659     else
660     {
661       fprintf (stderr,
662                _("Invalid time format `%s'\n"),
663                expirationstring);
664       GNUNET_SCHEDULER_shutdown ();
665       ret = 1;
666       return;
667     }
668     add_zit = GNUNET_NAMESTORE_zone_iteration_start (ns,
669                                                      &zone_pkey,
670                                                      &get_existing_record,
671                                                      NULL);
672   }
673   if (del)
674   {
675     if (NULL == name)
676     {
677       fprintf (stderr,
678                _("Missing option `%s' for operation `%s'\n"),
679                "-n", _("del"));
680       GNUNET_SCHEDULER_shutdown ();
681       ret = 1;
682       return;
683     }
684     del_qe = GNUNET_NAMESTORE_records_store (ns,
685                                              &zone_pkey,
686                                              name,
687                                              0, NULL,
688                                              &del_continuation,
689                                              NULL);
690   }
691   if (list)
692   {
693     if (NULL == name)
694     {
695       list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
696                                                        &zone_pkey,
697                                                        &display_record,
698                                                        NULL);
699     }
700     else
701     {
702       struct GNUNET_HashCode query;
703       struct GNUNET_CRYPTO_EccPublicSignKey zone_pubkey;
704
705       GNUNET_CRYPTO_ecc_key_get_public_for_signature (&zone_pkey,
706                                                       &zone_pubkey);
707       GNUNET_NAMESTORE_query_from_public_key (&zone_pubkey,
708                                               name,
709                                               &query);
710       list_qe = GNUNET_NAMESTORE_lookup_block (ns,
711                                                &query,
712                                                handle_block,
713                                                NULL);
714     }
715   }
716   if (NULL != uri)
717   {
718     char sh[105];
719     char sname[64];
720     struct GNUNET_CRYPTO_EccPublicSignKey pkey;
721
722     if ( (2 != (sscanf (uri,
723                         "gnunet://gns/%104s/%63s",
724                         sh,
725                         sname)) ) ||
726          (GNUNET_OK !=
727           GNUNET_CRYPTO_ecc_public_sign_key_from_string (sh, strlen (sh), &pkey)) )
728     {
729       fprintf (stderr,
730                _("Invalid URI `%s'\n"),
731                uri);
732       GNUNET_SCHEDULER_shutdown ();
733       ret = 1;
734       return;
735     }
736     memset (&rd, 0, sizeof (rd));
737     rd.data = &pkey;
738     rd.data_size = sizeof (struct GNUNET_CRYPTO_EccPublicSignKey);
739     rd.record_type = GNUNET_NAMESTORE_TYPE_PKEY;
740     if (GNUNET_YES == etime_is_rel)
741     {
742       rd.expiration_time = etime_rel.rel_value_us;
743       rd.flags |= GNUNET_NAMESTORE_RF_RELATIVE_EXPIRATION;
744     }
745     else if (GNUNET_NO == etime_is_rel)
746       rd.expiration_time = etime_abs.abs_value_us;
747     else
748       rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
749     if (1 != shadow)
750       rd.flags |= GNUNET_NAMESTORE_RF_SHADOW_RECORD;
751     add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
752                                                  &zone_pkey,
753                                                  sname,
754                                                  1,
755                                                  &rd,
756                                                  &add_continuation,
757                                                  &add_qe_uri);
758   }
759   if (monitor)
760   {
761     zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
762                                               &zone_pkey,
763                                               &display_record,
764                                               &sync_cb,
765                                               NULL);
766   }
767 }
768
769
770 /**
771  * Callback invoked from identity service with ego information.
772  * An @a ego of NULL means the ego was not found.
773  *
774  * @param cls closure with the configuration
775  * @param ego an ego known to identity service, or NULL
776  */
777 static void
778 identity_cb (void *cls,
779              const struct GNUNET_IDENTITY_Ego *ego)
780 {
781   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
782
783   el = NULL;
784   if (NULL == ego)
785   {
786     fprintf (stderr,
787              _("Ego `%s' not known to identity service\n"),
788              ego_name);
789     GNUNET_SCHEDULER_shutdown ();
790     return;
791   }
792   zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
793   GNUNET_free (ego_name);
794   ego_name = NULL;
795   GNUNET_CLIENT_service_test ("namestore", cfg,
796                               GNUNET_TIME_UNIT_SECONDS,
797                               &testservice_task,
798                               (void *) cfg);
799 }
800
801
802 /**
803  * Main function that will be run.
804  *
805  * @param cls closure
806  * @param args remaining command-line arguments
807  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
808  * @param cfg configuration
809  */
810 static void
811 run (void *cls, char *const *args, const char *cfgfile,
812      const struct GNUNET_CONFIGURATION_Handle *cfg)
813 {
814   if (NULL == ego_name)
815   {
816     fprintf (stderr,
817              _("You must specify which zone should be accessed\n"));
818     return;
819   }
820   if ( (NULL != args[0]) && (NULL == uri) )
821     uri = GNUNET_strdup (args[0]);
822   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
823                                 &do_shutdown, NULL);
824   el = GNUNET_IDENTITY_ego_lookup (cfg,
825                                    ego_name,
826                                    &identity_cb,
827                                    (void *) cfg);
828 }
829
830
831 /**
832  * The main function for gnunet-namestore.
833  *
834  * @param argc number of arguments from the command line
835  * @param argv command line arguments
836  * @return 0 ok, 1 on error
837  */
838 int
839 main (int argc, char *const *argv)
840 {
841   public = -1;
842
843   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
844     {'a', "add", NULL,
845      gettext_noop ("add record"), 0,
846      &GNUNET_GETOPT_set_one, &add},
847     {'d', "delete", NULL,
848      gettext_noop ("delete record"), 0,
849      &GNUNET_GETOPT_set_one, &del},
850     {'D', "display", NULL,
851      gettext_noop ("display records"), 0,
852      &GNUNET_GETOPT_set_one, &list},
853     {'e', "expiration", "TIME",
854      gettext_noop ("expiration time for record to use (for adding only), \"never\" is possible"), 1,
855      &GNUNET_GETOPT_set_string, &expirationstring},
856     {'m', "monitor", NULL,
857      gettext_noop ("monitor changes in the namestore"), 0,
858      &GNUNET_GETOPT_set_one, &monitor},
859     {'n', "name", "NAME",
860      gettext_noop ("name of the record to add/delete/display"), 1,
861      &GNUNET_GETOPT_set_string, &name},
862     {'t', "type", "TYPE",
863      gettext_noop ("type of the record to add/delete/display"), 1,
864      &GNUNET_GETOPT_set_string, &typestring},
865     {'u', "uri", "URI",
866      gettext_noop ("URI to import into our zone"), 1,
867      &GNUNET_GETOPT_set_string, &uri},
868     {'V', "value", "VALUE",
869      gettext_noop ("value of the record to add/delete"), 1,
870      &GNUNET_GETOPT_set_string, &value},
871     {'p', "public", NULL,
872      gettext_noop ("create or list public record"), 0,
873      &GNUNET_GETOPT_set_one, &public},
874     {'s', "shadow", NULL,
875      gettext_noop ("create shadow record (only valid if all other records of the same type have expired"), 0,
876      &GNUNET_GETOPT_set_one, &shadow},
877     {'z', "zone", "EGO",
878      gettext_noop ("name of the ego controlling the zone"), 1,
879      &GNUNET_GETOPT_set_string, &ego_name},
880     GNUNET_GETOPT_OPTION_END
881   };
882
883   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
884     return 2;
885
886   GNUNET_log_setup ("gnunet-namestore", "WARNING", NULL);
887   if (GNUNET_OK !=
888       GNUNET_PROGRAM_run (argc, argv, "gnunet-namestore",
889                           _("GNUnet zone manipulation tool"),
890                           options,
891                           &run, NULL))
892   {
893     GNUNET_free ((void*) argv);
894     GNUNET_CRYPTO_ecc_key_clear (&zone_pkey);
895     return 1;
896   }
897   GNUNET_free ((void*) argv);
898   GNUNET_CRYPTO_ecc_key_clear (&zone_pkey);
899   return ret;
900 }
901
902 /* end of gnunet-namestore.c */