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