Merge branch 'master' of ssh://gnunet.org/gnunet
[oweals/gnunet.git] / src / identity / gnunet-identity.c
index 6981b370924e641f03275d6dde960259abb7f658..9b66a1bc706aa81ccd8fdf9215ab1064c567701d 100644 (file)
@@ -1,6 +1,6 @@
 /*
      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
@@ -14,8 +14,8 @@
 
      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.
+     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+     Boston, MA 02110-1301, USA.
 */
 /**
  * @file identity/gnunet-identity.c
  * @author Christian Grothoff
  *
  * Todo:
- * - add options to get/set default egos
- * - print short hashes of egos when printing
+ * - 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.
  */
@@ -55,6 +60,21 @@ static char *create_ego;
  */
 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.
  */
@@ -65,23 +85,40 @@ static struct GNUNET_IDENTITY_Operation *create_op;
  */
 static struct GNUNET_IDENTITY_Operation *delete_op;
 
+/**
+ * Value to return from #main().
+ */
+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.
  */
@@ -90,9 +127,15 @@ test_finished ()
 {
   if ( (NULL == create_op) &&
        (NULL == delete_op) &&
+       (NULL == set_op) &&
+       (NULL == set_ego) &&
        (! list) &&
-       (! monitor) )  
+       (! monitor) )
+  {
+    if (TIMEOUT_STATUS_CODE == global_ret)
+      global_ret = 0;
     GNUNET_SCHEDULER_shutdown ();
+  }
 }
 
 
@@ -131,9 +174,34 @@ create_finished (void *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 ();
 }
 
@@ -152,11 +220,11 @@ create_finished (void *cls,
  * '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 
+ * 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.  
+ * (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,
@@ -176,16 +244,58 @@ print_ego (void *cls,
           struct GNUNET_IDENTITY_Ego *ego,
           void **ctx,
           const char *identifier)
-{  
-
-  if (! (list | monitor))
-    return;
+{
+  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) )
   {
-    GNUNET_SCHEDULER_shutdown ();
+    list = 0;
+    test_finished ();
     return;
   }
-  fprintf (stderr, "%s\n", identifier);
+  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);
 }
 
 
@@ -198,10 +308,21 @@ print_ego (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, &print_ego, 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,
@@ -212,8 +333,8 @@ run (void *cls, char *const *args, const char *cfgfile,
                                        create_ego,
                                        &create_finished,
                                        &create_op);
-  GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
-                               &shutdown_task, NULL);
+  GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
+                                 NULL);
   test_finished ();
 }
 
@@ -228,36 +349,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[] = {
-    {'C', "create", "NAME",
-     gettext_noop ("create ego NAME"),
-     1, &GNUNET_GETOPT_set_string, &create_ego},
-    {'D', "delete", "NAME",
-     gettext_noop ("delete ego NAME "),
-     1, &GNUNET_GETOPT_set_string, &delete_ego},
-    {'L', "list", NULL,
-     gettext_noop ("list all egos"),
-     0, &GNUNET_GETOPT_set_one, &list},
-    {'m', "monitor", NULL,
-     gettext_noop ("run in monitor mode egos"),
-     0, &GNUNET_GETOPT_set_one, &monitor},
     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 ("Maintain egos"), 
+  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 */