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