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