moved test files and fixed namestore
[oweals/gnunet.git] / src / identity / gnunet-identity.c
index 77ba6c2cd3ed5e8e5d727b4806ddec4bf4f4ab7c..0c3f9fead280e0ec3a8d6a9d4460d65ab6398f41 100644 (file)
 /*
      This file is part of GNUnet.
-     (C) 2013 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2013 GNUnet e.V.
 
-     GNUnet is free software; you can redistribute it and/or modify
-     it under the terms of the GNU General Public License as published
-     by the Free Software Foundation; either version 3, or (at your
-     option) any later version.
+     GNUnet is free software: you can redistribute it and/or modify it
+     under the terms of the GNU Affero General Public License as published
+     by the Free Software Foundation, either version 3 of the License,
+     or (at your option) any later version.
 
      GNUnet is distributed in the hope that it will be useful, but
      WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-     General Public License for more details.
-
-     You should have received a copy of the GNU General Public License
-     along with GNUnet; see the file COPYING.  If not, write to the
-     Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-     Boston, MA 02111-1307, USA.
+     Affero General Public License for more details.
+    
+     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/>.
 */
 /**
  * @file identity/gnunet-identity.c
- * @brief IDENTITY monitoring command line tool
+ * @brief IDENTITY management command line tool
  * @author Christian Grothoff
+ *
+ * Todo:
+ * - add options to get default egos
  */
 #include "platform.h"
 #include "gnunet_util_lib.h"
 #include "gnunet_identity_service.h"
 
+
+/**
+ * Return value from main on timeout.
+ */
+#define TIMEOUT_STATUS_CODE 40
+
 /**
  * Handle to IDENTITY service.
  */
 static struct GNUNET_IDENTITY_Handle *sh;
 
 /**
- * Was verbose specified?
+ * Was "list" specified?
+ */
+static int list;
+
+/**
+ * Was "monitor" specified?
+ */
+static int monitor;
+
+/**
+ * -C option
+ */
+static char *create_ego;
+
+/**
+ * -D option
+ */
+static char *delete_ego;
+
+/**
+ * -s option.
+ */
+static char *set_ego;
+
+/**
+ * -S option.
+ */
+static char *set_subsystem;
+
+/**
+ * Operation handle for set operation.
+ */
+static struct GNUNET_IDENTITY_Operation *set_op;
+
+/**
+ * Handle for create operation.
+ */
+static struct GNUNET_IDENTITY_Operation *create_op;
+
+/**
+ * Handle for delete operation.
+ */
+static struct GNUNET_IDENTITY_Operation *delete_op;
+
+/**
+ * Value to return from #main().
  */
-static int verbose;
+static int global_ret;
 
 
 /**
  * Task run on shutdown.
  *
  * @param cls NULL
- * @param tc unused
  */
 static void
-shutdown_task (void *cls,
-              const struct GNUNET_SCHEDULER_TaskContext *tc)
+shutdown_task (void *cls)
 {
+  if (NULL != set_op)
+  {
+    GNUNET_IDENTITY_cancel (set_op);
+    set_op = NULL;
+  }
+  if (NULL != create_op)
+  {
+    GNUNET_IDENTITY_cancel (create_op);
+    create_op = NULL;
+  }
+  if (NULL != delete_op)
+  {
+    GNUNET_IDENTITY_cancel (delete_op);
+    delete_op = NULL;
+  }
   GNUNET_IDENTITY_disconnect (sh);
   sh = NULL;
 }
 
 
