]> sjero.net Git - wget/blob - src/init.c
[svn] Don't allow opt.ipv4_only and opt.ipv6_only to both be set.
[wget] / src / init.c
1 /* Reading/parsing the initialization file.
2    Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2003
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 <sys/types.h>
35 #include <stdlib.h>
36 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
39 #ifdef HAVE_STRING_H
40 # include <string.h>
41 #else
42 # include <strings.h>
43 #endif
44 #include <errno.h>
45
46 #ifdef WINDOWS
47 # include <winsock.h>
48 #else
49 # include <sys/socket.h>
50 # include <netinet/in.h>
51 #ifndef __BEOS__
52 # include <arpa/inet.h>
53 #endif
54 #endif
55
56 #ifdef HAVE_PWD_H
57 # include <pwd.h>
58 #endif
59 #include <assert.h>
60
61 #include "wget.h"
62 #include "utils.h"
63 #include "init.h"
64 #include "host.h"
65 #include "netrc.h"
66 #include "cookies.h"            /* for cookie_jar_delete */
67 #include "progress.h"
68 #include "recur.h"              /* for INFINITE_RECURSION */
69
70 #ifndef errno
71 extern int errno;
72 #endif
73
74 extern struct cookie_jar *wget_cookie_jar;
75
76 /* We want tilde expansion enabled only when reading `.wgetrc' lines;
77    otherwise, it will be performed by the shell.  This variable will
78    be set by the wgetrc-reading function.  */
79
80 static int enable_tilde_expansion;
81
82
83 #define CMD_DECLARE(func) static int func \
84   PARAMS ((const char *, const char *, void *))
85
86 CMD_DECLARE (cmd_boolean);
87 CMD_DECLARE (cmd_bytes);
88 CMD_DECLARE (cmd_bytes_large);
89 CMD_DECLARE (cmd_directory_vector);
90 CMD_DECLARE (cmd_lockable_boolean);
91 CMD_DECLARE (cmd_number);
92 CMD_DECLARE (cmd_number_inf);
93 CMD_DECLARE (cmd_string);
94 CMD_DECLARE (cmd_file);
95 CMD_DECLARE (cmd_directory);
96 CMD_DECLARE (cmd_time);
97 CMD_DECLARE (cmd_vector);
98
99 CMD_DECLARE (cmd_spec_dirstruct);
100 CMD_DECLARE (cmd_spec_header);
101 CMD_DECLARE (cmd_spec_htmlify);
102 CMD_DECLARE (cmd_spec_mirror);
103 CMD_DECLARE (cmd_spec_progress);
104 CMD_DECLARE (cmd_spec_recursive);
105 CMD_DECLARE (cmd_spec_restrict_file_names);
106 CMD_DECLARE (cmd_spec_timeout);
107 CMD_DECLARE (cmd_spec_useragent);
108
109 /* List of recognized commands, each consisting of name, closure and
110    function.  When adding a new command, simply add it to the list,
111    but be sure to keep the list sorted alphabetically, as
112    command_by_name depends on it.  Also, be sure to add any entries
113    that allocate memory (e.g. cmd_string and cmd_vector guys) to the
114    cleanup() function below. */
115
116 static struct {
117   char *name;
118   void *closure;
119   int (*action) PARAMS ((const char *, const char *, void *));
120 } commands[] = {
121   { "accept",           &opt.accepts,           cmd_vector },
122   { "addhostdir",       &opt.add_hostdir,       cmd_boolean },
123   { "alwaysrest",       &opt.always_rest,       cmd_boolean }, /* deprecated */
124   { "background",       &opt.background,        cmd_boolean },
125   { "backupconverted",  &opt.backup_converted,  cmd_boolean },
126   { "backups",          &opt.backups,           cmd_number },
127   { "base",             &opt.base_href,         cmd_string },
128   { "bindaddress",      &opt.bind_address,      cmd_string },
129   { "cache",            &opt.allow_cache,       cmd_boolean },
130   { "connecttimeout",   &opt.connect_timeout,   cmd_time },
131   { "continue",         &opt.always_rest,       cmd_boolean },
132   { "convertlinks",     &opt.convert_links,     cmd_boolean },
133   { "cookies",          &opt.cookies,           cmd_boolean },
134   { "cutdirs",          &opt.cut_dirs,          cmd_number },
135 #ifdef ENABLE_DEBUG
136   { "debug",            &opt.debug,             cmd_boolean },
137 #endif
138   { "deleteafter",      &opt.delete_after,      cmd_boolean },
139   { "dirprefix",        &opt.dir_prefix,        cmd_directory },
140   { "dirstruct",        NULL,                   cmd_spec_dirstruct },
141   { "dnscache",         &opt.dns_cache,         cmd_boolean },
142   { "dnstimeout",       &opt.dns_timeout,       cmd_time },
143   { "domains",          &opt.domains,           cmd_vector },
144   { "dotbytes",         &opt.dot_bytes,         cmd_bytes },
145   { "dotsinline",       &opt.dots_in_line,      cmd_number },
146   { "dotspacing",       &opt.dot_spacing,       cmd_number },
147   { "dotstyle",         &opt.dot_style,         cmd_string },
148 #ifdef HAVE_SSL
149   { "egdfile",          &opt.sslegdsock,        cmd_file },
150 #endif
151   { "excludedirectories", &opt.excludes,        cmd_directory_vector },
152   { "excludedomains",   &opt.exclude_domains,   cmd_vector },
153   { "followftp",        &opt.follow_ftp,        cmd_boolean },
154   { "followtags",       &opt.follow_tags,       cmd_vector },
155   { "forcehtml",        &opt.force_html,        cmd_boolean },
156   { "ftpproxy",         &opt.ftp_proxy,         cmd_string },
157   { "glob",             &opt.ftp_glob,          cmd_boolean },
158   { "header",           NULL,                   cmd_spec_header },
159   { "htmlextension",    &opt.html_extension,    cmd_boolean },
160   { "htmlify",          NULL,                   cmd_spec_htmlify },
161   { "httpkeepalive",    &opt.http_keep_alive,   cmd_boolean },
162   { "httppasswd",       &opt.http_passwd,       cmd_string },
163   { "httpproxy",        &opt.http_proxy,        cmd_string },
164   { "httpsproxy",       &opt.https_proxy,       cmd_string },
165   { "httpuser",         &opt.http_user,         cmd_string },
166   { "ignorelength",     &opt.ignore_length,     cmd_boolean },
167   { "ignoretags",       &opt.ignore_tags,       cmd_vector },
168   { "includedirectories", &opt.includes,        cmd_directory_vector },
169 #ifdef ENABLE_IPV6
170   { "inet4only",        &opt.ipv4_only,         cmd_boolean },
171   { "inet6only",        &opt.ipv6_only,         cmd_boolean },
172 #endif
173   { "input",            &opt.input_filename,    cmd_file },
174   { "keepsessioncookies", &opt.keep_session_cookies, cmd_boolean },
175   { "killlonger",       &opt.kill_longer,       cmd_boolean },
176   { "limitrate",        &opt.limit_rate,        cmd_bytes },
177   { "loadcookies",      &opt.cookies_input,     cmd_file },
178   { "logfile",          &opt.lfilename,         cmd_file },
179   { "login",            &opt.ftp_acc,           cmd_string },
180   { "mirror",           NULL,                   cmd_spec_mirror },
181   { "netrc",            &opt.netrc,             cmd_boolean },
182   { "noclobber",        &opt.noclobber,         cmd_boolean },
183   { "noparent",         &opt.no_parent,         cmd_boolean },
184   { "noproxy",          &opt.no_proxy,          cmd_vector },
185   { "numtries",         &opt.ntry,              cmd_number_inf },/* deprecated*/
186   { "outputdocument",   &opt.output_document,   cmd_file },
187   { "pagerequisites",   &opt.page_requisites,   cmd_boolean },
188   { "passiveftp",       &opt.ftp_pasv,          cmd_lockable_boolean },
189   { "passwd",           &opt.ftp_pass,          cmd_string },
190   { "postdata",         &opt.post_data,         cmd_string },
191   { "postfile",         &opt.post_file_name,    cmd_file },
192   { "preservepermissions", &opt.preserve_perm,     cmd_boolean },
193   { "progress",         &opt.progress_type,     cmd_spec_progress },
194   { "proxypasswd",      &opt.proxy_passwd,      cmd_string },
195   { "proxyuser",        &opt.proxy_user,        cmd_string },
196   { "quiet",            &opt.quiet,             cmd_boolean },
197   { "quota",            &opt.quota,             cmd_bytes_large },
198   { "randomwait",       &opt.random_wait,       cmd_boolean },
199   { "readtimeout",      &opt.read_timeout,      cmd_time },
200   { "reclevel",         &opt.reclevel,          cmd_number_inf },
201   { "recursive",        NULL,                   cmd_spec_recursive },
202   { "referer",          &opt.referer,           cmd_string },
203   { "reject",           &opt.rejects,           cmd_vector },
204   { "relativeonly",     &opt.relative_only,     cmd_boolean },
205   { "removelisting",    &opt.remove_listing,    cmd_boolean },
206   { "restrictfilenames", NULL,                  cmd_spec_restrict_file_names },
207   { "retrsymlinks",     &opt.retr_symlinks,     cmd_boolean },
208   { "retryconnrefused", &opt.retry_connrefused, cmd_boolean },
209   { "robots",           &opt.use_robots,        cmd_boolean },
210   { "savecookies",      &opt.cookies_output,    cmd_file },
211   { "saveheaders",      &opt.save_headers,      cmd_boolean },
212   { "serverresponse",   &opt.server_response,   cmd_boolean },
213   { "spanhosts",        &opt.spanhost,          cmd_boolean },
214   { "spider",           &opt.spider,            cmd_boolean },
215 #ifdef HAVE_SSL
216   { "sslcadir",         &opt.sslcadir,          cmd_directory },
217   { "sslcafile",        &opt.sslcafile,         cmd_file },
218   { "sslcertfile",      &opt.sslcertfile,       cmd_file },
219   { "sslcertkey",       &opt.sslcertkey,        cmd_file },
220   { "sslcerttype",      &opt.sslcerttype,       cmd_number },
221   { "sslcheckcert",     &opt.sslcheckcert,      cmd_number },
222   { "sslprotocol",      &opt.sslprotocol,       cmd_number },
223 #endif /* HAVE_SSL */
224   { "strictcomments",   &opt.strict_comments,   cmd_boolean },
225   { "timeout",          NULL,                   cmd_spec_timeout },
226   { "timestamping",     &opt.timestamping,      cmd_boolean },
227   { "tries",            &opt.ntry,              cmd_number_inf },
228   { "useproxy",         &opt.use_proxy,         cmd_boolean },
229   { "useragent",        NULL,                   cmd_spec_useragent },
230   { "verbose",          &opt.verbose,           cmd_boolean },
231   { "wait",             &opt.wait,              cmd_time },
232   { "waitretry",        &opt.waitretry,         cmd_time }
233 };
234
235 /* Look up CMDNAME in the commands[] and return its position in the
236    array.  If CMDNAME is not found, return -1.  */
237
238 static int
239 command_by_name (const char *cmdname)
240 {
241   /* Use binary search for speed.  Wget has ~100 commands, which
242      guarantees a worst case performance of 7 string comparisons.  */
243   int lo = 0, hi = countof (commands) - 1;
244
245   while (lo <= hi)
246     {
247       int mid = (lo + hi) >> 1;
248       int cmp = strcasecmp (cmdname, commands[mid].name);
249       if (cmp < 0)
250         hi = mid - 1;
251       else if (cmp > 0)
252         lo = mid + 1;
253       else
254         return mid;
255     }
256   return -1;
257 }
258 \f
259 /* Reset the variables to default values.  */
260 static void
261 defaults (void)
262 {
263   char *tmp;
264
265   /* Most of the default values are 0.  Just reset everything, and
266      fill in the non-zero values.  Note that initializing pointers to
267      NULL this way is technically illegal, but porting Wget to a
268      machine where NULL is not all-zero bit pattern will be the least
269      of the implementors' worries.  */
270   xzero (opt);
271
272   opt.cookies = 1;
273   opt.verbose = -1;
274   opt.ntry = 20;
275   opt.reclevel = 5;
276   opt.add_hostdir = 1;
277   opt.ftp_acc  = xstrdup ("anonymous");
278   opt.ftp_pass = xstrdup ("-wget@");
279   opt.netrc = 1;
280   opt.ftp_glob = 1;
281   opt.htmlify = 1;
282   opt.http_keep_alive = 1;
283   opt.use_proxy = 1;
284   tmp = getenv ("no_proxy");
285   if (tmp)
286     opt.no_proxy = sepstring (tmp);
287   opt.allow_cache = 1;
288
289   opt.read_timeout = 900;
290   opt.use_robots = 1;
291
292   opt.remove_listing = 1;
293
294   opt.dot_bytes = 1024;
295   opt.dot_spacing = 10;
296   opt.dots_in_line = 50;
297
298   opt.dns_cache = 1;
299
300   /* The default for file name restriction defaults to the OS type. */
301 #if !defined(WINDOWS) && !defined(__CYGWIN__)
302   opt.restrict_files_os = restrict_unix;
303 #else
304   opt.restrict_files_os = restrict_windows;
305 #endif
306   opt.restrict_files_ctrl = 1;
307
308 #ifdef ENABLE_IPV6
309 # ifndef HAVE_GETADDRINFO_AI_ADDRCONFIG
310   /* If IPv6 is enabled, but AI_ADDRCONFIG is missing, check whether
311      we can create AF_INET6 sockets.  If we can't, turn on the
312      --inet4-only setting.  This is necessary because on some systems
313      (e.g. RHL 9) getaddrinfo resolves AAAA records, but socket()
314      can't even create an AF_INET6 socket, let alone connect to IPv6
315      hosts.  To avoid "address family not supported" error messages,
316      we set ipv4_only.
317
318      We do it as early as here, so that the user can revert the
319      settingn using --no-inet4-only, in case he wants to see the error
320      messages, for whatever reason.  */
321   {
322     int sock = socket (AF_INET6, SOCK_STREAM, 0);
323     if (sock < 0)
324       opt.ipv4_only = -1;       /* special value -1 because the option
325                                    was not specified by the user.  */
326     else
327       close (sock);
328   }
329 # endif /* not HAVE_GETADDRINFO_AI_ADDRCONFIG */
330 #endif /* ENABLE_IPV6 */
331 }
332 \f
333 /* Return the user's home directory (strdup-ed), or NULL if none is
334    found.  */
335 char *
336 home_dir (void)
337 {
338   char *home = getenv ("HOME");
339
340   if (!home)
341     {
342 #ifndef WINDOWS
343       /* If HOME is not defined, try getting it from the password
344          file.  */
345       struct passwd *pwd = getpwuid (getuid ());
346       if (!pwd || !pwd->pw_dir)
347         return NULL;
348       home = pwd->pw_dir;
349 #else  /* WINDOWS */
350       home = "C:\\";
351       /* #### Maybe I should grab home_dir from registry, but the best
352          that I could get from there is user's Start menu.  It sucks!  */
353 #endif /* WINDOWS */
354     }
355
356   return home ? xstrdup (home) : NULL;
357 }
358
359 /* Return the path to the user's .wgetrc.  This is either the value of
360    `WGETRC' environment variable, or `$HOME/.wgetrc'.
361
362    If the `WGETRC' variable exists but the file does not exist, the
363    function will exit().  */
364 static char *
365 wgetrc_file_name (void)
366 {
367   char *env, *home;
368   char *file = NULL;
369
370   /* Try the environment.  */
371   env = getenv ("WGETRC");
372   if (env && *env)
373     {
374       if (!file_exists_p (env))
375         {
376           fprintf (stderr, _("%s: WGETRC points to %s, which doesn't exist.\n"),
377                    exec_name, env);
378           exit (1);
379         }
380       return xstrdup (env);
381     }
382
383 #ifndef WINDOWS
384   /* If that failed, try $HOME/.wgetrc.  */
385   home = home_dir ();
386   if (home)
387     {
388       file = (char *)xmalloc (strlen (home) + 1 + strlen (".wgetrc") + 1);
389       sprintf (file, "%s/.wgetrc", home);
390     }
391   xfree_null (home);
392 #else  /* WINDOWS */
393   /* Under Windows, "home" is (for the purposes of this function) the
394      directory where `wget.exe' resides, and `wget.ini' will be used
395      as file name.  SYSTEM_WGETRC should not be defined under WINDOWS.
396
397      It is not as trivial as I assumed, because on 95 argv[0] is full
398      path, but on NT you get what you typed in command line.  --dbudor */
399   home = ws_mypath ();
400   if (home)
401     {
402       file = (char *)xmalloc (strlen (home) + strlen ("wget.ini") + 1);
403       sprintf (file, "%swget.ini", home);
404     }
405 #endif /* WINDOWS */
406
407   if (!file)
408     return NULL;
409   if (!file_exists_p (file))
410     {
411       xfree (file);
412       return NULL;
413     }
414   return file;
415 }
416
417 static int parse_line PARAMS ((const char *, char **, char **, int *));
418 static int setval_internal PARAMS ((int, const char *, const char *));
419
420 /* Initialize variables from a wgetrc file.  */
421
422 static void
423 run_wgetrc (const char *file)
424 {
425   FILE *fp;
426   char *line;
427   int ln;
428
429   fp = fopen (file, "rb");
430   if (!fp)
431     {
432       fprintf (stderr, _("%s: Cannot read %s (%s).\n"), exec_name,
433                file, strerror (errno));
434       return;
435     }
436   enable_tilde_expansion = 1;
437   ln = 1;
438   while ((line = read_whole_line (fp)))
439     {
440       char *com, *val;
441       int comind, status;
442
443       /* Parse the line.  */
444       status = parse_line (line, &com, &val, &comind);
445       xfree (line);
446       /* If everything is OK, set the value.  */
447       if (status == 1)
448         {
449           if (!setval_internal (comind, com, val))
450             fprintf (stderr, _("%s: Error in %s at line %d.\n"), exec_name,
451                      file, ln);
452           xfree (com);
453           xfree (val);
454         }
455       else if (status == 0)
456         fprintf (stderr, _("%s: Error in %s at line %d.\n"), exec_name,
457                  file, ln);
458       ++ln;
459     }
460   enable_tilde_expansion = 0;
461   fclose (fp);
462 }
463
464 /* Initialize the defaults and run the system wgetrc and user's own
465    wgetrc.  */
466 void
467 initialize (void)
468 {
469   char *file;
470
471   /* Load the hard-coded defaults.  */
472   defaults ();
473
474   /* If SYSTEM_WGETRC is defined, use it.  */
475 #ifdef SYSTEM_WGETRC
476   if (file_exists_p (SYSTEM_WGETRC))
477     run_wgetrc (SYSTEM_WGETRC);
478 #endif
479   /* Override it with your own, if one exists.  */
480   file = wgetrc_file_name ();
481   if (!file)
482     return;
483   /* #### We should canonicalize `file' and SYSTEM_WGETRC with
484      something like realpath() before comparing them with `strcmp'  */
485 #ifdef SYSTEM_WGETRC
486   if (!strcmp (file, SYSTEM_WGETRC))
487     {
488       fprintf (stderr, _("\
489 %s: Warning: Both system and user wgetrc point to `%s'.\n"),
490                exec_name, file);
491     }
492   else
493 #endif
494     run_wgetrc (file);
495   xfree (file);
496   return;
497 }
498 \f
499 /* Remove dashes and underscores from S, modifying S in the
500    process. */
501
502 static void
503 dehyphen (char *s)
504 {
505   char *t = s;                  /* t - tortoise */
506   char *h = s;                  /* h - hare     */
507   while (*h)
508     if (*h == '_' || *h == '-')
509       ++h;
510     else
511       *t++ = *h++;
512   *t = '\0';
513 }
514
515 /* Parse the line pointed by line, with the syntax:
516    <sp>* command <sp>* = <sp>* value <sp>*
517    Uses malloc to allocate space for command and value.
518    If the line is invalid, data is freed and 0 is returned.
519
520    Return values:
521     1 - success
522     0 - error
523    -1 - empty
524
525    In case of success, *COM and *VAL point to freshly allocated
526    strings, and *COMIND points to com's index.  In case of error or
527    empty line, those values are unaffected.  */
528
529 static int
530 parse_line (const char *line, char **com, char **val, int *comind)
531 {
532   const char *p;
533   const char *end = line + strlen (line);
534   const char *cmdstart, *cmdend;
535   const char *valstart, *valend;
536
537   char *cmdcopy;
538   int ind;
539
540   /* Skip leading and trailing whitespace.  */
541   while (*line && ISSPACE (*line))
542     ++line;
543   while (end > line && ISSPACE (end[-1]))
544     --end;
545
546   /* Skip empty lines and comments.  */
547   if (!*line || *line == '#')
548     return -1;
549
550   p = line;
551
552   cmdstart = p;
553   while (p < end && (ISALPHA (*p) || *p == '_' || *p == '-'))
554     ++p;
555   cmdend = p;
556
557   /* Skip '=', as well as any space before or after it. */
558   while (p < end && ISSPACE (*p))
559     ++p;
560   if (p == end || *p != '=')
561     return 0;
562   ++p;
563   while (p < end && ISSPACE (*p))
564     ++p;
565
566   valstart = p;
567   valend   = end;
568
569   /* The line now known to be syntactically correct.  Check whether
570      the command is valid.  */
571   BOUNDED_TO_ALLOCA (cmdstart, cmdend, cmdcopy);
572   dehyphen (cmdcopy);
573   ind = command_by_name (cmdcopy);
574   if (ind == -1)
575     return 0;
576
577   /* The command is valid.  Now fill in the values and report success
578      to the caller.  */
579   *comind = ind;
580   *com = strdupdelim (cmdstart, cmdend);
581   *val = strdupdelim (valstart, valend);
582   return 1;
583 }
584
585 /* Run commands[comind].action. */
586
587 static int
588 setval_internal (int comind, const char *com, const char *val)
589 {
590   assert (0 <= comind && comind < countof (commands));
591   DEBUGP (("Setting %s (%d) to %s\n", com, comind, val));
592   return ((*commands[comind].action) (com, val, commands[comind].closure));
593 }
594
595 /* Run command COM with value VAL.  If running the command produces an
596    error, report the error and exit.
597
598    This is intended to be called from main() to modify Wget's behavior
599    through command-line switches.  Since COM is hard-coded in main(),
600    it is not canonicalized, and this aborts when COM is not found.
601
602    If COMIND's are exported to init.h, this function will be changed
603    to accept COMIND directly.  */
604
605 void
606 setoptval (const char *com, const char *val)
607 {
608   assert (val != NULL);
609   if (!setval_internal (command_by_name (com), com, val))
610     exit (2);
611 }
612
613 /* Parse OPT into command and value and run it.  For example,
614    run_command("foo=bar") is equivalent to setoptval("foo", "bar").
615    This is used by the `--execute' flag in main.c.  */
616
617 void
618 run_command (const char *opt)
619 {
620   char *com, *val;
621   int comind;
622   int status = parse_line (opt, &com, &val, &comind);
623   if (status == 1)
624     {
625       if (!setval_internal (comind, com, val))
626         exit (2);
627       xfree (com);
628       xfree (val);
629     }
630   else if (status == 0)
631     {
632       fprintf (stderr, _("%s: Invalid --execute command `%s'\n"),
633                exec_name, opt);
634       exit (2);
635     }
636 }
637 \f
638 /* Generic helper functions, for use with `commands'. */
639
640 #define CMP1(p, c0) (TOLOWER((p)[0]) == (c0) && (p)[1] == '\0')
641
642 #define CMP2(p, c0, c1) (TOLOWER((p)[0]) == (c0)        \
643                          && TOLOWER((p)[1]) == (c1)     \
644                          && (p)[2] == '\0')
645
646 #define CMP3(p, c0, c1, c2) (TOLOWER((p)[0]) == (c0)    \
647                      && TOLOWER((p)[1]) == (c1)         \
648                      && TOLOWER((p)[2]) == (c2)         \
649                      && (p)[3] == '\0')
650
651
652 /* Store the boolean value from VAL to CLOSURE.  COM is ignored,
653    except for error messages.  */
654 static int
655 cmd_boolean (const char *com, const char *val, void *closure)
656 {
657   int bool_value;
658
659   if (CMP2 (val, 'o', 'n') || CMP3 (val, 'y', 'e', 's') || CMP1 (val, '1'))
660     /* "on", "yes" and "1" mean true. */
661     bool_value = 1;
662   else if (CMP3 (val, 'o', 'f', 'f') || CMP2 (val, 'n', 'o') || CMP1 (val, '0'))
663     /* "off", "no" and "0" mean false. */
664     bool_value = 0;
665   else
666     {
667       fprintf (stderr,
668                _("%s: %s: Invalid boolean `%s', use `on' or `off'.\n"),
669                exec_name, com, val);
670       return 0;
671     }
672
673   *(int *)closure = bool_value;
674   return 1;
675 }
676
677 /* Store the lockable_boolean {2, 1, 0, -1} value from VAL to CLOSURE.
678    COM is ignored, except for error messages.  Values 2 and -1
679    indicate that once defined, the value may not be changed by
680    successive wgetrc files or command-line arguments.
681
682    Values: 2 - Enable a particular option for good ("always")
683            1 - Enable an option ("on")
684            0 - Disable an option ("off")
685           -1 - Disable an option for good ("never") */
686 static int
687 cmd_lockable_boolean (const char *com, const char *val, void *closure)
688 {
689   int lockable_boolean_value;
690
691   int oldval = *(int *)closure;
692
693   /*
694    * If a config file said "always" or "never", don't allow command line
695    * arguments to override the config file.
696    */
697   if (oldval == -1 || oldval == 2)
698     return 1;
699
700   if (0 == strcasecmp (val, "always") || CMP1 (val, '2'))
701     lockable_boolean_value = 2;
702   else if (CMP2 (val, 'o', 'n') || CMP3 (val, 'y', 'e', 's') || CMP1 (val, '1'))
703     lockable_boolean_value = 1;
704   else if (CMP3 (val, 'o', 'f', 'f') || CMP2 (val, 'n', 'o') || CMP1 (val, '0'))
705     lockable_boolean_value = 0;
706   else if (0 == strcasecmp (val, "never") || CMP2 (val, '-', '1'))
707     lockable_boolean_value = -1;
708   else
709     {
710       fprintf (stderr,
711                _("%s: %s: Invalid boolean `%s', use always, on, off, or never.\n"),
712                exec_name, com, val);
713       return 0;
714     }
715
716   *(int *)closure = lockable_boolean_value;
717   return 1;
718 }
719
720 static int simple_atoi PARAMS ((const char *, const char *, int *));
721
722 /* Set the non-negative integer value from VAL to CLOSURE.  With
723    incorrect specification, the number remains unchanged.  */
724 static int
725 cmd_number (const char *com, const char *val, void *closure)
726 {
727   if (!simple_atoi (val, val + strlen (val), closure))
728     {
729       fprintf (stderr, _("%s: %s: Invalid number `%s'.\n"),
730                exec_name, com, val);
731       return 0;
732     }
733   return 1;
734 }
735
736 /* Similar to cmd_number(), only accepts `inf' as a synonym for 0.  */
737 static int
738 cmd_number_inf (const char *com, const char *val, void *closure)
739 {
740   if (!strcasecmp (val, "inf"))
741     {
742       *(int *)closure = 0;
743       return 1;
744     }
745   return cmd_number (com, val, closure);
746 }
747
748 /* Copy (strdup) the string at COM to a new location and place a
749    pointer to *CLOSURE.  */
750 static int
751 cmd_string (const char *com, const char *val, void *closure)
752 {
753   char **pstring = (char **)closure;
754
755   xfree_null (*pstring);
756   *pstring = xstrdup (val);
757   return 1;
758 }
759
760 #ifndef WINDOWS
761 # define ISSEP(c) ((c) == '/')
762 #else
763 # define ISSEP(c) ((c) == '/' || (c) == '\\')
764 #endif
765
766 /* Like the above, but handles tilde-expansion when reading a user's
767    `.wgetrc'.  In that case, and if VAL begins with `~', the tilde
768    gets expanded to the user's home directory.  */
769 static int
770 cmd_file (const char *com, const char *val, void *closure)
771 {
772   char **pstring = (char **)closure;
773
774   xfree_null (*pstring);
775
776   /* #### If VAL is empty, perhaps should set *CLOSURE to NULL.  */
777
778   if (!enable_tilde_expansion || !(*val == '~' && ISSEP (val[1])))
779     {
780     noexpand:
781       *pstring = xstrdup (val);
782     }
783   else
784     {
785       char *result;
786       int homelen;
787       char *home = home_dir ();
788       if (!home)
789         goto noexpand;
790
791       homelen = strlen (home);
792       while (homelen && ISSEP (home[homelen - 1]))
793         home[--homelen] = '\0';
794
795       /* Skip the leading "~/". */
796       for (++val; ISSEP (*val); val++)
797         ;
798
799       result = xmalloc (homelen + 1 + strlen (val) + 1);
800       memcpy (result, home, homelen);
801       result[homelen] = '/';
802       strcpy (result + homelen + 1, val);
803
804       *pstring = result;
805     }
806
807 #ifdef WINDOWS
808   /* Convert "\" to "/". */
809   {
810     char *s;
811     for (s = *pstring; *s; s++)
812       if (*s == '\\')
813         *s = '/';
814   }
815 #endif
816   return 1;
817 }
818
819 /* Like cmd_file, but strips trailing '/' characters.  */
820 static int
821 cmd_directory (const char *com, const char *val, void *closure)
822 {
823   char *s, *t;
824
825   /* Call cmd_file() for tilde expansion and separator
826      canonicalization (backslash -> slash under Windows).  These
827      things should perhaps be in a separate function.  */
828   if (!cmd_file (com, val, closure))
829     return 0;
830
831   s = *(char **)closure;
832   t = s + strlen (s);
833   while (t > s && *--t == '/')
834     *t = '\0';
835
836   return 1;
837 }
838
839 /* Split VAL by space to a vector of values, and append those values
840    to vector pointed to by the CLOSURE argument.  If VAL is empty, the
841    CLOSURE vector is cleared instead.  */
842
843 static int
844 cmd_vector (const char *com, const char *val, void *closure)
845 {
846   char ***pvec = (char ***)closure;
847
848   if (*val)
849     *pvec = merge_vecs (*pvec, sepstring (val));
850   else
851     {
852       free_vec (*pvec);
853       *pvec = NULL;
854     }
855   return 1;
856 }
857
858 static int
859 cmd_directory_vector (const char *com, const char *val, void *closure)
860 {
861   char ***pvec = (char ***)closure;
862
863   if (*val)
864     {
865       /* Strip the trailing slashes from directories.  */
866       char **t, **seps;
867
868       seps = sepstring (val);
869       for (t = seps; t && *t; t++)
870         {
871           int len = strlen (*t);
872           /* Skip degenerate case of root directory.  */
873           if (len > 1)
874             {
875               if ((*t)[len - 1] == '/')
876                 (*t)[len - 1] = '\0';
877             }
878         }
879       *pvec = merge_vecs (*pvec, seps);
880     }
881   else
882     {
883       free_vec (*pvec);
884       *pvec = NULL;
885     }
886   return 1;
887 }
888
889 static int simple_atof PARAMS ((const char *, const char *, double *));
890
891 /* Enginge for cmd_bytes and cmd_bytes_large: converts a string such
892    as "100k" or "2.5G" to a floating point number.  */
893
894 static int
895 parse_bytes_helper (const char *val, double *result)
896 {
897   double number, mult;
898   const char *end = val + strlen (val);
899
900   /* Check for "inf".  */
901   if (0 == strcmp (val, "inf"))
902     {
903       *result = 0;
904       return 1;
905     }
906
907   /* Strip trailing whitespace.  */
908   while (val < end && ISSPACE (end[-1]))
909     --end;
910   if (val == end)
911     return 0;
912
913   switch (TOLOWER (end[-1]))
914     {
915     case 'k':
916       --end, mult = 1024.0;
917       break;
918     case 'm':
919       --end, mult = 1048576.0;
920       break;
921     case 'g':
922       --end, mult = 1073741824.0;
923       break;
924     case 't':
925       --end, mult = 1099511627776.0;
926       break;
927     default:
928       /* Not a recognized suffix: assume it's a digit.  (If not,
929          simple_atof will raise an error.)  */
930       mult = 1;
931     }
932
933   /* Skip leading and trailing whitespace. */
934   while (val < end && ISSPACE (*val))
935     ++val;
936   while (val < end && ISSPACE (end[-1]))
937     --end;
938   if (val == end)
939     return 0;
940
941   if (!simple_atof (val, end, &number))
942     return 0;
943
944   *result = number * mult;
945   return 1;
946 }
947
948 /* Parse VAL as a number and set its value to CLOSURE (which should
949    point to a long int).
950
951    By default, the value is assumed to be in bytes.  If "K", "M", or
952    "G" are appended, the value is multiplied with 1<<10, 1<<20, or
953    1<<30, respectively.  Floating point values are allowed and are
954    cast to integer before use.  The idea is to be able to use things
955    like 1.5k instead of "1536".
956
957    The string "inf" is returned as 0.
958
959    In case of error, 0 is returned and memory pointed to by CLOSURE
960    remains unmodified.  */
961
962 static int
963 cmd_bytes (const char *com, const char *val, void *closure)
964 {
965   double byte_value;
966   if (!parse_bytes_helper (val, &byte_value))
967     {
968       fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"),
969                exec_name, com, val);
970       return 0;
971     }
972   *(long *)closure = (long)byte_value;
973   return 1;
974 }
975
976 /* Like cmd_bytes, but CLOSURE is interpreted as a pointer to
977    LARGE_INT.  It works by converting the string to double, therefore
978    working with values up to 2^53-1 without loss of precision.  This
979    value (8192 TB) is large enough to serve for a while.  */
980
981 static int
982 cmd_bytes_large (const char *com, const char *val, void *closure)
983 {
984   double byte_value;
985   if (!parse_bytes_helper (val, &byte_value))
986     {
987       fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"),
988                exec_name, com, val);
989       return 0;
990     }
991   *(LARGE_INT *)closure = (LARGE_INT)byte_value;
992   return 1;
993 }
994
995 /* Store the value of VAL to *OUT.  The value is a time period, by
996    default expressed in seconds, but also accepting suffixes "m", "h",
997    "d", and "w" for minutes, hours, days, and weeks respectively.  */
998
999 static int
1000 cmd_time (const char *com, const char *val, void *closure)
1001 {
1002   double number, mult;
1003   const char *end = val + strlen (val);
1004
1005   /* Strip trailing whitespace.  */
1006   while (val < end && ISSPACE (end[-1]))
1007     --end;
1008
1009   if (val == end)
1010     {
1011     err:
1012       fprintf (stderr, _("%s: %s: Invalid time period `%s'\n"),
1013                exec_name, com, val);
1014       return 0;
1015     }
1016
1017   switch (TOLOWER (end[-1]))
1018     {
1019     case 's':
1020       --end, mult = 1;          /* seconds */
1021       break;
1022     case 'm':
1023       --end, mult = 60;         /* minutes */
1024       break;
1025     case 'h':
1026       --end, mult = 3600;       /* hours */
1027       break;
1028     case 'd':
1029       --end, mult = 86400.0;    /* days */
1030       break;
1031     case 'w':
1032       --end, mult = 604800.0;   /* weeks */
1033       break;
1034     default:
1035       /* Not a recognized suffix: assume it belongs to the number.
1036          (If not, atof simple_atof will raise an error.)  */
1037       mult = 1;
1038     }
1039
1040   /* Skip leading and trailing whitespace. */
1041   while (val < end && ISSPACE (*val))
1042     ++val;
1043   while (val < end && ISSPACE (end[-1]))
1044     --end;
1045   if (val == end)
1046     goto err;
1047
1048   if (!simple_atof (val, end, &number))
1049     goto err;
1050
1051   *(double *)closure = number * mult;
1052   return 1;
1053 }
1054 \f
1055 /* Specialized helper functions, used by `commands' to handle some
1056    options specially.  */
1057
1058 static int check_user_specified_header PARAMS ((const char *));
1059
1060 static int
1061 cmd_spec_dirstruct (const char *com, const char *val, void *closure)
1062 {
1063   if (!cmd_boolean (com, val, &opt.dirstruct))
1064     return 0;
1065   /* Since dirstruct behaviour is explicitly changed, no_dirstruct
1066      must be affected inversely.  */
1067   if (opt.dirstruct)
1068     opt.no_dirstruct = 0;
1069   else
1070     opt.no_dirstruct = 1;
1071   return 1;
1072 }
1073
1074 static int
1075 cmd_spec_header (const char *com, const char *val, void *closure)
1076 {
1077   if (!*val)
1078     {
1079       /* Empty header means reset headers.  */
1080       xfree_null (opt.user_header);
1081       opt.user_header = NULL;
1082     }
1083   else
1084     {
1085       int i;
1086
1087       if (!check_user_specified_header (val))
1088         {
1089           fprintf (stderr, _("%s: %s: Invalid header `%s'.\n"),
1090                    exec_name, com, val);
1091           return 0;
1092         }
1093       i = opt.user_header ? strlen (opt.user_header) : 0;
1094       opt.user_header = (char *)xrealloc (opt.user_header, i + strlen (val)
1095                                           + 2 + 1);
1096       strcpy (opt.user_header + i, val);
1097       i += strlen (val);
1098       opt.user_header[i++] = '\r';
1099       opt.user_header[i++] = '\n';
1100       opt.user_header[i] = '\0';
1101     }
1102   return 1;
1103 }
1104
1105 static int
1106 cmd_spec_htmlify (const char *com, const char *val, void *closure)
1107 {
1108   int flag = cmd_boolean (com, val, &opt.htmlify);
1109   if (flag && !opt.htmlify)
1110     opt.remove_listing = 0;
1111   return flag;
1112 }
1113
1114 /* Set the "mirror" mode.  It means: recursive download, timestamping,
1115    no limit on max. recursion depth, and don't remove listings.  */
1116
1117 static int
1118 cmd_spec_mirror (const char *com, const char *val, void *closure)
1119 {
1120   int mirror;
1121
1122   if (!cmd_boolean (com, val, &mirror))
1123     return 0;
1124   if (mirror)
1125     {
1126       opt.recursive = 1;
1127       if (!opt.no_dirstruct)
1128         opt.dirstruct = 1;
1129       opt.timestamping = 1;
1130       opt.reclevel = INFINITE_RECURSION;
1131       opt.remove_listing = 0;
1132     }
1133   return 1;
1134 }
1135
1136 /* Set progress.type to VAL, but verify that it's a valid progress
1137    implementation before that.  */
1138
1139 static int
1140 cmd_spec_progress (const char *com, const char *val, void *closure)
1141 {
1142   if (!valid_progress_implementation_p (val))
1143     {
1144       fprintf (stderr, _("%s: %s: Invalid progress type `%s'.\n"),
1145                exec_name, com, val);
1146       return 0;
1147     }
1148   xfree_null (opt.progress_type);
1149
1150   /* Don't call set_progress_implementation here.  It will be called
1151      in main() when it becomes clear what the log output is.  */
1152   opt.progress_type = xstrdup (val);
1153   return 1;
1154 }
1155
1156 /* Set opt.recursive to VAL as with cmd_boolean.  If opt.recursive is
1157    set to true, also set opt.dirstruct to 1, unless opt.no_dirstruct
1158    is specified.  */
1159
1160 static int
1161 cmd_spec_recursive (const char *com, const char *val, void *closure)
1162 {
1163   if (!cmd_boolean (com, val, &opt.recursive))
1164     return 0;
1165   else
1166     {
1167       if (opt.recursive && !opt.no_dirstruct)
1168         opt.dirstruct = 1;
1169     }
1170   return 1;
1171 }
1172
1173 static int
1174 cmd_spec_restrict_file_names (const char *com, const char *val, void *closure)
1175 {
1176   int restrict_os = opt.restrict_files_os;
1177   int restrict_ctrl = opt.restrict_files_ctrl;
1178
1179   const char *end = strchr (val, ',');
1180   if (!end)
1181     end = val + strlen (val);
1182
1183 #define VAL_IS(string_literal) BOUNDED_EQUAL (val, end, string_literal)
1184
1185   if (VAL_IS ("unix"))
1186     restrict_os = restrict_unix;
1187   else if (VAL_IS ("windows"))
1188     restrict_os = restrict_windows;
1189   else if (VAL_IS ("nocontrol"))
1190     restrict_ctrl = 0;
1191   else
1192     {
1193     err:
1194       fprintf (stderr,
1195                _("%s: %s: Invalid restriction `%s', use `unix' or `windows'.\n"),
1196                exec_name, com, val);
1197       return 0;
1198     }
1199
1200 #undef VAL_IS
1201
1202   if (*end)
1203     {
1204       if (!strcmp (end + 1, "nocontrol"))
1205         restrict_ctrl = 0;
1206       else
1207         goto err;
1208     }
1209
1210   opt.restrict_files_os = restrict_os;
1211   opt.restrict_files_ctrl = restrict_ctrl;
1212   return 1;
1213 }
1214
1215 /* Set all three timeout values. */
1216
1217 static int
1218 cmd_spec_timeout (const char *com, const char *val, void *closure)
1219 {
1220   double value;
1221   if (!cmd_time (com, val, &value))
1222     return 0;
1223   opt.read_timeout = value;
1224   opt.connect_timeout = value;
1225   opt.dns_timeout = value;
1226   return 1;
1227 }
1228
1229 static int
1230 cmd_spec_useragent (const char *com, const char *val, void *closure)
1231 {
1232   /* Just check for empty string and newline, so we don't throw total
1233      junk to the server.  */
1234   if (!*val || strchr (val, '\n'))
1235     {
1236       fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"),
1237                exec_name, com, val);
1238       return 0;
1239     }
1240   opt.useragent = xstrdup (val);
1241   return 1;
1242 }
1243 \f
1244 /* Miscellaneous useful routines.  */
1245
1246 /* A very simple atoi clone, more portable than strtol and friends,
1247    but reports errors, unlike atoi.  Returns 1 on success, 0 on
1248    failure.  In case of success, stores result to *DEST.  */
1249
1250 static int
1251 simple_atoi (const char *beg, const char *end, int *dest)
1252 {
1253   int result = 0;
1254   const char *p;
1255
1256   if (beg == end)
1257     return 0;
1258
1259   for (p = beg; p < end && ISDIGIT (*p); p++)
1260     result = (10 * result) + (*p - '0');
1261
1262   if (p != end)
1263     return 0;
1264
1265   *dest = result;
1266   return 1;
1267 }
1268
1269 /* Trivial atof, with error reporting.  Handles "<digits>[.<digits>]",
1270    doesn't handle exponential notation.  Returns 1 on success, 0 on
1271    failure.  In case of success, stores its result to *DEST.  */
1272
1273 static int
1274 simple_atof (const char *beg, const char *end, double *dest)
1275 {
1276   double result = 0;
1277
1278   int seen_dot = 0;
1279   int seen_digit = 0;
1280   double divider = 1;
1281
1282   const char *p;
1283
1284   for (p = beg; p < end; p++)
1285     {
1286       char ch = *p;
1287       if (ISDIGIT (ch))
1288         {
1289           if (!seen_dot)
1290             result = (10 * result) + (ch - '0');
1291           else
1292             result += (ch - '0') / (divider *= 10);
1293           seen_digit = 1;
1294         }
1295       else if (ch == '.')
1296         {
1297           if (!seen_dot)
1298             seen_dot = 1;
1299           else
1300             return 0;
1301         }
1302       else
1303         return 0;
1304     }
1305   if (!seen_digit)
1306     return 0;
1307
1308   *dest = result;
1309   return 1;
1310 }
1311
1312 static int
1313 check_user_specified_header (const char *s)
1314 {
1315   const char *p;
1316
1317   for (p = s; *p && *p != ':' && !ISSPACE (*p); p++);
1318   /* The header MUST contain `:' preceded by at least one
1319      non-whitespace character.  */
1320   if (*p != ':' || p == s)
1321     return 0;
1322   /* The header MUST NOT contain newlines.  */
1323   if (strchr (s, '\n'))
1324     return 0;
1325   return 1;
1326 }
1327 \f
1328 void cleanup_html_url PARAMS ((void));
1329 void res_cleanup PARAMS ((void));
1330 void downloaded_files_free PARAMS ((void));
1331 void http_cleanup PARAMS ((void));
1332
1333
1334 /* Free the memory allocated by global variables.  */
1335 void
1336 cleanup (void)
1337 {
1338   /* Free external resources, close files, etc. */
1339
1340   if (opt.dfp)
1341     fclose (opt.dfp);
1342
1343   /* We're exiting anyway so there's no real need to call free()
1344      hundreds of times.  Skipping the frees will make Wget exit
1345      faster.
1346
1347      However, when detecting leaks, it's crucial to free() everything
1348      because then you can find the real leaks, i.e. the allocated
1349      memory which grows with the size of the program.  */
1350
1351 #ifdef DEBUG_MALLOC
1352   convert_cleanup ();
1353   res_cleanup ();
1354   http_cleanup ();
1355   cleanup_html_url ();
1356   downloaded_files_free ();
1357   host_cleanup ();
1358   if (wget_cookie_jar)
1359     cookie_jar_delete (wget_cookie_jar);
1360
1361   {
1362     extern acc_t *netrc_list;
1363     free_netrc (netrc_list);
1364   }
1365   xfree_null (opt.lfilename);
1366   xfree_null (opt.dir_prefix);
1367   xfree_null (opt.input_filename);
1368   xfree_null (opt.output_document);
1369   free_vec (opt.accepts);
1370   free_vec (opt.rejects);
1371   free_vec (opt.excludes);
1372   free_vec (opt.includes);
1373   free_vec (opt.domains);
1374   free_vec (opt.follow_tags);
1375   free_vec (opt.ignore_tags);
1376   xfree_null (opt.progress_type);
1377   xfree (opt.ftp_acc);
1378   xfree_null (opt.ftp_pass);
1379   xfree_null (opt.ftp_proxy);
1380   xfree_null (opt.https_proxy);
1381   xfree_null (opt.http_proxy);
1382   free_vec (opt.no_proxy);
1383   xfree_null (opt.useragent);
1384   xfree_null (opt.referer);
1385   xfree_null (opt.http_user);
1386   xfree_null (opt.http_passwd);
1387   xfree_null (opt.user_header);
1388 #ifdef HAVE_SSL
1389   xfree_null (opt.sslcertkey);
1390   xfree_null (opt.sslcertfile);
1391 #endif /* HAVE_SSL */
1392   xfree_null (opt.bind_address);
1393   xfree_null (opt.cookies_input);
1394   xfree_null (opt.cookies_output);
1395 #endif
1396 }