~ubuntu-branches/ubuntu/trusty/wget/trusty-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-05-17 19:46:25 UTC
  • mfrom: (2.1.10 sid)
  • Revision ID: james.westby@ubuntu.com-20110517194625-awyf9lkvyohk71ni
Tags: 1.12-3.1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add wget-udeb to ship wget.gnu as alternative to busybox wget
    implementation.
  - Keep build dependencies in main:
    + debian/control: remove info2man build-dep
    + debian/patches/series: disable wget-infopod_generated_manpage
  - Depend on libssl-dev 0.9.8k-7ubuntu4 (LP: #503339)
  - Mark wget Multi-Arch: foreign, so packages that aren't of the same arch
    can depend on it.

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