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