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