-fix options for gnunet-gns
[oweals/gnunet.git] / src / gns / gnunet-gns.c
1 /*
2      This file is part of GNUnet.
3      (C) 2012 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20 /**
21  * @file gnunet-gns.c
22  * @brief command line tool to access distributed GNS
23  * @author Christian Grothoff
24  *
25  */
26 #include "platform.h"
27 #include <gnunet_util_lib.h>
28 #include <gnunet_dnsparser_lib.h>
29 #include <gnunet_namestore_service.h>
30 #include <gnunet_gns_service.h>
31
32 /**
33  * Handle to GNS service.
34  */
35 static struct GNUNET_GNS_Handle *gns;
36
37 /**
38  * GNS name to shorten. (-s option)
39  */
40 static char *shorten_name;
41
42 /**
43  * GNS name to lookup. (-u option)
44  */
45 static char *lookup_name;
46
47 /**
48  * record type to look up (-t option)
49  */
50 static char *lookup_type;
51
52 /**
53  * name to look up authority for (-a option)
54  */
55 static char *auth_name;
56
57 /**
58  * raw output
59  */
60 static int raw;
61
62 /**
63  * Requested record type.
64  */
65 static enum GNUNET_GNS_RecordType rtype;
66
67 /**
68  * Handle to lookup request 
69  */
70 static struct GNUNET_GNS_LookupRequest *lookup_request;
71
72 /**
73  * Handle to shorten request 
74  */
75 static struct GNUNET_GNS_ShortenRequest *shorten_request;
76
77 /**
78  * Handle to get authority request
79  */
80 static struct GNUNET_GNS_GetAuthRequest *getauth_request;
81
82
83 /**
84  * Task run on shutdown.  Cleans up everything.
85  *
86  * @param cls unused
87  * @param tc scheduler context
88  */
89 static void
90 do_shutdown (void *cls,
91              const struct GNUNET_SCHEDULER_TaskContext *tc)
92 {
93   if (NULL != lookup_request)
94   {
95     GNUNET_GNS_cancel_lookup_request (lookup_request);
96     lookup_request = NULL;
97   }
98   if (NULL != shorten_request)
99   {
100     GNUNET_GNS_cancel_shorten_request (shorten_request);
101     shorten_request = NULL;
102   }
103   if (NULL != getauth_request)
104   {
105     GNUNET_GNS_cancel_get_auth_request (getauth_request);
106     getauth_request = NULL;
107   }
108   if (NULL != gns)
109   {
110     GNUNET_GNS_disconnect (gns);
111     gns = NULL;
112   }
113 }
114
115
116 /**
117  * Function called with the result of a shorten operation.
118  * Prints the result.
119  *
120  * @param cls a 'const char *' with the original (long) name
121  * @param nshort the shortened name
122  */
123 static void
124 process_shorten_result (void* cls, const char *nshort)
125 {
126   const char *original_name = cls;
127
128   shorten_request = NULL;
129   if (raw)
130     printf("%s", nshort);
131   else
132     printf("%s shortened to %s\n", original_name, nshort);
133   GNUNET_SCHEDULER_shutdown ();
134 }
135
136
137 /**
138  * Function called with the result of a GADS lookup.
139  *
140  * @param cls the 'const char *' name that was resolved
141  * @param rd_count number of records returned
142  * @param rd array of 'rd_count' records with the results
143  */
144 static void
145 process_lookup_result (void* cls, uint32_t rd_count,
146                        const struct GNUNET_NAMESTORE_RecordData *rd)
147 {
148   const char* name = cls;
149   uint32_t i;
150   const char* typename;
151   char* string_val;
152
153   lookup_request = NULL; 
154   if (!raw) 
155   {
156     if (0 == rd_count)
157       printf("No results.\n");
158     else
159       printf("%s:\n", name);
160   }
161   for (i=0; i<rd_count; i++)
162   {
163     typename = GNUNET_NAMESTORE_number_to_typename (rd[i].record_type);
164     string_val = GNUNET_NAMESTORE_value_to_string (rd[i].record_type,
165                                                    rd[i].data,
166                                                    rd[i].data_size);
167     if (raw)
168       printf ("%s\n", string_val);
169     else
170       printf ("Got `%s' record: %s\n", typename, string_val);
171     GNUNET_free_non_null (string_val);
172   }
173   GNUNET_SCHEDULER_shutdown ();
174 }
175
176
177 /**
178  * Function called with the result of an authority lookup.
179  *
180  * @param cls the 'const char *' with the name for which the
181  *            authority was resolved
182  * @param auth name of the authority
183  */
184 static void
185 process_auth_result (void* cls, 
186                      const char *auth)
187 {
188   getauth_request = NULL;
189   printf ("%s\n", auth);
190   GNUNET_SCHEDULER_shutdown ();
191 }
192
193
194 /**
195  * Main function that will be run.
196  *
197  * @param cls closure
198  * @param args remaining command-line arguments
199  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
200  * @param cfg configuration
201  */
202 static void
203 run (void *cls, char *const *args, const char *cfgfile,
204      const struct GNUNET_CONFIGURATION_Handle *cfg)
205 {
206   char* keyfile;
207   struct GNUNET_CRYPTO_RsaPrivateKey *key = NULL;
208   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pkey;
209   struct GNUNET_CRYPTO_ShortHashCode *zone = NULL;
210   struct GNUNET_CRYPTO_ShortHashCode user_zone;
211   struct GNUNET_CRYPTO_ShortHashAsciiEncoded zonename;
212   struct GNUNET_CRYPTO_RsaPrivateKey *shorten_key = NULL;
213   struct GNUNET_CRYPTO_RsaPrivateKey *private_key = NULL;
214   struct GNUNET_CRYPTO_ShortHashCode *private_zone = NULL;
215   struct GNUNET_CRYPTO_ShortHashCode *shorten_zone = NULL;
216
217   gns = GNUNET_GNS_connect (cfg);
218   if (NULL == gns)
219   {
220     fprintf (stderr,
221              _("Failed to connect to GNS\n"));
222     return;
223   }
224   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
225                                                            "ZONEKEY", &keyfile))
226   {
227     if (! raw)
228       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
229                   "No private key for root zone found, using default!\n");
230   }
231   else
232   {
233     key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
234     GNUNET_CRYPTO_rsa_key_get_public (key, &pkey);
235     GNUNET_CRYPTO_short_hash (&pkey,
236                               sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
237                               &user_zone);
238     zone = &user_zone;
239     GNUNET_CRYPTO_short_hash_to_enc (zone, &zonename);
240     if (!raw)
241       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
242                   "Using zone: %s!\n", &zonename);
243     GNUNET_CRYPTO_rsa_key_free (key);  
244     GNUNET_free(keyfile);
245   }
246   
247   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
248                                                             "SHORTEN_ZONEKEY", &keyfile))
249   {
250     if (! raw)
251       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
252                   "No shorten key found!\n");
253   }
254   else
255   {
256     shorten_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
257     GNUNET_CRYPTO_rsa_key_get_public (shorten_key, &pkey);
258     shorten_zone = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_ShortHashCode));
259     GNUNET_CRYPTO_short_hash(&pkey,
260                              sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
261                              shorten_zone);
262     GNUNET_CRYPTO_short_hash_to_enc (shorten_zone, &zonename);
263     if (! raw)
264       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
265                   "Using shorten zone: %s!\n", &zonename);
266     GNUNET_free (keyfile);
267   }
268     
269   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "gns",
270                                                             "PRIVATE_ZONEKEY", &keyfile))
271   {
272     if (! raw)
273       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
274                   "No private zone key file name specified in configuration!\n");
275   }
276   else
277   {
278     private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
279     GNUNET_CRYPTO_rsa_key_get_public (private_key, &pkey);
280     private_zone = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_ShortHashCode));
281     GNUNET_CRYPTO_short_hash(&pkey,
282                              sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
283                              private_zone);
284     GNUNET_CRYPTO_short_hash_to_enc (private_zone, &zonename);
285     if (! raw)
286       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
287                   "Using private zone: %s!\n", &zonename);
288     GNUNET_CRYPTO_rsa_key_free (private_key);
289   }
290   
291   if (NULL != lookup_type)
292     rtype = GNUNET_NAMESTORE_typename_to_number (lookup_type);
293   else
294     rtype = GNUNET_GNS_RECORD_A;
295
296   if ( (NULL != shorten_name) && 
297        (NULL != shorten_zone) && 
298        (NULL != private_zone) )
299   {
300     shorten_request = GNUNET_GNS_shorten_zone (gns, shorten_name,
301                                                private_zone,
302                                                shorten_zone,
303                                                zone,
304                                                &process_shorten_result,
305                                                shorten_name);
306   }
307   if (NULL != lookup_name)
308   {
309     lookup_request = GNUNET_GNS_lookup_zone (gns, lookup_name,
310                                              zone,
311                                              rtype,
312                                              GNUNET_NO, /* Use DHT */
313                                              shorten_key,
314                                              &process_lookup_result, 
315                                              lookup_name);
316   }
317   if (NULL != auth_name)
318   {
319     getauth_request = GNUNET_GNS_get_authority (gns, auth_name,
320                                                 &process_auth_result, auth_name);
321   }
322
323   if (NULL != shorten_key)
324     GNUNET_CRYPTO_rsa_key_free (shorten_key);
325   if (NULL != shorten_zone)
326     GNUNET_free (shorten_zone);
327   if (NULL != private_zone)
328     GNUNET_free (private_zone);
329   
330   if ( (NULL == auth_name) &&
331        (NULL == shorten_name) &&
332        (NULL == lookup_name))
333   {
334     fprintf (stderr,
335              _("Please specify lookup, shorten or authority operation!\n"));
336     GNUNET_SCHEDULER_add_now (&do_shutdown, NULL);
337     return;
338   }
339   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
340                                 &do_shutdown, NULL);
341 }
342
343
344 /**
345  * The main function for gnunet-gns.
346  *
347  * @param argc number of arguments from the command line
348  * @param argv command line arguments
349  * @return 0 ok, 1 on error
350  */
351 int
352 main (int argc, char *const *argv)
353 {
354   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
355     {'s', "shorten", "NAME",
356      gettext_noop ("try to shorten a given name"), 1,
357      &GNUNET_GETOPT_set_string, &shorten_name},
358     {'u', "lookup", "NAME",
359       gettext_noop ("Lookup a record for the given name"), 1,
360       &GNUNET_GETOPT_set_string, &lookup_name},
361     {'a', "authority", "NAME",
362       gettext_noop ("Get the authority of a particular name"), 1,
363       &GNUNET_GETOPT_set_string, &auth_name},
364     {'t', "type", "TYPE",
365       gettext_noop ("Specify the type of the record to lookup"), 1,
366       &GNUNET_GETOPT_set_string, &lookup_type},
367     {'r', "raw", NULL,
368       gettext_noop ("No unneeded output"), 0,
369       &GNUNET_GETOPT_set_one, &raw},
370     GNUNET_GETOPT_OPTION_END
371   };
372   int ret;
373
374   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
375     return 2;
376
377   GNUNET_log_setup ("gnunet-gns", "WARNING", NULL);
378   ret =
379       (GNUNET_OK ==
380        GNUNET_PROGRAM_run (argc, argv, "gnunet-gns",
381                            _("GNUnet GNS access tool"), 
382                            options,
383                            &run, NULL)) ? 0 : 1;
384   GNUNET_free ((void*) argv);
385   return ret;
386 }
387
388 /* end of gnunet-gns.c */