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

« back to all changes in this revision

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