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