NAMESTORE/JSON: fix parsing exp and flags
[oweals/gnunet.git] / src / namestore / gnunet-namestore.c
index 619d0c52854ad480eeffa67504344b269b224f7c..470716f43afc6e779081ca4a9d76f7ffbf21fe75 100644 (file)
@@ -14,6 +14,8 @@
     
      You should have received a copy of the GNU Affero General Public License
      along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+     SPDX-License-Identifier: AGPL3.0-or-later
 */
 /**
  * @file gnunet-namestore.c
@@ -135,6 +137,11 @@ static int is_shadow;
  */
 static struct GNUNET_NAMESTORE_QueueEntry *del_qe;
 
+/**
+ * Queue entry for the 'set/replace' operation.
+ */
+static struct GNUNET_NAMESTORE_QueueEntry *set_qe;
+
 /**
  * Name of the records to add/list/remove.
  */
@@ -195,7 +202,6 @@ static size_t data_size;
  */
 static uint64_t etime;
 
-
 /**
  * Is expiration time relative or absolute time?
  */
@@ -251,6 +257,11 @@ do_shutdown (void *cls)
     GNUNET_NAMESTORE_cancel (add_qe);
     add_qe = NULL;
   }
+  if (NULL != set_qe)
+  {
+    GNUNET_NAMESTORE_cancel (set_qe);
+    set_qe = NULL;
+  }
   if (NULL != add_qe_uri)
   {
     GNUNET_NAMESTORE_cancel (add_qe_uri);
@@ -930,43 +941,34 @@ parse_expiration (const char *expirationstring,
 }
 
 
-#if 0
-/* globals? */
-unsigned int rd_count;
-struct GNUNET_GNSRECORD_Data *rd;
-
-
-rd_count = 0;
-for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
-  rd_count++;
-rd = GNUNET_new_array (rd_count,
-                      struct GNUNET_GNSRECORD_Data);
-rd_count = 0;
-for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
+/**
+ * Function called when namestore is done with the replace
+ * operation.
+ *
+ * @param cls NULL
+ * @param success #GNUNET_SYSERR on failure (including timeout/queue drop/failure to validate)
+ *                #GNUNET_NO if content was already there or not found
+ *                #GNUNET_YES (or other positive value) on success
+ * @param emsg NULL on success, otherwise an error message
+ */
+static void
+replace_cont (void *cls,
+             int success,
+             const char *emsg)
 {
-  rd[rd_count] = e->record;
-  rd_count++;
+  (void) cls;
+  
+  set_qe = NULL;
+  if (GNUNET_OK != success)
+  {
+    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+               _("Failed to replace records: %s\n"),
+               emsg);
+    ret = 1; /* fail from 'main' */
+  }
+  GNUNET_SCHEDULER_shutdown ();
 }
 
-/* if add: */
-qe = GNUNET_NAMESTORE_records_store (...,
-                               rd_count,
-                               rd,
-                               &my_cont
-                               ..);
-
-in 'my_cont' and/or shutdown:
-
-qe = NULL;
-GNUNET_free (rd);
-
-in shutdown:
-
-if NULL != qe  NAMESTORE_cancel (qe);
-GNUNET_free (rd);
-
-#endif
-
 
 /**
  * Callback invoked from identity service with ego information.
@@ -1000,7 +1002,7 @@ identity_cb (void *cls,
   GNUNET_free_non_null (ego_name);
   ego_name = NULL;
 
-  if (! (add|del|list|(NULL != nickstring)|(NULL != uri)|(NULL != reverse_pkey)) )
+  if (! (add|del|list|(NULL != nickstring)|(NULL != uri)|(NULL != reverse_pkey)|(NULL != recordset)) )
   {
     /* nothing more to be done */
     fprintf (stderr,
@@ -1009,8 +1011,7 @@ identity_cb (void *cls,
     return;
   }
   GNUNET_CRYPTO_ecdsa_key_get_public (&zone_pkey,
-                                    &pub);
-
+                                     &pub);
   ns = GNUNET_NAMESTORE_connect (cfg);
   if (NULL == ns)
   {
@@ -1018,6 +1019,44 @@ identity_cb (void *cls,
                 _("Failed to connect to namestore\n"));
     return;
   }
