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