~ubuntu-branches/ubuntu/precise/wget/precise-proposed

« back to all changes in this revision

Viewing changes to .pc/CVE-2010-2252/src/init.c

  • Committer: Bazaar Package Importer
  • Author(s): Steve Langasek
  • Date: 2011-10-19 00:00:09 UTC
  • mfrom: (2.1.13 sid)
  • Revision ID: james.westby@ubuntu.com-20111019000009-8p33w3wz4b1rdri0
Tags: 1.13-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add wget-udeb to ship wget.gnu as alternative to busybox wget
    implementation.
  - Depend on libssl-dev 0.9.8k-7ubuntu4 (LP: #503339)
* Dropped changes, superseded in Debian:
  - Keep build dependencies in main:
    + debian/control: remove info2man build-dep
    + debian/patches/series: disable wget-infopod_generated_manpage
  - Mark wget Multi-Arch: foreign, so packages that aren't of the same arch
    can depend on it.
* Pass --with-ssl=openssl; we don't want to use gnutls, there's no udeb for
  it.
* Add a second build pass for the udeb, so we can build without libidn.

Show diffs side-by-side

added added

removed removed

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