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