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