doxygen fixes
[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 2, 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_SCHEDULER_Handle *sched;
42
43 static struct GNUNET_FS_DownloadContext *dc;
44
45 static unsigned int anonymity = 1;
46
47 static unsigned int parallelism = 16;
48
49 static int do_recursive;
50
51 static char *filename;
52
53
54 static void
55 cleanup_task (void *cls,
56               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,
65               const struct GNUNET_SCHEDULER_TaskContext *tc)
66 {
67   struct GNUNET_FS_DownloadContext *d;
68
69   if (dc != NULL)
70     {
71       d = dc;
72       dc = NULL;
73       GNUNET_FS_download_stop (d, delete_incomplete);
74     }
75 }
76
77
78 /**
79  * Called by FS client to give information about the progress of an 
80  * operation.
81  *
82  * @param cls closure
83  * @param info details about the event, specifying the event type
84  *        and various bits about the event
85  * @return client-context (for the next progress call
86  *         for this operation; should be set to NULL for
87  *         SUSPEND and STOPPED events).  The value returned
88  *         will be passed to future callbacks in the respective
89  *         field in the GNUNET_FS_ProgressInfo struct.
90  */
91 static void *
92 progress_cb (void *cls,
93              const struct GNUNET_FS_ProgressInfo *info)
94 {
95   char *s;
96   char *t;
97
98   switch (info->status)
99     {
100     case GNUNET_FS_STATUS_DOWNLOAD_START:
101       break;
102     case GNUNET_FS_STATUS_DOWNLOAD_PROGRESS:
103       if (verbose)
104         {         
105           s = GNUNET_STRINGS_relative_time_to_string(info->value.download.eta);
106           t = GNUNET_STRINGS_byte_size_fancy(info->value.download.completed * 1000LL / (info->value.download.duration.value + 1));
107           fprintf (stdout,
108                    _("Downloading `%s' at %llu/%llu (%s remaining, %s/s)\n"),
109                    info->value.download.filename,
110                    (unsigned long long) info->value.download.completed,
111                    (unsigned long long) info->value.download.size,
112                    s,
113                    t);
114           GNUNET_free (s);
115           GNUNET_free (t);
116         }
117       break;
118     case GNUNET_FS_STATUS_DOWNLOAD_ERROR:
119       fprintf (stderr,
120                _("Error downloading: %s.\n"),
121                info->value.download.specifics.error.message);
122       GNUNET_SCHEDULER_shutdown (sched);
123       break;
124     case GNUNET_FS_STATUS_DOWNLOAD_COMPLETED:
125       s = GNUNET_STRINGS_byte_size_fancy(info->value.download.completed * 1000 / (info->value.download.duration.value + 1));
126       fprintf (stdout,
127                _("Downloading `%s' done (%s/s).\n"),
128                info->value.download.filename,
129                s);
130       GNUNET_free (s);
131       if (info->value.download.dc == dc)
132         GNUNET_SCHEDULER_shutdown (sched);
133       break;
134     case GNUNET_FS_STATUS_DOWNLOAD_STOPPED: 
135       if (info->value.download.dc == dc)
136         GNUNET_SCHEDULER_add_continuation (sched,
137                                            &cleanup_task,
138                                            NULL,
139                                            GNUNET_SCHEDULER_REASON_PREREQ_DONE);
140       break;      
141     default:
142       fprintf (stderr,
143                _("Unexpected status: %d\n"),
144                info->status);
145       break;
146     }
147   return NULL;
148 }
149
150
151 /**
152  * Main function that will be run by the scheduler.
153  *
154  * @param cls closure
155  * @param s the scheduler to use
156  * @param args remaining command-line arguments
157  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
158  * @param c configuration
159  */
160 static void
161 run (void *cls,
162      struct GNUNET_SCHEDULER_Handle *s,
163      char *const *args,
164      const char *cfgfile,
165      const struct GNUNET_CONFIGURATION_Handle *c)
166 {
167   struct GNUNET_FS_Uri *uri;
168   char *emsg;
169   enum GNUNET_FS_DownloadOptions options;
170
171   sched = s;
172   uri = GNUNET_FS_uri_parse (args[0],
173                              &emsg);
174   if (NULL == uri)
175     {
176       fprintf (stderr,
177                _("Failed to parse URI: %s\n"),
178                emsg);
179       GNUNET_free (emsg);
180       ret = 1;
181       return;
182     }
183   if (! GNUNET_FS_uri_test_chk (uri))
184     {
185       fprintf (stderr,
186                "Only CHK URIs supported right now.\n");
187       ret = 1;
188       GNUNET_FS_uri_destroy (uri);
189       return;            
190     }
191   if (NULL == filename)
192     {
193       fprintf (stderr,
194                "Target filename must be specified.\n");
195       ret = 1;
196       GNUNET_FS_uri_destroy (uri);
197       return;            
198     }
199   cfg = c;
200   ctx = GNUNET_FS_start (sched,
201                          cfg,
202                          "gnunet-download",
203                          &progress_cb,
204                          NULL,
205                          GNUNET_FS_FLAGS_NONE,
206                          GNUNET_FS_OPTIONS_DOWNLOAD_PARALLELISM,
207                          parallelism,
208                          GNUNET_FS_OPTIONS_END);
209   if (NULL == ctx)
210     {
211       fprintf (stderr,
212                _("Could not initialize `%s' subsystem.\n"),
213                "FS");
214       GNUNET_FS_uri_destroy (uri);
215       ret = 1;
216       return;
217     }
218   options = GNUNET_FS_DOWNLOAD_OPTION_NONE;
219   if (do_recursive)
220     options |= GNUNET_FS_DOWNLOAD_OPTION_RECURSIVE;
221   dc = GNUNET_FS_download_start (ctx,
222                                  uri,
223                                  NULL,
224                                  filename,
225                                  0,
226                                  GNUNET_FS_uri_chk_get_file_size (uri),
227                                  anonymity,
228                                  options,
229                                  NULL,
230                                  NULL);
231   GNUNET_FS_uri_destroy (uri);
232   if (dc == NULL)
233     {
234       GNUNET_FS_stop (ctx);
235       ctx = NULL;
236       return;
237     }
238   GNUNET_SCHEDULER_add_delayed (sched,
239                                 GNUNET_TIME_UNIT_FOREVER_REL,
240                                 &shutdown_task,
241                                 NULL);
242 }
243
244
245 /**
246  * gnunet-download command line options
247  */
248 static struct GNUNET_GETOPT_CommandLineOption options[] = {
249   {'a', "anonymity", "LEVEL",
250    gettext_noop ("set the desired LEVEL of receiver-anonymity"),
251    1, &GNUNET_GETOPT_set_uint, &anonymity},
252   {'D', "delete-incomplete", NULL,
253    gettext_noop ("delete incomplete downloads (when aborted with CTRL-C)"),
254    0, &GNUNET_GETOPT_set_one, &delete_incomplete},
255   {'o', "output", "FILENAME",
256    gettext_noop ("write the file to FILENAME"),
257    1, &GNUNET_GETOPT_set_string, &filename},
258   {'p', "parallelism", "DOWNLOADS",
259    gettext_noop
260    ("set the maximum number of parallel downloads that are allowed"),
261    1, &GNUNET_GETOPT_set_uint, &parallelism},
262   {'R', "recursive", NULL,
263    gettext_noop ("download a GNUnet directory recursively"),
264    0, &GNUNET_GETOPT_set_one, &do_recursive},
265   {'V', "verbose", NULL,
266    gettext_noop ("be verbose (print progress information)"),
267    0, &GNUNET_GETOPT_set_one, &verbose},
268   GNUNET_GETOPT_OPTION_END
269 };
270
271
272 /**
273  * The main function to download GNUnet.
274  *
275  * @param argc number of arguments from the command line
276  * @param argv command line arguments
277  * @return 0 ok, 1 on error
278  */
279 int
280 main (int argc, char *const *argv)
281 {
282   return (GNUNET_OK ==
283           GNUNET_PROGRAM_run (argc,
284                               argv,
285                               "gnunet-download",
286                               gettext_noop
287                               ("Download files from GNUnet."),
288                               options, &run, NULL)) ? ret : 1;
289 }
290
291 /* end of gnunet-download.c */
292