really make GNUNET_SCHEDULER_run_from_driver more graceful (must have been late)
[oweals/gnunet.git] / src / identity / gnunet-identity.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013 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 identity/gnunet-identity.c
22  * @brief IDENTITY management command line tool
23  * @author Christian Grothoff
24  *
25  * Todo:
26  * - add options to get default egos
27  */
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_identity_service.h"
31
32
33 /**
34  * Return value from main on timeout.
35  */
36 #define TIMEOUT_STATUS_CODE 40
37
38 /**
39  * Handle to IDENTITY service.
40  */
41 static struct GNUNET_IDENTITY_Handle *sh;
42
43 /**
44  * Was "list" specified?
45  */
46 static int list;
47
48 /**
49  * Was "monitor" specified?
50  */
51 static int monitor;
52
53 /**
54  * -C option
55  */
56 static char *create_ego;
57
58 /**
59  * -D option
60  */
61 static char *delete_ego;
62
63 /**
64  * -s option.
65  */
66 static char *set_ego;
67
68 /**
69  * -S option.
70  */
71 static char *set_subsystem;
72
73 /**
74  * Operation handle for set operation.
75  */
76 static struct GNUNET_IDENTITY_Operation *set_op;
77
78 /**
79  * Handle for create operation.
80  */
81 static struct GNUNET_IDENTITY_Operation *create_op;
82
83 /**
84  * Handle for delete operation.
85  */
86 static struct GNUNET_IDENTITY_Operation *delete_op;
87
88 /**
89  * Value to return from #main().
90  */
91 static int global_ret;
92
93
94 /**
95  * Task run on shutdown.
96  *
97  * @param cls NULL
98  */
99 static void
100 shutdown_task (void *cls)
101 {
102   if (NULL != set_op)
103   {
104     GNUNET_IDENTITY_cancel (set_op);
105     set_op = NULL;
106   }
107   if (NULL != create_op)
108   {
109     GNUNET_IDENTITY_cancel (create_op);
110     create_op = NULL;
111   }
112   if (NULL != delete_op)
113   {
114     GNUNET_IDENTITY_cancel (delete_op);
115     delete_op = NULL;
116   }
117   GNUNET_IDENTITY_disconnect (sh);
118   sh = NULL;
119 }
120
121
122 /**
123  * Test if we are finished yet.
124  */
125 static void
126 test_finished ()
127 {
128   if ( (NULL == create_op) &&
129        (NULL == delete_op) &&
130        (NULL == set_op) &&
131        (NULL == set_ego) &&
132        (! list) &&
133        (! monitor) )
134   {
135     if (TIMEOUT_STATUS_CODE == global_ret)
136       global_ret = 0;
137     GNUNET_SCHEDULER_shutdown ();
138   }
139 }
140
141
142 /**
143  * Deletion operation finished.
144  *
145  * @param cls pointer to operation handle
146  * @param emsg NULL on success, otherwise an error message
147  */
148 static void
149 delete_finished (void *cls,
150                  const char *emsg)
151 {
152   struct GNUNET_IDENTITY_Operation **op = cls;
153
154   *op = NULL;
155   if (NULL != emsg)
156     fprintf (stderr,
157              "%s\n",
158              gettext (emsg));
159   test_finished ();
160 }
161
162
163 /**
164  * Creation operation finished.
165  *
166  * @param cls pointer to operation handle
167  * @param emsg error message, NULL on success
168  */
169 static void
170 create_finished (void *cls,
171                  const char *emsg)
172 {
173   struct GNUNET_IDENTITY_Operation **op = cls;
174
175   *op = NULL;
176   if (NULL != emsg)
177   {
178     fprintf (stderr,
179              _("Failed to create ego: %s\n"),
180              emsg);
181     global_ret = 1;
182   }
183   test_finished ();
184 }
185
186
187 /**
188  * Function called by #GNUNET_IDENTITY_set up on completion.
189  *
190  * @param cls NULL
191  * @param emsg error message (NULL on success)
192  */
193 static void
194 set_done (void *cls,
195           const char *emsg)
196 {
197   set_op = NULL;
198   if (NULL != emsg)
199   {
200     fprintf (stderr,
201              _("Failed to set default ego: %s\n"),
202              emsg);
203     global_ret = 1;
204   }
205   test_finished ();
206 }
207
208
209 /**
210  * If listing is enabled, prints information about the egos.
211  *
212  * This function is initially called for all egos and then again
213  * whenever a ego's identifier changes or if it is deleted.  At the
214  * end of the initial pass over all egos, the function is once called
215  * with 'NULL' for 'ego'. That does NOT mean that the callback won't
216  * be invoked in the future or that there was an error.
217  *
218  * When used with 'GNUNET_IDENTITY_create' or 'GNUNET_IDENTITY_get',
219  * this function is only called ONCE, and 'NULL' being passed in
220  * 'ego' does indicate an error (i.e. name is taken or no default
221  * value is known).  If 'ego' is non-NULL and if '*ctx'
222  * is set in those callbacks, the value WILL be passed to a subsequent
223  * call to the identity callback of 'GNUNET_IDENTITY_connect' (if
224  * that one was not NULL).
225  *
226  * When an identity is renamed, this function is called with the
227  * (known) ego but the NEW identifier.
228  *
229  * When an identity is deleted, this function is called with the
230  * (known) ego and "NULL" for the 'identifier'.  In this case,
231  * the 'ego' is henceforth invalid (and the 'ctx' should also be
232  * cleaned up).
233  *
234  * @param cls closure
235  * @param ego ego handle
236  * @param ctx context for application to store data for this ego
237  *                 (during the lifetime of this process, initially NULL)
238  * @param identifier identifier assigned by the user for this ego,
239  *                   NULL if the user just deleted the ego and it
240  *                   must thus no longer be used
241 */
242 static void
243 print_ego (void *cls,
244            struct GNUNET_IDENTITY_Ego *ego,
245            void **ctx,
246            const char *identifier)
247 {
248   struct GNUNET_CRYPTO_EcdsaPublicKey pk;
249   char *s;
250
251   if ( (NULL != set_ego) &&
252        (NULL != ego) &&
253        (NULL != identifier) &&
254        (0 == strcmp (identifier,
255                      set_ego)) )
256     {
257       set_op = GNUNET_IDENTITY_set (sh,
258                                     set_subsystem,
259                                     ego,
260                                     &set_done,
261                                     NULL);
262       GNUNET_free (set_subsystem);
263       set_subsystem = NULL;
264       GNUNET_free (set_ego);
265       set_ego = NULL;
266     }
267   if ( (NULL == ego) &&
268        (NULL != set_ego) )
269   {
270     fprintf (stderr,
271              "Could not set ego to `%s' for subsystem `%s', ego not known\n",
272              set_ego,
273              set_subsystem);
274     GNUNET_free (set_subsystem);
275     set_subsystem = NULL;
276     GNUNET_free (set_ego);
277     set_ego = NULL;
278   }
279   if ( (NULL == ego) && (! monitor) )
280   {
281     list = 0;
282     test_finished ();
283     return;
284   }
285   if (! (list | monitor))
286     return;
287   if (NULL == ego)
288     return;
289   GNUNET_IDENTITY_ego_get_public_key (ego,
290                                       &pk);
291   s = GNUNET_CRYPTO_ecdsa_public_key_to_string (&pk);
292   if ( (monitor) ||
293        (NULL != identifier) )
294     fprintf (stdout,
295              "%s - %s\n",
296              identifier,
297              s);
298   GNUNET_free (s);
299 }
300
301
302 /**
303  * Main function that will be run by the scheduler.
304  *
305  * @param cls closure
306  * @param args remaining command-line arguments
307  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
308  * @param cfg configuration
309  */
310 static void
311 run (void *cls,
312      char *const *args,
313      const char *cfgfile,
314      const struct GNUNET_CONFIGURATION_Handle *cfg)
315 {
316   if ( (NULL == set_subsystem) ^
317        (NULL == set_ego) )
318   {
319     fprintf (stderr,
320              "Options -e and -s must always be specified together\n");
321     return;
322   }
323   sh = GNUNET_IDENTITY_connect (cfg,
324                                 &print_ego,
325                                 NULL);
326   if (NULL != delete_ego)
327     delete_op = GNUNET_IDENTITY_delete (sh,
328                                         delete_ego,
329                                         &delete_finished,
330                                         &delete_op);
331   if (NULL != create_ego)
332     create_op = GNUNET_IDENTITY_create (sh,
333                                         create_ego,
334                                         &create_finished,
335                                         &create_op);
336   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
337                                  NULL);
338   test_finished ();
339 }
340
341
342 /**
343  * The main function.
344  *
345  * @param argc number of arguments from the command line
346  * @param argv command line arguments
347  * @return 0 ok, 1 on error
348  */
349 int
350 main (int argc, char *const *argv)
351 {
352   struct GNUNET_GETOPT_CommandLineOption options[] = {
353     GNUNET_GETOPT_option_string ('C',
354                                  "create",
355                                  "NAME",
356                                  gettext_noop ("create ego NAME"),
357                                  &create_ego),
358
359     GNUNET_GETOPT_option_string ('D',
360                                  "delete",
361                                  "NAME",
362                                  gettext_noop ("delete ego NAME "),
363                                  &delete_ego),
364
365     GNUNET_GETOPT_option_flag ('d',
366                                   "display",
367                                   gettext_noop ("display all egos"),
368                                   &list),
369     
370     GNUNET_GETOPT_option_string ('e',
371                                  "ego",
372                                  "NAME",
373                                  gettext_noop ("set default identity to EGO for a subsystem SUBSYSTEM (use together with -s)"),
374                                  &set_ego),
375
376     GNUNET_GETOPT_option_flag ('m',
377                                   "monitor",
378                                   gettext_noop ("run in monitor mode egos"),
379                                   &monitor),
380
381     GNUNET_GETOPT_option_string ('s',
382                                  "set",
383                                  "SUBSYSTEM",
384                                  gettext_noop ("set default identity to EGO for a subsystem SUBSYSTEM (use together with -e)"),
385                                  &set_subsystem),
386
387     GNUNET_GETOPT_OPTION_END
388   };
389   int res;
390
391   if (GNUNET_OK !=
392       GNUNET_STRINGS_get_utf8_args (argc, argv,
393                                     &argc, &argv))
394     return 4;
395   global_ret = TIMEOUT_STATUS_CODE; /* timeout */
396   res = GNUNET_PROGRAM_run (argc, argv,
397                             "gnunet-identity",
398                             gettext_noop ("Maintain egos"),
399                             options, &run,
400                             NULL);
401   GNUNET_free ((void *) argv);
402
403   if (GNUNET_OK != res)
404     return 3;
405   return global_ret;
406 }
407
408 /* end of gnunet-identity.c */