]> sjero.net Git - wget/blob - src/main.c
Merge with mainline.
[wget] / src / main.c
1 /* Command line parsing.
2    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
3    2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
4
5 This file is part of GNU Wget.
6
7 GNU Wget is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 GNU Wget is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Wget.  If not, see <http://www.gnu.org/licenses/>.
19
20 Additional permission under GNU GPL version 3 section 7
21
22 If you modify this program, or any covered work, by linking or
23 combining it with the OpenSSL project's OpenSSL library (or a
24 modified version of that library), containing parts covered by the
25 terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
26 grants you additional permission to convey the resulting work.
27 Corresponding Source for a non-source form of such a combination
28 shall include the source code for the parts of OpenSSL used as well
29 as that of the covered work.  */
30
31 #include "wget.h"
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #ifdef HAVE_UNISTD_H
36 # include <unistd.h>
37 #endif /* HAVE_UNISTD_H */
38 #include <string.h>
39 #include <signal.h>
40 #ifdef ENABLE_NLS
41 # include <locale.h>
42 #endif
43 #include <assert.h>
44 #include <errno.h>
45 #include <time.h>
46
47 #include "utils.h"
48 #include "init.h"
49 #include "retr.h"
50 #include "recur.h"
51 #include "host.h"
52 #include "url.h"
53 #include "progress.h"           /* for progress_handle_sigwinch */
54 #include "convert.h"
55 #include "spider.h"
56 #include "http.h"               /* for save_cookies */
57
58 #include <getopt.h>
59 #include <getpass.h>
60 #include <quote.h>
61
62 #ifndef PATH_SEPARATOR
63 # define PATH_SEPARATOR '/'
64 #endif
65
66 struct options opt;
67
68 /* defined in version.c */
69 extern char *version_string;
70 extern char *compilation_string;
71 extern char *system_getrc;
72 extern char *link_string;
73 /* defined in build_info.c */
74 extern char *compiled_features[];
75 /* Used for --version output in print_version */
76 static const int max_chars_per_line = 72;
77
78 #if defined(SIGHUP) || defined(SIGUSR1)
79 static void redirect_output_signal (int);
80 #endif
81
82 const char *exec_name;
83 \f
84 #ifndef TESTING
85 /* Initialize I18N/L10N.  That amounts to invoking setlocale, and
86    setting up gettext's message catalog using bindtextdomain and
87    textdomain.  Does nothing if NLS is disabled or missing.  */
88
89 static void
90 i18n_initialize (void)
91 {
92   /* ENABLE_NLS implies existence of functions invoked here.  */
93 #ifdef ENABLE_NLS
94   /* Set the current locale.  */
95   setlocale (LC_ALL, "");
96   /* Set the text message domain.  */
97   bindtextdomain ("wget", LOCALEDIR);
98   textdomain ("wget");
99 #endif /* ENABLE_NLS */
100 }
101 \f
102 /* Definition of command-line options. */
103
104 static void print_help (void);
105 static void print_version (void);
106
107 #ifdef HAVE_SSL
108 # define IF_SSL(x) x
109 #else
110 # define IF_SSL(x) NULL
111 #endif
112
113 #ifdef ENABLE_DEBUG
114 # define WHEN_DEBUG(x) x
115 #else
116 # define WHEN_DEBUG(x) NULL
117 #endif
118
119 struct cmdline_option {
120   const char *long_name;
121   char short_name;
122   enum {
123     OPT_VALUE,
124     OPT_BOOLEAN,
125     OPT_FUNCALL,
126     /* Non-standard options that have to be handled specially in
127        main().  */
128     OPT__APPEND_OUTPUT,
129     OPT__CLOBBER,
130     OPT__DONT_REMOVE_LISTING,
131     OPT__EXECUTE,
132     OPT__NO,
133     OPT__PARENT
134   } type;
135   const void *data;             /* for standard options */
136   int argtype;                  /* for non-standard options */
137 };
138
139 static struct cmdline_option option_data[] =
140   {
141     { "accept", 'A', OPT_VALUE, "accept", -1 },
142     { "append-output", 'a', OPT__APPEND_OUTPUT, NULL, required_argument },
143     { "ask-password", 0, OPT_BOOLEAN, "askpassword", -1 },
144     { "auth-no-challenge", 0, OPT_BOOLEAN, "authnochallenge", -1 },
145     { "background", 'b', OPT_BOOLEAN, "background", -1 },
146     { "backup-converted", 'K', OPT_BOOLEAN, "backupconverted", -1 },
147     { "backups", 0, OPT_BOOLEAN, "backups", -1 },
148     { "base", 'B', OPT_VALUE, "base", -1 },
149     { "bind-address", 0, OPT_VALUE, "bindaddress", -1 },
150     { IF_SSL ("ca-certificate"), 0, OPT_VALUE, "cacertificate", -1 },
151     { IF_SSL ("ca-directory"), 0, OPT_VALUE, "cadirectory", -1 },
152     { "cache", 0, OPT_BOOLEAN, "cache", -1 },
153     { IF_SSL ("certificate"), 0, OPT_VALUE, "certificate", -1 },
154     { IF_SSL ("certificate-type"), 0, OPT_VALUE, "certificatetype", -1 },
155     { IF_SSL ("check-certificate"), 0, OPT_BOOLEAN, "checkcertificate", -1 },
156     { "clobber", 0, OPT__CLOBBER, NULL, optional_argument },
157     { "connect-timeout", 0, OPT_VALUE, "connecttimeout", -1 },
158     { "continue", 'c', OPT_BOOLEAN, "continue", -1 },
159     { "convert-links", 'k', OPT_BOOLEAN, "convertlinks", -1 },
160     { "content-disposition", 0, OPT_BOOLEAN, "contentdisposition", -1 },
161     { "cookies", 0, OPT_BOOLEAN, "cookies", -1 },
162     { "cut-dirs", 0, OPT_VALUE, "cutdirs", -1 },
163     { WHEN_DEBUG ("debug"), 'd', OPT_BOOLEAN, "debug", -1 },
164     { "default-page", 0, OPT_VALUE, "defaultpage", -1 },
165     { "delete-after", 0, OPT_BOOLEAN, "deleteafter", -1 },
166     { "directories", 0, OPT_BOOLEAN, "dirstruct", -1 },
167     { "directory-prefix", 'P', OPT_VALUE, "dirprefix", -1 },
168     { "dns-cache", 0, OPT_BOOLEAN, "dnscache", -1 },
169     { "dns-timeout", 0, OPT_VALUE, "dnstimeout", -1 },
170     { "domains", 'D', OPT_VALUE, "domains", -1 },
171     { "dont-remove-listing", 0, OPT__DONT_REMOVE_LISTING, NULL, no_argument },
172     { "dot-style", 0, OPT_VALUE, "dotstyle", -1 },
173     { "egd-file", 0, OPT_VALUE, "egdfile", -1 },
174     { "exclude-directories", 'X', OPT_VALUE, "excludedirectories", -1 },
175     { "exclude-domains", 0, OPT_VALUE, "excludedomains", -1 },
176     { "execute", 'e', OPT__EXECUTE, NULL, required_argument },
177     { "follow-ftp", 0, OPT_BOOLEAN, "followftp", -1 },
178     { "follow-tags", 0, OPT_VALUE, "followtags", -1 },
179     { "force-directories", 'x', OPT_BOOLEAN, "dirstruct", -1 },
180     { "force-html", 'F', OPT_BOOLEAN, "forcehtml", -1 },
181     { "ftp-password", 0, OPT_VALUE, "ftppassword", -1 },
182     { "ftp-user", 0, OPT_VALUE, "ftpuser", -1 },
183     { "glob", 0, OPT_BOOLEAN, "glob", -1 },
184     { "header", 0, OPT_VALUE, "header", -1 },
185     { "help", 'h', OPT_FUNCALL, (void *)print_help, no_argument },
186     { "host-directories", 0, OPT_BOOLEAN, "addhostdir", -1 },
187     { "html-extension", 'E', OPT_BOOLEAN, "htmlextension", -1 },
188     { "htmlify", 0, OPT_BOOLEAN, "htmlify", -1 },
189     { "http-keep-alive", 0, OPT_BOOLEAN, "httpkeepalive", -1 },
190     { "http-passwd", 0, OPT_VALUE, "httppassword", -1 }, /* deprecated */
191     { "http-password", 0, OPT_VALUE, "httppassword", -1 },
192     { "http-user", 0, OPT_VALUE, "httpuser", -1 },
193     { "ignore-case", 0, OPT_BOOLEAN, "ignorecase", -1 },
194     { "ignore-length", 0, OPT_BOOLEAN, "ignorelength", -1 },
195     { "ignore-tags", 0, OPT_VALUE, "ignoretags", -1 },
196     { "include-directories", 'I', OPT_VALUE, "includedirectories", -1 },
197 #ifdef ENABLE_IPV6
198     { "inet4-only", '4', OPT_BOOLEAN, "inet4only", -1 },
199     { "inet6-only", '6', OPT_BOOLEAN, "inet6only", -1 },
200 #endif
201     { "input-file", 'i', OPT_VALUE, "input", -1 },
202     { "iri", 0, OPT_BOOLEAN, "iri", -1 },
203     { "keep-session-cookies", 0, OPT_BOOLEAN, "keepsessioncookies", -1 },
204     { "level", 'l', OPT_VALUE, "reclevel", -1 },
205     { "limit-rate", 0, OPT_VALUE, "limitrate", -1 },
206     { "load-cookies", 0, OPT_VALUE, "loadcookies", -1 },
207     { "locale", 0, OPT_VALUE, "locale", -1 },
208     { "max-redirect", 0, OPT_VALUE, "maxredirect", -1 },
209     { "mirror", 'm', OPT_BOOLEAN, "mirror", -1 },
210     { "no", 'n', OPT__NO, NULL, required_argument },
211     { "no-clobber", 0, OPT_BOOLEAN, "noclobber", -1 },
212     { "no-parent", 0, OPT_BOOLEAN, "noparent", -1 },
213     { "output-document", 'O', OPT_VALUE, "outputdocument", -1 },
214     { "output-file", 'o', OPT_VALUE, "logfile", -1 },
215     { "page-requisites", 'p', OPT_BOOLEAN, "pagerequisites", -1 },
216     { "parent", 0, OPT__PARENT, NULL, optional_argument },
217     { "passive-ftp", 0, OPT_BOOLEAN, "passiveftp", -1 },
218     { "password", 0, OPT_VALUE, "password", -1 },
219     { "post-data", 0, OPT_VALUE, "postdata", -1 },
220     { "post-file", 0, OPT_VALUE, "postfile", -1 },
221     { "prefer-family", 0, OPT_VALUE, "preferfamily", -1 },
222     { "preserve-permissions", 0, OPT_BOOLEAN, "preservepermissions", -1 },
223     { IF_SSL ("private-key"), 0, OPT_VALUE, "privatekey", -1 },
224     { IF_SSL ("private-key-type"), 0, OPT_VALUE, "privatekeytype", -1 },
225     { "progress", 0, OPT_VALUE, "progress", -1 },
226     { "protocol-directories", 0, OPT_BOOLEAN, "protocoldirectories", -1 },
227     { "proxy", 0, OPT_BOOLEAN, "useproxy", -1 },
228     { "proxy__compat", 'Y', OPT_VALUE, "useproxy", -1 }, /* back-compatible */
229     { "proxy-passwd", 0, OPT_VALUE, "proxypassword", -1 }, /* deprecated */
230     { "proxy-password", 0, OPT_VALUE, "proxypassword", -1 },
231     { "proxy-user", 0, OPT_VALUE, "proxyuser", -1 },
232     { "quiet", 'q', OPT_BOOLEAN, "quiet", -1 },
233     { "quota", 'Q', OPT_VALUE, "quota", -1 },
234     { "random-file", 0, OPT_VALUE, "randomfile", -1 },
235     { "random-wait", 0, OPT_BOOLEAN, "randomwait", -1 },
236     { "read-timeout", 0, OPT_VALUE, "readtimeout", -1 },
237     { "recursive", 'r', OPT_BOOLEAN, "recursive", -1 },
238     { "referer", 0, OPT_VALUE, "referer", -1 },
239     { "reject", 'R', OPT_VALUE, "reject", -1 },
240     { "relative", 'L', OPT_BOOLEAN, "relativeonly", -1 },
241     { "remote-encoding", 0, OPT_VALUE, "remoteencoding", -1},
242     { "remove-listing", 0, OPT_BOOLEAN, "removelisting", -1 },
243     { "restrict-file-names", 0, OPT_BOOLEAN, "restrictfilenames", -1 },
244     { "retr-symlinks", 0, OPT_BOOLEAN, "retrsymlinks", -1 },
245     { "retry-connrefused", 0, OPT_BOOLEAN, "retryconnrefused", -1 },
246     { "save-cookies", 0, OPT_VALUE, "savecookies", -1 },
247     { "save-headers", 0, OPT_BOOLEAN, "saveheaders", -1 },
248     { IF_SSL ("secure-protocol"), 0, OPT_VALUE, "secureprotocol", -1 },
249     { "server-response", 'S', OPT_BOOLEAN, "serverresponse", -1 },
250     { "span-hosts", 'H', OPT_BOOLEAN, "spanhosts", -1 },
251     { "spider", 0, OPT_BOOLEAN, "spider", -1 },
252     { "strict-comments", 0, OPT_BOOLEAN, "strictcomments", -1 },
253     { "timeout", 'T', OPT_VALUE, "timeout", -1 },
254     { "timestamping", 'N', OPT_BOOLEAN, "timestamping", -1 },
255     { "tries", 't', OPT_VALUE, "tries", -1 },
256     { "user", 0, OPT_VALUE, "user", -1 },
257     { "user-agent", 'U', OPT_VALUE, "useragent", -1 },
258     { "verbose", 'v', OPT_BOOLEAN, "verbose", -1 },
259     { "verbose", 0, OPT_BOOLEAN, "verbose", -1 },
260     { "version", 'V', OPT_FUNCALL, (void *) print_version, no_argument },
261     { "wait", 'w', OPT_VALUE, "wait", -1 },
262     { "waitretry", 0, OPT_VALUE, "waitretry", -1 },
263 #ifdef MSDOS
264     { "wdebug", 0, OPT_BOOLEAN, "wdebug", -1 },
265 #endif
266   };
267
268 #undef WHEN_DEBUG
269 #undef IF_SSL
270
271 /* Return a string that contains S with "no-" prepended.  The string
272    is NUL-terminated and allocated off static storage at Wget
273    startup.  */
274
275 static char *
276 no_prefix (const char *s)
277 {
278   static char buffer[1024];
279   static char *p = buffer;
280
281   char *cp = p;
282   int size = 3 + strlen (s) + 1;  /* "no-STRING\0" */
283   if (p + size >= buffer + sizeof (buffer))
284     abort ();
285
286   cp[0] = 'n', cp[1] = 'o', cp[2] = '-';
287   strcpy (cp + 3, s);
288   p += size;
289   return cp;
290 }
291
292 /* The arguments that that main passes to getopt_long. */
293 static struct option long_options[2 * countof (option_data) + 1];
294 static char short_options[128];
295
296 /* Mapping between short option chars and option_data indices. */
297 static unsigned char optmap[96];
298
299 /* Marker for `--no-FOO' values in long_options.  */
300 #define BOOLEAN_NEG_MARKER 1024
301
302 /* Initialize the long_options array used by getopt_long from the data
303    in option_data.  */
304
305 static void
306 init_switches (void)
307 {
308   char *p = short_options;
309   size_t i, o = 0;
310   for (i = 0; i < countof (option_data); i++)
311     {
312       struct cmdline_option *opt = &option_data[i];
313       struct option *longopt;
314
315       if (!opt->long_name)
316         /* The option is disabled. */
317         continue;
318
319       longopt = &long_options[o++];
320       longopt->name = opt->long_name;
321       longopt->val = i;
322       if (opt->short_name)
323         {
324           *p++ = opt->short_name;
325           optmap[opt->short_name - 32] = longopt - long_options;
326         }
327       switch (opt->type)
328         {
329         case OPT_VALUE:
330           longopt->has_arg = required_argument;
331           if (opt->short_name)
332             *p++ = ':';
333           break;
334         case OPT_BOOLEAN:
335           /* Specify an optional argument for long options, so that
336              --option=off works the same as --no-option, for
337              compatibility with pre-1.10 Wget.  However, don't specify
338              optional arguments short-option booleans because they
339              prevent combining of short options.  */
340           longopt->has_arg = optional_argument;
341           /* For Boolean options, add the "--no-FOO" variant, which is
342              identical to "--foo", except it has opposite meaning and
343              it doesn't allow an argument.  */
344           longopt = &long_options[o++];
345           longopt->name = no_prefix (opt->long_name);
346           longopt->has_arg = no_argument;
347           /* Mask the value so we'll be able to recognize that we're
348              dealing with the false value.  */
349           longopt->val = i | BOOLEAN_NEG_MARKER;
350           break;
351         default:
352           assert (opt->argtype != -1);
353           longopt->has_arg = opt->argtype;
354           if (opt->short_name)
355             {
356               if (longopt->has_arg == required_argument)
357                 *p++ = ':';
358               /* Don't handle optional_argument */
359             }
360         }
361     }
362   /* Terminate short_options. */
363   *p = '\0';
364   /* No need for xzero(long_options[o]) because its storage is static
365      and it will be zeroed by default.  */
366   assert (o <= countof (long_options));
367 }
368
369 /* Print the usage message.  */
370 static void
371 print_usage (void)
372 {
373   printf (_("Usage: %s [OPTION]... [URL]...\n"), exec_name);
374 }
375
376 /* Print the help message, describing all the available options.  If
377    you add an option, be sure to update this list.  */
378 static void
379 print_help (void)
380 {
381   /* We split the help text this way to ease translation of individual
382      entries.  */
383   static const char *help[] = {
384     "\n",
385     N_("\
386 Mandatory arguments to long options are mandatory for short options too.\n\n"),
387     N_("\
388 Startup:\n"),
389     N_("\
390   -V,  --version           display the version of Wget and exit.\n"),
391     N_("\
392   -h,  --help              print this help.\n"),
393     N_("\
394   -b,  --background        go to background after startup.\n"),
395     N_("\
396   -e,  --execute=COMMAND   execute a `.wgetrc'-style command.\n"),
397     "\n",
398
399     N_("\
400 Logging and input file:\n"),
401     N_("\
402   -o,  --output-file=FILE    log messages to FILE.\n"),
403     N_("\
404   -a,  --append-output=FILE  append messages to FILE.\n"),
405 #ifdef ENABLE_DEBUG
406     N_("\
407   -d,  --debug               print lots of debugging information.\n"),
408 #endif
409 #ifdef MSDOS
410     N_("\
411        --wdebug              print Watt-32 debug output.\n"),
412 #endif
413     N_("\
414   -q,  --quiet               quiet (no output).\n"),
415     N_("\
416   -v,  --verbose             be verbose (this is the default).\n"),
417     N_("\
418   -nv, --no-verbose          turn off verboseness, without being quiet.\n"),
419     N_("\
420   -i,  --input-file=FILE     download URLs found in local or external FILE.\n"),
421     N_("\
422   -F,  --force-html          treat input file as HTML.\n"),
423     N_("\
424   -B,  --base=URL            prepends URL to relative links in -F -i file.\n"),
425     "\n",
426
427     N_("\
428 Download:\n"),
429     N_("\
430   -t,  --tries=NUMBER            set number of retries to NUMBER (0 unlimits).\n"),
431     N_("\
432        --retry-connrefused       retry even if connection is refused.\n"),
433     N_("\
434   -O,  --output-document=FILE    write documents to FILE.\n"),
435     N_("\
436   -nc, --no-clobber              skip downloads that would download to\n\
437                                  existing files.\n"),
438     N_("\
439   -c,  --continue                resume getting a partially-downloaded file.\n"),
440     N_("\
441        --progress=TYPE           select progress gauge type.\n"),
442     N_("\
443   -N,  --timestamping            don't re-retrieve files unless newer than\n\
444                                  local.\n"),
445     N_("\
446   -S,  --server-response         print server response.\n"),
447     N_("\
448        --spider                  don't download anything.\n"),
449     N_("\
450   -T,  --timeout=SECONDS         set all timeout values to SECONDS.\n"),
451     N_("\
452        --dns-timeout=SECS        set the DNS lookup timeout to SECS.\n"),
453     N_("\
454        --connect-timeout=SECS    set the connect timeout to SECS.\n"),
455     N_("\
456        --read-timeout=SECS       set the read timeout to SECS.\n"),
457     N_("\
458   -w,  --wait=SECONDS            wait SECONDS between retrievals.\n"),
459     N_("\
460        --waitretry=SECONDS       wait 1..SECONDS between retries of a retrieval.\n"),
461     N_("\
462        --random-wait             wait from 0...2*WAIT secs between retrievals.\n"),
463     N_("\
464        --no-proxy                explicitly turn off proxy.\n"),
465     N_("\
466   -Q,  --quota=NUMBER            set retrieval quota to NUMBER.\n"),
467     N_("\
468        --bind-address=ADDRESS    bind to ADDRESS (hostname or IP) on local host.\n"),
469     N_("\
470        --limit-rate=RATE         limit download rate to RATE.\n"),
471     N_("\
472        --no-dns-cache            disable caching DNS lookups.\n"),
473     N_("\
474        --restrict-file-names=OS  restrict chars in file names to ones OS allows.\n"),
475     N_("\
476        --ignore-case             ignore case when matching files/directories.\n"),
477 #ifdef ENABLE_IPV6
478     N_("\
479   -4,  --inet4-only              connect only to IPv4 addresses.\n"),
480     N_("\
481   -6,  --inet6-only              connect only to IPv6 addresses.\n"),
482     N_("\
483        --prefer-family=FAMILY    connect first to addresses of specified family,\n\
484                                  one of IPv6, IPv4, or none.\n"),
485 #endif
486     N_("\
487        --user=USER               set both ftp and http user to USER.\n"),
488     N_("\
489        --password=PASS           set both ftp and http password to PASS.\n"),
490     N_("\
491        --ask-password            prompt for passwords.\n"),
492     "\n",
493
494     N_("\
495 Directories:\n"),
496     N_("\
497   -nd, --no-directories           don't create directories.\n"),
498     N_("\
499   -x,  --force-directories        force creation of directories.\n"),
500     N_("\
501   -nH, --no-host-directories      don't create host directories.\n"),
502     N_("\
503        --protocol-directories     use protocol name in directories.\n"),
504     N_("\
505   -P,  --directory-prefix=PREFIX  save files to PREFIX/...\n"),
506     N_("\
507        --cut-dirs=NUMBER          ignore NUMBER remote directory components.\n"),
508     "\n",
509
510     N_("\
511 HTTP options:\n"),
512     N_("\
513        --http-user=USER        set http user to USER.\n"),
514     N_("\
515        --http-password=PASS    set http password to PASS.\n"),
516     N_("\
517        --no-cache              disallow server-cached data.\n"),
518     N_ ("\
519        --default-page=NAME     Change the default page name (normally\n\
520                                this is `index.html'.).\n"),
521     N_("\
522   -E,  --html-extension        save HTML documents with `.html' extension.\n"),
523     N_("\
524        --ignore-length         ignore `Content-Length' header field.\n"),
525     N_("\
526        --header=STRING         insert STRING among the headers.\n"),
527     N_("\
528        --max-redirect          maximum redirections allowed per page.\n"),
529     N_("\
530        --proxy-user=USER       set USER as proxy username.\n"),
531     N_("\
532        --proxy-password=PASS   set PASS as proxy password.\n"),
533     N_("\
534        --referer=URL           include `Referer: URL' header in HTTP request.\n"),
535     N_("\
536        --save-headers          save the HTTP headers to file.\n"),
537     N_("\
538   -U,  --user-agent=AGENT      identify as AGENT instead of Wget/VERSION.\n"),
539     N_("\
540        --no-http-keep-alive    disable HTTP keep-alive (persistent connections).\n"),
541     N_("\
542        --no-cookies            don't use cookies.\n"),
543     N_("\
544        --load-cookies=FILE     load cookies from FILE before session.\n"),
545     N_("\
546        --save-cookies=FILE     save cookies to FILE after session.\n"),
547     N_("\
548        --keep-session-cookies  load and save session (non-permanent) cookies.\n"),
549     N_("\
550        --post-data=STRING      use the POST method; send STRING as the data.\n"),
551     N_("\
552        --post-file=FILE        use the POST method; send contents of FILE.\n"),
553     N_("\
554        --content-disposition   honor the Content-Disposition header when\n\
555                                choosing local file names (EXPERIMENTAL).\n"),
556     N_("\
557        --auth-no-challenge     Send Basic HTTP authentication information\n\
558                                without first waiting for the server's\n\
559                                challenge.\n"),
560     "\n",
561
562 #ifdef HAVE_SSL
563     N_("\
564 HTTPS (SSL/TLS) options:\n"),
565     N_("\
566        --secure-protocol=PR     choose secure protocol, one of auto, SSLv2,\n\
567                                 SSLv3, and TLSv1.\n"),
568     N_("\
569        --no-check-certificate   don't validate the server's certificate.\n"),
570     N_("\
571        --certificate=FILE       client certificate file.\n"),
572     N_("\
573        --certificate-type=TYPE  client certificate type, PEM or DER.\n"),
574     N_("\
575        --private-key=FILE       private key file.\n"),
576     N_("\
577        --private-key-type=TYPE  private key type, PEM or DER.\n"),
578     N_("\
579        --ca-certificate=FILE    file with the bundle of CA's.\n"),
580     N_("\
581        --ca-directory=DIR       directory where hash list of CA's is stored.\n"),
582     N_("\
583        --random-file=FILE       file with random data for seeding the SSL PRNG.\n"),
584     N_("\
585        --egd-file=FILE          file naming the EGD socket with random data.\n"),
586     "\n",
587 #endif /* HAVE_SSL */
588
589     N_("\
590 FTP options:\n"),
591     N_("\
592        --ftp-user=USER         set ftp user to USER.\n"),
593     N_("\
594        --ftp-password=PASS     set ftp password to PASS.\n"),
595     N_("\
596        --no-remove-listing     don't remove `.listing' files.\n"),
597     N_("\
598        --no-glob               turn off FTP file name globbing.\n"),
599     N_("\
600        --no-passive-ftp        disable the \"passive\" transfer mode.\n"),
601     N_("\
602        --retr-symlinks         when recursing, get linked-to files (not dir).\n"),
603     N_("\
604        --preserve-permissions  preserve remote file permissions.\n"),
605     "\n",
606
607     N_("\
608 Recursive download:\n"),
609     N_("\
610   -r,  --recursive          specify recursive download.\n"),
611     N_("\
612   -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n"),
613     N_("\
614        --delete-after       delete files locally after downloading them.\n"),
615     N_("\
616   -k,  --convert-links      make links in downloaded HTML or CSS point to\n\
617                             local files.\n"),
618     N_("\
619   -K,  --backup-converted   before converting file X, back up as X.orig.\n"),
620     N_("\
621   -m,  --mirror             shortcut for -N -r -l inf --no-remove-listing.\n"),
622     N_("\
623   -p,  --page-requisites    get all images, etc. needed to display HTML page.\n"),
624     N_("\
625        --strict-comments    turn on strict (SGML) handling of HTML comments.\n"),
626     "\n",
627
628     N_("\
629 Recursive accept/reject:\n"),
630     N_("\
631   -A,  --accept=LIST               comma-separated list of accepted extensions.\n"),
632     N_("\
633   -R,  --reject=LIST               comma-separated list of rejected extensions.\n"),
634     N_("\
635   -D,  --domains=LIST              comma-separated list of accepted domains.\n"),
636     N_("\
637        --exclude-domains=LIST      comma-separated list of rejected domains.\n"),
638     N_("\
639        --follow-ftp                follow FTP links from HTML documents.\n"),
640     N_("\
641        --follow-tags=LIST          comma-separated list of followed HTML tags.\n"),
642     N_("\
643        --ignore-tags=LIST          comma-separated list of ignored HTML tags.\n"),
644     N_("\
645   -H,  --span-hosts                go to foreign hosts when recursive.\n"),
646     N_("\
647   -L,  --relative                  follow relative links only.\n"),
648     N_("\
649   -I,  --include-directories=LIST  list of allowed directories.\n"),
650     N_("\
651   -X,  --exclude-directories=LIST  list of excluded directories.\n"),
652     N_("\
653   -np, --no-parent                 don't ascend to the parent directory.\n"),
654     "\n",
655
656     N_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n")
657   };
658
659   size_t i;
660
661   printf (_("GNU Wget %s, a non-interactive network retriever.\n"),
662           version_string);
663   print_usage ();
664
665   for (i = 0; i < countof (help); i++)
666     fputs (_(help[i]), stdout);
667
668   exit (0);
669 }
670
671 /* Return a human-readable printed representation of INTERVAL,
672    measured in seconds.  */
673
674 static char *
675 secs_to_human_time (double interval)
676 {
677   static char buf[32];
678   int secs = (int) (interval + 0.5);
679   int hours, mins, days;
680
681   days = secs / 86400, secs %= 86400;
682   hours = secs / 3600, secs %= 3600;
683   mins = secs / 60, secs %= 60;
684
685   if (days)
686     sprintf (buf, "%dd %dh %dm %ds", days, hours, mins, secs);
687   else if (hours)
688     sprintf (buf, "%dh %dm %ds", hours, mins, secs);
689   else if (mins)
690     sprintf (buf, "%dm %ds", mins, secs);
691   else
692     sprintf (buf, "%ss", print_decimal (interval));
693
694   return buf;
695 }
696
697 static char *
698 prompt_for_password (void)
699 {
700   if (opt.user)
701     printf (_("Password for user %s: "), quote (opt.user));
702   else
703     printf (_("Password: "));
704   return getpass("");
705 }
706
707 /* Function that prints the line argument while limiting it
708    to at most line_length. prefix is printed on the first line
709    and an appropriate number of spaces are added on subsequent
710    lines.*/
711 static void
712 format_and_print_line (const char *prefix, const char *line,
713                        int line_length) 
714 {
715   int leading_spaces;
716   int remaining_chars;
717   char *line_dup, *token;
718   
719   assert (prefix != NULL);
720   assert (line != NULL);
721
722   line_dup = xstrdup (line);
723
724   if (line_length <= 0)
725     line_length = max_chars_per_line;
726
727   leading_spaces = strlen (prefix);
728   printf ("%s", prefix);
729   remaining_chars = line_length - leading_spaces;
730   /* We break on spaces. */
731   token = strtok (line_dup, " ");
732   while (token != NULL) 
733     {
734       /* If however a token is much larger than the maximum
735          line length, all bets are off and we simply print the
736          token on the next line. */
737       if (remaining_chars <= strlen (token)) 
738         {
739           int j;
740           printf ("\n");
741           j = 0;
742           for (j = 0; j < leading_spaces; j++) 
743             {
744               printf (" ");
745             }
746           remaining_chars = line_length - leading_spaces;
747         }
748       printf ("%s ", token);
749       remaining_chars -= strlen (token) + 1;  // account for " "
750       token = strtok (NULL, " ");
751     }
752
753   printf ("\n");
754
755   xfree (line_dup);
756 }
757
758 static void
759 print_version (void)
760 {
761   const char *options_title = "Options    : ";
762   const char *wgetrc_title  = "Wgetrc     : ";
763   const char *locale_title  = "Locale     : ";
764   const char *compile_title = "Compile    : ";
765   const char *link_title    = "Link       : ";
766   const char *prefix_spaces = "             ";
767   const int prefix_space_length = strlen (prefix_spaces);
768   char *line;
769   char *env_wgetrc, *user_wgetrc;
770   int i;
771
772   printf ("GNU Wget %s\n", version_string);
773   printf (options_title);
774   /* compiled_features is a char*[]. We limit the characters per
775      line to max_chars_per_line and prefix each line with a constant
776      number of spaces for proper alignment. */
777   for (i = 0; compiled_features[i] != NULL; ) 
778     {
779       int line_length = max_chars_per_line - prefix_space_length;
780       while ((line_length > 0) && (compiled_features[i] != NULL)) 
781         {
782           printf ("%s ", compiled_features[i]);
783           line_length -= strlen (compiled_features[i]) + 2;
784           i++;
785         }
786       printf ("\n");
787       if (compiled_features[i] != NULL) 
788         {
789           printf (prefix_spaces);
790         }
791     }
792   /* Handle the case when $WGETRC is unset and $HOME/.wgetrc is 
793      absent. */
794   printf (wgetrc_title);
795   env_wgetrc = wgetrc_env_file_name ();
796   if (env_wgetrc && *env_wgetrc) 
797     {
798       printf ("%s (env)\n%s", env_wgetrc, prefix_spaces);
799       xfree (env_wgetrc);
800     }
801   user_wgetrc = wgetrc_user_file_name ();
802   if (user_wgetrc) 
803     {
804       printf ("%s (user)\n%s", user_wgetrc, prefix_spaces);
805       xfree (user_wgetrc);
806     }
807 #ifdef SYSTEM_WGETRC
808   printf ("%s (system)\n", SYSTEM_WGETRC);
809 #else
810   putchar ('\n');
811 #endif
812
813   format_and_print_line (locale_title,
814                          LOCALEDIR, 
815                          max_chars_per_line);
816   
817   format_and_print_line (compile_title,
818                          compilation_string,
819                          max_chars_per_line);
820
821   format_and_print_line (link_title,
822                          link_string,
823                          max_chars_per_line);
824
825   printf ("\n");
826   /* TRANSLATORS: When available, an actual copyright character
827      (cirle-c) should be used in preference to "(C)". */
828   fputs (_("\
829 Copyright (C) 2008 Free Software Foundation, Inc.\n"), stdout);
830   fputs (_("\
831 License GPLv3+: GNU GPL version 3 or later\n\
832 <http://www.gnu.org/licenses/gpl.html>.\n\
833 This is free software: you are free to change and redistribute it.\n\
834 There is NO WARRANTY, to the extent permitted by law.\n"), stdout);
835   /* TRANSLATORS: When available, please use the proper diacritics for
836      names such as this one. See en_US.po for reference. */
837   fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"),
838          stdout);
839   fputs (_("Currently maintained by Micah Cowan <micah@cowan.name>.\n"),
840          stdout);
841   fputs (_("Please send bug reports and questions to <bug-wget@gnu.org>.\n"),
842          stdout);
843   exit (0);
844 }
845
846 char *program_name; /* Needed by lib/error.c. */
847
848 int
849 main (int argc, char **argv)
850 {
851   char **url, **t;
852   int i, ret, longindex;
853   int nurl, status;
854   bool append_to_log = false;
855
856   program_name = argv[0];
857
858   i18n_initialize ();
859
860   /* Construct the name of the executable, without the directory part.  */
861   exec_name = strrchr (argv[0], PATH_SEPARATOR);
862   if (!exec_name)
863     exec_name = argv[0];
864   else
865     ++exec_name;
866
867 #ifdef WINDOWS
868   /* Drop extension (typically .EXE) from executable filename. */
869   windows_main ((char **) &exec_name);
870 #endif
871
872   /* Set option defaults; read the system wgetrc and ~/.wgetrc.  */
873   initialize ();
874
875   init_switches ();
876   longindex = -1;
877   while ((ret = getopt_long (argc, argv,
878                              short_options, long_options, &longindex)) != -1)
879     {
880       int val;
881       struct cmdline_option *opt;
882
883       /* If LONGINDEX is unchanged, it means RET is referring a short
884          option.  */
885       if (longindex == -1)
886         {
887           if (ret == '?')
888             {
889               print_usage ();
890               printf ("\n");
891               printf (_("Try `%s --help' for more options.\n"), exec_name);
892               exit (2);
893             }
894           /* Find the short option character in the mapping.  */
895           longindex = optmap[ret - 32];
896         }
897       val = long_options[longindex].val;
898
899       /* Use the retrieved value to locate the option in the
900          option_data array, and to see if we're dealing with the
901          negated "--no-FOO" variant of the boolean option "--foo".  */
902       opt = &option_data[val & ~BOOLEAN_NEG_MARKER];
903       switch (opt->type)
904         {
905         case OPT_VALUE:
906           setoptval (opt->data, optarg, opt->long_name);
907           break;
908         case OPT_BOOLEAN:
909           if (optarg)
910             /* The user has specified a value -- use it. */
911             setoptval (opt->data, optarg, opt->long_name);
912           else
913             {
914               /* NEG is true for `--no-FOO' style boolean options. */
915               bool neg = !!(val & BOOLEAN_NEG_MARKER);
916               setoptval (opt->data, neg ? "0" : "1", opt->long_name);
917             }
918           break;
919         case OPT_FUNCALL:
920           {
921             void (*func) (void) = (void (*) (void)) opt->data;
922             func ();
923           }
924           break;
925         case OPT__APPEND_OUTPUT:
926           setoptval ("logfile", optarg, opt->long_name);
927           append_to_log = true;
928           break;
929         case OPT__EXECUTE:
930           run_command (optarg);
931           break;
932         case OPT__NO:
933           {
934             /* We support real --no-FOO flags now, but keep these
935                short options for convenience and backward
936                compatibility.  */
937             char *p;
938             for (p = optarg; *p; p++)
939               switch (*p)
940                 {
941                 case 'v':
942                   setoptval ("verbose", "0", opt->long_name);
943                   break;
944                 case 'H':
945                   setoptval ("addhostdir", "0", opt->long_name);
946                   break;
947                 case 'd':
948                   setoptval ("dirstruct", "0", opt->long_name);
949                   break;
950                 case 'c':
951                   setoptval ("noclobber", "1", opt->long_name);
952                   break;
953                 case 'p':
954                   setoptval ("noparent", "1", opt->long_name);
955                   break;
956                 default:
957                   printf (_("%s: illegal option -- `-n%c'\n"), exec_name, *p);
958                   print_usage ();
959                   printf ("\n");
960                   printf (_("Try `%s --help' for more options.\n"), exec_name);
961                   exit (1);
962                 }
963             break;
964           }
965         case OPT__PARENT:
966         case OPT__CLOBBER:
967           {
968             /* The wgetrc commands are named noparent and noclobber,
969                so we must revert the meaning of the cmdline options
970                before passing the value to setoptval.  */
971             bool flag = true;
972             if (optarg)
973               flag = (*optarg == '1' || c_tolower (*optarg) == 'y'
974                       || (c_tolower (optarg[0]) == 'o'
975                           && c_tolower (optarg[1]) == 'n'));
976             setoptval (opt->type == OPT__PARENT ? "noparent" : "noclobber",
977                        flag ? "0" : "1", opt->long_name);
978             break;
979           }
980         case OPT__DONT_REMOVE_LISTING:
981           setoptval ("removelisting", "0", opt->long_name);
982           break;
983         }
984
985       longindex = -1;
986     }
987
988   nurl = argc - optind;
989
990   /* All user options have now been processed, so it's now safe to do
991      interoption dependency checks. */
992
993   if (opt.reclevel == 0)
994       opt.reclevel = INFINITE_RECURSION; /* see recur.h for commentary */
995
996   if (opt.spider || opt.delete_after)
997       opt.no_dirstruct = true;
998
999   if (opt.page_requisites && !opt.recursive)
1000     {
1001       /* Don't set opt.recursive here because it would confuse the FTP
1002          code.  Instead, call retrieve_tree below when either
1003          page_requisites or recursive is requested.  */
1004       opt.reclevel = 0;
1005       if (!opt.no_dirstruct)
1006         opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
1007     }
1008
1009   if (opt.verbose == -1)
1010     opt.verbose = !opt.quiet;
1011
1012   /* Sanity checks.  */
1013   if (opt.verbose && opt.quiet)
1014     {
1015       printf (_("Can't be verbose and quiet at the same time.\n"));
1016       print_usage ();
1017       exit (1);
1018     }
1019   if (opt.timestamping && opt.noclobber)
1020     {
1021       printf (_("\
1022 Can't timestamp and not clobber old files at the same time.\n"));
1023       print_usage ();
1024       exit (1);
1025     }
1026 #ifdef ENABLE_IPV6
1027   if (opt.ipv4_only && opt.ipv6_only)
1028     {
1029       printf (_("Cannot specify both --inet4-only and --inet6-only.\n"));
1030       print_usage ();
1031       exit (1);
1032     }
1033 #endif
1034   if (opt.output_document)
1035     {
1036       if (opt.convert_links 
1037           && (nurl > 1 || opt.page_requisites || opt.recursive))
1038         {
1039           fputs (_("\
1040 Cannot specify both -k and -O if multiple URLs are given, or in combination\n\
1041 with -p or -r. See the manual for details.\n\n"), stdout);
1042           print_usage ();
1043           exit (1);
1044         }
1045       if (opt.page_requisites
1046           || opt.recursive)
1047         {
1048           logprintf (LOG_NOTQUIET, "%s", _("\
1049 WARNING: combining -O with -r or -p will mean that all downloaded content\n\
1050 will be placed in the single file you specified.\n\n"));
1051         }
1052       if (opt.timestamping)
1053         {
1054           logprintf (LOG_NOTQUIET, "%s", _("\
1055 WARNING: timestamping does nothing in combination with -O. See the manual\n\
1056 for details.\n\n"));
1057           opt.timestamping = false;
1058         }
1059       if (opt.noclobber && file_exists_p(opt.output_document)) 
1060            { 
1061               /* Check if output file exists; if it does, exit. */
1062               logprintf (LOG_VERBOSE, _("File `%s' already there; not retrieving.\n"), opt.output_document);
1063               exit(1);
1064            }  
1065     }
1066
1067   if (opt.ask_passwd && opt.passwd)
1068     {
1069       printf (_("Cannot specify both --ask-password and --password.\n"));
1070       print_usage ();
1071       exit (1);
1072     }
1073
1074   if (!nurl && !opt.input_filename)
1075     {
1076       /* No URL specified.  */
1077       printf (_("%s: missing URL\n"), exec_name);
1078       print_usage ();
1079       printf ("\n");
1080       /* #### Something nicer should be printed here -- similar to the
1081          pre-1.5 `--help' page.  */
1082       printf (_("Try `%s --help' for more options.\n"), exec_name);
1083       exit (1);
1084     }
1085
1086 #ifdef ENABLE_IRI
1087   if (opt.enable_iri)
1088     {
1089       if (opt.locale && !check_encoding_name (opt.locale))
1090         opt.locale = NULL;
1091
1092       if (!opt.locale)
1093         opt.locale = find_locale ();
1094
1095       if (opt.encoding_remote && !check_encoding_name (opt.encoding_remote))
1096         opt.encoding_remote = NULL;
1097     }
1098 #else
1099   if (opt.enable_iri || opt.locale || opt.encoding_remote)
1100     {
1101       /* sXXXav : be more specific... */
1102       printf(_("This version does not have support for IRIs\n"));
1103       exit(1);
1104     }
1105 #endif
1106
1107   if (opt.ask_passwd)
1108     {
1109       opt.passwd = prompt_for_password ();
1110
1111       if (opt.passwd == NULL || opt.passwd[0] == '\0')
1112         exit (1);
1113     }
1114
1115 #ifdef MSDOS
1116   if (opt.wdebug)
1117      dbug_init();
1118   sock_init();
1119 #else
1120   if (opt.background)
1121     fork_to_background ();
1122 #endif
1123
1124   /* Initialize progress.  Have to do this after the options are
1125      processed so we know where the log file is.  */
1126   if (opt.verbose)
1127     set_progress_implementation (opt.progress_type);
1128
1129   /* Fill in the arguments.  */
1130   url = alloca_array (char *, nurl + 1);
1131   for (i = 0; i < nurl; i++, optind++)
1132     {
1133       char *rewritten = rewrite_shorthand_url (argv[optind]);
1134       if (rewritten)
1135         url[i] = rewritten;
1136       else
1137         url[i] = xstrdup (argv[optind]);
1138     }
1139   url[i] = NULL;
1140
1141   /* Initialize logging.  */
1142   log_init (opt.lfilename, append_to_log);
1143
1144   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n", version_string,
1145            OS_TYPE));
1146
1147   /* Open the output filename if necessary.  */
1148   if (opt.output_document)
1149     {
1150       if (HYPHENP (opt.output_document))
1151         {
1152 #ifdef WINDOWS
1153           FILE *result;
1154           result = freopen (NULL, "wb", stdout);
1155           if (result == NULL)
1156             {
1157               logputs (LOG_NOTQUIET, _("\
1158 WARNING: Can't reopen standard output in binary mode;\n\
1159          downloaded file may contain inappropriate line endings.\n"));
1160             }
1161 #endif
1162           output_stream = stdout;
1163         }
1164       else
1165         {
1166           struct_fstat st;
1167           output_stream = fopen (opt.output_document,
1168                                  opt.always_rest ? "ab" : "wb");
1169           if (output_stream == NULL)
1170             {
1171               perror (opt.output_document);
1172               exit (1);
1173             }
1174           if (fstat (fileno (output_stream), &st) == 0 && S_ISREG (st.st_mode))
1175             output_stream_regular = true;
1176         }
1177     }
1178
1179 #ifdef WINDOWS
1180   ws_startup ();
1181 #endif
1182
1183 #ifdef SIGHUP
1184   /* Setup the signal handler to redirect output when hangup is
1185      received.  */
1186   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1187     signal(SIGHUP, redirect_output_signal);
1188 #endif
1189   /* ...and do the same for SIGUSR1.  */
1190 #ifdef SIGUSR1
1191   signal (SIGUSR1, redirect_output_signal);
1192 #endif
1193 #ifdef SIGPIPE
1194   /* Writing to a closed socket normally signals SIGPIPE, and the
1195      process exits.  What we want is to ignore SIGPIPE and just check
1196      for the return value of write().  */
1197   signal (SIGPIPE, SIG_IGN);
1198 #endif
1199 #ifdef SIGWINCH
1200   signal (SIGWINCH, progress_handle_sigwinch);
1201 #endif
1202
1203   status = RETROK;              /* initialize it, just-in-case */
1204   /* Retrieve the URLs from argument list.  */
1205   for (t = url; *t; t++)
1206     {
1207       char *filename = NULL, *redirected_URL = NULL;
1208       int dt;
1209
1210       if ((opt.recursive || opt.page_requisites)
1211           && (url_scheme (*t) != SCHEME_FTP || url_uses_proxy (*t)))
1212         {
1213           int old_follow_ftp = opt.follow_ftp;
1214
1215           /* Turn opt.follow_ftp on in case of recursive FTP retrieval */
1216           if (url_scheme (*t) == SCHEME_FTP)
1217             opt.follow_ftp = 1;
1218
1219           status = retrieve_tree (*t, NULL);
1220
1221           opt.follow_ftp = old_follow_ftp;
1222         }
1223       else
1224         {
1225           struct iri *i = iri_new ();
1226           set_uri_encoding (i, opt.locale, true);
1227           status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt,
1228                                  opt.recursive, i);
1229           iri_free (i);
1230         }
1231
1232       if (opt.delete_after && file_exists_p(filename))
1233         {
1234           DEBUGP (("Removing file due to --delete-after in main():\n"));
1235           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
1236           if (unlink (filename))
1237             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1238         }
1239
1240       xfree_null (redirected_URL);
1241       xfree_null (filename);
1242     }
1243
1244   /* And then from the input file, if any.  */
1245   if (opt.input_filename)
1246     {
1247       int count;
1248       status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
1249       if (!count)
1250         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
1251                    opt.input_filename);
1252     }
1253
1254   /* Print broken links. */
1255   if (opt.recursive && opt.spider)
1256     {
1257       print_broken_links();
1258     }
1259   
1260   /* Print the downloaded sum.  */
1261   if ((opt.recursive || opt.page_requisites
1262        || nurl > 1
1263        || (opt.input_filename && total_downloaded_bytes != 0))
1264       &&
1265       total_downloaded_bytes != 0)
1266     {
1267       logprintf (LOG_NOTQUIET,
1268                  _("FINISHED --%s--\nDownloaded: %d files, %s in %s (%s)\n"),
1269                  datetime_str (time (NULL)),
1270                  opt.numurls,
1271                  human_readable (total_downloaded_bytes),
1272                  secs_to_human_time (total_download_time),
1273                  retr_rate (total_downloaded_bytes, total_download_time));
1274       /* Print quota warning, if exceeded.  */
1275       if (opt.quota && total_downloaded_bytes > opt.quota)
1276         logprintf (LOG_NOTQUIET,
1277                    _("Download quota of %s EXCEEDED!\n"),
1278                    human_readable (opt.quota));
1279     }
1280
1281   if (opt.cookies_output)
1282     save_cookies ();
1283
1284   if (opt.convert_links && !opt.delete_after)
1285     convert_all_links ();
1286
1287   log_close ();
1288   for (i = 0; i < nurl; i++)
1289     xfree (url[i]);
1290   cleanup ();
1291
1292   if (status == RETROK)
1293     return 0;
1294   else
1295     return 1;
1296 }
1297 #endif /* TESTING */
1298 \f
1299 #if defined(SIGHUP) || defined(SIGUSR1)
1300
1301 /* So the signal_name check doesn't blow when only one is available. */
1302 #ifndef SIGHUP
1303 # define SIGHUP -1
1304 #endif
1305 #ifndef SIGUSR1
1306 # define SIGUSR1 -1
1307 #endif
1308
1309 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
1310    will proceed operation as usual, trying to write into a log file.
1311    If that is impossible, the output will be turned off.  */
1312
1313 static void
1314 redirect_output_signal (int sig)
1315 {
1316   const char *signal_name = (sig == SIGHUP ? "SIGHUP" :
1317                              (sig == SIGUSR1 ? "SIGUSR1" :
1318                               "WTF?!"));
1319   log_request_redirect_output (signal_name);
1320   progress_schedule_redirect ();
1321   signal (sig, redirect_output_signal);
1322 }
1323 #endif
1324
1325 /*
1326  * vim: et ts=2 sw=2
1327  */