]> sjero.net Git - wget/blob - src/main.c
[svn] Improvements/fixes to HTTP Content-Disposition header support.
[wget] / src / main.c
1 /* Command line parsing.
2    Copyright (C) 1996-2005 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 #include <config.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif /* HAVE_UNISTD_H */
37 #include <string.h>
38 #include <signal.h>
39 #ifdef HAVE_NLS
40 # include <locale.h>
41 #endif
42 #include <assert.h>
43 #include <errno.h>
44
45 #include "wget.h"
46 #include "utils.h"
47 #include "init.h"
48 #include "retr.h"
49 #include "recur.h"
50 #include "host.h"
51 #include "url.h"
52 #include "progress.h"           /* for progress_handle_sigwinch */
53 #include "convert.h"
54 #include "http.h"               /* for save_cookies */
55
56 /* On GNU system this will include system-wide getopt.h. */
57 #include "getopt.h"
58
59 #ifndef PATH_SEPARATOR
60 # define PATH_SEPARATOR '/'
61 #endif
62
63 struct options opt;
64
65 extern char *version_string;
66
67 #if defined(SIGHUP) || defined(SIGUSR1)
68 static void redirect_output_signal (int);
69 #endif
70
71 const char *exec_name;
72 \f
73 /* Initialize I18N/L10N.  That amounts to invoking setlocale, and
74    setting up gettext's message catalog using bindtextdomain and
75    textdomain.  Does nothing if NLS is disabled or missing.  */
76
77 static void
78 i18n_initialize (void)
79 {
80   /* HAVE_NLS implies existence of functions invoked here.  */
81 #ifdef HAVE_NLS
82   /* Set the current locale.  */
83   setlocale (LC_ALL, "");
84   /* Set the text message domain.  */
85   bindtextdomain ("wget", LOCALEDIR);
86   textdomain ("wget");
87 #endif /* HAVE_NLS */
88 }
89 \f
90 /* Definition of command-line options. */
91
92 static void print_help (void);
93 static void print_version (void);
94
95 #ifdef HAVE_SSL
96 # define IF_SSL(x) x
97 #else
98 # define IF_SSL(x) NULL
99 #endif
100
101 #ifdef ENABLE_DEBUG
102 # define WHEN_DEBUG(x) x
103 #else
104 # define WHEN_DEBUG(x) NULL
105 #endif
106
107 struct cmdline_option {
108   const char *long_name;
109   char short_name;
110   enum {
111     OPT_VALUE,
112     OPT_BOOLEAN,
113     OPT_FUNCALL,
114     /* Non-standard options that have to be handled specially in
115        main().  */
116     OPT__APPEND_OUTPUT,
117     OPT__CLOBBER,
118     OPT__DONT_REMOVE_LISTING,
119     OPT__EXECUTE,
120     OPT__NO,
121     OPT__PARENT
122   } type;
123   const void *data;             /* for standard options */
124   int argtype;                  /* for non-standard options */
125 };
126
127 static struct cmdline_option option_data[] =
128   {
129     { "accept", 'A', OPT_VALUE, "accept", -1 },
130     { "append-output", 'a', OPT__APPEND_OUTPUT, NULL, required_argument },
131     { "background", 'b', OPT_BOOLEAN, "background", -1 },
132     { "backup-converted", 'K', OPT_BOOLEAN, "backupconverted", -1 },
133     { "backups", 0, OPT_BOOLEAN, "backups", -1 },
134     { "base", 'B', OPT_VALUE, "base", -1 },
135     { "bind-address", 0, OPT_VALUE, "bindaddress", -1 },
136     { IF_SSL ("ca-certificate"), 0, OPT_VALUE, "cacertificate", -1 },
137     { IF_SSL ("ca-directory"), 0, OPT_VALUE, "cadirectory", -1 },
138     { "cache", 0, OPT_BOOLEAN, "cache", -1 },
139     { IF_SSL ("certificate"), 0, OPT_VALUE, "certificate", -1 },
140     { IF_SSL ("certificate-type"), 0, OPT_VALUE, "certificatetype", -1 },
141     { IF_SSL ("check-certificate"), 0, OPT_BOOLEAN, "checkcertificate", -1 },
142     { "clobber", 0, OPT__CLOBBER, NULL, optional_argument },
143     { "connect-timeout", 0, OPT_VALUE, "connecttimeout", -1 },
144     { "continue", 'c', OPT_BOOLEAN, "continue", -1 },
145     { "convert-links", 'k', OPT_BOOLEAN, "convertlinks", -1 },
146     { "content-disposition", 0, OPT_BOOLEAN, "contentdisposition", -1 },
147     { "cookies", 0, OPT_BOOLEAN, "cookies", -1 },
148     { "cut-dirs", 0, OPT_VALUE, "cutdirs", -1 },
149     { WHEN_DEBUG ("debug"), 'd', OPT_BOOLEAN, "debug", -1 },
150     { "delete-after", 0, OPT_BOOLEAN, "deleteafter", -1 },
151     { "directories", 0, OPT_BOOLEAN, "dirstruct", -1 },
152     { "directory-prefix", 'P', OPT_VALUE, "dirprefix", -1 },
153     { "dns-cache", 0, OPT_BOOLEAN, "dnscache", -1 },
154     { "dns-timeout", 0, OPT_VALUE, "dnstimeout", -1 },
155     { "domains", 'D', OPT_VALUE, "domains", -1 },
156     { "dont-remove-listing", 0, OPT__DONT_REMOVE_LISTING, NULL, no_argument },
157     { "dot-style", 0, OPT_VALUE, "dotstyle", -1 },
158     { "egd-file", 0, OPT_VALUE, "egdfile", -1 },
159     { "exclude-directories", 'X', OPT_VALUE, "excludedirectories", -1 },
160     { "exclude-domains", 0, OPT_VALUE, "excludedomains", -1 },
161     { "execute", 'e', OPT__EXECUTE, NULL, required_argument },
162     { "follow-ftp", 0, OPT_BOOLEAN, "followftp", -1 },
163     { "follow-tags", 0, OPT_VALUE, "followtags", -1 },
164     { "force-directories", 'x', OPT_BOOLEAN, "dirstruct", -1 },
165     { "force-html", 'F', OPT_BOOLEAN, "forcehtml", -1 },
166     { "ftp-password", 0, OPT_VALUE, "ftppassword", -1 },
167     { "ftp-user", 0, OPT_VALUE, "ftpuser", -1 },
168     { "glob", 0, OPT_BOOLEAN, "glob", -1 },
169     { "header", 0, OPT_VALUE, "header", -1 },
170     { "help", 'h', OPT_FUNCALL, (void *)print_help, no_argument },
171     { "host-directories", 0, OPT_BOOLEAN, "addhostdir", -1 },
172     { "html-extension", 'E', OPT_BOOLEAN, "htmlextension", -1 },
173     { "htmlify", 0, OPT_BOOLEAN, "htmlify", -1 },
174     { "http-keep-alive", 0, OPT_BOOLEAN, "httpkeepalive", -1 },
175     { "http-passwd", 0, OPT_VALUE, "httppassword", -1 }, /* deprecated */
176     { "http-password", 0, OPT_VALUE, "httppassword", -1 },
177     { "http-user", 0, OPT_VALUE, "httpuser", -1 },
178     { "ignore-case", 0, OPT_BOOLEAN, "ignorecase", -1 },
179     { "ignore-length", 0, OPT_BOOLEAN, "ignorelength", -1 },
180     { "ignore-tags", 0, OPT_VALUE, "ignoretags", -1 },
181     { "include-directories", 'I', OPT_VALUE, "includedirectories", -1 },
182 #ifdef ENABLE_IPV6
183     { "inet4-only", '4', OPT_BOOLEAN, "inet4only", -1 },
184     { "inet6-only", '6', OPT_BOOLEAN, "inet6only", -1 },
185 #endif
186     { "input-file", 'i', OPT_VALUE, "input", -1 },
187     { "keep-session-cookies", 0, OPT_BOOLEAN, "keepsessioncookies", -1 },
188     { "level", 'l', OPT_VALUE, "reclevel", -1 },
189     { "limit-rate", 0, OPT_VALUE, "limitrate", -1 },
190     { "load-cookies", 0, OPT_VALUE, "loadcookies", -1 },
191     { "mirror", 'm', OPT_BOOLEAN, "mirror", -1 },
192     { "no", 'n', OPT__NO, NULL, required_argument },
193     { "no-clobber", 0, OPT_BOOLEAN, "noclobber", -1 },
194     { "no-parent", 0, OPT_BOOLEAN, "noparent", -1 },
195     { "output-document", 'O', OPT_VALUE, "outputdocument", -1 },
196     { "output-file", 'o', OPT_VALUE, "logfile", -1 },
197     { "page-requisites", 'p', OPT_BOOLEAN, "pagerequisites", -1 },
198     { "parent", 0, OPT__PARENT, NULL, optional_argument },
199     { "passive-ftp", 0, OPT_BOOLEAN, "passiveftp", -1 },
200     { "password", 0, OPT_VALUE, "password", -1 },
201     { "post-data", 0, OPT_VALUE, "postdata", -1 },
202     { "post-file", 0, OPT_VALUE, "postfile", -1 },
203     { "prefer-family", 0, OPT_VALUE, "preferfamily", -1 },
204     { "preserve-permissions", 0, OPT_BOOLEAN, "preservepermissions", -1 },
205     { IF_SSL ("private-key"), 0, OPT_VALUE, "privatekey", -1 },
206     { IF_SSL ("private-key-type"), 0, OPT_VALUE, "privatekeytype", -1 },
207     { "progress", 0, OPT_VALUE, "progress", -1 },
208     { "protocol-directories", 0, OPT_BOOLEAN, "protocoldirectories", -1 },
209     { "proxy", 0, OPT_BOOLEAN, "useproxy", -1 },
210     { "proxy__compat", 'Y', OPT_VALUE, "useproxy", -1 }, /* back-compatible */
211     { "proxy-passwd", 0, OPT_VALUE, "proxypassword", -1 }, /* deprecated */
212     { "proxy-password", 0, OPT_VALUE, "proxypassword", -1 },
213     { "proxy-user", 0, OPT_VALUE, "proxyuser", -1 },
214     { "quiet", 'q', OPT_BOOLEAN, "quiet", -1 },
215     { "quota", 'Q', OPT_VALUE, "quota", -1 },
216     { "random-file", 0, OPT_VALUE, "randomfile", -1 },
217     { "random-wait", 0, OPT_BOOLEAN, "randomwait", -1 },
218     { "read-timeout", 0, OPT_VALUE, "readtimeout", -1 },
219     { "recursive", 'r', OPT_BOOLEAN, "recursive", -1 },
220     { "referer", 0, OPT_VALUE, "referer", -1 },
221     { "reject", 'R', OPT_VALUE, "reject", -1 },
222     { "relative", 'L', OPT_BOOLEAN, "relativeonly", -1 },
223     { "remove-listing", 0, OPT_BOOLEAN, "removelisting", -1 },
224     { "restrict-file-names", 0, OPT_BOOLEAN, "restrictfilenames", -1 },
225     { "retr-symlinks", 0, OPT_BOOLEAN, "retrsymlinks", -1 },
226     { "retry-connrefused", 0, OPT_BOOLEAN, "retryconnrefused", -1 },
227     { "save-cookies", 0, OPT_VALUE, "savecookies", -1 },
228     { "save-headers", 0, OPT_BOOLEAN, "saveheaders", -1 },
229     { IF_SSL ("secure-protocol"), 0, OPT_VALUE, "secureprotocol", -1 },
230     { "server-response", 'S', OPT_BOOLEAN, "serverresponse", -1 },
231     { "span-hosts", 'H', OPT_BOOLEAN, "spanhosts", -1 },
232     { "spider", 0, OPT_BOOLEAN, "spider", -1 },
233     { "strict-comments", 0, OPT_BOOLEAN, "strictcomments", -1 },
234     { "timeout", 'T', OPT_VALUE, "timeout", -1 },
235     { "timestamping", 'N', OPT_BOOLEAN, "timestamping", -1 },
236     { "tries", 't', OPT_VALUE, "tries", -1 },
237     { "user", 0, OPT_VALUE, "user", -1 },
238     { "user-agent", 'U', OPT_VALUE, "useragent", -1 },
239     { "verbose", 'v', OPT_BOOLEAN, "verbose", -1 },
240     { "verbose", 0, OPT_BOOLEAN, "verbose", -1 },
241     { "version", 'V', OPT_FUNCALL, (void *) print_version, no_argument },
242     { "wait", 'w', OPT_VALUE, "wait", -1 },
243     { "waitretry", 0, OPT_VALUE, "waitretry", -1 },
244   };
245
246 #undef WHEN_DEBUG
247 #undef IF_SSL
248
249 /* Return a string that contains S with "no-" prepended.  The string
250    is NUL-terminated and allocated off static storage at Wget
251    startup.  */
252
253 static char *
254 no_prefix (const char *s)
255 {
256   static char buffer[1024];
257   static char *p = buffer;
258
259   char *cp = p;
260   int size = 3 + strlen (s) + 1;  /* "no-STRING\0" */
261   if (p + size >= buffer + sizeof (buffer))
262     abort ();
263
264   cp[0] = 'n', cp[1] = 'o', cp[2] = '-';
265   strcpy (cp + 3, s);
266   p += size;
267   return cp;
268 }
269
270 /* The arguments that that main passes to getopt_long. */
271 static struct option long_options[2 * countof (option_data) + 1];
272 static char short_options[128];
273
274 /* Mapping between short option chars and option_data indices. */
275 static unsigned char optmap[96];
276
277 /* Marker for `--no-FOO' values in long_options.  */
278 #define BOOLEAN_NEG_MARKER 1024
279
280 /* Initialize the long_options array used by getopt_long from the data
281    in option_data.  */
282
283 static void
284 init_switches (void)
285 {
286   char *p = short_options;
287   int i, o = 0;
288   for (i = 0; i < countof (option_data); i++)
289     {
290       struct cmdline_option *opt = &option_data[i];
291       struct option *longopt;
292
293       if (!opt->long_name)
294         /* The option is disabled. */
295         continue;
296
297       longopt = &long_options[o++];
298       longopt->name = opt->long_name;
299       longopt->val = i;
300       if (opt->short_name)
301         {
302           *p++ = opt->short_name;
303           optmap[opt->short_name - 32] = longopt - long_options;
304         }
305       switch (opt->type)
306         {
307         case OPT_VALUE:
308           longopt->has_arg = required_argument;
309           if (opt->short_name)
310             *p++ = ':';
311           break;
312         case OPT_BOOLEAN:
313           /* Specify an optional argument for long options, so that
314              --option=off works the same as --no-option, for
315              compatibility with pre-1.10 Wget.  However, don't specify
316              optional arguments short-option booleans because they
317              prevent combining of short options.  */
318           longopt->has_arg = optional_argument;
319           /* For Boolean options, add the "--no-FOO" variant, which is
320              identical to "--foo", except it has opposite meaning and
321              it doesn't allow an argument.  */
322           longopt = &long_options[o++];
323           longopt->name = no_prefix (opt->long_name);
324           longopt->has_arg = no_argument;
325           /* Mask the value so we'll be able to recognize that we're
326              dealing with the false value.  */
327           longopt->val = i | BOOLEAN_NEG_MARKER;
328           break;
329         default:
330           assert (opt->argtype != -1);
331           longopt->has_arg = opt->argtype;
332           if (opt->short_name)
333             {
334               if (longopt->has_arg == required_argument)
335                 *p++ = ':';
336               /* Don't handle optional_argument */
337             }
338         }
339     }
340   /* Terminate short_options. */
341   *p = '\0';
342   /* No need for xzero(long_options[o]) because its storage is static
343      and it will be zeroed by default.  */
344   assert (o <= countof (long_options));
345 }
346
347 /* Print the usage message.  */
348 static void
349 print_usage (void)
350 {
351   printf (_("Usage: %s [OPTION]... [URL]...\n"), exec_name);
352 }
353
354 /* Print the help message, describing all the available options.  If
355    you add an option, be sure to update this list.  */
356 static void
357 print_help (void)
358 {
359   /* We split the help text this way to ease translation of individual
360      entries.  */
361   static const char *help[] = {
362     "\n",
363     N_("\
364 Mandatory arguments to long options are mandatory for short options too.\n\n"),
365     N_("\
366 Startup:\n"),
367     N_("\
368   -V,  --version           display the version of Wget and exit.\n"),
369     N_("\
370   -h,  --help              print this help.\n"),
371     N_("\
372   -b,  --background        go to background after startup.\n"),
373     N_("\
374   -e,  --execute=COMMAND   execute a `.wgetrc'-style command.\n"),
375     "\n",
376
377     N_("\
378 Logging and input file:\n"),
379     N_("\
380   -o,  --output-file=FILE    log messages to FILE.\n"),
381     N_("\
382   -a,  --append-output=FILE  append messages to FILE.\n"),
383 #ifdef ENABLE_DEBUG
384     N_("\
385   -d,  --debug               print lots of debugging information.\n"),
386 #endif
387     N_("\
388   -q,  --quiet               quiet (no output).\n"),
389     N_("\
390   -v,  --verbose             be verbose (this is the default).\n"),
391     N_("\
392   -nv, --no-verbose          turn off verboseness, without being quiet.\n"),
393     N_("\
394   -i,  --input-file=FILE     download URLs found in FILE.\n"),
395     N_("\
396   -F,  --force-html          treat input file as HTML.\n"),
397     N_("\
398   -B,  --base=URL            prepends URL to relative links in -F -i file.\n"),
399     "\n",
400
401     N_("\
402 Download:\n"),
403     N_("\
404   -t,  --tries=NUMBER            set number of retries to NUMBER (0 unlimits).\n"),
405     N_("\
406        --retry-connrefused       retry even if connection is refused.\n"),
407     N_("\
408   -O,  --output-document=FILE    write documents to FILE.\n"),
409     N_("\
410   -nc, --no-clobber              skip downloads that would download to\n\
411                                  existing files.\n"),
412     N_("\
413   -c,  --continue                resume getting a partially-downloaded file.\n"),
414     N_("\
415        --progress=TYPE           select progress gauge type.\n"),
416     N_("\
417   -N,  --timestamping            don't re-retrieve files unless newer than\n\
418                                  local.\n"),
419     N_("\
420   -S,  --server-response         print server response.\n"),
421     N_("\
422        --spider                  don't download anything.\n"),
423     N_("\
424   -T,  --timeout=SECONDS         set all timeout values to SECONDS.\n"),
425     N_("\
426        --dns-timeout=SECS        set the DNS lookup timeout to SECS.\n"),
427     N_("\
428        --connect-timeout=SECS    set the connect timeout to SECS.\n"),
429     N_("\
430        --read-timeout=SECS       set the read timeout to SECS.\n"),
431     N_("\
432   -w,  --wait=SECONDS            wait SECONDS between retrievals.\n"),
433     N_("\
434        --waitretry=SECONDS       wait 1..SECONDS between retries of a retrieval.\n"),
435     N_("\
436        --random-wait             wait from 0...2*WAIT secs between retrievals.\n"),
437     N_("\
438   -Y,  --proxy                   explicitly turn on proxy.\n"),
439     N_("\
440        --no-proxy                explicitly turn off proxy.\n"),
441     N_("\
442   -Q,  --quota=NUMBER            set retrieval quota to NUMBER.\n"),
443     N_("\
444        --bind-address=ADDRESS    bind to ADDRESS (hostname or IP) on local host.\n"),
445     N_("\
446        --limit-rate=RATE         limit download rate to RATE.\n"),
447     N_("\
448        --no-dns-cache            disable caching DNS lookups.\n"),
449     N_("\
450        --restrict-file-names=OS  restrict chars in file names to ones OS allows.\n"),
451     N_("\
452        --ignore-case             ignore case when matching files/directories.\n"),
453 #ifdef ENABLE_IPV6
454     N_("\
455   -4,  --inet4-only              connect only to IPv4 addresses.\n"),
456     N_("\
457   -6,  --inet6-only              connect only to IPv6 addresses.\n"),
458     N_("\
459        --prefer-family=FAMILY    connect first to addresses of specified family,\n\
460                                  one of IPv6, IPv4, or none.\n"),
461 #endif
462     N_("\
463        --user=USER               set both ftp and http user to USER.\n"),
464     N_("\
465        --password=PASS           set both ftp and http password to PASS.\n"),
466     "\n",
467
468     N_("\
469 Directories:\n"),
470     N_("\
471   -nd, --no-directories           don't create directories.\n"),
472     N_("\
473   -x,  --force-directories        force creation of directories.\n"),
474     N_("\
475   -nH, --no-host-directories      don't create host directories.\n"),
476     N_("\
477        --protocol-directories     use protocol name in directories.\n"),
478     N_("\
479   -P,  --directory-prefix=PREFIX  save files to PREFIX/...\n"),
480     N_("\
481        --cut-dirs=NUMBER          ignore NUMBER remote directory components.\n"),
482     "\n",
483
484     N_("\
485 HTTP options:\n"),
486     N_("\
487        --http-user=USER        set http user to USER.\n"),
488     N_("\
489        --http-password=PASS    set http password to PASS.\n"),
490     N_("\
491        --no-cache              disallow server-cached data.\n"),
492     N_("\
493   -E,  --html-extension        save HTML documents with `.html' extension.\n"),
494     N_("\
495        --ignore-length         ignore `Content-Length' header field.\n"),
496     N_("\
497        --header=STRING         insert STRING among the headers.\n"),
498     N_("\
499        --proxy-user=USER       set USER as proxy username.\n"),
500     N_("\
501        --proxy-password=PASS   set PASS as proxy password.\n"),
502     N_("\
503        --referer=URL           include `Referer: URL' header in HTTP request.\n"),
504     N_("\
505        --save-headers          save the HTTP headers to file.\n"),
506     N_("\
507   -U,  --user-agent=AGENT      identify as AGENT instead of Wget/VERSION.\n"),
508     N_("\
509        --no-http-keep-alive    disable HTTP keep-alive (persistent connections).\n"),
510     N_("\
511        --no-cookies            don't use cookies.\n"),
512     N_("\
513        --load-cookies=FILE     load cookies from FILE before session.\n"),
514     N_("\
515        --save-cookies=FILE     save cookies to FILE after session.\n"),
516     N_("\
517        --keep-session-cookies  load and save session (non-permanent) cookies.\n"),
518     N_("\
519        --post-data=STRING      use the POST method; send STRING as the data.\n"),
520     N_("\
521        --post-file=FILE        use the POST method; send contents of FILE.\n"),
522     N_("\
523        --no-content-disposition  don't honor Content-Disposition header.\n"),
524     "\n",
525
526 #ifdef HAVE_SSL
527     N_("\
528 HTTPS (SSL/TLS) options:\n"),
529     N_("\
530        --secure-protocol=PR     choose secure protocol, one of auto, SSLv2,\n\
531                                 SSLv3, and TLSv1.\n"),
532     N_("\
533        --no-check-certificate   don't validate the server's certificate.\n"),
534     N_("\
535        --certificate=FILE       client certificate file.\n"),
536     N_("\
537        --certificate-type=TYPE  client certificate type, PEM or DER.\n"),
538     N_("\
539        --private-key=FILE       private key file.\n"),
540     N_("\
541        --private-key-type=TYPE  private key type, PEM or DER.\n"),
542     N_("\
543        --ca-certificate=FILE    file with the bundle of CA's.\n"),
544     N_("\
545        --ca-directory=DIR       directory where hash list of CA's is stored.\n"),
546     N_("\
547        --random-file=FILE       file with random data for seeding the SSL PRNG.\n"),
548     N_("\
549        --egd-file=FILE          file naming the EGD socket with random data.\n"),
550     "\n",
551 #endif /* HAVE_SSL */
552
553     N_("\
554 FTP options:\n"),
555     N_("\
556        --ftp-user=USER         set ftp user to USER.\n"),
557     N_("\
558        --ftp-password=PASS     set ftp password to PASS.\n"),
559     N_("\
560        --no-remove-listing     don't remove `.listing' files.\n"),
561     N_("\
562        --no-glob               turn off FTP file name globbing.\n"),
563     N_("\
564        --no-passive-ftp        disable the \"passive\" transfer mode.\n"),
565     N_("\
566        --retr-symlinks         when recursing, get linked-to files (not dir).\n"),
567     N_("\
568        --preserve-permissions  preserve remote file permissions.\n"),
569     "\n",
570
571     N_("\
572 Recursive download:\n"),
573     N_("\
574   -r,  --recursive          specify recursive download.\n"),
575     N_("\
576   -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n"),
577     N_("\
578        --delete-after       delete files locally after downloading them.\n"),
579     N_("\
580   -k,  --convert-links      make links in downloaded HTML point to local files.\n"),
581     N_("\
582   -K,  --backup-converted   before converting file X, back up as X.orig.\n"),
583     N_("\
584   -m,  --mirror             shortcut for -N -r -l inf --no-remove-listing.\n"),
585     N_("\
586   -p,  --page-requisites    get all images, etc. needed to display HTML page.\n"),
587     N_("\
588        --strict-comments    turn on strict (SGML) handling of HTML comments.\n"),
589     "\n",
590
591     N_("\
592 Recursive accept/reject:\n"),
593     N_("\
594   -A,  --accept=LIST               comma-separated list of accepted extensions.\n"),
595     N_("\
596   -R,  --reject=LIST               comma-separated list of rejected extensions.\n"),
597     N_("\
598   -D,  --domains=LIST              comma-separated list of accepted domains.\n"),
599     N_("\
600        --exclude-domains=LIST      comma-separated list of rejected domains.\n"),
601     N_("\
602        --follow-ftp                follow FTP links from HTML documents.\n"),
603     N_("\
604        --follow-tags=LIST          comma-separated list of followed HTML tags.\n"),
605     N_("\
606        --ignore-tags=LIST          comma-separated list of ignored HTML tags.\n"),
607     N_("\
608   -H,  --span-hosts                go to foreign hosts when recursive.\n"),
609     N_("\
610   -L,  --relative                  follow relative links only.\n"),
611     N_("\
612   -I,  --include-directories=LIST  list of allowed directories.\n"),
613     N_("\
614   -X,  --exclude-directories=LIST  list of excluded directories.\n"),
615     N_("\
616   -np, --no-parent                 don't ascend to the parent directory.\n"),
617     "\n",
618
619     N_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n")
620   };
621
622   int i;
623
624   printf (_("GNU Wget %s, a non-interactive network retriever.\n"),
625           version_string);
626   print_usage ();
627
628   for (i = 0; i < countof (help); i++)
629     fputs (_(help[i]), stdout);
630
631   exit (0);
632 }
633
634 /* Return a human-readable printed representation of INTERVAL,
635    measured in seconds.  */
636
637 static char *
638 secs_to_human_time (double interval)
639 {
640   static char buf[32];
641   int secs = (int) (interval + 0.5);
642   int hours, mins, days;
643
644   days = secs / 86400, secs %= 86400;
645   hours = secs / 3600, secs %= 3600;
646   mins = secs / 60, secs %= 60;
647
648   if (days)
649     sprintf (buf, "%dd %dh %dm %ds", days, hours, mins, secs);
650   else if (hours)
651     sprintf (buf, "%dh %dm %ds", hours, mins, secs);
652   else if (mins)
653     sprintf (buf, "%dm %ds", mins, secs);
654   else
655     sprintf (buf, "%ss", print_decimal (interval));
656
657   return buf;
658 }
659
660 static void
661 print_version (void)
662 {
663   printf ("GNU Wget %s\n\n", version_string);
664   fputs (_("\
665 Copyright (C) 2005 Free Software Foundation, Inc.\n"), stdout);
666   fputs (_("\
667 This program is distributed in the hope that it will be useful,\n\
668 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
669 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
670 GNU General Public License for more details.\n"), stdout);
671   fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"),
672          stdout);
673   exit (0);
674 }
675 \f
676 #ifndef TESTING
677 int
678 main (int argc, char *const *argv)
679 {
680   char **url, **t;
681   int i, ret, longindex;
682   int nurl, status;
683   bool append_to_log = false;
684
685   i18n_initialize ();
686
687   /* Construct the name of the executable, without the directory part.  */
688   exec_name = strrchr (argv[0], PATH_SEPARATOR);
689   if (!exec_name)
690     exec_name = argv[0];
691   else
692     ++exec_name;
693
694 #ifdef WINDOWS
695   /* Drop extension (typically .EXE) from executable filename. */
696   windows_main (&argc, (char **) argv, (char **) &exec_name);
697 #endif
698
699   /* Set option defaults; read the system wgetrc and ~/.wgetrc.  */
700   initialize ();
701
702   init_switches ();
703   longindex = -1;
704   while ((ret = getopt_long (argc, argv,
705                              short_options, long_options, &longindex)) != -1)
706     {
707       int val;
708       struct cmdline_option *opt;
709
710       /* If LONGINDEX is unchanged, it means RET is referring a short
711          option.  */
712       if (longindex == -1)
713         {
714           if (ret == '?')
715             {
716               print_usage ();
717               printf ("\n");
718               printf (_("Try `%s --help' for more options.\n"), exec_name);
719               exit (2);
720             }
721           /* Find the short option character in the mapping.  */
722           longindex = optmap[ret - 32];
723         }
724       val = long_options[longindex].val;
725
726       /* Use the retrieved value to locate the option in the
727          option_data array, and to see if we're dealing with the
728          negated "--no-FOO" variant of the boolean option "--foo".  */
729       opt = &option_data[val & ~BOOLEAN_NEG_MARKER];
730       switch (opt->type)
731         {
732         case OPT_VALUE:
733           setoptval (opt->data, optarg, opt->long_name);
734           break;
735         case OPT_BOOLEAN:
736           if (optarg)
737             /* The user has specified a value -- use it. */
738             setoptval (opt->data, optarg, opt->long_name);
739           else
740             {
741               /* NEG is true for `--no-FOO' style boolean options. */
742               bool neg = !!(val & BOOLEAN_NEG_MARKER);
743               setoptval (opt->data, neg ? "0" : "1", opt->long_name);
744             }
745           break;
746         case OPT_FUNCALL:
747           {
748             void (*func) (void) = (void (*) (void)) opt->data;
749             func ();
750           }
751           break;
752         case OPT__APPEND_OUTPUT:
753           setoptval ("logfile", optarg, opt->long_name);
754           append_to_log = true;
755           break;
756         case OPT__EXECUTE:
757           run_command (optarg);
758           break;
759         case OPT__NO:
760           {
761             /* We support real --no-FOO flags now, but keep these
762                short options for convenience and backward
763                compatibility.  */
764             char *p;
765             for (p = optarg; *p; p++)
766               switch (*p)
767                 {
768                 case 'v':
769                   setoptval ("verbose", "0", opt->long_name);
770                   break;
771                 case 'H':
772                   setoptval ("addhostdir", "0", opt->long_name);
773                   break;
774                 case 'd':
775                   setoptval ("dirstruct", "0", opt->long_name);
776                   break;
777                 case 'c':
778                   setoptval ("noclobber", "1", opt->long_name);
779                   break;
780                 case 'p':
781                   setoptval ("noparent", "1", opt->long_name);
782                   break;
783                 default:
784                   printf (_("%s: illegal option -- `-n%c'\n"), exec_name, *p);
785                   print_usage ();
786                   printf ("\n");
787                   printf (_("Try `%s --help' for more options.\n"), exec_name);
788                   exit (1);
789                 }
790             break;
791           }
792         case OPT__PARENT:
793         case OPT__CLOBBER:
794           {
795             /* The wgetrc commands are named noparent and noclobber,
796                so we must revert the meaning of the cmdline options
797                before passing the value to setoptval.  */
798             bool flag = true;
799             if (optarg)
800               flag = (*optarg == '1' || TOLOWER (*optarg) == 'y'
801                       || (TOLOWER (optarg[0]) == 'o'
802                           && TOLOWER (optarg[1]) == 'n'));
803             setoptval (opt->type == OPT__PARENT ? "noparent" : "noclobber",
804                        flag ? "0" : "1", opt->long_name);
805             break;
806           }
807         case OPT__DONT_REMOVE_LISTING:
808           setoptval ("removelisting", "0", opt->long_name);
809           break;
810         }
811
812       longindex = -1;
813     }
814
815   /* All user options have now been processed, so it's now safe to do
816      interoption dependency checks. */
817
818   if (opt.reclevel == 0)
819     opt.reclevel = INFINITE_RECURSION; /* see recur.h for commentary on this */
820
821   if (opt.page_requisites && !opt.recursive)
822     {
823       /* Don't set opt.recursive here because it would confuse the FTP
824          code.  Instead, call retrieve_tree below when either
825          page_requisites or recursive is requested.  */
826       opt.reclevel = 0;
827       if (!opt.no_dirstruct)
828         opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
829     }
830
831   if (opt.verbose == -1)
832     opt.verbose = !opt.quiet;
833
834   /* Sanity checks.  */
835   if (opt.verbose && opt.quiet)
836     {
837       printf (_("Can't be verbose and quiet at the same time.\n"));
838       print_usage ();
839       exit (1);
840     }
841   if (opt.timestamping && opt.noclobber)
842     {
843       printf (_("\
844 Can't timestamp and not clobber old files at the same time.\n"));
845       print_usage ();
846       exit (1);
847     }
848 #ifdef ENABLE_IPV6
849   if (opt.ipv4_only && opt.ipv6_only)
850     {
851       printf (_("Cannot specify both --inet4-only and --inet6-only.\n"));
852       print_usage ();
853       exit (1);
854     }
855 #endif
856
857   nurl = argc - optind;
858   if (!nurl && !opt.input_filename)
859     {
860       /* No URL specified.  */
861       printf (_("%s: missing URL\n"), exec_name);
862       print_usage ();
863       printf ("\n");
864       /* #### Something nicer should be printed here -- similar to the
865          pre-1.5 `--help' page.  */
866       printf (_("Try `%s --help' for more options.\n"), exec_name);
867       exit (1);
868     }
869
870   if (opt.background)
871     fork_to_background ();
872
873   /* Initialize progress.  Have to do this after the options are
874      processed so we know where the log file is.  */
875   if (opt.verbose)
876     set_progress_implementation (opt.progress_type);
877
878   /* Fill in the arguments.  */
879   url = alloca_array (char *, nurl + 1);
880   for (i = 0; i < nurl; i++, optind++)
881     {
882       char *rewritten = rewrite_shorthand_url (argv[optind]);
883       if (rewritten)
884         url[i] = rewritten;
885       else
886         url[i] = xstrdup (argv[optind]);
887     }
888   url[i] = NULL;
889
890   /* Initialize logging.  */
891   log_init (opt.lfilename, append_to_log);
892
893   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n", version_string,
894            OS_TYPE));
895
896   /* Open the output filename if necessary.  */
897   if (opt.output_document)
898     {
899       if (HYPHENP (opt.output_document))
900         output_stream = stdout;
901       else
902         {
903           struct_fstat st;
904           output_stream = fopen (opt.output_document,
905                                  opt.always_rest ? "ab" : "wb");
906           if (output_stream == NULL)
907             {
908               perror (opt.output_document);
909               exit (1);
910             }
911           if (fstat (fileno (output_stream), &st) == 0 && S_ISREG (st.st_mode))
912             output_stream_regular = true;
913         }
914     }
915
916 #ifdef WINDOWS
917   ws_startup ();
918 #endif
919
920 #ifdef SIGHUP
921   /* Setup the signal handler to redirect output when hangup is
922      received.  */
923   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
924     signal(SIGHUP, redirect_output_signal);
925 #endif
926   /* ...and do the same for SIGUSR1.  */
927 #ifdef SIGUSR1
928   signal (SIGUSR1, redirect_output_signal);
929 #endif
930 #ifdef SIGPIPE
931   /* Writing to a closed socket normally signals SIGPIPE, and the
932      process exits.  What we want is to ignore SIGPIPE and just check
933      for the return value of write().  */
934   signal (SIGPIPE, SIG_IGN);
935 #endif
936 #ifdef SIGWINCH
937   signal (SIGWINCH, progress_handle_sigwinch);
938 #endif
939
940   status = RETROK;              /* initialize it, just-in-case */
941   /* Retrieve the URLs from argument list.  */
942   for (t = url; *t; t++)
943     {
944       char *filename = NULL, *redirected_URL = NULL;
945       int dt;
946
947       if ((opt.recursive || opt.page_requisites)
948           && url_scheme (*t) != SCHEME_FTP)
949         status = retrieve_tree (*t);
950       else
951         status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt);
952
953       if (opt.delete_after && file_exists_p(filename))
954         {
955           DEBUGP (("Removing file due to --delete-after in main():\n"));
956           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
957           if (unlink (filename))
958             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
959         }
960
961       xfree_null (redirected_URL);
962       xfree_null (filename);
963     }
964
965   /* And then from the input file, if any.  */
966   if (opt.input_filename)
967     {
968       int count;
969       status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
970       if (!count)
971         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
972                    opt.input_filename);
973     }
974   /* Print the downloaded sum.  */
975   if ((opt.recursive || opt.page_requisites
976        || nurl > 1
977        || (opt.input_filename && total_downloaded_bytes != 0))
978       &&
979       total_downloaded_bytes != 0)
980     {
981       logprintf (LOG_NOTQUIET,
982                  _("FINISHED --%s--\nDownloaded: %d files, %s in %s (%s)\n"),
983                  time_str (NULL),
984                  opt.numurls,
985                  human_readable (total_downloaded_bytes),
986                  secs_to_human_time (total_download_time),
987                  retr_rate (total_downloaded_bytes, total_download_time));
988       /* Print quota warning, if exceeded.  */
989       if (opt.quota && total_downloaded_bytes > opt.quota)
990         logprintf (LOG_NOTQUIET,
991                    _("Download quota of %s EXCEEDED!\n"),
992                    human_readable (opt.quota));
993     }
994
995   if (opt.cookies_output)
996     save_cookies ();
997
998   if (opt.convert_links && !opt.delete_after)
999     convert_all_links ();
1000
1001   log_close ();
1002   for (i = 0; i < nurl; i++)
1003     xfree (url[i]);
1004   cleanup ();
1005
1006 #ifdef DEBUG_MALLOC
1007   print_malloc_debug_stats ();
1008 #endif
1009   if (status == RETROK)
1010     return 0;
1011   else
1012     return 1;
1013 }
1014 #endif /* TESTING */
1015 \f
1016 #if defined(SIGHUP) || defined(SIGUSR1)
1017
1018 /* So the signal_name check doesn't blow when only one is available. */
1019 #ifndef SIGHUP
1020 # define SIGHUP -1
1021 #endif
1022 #ifndef SIGUSR1
1023 # define SIGUSR1 -1
1024 #endif
1025
1026 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
1027    will proceed operation as usual, trying to write into a log file.
1028    If that is impossible, the output will be turned off.  */
1029
1030 static void
1031 redirect_output_signal (int sig)
1032 {
1033   const char *signal_name = (sig == SIGHUP ? "SIGHUP" :
1034                              (sig == SIGUSR1 ? "SIGUSR1" :
1035                               "WTF?!"));
1036   log_request_redirect_output (signal_name);
1037   progress_schedule_redirect ();
1038   signal (sig, redirect_output_signal);
1039 }
1040 #endif