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