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