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