]> sjero.net Git - wget/blob - src/init.c
7d48072a63d885d33cb786fe46ead8cac7ac922a
[wget] / src / init.c
1 /* Reading/parsing the initialization file.
2    Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001
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
60 #include "wget.h"
61 #include "utils.h"
62 #include "init.h"
63 #include "host.h"
64 #include "recur.h"
65 #include "netrc.h"
66 #include "cookies.h"            /* for cookie_jar_delete */
67 #include "progress.h"
68
69 #ifndef errno
70 extern int errno;
71 #endif
72
73 extern struct cookie_jar *wget_cookie_jar;
74
75 /* We want tilde expansion enabled only when reading `.wgetrc' lines;
76    otherwise, it will be performed by the shell.  This variable will
77    be set by the wgetrc-reading function.  */
78
79 static int enable_tilde_expansion;
80
81
82 #define CMD_DECLARE(func) static int func \
83   PARAMS ((const char *, const char *, void *))
84
85 CMD_DECLARE (cmd_boolean);
86 CMD_DECLARE (cmd_bytes);
87 CMD_DECLARE (cmd_directory_vector);
88 CMD_DECLARE (cmd_lockable_boolean);
89 CMD_DECLARE (cmd_number);
90 CMD_DECLARE (cmd_number_inf);
91 CMD_DECLARE (cmd_string);
92 CMD_DECLARE (cmd_file);
93 CMD_DECLARE (cmd_directory);
94 CMD_DECLARE (cmd_time);
95 CMD_DECLARE (cmd_vector);
96
97 CMD_DECLARE (cmd_spec_dirstruct);
98 CMD_DECLARE (cmd_spec_header);
99 CMD_DECLARE (cmd_spec_htmlify);
100 CMD_DECLARE (cmd_spec_mirror);
101 CMD_DECLARE (cmd_spec_progress);
102 CMD_DECLARE (cmd_spec_recursive);
103 CMD_DECLARE (cmd_spec_restrict_file_names);
104 CMD_DECLARE (cmd_spec_useragent);
105
106 /* List of recognized commands, each consisting of name, closure and function.
107    When adding a new command, simply add it to the list, but be sure to keep the
108    list sorted alphabetically, as comind() depends on it.  Also, be sure to add
109    any entries that allocate memory (e.g. cmd_string and cmd_vector guys) to the
110    cleanup() function below. */
111 static struct {
112   char *name;
113   void *closure;
114   int (*action) PARAMS ((const char *, const char *, void *));
115 } commands[] = {
116   { "accept",           &opt.accepts,           cmd_vector },
117   { "addhostdir",       &opt.add_hostdir,       cmd_boolean },
118   { "alwaysrest",       &opt.always_rest,       cmd_boolean }, /* deprecated */
119   { "background",       &opt.background,        cmd_boolean },
120   { "backupconverted",  &opt.backup_converted,  cmd_boolean },
121   { "backups",          &opt.backups,           cmd_number },
122   { "base",             &opt.base_href,         cmd_string },
123   { "bindaddress",      &opt.bind_address,      cmd_string },
124   { "cache",            &opt.allow_cache,       cmd_boolean },
125   { "continue",         &opt.always_rest,       cmd_boolean },
126   { "convertlinks",     &opt.convert_links,     cmd_boolean },
127   { "cookies",          &opt.cookies,           cmd_boolean },
128   { "cutdirs",          &opt.cut_dirs,          cmd_number },
129 #ifdef DEBUG
130   { "debug",            &opt.debug,             cmd_boolean },
131 #endif
132   { "deleteafter",      &opt.delete_after,      cmd_boolean },
133   { "dirprefix",        &opt.dir_prefix,        cmd_directory },
134   { "dirstruct",        NULL,                   cmd_spec_dirstruct },
135   { "dnscache",         &opt.dns_cache,         cmd_boolean },
136   { "domains",          &opt.domains,           cmd_vector },
137   { "dotbytes",         &opt.dot_bytes,         cmd_bytes },
138   { "dotsinline",       &opt.dots_in_line,      cmd_number },
139   { "dotspacing",       &opt.dot_spacing,       cmd_number },
140   { "dotstyle",         &opt.dot_style,         cmd_string },
141 #ifdef HAVE_SSL
142   { "egdfile",          &opt.sslegdsock,        cmd_file },
143 #endif
144   { "excludedirectories", &opt.excludes,        cmd_directory_vector },
145   { "excludedomains",   &opt.exclude_domains,   cmd_vector },
146   { "followftp",        &opt.follow_ftp,        cmd_boolean },
147   { "followtags",       &opt.follow_tags,       cmd_vector },
148   { "forcehtml",        &opt.force_html,        cmd_boolean },
149   { "ftpproxy",         &opt.ftp_proxy,         cmd_string },
150   { "glob",             &opt.ftp_glob,          cmd_boolean },
151   { "header",           NULL,                   cmd_spec_header },
152   { "htmlextension",    &opt.html_extension,    cmd_boolean },
153   { "htmlify",          NULL,                   cmd_spec_htmlify },
154   { "httpkeepalive",    &opt.http_keep_alive,   cmd_boolean },
155   { "httppasswd",       &opt.http_passwd,       cmd_string },
156   { "httpproxy",        &opt.http_proxy,        cmd_string },
157   { "httpsproxy",       &opt.https_proxy,       cmd_string },
158   { "httpuser",         &opt.http_user,         cmd_string },
159   { "ignorelength",     &opt.ignore_length,     cmd_boolean },
160   { "ignoretags",       &opt.ignore_tags,       cmd_vector },
161   { "includedirectories", &opt.includes,        cmd_directory_vector },
162   { "input",            &opt.input_filename,    cmd_file },
163   { "killlonger",       &opt.kill_longer,       cmd_boolean },
164   { "limitrate",        &opt.limit_rate,        cmd_bytes },
165   { "loadcookies",      &opt.cookies_input,     cmd_file },
166   { "logfile",          &opt.lfilename,         cmd_file },
167   { "login",            &opt.ftp_acc,           cmd_string },
168   { "mirror",           NULL,                   cmd_spec_mirror },
169   { "netrc",            &opt.netrc,             cmd_boolean },
170   { "noclobber",        &opt.noclobber,         cmd_boolean },
171   { "noparent",         &opt.no_parent,         cmd_boolean },
172   { "noproxy",          &opt.no_proxy,          cmd_vector },
173   { "numtries",         &opt.ntry,              cmd_number_inf },/* deprecated*/
174   { "outputdocument",   &opt.output_document,   cmd_file },
175   { "pagerequisites",   &opt.page_requisites,   cmd_boolean },
176   { "passiveftp",       &opt.ftp_pasv,          cmd_lockable_boolean },
177   { "passwd",           &opt.ftp_pass,          cmd_string },
178   { "postdata",         &opt.post_data,         cmd_string },
179   { "postfile",         &opt.post_file_name,    cmd_file },
180   { "progress",         &opt.progress_type,     cmd_spec_progress },
181   { "proxypasswd",      &opt.proxy_passwd,      cmd_string },
182   { "proxyuser",        &opt.proxy_user,        cmd_string },
183   { "quiet",            &opt.quiet,             cmd_boolean },
184   { "quota",            &opt.quota,             cmd_bytes },
185   { "randomwait",       &opt.random_wait,       cmd_boolean },
186   { "reclevel",         &opt.reclevel,          cmd_number_inf },
187   { "recursive",        NULL,                   cmd_spec_recursive },
188   { "referer",          &opt.referer,           cmd_string },
189   { "reject",           &opt.rejects,           cmd_vector },
190   { "relativeonly",     &opt.relative_only,     cmd_boolean },
191   { "removelisting",    &opt.remove_listing,    cmd_boolean },
192   { "restrictfilenames", NULL,                  cmd_spec_restrict_file_names },
193   { "retrsymlinks",     &opt.retr_symlinks,     cmd_boolean },
194   { "retryconnrefused", &opt.retry_connrefused, cmd_boolean },
195   { "robots",           &opt.use_robots,        cmd_boolean },
196   { "savecookies",      &opt.cookies_output,    cmd_file },
197   { "saveheaders",      &opt.save_headers,      cmd_boolean },
198   { "serverresponse",   &opt.server_response,   cmd_boolean },
199   { "spanhosts",        &opt.spanhost,          cmd_boolean },
200   { "spider",           &opt.spider,            cmd_boolean },
201 #ifdef HAVE_SSL
202   { "sslcadir",         &opt.sslcadir,          cmd_directory },
203   { "sslcafile",        &opt.sslcafile,         cmd_file },
204   { "sslcertfile",      &opt.sslcertfile,       cmd_file },
205   { "sslcertkey",       &opt.sslcertkey,        cmd_file },
206   { "sslcerttype",      &opt.sslcerttype,       cmd_number },
207   { "sslcheckcert",     &opt.sslcheckcert,      cmd_number },
208   { "sslprotocol",      &opt.sslprotocol,       cmd_number },
209 #endif /* HAVE_SSL */
210   { "timeout",          &opt.timeout,           cmd_time },
211   { "timestamping",     &opt.timestamping,      cmd_boolean },
212   { "tries",            &opt.ntry,              cmd_number_inf },
213   { "useproxy",         &opt.use_proxy,         cmd_boolean },
214   { "useragent",        NULL,                   cmd_spec_useragent },
215   { "verbose",          &opt.verbose,           cmd_boolean },
216   { "wait",             &opt.wait,              cmd_time },
217   { "waitretry",        &opt.waitretry,         cmd_time }
218 };
219
220 /* Look up COM in the commands[] array and return its index.  If COM
221    is not found, -1 is returned.  This function uses binary search.  */
222
223 static int
224 comind (const char *com)
225 {
226   int lo = 0, hi = ARRAY_SIZE (commands) - 1;
227
228   while (lo <= hi)
229     {
230       int mid = (lo + hi) >> 1;
231       int cmp = strcasecmp (com, commands[mid].name);
232       if (cmp < 0)
233         hi = mid - 1;
234       else if (cmp > 0)
235         lo = mid + 1;
236       else
237         return mid;
238     }
239   return -1;
240 }
241 \f
242 /* Reset the variables to default values.  */
243 static void
244 defaults (void)
245 {
246   char *tmp;
247
248   /* Most of the default values are 0.  Just reset everything, and
249      fill in the non-zero values.  Note that initializing pointers to
250      NULL this way is technically illegal, but porting Wget to a
251      machine where NULL is not all-zero bit pattern will be the least
252      of the implementors' worries.  */
253   memset (&opt, 0, sizeof (opt));
254
255   opt.cookies = 1;
256
257   opt.verbose = -1;
258   opt.dir_prefix = xstrdup (".");
259   opt.ntry = 20;
260   opt.reclevel = 5;
261   opt.add_hostdir = 1;
262   opt.ftp_acc  = xstrdup ("anonymous");
263   opt.ftp_pass = xstrdup ("-wget@");
264   opt.netrc = 1;
265   opt.ftp_glob = 1;
266   opt.htmlify = 1;
267   opt.http_keep_alive = 1;
268   opt.use_proxy = 1;
269   tmp = getenv ("no_proxy");
270   if (tmp)
271     opt.no_proxy = sepstring (tmp);
272   opt.allow_cache = 1;
273
274 #ifdef HAVE_SELECT
275   opt.timeout = 900;
276 #endif
277   opt.use_robots = 1;
278
279   opt.remove_listing = 1;
280
281   opt.dot_bytes = 1024;
282   opt.dot_spacing = 10;
283   opt.dots_in_line = 50;
284
285   opt.dns_cache = 1;
286
287   /* The default for file name restriction defaults to the OS type. */
288 #if !defined(WINDOWS) && !defined(__CYGWIN__)
289   opt.restrict_files_os = restrict_unix;
290 #else
291   opt.restrict_files_os = restrict_windows;
292 #endif
293   opt.restrict_files_ctrl = 1;
294 }
295 \f
296 /* Return the user's home directory (strdup-ed), or NULL if none is
297    found.  */
298 char *
299 home_dir (void)
300 {
301   char *home = getenv ("HOME");
302
303   if (!home)
304     {
305 #ifndef WINDOWS
306       /* If HOME is not defined, try getting it from the password
307          file.  */
308       struct passwd *pwd = getpwuid (getuid ());
309       if (!pwd || !pwd->pw_dir)
310         return NULL;
311       home = pwd->pw_dir;
312 #else  /* WINDOWS */
313       home = "C:\\";
314       /* #### Maybe I should grab home_dir from registry, but the best
315          that I could get from there is user's Start menu.  It sucks!  */
316 #endif /* WINDOWS */
317     }
318
319   return home ? xstrdup (home) : NULL;
320 }
321
322 /* Return the path to the user's .wgetrc.  This is either the value of
323    `WGETRC' environment variable, or `$HOME/.wgetrc'.
324
325    If the `WGETRC' variable exists but the file does not exist, the
326    function will exit().  */
327 static char *
328 wgetrc_file_name (void)
329 {
330   char *env, *home;
331   char *file = NULL;
332
333   /* Try the environment.  */
334   env = getenv ("WGETRC");
335   if (env && *env)
336     {
337       if (!file_exists_p (env))
338         {
339           fprintf (stderr, "%s: %s: %s.\n", exec_name, env, strerror (errno));
340           exit (1);
341         }
342       return xstrdup (env);
343     }
344
345 #ifndef WINDOWS
346   /* If that failed, try $HOME/.wgetrc.  */
347   home = home_dir ();
348   if (home)
349     {
350       file = (char *)xmalloc (strlen (home) + 1 + strlen (".wgetrc") + 1);
351       sprintf (file, "%s/.wgetrc", home);
352     }
353   FREE_MAYBE (home);
354 #else  /* WINDOWS */
355   /* Under Windows, "home" is (for the purposes of this function) the
356      directory where `wget.exe' resides, and `wget.ini' will be used
357      as file name.  SYSTEM_WGETRC should not be defined under WINDOWS.
358
359      It is not as trivial as I assumed, because on 95 argv[0] is full
360      path, but on NT you get what you typed in command line.  --dbudor */
361   home = ws_mypath ();
362   if (home)
363     {
364       file = (char *)xmalloc (strlen (home) + strlen ("wget.ini") + 1);
365       sprintf (file, "%swget.ini", home);
366     }
367 #endif /* WINDOWS */
368
369   if (!file)
370     return NULL;
371   if (!file_exists_p (file))
372     {
373       xfree (file);
374       return NULL;
375     }
376   return file;
377 }
378
379 /* Initialize variables from a wgetrc file */
380 static void
381 run_wgetrc (const char *file)
382 {
383   FILE *fp;
384   char *line;
385   int ln;
386
387   fp = fopen (file, "rb");
388   if (!fp)
389     {
390       fprintf (stderr, _("%s: Cannot read %s (%s).\n"), exec_name,
391                file, strerror (errno));
392       return;
393     }
394   enable_tilde_expansion = 1;
395   ln = 1;
396   while ((line = read_whole_line (fp)))
397     {
398       char *com, *val;
399       int status;
400
401       /* Parse the line.  */
402       status = parse_line (line, &com, &val);
403       xfree (line);
404       /* If everything is OK, set the value.  */
405       if (status == 1)
406         {
407           if (!setval (com, val))
408             fprintf (stderr, _("%s: Error in %s at line %d.\n"), exec_name,
409                      file, ln);
410           xfree (com);
411           xfree (val);
412         }
413       else if (status == 0)
414         fprintf (stderr, _("%s: Error in %s at line %d.\n"), exec_name,
415                  file, ln);
416       ++ln;
417     }
418   enable_tilde_expansion = 0;
419   fclose (fp);
420 }
421
422 /* Initialize the defaults and run the system wgetrc and user's own
423    wgetrc.  */
424 void
425 initialize (void)
426 {
427   char *file;
428
429   /* Load the hard-coded defaults.  */
430   defaults ();
431
432   /* If SYSTEM_WGETRC is defined, use it.  */
433 #ifdef SYSTEM_WGETRC
434   if (file_exists_p (SYSTEM_WGETRC))
435     run_wgetrc (SYSTEM_WGETRC);
436 #endif
437   /* Override it with your own, if one exists.  */
438   file = wgetrc_file_name ();
439   if (!file)
440     return;
441   /* #### We should somehow canonicalize `file' and SYSTEM_WGETRC,
442      really.  */
443 #ifdef SYSTEM_WGETRC
444   if (!strcmp (file, SYSTEM_WGETRC))
445     {
446       fprintf (stderr, _("\
447 %s: Warning: Both system and user wgetrc point to `%s'.\n"),
448                exec_name, file);
449     }
450   else
451 #endif
452     run_wgetrc (file);
453   xfree (file);
454   return;
455 }
456 \f
457 /* Parse the line pointed by line, with the syntax:
458    <sp>* command <sp>* = <sp>* value <newline>
459    Uses malloc to allocate space for command and value.
460    If the line is invalid, data is freed and 0 is returned.
461
462    Return values:
463     1 - success
464     0 - failure
465    -1 - empty */
466 int
467 parse_line (const char *line, char **com, char **val)
468 {
469   const char *p = line;
470   const char *orig_comptr, *end;
471   char *new_comptr;
472
473   /* Skip whitespace.  */
474   while (*p && ISSPACE (*p))
475     ++p;
476
477   /* Don't process empty lines.  */
478   if (!*p || *p == '#')
479     return -1;
480
481   for (orig_comptr = p; ISALPHA (*p) || *p == '_' || *p == '-'; p++)
482     ;
483   /* The next char should be space or '='.  */
484   if (!ISSPACE (*p) && (*p != '='))
485     return 0;
486   /* Here we cannot use strdupdelim() as we normally would because we
487      want to skip the `-' and `_' characters in the input string.  */
488   *com = (char *)xmalloc (p - orig_comptr + 1);
489   for (new_comptr = *com; orig_comptr < p; orig_comptr++)
490     {
491       if (*orig_comptr == '_' || *orig_comptr == '-')
492         continue;
493       *new_comptr++ = *orig_comptr;
494     }
495   *new_comptr = '\0';
496   /* If the command is invalid, exit now.  */
497   if (comind (*com) == -1)
498     {
499       xfree (*com);
500       return 0;
501     }
502
503   /* Skip spaces before '='.  */
504   for (; ISSPACE (*p); p++);
505   /* If '=' not found, bail out.  */
506   if (*p != '=')
507     {
508       xfree (*com);
509       return 0;
510     }
511   /* Skip spaces after '='.  */
512   for (++p; ISSPACE (*p); p++);
513   /* Get the ending position for VAL by starting with the end of the
514      line and skipping whitespace.  */
515   end = line + strlen (line) - 1;
516   while (end > p && ISSPACE (*end))
517     --end;
518   *val = strdupdelim (p, end + 1);
519   return 1;
520 }
521
522 /* Set COM to VAL.  This is the meat behind processing `.wgetrc'.  No
523    fatals -- error signal prints a warning and resets to default
524    value.  All error messages are printed to stderr, *not* to
525    opt.lfile, since opt.lfile wasn't even generated yet.  */
526 int
527 setval (const char *com, const char *val)
528 {
529   int ind;
530
531   if (!com || !val)
532     return 0;
533   ind = comind (com);
534   if (ind == -1)
535     {
536       /* #### Should I just abort()?  */
537 #ifdef DEBUG
538       fprintf (stderr, _("%s: BUG: unknown command `%s', value `%s'.\n"),
539                exec_name, com, val);
540 #endif
541       return 0;
542     }
543   return ((*commands[ind].action) (com, val, commands[ind].closure));
544 }
545 \f
546 /* Generic helper functions, for use with `commands'. */
547
548 static int myatoi PARAMS ((const char *s));
549
550 /* Store the boolean value from VAL to CLOSURE.  COM is ignored,
551    except for error messages.  */
552 static int
553 cmd_boolean (const char *com, const char *val, void *closure)
554 {
555   int bool_value;
556   const char *v = val;
557 #define LC(x) TOLOWER(x)
558
559   if ((LC(v[0]) == 'o' && LC(v[1]) == 'n' && !v[2])
560       ||
561       (LC(v[0]) == 'y' && LC(v[1]) == 'e' && LC(v[2]) == 's' && !v[3])
562       ||
563       (v[0] == '1' && !v[1]))
564     /* "on", "yes" and "1" mean true. */
565     bool_value = 1;
566   else if ((LC(v[0]) == 'o' && LC(v[1]) == 'f' && LC(v[2]) == 'f' && !v[3])
567            ||
568            (LC(v[0]) == 'n' && LC(v[1]) == 'o' && !v[2])
569            ||
570            (v[0] == '0' && !v[1]))
571     /* "off", "no" and "0" mean false. */
572     bool_value = 0;
573   else
574     {
575       fprintf (stderr, _("%s: %s: Please specify on or off.\n"),
576                exec_name, com);
577       return 0;
578     }
579
580   *(int *)closure = bool_value;
581   return 1;
582 }
583
584 /* Store the lockable_boolean {2, 1, 0, -1} value from VAL to CLOSURE.  COM is
585    ignored, except for error messages.  Values 2 and -1 indicate that once
586    defined, the value may not be changed by successive wgetrc files or
587    command-line arguments.
588
589    Values: 2 - Enable a particular option for good ("always")
590            1 - Enable an option ("on")
591            0 - Disable an option ("off")
592           -1 - Disable an option for good ("never") */
593 static int
594 cmd_lockable_boolean (const char *com, const char *val, void *closure)
595 {
596   int lockable_boolean_value;
597
598   /*
599    * If a config file said "always" or "never", don't allow command line
600    * arguments to override the config file.
601    */
602   if (*(int *)closure == -1 || *(int *)closure == 2)
603     return 1;
604
605   if (!strcasecmp (val, "always") || !strcmp (val, "2"))
606     lockable_boolean_value = 2;
607   else if (!strcasecmp (val, "on")
608            || !strcasecmp (val, "yes")
609            || !strcmp (val, "1"))
610     lockable_boolean_value = 1;
611   else if (!strcasecmp (val, "off")
612            || !strcasecmp (val, "no")
613            || !strcmp (val, "0"))
614     lockable_boolean_value = 0;
615   else if (!strcasecmp (val, "never") || !strcmp (val, "-1"))
616     lockable_boolean_value = -1;
617   else
618     {
619       fprintf (stderr, _("%s: %s: Please specify always, on, off, "
620                          "or never.\n"),
621                exec_name, com);
622       return 0;
623     }
624
625   *(int *)closure = lockable_boolean_value;
626   return 1;
627 }
628
629 /* Set the non-negative integer value from VAL to CLOSURE.  With
630    incorrect specification, the number remains unchanged.  */
631 static int
632 cmd_number (const char *com, const char *val, void *closure)
633 {
634   int num = myatoi (val);
635
636   if (num == -1)
637     {
638       fprintf (stderr, _("%s: %s: Invalid specification `%s'.\n"),
639                exec_name, com, val);
640       return 0;
641     }
642   *(int *)closure = num;
643   return 1;
644 }
645
646 /* Similar to cmd_number(), only accepts `inf' as a synonym for 0.  */
647 static int
648 cmd_number_inf (const char *com, const char *val, void *closure)
649 {
650   if (!strcasecmp (val, "inf"))
651     {
652       *(int *)closure = 0;
653       return 1;
654     }
655   return cmd_number (com, val, closure);
656 }
657
658 /* Copy (strdup) the string at COM to a new location and place a
659    pointer to *CLOSURE.  */
660 static int
661 cmd_string (const char *com, const char *val, void *closure)
662 {
663   char **pstring = (char **)closure;
664
665   FREE_MAYBE (*pstring);
666   *pstring = xstrdup (val);
667   return 1;
668 }
669
670 /* Like the above, but handles tilde-expansion when reading a user's
671    `.wgetrc'.  In that case, and if VAL begins with `~', the tilde
672    gets expanded to the user's home directory.  */
673 static int
674 cmd_file (const char *com, const char *val, void *closure)
675 {
676   char **pstring = (char **)closure;
677
678   FREE_MAYBE (*pstring);
679
680   /* #### If VAL is empty, perhaps should set *CLOSURE to NULL.  */
681
682   if (!enable_tilde_expansion || !(*val == '~' && (*(val + 1) == '/'
683 #ifdef WINDOWS
684           || *(val + 1) == '\\'
685 #endif
686           )))
687     {
688     noexpand:
689       *pstring = xstrdup (val);
690     }
691   else
692     {
693       char *result;
694       int homelen;
695       char *home = home_dir ();
696       if (!home)
697         goto noexpand;
698
699       homelen = strlen (home);
700       while (homelen && (home[homelen - 1] == '/'
701 #ifdef WINDOWS
702             || home[homelen - 1] == '\\'
703 #endif
704             ))
705         home[--homelen] = '\0';
706
707       /* Skip the leading "~/". */
708 #ifdef WINDOWS
709       for (++val; *val == '/' || *val == '\\'; val++)
710         ;
711 #else
712       for (++val; *val == '/'; val++)
713         ;
714 #endif
715
716       result = xmalloc (homelen + 1 + strlen (val) + 1);
717       memcpy (result, home, homelen);
718       result[homelen] = '/';
719       strcpy (result + homelen + 1, val);
720
721       *pstring = result;
722     }
723 #ifdef WINDOWS
724   /* Convert "\" to "/". */
725   {
726     char *s;
727     for (s = *pstring; *s; s++)
728       if (*s == '\\')
729         *s = '/';
730   }
731 #endif
732   return 1;
733 }
734
735 /* Like cmd_file, but strips trailing '/' characters.  */
736 static int
737 cmd_directory (const char *com, const char *val, void *closure)
738 {
739   char *s, *t;
740
741   /* Call cmd_file() for tilde expansion and separator
742      canonicalization (backslash -> slash under Windows).  These
743      things should perhaps be in a separate function.  */
744   if (!cmd_file (com, val, closure))
745     return 0;
746
747   s = *(char **)closure;
748   t = s + strlen (s);
749   while (t > s && *--t == '/')
750     *t = '\0';
751
752   return 1;
753 }
754
755 /* Merge the vector (array of strings separated with `,') in COM with
756    the vector (NULL-terminated array of strings) pointed to by
757    CLOSURE.  */
758 static int
759 cmd_vector (const char *com, const char *val, void *closure)
760 {
761   char ***pvec = (char ***)closure;
762
763   if (*val)
764     *pvec = merge_vecs (*pvec, sepstring (val));
765   else
766     {
767       free_vec (*pvec);
768       *pvec = NULL;
769     }
770   return 1;
771 }
772
773 static int
774 cmd_directory_vector (const char *com, const char *val, void *closure)
775 {
776   char ***pvec = (char ***)closure;
777
778   if (*val)
779     {
780       /* Strip the trailing slashes from directories.  */
781       char **t, **seps;
782
783       seps = sepstring (val);
784       for (t = seps; t && *t; t++)
785         {
786           int len = strlen (*t);
787           /* Skip degenerate case of root directory.  */
788           if (len > 1)
789             {
790               if ((*t)[len - 1] == '/')
791                 (*t)[len - 1] = '\0';
792             }
793         }
794       *pvec = merge_vecs (*pvec, seps);
795     }
796   else
797     {
798       free_vec (*pvec);
799       *pvec = NULL;
800     }
801   return 1;
802 }
803
804 /* Set the value stored in VAL to CLOSURE (which should point to a
805    long int), allowing several postfixes, with the following syntax
806    (regexp):
807
808    [0-9]+       -> bytes
809    [0-9]+[kK]   -> bytes * 1024
810    [0-9]+[mM]   -> bytes * 1024 * 1024
811    inf          -> 0
812
813    Anything else is flagged as incorrect, and CLOSURE is unchanged.  */
814 static int
815 cmd_bytes (const char *com, const char *val, void *closure)
816 {
817   long result;
818   long *out = (long *)closure;
819   const char *p;
820
821   result = 0;
822   p = val;
823   /* Check for "inf".  */
824   if (p[0] == 'i' && p[1] == 'n' && p[2] == 'f' && p[3] == '\0')
825     {
826       *out = 0;
827       return 1;
828     }
829   /* Search for digits and construct result.  */
830   for (; *p && ISDIGIT (*p); p++)
831     result = (10 * result) + (*p - '0');
832   /* If no digits were found, or more than one character is following
833      them, bail out.  */
834   if (p == val || (*p != '\0' && *(p + 1) != '\0'))
835     {
836       printf (_("%s: Invalid specification `%s'\n"), com, val);
837       return 0;
838     }
839   /* Search for a designator.  */
840   switch (TOLOWER (*p))
841     {
842     case '\0':
843       /* None */
844       break;
845     case 'k':
846       /* Kilobytes */
847       result *= 1024;
848       break;
849     case 'm':
850       /* Megabytes */
851       result *= (long)1024 * 1024;
852       break;
853     case 'g':
854       /* Gigabytes */
855       result *= (long)1024 * 1024 * 1024;
856       break;
857     default:
858       printf (_("%s: Invalid specification `%s'\n"), com, val);
859       return 0;
860     }
861   *out = result;
862   return 1;
863 }
864
865 /* Store the value of VAL to *OUT, allowing suffixes for minutes and
866    hours.  */
867 static int
868 cmd_time (const char *com, const char *val, void *closure)
869 {
870   long result = 0;
871   const char *p = val;
872
873   /* Search for digits and construct result.  */
874   for (; *p && ISDIGIT (*p); p++)
875     result = (10 * result) + (*p - '0');
876   /* If no digits were found, or more than one character is following
877      them, bail out.  */
878   if (p == val || (*p != '\0' && *(p + 1) != '\0'))
879     {
880       printf (_("%s: Invalid specification `%s'\n"), com, val);
881       return 0;
882     }
883   /* Search for a suffix.  */
884   switch (TOLOWER (*p))
885     {
886     case '\0':
887       /* None */
888       break;
889     case 'm':
890       /* Minutes */
891       result *= 60;
892       break;
893     case 'h':
894       /* Seconds */
895       result *= 3600;
896       break;
897     case 'd':
898       /* Days (overflow on 16bit machines) */
899       result *= 86400L;
900       break;
901     case 'w':
902       /* Weeks :-) */
903       result *= 604800L;
904       break;
905     default:
906       printf (_("%s: Invalid specification `%s'\n"), com, val);
907       return 0;
908     }
909   *(long *)closure = result;
910   return 1;
911 }
912 \f
913 /* Specialized helper functions, used by `commands' to handle some
914    options specially.  */
915
916 static int check_user_specified_header PARAMS ((const char *));
917
918 static int
919 cmd_spec_dirstruct (const char *com, const char *val, void *closure)
920 {
921   if (!cmd_boolean (com, val, &opt.dirstruct))
922     return 0;
923   /* Since dirstruct behaviour is explicitly changed, no_dirstruct
924      must be affected inversely.  */
925   if (opt.dirstruct)
926     opt.no_dirstruct = 0;
927   else
928     opt.no_dirstruct = 1;
929   return 1;
930 }
931
932 static int
933 cmd_spec_header (const char *com, const char *val, void *closure)
934 {
935   if (!*val)
936     {
937       /* Empty header means reset headers.  */
938       FREE_MAYBE (opt.user_header);
939       opt.user_header = NULL;
940     }
941   else
942     {
943       int i;
944
945       if (!check_user_specified_header (val))
946         {
947           fprintf (stderr, _("%s: %s: Invalid specification `%s'.\n"),
948                    exec_name, com, val);
949           return 0;
950         }
951       i = opt.user_header ? strlen (opt.user_header) : 0;
952       opt.user_header = (char *)xrealloc (opt.user_header, i + strlen (val)
953                                           + 2 + 1);
954       strcpy (opt.user_header + i, val);
955       i += strlen (val);
956       opt.user_header[i++] = '\r';
957       opt.user_header[i++] = '\n';
958       opt.user_header[i] = '\0';
959     }
960   return 1;
961 }
962
963 static int
964 cmd_spec_htmlify (const char *com, const char *val, void *closure)
965 {
966   int flag = cmd_boolean (com, val, &opt.htmlify);
967   if (flag && !opt.htmlify)
968     opt.remove_listing = 0;
969   return flag;
970 }
971
972 static int
973 cmd_spec_mirror (const char *com, const char *val, void *closure)
974 {
975   int mirror;
976
977   if (!cmd_boolean (com, val, &mirror))
978     return 0;
979   if (mirror)
980     {
981       opt.recursive = 1;
982       if (!opt.no_dirstruct)
983         opt.dirstruct = 1;
984       opt.timestamping = 1;
985       opt.reclevel = INFINITE_RECURSION;
986       opt.remove_listing = 0;
987     }
988   return 1;
989 }
990
991 static int
992 cmd_spec_progress (const char *com, const char *val, void *closure)
993 {
994   if (!valid_progress_implementation_p (val))
995     {
996       fprintf (stderr, _("%s: %s: Invalid progress type `%s'.\n"),
997                exec_name, com, val);
998       return 0;
999     }
1000   FREE_MAYBE (opt.progress_type);
1001
1002   /* Don't call set_progress_implementation here.  It will be called
1003      in main() when it becomes clear what the log output is.  */
1004   opt.progress_type = xstrdup (val);
1005   return 1;
1006 }
1007
1008 static int
1009 cmd_spec_recursive (const char *com, const char *val, void *closure)
1010 {
1011   if (!cmd_boolean (com, val, &opt.recursive))
1012     return 0;
1013   else
1014     {
1015       if (opt.recursive && !opt.no_dirstruct)
1016         opt.dirstruct = 1;
1017     }
1018   return 1;
1019 }
1020
1021 static int
1022 cmd_spec_restrict_file_names (const char *com, const char *val, void *closure)
1023 {
1024   int restrict_os = opt.restrict_files_os;
1025   int restrict_ctrl = opt.restrict_files_ctrl;
1026
1027   const char *end = strchr (val, ',');
1028   if (!end)
1029     end = val + strlen (val);
1030
1031 #define VAL_IS(string_literal) BOUNDED_EQUAL (val, end, string_literal)
1032
1033   if (VAL_IS ("unix"))
1034     restrict_os = restrict_unix;
1035   else if (VAL_IS ("windows"))
1036     restrict_os = restrict_windows;
1037   else if (VAL_IS ("nocontrol"))
1038     restrict_ctrl = 0;
1039   else
1040     {
1041     err:
1042       fprintf (stderr, _("%s: %s: Invalid specification `%s'.\n"),
1043                exec_name, com, val);
1044       return 0;
1045     }
1046
1047 #undef VAL_IS
1048
1049   if (*end)
1050     {
1051       if (!strcmp (end + 1, "nocontrol"))
1052         restrict_ctrl = 0;
1053       else
1054         goto err;
1055     }
1056
1057   opt.restrict_files_os = restrict_os;
1058   opt.restrict_files_ctrl = restrict_ctrl;
1059   return 1;
1060 }
1061
1062 static int
1063 cmd_spec_useragent (const char *com, const char *val, void *closure)
1064 {
1065   /* Just check for empty string and newline, so we don't throw total
1066      junk to the server.  */
1067   if (!*val || strchr (val, '\n'))
1068     {
1069       fprintf (stderr, _("%s: %s: Invalid specification `%s'.\n"),
1070                exec_name, com, val);
1071       return 0;
1072     }
1073   opt.useragent = xstrdup (val);
1074   return 1;
1075 }
1076 \f
1077 /* Miscellaneous useful routines.  */
1078
1079 /* Return the integer value of a positive integer written in S, or -1
1080    if an error was encountered.  */
1081 static int
1082 myatoi (const char *s)
1083 {
1084   int res;
1085   const char *orig = s;
1086
1087   for (res = 0; *s && ISDIGIT (*s); s++)
1088     res = 10 * res + (*s - '0');
1089   if (*s || orig == s)
1090     return -1;
1091   else
1092     return res;
1093 }
1094
1095 static int
1096 check_user_specified_header (const char *s)
1097 {
1098   const char *p;
1099
1100   for (p = s; *p && *p != ':' && !ISSPACE (*p); p++);
1101   /* The header MUST contain `:' preceded by at least one
1102      non-whitespace character.  */
1103   if (*p != ':' || p == s)
1104     return 0;
1105   /* The header MUST NOT contain newlines.  */
1106   if (strchr (s, '\n'))
1107     return 0;
1108   return 1;
1109 }
1110 \f
1111 void cleanup_html_url PARAMS ((void));
1112 void res_cleanup PARAMS ((void));
1113 void downloaded_files_free PARAMS ((void));
1114 void http_cleanup PARAMS ((void));
1115
1116
1117 /* Free the memory allocated by global variables.  */
1118 void
1119 cleanup (void)
1120 {
1121   /* Free external resources, close files, etc. */
1122
1123   if (opt.dfp)
1124     fclose (opt.dfp);
1125
1126   /* We're exiting anyway so there's no real need to call free()
1127      hundreds of times.  Skipping the frees will make Wget exit
1128      faster.
1129
1130      However, when detecting leaks, it's crucial to free() everything
1131      because then you can find the real leaks, i.e. the allocated
1132      memory which grows with the size of the program.  */
1133
1134 #ifdef DEBUG_MALLOC
1135   recursive_cleanup ();
1136   res_cleanup ();
1137   http_cleanup ();
1138   cleanup_html_url ();
1139   downloaded_files_free ();
1140   host_cleanup ();
1141   cookie_jar_delete (wget_cookie_jar);
1142
1143   {
1144     extern acc_t *netrc_list;
1145     free_netrc (netrc_list);
1146   }
1147   FREE_MAYBE (opt.lfilename);
1148   xfree (opt.dir_prefix);
1149   FREE_MAYBE (opt.input_filename);
1150   FREE_MAYBE (opt.output_document);
1151   free_vec (opt.accepts);
1152   free_vec (opt.rejects);
1153   free_vec (opt.excludes);
1154   free_vec (opt.includes);
1155   free_vec (opt.domains);
1156   free_vec (opt.follow_tags);
1157   free_vec (opt.ignore_tags);
1158   FREE_MAYBE (opt.progress_type);
1159   xfree (opt.ftp_acc);
1160   FREE_MAYBE (opt.ftp_pass);
1161   FREE_MAYBE (opt.ftp_proxy);
1162   FREE_MAYBE (opt.https_proxy);
1163   FREE_MAYBE (opt.http_proxy);
1164   free_vec (opt.no_proxy);
1165   FREE_MAYBE (opt.useragent);
1166   FREE_MAYBE (opt.referer);
1167   FREE_MAYBE (opt.http_user);
1168   FREE_MAYBE (opt.http_passwd);
1169   FREE_MAYBE (opt.user_header);
1170 #ifdef HAVE_SSL
1171   FREE_MAYBE (opt.sslcertkey);
1172   FREE_MAYBE (opt.sslcertfile);
1173 #endif /* HAVE_SSL */
1174   FREE_MAYBE (opt.bind_address);
1175   FREE_MAYBE (opt.cookies_input);
1176   FREE_MAYBE (opt.cookies_output);
1177 #endif
1178 }