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
777/* Foxconn modify start, Jesse Chen, 05/16/2013 @ http/ftp download*/
778#define MAX_XSS_CONVERT_LEN 5   /* strlen("&#40;") */
779static int decode_url(char *str_in_out, unsigned int str_out_len)
780{
781    int  i = 0;
782    int  j = 0;
783    int  i_len = 0;
784    char *buf = NULL;
785    int  ret = 0;
786
787    if (NULL == str_in_out)
788    {
789        ret = -1;
790        goto out;
791    }
792
793    i_len = strlen(str_in_out);
794
795    if (0 == i_len || 0 == str_out_len)
796    {
797        ret = -1;
798        goto out;
799    }
800    buf = str_in_out;
801    if (NULL == buf)
802    {
803        ret = -2;
804        goto out;
805    }
806    buf = malloc((MAX_XSS_CONVERT_LEN * i_len) + 1);
807
808    for (i=0; i<i_len; i++)
809    {
810        if (('%' == str_in_out[i])&&('2' == str_in_out[i+1])&&('6' == str_in_out[i+2]))
811        {
812            sprintf(&buf[j], "&");
813            j++;
814            i+=2;
815        }
816        else
817            buf[j++] = str_in_out[i];
818    }
819    buf[j] = '\0';
820    sprintf(str_in_out, "%s", buf);
821    if (NULL != buf)
822        free(buf);
823out:
824    return ret;
825}
826/* Foxconn modify start, Jesse Chen, 05/16/2013 @ http/ftp download*/
827
828static void
829print_version (void)
830{
831  const char *wgetrc_title  = _("Wgetrc: ");
832  const char *locale_title  = _("Locale: ");
833  const char *compile_title = _("Compile: ");
834  const char *link_title    = _("Link: ");
835  char *line;
836  char *env_wgetrc, *user_wgetrc;
837  int i;
838
839#ifdef __VMS
840  printf (_("GNU Wget %s built on VMS %s %s.\n\n"),
841   version_string, vms_arch(), vms_vers());
842#else /* def __VMS */
843  printf (_("GNU Wget %s built on %s.\n\n"), version_string, OS_TYPE);
844#endif /* def __VMS */
845  /* compiled_features is a char*[]. We limit the characters per
846     line to MAX_CHARS_PER_LINE and prefix each line with a constant
847     number of spaces for proper alignment. */
848  for (i = 0; compiled_features[i] != NULL; )
849    {
850      int line_length = MAX_CHARS_PER_LINE;
851      while ((line_length > 0) && (compiled_features[i] != NULL))
852        {
853          printf ("%s ", compiled_features[i]);
854          line_length -= strlen (compiled_features[i]) + 2;
855          i++;
856        }
857      printf ("\n");
858    }
859  printf ("\n");
860  /* Handle the case when $WGETRC is unset and $HOME/.wgetrc is
861     absent. */
862  printf ("%s\n", wgetrc_title);
863  env_wgetrc = wgetrc_env_file_name ();
864  if (env_wgetrc && *env_wgetrc)
865    {
866      printf (_("    %s (env)\n"), env_wgetrc);
867      xfree (env_wgetrc);
868    }
869  user_wgetrc = wgetrc_user_file_name ();
870  if (user_wgetrc)
871    {
872      printf (_("    %s (user)\n"), user_wgetrc);
873      xfree (user_wgetrc);
874    }
875#ifdef SYSTEM_WGETRC
876  printf (_("    %s (system)\n"), SYSTEM_WGETRC);
877#endif
878
879#ifdef ENABLE_NLS
880  format_and_print_line (locale_title,
881                        LOCALEDIR,
882                        MAX_CHARS_PER_LINE);
883#endif /* def ENABLE_NLS */
884
885  format_and_print_line (compile_title,
886			 compilation_string,
887			 MAX_CHARS_PER_LINE);
888
889  format_and_print_line (link_title,
890			 link_string,
891			 MAX_CHARS_PER_LINE);
892
893  printf ("\n");
894  /* TRANSLATORS: When available, an actual copyright character
895     (cirle-c) should be used in preference to "(C)". */
896  fputs (_("\
897Copyright (C) 2009 Free Software Foundation, Inc.\n"), stdout);
898  fputs (_("\
899License GPLv3+: GNU GPL version 3 or later\n\
900<http://www.gnu.org/licenses/gpl.html>.\n\
901This is free software: you are free to change and redistribute it.\n\
902There is NO WARRANTY, to the extent permitted by law.\n"), stdout);
903  /* TRANSLATORS: When available, please use the proper diacritics for
904     names such as this one. See en_US.po for reference. */
905  fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"),
906         stdout);
907  fputs (_("Currently maintained by Micah Cowan <micah@cowan.name>.\n"),
908         stdout);
909  fputs (_("Please send bug reports and questions to <bug-wget@gnu.org>.\n"),
910         stdout);
911  exit (0);
912}
913
914char *program_name; /* Needed by lib/error.c. */
915
916int
917main (int argc, char **argv)
918{
919  char **url, **t;
920  int i, ret, longindex;
921  int nurl, status;
922  bool append_to_log = false;
923
924  program_name = argv[0];
925
926  i18n_initialize ();
927
928  /* Construct the name of the executable, without the directory part.  */
929  exec_name = strrchr (argv[0], PATH_SEPARATOR);
930  if (!exec_name)
931    exec_name = argv[0];
932  else
933    ++exec_name;
934
935#ifdef WINDOWS
936  /* Drop extension (typically .EXE) from executable filename. */
937  windows_main ((char **) &exec_name);
938#endif
939
940  /* Set option defaults; read the system wgetrc and ~/.wgetrc.  */
941  initialize ();
942
943  init_switches ();
944  longindex = -1;
945  while ((ret = getopt_long (argc, argv,
946                             short_options, long_options, &longindex)) != -1)
947    {
948      int val;
949      struct cmdline_option *opt;
950
951      /* If LONGINDEX is unchanged, it means RET is referring a short
952         option.  */
953      if (longindex == -1)
954        {
955          if (ret == '?')
956            {
957              print_usage ();
958              printf ("\n");
959              printf (_("Try `%s --help' for more options.\n"), exec_name);
960              exit (2);
961            }
962          /* Find the short option character in the mapping.  */
963          longindex = optmap[ret - 32];
964        }
965      val = long_options[longindex].val;
966
967      /* Use the retrieved value to locate the option in the
968         option_data array, and to see if we're dealing with the
969         negated "--no-FOO" variant of the boolean option "--foo".  */
970      opt = &option_data[val & ~BOOLEAN_NEG_MARKER];
971      switch (opt->type)
972        {
973        case OPT_VALUE:
974          setoptval (opt->data, optarg, opt->long_name);
975          break;
976        case OPT_BOOLEAN:
977          if (optarg)
978            /* The user has specified a value -- use it. */
979            setoptval (opt->data, optarg, opt->long_name);
980          else
981            {
982              /* NEG is true for `--no-FOO' style boolean options. */
983              bool neg = !!(val & BOOLEAN_NEG_MARKER);
984              setoptval (opt->data, neg ? "0" : "1", opt->long_name);
985            }
986          break;
987        case OPT_FUNCALL:
988          {
989            void (*func) (void) = (void (*) (void)) opt->data;
990            func ();
991          }
992          break;
993        case OPT__APPEND_OUTPUT:
994          setoptval ("logfile", optarg, opt->long_name);
995          append_to_log = true;
996          break;
997        case OPT__EXECUTE:
998          run_command (optarg);
999          break;
1000        case OPT__NO:
1001          {
1002            /* We support real --no-FOO flags now, but keep these
1003               short options for convenience and backward
1004               compatibility.  */
1005            char *p;
1006            for (p = optarg; *p; p++)
1007              switch (*p)
1008                {
1009                case 'v':
1010                  setoptval ("verbose", "0", opt->long_name);
1011                  break;
1012                case 'H':
1013                  setoptval ("addhostdir", "0", opt->long_name);
1014                  break;
1015                case 'd':
1016                  setoptval ("dirstruct", "0", opt->long_name);
1017                  break;
1018                case 'c':
1019                  setoptval ("noclobber", "1", opt->long_name);
1020                  break;
1021                case 'p':
1022                  setoptval ("noparent", "1", opt->long_name);
1023                  break;
1024                default:
1025                  printf (_("%s: illegal option -- `-n%c'\n"), exec_name, *p);
1026                  print_usage ();
1027                  printf ("\n");
1028                  printf (_("Try `%s --help' for more options.\n"), exec_name);
1029                  exit (1);
1030                }
1031            break;
1032          }
1033        case OPT__PARENT:
1034        case OPT__CLOBBER:
1035          {
1036            /* The wgetrc commands are named noparent and noclobber,
1037               so we must revert the meaning of the cmdline options
1038               before passing the value to setoptval.  */
1039            bool flag = true;
1040            if (optarg)
1041              flag = (*optarg == '1' || c_tolower (*optarg) == 'y'
1042                      || (c_tolower (optarg[0]) == 'o'
1043                          && c_tolower (optarg[1]) == 'n'));
1044            setoptval (opt->type == OPT__PARENT ? "noparent" : "noclobber",
1045                       flag ? "0" : "1", opt->long_name);
1046            break;
1047          }
1048        case OPT__DONT_REMOVE_LISTING:
1049          setoptval ("removelisting", "0", opt->long_name);
1050          break;
1051        }
1052
1053      longindex = -1;
1054    }
1055
1056  nurl = argc - optind;
1057  /* Foxconn modify start, Jesse Chen, 05/16/2013 @ http/ftp download*/
1058  decode_url(argv[optind],strlen(argv[optind]));
1059  /* Foxconn modify start, Jesse Chen, 05/16/2013 @ http/ftp download*/
1060  /* All user options have now been processed, so it's now safe to do
1061     interoption dependency checks. */
1062
1063  if (opt.reclevel == 0)
1064      opt.reclevel = INFINITE_RECURSION; /* see recur.h for commentary */
1065
1066  if (opt.spider || opt.delete_after)
1067      opt.no_dirstruct = true;
1068
1069  if (opt.page_requisites && !opt.recursive)
1070    {
1071      /* Don't set opt.recursive here because it would confuse the FTP
1072         code.  Instead, call retrieve_tree below when either
1073         page_requisites or recursive is requested.  */
1074      opt.reclevel = 0;
1075      if (!opt.no_dirstruct)
1076        opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
1077    }
1078
1079  if (opt.verbose == -1)
1080    opt.verbose = !opt.quiet;
1081
1082  /* Sanity checks.  */
1083  if (opt.verbose && opt.quiet)
1084    {
1085      printf (_("Can't be verbose and quiet at the same time.\n"));
1086      print_usage ();
1087      exit (1);
1088    }
1089  if (opt.timestamping && opt.noclobber)
1090    {
1091      printf (_("\
1092Can't timestamp and not clobber old files at the same time.\n"));
1093      print_usage ();
1094      exit (1);
1095    }
1096#ifdef ENABLE_IPV6
1097  if (opt.ipv4_only && opt.ipv6_only)
1098    {
1099      printf (_("Cannot specify both --inet4-only and --inet6-only.\n"));
1100      print_usage ();
1101      exit (1);
1102    }
1103#endif
1104  if (opt.output_document)
1105    {
1106      if (opt.convert_links
1107          && (nurl > 1 || opt.page_requisites || opt.recursive))
1108        {
1109          fputs (_("\
1110Cannot specify both -k and -O if multiple URLs are given, or in combination\n\
1111with -p or -r. See the manual for details.\n\n"), stdout);
1112          print_usage ();
1113          exit (1);
1114        }
1115      if (opt.page_requisites
1116          || opt.recursive)
1117        {
1118          logprintf (LOG_NOTQUIET, "%s", _("\
1119WARNING: combining -O with -r or -p will mean that all downloaded content\n\
1120will be placed in the single file you specified.\n\n"));
1121        }
1122      if (opt.timestamping)
1123        {
1124          logprintf (LOG_NOTQUIET, "%s", _("\
1125WARNING: timestamping does nothing in combination with -O. See the manual\n\
1126for details.\n\n"));
1127          opt.timestamping = false;
1128        }
1129      if (opt.noclobber && file_exists_p(opt.output_document))
1130           {
1131              /* Check if output file exists; if it does, exit. */
1132              logprintf (LOG_VERBOSE, _("File `%s' already there; not retrieving.\n"), opt.output_document);
1133              exit(1);
1134           }
1135    }
1136
1137  if (opt.ask_passwd && opt.passwd)
1138    {
1139      printf (_("Cannot specify both --ask-password and --password.\n"));
1140      print_usage ();
1141      exit (1);
1142    }
1143
1144  if (!nurl && !opt.input_filename)
1145    {
1146      /* No URL specified.  */
1147      printf (_("%s: missing URL\n"), exec_name);
1148      print_usage ();
1149      printf ("\n");
1150      /* #### Something nicer should be printed here -- similar to the
1151         pre-1.5 `--help' page.  */
1152      printf (_("Try `%s --help' for more options.\n"), exec_name);
1153      exit (1);
1154    }
1155
1156#ifdef ENABLE_IRI
1157  if (opt.enable_iri)
1158    {
1159      if (opt.locale && !check_encoding_name (opt.locale))
1160        opt.locale = NULL;
1161
1162      if (!opt.locale)
1163        opt.locale = find_locale ();
1164
1165      if (opt.encoding_remote && !check_encoding_name (opt.encoding_remote))
1166        opt.encoding_remote = NULL;
1167    }
1168#else
1169  if (opt.enable_iri || opt.locale || opt.encoding_remote)
1170    {
1171      /* sXXXav : be more specific... */
1172      printf(_("This version does not have support for IRIs\n"));
1173      exit(1);
1174    }
1175#endif
1176
1177  if (opt.ask_passwd)
1178    {
1179      opt.passwd = prompt_for_password ();
1180
1181      if (opt.passwd == NULL || opt.passwd[0] == '\0')
1182        exit (1);
1183    }
1184
1185#ifdef USE_WATT32
1186  if (opt.wdebug)
1187     dbug_init();
1188  sock_init();
1189#else
1190  if (opt.background)
1191    fork_to_background ();
1192#endif
1193
1194  /* Initialize progress.  Have to do this after the options are
1195     processed so we know where the log file is.  */
1196  if (opt.verbose)
1197    set_progress_implementation (opt.progress_type);
1198
1199  /* Fill in the arguments.  */
1200  url = alloca_array (char *, nurl + 1);
1201  for (i = 0; i < nurl; i++, optind++)
1202    {
1203      char *rewritten = rewrite_shorthand_url (argv[optind]);
1204      if (rewritten)
1205        url[i] = rewritten;
1206      else
1207        url[i] = xstrdup (argv[optind]);
1208    }
1209  url[i] = NULL;
1210
1211  /* Initialize logging.  */
1212  log_init (opt.lfilename, append_to_log);
1213
1214  DEBUGP (("DEBUG output created by Wget %s on %s.\n\n",
1215           version_string, OS_TYPE));
1216
1217  /* Open the output filename if necessary.  */
1218
1219/* 2005-04-17 SMS.
1220   Note that having the output_stream ("-O") file opened here for an FTP
1221   URL rather than in getftp() (ftp.c) (and the http equivalent) rather
1222   limits the ability in VMS to open the file differently for ASCII
1223   versus binary FTP there.  (Of course, doing it here allows a open
1224   failure to be detected immediately, without first connecting to the
1225   server.)
1226*/
1227  if (opt.output_document)
1228    {
1229      if (HYPHENP (opt.output_document))
1230        {
1231#ifdef WINDOWS
1232          FILE *result;
1233          result = freopen ("CONOUT$", "wb", stdout);
1234          if (result == NULL)
1235            {
1236              logputs (LOG_NOTQUIET, _("\
1237WARNING: Can't reopen standard output in binary mode;\n\
1238         downloaded file may contain inappropriate line endings.\n"));
1239            }
1240#endif
1241          output_stream = stdout;
1242        }
1243      else
1244        {
1245          struct_fstat st;
1246
1247#ifdef __VMS
1248/* Common fopen() optional arguments:
1249   sequential access only, access callback function.
1250*/
1251# define FOPEN_OPT_ARGS , "fop=sqo", "acc", acc_cb, &open_id
1252          int open_id = 7;
1253#else /* def __VMS */
1254# define FOPEN_OPT_ARGS
1255#endif /* def __VMS [else] */
1256
1257          output_stream = fopen (opt.output_document,
1258                                 opt.always_rest ? "ab" : "wb"
1259                                 FOPEN_OPT_ARGS);
1260          if (output_stream == NULL)
1261            {
1262              perror (opt.output_document);
1263              exit (1);
1264            }
1265          if (fstat (fileno (output_stream), &st) == 0 && S_ISREG (st.st_mode))
1266            output_stream_regular = true;
1267        }
1268    }
1269
1270#ifdef __VMS
1271  /* Set global ODS5 flag according to the specified destination (if
1272     any), otherwise according to the current default device.
1273  */
1274  if (output_stream == NULL)
1275    {
1276      set_ods5_dest( "SYS$DISK");
1277    }
1278  else if (output_stream != stdout)
1279    {
1280      set_ods5_dest( opt.output_document);
1281    }
1282#endif /* def __VMS */
1283
1284#ifdef WINDOWS
1285  ws_startup ();
1286#endif
1287
1288#ifdef SIGHUP
1289  /* Setup the signal handler to redirect output when hangup is
1290     received.  */
1291  if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1292    signal(SIGHUP, redirect_output_signal);
1293#endif
1294  /* ...and do the same for SIGUSR1.  */
1295#ifdef SIGUSR1
1296  signal (SIGUSR1, redirect_output_signal);
1297#endif
1298#ifdef SIGPIPE
1299  /* Writing to a closed socket normally signals SIGPIPE, and the
1300     process exits.  What we want is to ignore SIGPIPE and just check
1301     for the return value of write().  */
1302  signal (SIGPIPE, SIG_IGN);
1303#endif
1304#ifdef SIGWINCH
1305  signal (SIGWINCH, progress_handle_sigwinch);
1306#endif
1307
1308  status = RETROK;              /* initialize it, just-in-case */
1309  /* Retrieve the URLs from argument list.  */
1310  for (t = url; *t; t++)
1311    {
1312      char *filename = NULL, *redirected_URL = NULL;
1313      int dt, url_err;
1314      /* Need to do a new struct iri every time, because
1315       * retrieve_url may modify it in some circumstances,
1316       * currently. */
1317      struct iri *iri = iri_new ();
1318      struct url *url_parsed;
1319
1320      set_uri_encoding (iri, opt.locale, true);
1321      url_parsed = url_parse (*t, &url_err, iri, true);
1322
1323      if (!url_parsed)
1324        {
1325          char *error = url_error (*t, url_err);
1326          logprintf (LOG_NOTQUIET, "%s: %s.\n",*t, error);
1327          xfree (error);
1328          status = URLERROR;
1329        }
1330      else
1331        {
1332          if ((opt.recursive || opt.page_requisites)
1333              && (url_scheme (*t) != SCHEME_FTP || url_uses_proxy (url_parsed)))
1334            {
1335              int old_follow_ftp = opt.follow_ftp;
1336
1337              /* Turn opt.follow_ftp on in case of recursive FTP retrieval */
1338              if (url_scheme (*t) == SCHEME_FTP)
1339                opt.follow_ftp = 1;
1340
1341              status = retrieve_tree (url_parsed, NULL);
1342
1343              opt.follow_ftp = old_follow_ftp;
1344            }
1345          else
1346          {
1347            status = retrieve_url (url_parsed, *t, &filename, &redirected_URL,
1348                                   NULL, &dt, opt.recursive, iri, true);
1349          }
1350
1351          if (opt.delete_after && file_exists_p(filename))
1352            {
1353              DEBUGP (("Removing file due to --delete-after in main():\n"));
1354              logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
1355              if (unlink (filename))
1356                logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1357            }
1358          xfree_null (redirected_URL);
1359          xfree_null (filename);
1360          url_free (url_parsed);
1361        }
1362      iri_free (iri);
1363    }
1364
1365  /* And then from the input file, if any.  */
1366  if (opt.input_filename)
1367    {
1368      int count;
1369      status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
1370      if (!count)
1371        logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
1372                   opt.input_filename);
1373    }
1374
1375  /* Print broken links. */
1376  if (opt.recursive && opt.spider)
1377    {
1378      print_broken_links();
1379    }
1380
1381  /* Print the downloaded sum.  */
1382  if ((opt.recursive || opt.page_requisites
1383       || nurl > 1
1384       || (opt.input_filename && total_downloaded_bytes != 0))
1385      &&
1386      total_downloaded_bytes != 0)
1387    {
1388      logprintf (LOG_NOTQUIET,
1389                 _("FINISHED --%s--\nDownloaded: %d files, %s in %s (%s)\n"),
1390                 datetime_str (time (NULL)),
1391                 numurls,
1392                 human_readable (total_downloaded_bytes),
1393                 secs_to_human_time (total_download_time),
1394                 retr_rate (total_downloaded_bytes, total_download_time));
1395      /* Print quota warning, if exceeded.  */
1396      if (opt.quota && total_downloaded_bytes > opt.quota)
1397        logprintf (LOG_NOTQUIET,
1398                   _("Download quota of %s EXCEEDED!\n"),
1399                   human_readable (opt.quota));
1400    }
1401
1402  if (opt.cookies_output)
1403    save_cookies ();
1404
1405  if (opt.convert_links && !opt.delete_after)
1406    convert_all_links ();
1407
1408  log_close ();
1409  for (i = 0; i < nurl; i++)
1410    xfree (url[i]);
1411  cleanup ();
1412
1413  return get_exit_status ();
1414}
1415#endif /* TESTING */
1416
1417#if defined(SIGHUP) || defined(SIGUSR1)
1418
1419/* So the signal_name check doesn't blow when only one is available. */
1420#ifndef SIGHUP
1421# define SIGHUP -1
1422#endif
1423#ifndef SIGUSR1
1424# define SIGUSR1 -1
1425#endif
1426
1427/* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
1428   will proceed operation as usual, trying to write into a log file.
1429   If that is impossible, the output will be turned off.  */
1430
1431static void
1432redirect_output_signal (int sig)
1433{
1434  const char *signal_name = (sig == SIGHUP ? "SIGHUP" :
1435                             (sig == SIGUSR1 ? "SIGUSR1" :
1436                              "WTF?!"));
1437  log_request_redirect_output (signal_name);
1438  progress_schedule_redirect ();
1439  signal (sig, redirect_output_signal);
1440}
1441#endif
1442
1443/*
1444 * vim: et ts=2 sw=2
1445 */
1446