]> sjero.net Git - wget/blob - src/main.c
Merging to reinstate autoreconf.
[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 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 ENABLE_NLS
40 # include <locale.h>
41 #endif
42 #include <assert.h>
43 #include <errno.h>
44 #include <time.h>
45
46 #include "wget.h"
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        --no-content-disposition  don't honor Content-Disposition header.\n"),
536     "\n",
537
538 #ifdef HAVE_SSL
539     N_("\
540 HTTPS (SSL/TLS) options:\n"),
541     N_("\
542        --secure-protocol=PR     choose secure protocol, one of auto, SSLv2,\n\
543                                 SSLv3, and TLSv1.\n"),
544     N_("\
545        --no-check-certificate   don't validate the server's certificate.\n"),
546     N_("\
547        --certificate=FILE       client certificate file.\n"),
548     N_("\
549        --certificate-type=TYPE  client certificate type, PEM or DER.\n"),
550     N_("\
551        --private-key=FILE       private key file.\n"),
552     N_("\
553        --private-key-type=TYPE  private key type, PEM or DER.\n"),
554     N_("\
555        --ca-certificate=FILE    file with the bundle of CA's.\n"),
556     N_("\
557        --ca-directory=DIR       directory where hash list of CA's is stored.\n"),
558     N_("\
559        --random-file=FILE       file with random data for seeding the SSL PRNG.\n"),
560     N_("\
561        --egd-file=FILE          file naming the EGD socket with random data.\n"),
562     "\n",
563 #endif /* HAVE_SSL */
564
565     N_("\
566 FTP options:\n"),
567     N_("\
568        --ftp-user=USER         set ftp user to USER.\n"),
569     N_("\
570        --ftp-password=PASS     set ftp password to PASS.\n"),
571     N_("\
572        --no-remove-listing     don't remove `.listing' files.\n"),
573     N_("\
574        --no-glob               turn off FTP file name globbing.\n"),
575     N_("\
576        --no-passive-ftp        disable the \"passive\" transfer mode.\n"),
577     N_("\
578        --retr-symlinks         when recursing, get linked-to files (not dir).\n"),
579     N_("\
580        --preserve-permissions  preserve remote file permissions.\n"),
581     "\n",
582
583     N_("\
584 Recursive download:\n"),
585     N_("\
586   -r,  --recursive          specify recursive download.\n"),
587     N_("\
588   -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n"),
589     N_("\
590        --delete-after       delete files locally after downloading them.\n"),
591     N_("\
592   -k,  --convert-links      make links in downloaded HTML point to local files.\n"),
593     N_("\
594   -K,  --backup-converted   before converting file X, back up as X.orig.\n"),
595     N_("\
596   -m,  --mirror             shortcut for -N -r -l inf --no-remove-listing.\n"),
597     N_("\
598   -p,  --page-requisites    get all images, etc. needed to display HTML page.\n"),
599     N_("\
600        --strict-comments    turn on strict (SGML) handling of HTML comments.\n"),
601     "\n",
602
603     N_("\
604 Recursive accept/reject:\n"),
605     N_("\
606   -A,  --accept=LIST               comma-separated list of accepted extensions.\n"),
607     N_("\
608   -R,  --reject=LIST               comma-separated list of rejected extensions.\n"),
609     N_("\
610   -D,  --domains=LIST              comma-separated list of accepted domains.\n"),
611     N_("\
612        --exclude-domains=LIST      comma-separated list of rejected domains.\n"),
613     N_("\
614        --follow-ftp                follow FTP links from HTML documents.\n"),
615     N_("\
616        --follow-tags=LIST          comma-separated list of followed HTML tags.\n"),
617     N_("\
618        --ignore-tags=LIST          comma-separated list of ignored HTML tags.\n"),
619     N_("\
620   -H,  --span-hosts                go to foreign hosts when recursive.\n"),
621     N_("\
622   -L,  --relative                  follow relative links only.\n"),
623     N_("\
624   -I,  --include-directories=LIST  list of allowed directories.\n"),
625     N_("\
626   -X,  --exclude-directories=LIST  list of excluded directories.\n"),
627     N_("\
628   -np, --no-parent                 don't ascend to the parent directory.\n"),
629     "\n",
630
631     N_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n")
632   };
633
634   int i;
635
636   printf (_("GNU Wget %s, a non-interactive network retriever.\n"),
637           version_string);
638   print_usage ();
639
640   for (i = 0; i < countof (help); i++)
641     fputs (_(help[i]), stdout);
642
643   exit (0);
644 }
645
646 /* Return a human-readable printed representation of INTERVAL,
647    measured in seconds.  */
648
649 static char *
650 secs_to_human_time (double interval)
651 {
652   static char buf[32];
653   int secs = (int) (interval + 0.5);
654   int hours, mins, days;
655
656   days = secs / 86400, secs %= 86400;
657   hours = secs / 3600, secs %= 3600;
658   mins = secs / 60, secs %= 60;
659
660   if (days)
661     sprintf (buf, "%dd %dh %dm %ds", days, hours, mins, secs);
662   else if (hours)
663     sprintf (buf, "%dh %dm %ds", hours, mins, secs);
664   else if (mins)
665     sprintf (buf, "%dm %ds", mins, secs);
666   else
667     sprintf (buf, "%ss", print_decimal (interval));
668
669   return buf;
670 }
671
672 static void
673 print_version (void)
674 {
675   printf ("GNU Wget %s\n\n", version_string);
676   fputs (_("\
677 Copyright (C) 2007 Free Software Foundation, Inc.\n"), stdout);
678   fputs (_("\
679 License GPLv3+: GNU GPL version 3 or later\n\
680 <http://www.gnu.org/licenses/gpl.html>.\n\
681 This is free software: you are free to change and redistribute it.\n\
682 There is NO WARRANTY, to the extent permitted by law.\n"), stdout);
683   fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"),
684          stdout);
685   fputs (_("Currently maintained by Micah Cowan <micah@cowan.name>.\n"),
686          stdout);
687   exit (0);
688 }
689 \f
690
691 int
692 main (int argc, char *const *argv)
693 {
694   char **url, **t;
695   int i, ret, longindex;
696   int nurl, status;
697   bool append_to_log = false;
698
699   i18n_initialize ();
700
701   /* Construct the name of the executable, without the directory part.  */
702   exec_name = strrchr (argv[0], PATH_SEPARATOR);
703   if (!exec_name)
704     exec_name = argv[0];
705   else
706     ++exec_name;
707
708 #ifdef WINDOWS
709   /* Drop extension (typically .EXE) from executable filename. */
710   windows_main ((char **) &exec_name);
711 #endif
712
713   /* Set option defaults; read the system wgetrc and ~/.wgetrc.  */
714   initialize ();
715
716   init_switches ();
717   longindex = -1;
718   while ((ret = getopt_long (argc, argv,
719                              short_options, long_options, &longindex)) != -1)
720     {
721       int val;
722       struct cmdline_option *opt;
723
724       /* If LONGINDEX is unchanged, it means RET is referring a short
725          option.  */
726       if (longindex == -1)
727         {
728           if (ret == '?')
729             {
730               print_usage ();
731               printf ("\n");
732               printf (_("Try `%s --help' for more options.\n"), exec_name);
733               exit (2);
734             }
735           /* Find the short option character in the mapping.  */
736           longindex = optmap[ret - 32];
737         }
738       val = long_options[longindex].val;
739
740       /* Use the retrieved value to locate the option in the
741          option_data array, and to see if we're dealing with the
742          negated "--no-FOO" variant of the boolean option "--foo".  */
743       opt = &option_data[val & ~BOOLEAN_NEG_MARKER];
744       switch (opt->type)
745         {
746         case OPT_VALUE:
747           setoptval (opt->data, optarg, opt->long_name);
748           break;
749         case OPT_BOOLEAN:
750           if (optarg)
751             /* The user has specified a value -- use it. */
752             setoptval (opt->data, optarg, opt->long_name);
753           else
754             {
755               /* NEG is true for `--no-FOO' style boolean options. */
756               bool neg = !!(val & BOOLEAN_NEG_MARKER);
757               setoptval (opt->data, neg ? "0" : "1", opt->long_name);
758             }
759           break;
760         case OPT_FUNCALL:
761           {
762             void (*func) (void) = (void (*) (void)) opt->data;
763             func ();
764           }
765           break;
766         case OPT__APPEND_OUTPUT:
767           setoptval ("logfile", optarg, opt->long_name);
768           append_to_log = true;
769           break;
770         case OPT__EXECUTE:
771           run_command (optarg);
772           break;
773         case OPT__NO:
774           {
775             /* We support real --no-FOO flags now, but keep these
776                short options for convenience and backward
777                compatibility.  */
778             char *p;
779             for (p = optarg; *p; p++)
780               switch (*p)
781                 {
782                 case 'v':
783                   setoptval ("verbose", "0", opt->long_name);
784                   break;
785                 case 'H':
786                   setoptval ("addhostdir", "0", opt->long_name);
787                   break;
788                 case 'd':
789                   setoptval ("dirstruct", "0", opt->long_name);
790                   break;
791                 case 'c':
792                   setoptval ("noclobber", "1", opt->long_name);
793                   break;
794                 case 'p':
795                   setoptval ("noparent", "1", opt->long_name);
796                   break;
797                 default:
798                   printf (_("%s: illegal option -- `-n%c'\n"), exec_name, *p);
799                   print_usage ();
800                   printf ("\n");
801                   printf (_("Try `%s --help' for more options.\n"), exec_name);
802                   exit (1);
803                 }
804             break;
805           }
806         case OPT__PARENT:
807         case OPT__CLOBBER:
808           {
809             /* The wgetrc commands are named noparent and noclobber,
810                so we must revert the meaning of the cmdline options
811                before passing the value to setoptval.  */
812             bool flag = true;
813             if (optarg)
814               flag = (*optarg == '1' || c_tolower (*optarg) == 'y'
815                       || (c_tolower (optarg[0]) == 'o'
816                           && c_tolower (optarg[1]) == 'n'));
817             setoptval (opt->type == OPT__PARENT ? "noparent" : "noclobber",
818                        flag ? "0" : "1", opt->long_name);
819             break;
820           }
821         case OPT__DONT_REMOVE_LISTING:
822           setoptval ("removelisting", "0", opt->long_name);
823           break;
824         }
825
826       longindex = -1;
827     }
828
829   nurl = argc - optind;
830
831   /* All user options have now been processed, so it's now safe to do
832      interoption dependency checks. */
833
834   if (opt.reclevel == 0)
835       opt.reclevel = INFINITE_RECURSION; /* see recur.h for commentary */
836
837   if (opt.spider || opt.delete_after)
838       opt.no_dirstruct = true;
839
840   if (opt.page_requisites && !opt.recursive)
841     {
842       /* Don't set opt.recursive here because it would confuse the FTP
843          code.  Instead, call retrieve_tree below when either
844          page_requisites or recursive is requested.  */
845       opt.reclevel = 0;
846       if (!opt.no_dirstruct)
847         opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
848     }
849
850   if (opt.verbose == -1)
851     opt.verbose = !opt.quiet;
852
853   /* Sanity checks.  */
854   if (opt.verbose && opt.quiet)
855     {
856       printf (_("Can't be verbose and quiet at the same time.\n"));
857       print_usage ();
858       exit (1);
859     }
860   if (opt.timestamping && opt.noclobber)
861     {
862       printf (_("\
863 Can't timestamp and not clobber old files at the same time.\n"));
864       print_usage ();
865       exit (1);
866     }
867 #ifdef ENABLE_IPV6
868   if (opt.ipv4_only && opt.ipv6_only)
869     {
870       printf (_("Cannot specify both --inet4-only and --inet6-only.\n"));
871       print_usage ();
872       exit (1);
873     }
874 #endif
875   if (opt.output_document
876       && (opt.page_requisites
877           || opt.recursive
878           || opt.timestamping))
879     {
880           printf (_("Cannot specify -r, -p or -N if -O is given.\n"));
881           print_usage ();
882           exit (1);
883     }
884   if (opt.output_document
885       && opt.convert_links 
886       && nurl > 1)
887     {
888           printf (_("Cannot specify both -k and -O if multiple URLs are given.\n"));
889           print_usage ();
890           exit (1);
891     }
892
893   if (!nurl && !opt.input_filename)
894     {
895       /* No URL specified.  */
896       printf (_("%s: missing URL\n"), exec_name);
897       print_usage ();
898       printf ("\n");
899       /* #### Something nicer should be printed here -- similar to the
900          pre-1.5 `--help' page.  */
901       printf (_("Try `%s --help' for more options.\n"), exec_name);
902       exit (1);
903     }
904
905 #ifdef MSDOS
906   if (opt.wdebug)
907      dbug_init();
908   sock_init();
909 #else
910   if (opt.background)
911     fork_to_background ();
912 #endif
913
914   /* Initialize progress.  Have to do this after the options are
915      processed so we know where the log file is.  */
916   if (opt.verbose)
917     set_progress_implementation (opt.progress_type);
918
919   /* Fill in the arguments.  */
920   url = alloca_array (char *, nurl + 1);
921   for (i = 0; i < nurl; i++, optind++)
922     {
923       char *rewritten = rewrite_shorthand_url (argv[optind]);
924       if (rewritten)
925         url[i] = rewritten;
926       else
927         url[i] = xstrdup (argv[optind]);
928     }
929   url[i] = NULL;
930
931   /* Initialize logging.  */
932   log_init (opt.lfilename, append_to_log);
933
934   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n", version_string,
935            OS_TYPE));
936
937   /* Open the output filename if necessary.  */
938   if (opt.output_document)
939     {
940       if (HYPHENP (opt.output_document))
941         output_stream = stdout;
942       else
943         {
944           struct_fstat st;
945           output_stream = fopen (opt.output_document,
946                                  opt.always_rest ? "ab" : "wb");
947           if (output_stream == NULL)
948             {
949               perror (opt.output_document);
950               exit (1);
951             }
952           if (fstat (fileno (output_stream), &st) == 0 && S_ISREG (st.st_mode))
953             output_stream_regular = true;
954         }
955     }
956
957 #ifdef WINDOWS
958   ws_startup ();
959 #endif
960
961 #ifdef SIGHUP
962   /* Setup the signal handler to redirect output when hangup is
963      received.  */
964   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
965     signal(SIGHUP, redirect_output_signal);
966 #endif
967   /* ...and do the same for SIGUSR1.  */
968 #ifdef SIGUSR1
969   signal (SIGUSR1, redirect_output_signal);
970 #endif
971 #ifdef SIGPIPE
972   /* Writing to a closed socket normally signals SIGPIPE, and the
973      process exits.  What we want is to ignore SIGPIPE and just check
974      for the return value of write().  */
975   signal (SIGPIPE, SIG_IGN);
976 #endif
977 #ifdef SIGWINCH
978   signal (SIGWINCH, progress_handle_sigwinch);
979 #endif
980
981   status = RETROK;              /* initialize it, just-in-case */
982   /* Retrieve the URLs from argument list.  */
983   for (t = url; *t; t++)
984     {
985       char *filename = NULL, *redirected_URL = NULL;
986       int dt;
987
988       if ((opt.recursive || opt.page_requisites)
989           && (url_scheme (*t) != SCHEME_FTP || url_uses_proxy (*t)))
990         {
991           int old_follow_ftp = opt.follow_ftp;
992
993           /* Turn opt.follow_ftp on in case of recursive FTP retrieval */
994           if (url_scheme (*t) == SCHEME_FTP) 
995             opt.follow_ftp = 1;
996           
997           status = retrieve_tree (*t);
998
999           opt.follow_ftp = old_follow_ftp;
1000         }
1001       else
1002         status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt, opt.recursive);
1003
1004       if (opt.delete_after && file_exists_p(filename))
1005         {
1006           DEBUGP (("Removing file due to --delete-after in main():\n"));
1007           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
1008           if (unlink (filename))
1009             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1010         }
1011
1012       xfree_null (redirected_URL);
1013       xfree_null (filename);
1014     }
1015
1016   /* And then from the input file, if any.  */
1017   if (opt.input_filename)
1018     {
1019       int count;
1020       status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
1021       if (!count)
1022         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
1023                    opt.input_filename);
1024     }
1025
1026   /* Print broken links. */
1027   if (opt.recursive && opt.spider)
1028     {
1029       print_broken_links();
1030     }
1031   
1032   /* Print the downloaded sum.  */
1033   if ((opt.recursive || opt.page_requisites
1034        || nurl > 1
1035        || (opt.input_filename && total_downloaded_bytes != 0))
1036       &&
1037       total_downloaded_bytes != 0)
1038     {
1039       logprintf (LOG_NOTQUIET,
1040                  _("FINISHED --%s--\nDownloaded: %d files, %s in %s (%s)\n"),
1041                  datetime_str (time (NULL)),
1042                  opt.numurls,
1043                  human_readable (total_downloaded_bytes),
1044                  secs_to_human_time (total_download_time),
1045                  retr_rate (total_downloaded_bytes, total_download_time));
1046       /* Print quota warning, if exceeded.  */
1047       if (opt.quota && total_downloaded_bytes > opt.quota)
1048         logprintf (LOG_NOTQUIET,
1049                    _("Download quota of %s EXCEEDED!\n"),
1050                    human_readable (opt.quota));
1051     }
1052
1053   if (opt.cookies_output)
1054     save_cookies ();
1055
1056   if (opt.convert_links && !opt.delete_after)
1057     convert_all_links ();
1058
1059   log_close ();
1060   for (i = 0; i < nurl; i++)
1061     xfree (url[i]);
1062   cleanup ();
1063
1064 #ifdef DEBUG_MALLOC
1065   print_malloc_debug_stats ();
1066 #endif
1067   if (status == RETROK)
1068     return 0;
1069   else
1070     return 1;
1071 }
1072 #endif /* TESTING */
1073 \f
1074 #if defined(SIGHUP) || defined(SIGUSR1)
1075
1076 /* So the signal_name check doesn't blow when only one is available. */
1077 #ifndef SIGHUP
1078 # define SIGHUP -1
1079 #endif
1080 #ifndef SIGUSR1
1081 # define SIGUSR1 -1
1082 #endif
1083
1084 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
1085    will proceed operation as usual, trying to write into a log file.
1086    If that is impossible, the output will be turned off.  */
1087
1088 static void
1089 redirect_output_signal (int sig)
1090 {
1091   const char *signal_name = (sig == SIGHUP ? "SIGHUP" :
1092                              (sig == SIGUSR1 ? "SIGUSR1" :
1093                               "WTF?!"));
1094   log_request_redirect_output (signal_name);
1095   progress_schedule_redirect ();
1096   signal (sig, redirect_output_signal);
1097 }
1098 #endif
1099
1100 /*
1101  * vim: et ts=2 sw=2
1102  */