]> sjero.net Git - wget/blob - src/main.c
[svn] Improve SSL code. Only initialize PRNG when needed.
[wget] / src / main.c
1 /* Command line parsing.
2    Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002
3    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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 In addition, as a special exception, the Free Software Foundation
22 gives permission to link the code of its release of Wget with the
23 OpenSSL project's "OpenSSL" library (or with modified versions of it
24 that use the same license as the "OpenSSL" library), and distribute
25 the linked executables.  You must obey the GNU General Public License
26 in all respects for all of the code used other than "OpenSSL".  If you
27 modify this file, you may extend this exception to your version of the
28 file, but you are not obligated to do so.  If you do not wish to do
29 so, delete this exception statement from your version.  */
30
31 #include <config.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 <sys/types.h>
39 #ifdef HAVE_STRING_H
40 # include <string.h>
41 #else
42 # include <strings.h>
43 #endif /* HAVE_STRING_H */
44 #ifdef HAVE_SIGNAL_H
45 # include <signal.h>
46 #endif
47 #ifdef HAVE_NLS
48 #ifdef HAVE_LOCALE_H
49 # include <locale.h>
50 #endif /* HAVE_LOCALE_H */
51 #endif /* HAVE_NLS */
52 #include <errno.h>
53 #ifndef errno
54 extern int errno;
55 #endif
56
57 #include "wget.h"
58 #include "utils.h"
59 #include "init.h"
60 #include "retr.h"
61 #include "recur.h"
62 #include "host.h"
63 #include "cookies.h"
64 #include "url.h"
65 #include "progress.h"           /* for progress_handle_sigwinch */
66 #include "convert.h"
67
68 /* On GNU system this will include system-wide getopt.h. */
69 #include "getopt.h"
70
71 #ifndef PATH_SEPARATOR
72 # define PATH_SEPARATOR '/'
73 #endif
74
75 struct options opt;
76
77 extern LARGE_INT total_downloaded_bytes;
78 extern char *version_string;
79
80 extern struct cookie_jar *wget_cookie_jar;
81
82 /* From log.c.  */
83 void log_init PARAMS ((const char *, int));
84 void log_close PARAMS ((void));
85 void log_request_redirect_output PARAMS ((const char *));
86
87 static RETSIGTYPE redirect_output_signal PARAMS ((int));
88
89 const char *exec_name;
90 \f
91 /* Initialize I18N.  The initialization amounts to invoking
92    setlocale(), bindtextdomain() and textdomain().
93    Does nothing if NLS is disabled or missing.  */
94 static void
95 i18n_initialize (void)
96 {
97   /* If HAVE_NLS is defined, assume the existence of the three
98      functions invoked here.  */
99 #ifdef HAVE_NLS
100   /* Set the current locale.  */
101   /* Here we use LC_MESSAGES instead of LC_ALL, for two reasons.
102      First, message catalogs are all of I18N Wget uses anyway.
103      Second, setting LC_ALL has a dangerous potential of messing
104      things up.  For example, when in a foreign locale, Solaris
105      strptime() fails to handle international dates correctly, which
106      makes http_atotm() malfunction.  */
107 #ifdef LC_MESSAGES
108   setlocale (LC_MESSAGES, "");
109   setlocale (LC_CTYPE, "");
110 #else
111   setlocale (LC_ALL, "");
112 #endif
113   /* Set the text message domain.  */
114   bindtextdomain ("wget", LOCALEDIR);
115   textdomain ("wget");
116 #endif /* HAVE_NLS */
117 }
118 \f
119 /* Print the usage message.  */
120 static void
121 print_usage (void)
122 {
123   printf (_("Usage: %s [OPTION]... [URL]...\n"), exec_name);
124 }
125
126 /* Print the help message, describing all the available options.  If
127    you add an option, be sure to update this list.  */
128 static void
129 print_help (void)
130 {
131   printf (_("GNU Wget %s, a non-interactive network retriever.\n"),
132           version_string);
133   print_usage ();
134   /* Had to split this in parts, so the #@@#%# Ultrix compiler and cpp
135      don't bitch.  Also, it makes translation much easier.  */
136   fputs (_("\
137 \n\
138 Mandatory arguments to long options are mandatory for short options too.\n\
139 \n"), stdout);
140   fputs (_("\
141 Startup:\n\
142   -V,  --version           display the version of Wget and exit.\n\
143   -h,  --help              print this help.\n\
144   -b,  --background        go to background after startup.\n\
145   -e,  --execute=COMMAND   execute a `.wgetrc\'-style command.\n\
146 \n"), stdout);
147   fputs (_("\
148 Logging and input file:\n\
149   -o,  --output-file=FILE     log messages to FILE.\n\
150   -a,  --append-output=FILE   append messages to FILE.\n\
151   -d,  --debug                print debug output.\n\
152   -q,  --quiet                quiet (no output).\n\
153   -v,  --verbose              be verbose (this is the default).\n\
154   -nv, --non-verbose          turn off verboseness, without being quiet.\n\
155   -i,  --input-file=FILE      download URLs found in FILE.\n\
156   -F,  --force-html           treat input file as HTML.\n\
157   -B,  --base=URL             prepends URL to relative links in -F -i file.\n\
158 \n"),stdout);
159   fputs (_("\
160 Download:\n\
161   -t,  --tries=NUMBER           set number of retries to NUMBER (0 unlimits).\n\
162        --retry-connrefused      retry even if connection is refused.\n\
163   -O   --output-document=FILE   write documents to FILE.\n\
164   -nc, --no-clobber             don\'t clobber existing files or use .# suffixes.\n\
165   -c,  --continue               resume getting a partially-downloaded file.\n\
166        --progress=TYPE          select progress gauge type.\n\
167   -N,  --timestamping           don\'t re-retrieve files unless newer than local.\n\
168   -S,  --server-response        print server response.\n\
169        --spider                 don\'t download anything.\n\
170   -T,  --timeout=SECONDS        set all timeout values to SECONDS.\n\
171        --dns-timeout=SECS       set the DNS lookup timeout to SECS.\n\
172        --connect-timeout=SECS   set the connect timeout to SECS.\n\
173        --read-timeout=SECS      set the read timeout to SECS.\n\
174   -w,  --wait=SECONDS           wait SECONDS between retrievals.\n\
175        --waitretry=SECONDS      wait 1...SECONDS between retries of a retrieval.\n\
176        --random-wait            wait from 0...2*WAIT secs between retrievals.\n\
177   -Y,  --proxy=on/off           turn proxy on or off.\n\
178   -Q,  --quota=NUMBER           set retrieval quota to NUMBER.\n\
179        --bind-address=ADDRESS   bind to ADDRESS (hostname or IP) on local host.\n\
180        --limit-rate=RATE        limit download rate to RATE.\n\
181        --dns-cache=off          disable caching DNS lookups.\n\
182        --restrict-file-names=OS restrict chars in file names to ones OS allows.\n\
183 \n"), stdout);
184   fputs (_("\
185 Directories:\n\
186   -nd, --no-directories            don\'t create directories.\n\
187   -x,  --force-directories         force creation of directories.\n\
188   -nH, --no-host-directories       don\'t create host directories.\n\
189   -P,  --directory-prefix=PREFIX   save files to PREFIX/...\n\
190        --cut-dirs=NUMBER           ignore NUMBER remote directory components.\n\
191 \n"), stdout);
192   fputs (_("\
193 HTTP options:\n\
194        --http-user=USER      set http user to USER.\n\
195        --http-passwd=PASS    set http password to PASS.\n\
196   -C,  --cache=on/off        (dis)allow server-cached data (normally allowed).\n\
197   -E,  --html-extension      save all text/html documents with .html extension.\n\
198        --ignore-length       ignore `Content-Length\' header field.\n\
199        --header=STRING       insert STRING among the headers.\n\
200        --proxy-user=USER     set USER as proxy username.\n\
201        --proxy-passwd=PASS   set PASS as proxy password.\n\
202        --referer=URL         include `Referer: URL\' header in HTTP request.\n\
203   -s,  --save-headers        save the HTTP headers to file.\n\
204   -U,  --user-agent=AGENT    identify as AGENT instead of Wget/VERSION.\n\
205        --no-http-keep-alive  disable HTTP keep-alive (persistent connections).\n\
206        --cookies=off         don't use cookies.\n\
207        --load-cookies=FILE   load cookies from FILE before session.\n\
208        --save-cookies=FILE   save cookies to FILE after session.\n\
209        --keep-session-cookies  load and save session (non-permanent) cookies.\n\
210        --post-data=STRING    use the POST method; send STRING as the data.\n\
211        --post-file=FILE      use the POST method; send contents of FILE.\n\
212 \n"), stdout);
213 #ifdef HAVE_SSL
214   fputs (_("\
215 HTTPS (SSL) options:\n\
216        --sslcertfile=FILE     optional client certificate.\n\
217        --sslcertkey=KEYFILE   optional keyfile for this certificate.\n\
218        --egd-file=FILE        file name of the EGD socket.\n\
219        --sslcadir=DIR         dir where hash list of CA's are stored.\n\
220        --sslcafile=FILE       file with bundle of CA's\n\
221        --sslcerttype=0/1      Client-Cert type 0=PEM (default) / 1=ASN1 (DER)\n\
222        --sslcheckcert=0/1     Check the server cert agenst given CA\n\
223        --sslprotocol=0-3      choose SSL protocol; 0=automatic,\n\
224                               1=SSLv2 2=SSLv3 3=TLSv1\n\
225 \n"), stdout);
226 #endif
227   fputs (_("\
228 FTP options:\n\
229   -nr, --dont-remove-listing   don\'t remove `.listing\' files.\n\
230   -g,  --glob=on/off           turn file name globbing on or off.\n\
231        --passive-ftp           use the \"passive\" transfer mode.\n\
232        --retr-symlinks         when recursing, get linked-to files (not dirs).\n\
233 \n"), stdout);
234   fputs (_("\
235 Recursive retrieval:\n\
236   -r,  --recursive          recursive download.\n\
237   -l,  --level=NUMBER       maximum recursion depth (inf or 0 for infinite).\n\
238        --delete-after       delete files locally after downloading them.\n\
239   -k,  --convert-links      convert non-relative links to relative.\n\
240   -K,  --backup-converted   before converting file X, back up as X.orig.\n\
241   -m,  --mirror             shortcut option equivalent to -r -N -l inf -nr.\n\
242   -p,  --page-requisites    get all images, etc. needed to display HTML page.\n\
243        --strict-comments    turn on strict (SGML) handling of HTML comments.\n\
244 \n"), stdout);
245   fputs (_("\
246 Recursive accept/reject:\n\
247   -A,  --accept=LIST                comma-separated list of accepted extensions.\n\
248   -R,  --reject=LIST                comma-separated list of rejected extensions.\n\
249   -D,  --domains=LIST               comma-separated list of accepted domains.\n\
250        --exclude-domains=LIST       comma-separated list of rejected domains.\n\
251        --follow-ftp                 follow FTP links from HTML documents.\n\
252        --follow-tags=LIST           comma-separated list of followed HTML tags.\n\
253   -G,  --ignore-tags=LIST           comma-separated list of ignored HTML tags.\n\
254   -H,  --span-hosts                 go to foreign hosts when recursive.\n\
255   -L,  --relative                   follow relative links only.\n\
256   -I,  --include-directories=LIST   list of allowed directories.\n\
257   -X,  --exclude-directories=LIST   list of excluded directories.\n\
258   -np, --no-parent                  don\'t ascend to the parent directory.\n\
259 \n"), stdout);
260   fputs (_("Mail bug reports and suggestions to <bug-wget@gnu.org>.\n"),
261          stdout);
262 }
263 \f
264 int
265 main (int argc, char *const *argv)
266 {
267   char **url, **t;
268   int i, c, nurl, status, append_to_log;
269
270   static struct option long_options[] =
271   {
272     /* Options without arguments: */
273     { "background", no_argument, NULL, 'b' },
274     { "backup-converted", no_argument, NULL, 'K' },
275     { "continue", no_argument, NULL, 'c' },
276     { "convert-links", no_argument, NULL, 'k' },
277     { "debug", no_argument, NULL, 'd' },
278     { "delete-after", no_argument, NULL, 136 },
279     { "dont-remove-listing", no_argument, NULL, 149 },
280     { "follow-ftp", no_argument, NULL, 142 },
281     { "force-directories", no_argument, NULL, 'x' },
282     { "force-hier", no_argument, NULL, 'x' }, /* obsolete */
283     { "force-html", no_argument, NULL, 'F'},
284     { "help", no_argument, NULL, 'h' },
285     { "html-extension", no_argument, NULL, 'E' },
286     { "ignore-length", no_argument, NULL, 138 },
287     { "keep-session-cookies", no_argument, NULL, 181 },
288     { "mirror", no_argument, NULL, 'm' },
289     { "no-clobber", no_argument, NULL, 141 },
290     { "no-directories", no_argument, NULL, 147 },
291     { "no-host-directories", no_argument, NULL, 148 },
292     { "no-host-lookup", no_argument, NULL, 150 },
293     { "no-http-keep-alive", no_argument, NULL, 156 },
294     { "no-parent", no_argument, NULL, 133 },
295     { "non-verbose", no_argument, NULL, 146 },
296     { "passive-ftp", no_argument, NULL, 139 },
297     { "page-requisites", no_argument, NULL, 'p' },
298     { "quiet", no_argument, NULL, 'q' },
299     { "random-wait", no_argument, NULL, 165 },
300     { "recursive", no_argument, NULL, 'r' },
301     { "relative", no_argument, NULL, 'L' },
302     { "retr-symlinks", no_argument, NULL, 137 },
303     { "retry-connrefused", no_argument, NULL, 174 },
304     { "save-headers", no_argument, NULL, 's' },
305     { "server-response", no_argument, NULL, 'S' },
306     { "span-hosts", no_argument, NULL, 'H' },
307     { "spider", no_argument, NULL, 132 },
308     { "strict-comments", no_argument, NULL, 177 },
309     { "timestamping", no_argument, NULL, 'N' },
310     { "verbose", no_argument, NULL, 'v' },
311     { "version", no_argument, NULL, 'V' },
312
313     /* Options accepting an argument: */
314     { "accept", required_argument, NULL, 'A' },
315     { "append-output", required_argument, NULL, 'a' },
316     { "backups", required_argument, NULL, 151 }, /* undocumented */
317     { "base", required_argument, NULL, 'B' },
318     { "bind-address", required_argument, NULL, 155 },
319     { "cache", required_argument, NULL, 'C' },
320     { "connect-timeout", required_argument, NULL, 180 },
321     { "cookies", required_argument, NULL, 160 },
322     { "cut-dirs", required_argument, NULL, 145 },
323     { "dns-timeout", required_argument, NULL, 178 },
324     { "directory-prefix", required_argument, NULL, 'P' },
325     { "dns-cache", required_argument, NULL, 175 },
326     { "domains", required_argument, NULL, 'D' },
327     { "dot-style", required_argument, NULL, 134 },
328     { "execute", required_argument, NULL, 'e' },
329     { "exclude-directories", required_argument, NULL, 'X' },
330     { "exclude-domains", required_argument, NULL, 140 },
331     { "follow-tags", required_argument, NULL, 153 },
332     { "glob", required_argument, NULL, 'g' },
333     { "header", required_argument, NULL, 131 },
334     { "htmlify", required_argument, NULL, 135 },
335     { "http-passwd", required_argument, NULL, 130 },
336     { "http-user", required_argument, NULL, 129 },
337     { "ignore-tags", required_argument, NULL, 'G' },
338     { "include-directories", required_argument, NULL, 'I' },
339     { "input-file", required_argument, NULL, 'i' },
340     { "level", required_argument, NULL, 'l' },
341     { "limit-rate", required_argument, NULL, 164 },
342     { "load-cookies", required_argument, NULL, 161 },
343     { "no", required_argument, NULL, 'n' },
344     { "output-document", required_argument, NULL, 'O' },
345     { "output-file", required_argument, NULL, 'o' },
346     { "post-data", required_argument, NULL, 167 },
347     { "post-file", required_argument, NULL, 168 },
348     { "progress", required_argument, NULL, 163 },
349     { "proxy", required_argument, NULL, 'Y' },
350     { "proxy-passwd", required_argument, NULL, 144 },
351     { "proxy-user", required_argument, NULL, 143 },
352     { "quota", required_argument, NULL, 'Q' },
353     { "read-timeout", required_argument, NULL, 179 },
354     { "reject", required_argument, NULL, 'R' },
355     { "restrict-file-names", required_argument, NULL, 176 },
356     { "save-cookies", required_argument, NULL, 162 },
357     { "timeout", required_argument, NULL, 'T' },
358     { "tries", required_argument, NULL, 't' },
359     { "user-agent", required_argument, NULL, 'U' },
360     { "referer", required_argument, NULL, 157 },
361     { "use-proxy", required_argument, NULL, 'Y' },
362 #ifdef HAVE_SSL
363     { "sslcertfile", required_argument, NULL, 158 },
364     { "sslcertkey", required_argument, NULL, 159 },
365     { "egd-file", required_argument, NULL, 166 },
366     { "sslcadir",         required_argument, NULL, 169},
367     { "sslcafile",        required_argument, NULL, 170},
368     { "sslcerttype",      required_argument, NULL, 171},
369     { "sslcheckcert",     required_argument, NULL, 172},
370     { "sslprotocol",      required_argument, NULL, 173},
371 #endif /* HAVE_SSL */
372     { "wait", required_argument, NULL, 'w' },
373     { "waitretry", required_argument, NULL, 152 },
374     { 0, 0, 0, 0 }
375   };
376
377   i18n_initialize ();
378
379   append_to_log = 0;
380
381   /* Construct the name of the executable, without the directory part.  */
382   exec_name = strrchr (argv[0], PATH_SEPARATOR);
383   if (!exec_name)
384     exec_name = argv[0];
385   else
386     ++exec_name;
387
388 #ifdef WINDOWS
389   windows_main_junk (&argc, (char **) argv, (char **) &exec_name);
390 #endif
391
392   initialize (); /* sets option defaults; reads the system wgetrc and .wgetrc */
393
394   /* [Is the order of the option letters significant?  If not, they should be
395       alphabetized, like the long_options.  The only thing I know for sure is
396       that the options with required arguments must be followed by a ':'.
397       -- Dan Harkless <wget@harkless.org>] */
398   while ((c = getopt_long (argc, argv, "\
399 hpVqvdkKsxmNWrHSLcFbEY:G:g:T:U:O:l:n:i:o:a:t:D:A:R:P:B:e:Q:X:I:w:C:",
400                            long_options, (int *)0)) != EOF)
401     {
402       switch (c)
403         {
404           /* Options without arguments: */
405         case 132:
406           setoptval ("spider", "on");
407           break;
408         case 133:
409           setoptval ("noparent", "on");
410           break;
411         case 136:
412           setoptval ("deleteafter", "on");
413           break;
414         case 137:
415           setoptval ("retrsymlinks", "on");
416           break;
417         case 138:
418           setoptval ("ignorelength", "on");
419           break;
420         case 139:
421           setoptval ("passiveftp", "on");
422           break;
423         case 141:
424           setoptval ("noclobber", "on");
425           break;
426         case 142:
427           setoptval ("followftp", "on");
428           break;
429         case 145:
430           setoptval ("cutdirs", optarg);
431           break;
432         case 146:
433           setoptval ("verbose", "off");
434           break;
435         case 147:
436           setoptval ("dirstruct", "off");
437           break;
438         case 148:
439           setoptval ("addhostdir", "off");
440           break;
441         case 149:
442           setoptval ("removelisting", "off");
443           break;
444         case 155:
445           setoptval ("bindaddress", optarg);
446           break;
447         case 156:
448           setoptval ("httpkeepalive", "off");
449           break;
450         case 165:
451           setoptval ("randomwait", "on");
452           break;
453         case 'b':
454           setoptval ("background", "on");
455           break;
456         case 'c':
457           setoptval ("continue", "on");
458           break;
459         case 'd':
460 #ifdef ENABLE_DEBUG
461           setoptval ("debug", "on");
462 #else
463           fprintf (stderr, _("%s: debug support not compiled in.\n"),
464                    exec_name);
465 #endif
466           break;
467         case 'E':
468           setoptval ("htmlextension", "on");
469           break;
470         case 'F':
471           setoptval ("forcehtml", "on");
472           break;
473         case 'H':
474           setoptval ("spanhosts", "on");
475           break;
476         case 'h':
477           print_help ();
478 #ifdef WINDOWS
479           ws_help (exec_name);
480 #endif
481           exit (0);
482           break;
483         case 'K':
484           setoptval ("backupconverted", "on");
485           break;
486         case 'k':
487           setoptval ("convertlinks", "on");
488           break;
489         case 'L':
490           setoptval ("relativeonly", "on");
491           break;
492         case 'm':
493           setoptval ("mirror", "on");
494           break;
495         case 'N':
496           setoptval ("timestamping", "on");
497           break;
498         case 'p':
499           setoptval ("pagerequisites", "on");
500           break;
501         case 'S':
502           setoptval ("serverresponse", "on");
503           break;
504         case 's':
505           setoptval ("saveheaders", "on");
506           break;
507         case 'q':
508           setoptval ("quiet", "on");
509           break;
510         case 'r':
511           setoptval ("recursive", "on");
512           break;
513         case 'V':
514           printf ("GNU Wget %s\n\n", version_string);
515           printf ("%s", _("\
516 Copyright (C) 2003 Free Software Foundation, Inc.\n"));
517           printf ("%s", _("\
518 This program is distributed in the hope that it will be useful,\n\
519 but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
520 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n\
521 GNU General Public License for more details.\n"));
522           printf (_("\nOriginally written by Hrvoje Niksic <hniksic@xemacs.org>.\n"));
523           exit (0);
524           break;
525         case 'v':
526           setoptval ("verbose", "on");
527           break;
528         case 'x':
529           setoptval ("dirstruct", "on");
530           break;
531         case 174:
532           setoptval ("retryconnrefused", "on");
533           break;
534         case 177:
535           setoptval ("strictcomments", "on");
536           break;
537         case 181:
538           setoptval ("keepsessioncookies", "on");
539           break;
540
541           /* Options accepting an argument: */
542         case 129:
543           setoptval ("httpuser", optarg);
544           break;
545         case 130:
546           setoptval ("httppasswd", optarg);
547           break;
548         case 131:
549           setoptval ("header", optarg);
550           break;
551         case 134:
552           setoptval ("dotstyle", optarg);
553           break;
554         case 135:
555           setoptval ("htmlify", optarg);
556           break;
557         case 140:
558           setoptval ("excludedomains", optarg);
559           break;
560         case 143:
561           setoptval ("proxyuser", optarg);
562           break;
563         case 144:
564           setoptval ("proxypasswd", optarg);
565           break;
566         case 151:
567           setoptval ("backups", optarg);
568           break;
569         case 152:
570           setoptval ("waitretry", optarg);
571           break;
572         case 153:
573           setoptval ("followtags", optarg);
574           break;
575         case 160:
576           setoptval ("cookies", optarg);
577           break;
578         case 161:
579           setoptval ("loadcookies", optarg);
580           break;
581         case 162:
582           setoptval ("savecookies", optarg);
583           break;
584         case 163:
585           setoptval ("progress", optarg);
586           break;
587         case 164:
588           setoptval ("limitrate", optarg);
589           break;
590         case 157:
591           setoptval ("referer", optarg);
592           break;
593 #ifdef HAVE_SSL
594         case 158:
595           setoptval ("sslcertfile", optarg);
596           break;
597         case 159:
598           setoptval ("sslcertkey", optarg);
599           break;
600         case 166:
601           setoptval ("egdfile", optarg);
602           break;
603         case 169:
604           setoptval ("sslcadir", optarg);
605           break;
606         case 170:
607           setoptval ("sslcafile", optarg);
608           break;
609         case 171:
610           setoptval ("sslcerttype", optarg);
611           break;
612         case 172:
613           setoptval ("sslcheckcert", optarg);
614           break;
615         case 173:
616           setoptval ("sslprotocol", optarg);
617           break;
618 #endif /* HAVE_SSL */
619         case 167:
620           setoptval ("postdata", optarg);
621           break;
622         case 168:
623           setoptval ("postfile", optarg);
624           break;
625         case 175:
626           setoptval ("dnscache", optarg);
627           break;
628         case 176:
629           setoptval ("restrictfilenames", optarg);
630           break;
631         case 178:
632           setoptval ("dnstimeout", optarg);
633           break;
634         case 179:
635           setoptval ("readtimeout", optarg);
636           break;
637         case 180:
638           setoptval ("connecttimeout", optarg);
639           break;
640         case 'A':
641           setoptval ("accept", optarg);
642           break;
643         case 'a':
644           setoptval ("logfile", optarg);
645           append_to_log = 1;
646           break;
647         case 'B':
648           setoptval ("base", optarg);
649           break;
650         case 'C':
651           setoptval ("cache", optarg);
652           break;
653         case 'D':
654           setoptval ("domains", optarg);
655           break;
656         case 'e':
657           run_command (optarg);
658           break;
659         case 'G':
660           setoptval ("ignoretags", optarg);
661           break;
662         case 'g':
663           setoptval ("glob", optarg);
664           break;
665         case 'I':
666           setoptval ("includedirectories", optarg);
667           break;
668         case 'i':
669           setoptval ("input", optarg);
670           break;
671         case 'l':
672           setoptval ("reclevel", optarg);
673           break;
674         case 'n':
675           {
676             /* #### What we really want here is --no-foo. */
677             char *p;
678
679             for (p = optarg; *p; p++)
680               switch (*p)
681                 {
682                 case 'v':
683                   setoptval ("verbose", "off");
684                   break;
685                 case 'H':
686                   setoptval ("addhostdir", "off");
687                   break;
688                 case 'd':
689                   setoptval ("dirstruct", "off");
690                   break;
691                 case 'c':
692                   setoptval ("noclobber", "on");
693                   break;
694                 case 'r':
695                   setoptval ("removelisting", "off");
696                   break;
697                 case 'p':
698                   setoptval ("noparent", "on");
699                   break;
700                 case 'k':
701                   setoptval ("httpkeepalive", "off");
702                   break;
703                 default:
704                   printf (_("%s: illegal option -- `-n%c'\n"), exec_name, *p);
705                   print_usage ();
706                   printf ("\n");
707                   printf (_("Try `%s --help\' for more options.\n"), exec_name);
708                   exit (1);
709                 }
710             break;
711           }
712         case 'O':
713           setoptval ("outputdocument", optarg);
714           break;
715         case 'o':
716           setoptval ("logfile", optarg);
717           break;
718         case 'P':
719           setoptval ("dirprefix", optarg);
720           break;
721         case 'Q':
722           setoptval ("quota", optarg);
723           break;
724         case 'R':
725           setoptval ("reject", optarg);
726           break;
727         case 'T':
728           setoptval ("timeout", optarg);
729           break;
730         case 't':
731           setoptval ("tries", optarg);
732           break;
733         case 'U':
734           setoptval ("useragent", optarg);
735           break;
736         case 'w':
737           setoptval ("wait", optarg);
738           break;
739         case 'X':
740           setoptval ("excludedirectories", optarg);
741           break;
742         case 'Y':
743           setoptval ("useproxy", optarg);
744           break;
745
746         case '?':
747           print_usage ();
748           printf ("\n");
749           printf (_("Try `%s --help' for more options.\n"), exec_name);
750           exit (0);
751           break;
752         }
753     }
754
755   /* All user options have now been processed, so it's now safe to do
756      interoption dependency checks. */
757
758   if (opt.reclevel == 0)
759     opt.reclevel = INFINITE_RECURSION;  /* see wget.h for commentary on this */
760
761   if (opt.page_requisites && !opt.recursive)
762     {
763       /* Don't set opt.recursive here because it would confuse the FTP
764          code.  Instead, call retrieve_tree below when either
765          page_requisites or recursive is requested.  */
766       opt.reclevel = 0;
767       if (!opt.no_dirstruct)
768         opt.dirstruct = 1;      /* normally handled by cmd_spec_recursive() */
769     }
770
771   if (opt.verbose == -1)
772     opt.verbose = !opt.quiet;
773
774   /* Sanity checks.  */
775   if (opt.verbose && opt.quiet)
776     {
777       printf (_("Can't be verbose and quiet at the same time.\n"));
778       print_usage ();
779       exit (1);
780     }
781   if (opt.timestamping && opt.noclobber)
782     {
783       printf (_("\
784 Can't timestamp and not clobber old files at the same time.\n"));
785       print_usage ();
786       exit (1);
787     }
788   nurl = argc - optind;
789   if (!nurl && !opt.input_filename)
790     {
791       /* No URL specified.  */
792       printf (_("%s: missing URL\n"), exec_name);
793       print_usage ();
794       printf ("\n");
795       /* #### Something nicer should be printed here -- similar to the
796          pre-1.5 `--help' page.  */
797       printf (_("Try `%s --help' for more options.\n"), exec_name);
798       exit (1);
799     }
800
801   if (opt.background)
802     fork_to_background ();
803
804   /* Initialize progress.  Have to do this after the options are
805      processed so we know where the log file is.  */
806   if (opt.verbose)
807     set_progress_implementation (opt.progress_type);
808
809   /* Fill in the arguments.  */
810   url = alloca_array (char *, nurl + 1);
811   for (i = 0; i < nurl; i++, optind++)
812     {
813       char *rewritten = rewrite_shorthand_url (argv[optind]);
814       if (rewritten)
815         url[i] = rewritten;
816       else
817         url[i] = xstrdup (argv[optind]);
818     }
819   url[i] = NULL;
820
821   /* Change the title of console window on Windows.  #### I think this
822      statement should belong to retrieve_url().  --hniksic.  */
823 #ifdef WINDOWS
824   ws_changetitle (*url, nurl);
825 #endif
826
827   /* Initialize logging.  */
828   log_init (opt.lfilename, append_to_log);
829
830   DEBUGP (("DEBUG output created by Wget %s on %s.\n\n", version_string,
831            OS_TYPE));
832
833   /* Open the output filename if necessary.  */
834   if (opt.output_document)
835     {
836       if (HYPHENP (opt.output_document))
837         opt.dfp = stdout;
838       else
839         {
840           struct stat st;
841           opt.dfp = fopen (opt.output_document, opt.always_rest ? "ab" : "wb");
842           if (opt.dfp == NULL)
843             {
844               perror (opt.output_document);
845               exit (1);
846             }
847           if (fstat (fileno (opt.dfp), &st) == 0 && S_ISREG (st.st_mode))
848             opt.od_known_regular = 1;
849         }
850     }
851
852 #ifdef WINDOWS
853   ws_startup ();
854 #endif
855
856   /* Setup the signal handler to redirect output when hangup is
857      received.  */
858 #ifdef HAVE_SIGNAL
859   if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
860     signal(SIGHUP, redirect_output_signal);
861   /* ...and do the same for SIGUSR1.  */
862   signal (SIGUSR1, redirect_output_signal);
863   /* Writing to a closed socket normally signals SIGPIPE, and the
864      process exits.  What we want is to ignore SIGPIPE and just check
865      for the return value of write().  */
866   signal (SIGPIPE, SIG_IGN);
867 #ifdef SIGWINCH
868   signal (SIGWINCH, progress_handle_sigwinch);
869 #endif
870 #endif /* HAVE_SIGNAL */
871
872   status = RETROK;              /* initialize it, just-in-case */
873   /* Retrieve the URLs from argument list.  */
874   for (t = url; *t; t++)
875     {
876       char *filename = NULL, *redirected_URL = NULL;
877       int dt;
878
879       if ((opt.recursive || opt.page_requisites)
880           && url_scheme (*t) != SCHEME_FTP)
881         status = retrieve_tree (*t);
882       else
883         status = retrieve_url (*t, &filename, &redirected_URL, NULL, &dt);
884
885       if (opt.delete_after && file_exists_p(filename))
886         {
887           DEBUGP (("Removing file due to --delete-after in main():\n"));
888           logprintf (LOG_VERBOSE, _("Removing %s.\n"), filename);
889           if (unlink (filename))
890             logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
891         }
892
893       xfree_null (redirected_URL);
894       xfree_null (filename);
895     }
896
897   /* And then from the input file, if any.  */
898   if (opt.input_filename)
899     {
900       int count;
901       status = retrieve_from_file (opt.input_filename, opt.force_html, &count);
902       if (!count)
903         logprintf (LOG_NOTQUIET, _("No URLs found in %s.\n"),
904                    opt.input_filename);
905     }
906   /* Print the downloaded sum.  */
907   if (opt.recursive || opt.page_requisites
908       || nurl > 1
909       || (opt.input_filename && total_downloaded_bytes != 0))
910     {
911       logprintf (LOG_NOTQUIET,
912                  _("\nFINISHED --%s--\nDownloaded: %s bytes in %d files\n"),
913                  time_str (NULL), legible_large_int (total_downloaded_bytes),
914                  opt.numurls);
915       /* Print quota warning, if exceeded.  */
916       if (opt.quota && total_downloaded_bytes > opt.quota)
917         logprintf (LOG_NOTQUIET,
918                    _("Download quota (%s bytes) EXCEEDED!\n"),
919                    legible (opt.quota));
920     }
921
922   if (opt.cookies_output && wget_cookie_jar)
923     cookie_jar_save (wget_cookie_jar, opt.cookies_output);
924
925   if (opt.convert_links && !opt.delete_after)
926     convert_all_links ();
927
928   log_close ();
929   for (i = 0; i < nurl; i++)
930     xfree (url[i]);
931   cleanup ();
932
933 #ifdef DEBUG_MALLOC
934   print_malloc_debug_stats ();
935 #endif
936   if (status == RETROK)
937     return 0;
938   else
939     return 1;
940 }
941 \f
942 #ifdef HAVE_SIGNAL
943 /* Hangup signal handler.  When wget receives SIGHUP or SIGUSR1, it
944    will proceed operation as usual, trying to write into a log file.
945    If that is impossible, the output will be turned off.
946
947    #### It is unsafe to do call libc functions from a signal handler.
948    What we should do is, set a global variable, and have the code in
949    log.c pick it up.  */
950
951 static RETSIGTYPE
952 redirect_output_signal (int sig)
953 {
954   char *signal_name = (sig == SIGHUP ? "SIGHUP" :
955                        (sig == SIGUSR1 ? "SIGUSR1" :
956                         "WTF?!"));
957   log_request_redirect_output (signal_name);
958   progress_schedule_redirect ();
959   signal (sig, redirect_output_signal);
960 }
961 #endif /* HAVE_SIGNAL */