+
+  if (NULL != recordset)
+  {
+    /* replace entire record set */
+    unsigned int rd_count;
+    struct GNUNET_GNSRECORD_Data *rd;
+
+    if (NULL == name)
+    {
+      fprintf (stderr,
+               _("Missing option `%s' for operation `%s'\n"),
+               "-R", _("replace"));
+      GNUNET_SCHEDULER_shutdown ();
+      ret = 1;
+      return;
+    }
+    rd_count = 0;
+    for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
+      rd_count++;
+    rd = GNUNET_new_array (rd_count,
+                          struct GNUNET_GNSRECORD_Data);
+    rd_count = 0;
+    for (struct RecordSetEntry *e = recordset; NULL != e; e = e->next)
+    {
+      rd[rd_count] = e->record;
+      rd_count++;
+    }
+    set_qe = GNUNET_NAMESTORE_records_store (ns,
+                                            &zone_pkey,
+                                            name,
+                                            rd_count,
+                                            rd,
+                                            &replace_cont,
+                                            NULL);
+    GNUNET_free (rd);
+    return;
+  }
+  
   if (add)
   {
     if (NULL == name)
@@ -1297,6 +1336,10 @@ run (void *cls,
   (void) cls;
   (void) args;
   (void) cfgfile;
+  if (NULL != args[0])
+    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+               _("Superfluous command line arguments (starting with `%s') ignored\n"),
+               args[0]);
   if ( (NULL != args[0]) &&
        (NULL == uri) )
     uri = GNUNET_strdup (args[0]);
@@ -1333,6 +1376,7 @@ run (void *cls,
  * @param option name of the option (typically 'R')
  * @param value command line argument given; format is
  *        "TTL TYPE FLAGS VALUE" where TTL is an expiration time (rel or abs),
+ *        always given in seconds (without the unit),
  *         TYPE is a DNS/GNS record type, FLAGS is either "n" for no flags or
  *         a combination of 's' (shadow) and 'p' (public) and VALUE is the 
  *         value (in human-readable format)
@@ -1349,35 +1393,45 @@ multirecord_process (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
   struct GNUNET_GNSRECORD_Data record;
   char *cp;
   char *tok;
+  char *saveptr;
   int etime_is_rel;
   void *raw_data;
 
   (void) ctx;
   (void) option;
   cp = GNUNET_strdup (value);
-  tok = strtok (cp, " ");
+  tok = strtok_r (cp, " ", &saveptr);
   if (NULL == tok)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Empty record line argument is not allowed.\n"));
     GNUNET_free (cp);
     return GNUNET_SYSERR;
   }
-  if (GNUNET_OK !=
-      parse_expiration (tok,
-                       &etime_is_rel,
-                       &record.expiration_time))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
-               _("Invalid expiration time `%s'\n"),
-               tok);
-    GNUNET_free (cp);
-    return GNUNET_SYSERR;
+    char *etime_in_s;
+
+    GNUNET_asprintf (&etime_in_s,
+                    "%s s",
+                    tok);
+    if (GNUNET_OK !=
+       parse_expiration (etime_in_s,
+                         &etime_is_rel,
+                         &record.expiration_time))
+    {
+      GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+                 _("Invalid expiration time `%s' (must be without unit)\n"),
+                 tok);
+      GNUNET_free (cp);
+      GNUNET_free (etime_in_s);
+      return GNUNET_SYSERR;
+    }
+    GNUNET_free (etime_in_s);
   }
-  tok = strtok (NULL, " ");
+  tok = strtok_r (NULL, " ", &saveptr);
   if (NULL == tok)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Missing entries in record line `%s'.\n"),
                value);
     GNUNET_free (cp);
@@ -1386,16 +1440,16 @@ multirecord_process (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
   record.record_type = GNUNET_GNSRECORD_typename_to_number (tok);
   if (UINT32_MAX == record.record_type)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Unknown record type `%s'\n"),
                tok);
     GNUNET_free (cp);
     return GNUNET_SYSERR;
   }
-  tok = strtok (NULL, " ");
+  tok = strtok_r (NULL, " ", &saveptr);
   if (NULL == tok)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Missing entries in record line `%s'.\n"),
                value);
     GNUNET_free (cp);
@@ -1412,7 +1466,7 @@ multirecord_process (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
   tok = strchr (&value[tok - cp], (unsigned char) ' ');
   if (NULL == tok)
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Missing entries in record line `%s'.\n"),
                value);
     GNUNET_free (cp);
@@ -1426,7 +1480,7 @@ multirecord_process (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx,
                                        &raw_data,
                                        &record.data_size))
   {
-    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Invalid record data for type %s: `%s'.\n"),
                GNUNET_GNSRECORD_number_to_typename (record.record_type),               
                tok);
@@ -1526,9 +1580,9 @@ main (int argc,
                                  gettext_noop ("determine our name for the given PKEY"),
                                  &reverse_pkey),
     multirecord_option ('R',
-                       "record",
+                       "replace",
                        "RECORDLINE",
-                       gettext_noop ("complete record on one line to add/delete/display; can be specified multiple times"),
+                       gettext_noop ("set record set to values given by (possibly multiple) RECORDLINES; can be specified multiple times"),
                        &recordset),
     GNUNET_GETOPT_option_string ('t',
                                  "type",