+/**
+ * Test if we are finished yet.
+ */
+static void
+test_finished ()
+{
+  if ( (NULL == create_op) &&
+       (NULL == delete_op) &&
+       (NULL == set_op) &&
+       (NULL == set_ego) &&
+       (! list) &&
+       (! monitor) )
+  {
+    if (TIMEOUT_STATUS_CODE == global_ret)
+      global_ret = 0;
+    GNUNET_SCHEDULER_shutdown ();
+  }
+}
+
+
+/**
+ * Deletion operation finished.
+ *
+ * @param cls pointer to operation handle
+ * @param emsg NULL on success, otherwise an error message
+ */
+static void
+delete_finished (void *cls,
+                const char *emsg)
+{
+  struct GNUNET_IDENTITY_Operation **op = cls;
+
+  *op = NULL;
+  if (NULL != emsg)
+    fprintf (stderr,
+            "%s\n",
+            gettext (emsg));
+  test_finished ();
+}
+
+
+/**
+ * Creation operation finished.
+ *
+ * @param cls pointer to operation handle
+ * @param emsg error message, NULL on success
+ */
+static void
+create_finished (void *cls,
+                const char *emsg)
+{
+  struct GNUNET_IDENTITY_Operation **op = cls;
+
+  *op = NULL;
+  if (NULL != emsg)
+  {
+    fprintf (stderr,
+            _("Failed to create ego: %s\n"),
+            emsg);
+    global_ret = 1;
+  }
+  test_finished ();
+}
+
+
+/**
+ * Function called by #GNUNET_IDENTITY_set up on completion.
+ *
+ * @param cls NULL
+ * @param emsg error message (NULL on success)
+ */
+static void
+set_done (void *cls,
+         const char *emsg)
+{
+  set_op = NULL;
+  if (NULL != emsg)
+  {
+    fprintf (stderr,
+            _("Failed to set default ego: %s\n"),
+            emsg);
+    global_ret = 1;
+  }
+  test_finished ();
+}
+
+
+/**
+ * If listing is enabled, prints information about the egos.
+ *
+ * This function is initially called for all egos and then again
+ * whenever a ego's identifier changes or if it is deleted.  At the
+ * end of the initial pass over all egos, the function is once called
+ * with 'NULL' for 'ego'. That does NOT mean that the callback won't
+ * be invoked in the future or that there was an error.
+ *
+ * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
+ * this function is only called ONCE, and 'NULL' being passed in
+ * 'ego' does indicate an error (i.e. name is taken or no default
+ * value is known).  If 'ego' is non-NULL and if '*ctx'
+ * is set in those callbacks, the value WILL be passed to a subsequent
+ * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
+ * that one was not NULL).
+ *
+ * When an identity is renamed, this function is called with the
+ * (known) ego but the NEW identifier.
+ *
+ * When an identity is deleted, this function is called with the
+ * (known) ego and "NULL" for the 'identifier'.  In this case,
+ * the 'ego' is henceforth invalid (and the 'ctx' should also be
+ * cleaned up).
+ *
+ * @param cls closure
+ * @param ego ego handle
+ * @param ctx context for application to store data for this ego
+ *                 (during the lifetime of this process, initially NULL)
+ * @param identifier identifier assigned by the user for this ego,
+ *                   NULL if the user just deleted the ego and it
+ *                   must thus no longer be used
+*/
+static void
+print_ego (void *cls,
+          struct GNUNET_IDENTITY_Ego *ego,
+          void **ctx,
+          const char *identifier)
+{
+  struct GNUNET_CRYPTO_EcdsaPublicKey pk;
+  char *s;
+
+  if ( (NULL != set_ego) &&
+       (NULL != ego) &&
+       (NULL != identifier) &&
+       (0 == strcmp (identifier,
+                    set_ego)) )
+    {
+      set_op = GNUNET_IDENTITY_set (sh,
+                                   set_subsystem,
+                                   ego,
+                                   &set_done,
+                                   NULL);
+      GNUNET_free (set_subsystem);
+      set_subsystem = NULL;
+      GNUNET_free (set_ego);
+      set_ego = NULL;
+    }
+  if ( (NULL == ego) &&
+       (NULL != set_ego) )
+  {
+    fprintf (stderr,
+            "Could not set ego to `%s' for subsystem `%s', ego not known\n",
+            set_ego,
+            set_subsystem);
+    GNUNET_free (set_subsystem);
+    set_subsystem = NULL;
+    GNUNET_free (set_ego);
+    set_ego = NULL;
+  }
+  if ( (NULL == ego) && (! monitor) )
+  {
+    list = 0;
+    test_finished ();
+    return;
+  }
+  if (! (list | monitor))
+    return;
+  if (NULL == ego)
+    return;
+  GNUNET_IDENTITY_ego_get_public_key (ego,
+                                      &pk);
+  s = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
+  if ( (monitor) ||
+       (NULL != identifier) )
+    fprintf (stdout,
+             "%s - %s\n",
+             identifier,
+             s);
+  GNUNET_free (s);
+}
+
+
 /**
  * Main function that will be run by the scheduler.
  *
@@ -61,12 +306,34 @@ shutdown_task (void *cls,
  * @param cfg configuration
  */
 static void
