adding man page for gnunet-auto-share, updating man page for gnunet-publish
[oweals/gnunet.git] / src / fs / gnunet-download.c
1 /*
2      This file is part of GNUnet.
3      (C) 2001, 2002, 2004, 2005, 2006, 2007, 2009 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 fs/gnunet-download.c
22  * @brief downloading for files on GNUnet
23  * @author Christian Grothoff
24  * @author Krista Bennett
25  * @author James Blackwell
26  * @author Igor Wronsky
27  */
28 #include "platform.h"
29 #include "gnunet_fs_service.h"
30
31 static int ret;
32
33 static int verbose;
34
35 static int delete_incomplete;
36
37 static const struct GNUNET_CONFIGURATION_Handle *cfg;
38
39 static struct GNUNET_FS_Handle *ctx;
40
41 static struct GNUNET_FS_DownloadContext *dc;
42
43 static unsigned int anonymity = 1;
44
45 static unsigned int parallelism = 16;
46
47 static unsigned int request_parallelism = 4092;
48
49 static int do_recursive;
50
51 static char *filename;
52
53 static int local_only;
54
55 static void
56 cleanup_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
57 {
58   GNUNET_FS_stop (ctx);
59   ctx = NULL;
60 }
61
62
63 static void
64 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
65 {
66   struct GNUNET_FS_DownloadContext *d;
67
68   if (dc != NULL)
69   {
70     d = dc;
71     dc = NULL;
72     GNUNET_FS_download_stop (d, delete_incomplete);
73   }
74 }
75
76
77 /**
78  * Display progress bar (if tty).
79  *
80  * @param x current position in the download
81  * @param n total size of the download
82  * @param w desired number of steps in the progress bar
83  */
84 static void 
85 display_bar (unsigned long long x, 
86              unsigned long long n, 
87              unsigned int w)
88 {
89   char buf[w + 20];
90   unsigned int p;
91   unsigned int endeq;
92   float ratio_complete;
93
94 #if !WINDOWS
95   if (0 == isatty (1))
96     return;
97 #else
98   if (FILE_TYPE_CHAR != GetFileType (GetStdHandle (STD_OUTPUT_HANDLE)))
99     return;
100 #endif
101   ratio_complete = x/(float)n;
102   endeq = ratio_complete * w;
103   GNUNET_snprintf (buf, sizeof (buf),
104                    "%3d%% [", (int)(ratio_complete*100) );
105   for (p=0; p<endeq; p++)
106     strcat (buf, "=");
107   for (p=endeq; p<w; p++)
108     strcat (buf, " ");
109   strcat (buf, "]\r");
110   printf ("%s", buf);
111   fflush(stdout);
112 }
113
114
115 /**
116  * Called by FS client to give information about the progress of an
117  * operation.
118  *
119  * @param cls closure
120  * @param info details about the event, specifying the event type
121  *        and various bits about the event
122  * @return client-context (for the next progress call
123  *         for this operation; should be set to NULL for
124  *         SUSPEND and STOPPED events).  The value returned
125  *         will be passed to future callbacks in the respective
126  *         field in the GNUNET_FS_ProgressInfo struct.
127  */
128 static void *
129 progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info)
130 {
131   char *s;
132   char *s2;
133   char *t;
134
135   switch (info->status)
136   {
137   case GNUNET_FS_STATUS_DOWNLOAD_START:
138     if (verbose > 1)
139       FPRINTF (stderr, _("Starting download `%s'.\n"),
140                info->value.download.filename);
141     break;
142   case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
143     if (verbose)
144     {
145       s = GNUNET_STRINGS_relative_time_to_string (info->value.download.eta);
146       if (info->value.download.specifics.progress.block_download_duration.rel_value 
147           == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
148         s2 = GNUNET_strdup (_("<unknown time>"));
149       else
150         s2 = GNUNET_STRINGS_relative_time_to_string (
151               info->value.download.specifics.progress.block_download_duration);
152       t = GNUNET_STRINGS_byte_size_fancy (info->value.download.completed *
153                                           1000LL /
154                                           (info->value.download.
155                                            duration.rel_value + 1));
156       FPRINTF (stdout,
157                _("Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to download\n"),
158                info->value.download.filename,
159                (unsigned long long) info->value.download.completed,
160                (unsigned long long) info->value.download.size, s, t, s2);
161       GNUNET_free (s);
162       GNUNET_free (s2);
163       GNUNET_free (t);
164     }
165     else
166     {
167       display_bar (info->value.download.completed,
168                    info->value.download.size,
169                    60);
170     }
171     break;
172   case GNUNET_FS_STATUS_DOWNLOAD_ERROR:
173     FPRINTF (stderr, _("Error downloading: %s.\n"),
174              info->value.download.specifics.error.message);
175     GNUNET_SCHEDULER_shutdown ();
176     break;
177   case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED:
178     s = GNUNET_STRINGS_byte_size_fancy (info->value.download.completed * 1000 /
179                                         (info->value.download.
180                                          duration.rel_value + 1));
181     FPRINTF (stdout, _("Downloading `%s' done (%s/s).\n"),
182              info->value.download.filename, s);
183     GNUNET_free (s);
184     if (info->value.download.dc == dc)
185       GNUNET_SCHEDULER_shutdown ();
186     break;
187   case GNUNET_FS_STATUS_DOWNLOAD_STOPPED:
188     if (info->value.download.dc == dc)
189       GNUNET_SCHEDULER_add_continuation (&cleanup_task, NULL,
190                                          GNUNET_SCHEDULER_REASON_PREREQ_DONE);
191     break;
192   case GNUNET_FS_STATUS_DOWNLOAD_ACTIVE:
193   case GNUNET_FS_STATUS_DOWNLOAD_INACTIVE:
194     break;
195   default:
196     FPRINTF (stderr, _("Unexpected status: %d\n"), info->status);
197     break;
198   }
199   return NULL;
200 }
201
202
203 /**
204  * Main function that will be run by the scheduler.
205  *
206  * @param cls closure
207  * @param args remaining command-line arguments
208  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
209  * @param c configuration
210  */
211 static void
212 run (void *cls, char *const *args, const char *cfgfile,
213      const struct GNUNET_CONFIGURATION_Handle *c)
214 {
215   struct GNUNET_FS_Uri *uri;
216   char *emsg;
217   enum GNUNET_FS_DownloadOptions options;
218
219   if (NULL == args[0])
220   {
221     FPRINTF (stderr, "%s",  _("You need to specify a URI argument.\n"));
222     return;
223   }
224   uri = GNUNET_FS_uri_parse (args[0], &emsg);
225   if (NULL == uri)
226   {
227     FPRINTF (stderr, _("Failed to parse URI: %s\n"), emsg);
228     GNUNET_free (emsg);
229     ret = 1;
230     return;
231   }
232   if ((!GNUNET_FS_uri_test_chk (uri)) && (!GNUNET_FS_uri_test_loc (uri)))
233   {
234     FPRINTF (stderr, "%s",  _("Only CHK or LOC URIs supported.\n"));
235     ret = 1;
236     GNUNET_FS_uri_destroy (uri);
237     return;
238   }
239   if (NULL == filename)
240   {
241     FPRINTF (stderr, "%s",  _("Target filename must be specified.\n"));
242     ret = 1;
243     GNUNET_FS_uri_destroy (uri);
244     return;
245   }
246   cfg = c;
247   ctx =
248       GNUNET_FS_start (cfg, "gnunet-download", &progress_cb, NULL,
249                        GNUNET_FS_FLAGS_NONE,
250                        GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM, parallelism,
251                        GNUNET_FS_OPTIONS_REQUEST_PARALLELISM,
252                        request_parallelism, GNUNET_FS_OPTIONS_END);
253   if (NULL == ctx)
254   {
255     FPRINTF (stderr, _("Could not initialize `%s' subsystem.\n"), "FS");
256     GNUNET_FS_uri_destroy (uri);
257     ret = 1;
258     return;
259   }
260   options = GNUNET_FS_DOWNLOAD_OPTION_NONE;
261   if (do_recursive)
262     options |= GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE;
263   if (local_only)
264     options |= GNUNET_FS_DOWNLOAD_OPTION_LOOPBACK_ONLY;
265   dc = GNUNET_FS_download_start (ctx, uri, NULL, filename, NULL, 0,
266                                  GNUNET_FS_uri_chk_get_file_size (uri),
267                                  anonymity, options, NULL, NULL);
268   GNUNET_FS_uri_destroy (uri);
269   if (dc == NULL)
270   {
271     GNUNET_FS_stop (ctx);
272     ctx = NULL;
273     return;
274   }
275   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
276                                 NULL);
277 }
278
279
280 /**
281  * The main function to download GNUnet.
282  *
283  * @param argc number of arguments from the command line
284  * @param argv command line arguments
285  * @return 0 ok, 1 on error
286  */
287 int
288 main (int argc, char *const *argv)
289 {
290   static const struct GNUNET_GETOPT_CommandLineOption options[] = {
291     {'a', "anonymity", "LEVEL",
292      gettext_noop ("set the desired LEVEL of receiver-anonymity"),
293      1, &GNUNET_GETOPT_set_uint, &anonymity},
294     {'D', "delete-incomplete", NULL,
295      gettext_noop ("delete incomplete downloads (when aborted with CTRL-C)"),
296      0, &GNUNET_GETOPT_set_one, &delete_incomplete},
297     {'n', "no-network", NULL,
298      gettext_noop ("only search the local peer (no P2P network search)"),
299      0, &GNUNET_GETOPT_set_uint, &local_only},
300     {'o', "output", "FILENAME",
301      gettext_noop ("write the file to FILENAME"),
302      1, &GNUNET_GETOPT_set_string, &filename},
303     {'p', "parallelism", "DOWNLOADS",
304      gettext_noop
305      ("set the maximum number of parallel downloads that is allowed"),
306      1, &GNUNET_GETOPT_set_uint, &parallelism},
307     {'r', "request-parallelism", "REQUESTS",
308      gettext_noop
309      ("set the maximum number of parallel requests for blocks that is allowed"),
310      1, &GNUNET_GETOPT_set_uint, &request_parallelism},
311     {'R', "recursive", NULL,
312      gettext_noop ("download a GNUnet directory recursively"),
313      0, &GNUNET_GETOPT_set_one, &do_recursive},
314     {'V', "verbose", NULL,
315      gettext_noop ("be verbose (print progress information)"),
316      0, &GNUNET_GETOPT_increment_value, &verbose},
317     GNUNET_GETOPT_OPTION_END
318   };
319
320   if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
321     return 2;
322
323   return (GNUNET_OK ==
324           GNUNET_PROGRAM_run (argc, argv, "gnunet-download [OPTIONS] URI",
325                               gettext_noop
326                               ("Download files from GNUnet using a GNUnet CHK or LOC URI (gnunet://fs/chk/...)"),
327                               options, &run, NULL)) ? ret : 1;
328 }
329
330 /* end of gnunet-download.c */