]> sjero.net Git - wget/blob - src/init.c
[svn] Update FSF's address and copyright years.
[wget] / src / init.c
1 /* Reading/parsing the initialization file.
2    Copyright (C) 1996-2005 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 GNU Wget is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Wget; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 #include <config.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif
37 #include <string.h>
38 #include <errno.h>
39
40 #ifdef HAVE_PWD_H
41 # include <pwd.h>
42 #endif
43 #include <assert.h>
44
45 #include "wget.h"
46 #include "utils.h"
47 #include "init.h"
48 #include "host.h"
49 #include "netrc.h"
50 #include "progress.h"
51 #include "recur.h"              /* for INFINITE_RECURSION */
52 #include "convert.h"            /* for convert_cleanup */
53 #include "res.h"                /* for res_cleanup */
54 #include "http.h"               /* for http_cleanup */
55 #include "retr.h"               /* for output_stream */
56
57 /* We want tilde expansion enabled only when reading `.wgetrc' lines;
58    otherwise, it will be performed by the shell.  This variable will
59    be set by the wgetrc-reading function.  */
60
61 static bool enable_tilde_expansion;
62
63
64 #define CMD_DECLARE(func) static bool func (const char *, const char *, void *)
65
66 CMD_DECLARE (cmd_boolean);
67 CMD_DECLARE (cmd_bytes);
68 CMD_DECLARE (cmd_bytes_sum);
69 #ifdef HAVE_SSL
70 CMD_DECLARE (cmd_cert_type);
71 #endif
72 CMD_DECLARE (cmd_directory_vector);
73 CMD_DECLARE (cmd_number);
74 CMD_DECLARE (cmd_number_inf);
75 CMD_DECLARE (cmd_string);
76 CMD_DECLARE (cmd_file);
77 CMD_DECLARE (cmd_directory);
78 CMD_DECLARE (cmd_time);
79 CMD_DECLARE (cmd_vector);
80
81 CMD_DECLARE (cmd_spec_dirstruct);
82 CMD_DECLARE (cmd_spec_header);
83 CMD_DECLARE (cmd_spec_htmlify);
84 CMD_DECLARE (cmd_spec_mirror);
85 CMD_DECLARE (cmd_spec_prefer_family);
86 CMD_DECLARE (cmd_spec_progress);
87 CMD_DECLARE (cmd_spec_recursive);
88 CMD_DECLARE (cmd_spec_restrict_file_names);
89 #ifdef HAVE_SSL
90 CMD_DECLARE (cmd_spec_secure_protocol);
91 #endif
92 CMD_DECLARE (cmd_spec_timeout);
93 CMD_DECLARE (cmd_spec_useragent);
94 CMD_DECLARE (cmd_spec_verbose);
95
96 /* List of recognized commands, each consisting of name, place and
97    function.  When adding a new command, simply add it to the list,
98    but be sure to keep the list sorted alphabetically, as
99    command_by_name depends on it.  Also, be sure to add any entries
100    that allocate memory (e.g. cmd_string and cmd_vector) to the
101    cleanup() function below. */
102
103 static struct {
104   const char *name;
105   void *place;
106   bool (*action) (const char *, const char *, void *);
107 } commands[] = {
108   { "accept",           &opt.accepts,           cmd_vector },
109   { "addhostdir",       &opt.add_hostdir,       cmd_boolean },
110   { "alwaysrest",       &opt.always_rest,       cmd_boolean }, /* deprecated */
111   { "background",       &opt.background,        cmd_boolean },
112   { "backupconverted",  &opt.backup_converted,  cmd_boolean },
113   { "backups",          &opt.backups,           cmd_number },
114   { "base",             &opt.base_href,         cmd_string },
115   { "bindaddress",      &opt.bind_address,      cmd_string },
116 #ifdef HAVE_SSL
117   { "cacertificate",    &opt.ca_cert,           cmd_file },
118 #endif
119   { "cache",            &opt.allow_cache,       cmd_boolean },
120 #ifdef HAVE_SSL
121   { "cadirectory",      &opt.ca_directory,      cmd_directory },
122   { "certificate",      &opt.cert_file,         cmd_file },
123   { "certificatetype",  &opt.cert_type,         cmd_cert_type },
124   { "checkcertificate", &opt.check_cert,        cmd_boolean },
125 #endif
126   { "connecttimeout",   &opt.connect_timeout,   cmd_time },
127   { "continue",         &opt.always_rest,       cmd_boolean },
128   { "convertlinks",     &opt.convert_links,     cmd_boolean },
129   { "cookies",          &opt.cookies,           cmd_boolean },
130   { "cutdirs",          &opt.cut_dirs,          cmd_number },
131 #ifdef ENABLE_DEBUG
132   { "debug",            &opt.debug,             cmd_boolean },
133 #endif
134   { "deleteafter",      &opt.delete_after,      cmd_boolean },
135   { "dirprefix",        &opt.dir_prefix,        cmd_directory },
136   { "dirstruct",        NULL,                   cmd_spec_dirstruct },
137   { "dnscache",         &opt.dns_cache,         cmd_boolean },
138   { "dnstimeout",       &opt.dns_timeout,       cmd_time },
139   { "domains",          &opt.domains,           cmd_vector },
140   { "dotbytes",         &opt.dot_bytes,         cmd_bytes },
141   { "dotsinline",       &opt.dots_in_line,      cmd_number },
142   { "dotspacing",       &opt.dot_spacing,       cmd_number },
143   { "dotstyle",         &opt.dot_style,         cmd_string },
144 #ifdef HAVE_SSL
145   { "egdfile",          &opt.egd_file,          cmd_file },
146 #endif
147   { "excludedirectories", &opt.excludes,        cmd_directory_vector },
148   { "excludedomains",   &opt.exclude_domains,   cmd_vector },
149   { "followftp",        &opt.follow_ftp,        cmd_boolean },
150   { "followtags",       &opt.follow_tags,       cmd_vector },
151   { "forcehtml",        &opt.force_html,        cmd_boolean },
152   { "ftppasswd",        &opt.ftp_passwd,        cmd_string }, /* deprecated */
153   { "ftppassword",      &opt.ftp_passwd,        cmd_string },
154   { "ftpproxy",         &opt.ftp_proxy,         cmd_string },
155   { "ftpuser",          &opt.ftp_user,          cmd_string },
156   { "glob",             &opt.ftp_glob,          cmd_boolean },
157   { "header",           NULL,                   cmd_spec_header },
158   { "htmlextension",    &opt.html_extension,    cmd_boolean },
159   { "htmlify",          NULL,                   cmd_spec_htmlify },
160   { "httpkeepalive",    &opt.http_keep_alive,   cmd_boolean },
161   { "httppasswd",       &opt.http_passwd,       cmd_string }, /* deprecated */
162   { "httppassword",     &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_user,          cmd_string },/* deprecated*/
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_boolean },
189   { "passwd",           &opt.ftp_passwd,        cmd_string },/* deprecated*/
190   { "password",         &opt.passwd,            cmd_string },
191   { "postdata",         &opt.post_data,         cmd_string },
192   { "postfile",         &opt.post_file_name,    cmd_file },
193   { "preferfamily",     NULL,                   cmd_spec_prefer_family },
194   { "preservepermissions", &opt.preserve_perm,  cmd_boolean },
195 #ifdef HAVE_SSL
196   { "privatekey",       &opt.private_key,       cmd_file },
197   { "privatekeytype",   &opt.private_key_type,  cmd_cert_type },
198 #endif
199   { "progress",         &opt.progress_type,     cmd_spec_progress },
200   { "protocoldirectories", &opt.protocol_directories, cmd_boolean },
201   { "proxypasswd",      &opt.proxy_passwd,      cmd_string }, /* deprecated */
202   { "proxypassword",    &opt.proxy_passwd,      cmd_string },
203   { "proxyuser",        &opt.proxy_user,        cmd_string },
204   { "quiet",            &opt.quiet,             cmd_boolean },
205   { "quota",            &opt.quota,             cmd_bytes_sum },
206 #ifdef HAVE_SSL
207   { "randomfile",       &opt.random_file,       cmd_file },
208 #endif
209   { "randomwait",       &opt.random_wait,       cmd_boolean },
210   { "readtimeout",      &opt.read_timeout,      cmd_time },
211   { "reclevel",         &opt.reclevel,          cmd_number_inf },
212   { "recursive",        NULL,                   cmd_spec_recursive },
213   { "referer",          &opt.referer,           cmd_string },
214   { "reject",           &opt.rejects,           cmd_vector },
215   { "relativeonly",     &opt.relative_only,     cmd_boolean },
216   { "removelisting",    &opt.remove_listing,    cmd_boolean },
217   { "restrictfilenames", NULL,                  cmd_spec_restrict_file_names },
218   { "retrsymlinks",     &opt.retr_symlinks,     cmd_boolean },
219   { "retryconnrefused", &opt.retry_connrefused, cmd_boolean },
220   { "robots",           &opt.use_robots,        cmd_boolean },
221   { "savecookies",      &opt.cookies_output,    cmd_file },
222   { "saveheaders",      &opt.save_headers,      cmd_boolean },
223 #ifdef HAVE_SSL
224   { "secureprotocol",   &opt.secure_protocol,   cmd_spec_secure_protocol },
225 #endif
226   { "serverresponse",   &opt.server_response,   cmd_boolean },
227   { "spanhosts",        &opt.spanhost,          cmd_boolean },
228   { "spider",           &opt.spider,            cmd_boolean },
229   { "strictcomments",   &opt.strict_comments,   cmd_boolean },
230   { "timeout",          NULL,                   cmd_spec_timeout },
231   { "timestamping",     &opt.timestamping,      cmd_boolean },
232   { "tries",            &opt.ntry,              cmd_number_inf },
233   { "useproxy",         &opt.use_proxy,         cmd_boolean },
234   { "user",             &opt.user,              cmd_string },
235   { "useragent",        NULL,                   cmd_spec_useragent },
236   { "verbose",          NULL,                   cmd_spec_verbose },
237   { "wait",             &opt.wait,              cmd_time },
238   { "waitretry",        &opt.waitretry,         cmd_time }
239 };
240
241 /* Look up CMDNAME in the commands[] and return its position in the
242    array.  If CMDNAME is not found, return -1.  */
243
244 static int
245 command_by_name (const char *cmdname)
246 {
247   /* Use binary search for speed.  Wget has ~100 commands, which
248      guarantees a worst case performance of 7 string comparisons.  */
249   int lo = 0, hi = countof (commands) - 1;
250
251   while (lo <= hi)
252     {
253       int mid = (lo + hi) >> 1;
254       int cmp = strcasecmp (cmdname, commands[mid].name);
255       if (cmp < 0)
256         hi = mid - 1;
257       else if (cmp > 0)
258         lo = mid + 1;
259       else
260         return mid;
261     }
262   return -1;
263 }
264 \f
265 /* Reset the variables to default values.  */
266 static void
267 defaults (void)
268 {
269   char *tmp;
270
271   /* Most of the default values are 0 (and 0.0, NULL, and false).
272      Just reset everything, and fill in the non-zero values.  Note
273      that initializing pointers to NULL this way is technically
274      illegal, but porting Wget to a machine where NULL is not all-zero
275      bit pattern will be the least of the implementors' worries.  */
276   xzero (opt);
277
278   opt.cookies = true;
279   opt.verbose = -1;
280   opt.ntry = 20;
281   opt.reclevel = 5;
282   opt.add_hostdir = true;
283   opt.netrc = true;
284   opt.ftp_glob = true;
285   opt.htmlify = true;
286   opt.http_keep_alive = true;
287   opt.use_proxy = true;
288   tmp = getenv ("no_proxy");
289   if (tmp)
290     opt.no_proxy = sepstring (tmp);
291   opt.allow_cache = true;
292
293   opt.read_timeout = 900;
294   opt.use_robots = true;
295
296   opt.remove_listing = true;
297
298   opt.dot_bytes = 1024;
299   opt.dot_spacing = 10;
300   opt.dots_in_line = 50;
301
302   opt.dns_cache = true;
303   opt.ftp_pasv = true;
304
305 #ifdef HAVE_SSL
306   opt.check_cert = true;
307 #endif
308
309   /* The default for file name restriction defaults to the OS type. */
310 #if !defined(WINDOWS) && !defined(__CYGWIN__)
311   opt.restrict_files_os = restrict_unix;
312 #else
313   opt.restrict_files_os = restrict_windows;
314 #endif
315   opt.restrict_files_ctrl = true;
316 }
317 \f
318 /* Return the user's home directory (strdup-ed), or NULL if none is
319    found.  */
320 char *
321 home_dir (void)
322 {
323   char *home = getenv ("HOME");
324
325   if (!home)
326     {
327 #ifndef WINDOWS
328       /* If HOME is not defined, try getting it from the password
329          file.  */
330       struct passwd *pwd = getpwuid (getuid ());
331       if (!pwd || !pwd->pw_dir)
332         return NULL;
333       home = pwd->pw_dir;
334 #else  /* WINDOWS */
335       /* Under Windows, if $HOME isn't defined, use the directory where
336          `wget.exe' resides.  */
337       home = ws_mypath ();
338 #endif /* WINDOWS */
339     }
340
341   return home ? xstrdup (home) : NULL;
342 }
343
344 /* Return the path to the user's .wgetrc.  This is either the value of
345    `WGETRC' environment variable, or `$HOME/.wgetrc'.
346
347    If the `WGETRC' variable exists but the file does not exist, the
348    function will exit().  */
349 static char *
350 wgetrc_file_name (void)
351 {
352   char *env, *home;
353   char *file = NULL;
354
355   /* Try the environment.  */
356   env = getenv ("WGETRC");
357   if (env && *env)
358     {
359       if (!file_exists_p (env))
360         {
361           fprintf (stderr, _("%s: WGETRC points to %s, which doesn't exist.\n"),
362                    exec_name, env);
363           exit (1);
364         }
365       return xstrdup (env);
366     }
367
368   /* If that failed, try $HOME/.wgetrc.  */
369   home = home_dir ();
370   if (home)
371     file = aprintf ("%s/.wgetrc", home);
372   xfree_null (home);
373
374 #ifdef WINDOWS
375   /* Under Windows, if we still haven't found .wgetrc, look for the file
376      `wget.ini' in the directory where `wget.exe' resides; we do this for
377      backward compatibility with previous versions of Wget.
378      SYSTEM_WGETRC should not be defined under WINDOWS.  */
379   if (!file || !file_exists_p (file))
380     {
381       xfree_null (file);
382       file = NULL;
383       home = ws_mypath ();
384       if (home)
385         file = aprintf ("%s/wget.ini", home);
386     }
387 #endif /* WINDOWS */
388
389   if (!file)
390     return NULL;
391   if (!file_exists_p (file))
392     {
393       xfree (file);
394       return NULL;
395     }
396   return file;
397 }
398
399 /* Return values of parse_line. */
400 enum parse_line {
401   line_ok,
402   line_empty,
403   line_syntax_error,
404   line_unknown_command
405 };
406
407 static enum parse_line parse_line (const char *, char **, char **, int *);
408 static bool setval_internal (int, const char *, const char *);
409
410 /* Initialize variables from a wgetrc file.  Returns zero (failure) if
411    there were errors in the file.  */
412
413 static bool
414 run_wgetrc (const char *file)
415 {
416   FILE *fp;
417   char *line;
418   int ln;
419   int errcnt = 0;
420
421   fp = fopen (file, "rb");
422   if (!fp)
423     {
424       fprintf (stderr, _("%s: Cannot read %s (%s).\n"), exec_name,
425                file, strerror (errno));
426       return true;                      /* not a fatal error */
427     }
428   enable_tilde_expansion = true;
429   ln = 1;
430   while ((line = read_whole_line (fp)) != NULL)
431     {
432       char *com = NULL, *val = NULL;
433       int comind;
434
435       /* Parse the line.  */
436       switch (parse_line (line, &com, &val, &comind))
437         {
438         case line_ok:
439           /* If everything is OK, set the value.  */
440           if (!setval_internal (comind, com, val))
441             {
442               fprintf (stderr, _("%s: Error in %s at line %d.\n"),
443                        exec_name, file, ln);
444               ++errcnt;
445             }
446           break;
447         case line_syntax_error:
448           fprintf (stderr, _("%s: Syntax error in %s at line %d.\n"),
449                    exec_name, file, ln);
450           ++errcnt;
451           break;
452         case line_unknown_command:
453           fprintf (stderr, _("%s: Unknown command `%s' in %s at line %d.\n"),
454                    exec_name, com, file, ln);
455           ++errcnt;
456           break;
457         case line_empty:
458           break;
459         default:
460           abort ();
461         }
462       xfree_null (com);
463       xfree_null (val);
464       xfree (line);
465       ++ln;
466     }
467   enable_tilde_expansion = false;
468   fclose (fp);
469
470   return errcnt == 0;
471 }
472
473 /* Initialize the defaults and run the system wgetrc and user's own
474    wgetrc.  */
475 void
476 initialize (void)
477 {
478   char *file;
479   int ok = true;
480
481   /* Load the hard-coded defaults.  */
482   defaults ();
483
484   /* If SYSTEM_WGETRC is defined, use it.  */
485 #ifdef SYSTEM_WGETRC
486   if (file_exists_p (SYSTEM_WGETRC))
487     ok &= run_wgetrc (SYSTEM_WGETRC);
488 #endif
489   /* Override it with your own, if one exists.  */
490   file = wgetrc_file_name ();
491   if (!file)
492     return;
493   /* #### We should canonicalize `file' and SYSTEM_WGETRC with
494      something like realpath() before comparing them with `strcmp'  */
495 #ifdef SYSTEM_WGETRC
496   if (!strcmp (file, SYSTEM_WGETRC))
497     {
498       fprintf (stderr, _("\
499 %s: Warning: Both system and user wgetrc point to `%s'.\n"),
500                exec_name, file);
501     }
502   else
503 #endif
504     ok &= run_wgetrc (file);
505
506   /* If there were errors processing either `.wgetrc', abort. */
507   if (!ok)
508     exit (2);
509
510   xfree (file);
511   return;
512 }
513 \f
514 /* Remove dashes and underscores from S, modifying S in the
515    process. */
516
517 static void
518 dehyphen (char *s)
519 {
520   char *t = s;                  /* t - tortoise */
521   char *h = s;                  /* h - hare     */
522   while (*h)
523     if (*h == '_' || *h == '-')
524       ++h;
525     else
526       *t++ = *h++;
527   *t = '\0';
528 }
529
530 /* Parse the line pointed by line, with the syntax:
531    <sp>* command <sp>* = <sp>* value <sp>*
532    Uses malloc to allocate space for command and value.
533
534    Returns one of line_ok, line_empty, line_syntax_error, or
535    line_unknown_command.
536
537    In case of line_ok, *COM and *VAL point to freshly allocated
538    strings, and *COMIND points to com's index.  In case of error or
539    empty line, their values are unmodified.  */
540
541 static enum parse_line
542 parse_line (const char *line, char **com, char **val, int *comind)
543 {
544   const char *p;
545   const char *end = line + strlen (line);
546   const char *cmdstart, *cmdend;
547   const char *valstart, *valend;
548
549   char *cmdcopy;
550   int ind;
551
552   /* Skip leading and trailing whitespace.  */
553   while (*line && ISSPACE (*line))
554     ++line;
555   while (end > line && ISSPACE (end[-1]))
556     --end;
557
558   /* Skip empty lines and comments.  */
559   if (!*line || *line == '#')
560     return line_empty;
561
562   p = line;
563
564   cmdstart = p;
565   while (p < end && (ISALNUM (*p) || *p == '_' || *p == '-'))
566     ++p;
567   cmdend = p;
568
569   /* Skip '=', as well as any space before or after it. */
570   while (p < end && ISSPACE (*p))
571     ++p;
572   if (p == end || *p != '=')
573     return line_syntax_error;
574   ++p;
575   while (p < end && ISSPACE (*p))
576     ++p;
577
578   valstart = p;
579   valend   = end;
580
581   /* The syntax is valid (even though the command might not be).  Fill
582      in the command name and value.  */
583   *com = strdupdelim (cmdstart, cmdend);
584   *val = strdupdelim (valstart, valend);
585
586   /* The line now known to be syntactically correct.  Check whether
587      the command is valid.  */
588   BOUNDED_TO_ALLOCA (cmdstart, cmdend, cmdcopy);
589   dehyphen (cmdcopy);
590   ind = command_by_name (cmdcopy);
591   if (ind == -1)
592     return line_unknown_command;
593
594   /* Report success to the caller. */
595   *comind = ind;
596   return line_ok;
597 }
598
599 /* Run commands[comind].action. */
600
601 static bool
602 setval_internal (int comind, const char *com, const char *val)
603 {
604   assert (0 <= comind && comind < countof (commands));
605   DEBUGP (("Setting %s (%s) to %s\n", com, commands[comind].name, val));
606   return commands[comind].action (com, val, commands[comind].place);
607 }
608
609 /* Run command COM with value VAL.  If running the command produces an
610    error, report the error and exit.
611
612    This is intended to be called from main() to modify Wget's behavior
613    through command-line switches.  Since COM is hard-coded in main(),
614    it is not canonicalized, and this aborts when COM is not found.
615
616    If COMIND's are exported to init.h, this function will be changed
617    to accept COMIND directly.  */
618
619 void
620 setoptval (const char *com, const char *val, const char *optname)
621 {
622   /* Prepend "--" to OPTNAME. */
623   char *dd_optname = (char *) alloca (2 + strlen (optname) + 1);
624   dd_optname[0] = '-';
625   dd_optname[1] = '-';
626   strcpy (dd_optname + 2, optname);
627
628   assert (val != NULL);
629   if (!setval_internal (command_by_name (com), dd_optname, val))
630     exit (2);
631 }
632
633 /* Parse OPT into command and value and run it.  For example,
634    run_command("foo=bar") is equivalent to setoptval("foo", "bar").
635    This is used by the `--execute' flag in main.c.  */
636
637 void
638 run_command (const char *opt)
639 {
640   char *com, *val;
641   int comind;
642   switch (parse_line (opt, &com, &val, &comind))
643     {
644     case line_ok:
645       if (!setval_internal (comind, com, val))
646         exit (2);
647       xfree (com);
648       xfree (val);
649       break;
650     default:
651       fprintf (stderr, _("%s: Invalid --execute command `%s'\n"),
652                exec_name, opt);
653       exit (2);
654     }
655 }
656 \f
657 /* Generic helper functions, for use with `commands'. */
658
659 /* Forward declarations: */
660 struct decode_item {
661   const char *name;
662   int code;
663 };
664 static bool decode_string (const char *, const struct decode_item *, int, int *);
665 static bool simple_atoi (const char *, const char *, int *);
666 static bool simple_atof (const char *, const char *, double *);
667
668 #define CMP1(p, c0) (TOLOWER((p)[0]) == (c0) && (p)[1] == '\0')
669
670 #define CMP2(p, c0, c1) (TOLOWER((p)[0]) == (c0)        \
671                          && TOLOWER((p)[1]) == (c1)     \
672                          && (p)[2] == '\0')
673
674 #define CMP3(p, c0, c1, c2) (TOLOWER((p)[0]) == (c0)    \
675                      && TOLOWER((p)[1]) == (c1)         \
676                      && TOLOWER((p)[2]) == (c2)         \
677                      && (p)[3] == '\0')
678
679
680 /* Store the boolean value from VAL to PLACE.  COM is ignored,
681    except for error messages.  */
682 static bool
683 cmd_boolean (const char *com, const char *val, void *place)
684 {
685   bool value;
686
687   if (CMP2 (val, 'o', 'n') || CMP3 (val, 'y', 'e', 's') || CMP1 (val, '1'))
688     /* "on", "yes" and "1" mean true. */
689     value = true;
690   else if (CMP3 (val, 'o', 'f', 'f') || CMP2 (val, 'n', 'o') || CMP1 (val, '0'))
691     /* "off", "no" and "0" mean false. */
692     value = false;
693   else
694     {
695       fprintf (stderr,
696                _("%s: %s: Invalid boolean `%s'; use `on' or `off'.\n"),
697                exec_name, com, val);
698       return false;
699     }
700
701   *(bool *) place = value;
702   return true;
703 }
704
705 /* Set the non-negative integer value from VAL to PLACE.  With
706    incorrect specification, the number remains unchanged.  */
707 static bool
708 cmd_number (const char *com, const char *val, void *place)
709 {
710   if (!simple_atoi (val, val + strlen (val), place)
711       || *(int *) place < 0)
712     {
713       fprintf (stderr, _("%s: %s: Invalid number `%s'.\n"),
714                exec_name, com, val);
715       return false;
716     }
717   return true;
718 }
719
720 /* Similar to cmd_number(), only accepts `inf' as a synonym for 0.  */
721 static bool
722 cmd_number_inf (const char *com, const char *val, void *place)
723 {
724   if (!strcasecmp (val, "inf"))
725     {
726       *(int *) place = 0;
727       return true;
728     }
729   return cmd_number (com, val, place);
730 }
731
732 /* Copy (strdup) the string at COM to a new location and place a
733    pointer to *PLACE.  */
734 static bool
735 cmd_string (const char *com, const char *val, void *place)
736 {
737   char **pstring = (char **)place;
738
739   xfree_null (*pstring);
740   *pstring = xstrdup (val);
741   return true;
742 }
743
744 #ifndef WINDOWS
745 # define ISSEP(c) ((c) == '/')
746 #else
747 # define ISSEP(c) ((c) == '/' || (c) == '\\')
748 #endif
749
750 /* Like the above, but handles tilde-expansion when reading a user's
751    `.wgetrc'.  In that case, and if VAL begins with `~', the tilde
752    gets expanded to the user's home directory.  */
753 static bool
754 cmd_file (const char *com, const char *val, void *place)
755 {
756   char **pstring = (char **)place;
757
758   xfree_null (*pstring);
759
760   /* #### If VAL is empty, perhaps should set *PLACE to NULL.  */
761
762   if (!enable_tilde_expansion || !(*val == '~' && ISSEP (val[1])))
763     {
764     noexpand:
765       *pstring = xstrdup (val);
766     }
767   else
768     {
769       int homelen;
770       char *home = home_dir ();
771       if (!home)
772         goto noexpand;
773
774       homelen = strlen (home);
775       while (homelen && ISSEP (home[homelen - 1]))
776         home[--homelen] = '\0';
777
778       /* Skip the leading "~/". */
779       for (++val; ISSEP (*val); val++)
780         ;
781
782       *pstring = concat_strings (home, "/", val, (char *) 0);
783     }
784
785 #ifdef WINDOWS
786   /* Convert "\" to "/". */
787   {
788     char *s;
789     for (s = *pstring; *s; s++)
790       if (*s == '\\')
791         *s = '/';
792   }
793 #endif
794   return true;
795 }
796
797 /* Like cmd_file, but strips trailing '/' characters.  */
798 static bool
799 cmd_directory (const char *com, const char *val, void *place)
800 {
801   char *s, *t;
802
803   /* Call cmd_file() for tilde expansion and separator
804      canonicalization (backslash -> slash under Windows).  These
805      things should perhaps be in a separate function.  */
806   if (!cmd_file (com, val, place))
807     return false;
808
809   s = *(char **)place;
810   t = s + strlen (s);
811   while (t > s && *--t == '/')
812     *t = '\0';
813
814   return true;
815 }
816
817 /* Split VAL by space to a vector of values, and append those values
818    to vector pointed to by the PLACE argument.  If VAL is empty, the
819    PLACE vector is cleared instead.  */
820
821 static bool
822 cmd_vector (const char *com, const char *val, void *place)
823 {
824   char ***pvec = (char ***)place;
825
826   if (*val)
827     *pvec = merge_vecs (*pvec, sepstring (val));
828   else
829     {
830       free_vec (*pvec);
831       *pvec = NULL;
832     }
833   return true;
834 }
835
836 static bool
837 cmd_directory_vector (const char *com, const char *val, void *place)
838 {
839   char ***pvec = (char ***)place;
840
841   if (*val)
842     {
843       /* Strip the trailing slashes from directories.  */
844       char **t, **seps;
845
846       seps = sepstring (val);
847       for (t = seps; t && *t; t++)
848         {
849           int len = strlen (*t);
850           /* Skip degenerate case of root directory.  */
851           if (len > 1)
852             {
853               if ((*t)[len - 1] == '/')
854                 (*t)[len - 1] = '\0';
855             }
856         }
857       *pvec = merge_vecs (*pvec, seps);
858     }
859   else
860     {
861       free_vec (*pvec);
862       *pvec = NULL;
863     }
864   return true;
865 }
866
867 /* Engine for cmd_bytes and cmd_bytes_sum: converts a string such as
868    "100k" or "2.5G" to a floating point number.  */
869
870 static bool
871 parse_bytes_helper (const char *val, double *result)
872 {
873   double number, mult;
874   const char *end = val + strlen (val);
875
876   /* Check for "inf".  */
877   if (0 == strcmp (val, "inf"))
878     {
879       *result = 0;
880       return true;
881     }
882
883   /* Strip trailing whitespace.  */
884   while (val < end && ISSPACE (end[-1]))
885     --end;
886   if (val == end)
887     return false;
888
889   switch (TOLOWER (end[-1]))
890     {
891     case 'k':
892       --end, mult = 1024.0;
893       break;
894     case 'm':
895       --end, mult = 1048576.0;
896       break;
897     case 'g':
898       --end, mult = 1073741824.0;
899       break;
900     case 't':
901       --end, mult = 1099511627776.0;
902       break;
903     default:
904       /* Not a recognized suffix: assume it's a digit.  (If not,
905          simple_atof will raise an error.)  */
906       mult = 1;
907     }
908
909   /* Skip leading and trailing whitespace. */
910   while (val < end && ISSPACE (*val))
911     ++val;
912   while (val < end && ISSPACE (end[-1]))
913     --end;
914   if (val == end)
915     return false;
916
917   if (!simple_atof (val, end, &number) || number < 0)
918     return false;
919
920   *result = number * mult;
921   return true;
922 }
923
924 /* Parse VAL as a number and set its value to PLACE (which should
925    point to a wgint).
926
927    By default, the value is assumed to be in bytes.  If "K", "M", or
928    "G" are appended, the value is multiplied with 1<<10, 1<<20, or
929    1<<30, respectively.  Floating point values are allowed and are
930    cast to integer before use.  The idea is to be able to use things
931    like 1.5k instead of "1536".
932
933    The string "inf" is returned as 0.
934
935    In case of error, false is returned and memory pointed to by PLACE
936    remains unmodified.  */
937
938 static bool
939 cmd_bytes (const char *com, const char *val, void *place)
940 {
941   double byte_value;
942   if (!parse_bytes_helper (val, &byte_value))
943     {
944       fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"),
945                exec_name, com, val);
946       return false;
947     }
948   *(wgint *)place = (wgint)byte_value;
949   return true;
950 }
951
952 /* Like cmd_bytes, but PLACE is interpreted as a pointer to
953    SIZE_SUM.  It works by converting the string to double, therefore
954    working with values up to 2^53-1 without loss of precision.  This
955    value (8192 TB) is large enough to serve for a while.  */
956
957 static bool
958 cmd_bytes_sum (const char *com, const char *val, void *place)
959 {
960   double byte_value;
961   if (!parse_bytes_helper (val, &byte_value))
962     {
963       fprintf (stderr, _("%s: %s: Invalid byte value `%s'\n"),
964                exec_name, com, val);
965       return false;
966     }
967   *(SUM_SIZE_INT *) place = (SUM_SIZE_INT) byte_value;
968   return true;
969 }
970
971 /* Store the value of VAL to *OUT.  The value is a time period, by
972    default expressed in seconds, but also accepting suffixes "m", "h",
973    "d", and "w" for minutes, hours, days, and weeks respectively.  */
974
975 static bool
976 cmd_time (const char *com, const char *val, void *place)
977 {
978   double number, mult;
979   const char *end = val + strlen (val);
980
981   /* Strip trailing whitespace.  */
982   while (val < end && ISSPACE (end[-1]))
983     --end;
984
985   if (val == end)
986     {
987     err:
988       fprintf (stderr, _("%s: %s: Invalid time period `%s'\n"),
989                exec_name, com, val);
990       return false;
991     }
992
993   switch (TOLOWER (end[-1]))
994     {
995     case 's':
996       --end, mult = 1;          /* seconds */
997       break;
998     case 'm':
999       --end, mult = 60;         /* minutes */
1000       break;
1001     case 'h':
1002       --end, mult = 3600;       /* hours */
1003       break;
1004     case 'd':
1005       --end, mult = 86400.0;    /* days */
1006       break;
1007     case 'w':
1008       --end, mult = 604800.0;   /* weeks */
1009       break;
1010     default:
1011       /* Not a recognized suffix: assume it belongs to the number.
1012          (If not, simple_atof will raise an error.)  */
1013       mult = 1;
1014     }
1015
1016   /* Skip leading and trailing whitespace. */
1017   while (val < end && ISSPACE (*val))
1018     ++val;
1019   while (val < end && ISSPACE (end[-1]))
1020     --end;
1021   if (val == end)
1022     goto err;
1023
1024   if (!simple_atof (val, end, &number))
1025     goto err;
1026
1027   *(double *)place = number * mult;
1028   return true;
1029 }
1030
1031 #ifdef HAVE_SSL
1032 static bool
1033 cmd_cert_type (const char *com, const char *val, void *place)
1034 {
1035   static const struct decode_item choices[] = {
1036     { "pem", keyfile_pem },
1037     { "der", keyfile_asn1 },
1038     { "asn1", keyfile_asn1 },
1039   };
1040   int ok = decode_string (val, choices, countof (choices), place);
1041   if (!ok)
1042     fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
1043   return ok;
1044 }
1045 #endif
1046 \f
1047 /* Specialized helper functions, used by `commands' to handle some
1048    options specially.  */
1049
1050 static bool check_user_specified_header (const char *);
1051
1052 static bool
1053 cmd_spec_dirstruct (const char *com, const char *val, void *place_ignored)
1054 {
1055   if (!cmd_boolean (com, val, &opt.dirstruct))
1056     return false;
1057   /* Since dirstruct behaviour is explicitly changed, no_dirstruct
1058      must be affected inversely.  */
1059   if (opt.dirstruct)
1060     opt.no_dirstruct = false;
1061   else
1062     opt.no_dirstruct = true;
1063   return true;
1064 }
1065
1066 static bool
1067 cmd_spec_header (const char *com, const char *val, void *place_ignored)
1068 {
1069   /* Empty value means reset the list of headers. */
1070   if (*val == '\0')
1071     {
1072       free_vec (opt.user_headers);
1073       opt.user_headers = NULL;
1074       return true;
1075     }
1076
1077   if (!check_user_specified_header (val))
1078     {
1079       fprintf (stderr, _("%s: %s: Invalid header `%s'.\n"),
1080                exec_name, com, val);
1081       return false;
1082     }
1083   opt.user_headers = vec_append (opt.user_headers, val);
1084   return true;
1085 }
1086
1087 static bool
1088 cmd_spec_htmlify (const char *com, const char *val, void *place_ignored)
1089 {
1090   int flag = cmd_boolean (com, val, &opt.htmlify);
1091   if (flag && !opt.htmlify)
1092     opt.remove_listing = false;
1093   return flag;
1094 }
1095
1096 /* Set the "mirror" mode.  It means: recursive download, timestamping,
1097    no limit on max. recursion depth, and don't remove listings.  */
1098
1099 static bool
1100 cmd_spec_mirror (const char *com, const char *val, void *place_ignored)
1101 {
1102   int mirror;
1103
1104   if (!cmd_boolean (com, val, &mirror))
1105     return false;
1106   if (mirror)
1107     {
1108       opt.recursive = true;
1109       if (!opt.no_dirstruct)
1110         opt.dirstruct = true;
1111       opt.timestamping = true;
1112       opt.reclevel = INFINITE_RECURSION;
1113       opt.remove_listing = false;
1114     }
1115   return true;
1116 }
1117
1118 /* Validate --prefer-family and set the choice.  Allowed values are
1119    "IPv4", "IPv6", and "none".  */
1120
1121 static bool
1122 cmd_spec_prefer_family (const char *com, const char *val, void *place_ignored)
1123 {
1124   static const struct decode_item choices[] = {
1125     { "IPv4", prefer_ipv4 },
1126     { "IPv6", prefer_ipv6 },
1127     { "none", prefer_none },
1128   };
1129   int ok = decode_string (val, choices, countof (choices),
1130                           (int *) &opt.prefer_family);
1131   if (!ok)
1132     fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
1133   return ok;
1134 }
1135
1136 /* Set progress.type to VAL, but verify that it's a valid progress
1137    implementation before that.  */
1138
1139 static bool
1140 cmd_spec_progress (const char *com, const char *val, void *place_ignored)
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 false;
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 true;
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 true, unless opt.no_dirstruct
1158    is specified.  */
1159
1160 static bool
1161 cmd_spec_recursive (const char *com, const char *val, void *place_ignored)
1162 {
1163   if (!cmd_boolean (com, val, &opt.recursive))
1164     return false;
1165   else
1166     {
1167       if (opt.recursive && !opt.no_dirstruct)
1168         opt.dirstruct = true;
1169     }
1170   return true;
1171 }
1172
1173 static bool
1174 cmd_spec_restrict_file_names (const char *com, const char *val, void *place_ignored)
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 false;
1198     }
1199
1200 #undef VAL_IS
1201
1202   if (*end)
1203     {
1204       if (!strcmp (end + 1, "nocontrol"))
1205         restrict_ctrl = false;
1206       else
1207         goto err;
1208     }
1209
1210   opt.restrict_files_os = restrict_os;
1211   opt.restrict_files_ctrl = restrict_ctrl;
1212   return true;
1213 }
1214
1215 #ifdef HAVE_SSL
1216 static bool
1217 cmd_spec_secure_protocol (const char *com, const char *val, void *place)
1218 {
1219   static const struct decode_item choices[] = {
1220     { "auto", secure_protocol_auto },
1221     { "sslv2", secure_protocol_sslv2 },
1222     { "sslv3", secure_protocol_sslv3 },
1223     { "tlsv1", secure_protocol_tlsv1 },
1224   };
1225   int ok = decode_string (val, choices, countof (choices), place);
1226   if (!ok)
1227     fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"), exec_name, com, val);
1228   return ok;
1229 }
1230 #endif
1231
1232 /* Set all three timeout values. */
1233
1234 static bool
1235 cmd_spec_timeout (const char *com, const char *val, void *place_ignored)
1236 {
1237   double value;
1238   if (!cmd_time (com, val, &value))
1239     return false;
1240   opt.read_timeout = value;
1241   opt.connect_timeout = value;
1242   opt.dns_timeout = value;
1243   return true;
1244 }
1245
1246 static bool
1247 cmd_spec_useragent (const char *com, const char *val, void *place_ignored)
1248 {
1249   /* Disallow embedded newlines.  */
1250   if (strchr (val, '\n'))
1251     {
1252       fprintf (stderr, _("%s: %s: Invalid value `%s'.\n"),
1253                exec_name, com, val);
1254       return false;
1255     }
1256   xfree_null (opt.useragent);
1257   opt.useragent = xstrdup (val);
1258   return true;
1259 }
1260
1261 /* The "verbose" option cannot be cmd_boolean because the variable is
1262    not bool -- it's of type int (-1 means uninitialized because of
1263    some random hackery for disallowing -q -v).  */
1264
1265 static bool
1266 cmd_spec_verbose (const char *com, const char *val, void *place_ignored)
1267 {
1268   bool flag;
1269   if (cmd_boolean (com, val, &flag))
1270     {
1271       opt.verbose = flag;
1272       return true;
1273     }
1274   return false;
1275 }
1276 \f
1277 /* Miscellaneous useful routines.  */
1278
1279 /* A very simple atoi clone, more useful than atoi because it works on
1280    delimited strings, and has error reportage.  Returns true on success,
1281    false on failure.  If successful, stores result to *DEST.  */
1282
1283 static bool
1284 simple_atoi (const char *beg, const char *end, int *dest)
1285 {
1286   int result = 0;
1287   bool negative = false;
1288   const char *p = beg;
1289
1290   while (p < end && ISSPACE (*p))
1291     ++p;
1292   if (p < end && (*p == '-' || *p == '+'))
1293     {
1294       negative = (*p == '-');
1295       ++p;
1296     }
1297   if (p == end)
1298     return false;
1299
1300   /* Read negative numbers in a separate loop because the most
1301      negative integer cannot be represented as a positive number.  */
1302
1303   if (!negative)
1304     for (; p < end && ISDIGIT (*p); p++)
1305       {
1306         int next = (10 * result) + (*p - '0');
1307         if (next < result)
1308           return false;         /* overflow */
1309         result = next;
1310       }
1311   else
1312     for (; p < end && ISDIGIT (*p); p++)
1313       {
1314         int next = (10 * result) - (*p - '0');
1315         if (next > result)
1316           return false;         /* underflow */
1317         result = next;
1318       }
1319
1320   if (p != end)
1321     return false;
1322
1323   *dest = result;
1324   return true;
1325 }
1326
1327 /* Trivial atof, with error reporting.  Handles "<digits>[.<digits>]",
1328    doesn't handle exponential notation.  Returns true on success,
1329    false on failure.  In case of success, stores its result to
1330    *DEST.  */
1331
1332 static bool
1333 simple_atof (const char *beg, const char *end, double *dest)
1334 {
1335   double result = 0;
1336
1337   bool negative = false;
1338   bool seen_dot = false;
1339   bool seen_digit = false;
1340   double divider = 1;
1341
1342   const char *p = beg;
1343
1344   while (p < end && ISSPACE (*p))
1345     ++p;
1346   if (p < end && (*p == '-' || *p == '+'))
1347     {
1348       negative = (*p == '-');
1349       ++p;
1350     }
1351
1352   for (; p < end; p++)
1353     {
1354       char ch = *p;
1355       if (ISDIGIT (ch))
1356         {
1357           if (!seen_dot)
1358             result = (10 * result) + (ch - '0');
1359           else
1360             result += (ch - '0') / (divider *= 10);
1361           seen_digit = true;
1362         }
1363       else if (ch == '.')
1364         {
1365           if (!seen_dot)
1366             seen_dot = true;
1367           else
1368             return false;
1369         }
1370       else
1371         return false;
1372     }
1373   if (!seen_digit)
1374     return false;
1375   if (negative)
1376     result = -result;
1377
1378   *dest = result;
1379   return true;
1380 }
1381
1382 /* Verify that the user-specified header in S is valid.  It must
1383    contain a colon preceded by non-white-space characters and must not
1384    contain newlines.  */
1385
1386 static bool
1387 check_user_specified_header (const char *s)
1388 {
1389   const char *p;
1390
1391   for (p = s; *p && *p != ':' && !ISSPACE (*p); p++);
1392   /* The header MUST contain `:' preceded by at least one
1393      non-whitespace character.  */
1394   if (*p != ':' || p == s)
1395     return false;
1396   /* The header MUST NOT contain newlines.  */
1397   if (strchr (s, '\n'))
1398     return false;
1399   return true;
1400 }
1401
1402 /* Decode VAL into a number, according to ITEMS. */
1403
1404 static bool
1405 decode_string (const char *val, const struct decode_item *items, int itemcount,
1406                int *place)
1407 {
1408   int i;
1409   for (i = 0; i < itemcount; i++)
1410     if (0 == strcasecmp (val, items[i].name))
1411       {
1412         *place = items[i].code;
1413         return true;
1414       }
1415   return false;
1416 }
1417
1418 \f
1419 void cleanup_html_url (void);
1420
1421
1422 /* Free the memory allocated by global variables.  */
1423 void
1424 cleanup (void)
1425 {
1426   /* Free external resources, close files, etc. */
1427
1428   if (output_stream)
1429     fclose (output_stream);
1430   /* No need to check for error because Wget flushes its output (and
1431      checks for errors) after any data arrives.  */
1432
1433   /* We're exiting anyway so there's no real need to call free()
1434      hundreds of times.  Skipping the frees will make Wget exit
1435      faster.
1436
1437      However, when detecting leaks, it's crucial to free() everything
1438      because then you can find the real leaks, i.e. the allocated
1439      memory which grows with the size of the program.  */
1440
1441 #ifdef DEBUG_MALLOC
1442   convert_cleanup ();
1443   res_cleanup ();
1444   http_cleanup ();
1445   cleanup_html_url ();
1446   host_cleanup ();
1447   log_cleanup ();
1448
1449   {
1450     extern acc_t *netrc_list;
1451     free_netrc (netrc_list);
1452   }
1453   xfree_null (opt.lfilename);
1454   xfree_null (opt.dir_prefix);
1455   xfree_null (opt.input_filename);
1456   xfree_null (opt.output_document);
1457   free_vec (opt.accepts);
1458   free_vec (opt.rejects);
1459   free_vec (opt.excludes);
1460   free_vec (opt.includes);
1461   free_vec (opt.domains);
1462   free_vec (opt.follow_tags);
1463   free_vec (opt.ignore_tags);
1464   xfree_null (opt.progress_type);
1465   xfree_null (opt.ftp_user);
1466   xfree_null (opt.ftp_passwd);
1467   xfree_null (opt.ftp_proxy);
1468   xfree_null (opt.https_proxy);
1469   xfree_null (opt.http_proxy);
1470   free_vec (opt.no_proxy);
1471   xfree_null (opt.useragent);
1472   xfree_null (opt.referer);
1473   xfree_null (opt.http_user);
1474   xfree_null (opt.http_passwd);
1475   free_vec (opt.user_headers);
1476 # ifdef HAVE_SSL
1477   xfree_null (opt.cert_file);
1478   xfree_null (opt.private_key);
1479   xfree_null (opt.ca_directory);
1480   xfree_null (opt.ca_cert);
1481   xfree_null (opt.random_file);
1482   xfree_null (opt.egd_file);
1483 # endif
1484   xfree_null (opt.bind_address);
1485   xfree_null (opt.cookies_input);
1486   xfree_null (opt.cookies_output);
1487   xfree_null (opt.user);
1488   xfree_null (opt.passwd);
1489 #endif /* DEBUG_MALLOC */
1490 }