-run (void *cls, char *const *args, const char *cfgfile,
+run (void *cls,
+     char *const *args,
+     const char *cfgfile,
      const struct GNUNET_CONFIGURATION_Handle *cfg)
 {
-  sh = GNUNET_IDENTITY_connect (cfg, NULL, NULL);
-  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
-                               &shutdown_task, NULL);
+  if ( (NULL == set_subsystem) ^
+       (NULL == set_ego) )
+  {
+    fprintf (stderr,
+            "Options -e and -s must always be specified together\n");
+    return;
+  }
+  sh = GNUNET_IDENTITY_connect (cfg,
+                                &print_ego,
+                                NULL);
+  if (NULL != delete_ego)
+    delete_op = GNUNET_IDENTITY_delete (sh,
+                                       delete_ego,
+                                       &delete_finished,
+                                       &delete_op);
+  if (NULL != create_ego)
+    create_op = GNUNET_IDENTITY_create (sh,
+                                       create_ego,
+                                       &create_finished,
+                                       &create_op);
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+                                 NULL);
+  test_finished ();
 }
 
 
@@ -80,27 +347,60 @@ run (void *cls, char *const *args, const char *cfgfile,
 int
 main (int argc, char *const *argv)
 {
-  int res;
+  struct GNUNET_GETOPT_CommandLineOption options[] = {
+    GNUNET_GETOPT_option_string ('C',
+                                 "create",
+                                 "NAME",
+                                 gettext_noop ("create ego NAME"),
+                                 &create_ego),
+
+    GNUNET_GETOPT_option_string ('D',
+                                 "delete",
+                                 "NAME",
+                                 gettext_noop ("delete ego NAME "),
+                                 &delete_ego),
+
+    GNUNET_GETOPT_option_flag ('d',
+                                  "display",
+                                  gettext_noop ("display all egos"),
+                                  &list),
+    
+    GNUNET_GETOPT_option_string ('e',
+                                 "ego",
+                                 "NAME",
+                                 gettext_noop ("set default identity to EGO for a subsystem SUBSYSTEM (use together with -s)"),
+                                 &set_ego),
+
+    GNUNET_GETOPT_option_flag ('m',
+                                  "monitor",
+                                  gettext_noop ("run in monitor mode egos"),
+                                  &monitor),
+
+    GNUNET_GETOPT_option_string ('s',
+                                 "set",
+                                 "SUBSYSTEM",
+                                 gettext_noop ("set default identity to EGO for a subsystem SUBSYSTEM (use together with -e)"),
+                                 &set_subsystem),
 
-  static const struct GNUNET_GETOPT_CommandLineOption options[] = {
-    {'V', "verbose", NULL,
-     gettext_noop ("verbose output"),
-     0, &GNUNET_GETOPT_set_one, &verbose},
     GNUNET_GETOPT_OPTION_END
   };
+  int res;
 
-  if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
-    return 2;
-
-  res = GNUNET_PROGRAM_run (argc, argv, "gnunet-identity",
-                           gettext_noop ("Print information about IDENTITY state"), 
+  if (GNUNET_OK !=
+      GNUNET_STRINGS_get_utf8_args (argc, argv,
+                                    &argc, &argv))
+    return 4;
+  global_ret = TIMEOUT_STATUS_CODE; /* timeout */
+  res = GNUNET_PROGRAM_run (argc, argv,
+                            "gnunet-identity",
+                           gettext_noop ("Maintain egos"),
                            options, &run,
                            NULL);
   GNUNET_free ((void *) argv);
 
   if (GNUNET_OK != res)
-    return 1;
-  return 0;
+    return 3;
+  return global_ret;
 }
 
 /* end of gnunet-identity.c */