aboutsummaryrefslogtreecommitdiff
path: root/src/namestore/gnunet-namestore.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/namestore/gnunet-namestore.c')
-rw-r--r--src/namestore/gnunet-namestore.c1660
1 files changed, 0 insertions, 1660 deletions
diff --git a/src/namestore/gnunet-namestore.c b/src/namestore/gnunet-namestore.c
deleted file mode 100644
index af40f2dbe..000000000
--- a/src/namestore/gnunet-namestore.c
+++ /dev/null
@@ -1,1660 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2014, 2019 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 SPDX-License-Identifier: AGPL3.0-or-later
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 * The upper bound for the zone iteration interval
38 * (per record).
39 */
40#define WARN_RELATIVE_EXPIRATION_LIMIT GNUNET_TIME_relative_multiply ( \
41 GNUNET_TIME_UNIT_MINUTES, 15)
42
43/**
44 * Entry in record set for bulk processing.
45 */
46struct RecordSetEntry
47{
48 /**
49 * Kept in a linked list.
50 */
51 struct RecordSetEntry *next;
52
53 /**
54 * The record to add/remove.
55 */
56 struct GNUNET_GNSRECORD_Data record;
57};
58
59
60/**
61 * Handle to the namestore.
62 */
63static struct GNUNET_NAMESTORE_Handle *ns;
64
65/**
66 * Private key for the our zone.
67 */
68static struct GNUNET_IDENTITY_PrivateKey zone_pkey;
69
70/**
71 * Handle to identity lookup.
72 */
73static struct GNUNET_IDENTITY_EgoLookup *el;
74
75/**
76 * Identity service handle
77 */
78static struct GNUNET_IDENTITY_Handle *idh;
79
80/**
81 * Obtain default ego
82 */
83struct GNUNET_IDENTITY_Operation *get_default;
84
85/**
86 * Name of the ego controlling the zone.
87 */
88static char *ego_name;
89
90/**
91 * Desired action is to add a record.
92 */
93static int add;
94
95/**
96 * Queue entry for the 'add-uri' operation.
97 */
98static struct GNUNET_NAMESTORE_QueueEntry *add_qe_uri;
99
100/**
101 * Queue entry for the 'add' operation.
102 */
103static struct GNUNET_NAMESTORE_QueueEntry *add_qe;
104
105/**
106 * Queue entry for the 'lookup' operation.
107 */
108static struct GNUNET_NAMESTORE_QueueEntry *get_qe;
109
110/**
111 * Queue entry for the 'reverse lookup' operation (in combination with a name).
112 */
113static struct GNUNET_NAMESTORE_QueueEntry *reverse_qe;
114
115/**
116 * Desired action is to list records.
117 */
118static int list;
119
120/**
121 * List iterator for the 'list' operation.
122 */
123static struct GNUNET_NAMESTORE_ZoneIterator *list_it;
124
125/**
126 * Desired action is to remove a record.
127 */
128static int del;
129
130/**
131 * Is record public (opposite of #GNUNET_GNSRECORD_RF_PRIVATE)
132 */
133static int is_public;
134
135/**
136 * Is record a shadow record (#GNUNET_GNSRECORD_RF_SHADOW_RECORD)
137 */
138static int is_shadow;
139
140/**
141 * Queue entry for the 'del' operation.
142 */
143static struct GNUNET_NAMESTORE_QueueEntry *del_qe;
144
145/**
146 * Queue entry for the 'set/replace' operation.
147 */
148static struct GNUNET_NAMESTORE_QueueEntry *set_qe;
149
150/**
151 * Name of the records to add/list/remove.
152 */
153static char *name;
154
155/**
156 * Value of the record to add/remove.
157 */
158static char *value;
159
160/**
161 * URI to import.
162 */
163static char *uri;
164
165/**
166 * Reverse lookup to perform.
167 */
168static char *reverse_pkey;
169
170/**
171 * Type of the record to add/remove, NULL to remove all.
172 */
173static char *typestring;
174
175/**
176 * Desired expiration time.
177 */
178static char *expirationstring;
179
180/**
181 * Desired nick name.
182 */
183static char *nickstring;
184
185/**
186 * Global return value
187 */
188static int ret;
189
190/**
191 * Type string converted to DNS type value.
192 */
193static uint32_t type;
194
195/**
196 * Value in binary format.
197 */
198static void *data;
199
200/**
201 * Number of bytes in #data.
202 */
203static size_t data_size;
204
205/**
206 * Expiration string converted to numeric value.
207 */
208static uint64_t etime;
209
210/**
211 * Is expiration time relative or absolute time?
212 */
213static int etime_is_rel = GNUNET_SYSERR;
214
215/**
216 * Monitor handle.
217 */
218static struct GNUNET_NAMESTORE_ZoneMonitor *zm;
219
220/**
221 * Enables monitor mode.
222 */
223static int monitor;
224
225/**
226 * Entry in record set for processing records in bulk.
227 */
228static struct RecordSetEntry *recordset;
229
230
231/**
232 * Task run on shutdown. Cleans up everything.
233 *
234 * @param cls unused
235 */
236static void
237do_shutdown (void *cls)
238{
239 (void) cls;
240 if (NULL != get_default)
241 {
242 GNUNET_IDENTITY_cancel (get_default);
243 get_default = NULL;
244 }
245 if (NULL != idh)
246 {
247 GNUNET_IDENTITY_disconnect (idh);
248 idh = NULL;
249 }
250 if (NULL != el)
251 {
252 GNUNET_IDENTITY_ego_lookup_cancel (el);
253 el = NULL;
254 }
255 if (NULL != list_it)
256 {
257 GNUNET_NAMESTORE_zone_iteration_stop (list_it);
258 list_it = NULL;
259 }
260 if (NULL != add_qe)
261 {
262 GNUNET_NAMESTORE_cancel (add_qe);
263 add_qe = NULL;
264 }
265 if (NULL != set_qe)
266 {
267 GNUNET_NAMESTORE_cancel (set_qe);
268 set_qe = NULL;
269 }
270 if (NULL != add_qe_uri)
271 {
272 GNUNET_NAMESTORE_cancel (add_qe_uri);
273 add_qe_uri = NULL;
274 }
275 if (NULL != get_qe)
276 {
277 GNUNET_NAMESTORE_cancel (get_qe);
278 get_qe = NULL;
279 }
280 if (NULL != del_qe)
281 {
282 GNUNET_NAMESTORE_cancel (del_qe);
283 del_qe = NULL;
284 }
285 if (NULL != ns)
286 {
287 GNUNET_NAMESTORE_disconnect (ns);
288 ns = NULL;
289 }
290 memset (&zone_pkey, 0, sizeof(zone_pkey));
291 if (NULL != uri)
292 {
293 GNUNET_free (uri);
294 uri = NULL;
295 }
296 if (NULL != zm)
297 {
298 GNUNET_NAMESTORE_zone_monitor_stop (zm);
299 zm = NULL;
300 }
301 if (NULL != data)
302 {
303 GNUNET_free (data);
304 data = NULL;
305 }
306}
307
308
309/**
310 * Check if we are finished, and if so, perform shutdown.
311 */
312static void
313test_finished ()
314{
315 if ((NULL == add_qe) && (NULL == add_qe_uri) && (NULL == get_qe) &&
316 (NULL == del_qe) && (NULL == reverse_qe) && (NULL == list_it))
317 GNUNET_SCHEDULER_shutdown ();
318}
319
320
321/**
322 * Continuation called to notify client about result of the
323 * operation.
324 *
325 * @param cls closure, location of the QueueEntry pointer to NULL out
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 */
331static void
332add_continuation (void *cls, int32_t success, const char *emsg)
333{
334 struct GNUNET_NAMESTORE_QueueEntry **qe = cls;
335
336 *qe = NULL;
337 if (GNUNET_YES != success)
338 {
339 fprintf (stderr,
340 _ ("Adding record failed: %s\n"),
341 (GNUNET_NO == success) ? "record exists" : emsg);
342 if (GNUNET_NO != success)
343 ret = 1;
344 }
345 ret = 0;
346 test_finished ();
347}
348
349
350/**
351 * Continuation called to notify client about result of the
352 * operation.
353 *
354 * @param cls closure, unused
355 * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
356 * #GNUNET_NO if content was already there
357 * #GNUNET_YES (or other positive value) on success
358 * @param emsg NULL on success, otherwise an error message
359 */
360static void
361del_continuation (void *cls, int32_t success, const char *emsg)
362{
363 (void) cls;
364 del_qe = NULL;
365 if (GNUNET_NO == success)
366 {
367 fprintf (stderr,
368 _ ("Deleting record failed, record does not exist%s%s\n"),
369 (NULL != emsg) ? ": " : "",
370 (NULL != emsg) ? emsg : "");
371 }
372 if (GNUNET_SYSERR == success)
373 {
374 fprintf (stderr,
375 _ ("Deleting record failed%s%s\n"),
376 (NULL != emsg) ? ": " : "",
377 (NULL != emsg) ? emsg : "");
378 }
379 test_finished ();
380}
381
382
383/**
384 * Function called when we are done with a zone iteration.
385 */
386static void
387zone_iteration_finished (void *cls)
388{
389 (void) cls;
390 list_it = NULL;
391 test_finished ();
392}
393
394
395/**
396 * Function called when we encountered an error in a zone iteration.
397 */
398static void
399zone_iteration_error_cb (void *cls)
400{
401 (void) cls;
402 list_it = NULL;
403 fprintf (stderr, "Error iterating over zone\n");
404 ret = 1;
405 test_finished ();
406}
407
408
409/**
410 * Process a record that was stored in the namestore.
411 *
412 * @param rname name that is being mapped (at most 255 characters long)
413 * @param rd_len number of entries in @a rd array
414 * @param rd array of records with data to store
415 */
416static void
417display_record (const char *rname,
418 unsigned int rd_len,
419 const struct GNUNET_GNSRECORD_Data *rd)
420{
421 const char *typestr;
422 char *s;
423 const char *ets;
424 struct GNUNET_TIME_Absolute at;
425 struct GNUNET_TIME_Relative rt;
426 int have_record;
427
428 if ((NULL != name) && (0 != strcmp (name, rname)))
429 {
430 GNUNET_NAMESTORE_zone_iterator_next (list_it, 1);
431 return;
432 }
433 have_record = GNUNET_NO;
434 for (unsigned int i = 0; i < rd_len; i++)
435 {
436 if ((GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
437 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)))
438 continue;
439 if (GNUNET_GNSRECORD_TYPE_TOMBSTONE == rd[i].record_type)
440 continue;
441 if ((type != rd[i].record_type) && (GNUNET_GNSRECORD_TYPE_ANY != type))
442 continue;
443 have_record = GNUNET_YES;
444 break;
445 }
446 if (GNUNET_NO == have_record)
447 return;
448 fprintf (stdout, "%s:\n", rname);
449 if (NULL != typestring)
450 type = GNUNET_GNSRECORD_typename_to_number (typestring);
451 else
452 type = GNUNET_GNSRECORD_TYPE_ANY;
453 for (unsigned int i = 0; i < rd_len; i++)
454 {
455 if ((GNUNET_GNSRECORD_TYPE_NICK == rd[i].record_type) &&
456 (0 != strcmp (rname, GNUNET_GNS_EMPTY_LABEL_AT)))
457 continue;
458 if (GNUNET_GNSRECORD_TYPE_TOMBSTONE == rd[i].record_type)
459 continue;
460 if ((type != rd[i].record_type) && (GNUNET_GNSRECORD_TYPE_ANY != type))
461 continue;
462 typestr = GNUNET_GNSRECORD_number_to_typename (rd[i].record_type);
463 s = GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
464 rd[i].data,
465 rd[i].data_size);
466 if (NULL == s)
467 {
468 fprintf (stdout,
469 _ ("\tCorrupt or unsupported record of type %u\n"),
470 (unsigned int) rd[i].record_type);
471 continue;
472 }
473 if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
474 {
475 rt.rel_value_us = rd[i].expiration_time;
476 ets = GNUNET_STRINGS_relative_time_to_string (rt, GNUNET_YES);
477 }
478 else
479 {
480 at.abs_value_us = rd[i].expiration_time;
481 ets = GNUNET_STRINGS_absolute_time_to_string (at);
482 }
483 fprintf (stdout,
484 "\t%s: %s (%s)\t%s\t%s\n",
485 typestr,
486 s,
487 ets,
488 (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_PRIVATE)) ? "PRIVATE"
489 : "PUBLIC",
490 (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)) ? "SHADOW"
491 : "");
492 GNUNET_free (s);
493 }
494 fprintf (stdout, "%s", "\n");
495}
496
497
498/**
499 * Process a record that was stored in the namestore.
500 *
501 * @param cls closure
502 * @param zone_key private key of the zone
503 * @param rname name that is being mapped (at most 255 characters long)
504 * @param rd_len number of entries in @a rd array
505 * @param rd array of records with data to store
506 */
507static void
508display_record_iterator (void *cls,
509 const struct GNUNET_IDENTITY_PrivateKey *zone_key,
510 const char *rname,
511 unsigned int rd_len,
512 const struct GNUNET_GNSRECORD_Data *rd)
513{
514 (void) cls;
515 (void) zone_key;
516 display_record (rname, rd_len, rd);
517 GNUNET_NAMESTORE_zone_iterator_next (list_it, 1);
518}
519
520
521/**
522 * Process a record that was stored in the namestore.
523 *
524 * @param cls closure
525 * @param zone_key private key of the zone
526 * @param rname name that is being mapped (at most 255 characters long)
527 * @param rd_len number of entries in @a rd array
528 * @param rd array of records with data to store
529 */
530static void
531display_record_monitor (void *cls,
532 const struct GNUNET_IDENTITY_PrivateKey *zone_key,
533 const char *rname,
534 unsigned int rd_len,
535 const struct GNUNET_GNSRECORD_Data *rd)
536{
537 (void) cls;
538 (void) zone_key;
539 display_record (rname, rd_len, rd);
540 GNUNET_NAMESTORE_zone_monitor_next (zm, 1);
541}
542
543
544/**
545 * Process a record that was stored in the namestore.
546 *
547 * @param cls closure
548 * @param zone_key private key of the zone
549 * @param rname name that is being mapped (at most 255 characters long)
550 * @param rd_len number of entries in @a rd array
551 * @param rd array of records with data to store
552 */
553static void
554display_record_lookup (void *cls,
555 const struct GNUNET_IDENTITY_PrivateKey *zone_key,
556 const char *rname,
557 unsigned int rd_len,
558 const struct GNUNET_GNSRECORD_Data *rd)
559{
560 (void) cls;
561 (void) zone_key;
562 get_qe = NULL;
563 display_record (rname, rd_len, rd);
564 test_finished ();
565}
566
567
568/**
569 * Function called once we are in sync in monitor mode.
570 *
571 * @param cls NULL
572 */
573static void
574sync_cb (void *cls)
575{
576 (void) cls;
577 fprintf (stdout, "%s", "Monitor is now in sync.\n");
578}
579
580
581/**
582 * Function called on errors while monitoring.
583 *
584 * @param cls NULL
585 */
586static void
587monitor_error_cb (void *cls)
588{
589 (void) cls;
590 fprintf (stderr, "%s", "Monitor disconnected and out of sync.\n");
591}
592
593
594/**
595 * Function called on errors while monitoring.
596 *
597 * @param cls NULL
598 */
599static void
600lookup_error_cb (void *cls)
601{
602 (void) cls;
603 get_qe = NULL;
604 fprintf (stderr, "%s", "Failed to lookup record.\n");
605 test_finished ();
606}
607
608
609/**
610 * Function called if lookup fails.
611 */
612static void
613add_error_cb (void *cls)
614{
615 (void) cls;
616 add_qe = NULL;
617 GNUNET_break (0);
618 ret = 1;
619 test_finished ();
620}
621
622
623/**
624 * We're storing a record; this function is given the existing record
625 * so that we can merge the information.
626 *
627 * @param cls closure, unused
628 * @param zone_key private key of the zone
629 * @param rec_name name that is being mapped (at most 255 characters long)
630 * @param rd_count number of entries in @a rd array
631 * @param rd array of records with data to store
632 */
633static void
634get_existing_record (void *cls,
635 const struct GNUNET_IDENTITY_PrivateKey *zone_key,
636 const char *rec_name,
637 unsigned int rd_count,
638 const struct GNUNET_GNSRECORD_Data *rd)
639{
640 struct GNUNET_GNSRECORD_Data rdn[rd_count + 1];
641 struct GNUNET_GNSRECORD_Data *rde;
642
643 (void) cls;
644 (void) zone_key;
645 add_qe = NULL;
646 if (0 != strcmp (rec_name, name))
647 {
648 GNUNET_break (0);
649 ret = 1;
650 test_finished ();
651 return;
652 }
653
654 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
655 "Received %u records for name `%s'\n",
656 rd_count,
657 rec_name);
658 for (unsigned int i = 0; i < rd_count; i++)
659 {
660 switch (rd[i].record_type)
661 {
662 case GNUNET_DNSPARSER_TYPE_SOA:
663 if (GNUNET_DNSPARSER_TYPE_SOA == type)
664 {
665 fprintf (
666 stderr,
667 _ (
668 "A SOA record exists already under `%s', cannot add a second SOA to the same zone.\n"),
669 rec_name);
670 ret = 1;
671 test_finished ();
672 return;
673 }
674 break;
675 }
676 }
677 memset (rdn, 0, sizeof(struct GNUNET_GNSRECORD_Data));
678 GNUNET_memcpy (&rdn[1], rd, rd_count * sizeof(struct GNUNET_GNSRECORD_Data));
679 rde = &rdn[0];
680 rde->data = data;
681 rde->data_size = data_size;
682 rde->record_type = type;
683 if (1 == is_shadow)
684 rde->flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
685 if (1 != is_public)
686 rde->flags |= GNUNET_GNSRECORD_RF_PRIVATE;
687 rde->expiration_time = etime;
688 if (GNUNET_YES == etime_is_rel)
689 rde->flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
690 else if (GNUNET_NO != etime_is_rel)
691 rde->expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
692 GNUNET_assert (NULL != name);
693 add_qe = GNUNET_NAMESTORE_records_store (ns,
694 &zone_pkey,
695 name,
696 rd_count + 1,
697 rde,
698 &add_continuation,
699 &add_qe);
700}
701
702
703/**
704 * Function called if we encountered an error in zone-to-name.
705 */
706static void
707reverse_error_cb (void *cls)
708{
709 (void) cls;
710 reverse_qe = NULL;
711 fprintf (stdout, "%s.zkey\n", reverse_pkey);
712}
713
714
715/**
716 * Function called with the result of our attempt to obtain a name for a given
717 * public key.
718 *
719 * @param cls NULL
720 * @param zone private key of the zone; NULL on disconnect
721 * @param label label of the records; NULL on disconnect
722 * @param rd_count number of entries in @a rd array, 0 if label was deleted
723 * @param rd array of records with data to store
724 */
725static void
726handle_reverse_lookup (void *cls,
727 const struct GNUNET_IDENTITY_PrivateKey *zone,
728 const char *label,
729 unsigned int rd_count,
730 const struct GNUNET_GNSRECORD_Data *rd)
731{
732 (void) cls;
733 (void) zone;
734 (void) rd_count;
735 (void) rd;
736 reverse_qe = NULL;
737 if (NULL == label)
738 fprintf (stdout, "%s\n", reverse_pkey);
739 else
740 fprintf (stdout, "%s.%s\n", label, ego_name);
741 test_finished ();
742}
743
744
745/**
746 * Function called if lookup for deletion fails.
747 */
748static void
749del_lookup_error_cb (void *cls)
750{
751 (void) cls;
752 del_qe = NULL;
753 GNUNET_break (0);
754 ret = 1;
755 test_finished ();
756}
757
758
759/**
760 * We were asked to delete something; this function is called with
761 * the existing records. Now we should determine what should be
762 * deleted and then issue the deletion operation.
763 *
764 * @param cls NULL
765 * @param zone private key of the zone we are deleting from
766 * @param label name of the records we are editing
767 * @param rd_count size of the @a rd array
768 * @param rd existing records
769 */
770static void
771del_monitor (void *cls,
772 const struct GNUNET_IDENTITY_PrivateKey *zone,
773 const char *label,
774 unsigned int rd_count,
775 const struct GNUNET_GNSRECORD_Data *rd)
776{
777 struct GNUNET_GNSRECORD_Data rdx[rd_count];
778 unsigned int rd_left;
779 uint32_t type;
780 char *vs;
781
782 (void) cls;
783 (void) zone;
784 del_qe = NULL;
785 if (0 == rd_count)
786 {
787 fprintf (stderr,
788 _ (
789 "There are no records under label `%s' that could be deleted.\n"),
790 label);
791 ret = 1;
792 test_finished ();
793 return;
794 }
795 if ((NULL == value) && (NULL == typestring))
796 {
797 /* delete everything */
798 del_qe = GNUNET_NAMESTORE_records_store (ns,
799 &zone_pkey,
800 name,
801 0,
802 NULL,
803 &del_continuation,
804 NULL);
805 return;
806 }
807 rd_left = 0;
808 if (NULL != typestring)
809 type = GNUNET_GNSRECORD_typename_to_number (typestring);
810 else
811 type = GNUNET_GNSRECORD_TYPE_ANY;
812 for (unsigned int i = 0; i < rd_count; i++)
813 {
814 vs = NULL;
815 if (! (((GNUNET_GNSRECORD_TYPE_ANY == type) ||
816 (rd[i].record_type == type)) &&
817 ((NULL == value) ||
818 (NULL ==
819 (vs = (GNUNET_GNSRECORD_value_to_string (rd[i].record_type,
820 rd[i].data,
821 rd[i].data_size)))) ||
822 (0 == strcmp (vs, value)))))
823 rdx[rd_left++] = rd[i];
824 GNUNET_free (vs);
825 }
826 if (rd_count == rd_left)
827 {
828 /* nothing got deleted */
829 fprintf (
830 stderr,
831 _ (
832 "There are no records under label `%s' that match the request for deletion.\n"),
833 label);
834 test_finished ();
835 return;
836 }
837 /* delete everything but what we copied to 'rdx' */
838 del_qe = GNUNET_NAMESTORE_records_store (ns,
839 &zone_pkey,
840 name,
841 rd_left,
842 rdx,
843 &del_continuation,
844 NULL);
845}
846
847
848/**
849 * Parse expiration time.
850 *
851 * @param expirationstring text to parse
852 * @param etime_is_rel[out] set to #GNUNET_YES if time is relative
853 * @param etime[out] set to expiration time (abs or rel)
854 * @return #GNUNET_OK on success
855 */
856static int
857parse_expiration (const char *expirationstring,
858 int *etime_is_rel,
859 uint64_t *etime)
860{
861 struct GNUNET_TIME_Relative etime_rel;
862 struct GNUNET_TIME_Absolute etime_abs;
863
864 if (0 == strcmp (expirationstring, "never"))
865 {
866 *etime = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;
867 *etime_is_rel = GNUNET_NO;
868 return GNUNET_OK;
869 }
870 if (GNUNET_OK ==
871 GNUNET_STRINGS_fancy_time_to_relative (expirationstring, &etime_rel))
872 {
873 *etime_is_rel = GNUNET_YES;
874 *etime = etime_rel.rel_value_us;
875 if (GNUNET_TIME_relative_cmp (etime_rel, <, WARN_RELATIVE_EXPIRATION_LIMIT))
876 {
877 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
878 "Relative expiration times of less than %s are not recommended. To improve availability, consider increasing this value.\n",
879 GNUNET_STRINGS_relative_time_to_string (
880 WARN_RELATIVE_EXPIRATION_LIMIT, GNUNET_NO));
881 }
882 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
883 "Storing record with relative expiration time of %s\n",
884 GNUNET_STRINGS_relative_time_to_string (etime_rel, GNUNET_NO));
885 return GNUNET_OK;
886 }
887 if (GNUNET_OK ==
888 GNUNET_STRINGS_fancy_time_to_absolute (expirationstring, &etime_abs))
889 {
890 *etime_is_rel = GNUNET_NO;
891 *etime = etime_abs.abs_value_us;
892 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
893 "Storing record with absolute expiration time of %s\n",
894 GNUNET_STRINGS_absolute_time_to_string (etime_abs));
895 return GNUNET_OK;
896 }
897 return GNUNET_SYSERR;
898}
899
900
901/**
902 * Function called when namestore is done with the replace
903 * operation.
904 *
905 * @param cls NULL
906 * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
907 * #GNUNET_NO if content was already there or not found
908 * #GNUNET_YES (or other positive value) on success
909 * @param emsg NULL on success, otherwise an error message
910 */
911static void
912replace_cont (void *cls, int success, const char *emsg)
913{
914 (void) cls;
915
916 set_qe = NULL;
917 if (GNUNET_OK != success)
918 {
919 GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
920 _ ("Failed to replace records: %s\n"),
921 emsg);
922 ret = 1; /* fail from 'main' */
923 }
924 GNUNET_SCHEDULER_shutdown ();
925}
926
927
928/**
929 * We have obtained the zone's private key, so now process
930 * the main commands using it.
931 *
932 * @param cfg configuration to use
933 */
934static void
935run_with_zone_pkey (const struct GNUNET_CONFIGURATION_Handle *cfg)
936{
937 struct GNUNET_GNSRECORD_Data rd;
938
939 if (! (add | del | list | (NULL != nickstring) | (NULL != uri)
940 | (NULL != reverse_pkey) | (NULL != recordset)))
941 {
942 /* nothing more to be done */
943 fprintf (stderr, _ ("No options given\n"));
944 GNUNET_SCHEDULER_shutdown ();
945 return;
946 }
947 ns = GNUNET_NAMESTORE_connect (cfg);
948 if (NULL == ns)
949 {
950 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
951 _ ("Failed to connect to namestore\n"));
952 return;
953 }
954
955 if (NULL != recordset)
956 {
957 /* replace entire record set */
958 unsigned int rd_count;
959 struct GNUNET_GNSRECORD_Data *rd;
960
961 if (NULL == name)
962 {
963 fprintf (stderr,
964 _ ("Missing option `%s' for operation `%s'\n"),
965 "-R",
966 _ ("replace"));
967 GNUNET_SCHEDULER_shutdown ();
968 ret = 1;
969 return;
970 }
971 rd_count = 0;
972 for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
973 rd_count++;
974 rd = GNUNET_new_array (rd_count, struct GNUNET_GNSRECORD_Data);
975 rd_count = 0;
976 for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
977 {
978 rd[rd_count] = e->record;
979 rd_count++;
980 }
981 set_qe = GNUNET_NAMESTORE_records_store (ns,
982 &zone_pkey,
983 name,
984 rd_count,
985 rd,
986 &replace_cont,
987 NULL);
988 GNUNET_free (rd);
989 return;
990 }
991 if (NULL != nickstring)
992 {
993 if (0 == strlen (nickstring))
994 {
995 fprintf (stderr, _ ("Invalid nick `%s'\n"), nickstring);
996 GNUNET_SCHEDULER_shutdown ();
997 ret = 1;
998 return;
999 }
1000 add = 1;
1001 typestring = GNUNET_strdup (GNUNET_GNSRECORD_number_to_typename (
1002 GNUNET_GNSRECORD_TYPE_NICK));
1003 name = GNUNET_strdup (GNUNET_GNS_EMPTY_LABEL_AT);
1004 value = GNUNET_strdup (nickstring);
1005 is_public = 0;
1006 expirationstring = GNUNET_strdup ("never");
1007 GNUNET_free (nickstring);
1008 nickstring = NULL;
1009 }
1010
1011 if (add)
1012 {
1013 if (NULL == name)
1014 {
1015 fprintf (stderr,
1016 _ ("Missing option `%s' for operation `%s'\n"),
1017 "-n",
1018 _ ("add"));
1019 GNUNET_SCHEDULER_shutdown ();
1020 ret = 1;
1021 return;
1022 }
1023 if (NULL == typestring)
1024 {
1025 fprintf (stderr,
1026 _ ("Missing option `%s' for operation `%s'\n"),
1027 "-t",
1028 _ ("add"));
1029 GNUNET_SCHEDULER_shutdown ();
1030 ret = 1;
1031 return;
1032 }
1033 type = GNUNET_GNSRECORD_typename_to_number (typestring);
1034 if (UINT32_MAX == type)
1035 {
1036 fprintf (stderr, _ ("Unsupported type `%s'\n"), typestring);
1037 GNUNET_SCHEDULER_shutdown ();
1038 ret = 1;
1039 return;
1040 }
1041 if ((GNUNET_DNSPARSER_TYPE_SRV == type) ||
1042 (GNUNET_DNSPARSER_TYPE_TLSA == type) ||
1043 (GNUNET_DNSPARSER_TYPE_OPENPGPKEY == type))
1044 {
1045 fprintf (stderr,
1046 _ ("For DNS record types `SRV', `TLSA' and `OPENPGPKEY'"));
1047 fprintf (stderr, ", please use a `BOX' record instead\n");
1048 GNUNET_SCHEDULER_shutdown ();
1049 ret = 1;
1050 return;
1051 }
1052 if (NULL == value)
1053 {
1054 fprintf (stderr,
1055 _ ("Missing option `%s' for operation `%s'\n"),
1056 "-V",
1057 _ ("add"));
1058 ret = 1;
1059 GNUNET_SCHEDULER_shutdown ();
1060 return;
1061 }
1062 if (GNUNET_OK !=
1063 GNUNET_GNSRECORD_string_to_value (type, value, &data, &data_size))
1064 {
1065 fprintf (stderr,
1066 _ ("Value `%s' invalid for record type `%s'\n"),
1067 value,
1068 typestring);
1069 GNUNET_SCHEDULER_shutdown ();
1070 ret = 1;
1071 return;
1072 }
1073 if (NULL == expirationstring)
1074 {
1075 fprintf (stderr,
1076 _ ("Missing option `%s' for operation `%s'\n"),
1077 "-e",
1078 _ ("add"));
1079 GNUNET_SCHEDULER_shutdown ();
1080 ret = 1;
1081 return;
1082 }
1083 if (GNUNET_OK != parse_expiration (expirationstring, &etime_is_rel, &etime))
1084 {
1085 fprintf (stderr, _ ("Invalid time format `%s'\n"), expirationstring);
1086 GNUNET_SCHEDULER_shutdown ();
1087 ret = 1;
1088 return;
1089 }
1090 add_qe = GNUNET_NAMESTORE_records_lookup (ns,
1091 &zone_pkey,
1092 name,
1093 &add_error_cb,
1094 NULL,
1095 &get_existing_record,
1096 NULL);
1097 }
1098 if (del)
1099 {
1100 if (NULL == name)
1101 {
1102 fprintf (stderr,
1103 _ ("Missing option `%s' for operation `%s'\n"),
1104 "-n",
1105 _ ("del"));
1106 GNUNET_SCHEDULER_shutdown ();
1107 ret = 1;
1108 return;
1109 }
1110 del_qe = GNUNET_NAMESTORE_records_lookup (ns,
1111 &zone_pkey,
1112 name,
1113 &del_lookup_error_cb,
1114 NULL,
1115 &del_monitor,
1116 NULL);
1117 }
1118 if (list)
1119 {
1120 if (NULL != name)
1121 get_qe = GNUNET_NAMESTORE_records_lookup (ns,
1122 &zone_pkey,
1123 name,
1124 &lookup_error_cb,
1125 NULL,
1126 &display_record_lookup,
1127 NULL);
1128 else
1129 list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
1130 &zone_pkey,
1131 &zone_iteration_error_cb,
1132 NULL,
1133 &display_record_iterator,
1134 NULL,
1135 &zone_iteration_finished,
1136 NULL);
1137 }
1138 if (NULL != reverse_pkey)
1139 {
1140 struct GNUNET_IDENTITY_PublicKey pubkey;
1141
1142 if (GNUNET_OK !=
1143 GNUNET_IDENTITY_public_key_from_string (reverse_pkey,
1144 &pubkey))
1145 {
1146 fprintf (stderr,
1147 _ ("Invalid public key for reverse lookup `%s'\n"),
1148 reverse_pkey);
1149 GNUNET_SCHEDULER_shutdown ();
1150 }
1151 reverse_qe = GNUNET_NAMESTORE_zone_to_name (ns,
1152 &zone_pkey,
1153 &pubkey,
1154 &reverse_error_cb,
1155 NULL,
1156 &handle_reverse_lookup,
1157 NULL);
1158 }
1159 if (NULL != uri)
1160 {
1161 char sh[105];
1162 char sname[64];
1163 struct GNUNET_IDENTITY_PublicKey pkey;
1164
1165 memset (sh, 0, 105);
1166 memset (sname, 0, 64);
1167
1168 if ((2 != (sscanf (uri, "gnunet://gns/%58s/%63s", sh, sname))) ||
1169 (GNUNET_OK !=
1170 GNUNET_IDENTITY_public_key_from_string (sh, &pkey)))
1171 {
1172 fprintf (stderr, _ ("Invalid URI `%s'\n"), uri);
1173 GNUNET_SCHEDULER_shutdown ();
1174 ret = 1;
1175 return;
1176 }
1177 if (NULL == expirationstring)
1178 {
1179 fprintf (stderr,
1180 _ ("Missing option `%s' for operation `%s'\n"),
1181 "-e",
1182 _ ("add"));
1183 GNUNET_SCHEDULER_shutdown ();
1184 ret = 1;
1185 return;
1186 }
1187 if (GNUNET_OK != parse_expiration (expirationstring, &etime_is_rel, &etime))
1188 {
1189 fprintf (stderr, _ ("Invalid time format `%s'\n"), expirationstring);
1190 GNUNET_SCHEDULER_shutdown ();
1191 ret = 1;
1192 return;
1193 }
1194 memset (&rd, 0, sizeof(rd));
1195 rd.data = &pkey;
1196 rd.data_size = GNUNET_IDENTITY_key_get_length (&pkey);
1197 rd.record_type = ntohl (pkey.type);
1198 rd.expiration_time = etime;
1199 if (GNUNET_YES == etime_is_rel)
1200 rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1201 if (1 == is_shadow)
1202 rd.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
1203 add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
1204 &zone_pkey,
1205 sname,
1206 1,
1207 &rd,
1208 &add_continuation,
1209 &add_qe_uri);
1210 }
1211 if (monitor)
1212 {
1213 zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
1214 &zone_pkey,
1215 GNUNET_YES,
1216 &monitor_error_cb,
1217 NULL,
1218 &display_record_monitor,
1219 NULL,
1220 &sync_cb,
1221 NULL);
1222 }
1223}
1224
1225
1226/**
1227 * Callback invoked from identity service with ego information.
1228 * An @a ego of NULL means the ego was not found.
1229 *
1230 * @param cls closure with the configuration
1231 * @param ego an ego known to identity service, or NULL
1232 */
1233static void
1234identity_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego)
1235{
1236 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1237
1238 el = NULL;
1239
1240 if (NULL == ego)
1241 {
1242 if (NULL != ego_name)
1243 {
1244 fprintf (stderr,
1245 _ ("Ego `%s' not known to identity service\n"),
1246 ego_name);
1247 }
1248 GNUNET_SCHEDULER_shutdown ();
1249 ret = -1;
1250 return;
1251 }
1252 zone_pkey = *GNUNET_IDENTITY_ego_get_private_key (ego);
1253 GNUNET_free (ego_name);
1254 ego_name = NULL;
1255 run_with_zone_pkey (cfg);
1256}
1257
1258
1259/**
1260 * Function called with the default ego to be used for GNS
1261 * operations. Used if the user did not specify a zone via
1262 * command-line or environment variables.
1263 *
1264 * @param cls NULL
1265 * @param ego default ego, NULL for none
1266 * @param ctx NULL
1267 * @param name unused
1268 */
1269static void
1270default_ego_cb (void *cls,
1271 struct GNUNET_IDENTITY_Ego *ego,
1272 void **ctx,
1273 const char *name)
1274{
1275 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1276
1277 (void) ctx;
1278 (void) name;
1279 get_default = NULL;
1280 if (NULL == ego)
1281 {
1282 fprintf (stderr,
1283 _ ("No default identity configured for `namestore' subsystem\n"
1284 "Run gnunet-identity -s namestore -e $NAME to set the default to $NAME\n"
1285 "Run gnunet-identity -d to get a list of choices for $NAME\n"));
1286 GNUNET_SCHEDULER_shutdown ();
1287 ret = -1;
1288 return;
1289 }
1290 else
1291 {
1292 identity_cb ((void *) cfg, ego);
1293 }
1294}
1295
1296
1297/**
1298 * Function called with ALL of the egos known to the
1299 * identity service, used on startup if the user did
1300 * not specify a zone on the command-line.
1301 * Once the iteration is done (@a ego is NULL), we
1302 * ask for the default ego for "namestore".
1303 *
1304 * @param cls a `struct GNUNET_CONFIGURATION_Handle`
1305 * @param ego an ego, NULL for end of iteration
1306 * @param ctx NULL
1307 * @param name name associated with @a ego
1308 */
1309static void
1310id_connect_cb (void *cls,
1311 struct GNUNET_IDENTITY_Ego *ego,
1312 void **ctx,
1313 const char *name)
1314{
1315 const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
1316
1317 (void) ctx;
1318 (void) name;
1319 if (NULL != ego)
1320 return;
1321 get_default =
1322 GNUNET_IDENTITY_get (idh, "namestore", &default_ego_cb, (void *) cfg);
1323}
1324
1325
1326/**
1327 * Main function that will be run.
1328 *
1329 * @param cls closure
1330 * @param args remaining command-line arguments
1331 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1332 * @param cfg configuration
1333 */
1334static void
1335run (void *cls,
1336 char *const *args,
1337 const char *cfgfile,
1338 const struct GNUNET_CONFIGURATION_Handle *cfg)
1339{
1340 const char *pkey_str;
1341
1342 (void) cls;
1343 (void) args;
1344 (void) cfgfile;
1345 if (NULL != args[0])
1346 GNUNET_log (
1347 GNUNET_ERROR_TYPE_WARNING,
1348 _ ("Superfluous command line arguments (starting with `%s') ignored\n"),
1349 args[0]);
1350 if ((NULL != args[0]) && (NULL == uri))
1351 uri = GNUNET_strdup (args[0]);
1352
1353 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, (void *) cfg);
1354 pkey_str = getenv ("GNUNET_NAMESTORE_EGO_PRIVATE_KEY");
1355 if (NULL != pkey_str)
1356 {
1357 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (pkey_str,
1358 strlen (pkey_str),
1359 &zone_pkey,
1360 sizeof(zone_pkey)))
1361 {
1362 fprintf (stderr,
1363 "Malformed private key `%s' in $%s\n",
1364 pkey_str,
1365 "GNUNET_NAMESTORE_EGO_PRIVATE_KEY");
1366 ret = 1;
1367 GNUNET_SCHEDULER_shutdown ();
1368 return;
1369 }
1370 run_with_zone_pkey (cfg);
1371 return;
1372 }
1373 if (NULL == ego_name)
1374 {
1375 idh = GNUNET_IDENTITY_connect (cfg, &id_connect_cb, (void *) cfg);
1376 if (NULL == idh)
1377 fprintf (stderr, _ ("Cannot connect to identity service\n"));
1378 ret = -1;
1379 return;
1380 }
1381 el = GNUNET_IDENTITY_ego_lookup (cfg, ego_name, &identity_cb, (void *) cfg);
1382}
1383
1384
1385/**
1386 * Command-line option parser function that allows the user to specify
1387 * a complete record as one argument for adding/removing. A pointer
1388 * to the head of the list of record sets must be passed as the "scls"
1389 * argument.
1390 *
1391 * @param ctx command line processor context
1392 * @param scls must be of type "struct GNUNET_FS_Uri **"
1393 * @param option name of the option (typically 'R')
1394 * @param value command line argument given; format is
1395 * "TTL TYPE FLAGS VALUE" where TTL is an expiration time (rel or abs),
1396 * always given in seconds (without the unit),
1397 * TYPE is a DNS/GNS record type, FLAGS is either "n" for no flags or
1398 * a combination of 's' (shadow) and 'p' (public) and VALUE is the
1399 * value (in human-readable format)
1400 * @return #GNUNET_OK on success
1401 */
1402static int
1403multirecord_process (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
1404 void *scls,
1405 const char *option,
1406 const char *value)
1407{
1408 struct RecordSetEntry **head = scls;
1409 struct RecordSetEntry *r;
1410 struct GNUNET_GNSRECORD_Data record;
1411 char *cp;
1412 char *tok;
1413 char *saveptr;
1414 int etime_is_rel;
1415 void *raw_data;
1416
1417 (void) ctx;
1418 (void) option;
1419 cp = GNUNET_strdup (value);
1420 tok = strtok_r (cp, " ", &saveptr);
1421 if (NULL == tok)
1422 {
1423 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1424 _ ("Empty record line argument is not allowed.\n"));
1425 GNUNET_free (cp);
1426 return GNUNET_SYSERR;
1427 }
1428 {
1429 char *etime_in_s;
1430
1431 GNUNET_asprintf (&etime_in_s, "%s s", tok);
1432 if (GNUNET_OK !=
1433 parse_expiration (etime_in_s, &etime_is_rel, &record.expiration_time))
1434 {
1435 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1436 _ ("Invalid expiration time `%s' (must be without unit)\n"),
1437 tok);
1438 GNUNET_free (cp);
1439 GNUNET_free (etime_in_s);
1440 return GNUNET_SYSERR;
1441 }
1442 GNUNET_free (etime_in_s);
1443 }
1444 tok = strtok_r (NULL, " ", &saveptr);
1445 if (NULL == tok)
1446 {
1447 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1448 _ ("Missing entries in record line `%s'.\n"),
1449 value);
1450 GNUNET_free (cp);
1451 return GNUNET_SYSERR;
1452 }
1453 record.record_type = GNUNET_GNSRECORD_typename_to_number (tok);
1454 if (UINT32_MAX == record.record_type)
1455 {
1456 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _ ("Unknown record type `%s'\n"), tok);
1457 GNUNET_free (cp);
1458 return GNUNET_SYSERR;
1459 }
1460 tok = strtok_r (NULL, " ", &saveptr);
1461 if (NULL == tok)
1462 {
1463 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1464 _ ("Missing entries in record line `%s'.\n"),
1465 value);
1466 GNUNET_free (cp);
1467 return GNUNET_SYSERR;
1468 }
1469 record.flags = GNUNET_GNSRECORD_RF_NONE;
1470 if (etime_is_rel)
1471 record.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
1472 if (NULL == strchr (tok, (unsigned char) 'p')) /* p = public */
1473 record.flags |= GNUNET_GNSRECORD_RF_PRIVATE;
1474 if (NULL != strchr (tok, (unsigned char) 's'))
1475 record.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
1476 /* find beginning of record value */
1477 tok = strchr (&value[tok - cp], (unsigned char) ' ');
1478 if (NULL == tok)
1479 {
1480 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1481 _ ("Missing entries in record line `%s'.\n"),
1482 value);
1483 GNUNET_free (cp);
1484 return GNUNET_SYSERR;
1485 }
1486 GNUNET_free (cp);
1487 tok++; /* skip space */
1488 if (GNUNET_OK != GNUNET_GNSRECORD_string_to_value (record.record_type,
1489 tok,
1490 &raw_data,
1491 &record.data_size))
1492 {
1493 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1494 _ ("Invalid record data for type %s: `%s'.\n"),
1495 GNUNET_GNSRECORD_number_to_typename (record.record_type),
1496 tok);
1497 return GNUNET_SYSERR;
1498 }
1499
1500 r = GNUNET_malloc (sizeof(struct RecordSetEntry) + record.data_size);
1501 r->next = *head;
1502 record.data = &r[1];
1503 memcpy (&r[1], raw_data, record.data_size);
1504 GNUNET_free (raw_data);
1505 r->record = record;
1506 *head = r;
1507 return GNUNET_OK;
1508}
1509
1510
1511/**
1512 * Allow user to specify keywords.
1513 *
1514 * @param shortName short name of the option
1515 * @param name long name of the option
1516 * @param argumentHelp help text for the option argument
1517 * @param description long help text for the option
1518 * @param[out] topKeywords set to the desired value
1519 */
1520struct GNUNET_GETOPT_CommandLineOption
1521multirecord_option (char shortName,
1522 const char *name,
1523 const char *argumentHelp,
1524 const char *description,
1525 struct RecordSetEntry **rs)
1526{
1527 struct GNUNET_GETOPT_CommandLineOption clo = { .shortName = shortName,
1528 .name = name,
1529 .argumentHelp = argumentHelp,
1530 .description = description,
1531 .require_argument = 1,
1532 .processor =
1533 &multirecord_process,
1534 .scls = (void *) rs };
1535
1536 return clo;
1537}
1538
1539
1540/**
1541 * The main function for gnunet-namestore.
1542 *
1543 * @param argc number of arguments from the command line
1544 * @param argv command line arguments
1545 * @return 0 ok, 1 on error
1546 */
1547int
1548main (int argc, char *const *argv)
1549{
1550 struct GNUNET_GETOPT_CommandLineOption options[] =
1551 { GNUNET_GETOPT_option_flag ('a', "add", gettext_noop ("add record"), &add),
1552 GNUNET_GETOPT_option_flag ('d',
1553 "delete",
1554 gettext_noop ("delete record"),
1555 &del),
1556 GNUNET_GETOPT_option_flag ('D',
1557 "display",
1558 gettext_noop ("display records"),
1559 &list),
1560 GNUNET_GETOPT_option_string (
1561 'e',
1562 "expiration",
1563 "TIME",
1564 gettext_noop (
1565 "expiration time for record to use (for adding only), \"never\" is possible"),
1566 &expirationstring),
1567 GNUNET_GETOPT_option_string ('i',
1568 "nick",
1569 "NICKNAME",
1570 gettext_noop (
1571 "set the desired nick name for the zone"),
1572 &nickstring),
1573 GNUNET_GETOPT_option_flag ('m',
1574 "monitor",
1575 gettext_noop (
1576 "monitor changes in the namestore"),
1577 &monitor),
1578 GNUNET_GETOPT_option_string ('n',
1579 "name",
1580 "NAME",
1581 gettext_noop (
1582 "name of the record to add/delete/display"),
1583 &name),
1584 GNUNET_GETOPT_option_string ('r',
1585 "reverse",
1586 "PKEY",
1587 gettext_noop (
1588 "determine our name for the given PKEY"),
1589 &reverse_pkey),
1590 multirecord_option (
1591 'R',
1592 "replace",
1593 "RECORDLINE",
1594 gettext_noop (
1595 "set record set to values given by (possibly multiple) RECORDLINES; can be specified multiple times"),
1596 &recordset),
1597 GNUNET_GETOPT_option_string ('t',
1598 "type",
1599 "TYPE",
1600 gettext_noop (
1601 "type of the record to add/delete/display"),
1602 &typestring),
1603 GNUNET_GETOPT_option_string ('u',
1604 "uri",
1605 "URI",
1606 gettext_noop ("URI to import into our zone"),
1607 &uri),
1608 GNUNET_GETOPT_option_string ('V',
1609 "value",
1610 "VALUE",
1611 gettext_noop (
1612 "value of the record to add/delete"),
1613 &value),
1614 GNUNET_GETOPT_option_flag ('p',
1615 "public",
1616 gettext_noop ("create or list public record"),
1617 &is_public),
1618 GNUNET_GETOPT_option_flag (
1619 's',
1620 "shadow",
1621 gettext_noop (
1622 "create shadow record (only valid if all other records of the same type have expired"),
1623 &is_shadow),
1624 GNUNET_GETOPT_option_string ('z',
1625 "zone",
1626 "EGO",
1627 gettext_noop (
1628 "name of the ego controlling the zone"),
1629 &ego_name),
1630 GNUNET_GETOPT_OPTION_END };
1631 int lret;
1632
1633 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1634 return 2;
1635
1636 is_public = -1;
1637 is_shadow = -1;
1638 GNUNET_log_setup ("gnunet-namestore", "WARNING", NULL);
1639 if (GNUNET_OK !=
1640 (lret = GNUNET_PROGRAM_run (argc,
1641 argv,
1642 "gnunet-namestore",
1643 _ ("GNUnet zone manipulation tool"),
1644 options,
1645 &run,
1646 NULL)))
1647 {
1648 GNUNET_free_nz ((void *) argv);
1649 // FIXME
1650 // GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
1651 return lret;
1652 }
1653 GNUNET_free_nz ((void *) argv);
1654 // FIXME
1655 // GNUNET_CRYPTO_ecdsa_key_clear (&zone_pkey);
1656 return ret;
1657}
1658
1659
1660/* end of gnunet-namestore.c */