]> sjero.net Git - wget/blob - src/main.c
mass change: update copyright years.
[wget] / src / main.c
1 /* Command line parsing.
2    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
3    2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
4    Inc.
5
6 This file is part of GNU Wget.
7
8 GNU Wget is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12
13 GNU Wget is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Wget.  If not, see <http://www.gnu.org/licenses/>.
20
21 Additional permission under GNU GPL version 3 section 7
22
23 If you modify this program, or any covered work, by linking or
24 combining it with the OpenSSL project's OpenSSL library (or a
25 modified version of that library), containing parts covered by the
26 terms of the OpenSSL or SSLeay licenses, the Free Software Foundation
27 grants you additional permission to convey the resulting work.
28 Corresponding Source for a non-source form of such a combination
29 shall include the source code for the parts of OpenSSL used as well
30 as that of the covered work.  */
31
32 #include "wget.h"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <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 "exits.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 #include "ptimer.h"
58
59 #include <getopt.h>
60 #include <getpass.h>
61 #include <quote.h>
62
63 #ifdef __VMS
64 #include "vms.h"
65 #endif /* __VMS */
66
67 #ifndef PATH_SEPARATOR
68 # define PATH_SEPARATOR '/'
69 #endif
70
71 struct options opt;
72
73 /* defined in version.c */
74 extern char *version_string;
75 extern char *compilation_string;
76 extern char *system_getrc;
77 extern char *link_string;
78 /* defined in build_info.c */
79 extern const char *compiled_features[];
80 /* Used for --version output in print_version */
81 #define MAX_CHARS_PER_LINE      72
82 #define TABULATION              4
83
84 #if defined(SIGHUP) || defined(SIGUSR1)
85 static void redirect_output_signal (int);
86 #endif
87
88 const char *exec_name;
89
90 /* Number of successfully downloaded URLs */
91 int numurls = 0;
92 \f
93 #ifndef TESTING
94 /* Initialize I18N/L10N.  That amounts to invoking setlocale, and
95    setting up gettext's message catalog using bindtextdomain and
96    textdomain.  Does nothing if NLS is disabled or missing.  */
97
98 static void
99 i18n_initialize (void)
100 {
101   /* ENABLE_NLS implies existence of functions invoked here.  */
102 #ifdef ENABLE_NLS
103   /* Set the current locale.  */
104   setlocale (LC_ALL, "");
105   /* Set the text message domain.  */
106   bindtextdomain ("wget", LOCALEDIR);
107   textdomain ("wget");
108 #endif /* ENABLE_NLS */
109 }
110 \f
111 /* Definition of command-line options. */
112
113 static void print_help (void);
114 static void print_version (void);
115
116 #ifdef HAVE_SSL
117 # define IF_SSL(x) x
118 #else
119 # define IF_SSL(x) NULL
120 #endif
121
122 #ifdef ENABLE_DEBUG
123 # define WHEN_DEBUG(x) x
124 #else
125 # define WHEN_DEBUG(x) NULL
126 #endif
127
128 struct cmdline_option {
129   const char *long_name;
130   char short_name;
131   enum {
132     OPT_VALUE,
133     OPT_BOOLEAN,
134     OPT_FUNCALL,
135     /* Non-standard options that have to be handled specially in
136        main().  */
137     OPT__APPEND_OUTPUT,
138     OPT__CLOBBER,
139     OPT__DONT_REMOVE_LISTING,
140     OPT__EXECUTE,
141     OPT__NO,
142     OPT__PARENT
143   } type;
144   const void *data;             /* for standard options */
145   int argtype;                  /* for non-standard options */
146 };
147
148 static struct cmdline_option option_data[] =
149   {
150     { "accept", 'A', OPT_VALUE, "accept", -1 },
151     { "adjust-extension", 'E', OPT_BOOLEAN, "adjustextension", -1 },
152     { "append-output", 'a', OPT__APPEND_OUTPUT, NULL, required_argument },
153     { "ask-password", 0, OPT_BOOLEAN, "askpassword", -1 },
154     { "auth-no-challenge", 0, OPT_BOOLEAN, "authnochallenge", -1 },
155     { "background", 'b', OPT_BOOLEAN, "background", -1 },
156     { "backup-converted", 'K', OPT_BOOLEAN, "backupconverted", -1 },
157     { "backups", 0, OPT_BOOLEAN, "backups", -1 },
158     { "base", 'B', OPT_VALUE, "base", -1 },
159     { "bind-address", 0, OPT_VALUE, "bindaddress", -1 },
160     { IF_SSL ("ca-certificate"), 0, OPT_VALUE, "cacertificate", -1 },
161     { IF_SSL ("ca-directory"), 0, OPT_VALUE, "cadirectory", -1 },
162     { "cache", 0, OPT_BOOLEAN, "cache", -1 },
163     { IF_SSL ("certificate"), 0, OPT_VALUE, "certificate", -1 },
164     { IF_SSL ("certificate-type"), 0, OPT_VALUE, "certificatetype", -1 },
165     { IF_SSL ("check-certificate"), 0, OPT_BOOLEAN, "checkcertificate", -1 },
166     { "clobber", 0, OPT__CLOBBER, NULL, optional_argument },
167     { "config", 0, OPT_VALUE, "chooseconfig", -1 },
168     { "connect-timeout", 0, OPT_VALUE, "connecttimeout", -1 },
169     { "continue", 'c', OPT_BOOLEAN, "continue", -1 },
170     { "convert-links", 'k', OPT_BOOLEAN, "convertlinks", -1 },
171     { "content-disposition", 0, OPT_BOOLEAN, "contentdisposition", -1 },
172     { "cookies", 0, OPT_BOOLEAN, "cookies", -1 },
173     { "cut-dirs", 0, OPT_VALUE, "cutdirs", -1 },
174     { WHEN_DEBUG ("debug"), 'd', OPT_BOOLEAN, "debug", -1 },
175     { "default-page", 0, OPT_VALUE, "defaultpage", -1 },
176     { "delete-after", 0, OPT_BOOLEAN, "deleteafter", -1 },
177     { "directories", 0, OPT_BOOLEAN, "dirstruct", -1 },
178     { "directory-prefix", 'P', OPT_VALUE, "dirprefix", -1 },
179     { "dns-cache", 0, OPT_BOOLEAN, "dnscache", -1 },
180     { "dns-timeout", 0, OPT_VALUE, "dnstimeout", -1 },
181     { "domains", 'D', OPT_VALUE, "domains", -1 },
182     { "dont-remove-listing", 0, OPT__DONT_REMOVE_LISTING, NULL, no_argument },
183     { "dot-style", 0, OPT_VALUE, "dotstyle", -1 }, /* deprecated */
184     { "egd-file", 0, OPT_VALUE, "egdfile", -1 },
185     { "exclude-directories", 'X', OPT_VALUE, "excludedirectories", -1 },
186     { "exclude-domains", 0, OPT_VALUE, "excludedomains", -1 },
187     { "execute", 'e', OPT__EXECUTE, NULL, required_argument },
188     { "follow-ftp", 0, OPT_BOOLEAN, "followftp", -1 },
189     { "follow-tags", 0, OPT_VALUE, "followtags", -1 },
190     { "force-directories", 'x', OPT_BOOLEAN, "dirstruct", -1 },
191     { "force-html", 'F', OPT_BOOLEAN, "forcehtml", -1 },
192     { "ftp-password", 0, OPT_VALUE, "ftppassword", -1 },
193 #ifdef __VMS
194     { "ftp-stmlf", 0, OPT_BOOLEAN, "ftpstmlf", -1 },
195 #endif /* def __VMS */
196     { "ftp-user", 0, OPT_VALUE, "ftpuser", -1 },
197     { "glob", 0, OPT_BOOLEAN, "glob", -1 },
198     { "header", 0, OPT_VALUE, "header", -1 },
199     { "help", 'h', OPT_FUNCALL, (void *)print_help, no_argument },
200     { "host-directories", 0, OPT_BOOLEAN, "addhostdir", -1 },
201     { "html-extension", 'E', OPT_BOOLEAN, "adjustextension", -1 }, /* deprecated */
202     { "htmlify", 0, OPT_BOOLEAN, "htmlify", -1 },
203     { "http-keep-alive", 0, OPT_BOOLEAN, "httpkeepalive", -1 },
204     { "http-passwd", 0, OPT_VALUE, "httppassword", -1 }, /* deprecated */
205     { "http-password", 0, OPT_VALUE, "httppassword", -1 },
206     { "http-user", 0, OPT_VALUE, "httpuser", -1 },
207     { "ignore-case", 0, OPT_BOOLEAN, "ignorecase", -1 },
208     { "ignore-length", 0, OPT_BOOLEAN, "ignorelength", -1 },
209     { "ignore-tags", 0, OPT_VALUE, "ignoretags", -1 },
210     { "include-directories", 'I', OPT_VALUE, "includedirectories", -1 },
211 #ifdef ENABLE_IPV6
212     { "inet4-only", '4', OPT_BOOLEAN, "inet4only", -1 },
213     { "inet6-only", '6', OPT_BOOLEAN, "inet6only", -1 },
214 #endif
215     { "input-file", 'i', OPT_VALUE, "input", -1 },
216     { "iri", 0, OPT_BOOLEAN, "iri", -1 },
217     { "keep-session-cookies", 0, OPT_BOOLEAN, "keepsessioncookies", -1 },
218     { "level", 'l', OPT_VALUE, "reclevel", -1 },
219     { "limit-rate", 0, OPT_VALUE, "limitrate", -1 },
220     { "load-cookies", 0, OPT_VALUE, "loadcookies", -1 },
221     { "local-encoding", 0, OPT_VALUE, "localencoding", -1 },
222     { "max-redirect", 0, OPT_VALUE, "maxredirect", -1 },
223     { "mirror", 'm', OPT_BOOLEAN, "mirror", -1 },
224     { "no", 'n', OPT__NO, NULL, required_argument },
225     { "no-clobber", 0, OPT_BOOLEAN, "noclobber", -1 },
226     { "no-parent", 0, OPT_BOOLEAN, "noparent", -1 },
227     { "output-document", 'O', OPT_VALUE, "outputdocument", -1 },
228     { "output-file", 'o', OPT_VALUE, "logfile", -1 },
229     { "page-requisites", 'p', OPT_BOOLEAN, "pagerequisites", -1 },
230     { "parent", 0, OPT__PARENT, NULL, optional_argument },
231     { "passive-ftp", 0, OPT_BOOLEAN, "passiveftp", -1 },
232     { "password", 0, OPT_VALUE, "password", -1 },
233     { "post-data", 0, OPT_VALUE, "postdata", -1 },
234     { "post-file", 0, OPT_VALUE, "postfile", -1 },
235     { "prefer-family", 0, OPT_VALUE, "preferfamily", -1 },
236     { "preserve-permissions", 0, OPT_BOOLEAN, "preservepermissions", -1 }, /* deprecated */
237     { IF_SSL ("private-key"), 0, OPT_VALUE, "privatekey", -1 },
238     { IF_SSL ("private-key-type"), 0, OPT_VALUE, "privatekeytype", -1 },
239     { "progress", 0, OPT_VALUE, "progress", -1 },
240     { "protocol-directories", 0, OPT_BOOLEAN, "protocoldirectories", -1 },
241     { "proxy", 0, OPT_BOOLEAN, "useproxy", -1 },
242     { "proxy__compat", 'Y', OPT_VALUE, "useproxy", -1 }, /* back-compatible */
243     { "proxy-passwd", 0, OPT_VALUE, "proxypassword", -1 }, /* deprecated */
244     { "proxy-password", 0, OPT_VALUE, "proxypassword", -1 },
245     { "proxy-user", 0, OPT_VALUE, "proxyuser", -1 },
246     { "quiet", 'q', OPT_BOOLEAN, "quiet", -1 },
247     { "quota", 'Q', OPT_VALUE, "quota", -1 },
248     { "random-file", 0, OPT_VALUE, "randomfile", -1 },
249     { "random-wait", 0, OPT_BOOLEAN, "randomwait", -1 },
250     { "read-timeout", 0, OPT_VALUE, "readtimeout", -1 },
251     { "recursive", 'r', OPT_BOOLEAN, "recursive", -1 },
252     { "referer", 0, OPT_VALUE, "referer", -1 },
253     { "reject", 'R', OPT_VALUE, "reject", -1 },
254     { "relative", 'L', OPT_BOOLEAN, "relativeonly", -1 },
255     { "remote-encoding", 0, OPT_VALUE, "remoteencoding", -1 },
256     { "remove-listing", 0, OPT_BOOLEAN, "removelisting", -1 },
257     { "restrict-file-names", 0, OPT_BOOLEAN, "restrictfilenames", -1 },
258     { "retr-symlinks", 0, OPT_BOOLEAN, "retrsymlinks", -1 },
259     { "retry-connrefused", 0, OPT_BOOLEAN, "retryconnrefused", -1 },
260     { "save-cookies", 0, OPT_VALUE, "savecookies", -1 },
261     { "save-headers", 0, OPT_BOOLEAN, "saveheaders", -1 },
262     { IF_SSL ("secure-protocol"), 0, OPT_VALUE, "secureprotocol", -1 },
263     { "server-response", 'S', OPT_BOOLEAN, "serverresponse", -1 },
264     { "span-hosts", 'H', OPT_BOOLEAN, "spanhosts", -1 },
265     { "spider", 0, OPT_BOOLEAN, "spider", -1 },
266     { "strict-comments", 0, OPT_BOOLEAN, "strictcomments", -1 },
267     { "timeout", 'T', OPT_VALUE, "timeout", -1 },
268     { "timestamping", 'N', OPT_BOOLEAN, "timestamping", -1 },
269     { "tries", 't', OPT_VALUE, "tries", -1 },
270     { "unlink", 0, OPT_BOOLEAN, "unlink", -1 },
271     { "trust-server-names", 0, OPT_BOOLEAN, "trustservernames", -1 },
272     { "use-server-timestamps", 0, OPT_BOOLEAN, "useservertimestamps", -1 },
273     { "user", 0, OPT_VALUE, "user", -1 },
274     { "user-agent", 'U', OPT_VALUE, "useragent", -1 },
275     { "verbose", 'v', OPT_BOOLEAN, "verbose", -1 },
276     { "verbose", 0, OPT_BOOLEAN, "verbose", -1 },
277     { "version", 'V', OPT_FUNCALL, (void *) print_version, no_argument },
278     { "wait", 'w', OPT_VALUE, "wait", -1 },
279     { "waitretry", 0, OPT_VALUE, "waitretry", -1 },
280 #ifdef USE_WATT32
281     { "wdebug", 0, OPT_BOOLEAN, "wdebug", -1 },
282 #endif
283   };
284
285 #undef WHEN_DEBUG
286 #undef IF_SSL
287
288 /* Return a string that contains S with "no-" prepended.  The string
289    is NUL-terminated and allocated off static storage at Wget
290    startup.  */
291
292 static char *
293 no_prefix (const char *s)
294 {
295   static char buffer[1024];
296   static char *p = buffer;
297
298   char *cp = p;
299   int size = 3 + strlen (s) + 1;  /* "no-STRING\0" */
300   if (p + size >= buffer + sizeof (buffer))
301     abort ();
302
303   cp[0] = 'n', cp[1] = 'o', cp[2] = '-';
304   strcpy (cp + 3, s);
305   p += size;
306   return cp;
307 }
308
309 /* The arguments that that main passes to getopt_long. */
310 static struct option long_options[2 * countof (option_data) + 1];
311 static char short_options[128];
312
313 /* Mapping between short option chars and option_data indices. */
314 static unsigned char optmap[96];
315
316 /* Marker for `--no-FOO' values in long_options.  */
317 #define BOOLEAN_NEG_MARKER 1024
318
319 /* Initialize the long_options array used by getopt_long from the data
320    in option_data.  */
321
322 static void
323 init_switches (void)
324 {
325   char *p = short_options;
326   size_t i, o = 0;
327   for (i = 0; i < countof (option_data); i++)
328     {
329       struct cmdline_option *opt = &option_data[i];
330       struct option *longopt;
331
332       if (!opt->long_name)
333         /* The option is disabled. */
334         continue;
335
336       longopt = &long_options[o++];
337       longopt->name = opt->long_name;
338       longopt->val = i;
339       if (opt->short_name)
340         {
341           *p++ = opt->short_name;
342           optmap[opt->short_name - 32] = longopt - long_options;
343         }
344       switch (opt->type)
345         {
346         case OPT_VALUE:
347           longopt->has_arg = required_argument;
348           if (opt->short_name)
349             *p++ = ':';
350           break;
351         case OPT_BOOLEAN:
352           /* Specify an optional argument for long options, so that
353              --option=off works the same as --no-option, for
354              compatibility with pre-1.10 Wget.  However, don't specify
355              optional arguments short-option booleans because they
356              prevent combining of short options.  */
357           longopt->has_arg = optional_argument;
358           /* For Boolean options, add the "--no-FOO" variant, which is
359              identical to "--foo", except it has opposite meaning and
360              it doesn't allow an argument.  */
361           longopt = &long_options[o++];
362           longopt->name = no_prefix (opt->long_name);
363           longopt->has_arg = no_argument;
364           /* Mask the value so we'll be able to recognize that we're
365              dealing with the false value.  */
366           longopt->val = i | BOOLEAN_NEG_MARKER;
367           break;
368         default:
369           assert (opt->argtype != -1);
370           longopt->has_arg = opt->argtype;
371           if (opt->short_name)
372             {
373               if (longopt->has_arg == required_argument)
374                 *p++ = ':';
375               /* Don't handle optional_argument */
376             }
377         }
378     }
379   /* Terminate short_options. */
380   *p = '\0';
381   /* No need for xzero(long_options[o]) because its storage is static
382      and it will be zeroed by default.  */
383   assert (o <= countof (long_options));
384 }
385
386 /* Print the usage message.  */
387 static void
388 print_usage (int error)
389 {
390   fprintf (error ? stderr : stdout, _("Usage: %s [OPTION]... [URL]...\n"),
391            exec_name);
392 }
393
394 /* Print the help message, describing all the available options.  If
395    you add an option, be sure to update this list.  */
396 static void
397 print_help (void)
398 {
399   /* We split the help text this way to ease translation of individual
400      entries.  */
401   static const char *help[] = {
402     "\n",
403     N_("\
404 Mandatory arguments to long options are mandatory for short options too.\n\n"),
405     N_("\
406 Startup:\n"),
407     N_("\
408   -V,  --version           display the version of Wget and exit.\n"),
409     N_("\
410   -h,  --help              print this help.\n"),
411     N_("\
412   -b,  --background        go to background after startup.\n"),
413     N_("\
414   -e,  --execute=COMMAND   execute a `.wgetrc'-style command.\n"),
415     "\n",
416
417     N_("\
418 Logging and input file:\n"),
419     N_("\
420   -o,  --output-file=FILE    log messages to FILE.\n"),
421     N_("\
422   -a,  --append-output=FILE  append messages to FILE.\n"),
423 #ifdef ENABLE_DEBUG
424     N_("\
425   -d,  --debug               print lots of debugging information.\n"),
426 #endif
427 #ifdef USE_WATT32
428     N_("\
429        --wdebug              print Watt-32 debug output.\n"),
430 #endif
431     N_("\
432   -q,  --quiet               quiet (no output).\n"),
433     N_("\
434   -v,  --verbose             be verbose (this is the default).\n"),
435     N_("\
436   -nv, --no-verbose          turn off verboseness, without being quiet.\n"),
437     N_("\
438   -i,  --input-file=FILE     download URLs found in local or external FILE.\n"),
439     N_("\
440   -F,  --force-html          treat input file as HTML.\n"),
441     N_("\
442   -B,  --base=URL            resolves HTML input-file links (-i -F)\n\
443                              relative to URL.\n"),
444     N_("\
445        --config=FILE         Specify config file to use.\n"), 
446     "\n",
447
448     N_("\
449 Download:\n"),
450     N_("\
451   -t,  --tries=NUMBER            set number of retries to NUMBER (0 unlimits).\n"),
452     N_("\
453        --retry-connrefused       retry even if connection is refused.\n"),
454     N_("\
455   -O,  --output-document=FILE    write documents to FILE.\n"),
456     N_("\
457   -nc, --no-clobber              skip downloads that would download to\n\
458                                  existing files (overwriting them).\n"),
459     N_("\
460   -c,  --continue                resume getting a partially-downloaded file.\n"),
461     N_("\
462        --progress=TYPE           select progress gauge type.\n"),
463     N_("\
464   -N,  --timestamping            don't re-retrieve files unless newer than\n\
465                                  local.\n"),
466     N_("\
467   --no-use-server-timestamps     don't set the local file's timestamp by\n\
468                                  the one on the server.\n"),
469     N_("\
470   -S,  --server-response         print server response.\n"),
471     N_("\
472        --spider                  don't download anything.\n"),
473     N_("\
474   -T,  --timeout=SECONDS         set all timeout values to SECONDS.\n"),
475     N_("\
476        --dns-timeout=SECS        set the DNS lookup timeout to SECS.\n"),
477     N_("\
478        --connect-timeout=SECS    set the connect timeout to SECS.\n"),
479     N_("\
480        --read-timeout=SECS       set the read timeout to SECS.\n"),
481     N_("\
482   -w,  --wait=SECONDS            wait SECONDS between retrievals.\n"),
483     N_("\
484        --waitretry=SECONDS       wait 1..SECONDS between retries of a retrieval.\n"),
485     N_("\
486        --random-wait             wait from 0.5*WAIT...1.5*WAIT secs between retrievals.\n"),
487     N_("\
488        --no-proxy                explicitly turn off proxy.\n"),
489     N_("\
490   -Q,  --quota=NUMBER            set retrieval quota to NUMBER.\n"),
491     N_("\
492        --bind-address=ADDRESS    bind to ADDRESS (hostname or IP) on local host.\n"),
493     N_("\
494        --limit-rate=RATE         limit download rate to RATE.\n"),
495     N_("\
496        --no-dns-cache            disable caching DNS lookups.\n"),
497     N_("\
498        --restrict-file-names=OS  restrict chars in file names to ones OS allows.\n"),
499     N_("\
500        --ignore-case             ignore case when matching files/directories.\n"),
501 #ifdef ENABLE_IPV6
502     N_("\
503   -4,  --inet4-only              connect only to IPv4 addresses.\n"),
504     N_("\
505   -6,  --inet6-only              connect only to IPv6 addresses.\n"),
506     N_("\
507        --prefer-family=FAMILY    connect first to addresses of specified family,\n\
508                                  one of IPv6, IPv4, or none.\n"),
509 #endif
510     N_("\
511        --user=USER               set both ftp and http user to USER.\n"),
512     N_("\
513        --password=PASS           set both ftp and http password to PASS.\n"),
514     N_("\
515        --ask-password            prompt for passwords.\n"),
516     N_("\
517        --no-iri                  turn off IRI support.\n"),
518     N_("\
519        --local-encoding=ENC      use ENC as the local encoding for IRIs.\n"),
520     N_("\
521        --remote-encoding=ENC     use ENC as the default remote encoding.\n"),
522     N_("\
523        --unlink                  remove file before clobber.\n"),
524     "\n",
525
526     N_("\
527 Directories:\n"),
528     N_("\
529   -nd, --no-directories           don't create directories.\n"),
530     N_("\
531   -x,  --force-directories        force creation of directories.\n"),
532     N_("\
533   -nH, --no-host-directories      don't create host directories.\n"),
534     N_("\
535        --protocol-directories     use protocol name in directories.\n"),
536     N_("\
537   -P,  --directory-prefix=PREFIX  save files to PREFIX/...\n"),
538     N_("\
539        --cut-dirs=NUMBER          ignore NUMBER remote directory components.\n"),
540     "\n",
541
542     N_("\
543 HTTP options:\n"),
544     N_("\
545        --http-user=USER        set http user to USER.\n"),
546     N_("\
547        --http-password=PASS    set http password to PASS.\n"),
548     N_("\
549        --no-cache              disallow server-cached data.\n"),
550     N_ ("\
551        --default-page=NAME     Change the default page name (normally\n\
552                                this is `index.html'.).\n"),
553     N_("\
554   -E,  --adjust-extension      save HTML/CSS documents with proper extensions.\n"),
555     N_("\
556        --ignore-length         ignore `Content-Length' header field.\n"),
557     N_("\
558        --header=STRING         insert STRING among the headers.\n"),
559     N_("\
560        --max-redirect          maximum redirections allowed per page.\n"),
561     N_("\
562        --proxy-user=USER       set USER as proxy username.\n"),
563     N_("\
564        --proxy-password=PASS   set PASS as proxy password.\n"),
565     N_("\
566        --referer=URL           include `Referer: URL' header in HTTP request.\n"),
567     N_("\
568        --save-headers          save the HTTP headers to file.\n"),
569     N_("\
570   -U,  --user-agent=AGENT      identify as AGENT instead of Wget/VERSION.\n"),
571     N_("\
572        --no-http-keep-alive    disable HTTP keep-alive (persistent connections).\n"),
573     N_("\
574        --no-cookies            don't use cookies.\n"),
575     N_("\
576        --load-cookies=FILE     load cookies from FILE before session.\n"),
577     N_("\
578        --save-cookies=FILE     save cookies to FILE after session.\n"),
579     N_("\
580        --keep-session-cookies  load and save session (non-permanent) cookies.\n"),
581     N_("\
582        --post-data=STRING      use the POST method; send STRING as the data.\n"),
583     N_("\
584        --post-file=FILE        use the POST method; send contents of FILE.\n"),
585     N_("\
586        --content-disposition   honor the Content-Disposition header when\n\
587                                choosing local file names (EXPERIMENTAL).\n"),
588     N_("\
589        --auth-no-challenge     send Basic HTTP authentication information\n\
590                                without first waiting for the server's\n\
591                                challenge.\n"),
592     "\n",
593
594 #ifdef HAVE_SSL
595     N_("\
596 HTTPS (SSL/TLS) options:\n"),
597     N_("\
598        --secure-protocol=PR     choose secure protocol, one of auto, SSLv2,\n\
599                                 SSLv3, and TLSv1.\n"),
600     N_("\
601        --no-check-certificate   don't validate the server's certificate.\n"),
602     N_("\
603        --certificate=FILE       client certificate file.\n"),
604     N_("\
605        --certificate-type=TYPE  client certificate type, PEM or DER.\n"),
606     N_("\
607        --private-key=FILE       private key file.\n"),
608     N_("\
609        --private-key-type=TYPE  private key type, PEM or DER.\n"),
610     N_("\
611        --ca-certificate=FILE    file with the bundle of CA's.\n"),
612     N_("\
613        --ca-directory=DIR       directory where hash list of CA's is stored.\n"),
614     N_("\
615        --random-file=FILE       file with random data for seeding the SSL PRNG.\n"),
616     N_("\
617        --egd-file=FILE          file naming the EGD socket with random data.\n"),
618     "\n",
619 #endif /* HAVE_SSL */
620
621     N_("\
622 FTP options:\n"),
623 #ifdef __VMS
624     N_("\
625        --ftp-stmlf             Use Stream_LF format for all binary FTP files.\n"),
626 #endif /* def __VMS */
627     N_("\
628        --ftp-user=USER         set ftp user to USER.\n"),
629     N_("\
630        --ftp-password=PASS     set ftp password to PASS.\n"),
631     N_("\
632        --no-remove-listing     don't remove `.listing' files.\n"),
633     N_("\
634        --no-glob               turn off FTP file name globbing.\n"),
635     N_("\
636        --no-passive-ftp        disable the \"passive\" transfer mode.\n"),
637     N_("\
638        --retr-symlinks         when recursing, get linked-to files (not dir).\n"),
639     "\n",
640
641     N_("\
642 Recursive download:\n"),
643     N_("\
644   -r,  --recursive          specify recursive download.\n"),
645     N_("\
646   -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n"),
647     N_("\
648        --delete-after       delete files locally after downloading them.\n"),
649     N_("\
650   -k,  --convert-links      make links in downloaded HTML or CSS point to\n\
651                             local files.\n"),
652 #ifdef __VMS
653     N_("\
654   -K,  --backup-converted   before converting file X, back up as X_orig.\n"),
655 #else /* def __VMS */
656     N_("\
657   -K,  --backup-converted   before converting file X, back up as X.orig.\n"),
658 #endif /* def __VMS [else] */
659     N_("\
660   -m,  --mirror             shortcut for -N -r -l inf --no-remove-listing.\n"),
661     N_("\
662   -p,  --page-requisites    get all images, etc. needed to display HTML page.\n"),
663     N_("\
664        --strict-comments    turn on strict (SGML) handling of HTML comments.\n"),
665     "\n",
666
667     N_("\
668 Recursive accept/reject:\n"),
669     N_("\
670   -A,  --accept=LIST               comma-separated list of accepted extensions.\n"),
671     N_("\
672   -R,  --reject=LIST               comma-separated list of rejected extensions.\n"),
673     N_("\
674   -D,  --domains=LIST              comma-separated list of accepted domains.\n"),
675     N_("\
676        --exclude-domains=LIST      comma-separated list of rejected domains.\n"),
677     N_("\
678        --follow-ftp                follow FTP links from HTML documents.\n"),
679     N_("\
680        --follow-tags=LIST          comma-separated list of followed HTML tags.\n"),
681     N_("\
682        --ignore-tags=LIST          comma-separated list of ignored HTML tags.\n"),
683     N_("\
684   -H,  --span-hosts                go to foreign hosts when recursive.\n"),
685     N_("\
686   -L,  --relative                  follow relative links only.\n"),
687     N_("\
688   -I,  --include-directories=LIST  list of allowed directories.\n"),
689     N_("\
690   --trust-server-names             use the name specified by the redirection\n\
691                                    url last component.\n"),
692     N_("\
693   -X,  --exclude-directories=LIST  list of excluded directories.\n"),
694     N_("\
695   -np, --no-parent                 don't ascend to the parent directory.\n"),
696     "\n",
697
698     N_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n")
699   };
700
701   size_t i;
702
703   printf (_("GNU Wget %s, a non-interactive network retriever.\n"),
704           version_string);
705   print_usage (0);
706
707   for (i = 0; i < countof (help); i++)
708     fputs (_(help[i]), stdout);
709
710   exit (0);
711 }
712
713 /* Return a human-readable printed representation of INTERVAL,
714    measured in seconds.  */
715
716 static char *
717 secs_to_human_time (double interval)
718 {
719   static char buf[32];
720   int secs = (int) (interval + 0.5);
721   int hours, mins, days;
722
723   days = secs / 86400, secs %= 86400;
724   hours = secs / 3600, secs %= 3600;
725   mins = secs / 60, secs %= 60;
726
727   if (days)
728     sprintf (buf, "%dd %dh %dm %ds", days, hours, mins, secs);
729   else if (hours)
730     sprintf (buf, "%dh %dm %ds", hours, mins, secs);
731   else if (mins)
732     sprintf (buf, "%dm %ds", mins, secs);
733   else
734     sprintf (buf, "%ss", print_decimal (interval));
735
736   return buf;
737 }
738
739 static char *
740 prompt_for_password (void)
741 {
742   if (opt.user)
743     printf (_("Password for user %s: "), quote (opt.user));
744   else
745     printf (_("Password: "));
746   return getpass("");
747 }
748
749 /* Function that prints the line argument while limiting it
750    to at most line_length. prefix is printed on the first line
751    and an appropriate number of spaces are added on subsequent
752    lines.*/
753 static void
754 format_and_print_line (const char *prefix, const char *line,
755                        int line_length)
756 {
757   int remaining_chars;
758   char *line_dup, *token;
759
760   assert (prefix != NULL);
761   assert (line != NULL);
762
763   line_dup = xstrdup (line);
764
765   if (line_length <= 0)
766     line_length = MAX_CHARS_PER_LINE - TABULATION;
767
768   printf ("%s", prefix);
769   remaining_chars = line_length;
770   /* We break on spaces. */
771   token = strtok (line_dup, " ");
772   while (token != NULL)
773     {
774       /* If however a token is much larger than the maximum
775          line length, all bets are off and we simply print the
776          token on the next line. */
777       if (remaining_chars <= strlen (token))
778         {
779           printf ("\n%*c", TABULATION, ' ');
780           remaining_chars = line_length - TABULATION;
781         }
782       printf ("%s ", token);
783       remaining_chars -= strlen (token) + 1;  /* account for " " */
784       token = strtok (NULL, " ");
785     }
786
787   printf ("\n");
788
789   xfree (line_dup);
790 }
791
792 static void
793 print_version (void)
794 {
795   const char *wgetrc_title  = _("Wgetrc: ");
796   const char *locale_title  = _("Locale: ");
797   const char *compile_title = _("Compile: ");
798   const char *link_title    = _("Link: ");
799   char *env_wgetrc, *user_wgetrc;
800   int i;
801
802   printf (_("GNU Wget %s built on %s.\n\n"), version_string, OS_TYPE);
803
804   for (i = 0; compiled_features[i] != NULL; )
805     {
806       int line_length = MAX_CHARS_PER_LINE;
807       while ((line_length > 0) && (compiled_features[i] != NULL))
808         {
809           printf ("%s ", compiled_features[i]);
810           line_length -= strlen (compiled_features[i]) + 2;
811           i++;
812         }
813       printf ("\n");
814     }
815   printf ("\n");
816
817   /* Handle the case when $WGETRC is unset and $HOME/.wgetrc is
818      absent. */
819   printf ("%s\n", wgetrc_title);
820   env_wgetrc = wgetrc_env_file_name ();
821   if (env_wgetrc && *env_wgetrc)
822     {
823       printf (_("    %s (env)\n"), env_wgetrc);
824       xfree (env_wgetrc);
825     }
826   user_wgetrc = wgetrc_user_file_name ();
827   if (user_wgetrc)
828     {
829       printf (_("    %s (user)\n"), user_wgetrc);
830       xfree (user_wgetrc);
831     }
832 #ifdef SYSTEM_WGETRC
833   printf (_("    %s (system)\n"), SYSTEM_WGETRC);
834 #endif
835
836 #ifdef ENABLE_NLS
837   format_and_print_line (locale_title,
838                         LOCALEDIR,
839                         MAX_CHARS_PER_LINE);
840 #endif /* def ENABLE_NLS */
841
842   if (compilation_string != NULL)
843     format_and_print_line (compile_title,
844                            compilation_string,
845                            MAX_CHARS_PER_LINE);
846
847   if (link_string != NULL)
848     format_and_print_line (link_title,
849                            link_string,
850                            MAX_CHARS_PER_LINE);
851
852   printf ("\n");
853   /* TRANSLATORS: When available, an actual copyright character
854      (cirle-c) should be used in preference to "(C)". */
855   fputs (_("\
856 Copyright (C) 2009 Free Software Foundation, Inc.\n"), stdout);
857   fputs (_("\
858 License GPLv3+: GNU GPL version 3 or later\n\
859 <http://www.gnu.org/licenses/gpl.html>.\n\
860 This is free software: you are free to change and redistribute it.\n\
861 There is NO WARRANTY, to the extent permitted by law.\n"), stdout);
862   /* TRANSLATORS: When available, please use the proper diacritics for
863      names such as this one. See en_US.po for reference. */
864   fputs (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"),
865          stdout);
866   fputs (_("Please send bug reports and questions to <bug-wget@gnu.org>.\n"),
867          stdout);
868   exit (0);
869 }
870
871 char *program_name; /* Needed by lib/error.c. */
872
873 int
874 main (int argc, char **argv)
875 {
876   char **url, **t;
877   int i, ret, longindex;
878   int nurl;
879   bool append_to_log = false;
880
881   total_downloaded_bytes = 0;
882
883   program_name = argv[0];
884
885   struct ptimer *timer = ptimer_new ();
886   double start_time = ptimer_measure (timer);
887
888   i18n_initialize ();
889
890   /* Construct the name of the executable, without the directory part.  */
891 #ifdef __VMS
892   /* On VMS, lose the "dev:[dir]" prefix and the ".EXE;nnn" suffix. */
893   exec_name = vms_basename (argv[0]);
894 #else /* def __VMS */
895   exec_name = strrchr (argv[0], PATH_SEPARATOR);
896   if (!exec_name)
897     exec_name = argv[0];
898   else
899     ++exec_name;
900 #endif /* def __VMS [else] */
901
902 #ifdef WINDOWS
903   /* Drop extension (typically .EXE) from executable filename. */
904   windows_main ((char **) &exec_name);
905 #endif
906
907   /* Load the hard-coded defaults.  */
908   defaults ();
909
910   init_switches ();
911
912   /* This seperate getopt_long is needed to find the user config
913      and parse it before the other user options. */
914   longindex = -1;
915   int retconf;
916   bool use_userconfig = false;
917
918   while ((retconf = getopt_long (argc, argv,
919                                 short_options, long_options, &longindex)) != -1)
920     {
921       int confval;
922       bool userrc_ret = true;
923       struct cmdline_option *config_opt;
924       confval = long_options[longindex].val;
925       config_opt = &option_data[confval & ~BOOLEAN_NEG_MARKER];
926       if (strcmp (config_opt->long_name, "config") == 0)
927         {
928           userrc_ret &= run_wgetrc (optarg);
929           use_userconfig = true;
930         }
931       if (!userrc_ret)
932         {
933           printf ("Exiting due to error in %s\n", optarg);
934           exit (2);
935         }
936       else
937         break;
938     }
939
940   /* If the user did not specify a config, read the system wgetrc and ~/.wgetrc. */
941   if (use_userconfig == false)
942     initialize ();
943
944   opterr = 0;
945   optind = 0;
946
947   longindex = -1;
948   while ((ret = getopt_long (argc, argv,
949                              short_options, long_options, &longindex)) != -1)
950     {
951       int val;
952       struct cmdline_option *opt;
953
954       /* If LONGINDEX is unchanged, it means RET is referring a short
955          option.  */
956       if (longindex == -1)
957         {
958           if (ret == '?')
959             {
960               print_usage (0);
961               printf ("\n");
962               printf (_("Try `%s --help' for more options.\n"), exec_name);
963               exit (2);
964             }
965           /* Find the short option character in the mapping.  */
966           longindex = optmap[ret - 32];
967         }
968       val = long_options[longindex].val;
969
970       /* Use the retrieved value to locate the option in the
971          option_data array, and to see if we're dealing with the
972          negated "--no-FOO" variant of the boolean option "--foo".  */
973       opt = &option_data[val & ~BOOLEAN_NEG_MARKER];
974       switch (opt->type)
975         {
976         case OPT_VALUE:
977           setoptval (opt->data, optarg, opt->long_name);
978           break;
979         case OPT_BOOLEAN:
980           if (optarg)
981             /* The user has specified a value -- use it. */
982             setoptval (opt->data, optarg, opt->long_name);
983           else
984             {
985               /* NEG is true for `--no-FOO' style boolean options. */
986               bool neg = !!(val & BOOLEAN_NEG_MARKER);
987               setoptval (opt->data, neg ? "0" : "1", opt->long_name);
988             }
989           break;
990         case OPT_FUNCALL:
991           {
992             void (*func) (void) = (void (*) (void)) opt->data;
993             func ();
994           }
995           break;
996         case OPT__APPEND_OUTPUT:
997           setoptval ("logfile", optarg, opt->long_name);
998           append_to_log = true;
999           break;
1000         case OPT__EXECUTE:
1001           run_command (optarg);
1002           break;
1003         case OPT__NO:
1004           {
1005             /* We support real --no-FOO flags now, but keep these
1006                short options for convenience and backward
1007                compatibility.  */
1008             char *p;
1009             for (p = optarg; p && *p; p++)
1010               switch (*p)
1011                 {
1012                 case 'v':
1013                   setoptval ("verbose", "0", opt->long_name);
1014                   break;
1015                 case 'H':
1016                   setoptval ("addhostdir", "0", opt->long_name);
1017                   break;
1018                 case 'd':
1019                   setoptval ("dirstruct", "0", opt->long_name);
1020                   break;
1021                 case 'c':
1022                   setoptval ("noclobber", "1", opt->long_name);
1023                   break;
1024                 case 'p':
1025                   setoptval ("noparent", "1", opt->long_name);
1026                   break;
1027                 default:
1028                   fprintf (stderr, _("%s: illegal option -- `-n%c'\n"),
1029                            exec_name, *p);
1030                   print_usage (1);
1031                   fprintf (stderr, "\n");
1032                   fprintf (stderr, _("Try `%s --help' for more options.\n"),
1033                            exec_name);
1034                   exit (1);
1035                 }
1036             break;
1037           }
1038         case OPT__PARENT:
1039         case OPT__CLOBBER:
1040           {
1041             /* The wgetrc commands are named noparent and noclobber,
1042                so we must revert the meaning of the cmdline options
1043                before passing the value to setoptval.  */
1044             bool flag = true;
1045             if (optarg)
1046               flag = (*optarg == '1' || c_tolower (*optarg) == 'y'
1047                       || (c_tolower (optarg[0]) == 'o'
1048                           && c_tolower (optarg[1]) == 'n'));
1049             setoptval (opt->type == OPT__PARENT ? "noparent" : "noclobber",
1050                        flag ? "0" : "1", opt->long_name);
1051             break;
1052           }
1053         case OPT__DONT_REMOVE_LISTING:
1054           setoptval ("removelisting", "0", opt->long_name);
1055           break;
1056         }
1057
1058       longindex = -1;
1059     }
1060
1061   nurl = argc - optind;
1062
1063   /* All user options have now been processed, so it's now safe to do
1064      interoption dependency checks. */
1065
1066   if (opt.noclobber && opt.convert_links)
1067     {
1068       fprintf (stderr,
1069                _("Both --no-clobber and --convert-links were specified,"
1070                  "only --convert-links will be used.\n"));
1071       opt.noclobber = false;
1072     }
1073
1074   if (opt.reclevel == 0)
1075       opt.reclevel = INFINITE_RECURSION; /* see recur.h for commentary */
1076
1077   if (opt.spider || opt.delete_after)
1078       opt.no_dirstruct = true;
1079
1080   if (opt.page_requisites && !opt.recursive)
1081     {
1082       /* Don't set opt.recursive here because it would confuse the FTP
1083          code.  Instead, call retrieve_tree below when either
1084          page_requisites or recursive is requested.  */
1085       opt.reclevel = 0;
1086       if (!opt.no_dirstruct)
1087         opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
1088     }
1089
1090   if (opt.verbose == -1)
1091     opt.verbose = !opt.quiet;
1092
1093   /* Sanity checks.  */
1094   if (opt.verbose && opt.quiet)
1095     {
1096       fprintf (stderr, _("Can't be verbose and quiet at the same time.\n"));
1097       print_usage (1);
1098       exit (1);
1099     }
1100   if (opt.timestamping && opt.noclobber)
1101     {
1102       fprintf (stderr, _("\
1103 Can't timestamp and not clobber old files at the same time.\n"));
1104       print_usage (1);
1105       exit (1);
1106     }
1107 #ifdef ENABLE_IPV6
1108   if (opt.ipv4_only && opt.ipv6_only)
1109     {
1110       fprintf (stderr,
1111                _("Cannot specify both --inet4-only and --inet6-only.\n"));
1112       print_usage (1);
1113       exit (1);
1114     }
1115 #endif
1116   if (opt.output_document)
1117     {
1118       if (opt.convert_links
1119           && (nurl > 1 || opt.page_requisites || opt.recursive))
1120         {
1121           fputs (_("\
1122 Cannot specify both -k and -O if multiple URLs are given, or in combination\n\
1123 with -p or -r. See the manual for details.\n\n"), stderr);
1124           print_usage (1);
1125           exit (1);
1126         }
1127       if (opt.page_requisites
1128           || opt.recursive)
1129         {
1130           logprintf (LOG_NOTQUIET, "%s", _("\
1131 WARNING: combining -O with -r or -p will mean that all downloaded content\n\
1132 will be placed in the single file you specified.\n\n"));
1133         }
1134       if (opt.timestamping)
1135         {
1136           logprintf (LOG_NOTQUIET, "%s", _("\
1137 WARNING: timestamping does nothing in combination with -O. See the manual\n\
1138 for details.\n\n"));
1139           opt.timestamping = false;
1140         }
1141       if (opt.noclobber && file_exists_p(opt.output_document))
1142            {
1143               /* Check if output file exists; if it does, exit. */
1144               logprintf (LOG_VERBOSE,
1145                          _("File `%s' already there; not retrieving.\n"),
1146                          opt.output_document);
1147               exit(1);
1148            }
1149     }
1150
1151   if (opt.ask_passwd && opt.passwd)
1152     {
1153       fprintf (stderr,
1154                _("Cannot specify both --ask-password and --password.\n"));
1155       print_usage (1);
1156       exit (1);
1157     }
1158
1159   if (!nurl && !opt.input_filename)
1160     {
1161       /* No URL specified.  */
1162       fprintf (stderr, _("%s: missing URL\n"), exec_name);
1163       print_usage (1);
1164       printf ("\n");
1165       /* #### Something nicer should be printed here -- similar to the
1166          pre-1.5 `--help' page.  */
1167       fprintf (stderr, _("Try `%s --help' for more options.\n"), exec_name);
1168       exit (1);
1169     }
1170
1171 #ifdef ENABLE_IRI
1172   if (opt.enable_iri)
1173     {
1174       if (opt.locale && !check_encoding_name (opt.locale))
1175         opt.locale = NULL;
1176
1177       if (!opt.locale)
1178         opt.locale = find_locale ();
1179
1180       if (opt.encoding_remote && !check_encoding_name (opt.encoding_remote))
1181         opt.encoding_remote = NULL;
1182     }
1183 #else
1184   if (opt.enable_iri || opt.locale || opt.encoding_remote)
1185     {
1186       /* sXXXav : be more specific... */
1187       fprintf (stderr, _("This version does not have support for IRIs\n"));
1188       exit(1);
1189     }
1190 #endif
1191
1192   if (opt.ask_passwd)
1193     {
1194       opt.passwd = prompt_for_password ();
1195
1196       if (opt.passwd == NULL || opt.passwd[0] == '\0')
1197         exit (1);
1198     }
1199
1200 #ifdef USE_WATT32
1201   if (opt.wdebug)
1202      dbug_init();
1203   sock_init();
1204 #else
1205   if (opt.background)
1206     fork_to_background ();
1207 #endif
1208
1209   /* Initialize progress.  Have to do this after the options are
1210      processed so we know where the log file is.  */
1211   if (opt.verbose)
1212     set_progress_implementation (opt.progress_type);
1213
1214   /* Fill in the arguments.  */
1215   url = alloca_array (char *, nurl + 1);
1216   for (i = 0; i < nurl; i++, optind++)
1217     {
1218       char *rewritten = rewrite_shorthand_url (argv[optind]);
1219       if (rewritten)
1220         url[i] = rewritten;
1221       else
1222         url[i] = xstrdup (argv[optind]);
1223     }
1224   url[i] = NULL;
1225
1226   /* Initialize logging.  */
1227   log_init (opt.lfilename, append_to_log);
1228
1229   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n",
1230            version_string, OS_TYPE));
1231
1232   /* Open the output filename if necessary.  */
1233
1234 /* 2005-04-17 SMS.
1235    Note that having the output_stream ("-O") file opened here for an FTP
1236    URL rather than in getftp() (ftp.c) (and the http equivalent) rather
1237    limits the ability in VMS to open the file differently for ASCII
1238    versus binary FTP there.  (Of course, doing it here allows a open
1239    failure to be detected immediately, without first connecting to the
1240    server.)
1241 */
1242   if (opt.output_document)
1243     {
1244       if (HYPHENP (opt.output_document))
1245         {
1246 #ifdef WINDOWS
1247           FILE *result;
1248           result = freopen ("CONOUT$", "wb", stdout);
1249           if (result == NULL)
1250             {
1251               logputs (LOG_NOTQUIET, _("\
1252 WARNING: Can't reopen standard output in binary mode;\n\
1253          downloaded file may contain inappropriate line endings.\n"));
1254             }
1255 #endif
1256           output_stream = stdout;
1257         }
1258       else
1259         {
1260           struct_fstat st;
1261
1262 #ifdef __VMS
1263 /* Common fopen() optional arguments:
1264    sequential access only, access callback function.
1265 */
1266 # define FOPEN_OPT_ARGS , "fop=sqo", "acc", acc_cb, &open_id
1267           int open_id = 7;
1268 #else /* def __VMS */
1269 # define FOPEN_OPT_ARGS
1270 #endif /* def __VMS [else] */
1271
1272           output_stream = fopen (opt.output_document,
1273                                  opt.always_rest ? "ab" : "wb"
1274                                  FOPEN_OPT_ARGS);
1275           if (output_stream == NULL)
1276             {
1277               perror (opt.output_document);
1278               exit (1);
1279             }
1280           if (fstat (fileno (output_stream), &st) == 0 && S_ISREG (st.st_mode))
1281             output_stream_regular = true;
1282         }
1283       if (!output_stream_regular && opt.convert_links)
1284         {
1285           fprintf (stderr, _("-k can be used together with -O only if \
1286 outputting to a regular file.\n"));
1287           print_usage (1);
1288           exit(1);
1289         }
1290     }
1291
1292 #ifdef __VMS
1293   /* Set global ODS5 flag according to the specified destination (if
1294      any), otherwise according to the current default device.
1295   */
1296   if (output_stream == NULL)
1297     set_ods5_dest( "SYS$DISK");
1298   else if (output_stream != stdout)
1299     set_ods5_dest( opt.output_document);
1300 #endif /* def __VMS */
1301
1302 #ifdef WINDOWS
1303   ws_startup ();
1304 #endif
1305
1306 #ifdef SIGHUP
1307   /* Setup the signal handler to redirect output when hangup is
1308      received.  */
1309   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1310     signal(SIGHUP, redirect_output_signal);
1311 #endif
1312   /* ...and do the same for SIGUSR1.  */
1313 #ifdef SIGUSR1
1314   signal (SIGUSR1, redirect_output_signal);
1315 #endif
1316 #ifdef SIGPIPE
1317   /* Writing to a closed socket normally signals SIGPIPE, and the
1318      process exits.  What we want is to ignore SIGPIPE and just check
1319      for the return value of write().  */
1320   signal (SIGPIPE, SIG_IGN);
1321 #endif
1322 #ifdef SIGWINCH
1323   signal (SIGWINCH, progress_handle_sigwinch);
1324 #endif
1325
1326   /* Retrieve the URLs from argument list.  */
1327   for (t = url; *t; t++)
1328     {
1329       char *filename = NULL, *redirected_URL = NULL;
1330       int dt, url_err;
1331       /* Need to do a new struct iri every time, because
1332        * retrieve_url may modify it in some circumstances,
1333        * currently. */
1334       struct iri *iri = iri_new ();
1335       struct url *url_parsed;
1336
1337       set_uri_encoding (iri, opt.locale, true);
1338       url_parsed = url_parse (*t, &url_err, iri, true);
1339
1340       if (!url_parsed)
1341         {
1342           char *error = url_error (*t, url_err);
1343           logprintf (LOG_NOTQUIET, "%s: %s.\n",*t, error);
1344           xfree (error);
1345         }
1346       else
1347         {
1348           if ((opt.recursive || opt.page_requisites)
1349               && (url_scheme (*t) != SCHEME_FTP || url_uses_proxy (url_parsed)))
1350             {
1351               int old_follow_ftp = opt.follow_ftp;
1352
1353               /* Turn opt.follow_ftp on in case of recursive FTP retrieval */
1354               if (url_scheme (*t) == SCHEME_FTP)
1355                 opt.follow_ftp = 1;
1356
1357               retrieve_tree (url_parsed, NULL);
1358
1359               opt.follow_ftp = old_follow_ftp;
1360             }
1361           else
1362           {
1363             retrieve_url (url_parsed, *t, &filename, &redirected_URL, NULL,
1364                           &dt, opt.recursive, iri, true);
1365           }
1366
1367           if (opt.delete_after && file_exists_p(filename))
1368             {
1369               DEBUGP (("Removing file due to --delete-after in main():\n"));
1370               logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
1371               if (unlink (filename))
1372                 logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
1373             }
1374           xfree_null (redirected_URL);
1375           xfree_null (filename);
1376           url_free (url_parsed);
1377         }
1378       iri_free (iri);
1379     }
1380
1381   /* And then from the input file, if any.  */
1382   if (opt.input_filename)
1383     {
1384       int count;
1385       retrieve_from_file (opt.input_filename, opt.force_html, &count);
1386       if (!count)
1387         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
1388                    opt.input_filename);
1389     }
1390
1391   /* Print broken links. */
1392   if (opt.recursive && opt.spider)
1393     print_broken_links ();
1394
1395   /* Print the downloaded sum.  */
1396   if ((opt.recursive || opt.page_requisites
1397        || nurl > 1
1398        || (opt.input_filename && total_downloaded_bytes != 0))
1399       &&
1400       total_downloaded_bytes != 0)
1401     {
1402       double end_time = ptimer_measure (timer);
1403       ptimer_destroy (timer);
1404
1405       char *wall_time = xstrdup (secs_to_human_time (end_time - start_time));
1406       char *download_time = xstrdup (secs_to_human_time (total_download_time));
1407       logprintf (LOG_NOTQUIET,
1408                  _("FINISHED --%s--\nTotal wall clock time: %s\n"
1409                    "Downloaded: %d files, %s in %s (%s)\n"),
1410                  datetime_str (time (NULL)),
1411                  wall_time,
1412                  numurls,
1413                  human_readable (total_downloaded_bytes),
1414                  download_time,
1415                  retr_rate (total_downloaded_bytes, total_download_time));
1416       xfree (wall_time);
1417       xfree (download_time);
1418
1419       /* Print quota warning, if exceeded.  */
1420       if (opt.quota && total_downloaded_bytes > opt.quota)
1421         logprintf (LOG_NOTQUIET,
1422                    _("Download quota of %s EXCEEDED!\n"),
1423                    human_readable (opt.quota));
1424     }
1425
1426   if (opt.cookies_output)
1427     save_cookies ();
1428
1429   if (opt.convert_links && !opt.delete_after)
1430     convert_all_links ();
1431
1432   log_close ();
1433   for (i = 0; i < nurl; i++)
1434     xfree (url[i]);
1435   cleanup ();
1436
1437   return get_exit_status ();
1438 }
1439 #endif /* TESTING */
1440 \f
1441 #if defined(SIGHUP) || defined(SIGUSR1)
1442
1443 /* So the signal_name check doesn't blow when only one is available. */
1444 #ifndef SIGHUP
1445 # define SIGHUP -1
1446 #endif
1447 #ifndef SIGUSR1
1448 # define SIGUSR1 -1
1449 #endif
1450
1451 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
1452    will proceed operation as usual, trying to write into a log file.
1453    If that is impossible, the output will be turned off.  */
1454
1455 static void
1456 redirect_output_signal (int sig)
1457 {
1458   const char *signal_name = (sig == SIGHUP ? "SIGHUP" :
1459                              (sig == SIGUSR1 ? "SIGUSR1" :
1460                               "WTF?!"));
1461   log_request_redirect_output (signal_name);
1462   progress_schedule_redirect ();
1463   signal (sig, redirect_output_signal);
1464 }
1465 #endif
1466
1467 /*
1468  * vim: et ts=2 sw=2
1469  */