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