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