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