Add:
[privoxy.git] / loadcfg.c
1 const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.48.2.4 2003/04/11 12:06:14 oes Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/Attic/loadcfg.c,v $
5  *
6  * Purpose     :  Loads settings from the configuration file into
7  *                global variables.  This file contains both the
8  *                routine to load the configuration and the global
9  *                variables it writes to.
10  *
11  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
12  *                Privoxy team. http://www.privoxy.org/
13  *
14  *                Based on the Internet Junkbuster originally written
15  *                by and Copyright (C) 1997 Anonymous Coders and
16  *                Junkbusters Corporation.  http://www.junkbusters.com
17  *
18  *                This program is free software; you can redistribute it
19  *                and/or modify it under the terms of the GNU General
20  *                Public License as published by the Free Software
21  *                Foundation; either version 2 of the License, or (at
22  *                your option) any later version.
23  *
24  *                This program is distributed in the hope that it will
25  *                be useful, but WITHOUT ANY WARRANTY; without even the
26  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
27  *                PARTICULAR PURPOSE.  See the GNU General Public
28  *                License for more details.
29  *
30  *                The GNU General Public License should be included with
31  *                this file.  If not, you can view it at
32  *                http://www.gnu.org/copyleft/gpl.html
33  *                or write to the Free Software Foundation, Inc., 59
34  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  *
36  * Revisions   :
37  *    $Log: loadcfg.c,v $
38  *    Revision 1.48.2.4  2003/04/11 12:06:14  oes
39  *    Addressed bug #719435
40  *     - Extraneous filterfile directives now logged as errors
41  *     - This and unrecnonised directives now really obvious on status page
42  *
43  *    Revision 1.48.2.3  2003/03/11 11:53:59  oes
44  *    Cosmetic: Renamed cryptic variable
45  *
46  *    Revision 1.48.2.2  2002/11/12 16:28:20  oes
47  *    Move unrelated variable declaration out of #ifdef FEATURE_ACL; fixes bug #636655
48  *
49  *    Revision 1.48.2.1  2002/08/21 17:58:05  oes
50  *    Temp kludge to let user and default action file be edited through win32 GUI (FR 592080)
51  *
52  *    Revision 1.48  2002/05/14 21:30:38  oes
53  *    savearg now uses own linking code instead of (now special-cased) add_help_link
54  *
55  *    Revision 1.47  2002/05/12 21:36:29  jongfoster
56  *    Correcting function comments
57  *
58  *    Revision 1.46  2002/04/26 12:55:14  oes
59  *     - New option "user-manual", defaults to our site
60  *       via project.h #define
61  *     - savearg now embeds option names in help links
62  *
63  *    Revision 1.45  2002/04/24 02:11:54  oes
64  *    Jon's multiple AF patch: Allow up to MAX_ACTION_FILES actionsfile options
65  *
66  *    Revision 1.44  2002/04/08 20:37:13  swa
67  *    fixed JB spelling
68  *
69  *    Revision 1.43  2002/04/08 20:36:50  swa
70  *    fixed JB spelling
71  *
72  *    Revision 1.42  2002/04/05 15:50:15  oes
73  *    fix for invalid HTML proxy_args
74  *
75  *    Revision 1.41  2002/03/31 17:19:00  jongfoster
76  *    Win32 only: Enabling STRICT to fix a VC++ compile warning.
77  *
78  *    Revision 1.40  2002/03/26 22:29:55  swa
79  *    we have a new homepage!
80  *
81  *    Revision 1.39  2002/03/24 13:25:43  swa
82  *    name change related issues
83  *
84  *    Revision 1.38  2002/03/24 13:05:48  jongfoster
85  *    Renaming re_filterfile to filterfile
86  *
87  *    Revision 1.37  2002/03/16 23:54:06  jongfoster
88  *    Adding graceful termination feature, to help look for memory leaks.
89  *    If you enable this (which, by design, has to be done by hand
90  *    editing config.h) and then go to http://i.j.b/die, then the program
91  *    will exit cleanly after the *next* request.  It should free all the
92  *    memory that was used.
93  *
94  *    Revision 1.36  2002/03/13 00:27:05  jongfoster
95  *    Killing warnings
96  *
97  *    Revision 1.35  2002/03/07 03:52:44  oes
98  *    Set logging to tty for --no-daemon mode
99  *
100  *    Revision 1.34  2002/03/06 23:14:35  jongfoster
101  *    Trivial cosmetic changes to make function comments easier to find.
102  *
103  *    Revision 1.33  2002/03/05 04:52:42  oes
104  *    Deleted non-errlog debugging code
105  *
106  *    Revision 1.32  2002/03/04 18:24:53  oes
107  *    Re-enabled output of unknown config directive hash
108  *
109  *    Revision 1.31  2002/03/03 15:07:20  oes
110  *    Re-enabled automatic config reloading
111  *
112  *    Revision 1.30  2002/01/22 23:31:43  jongfoster
113  *    Replacing strsav() with string_append()
114  *
115  *    Revision 1.29  2002/01/17 21:02:30  jongfoster
116  *    Moving all our URL and URL pattern parsing code to urlmatch.c.
117  *
118  *    Renaming free_url to free_url_spec, since it frees a struct url_spec.
119  *
120  *    Revision 1.28  2001/12/30 14:07:32  steudten
121  *    - Add signal handling (unix)
122  *    - Add SIGHUP handler (unix)
123  *    - Add creation of pidfile (unix)
124  *    - Add action 'top' in rc file (RH)
125  *    - Add entry 'SIGNALS' to manpage
126  *    - Add exit message to logfile (unix)
127  *
128  *    Revision 1.27  2001/11/07 00:02:13  steudten
129  *    Add line number in error output for lineparsing for
130  *    actionsfile and configfile.
131  *    Special handling for CLF added.
132  *
133  *    Revision 1.26  2001/11/05 21:41:43  steudten
134  *    Add changes to be a real daemon just for unix os.
135  *    (change cwd to /, detach from controlling tty, set
136  *    process group and session leader to the own process.
137  *    Add DBG() Macro.
138  *    Add some fatal-error log message for failed malloc().
139  *    Add '-d' if compiled with 'configure --with-debug' to
140  *    enable debug output.
141  *
142  *    Revision 1.25  2001/10/25 03:40:48  david__schmidt
143  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
144  *    threads to call select() simultaneously.  So, it's time to do a real, live,
145  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
146  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
147  *
148  *    Revision 1.24  2001/10/23 21:40:30  jongfoster
149  *    Added support for enable-edit-actions and enable-remote-toggle config
150  *    file options.
151  *
152  *    Revision 1.23  2001/10/07 15:36:00  oes
153  *    Introduced new config option "buffer-limit"
154  *
155  *    Revision 1.22  2001/09/22 16:36:59  jongfoster
156  *    Removing unused parameter fs from read_config_line()
157  *
158  *    Revision 1.21  2001/09/16 17:10:43  jongfoster
159  *    Moving function savearg() here, since it was the only thing left in
160  *    showargs.c.
161  *
162  *    Revision 1.20  2001/07/30 22:08:36  jongfoster
163  *    Tidying up #defines:
164  *    - All feature #defines are now of the form FEATURE_xxx
165  *    - Permanently turned off WIN_GUI_EDIT
166  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
167  *
168  *    Revision 1.19  2001/07/15 17:45:16  jongfoster
169  *    Removing some unused #includes
170  *
171  *    Revision 1.18  2001/07/13 14:01:14  oes
172  *     - Removed all #ifdef PCRS
173  *     - Removed vim-settings
174  *
175  *    Revision 1.17  2001/06/29 13:31:03  oes
176  *    - Improved comments
177  *    - Fixed (actionsfile) and sorted hashes
178  *    - Introduced admin_address and proxy-info-url
179  *      as config parameters
180  *    - Renamed config->proxy_args_invocation (which didn't have
181  *      the invocation but the options!) to config->proxy_args
182  *    - Various adaptions
183  *    - Removed logentry from cancelled commit
184  *
185  *    Revision 1.16  2001/06/09 10:55:28  jongfoster
186  *    Changing BUFSIZ ==> BUFFER_SIZE
187  *
188  *    Revision 1.15  2001/06/07 23:13:40  jongfoster
189  *    Merging ACL and forward files into config file.
190  *    Cosmetic: Sorting config file options alphabetically.
191  *    Cosmetic: Adding brief syntax comments to config file options.
192  *
193  *    Revision 1.14  2001/06/07 14:46:25  joergs
194  *    Missing make_path() added for re_filterfile.
195  *
196  *    Revision 1.13  2001/06/05 22:33:54  jongfoster
197  *
198  *    Fixed minor memory leak.
199  *    Also now uses make_path to prepend the pathnames.
200  *
201  *    Revision 1.12  2001/06/05 20:04:09  jongfoster
202  *    Now uses _snprintf() in place of snprintf() under Win32.
203  *
204  *    Revision 1.11  2001/06/04 18:31:58  swa
205  *    files are now prefixed with either `confdir' or `logdir'.
206  *    `make redhat-dist' replaces both entries confdir and logdir
207  *    with redhat values
208  *
209  *    Revision 1.10  2001/06/03 19:11:54  oes
210  *    introduced confdir option
211  *
212  *    Revision 1.9  2001/06/01 20:06:24  jongfoster
213  *    Removed support for "tinygif" option - moved to actions file.
214  *
215  *    Revision 1.8  2001/05/31 21:27:13  jongfoster
216  *    Removed many options from the config file and into the
217  *    "actions" file: add_forwarded, suppress_vanilla_wafer,
218  *    wafer, add_header, user_agent, referer, from
219  *    Also globally replaced "permission" with "action".
220  *
221  *    Revision 1.7  2001/05/29 09:50:24  jongfoster
222  *    Unified blocklist/imagelist/permissionslist.
223  *    File format is still under discussion, but the internal changes
224  *    are (mostly) done.
225  *
226  *    Also modified interceptor behaviour:
227  *    - We now intercept all URLs beginning with one of the following
228  *      prefixes (and *only* these prefixes):
229  *        * http://i.j.b/
230  *        * http://ijbswa.sf.net/config/
231  *        * http://ijbswa.sourceforge.net/config/
232  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
233  *    - Internal changes so that intercepted and fast redirect pages
234  *      are not replaced with an image.
235  *    - Interceptors now have the option to send a binary page direct
236  *      to the client. (i.e. ijb-send-banner uses this)
237  *    - Implemented show-url-info interceptor.  (Which is why I needed
238  *      the above interceptors changes - a typical URL is
239  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
240  *      The previous mechanism would not have intercepted that, and
241  *      if it had been intercepted then it then it would have replaced
242  *      it with an image.)
243  *
244  *    Revision 1.6  2001/05/26 00:28:36  jongfoster
245  *    Automatic reloading of config file.
246  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
247  *    Most of the global variables have been moved to a new
248  *    struct configuration_spec, accessed through csp->config->globalname
249  *    Most of the globals remaining are used by the Win32 GUI.
250  *
251  *    Revision 1.5  2001/05/25 22:34:30  jongfoster
252  *    Hard tabs->Spaces
253  *
254  *    Revision 1.4  2001/05/22 18:46:04  oes
255  *
256  *    - Enabled filtering banners by size rather than URL
257  *      by adding patterns that replace all standard banner
258  *      sizes with the "Junkbuster" gif to the re_filterfile
259  *
260  *    - Enabled filtering WebBugs by providing a pattern
261  *      which kills all 1x1 images
262  *
263  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
264  *      which is selected by the (nonstandard and therefore
265  *      capital) letter 'U' in the option string.
266  *      It causes the quantifiers to be ungreedy by default.
267  *      Appending a ? turns back to greedy (!).
268  *
269  *    - Added a new interceptor ijb-send-banner, which
270  *      sends back the "Junkbuster" gif. Without imagelist or
271  *      MSIE detection support, or if tinygif = 1, or the
272  *      URL isn't recognized as an imageurl, a lame HTML
273  *      explanation is sent instead.
274  *
275  *    - Added new feature, which permits blocking remote
276  *      script redirects and firing back a local redirect
277  *      to the browser.
278  *      The feature is conditionally compiled, i.e. it
279  *      can be disabled with --disable-fast-redirects,
280  *      plus it must be activated by a "fast-redirects"
281  *      line in the config file, has its own log level
282  *      and of course wants to be displayed by show-proxy-args
283  *      Note: Boy, all the #ifdefs in 1001 locations and
284  *      all the fumbling with configure.in and acconfig.h
285  *      were *way* more work than the feature itself :-(
286  *
287  *    - Because a generic redirect template was needed for
288  *      this, tinygif = 3 now uses the same.
289  *
290  *    - Moved GIFs, and other static HTTP response templates
291  *      to project.h
292  *
293  *    - Some minor fixes
294  *
295  *    - Removed some >400 CRs again (Jon, you really worked
296  *      a lot! ;-)
297  *
298  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
299  *    Version 2.9.4 checkin.
300  *    - Merged popupfile and cookiefile, and added control over PCRS
301  *      filtering, in new "permissionsfile".
302  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
303  *      file error you now get a message box (in the Win32 GUI) rather
304  *      than the program exiting with no explanation.
305  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
306  *      skipping.
307  *    - Removed tabs from "config"
308  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
309  *    - Bumped up version number.
310  *
311  *    Revision 1.2  2001/05/17 23:01:01  oes
312  *     - Cleaned CRLF's from the sources and related files
313  *
314  *    Revision 1.1.1.1  2001/05/15 13:58:58  oes
315  *    Initial import of version 2.9.3 source tree
316  *
317  *
318  *********************************************************************/
319 \f
320
321 #include "config.h"
322
323 #include <stdio.h>
324 #include <sys/types.h>
325 #include <stdlib.h>
326 #include <string.h>
327 #include <signal.h>
328 #include <fcntl.h>
329 #include <errno.h>
330 #include <ctype.h>
331 #include <assert.h>
332
333 #ifdef _WIN32
334
335 # ifndef STRICT
336 #  define STRICT
337 # endif
338 # include <windows.h>
339
340 # include "win32.h"
341 # ifndef _WIN_CONSOLE
342 #  include "w32log.h"
343 # endif /* ndef _WIN_CONSOLE */
344
345 /* VC++ has "_snprintf", not "snprintf" */
346 #define snprintf _snprintf
347
348 #else /* ifndef _WIN32 */
349
350 #ifndef __OS2__
351 # include <unistd.h>
352 # include <sys/wait.h>
353 #endif
354 # include <sys/time.h>
355 # include <sys/stat.h>
356 # include <signal.h>
357
358 #endif
359
360 #include "loadcfg.h"
361 #include "list.h"
362 #include "jcc.h"
363 #include "filters.h"
364 #include "loaders.h"
365 #include "miscutil.h"
366 #include "errlog.h"
367 #include "ssplit.h"
368 #include "encode.h"
369 #include "urlmatch.h"
370 #include "cgi.h"
371
372 const char loadcfg_h_rcs[] = LOADCFG_H_VERSION;
373
374 /*
375  * Fix a problem with Solaris.  There should be no effect on other
376  * platforms.
377  * Solaris's isspace() is a macro which uses it's argument directly
378  * as an array index.  Therefore we need to make sure that high-bit
379  * characters generate +ve values, and ideally we also want to make
380  * the argument match the declared parameter type of "int".
381  */
382 #define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
383 #define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
384
385 #ifdef FEATURE_TOGGLE
386 /* Privoxy is enabled by default. */
387 int global_toggle_state = 1;
388 #endif /* def FEATURE_TOGGLE */
389
390 /* The filename of the configfile */
391 const char *configfile  = NULL;
392
393 /*
394  * CGI functions will later need access to the invocation args,
395  * so we will make argc and argv global.
396  */
397 int Argc = 0;
398 const char **Argv = NULL;
399
400 static struct file_list *current_configfile = NULL;
401
402
403 /*
404  * This takes the "cryptic" hash of each keyword and aliases them to
405  * something a little more readable.  This also makes changing the
406  * hash values easier if they should change or the hash algorthm changes.
407  * Use the included "hash" program to find out what the hash will be
408  * for any string supplied on the command line.  (Or just put it in the
409  * config file and read the number from the error message in the log).
410  *
411  * Please keep this list sorted alphabetically (but with the Windows
412  * console and GUI specific options last).
413  */
414
415 #define hash_actions_file              1196306641ul /* "actionsfile" */
416 #define hash_admin_address             4112573064ul /* "admin-address" */
417 #define hash_buffer_limit              1881726070ul /* "buffer-limit */
418 #define hash_confdir                      1978389ul /* "confdir" */
419 #define hash_debug                          78263ul /* "debug" */
420 #define hash_deny_access               1227333715ul /* "deny-access" */
421 #define hash_enable_edit_actions       2517097536ul /* "enable-edit-actions" */
422 #define hash_enable_remote_toggle      2979744683ul /* "enable-remote-toggle" */
423 #define hash_filterfile                 250887266ul /* "filterfile" */
424 #define hash_forward                      2029845ul /* "forward" */
425 #define hash_forward_socks4            3963965521ul /* "forward-socks4" */
426 #define hash_forward_socks4a           2639958518ul /* "forward-socks4a" */
427 #define hash_jarfile                      2046641ul /* "jarfile" */
428 #define hash_listen_address            1255650842ul /* "listen-address" */
429 #define hash_logdir                        422889ul /* "logdir" */
430 #define hash_logfile                      2114766ul /* "logfile" */
431 #define hash_permit_access             3587953268ul /* "permit-access" */
432 #define hash_proxy_info_url            3903079059ul /* "proxy-info-url" */
433 #define hash_single_threaded           4250084780ul /* "single-threaded" */
434 #define hash_suppress_blocklists       1948693308ul /* "suppress-blocklists" */
435 #define hash_toggle                        447966ul /* "toggle" */
436 #define hash_trust_info_url             430331967ul /* "trust-info-url" */
437 #define hash_trustfile                   56494766ul /* "trustfile" */
438 #define hash_usermanual                1416668518ul /* "user-manual" */
439 #define hash_activity_animation        1817904738ul /* "activity-animation" */
440 #define hash_close_button_minimizes    3651284693ul /* "close-button-minimizes" */
441 #define hash_hide_console              2048809870ul /* "hide-console" */
442 #define hash_log_buffer_size           2918070425ul /* "log-buffer-size" */
443 #define hash_log_font_name             2866730124ul /* "log-font-name" */
444 #define hash_log_font_size             2866731014ul /* "log-font-size" */
445 #define hash_log_highlight_messages    4032101240ul /* "log-highlight-messages" */
446 #define hash_log_max_lines             2868344173ul /* "log-max-lines" */
447 #define hash_log_messages              2291744899ul /* "log-messages" */
448 #define hash_show_on_task_bar           215410365ul /* "show-on-task-bar" */
449
450
451 static void savearg(char *command, char *argument, struct configuration_spec * config);
452
453 /*********************************************************************
454  *
455  * Function    :  unload_configfile
456  *
457  * Description :  Free the config structure and all components.
458  *
459  * Parameters  :
460  *          1  :  data: struct configuration_spec to unload
461  *
462  * Returns     :  N/A
463  *
464  *********************************************************************/
465 void unload_configfile (void * data)
466 {
467    struct configuration_spec * config = (struct configuration_spec *)data;
468    struct forward_spec *cur_fwd = config->forward;
469    int i;
470
471 #ifdef FEATURE_ACL
472    struct access_control_list *cur_acl = config->acl;
473
474    while (cur_acl != NULL)
475    {
476       struct access_control_list * next_acl = cur_acl->next;
477       free(cur_acl);
478       cur_acl = next_acl;
479    }
480    config->acl = NULL;
481 #endif /* def FEATURE_ACL */
482
483    while (cur_fwd != NULL)
484    {
485       struct forward_spec * next_fwd = cur_fwd->next;
486       free_url_spec(cur_fwd->url);
487
488       freez(cur_fwd->gateway_host);
489       freez(cur_fwd->forward_host);
490       free(cur_fwd);
491       cur_fwd = next_fwd;
492    }
493    config->forward = NULL;
494
495 #ifdef FEATURE_COOKIE_JAR
496    if ( NULL != config->jar )
497    {
498       fclose( config->jar );
499       config->jar = NULL;
500    }
501 #endif /* def FEATURE_COOKIE_JAR */
502
503    freez(config->confdir);
504    freez(config->logdir);
505
506    freez(config->haddr);
507    freez(config->logfile);
508
509    for (i = 0; i < MAX_ACTION_FILES; i++)
510    {
511       freez(config->actions_file_short[i]);
512       freez(config->actions_file[i]);
513    }
514
515    freez(config->admin_address);
516    freez(config->proxy_info_url);
517    freez(config->proxy_args);
518    freez(config->usermanual);
519
520 #ifdef FEATURE_COOKIE_JAR
521    freez(config->jarfile);
522 #endif /* def FEATURE_COOKIE_JAR */
523
524 #ifdef FEATURE_TRUST
525    freez(config->trustfile);
526    list_remove_all(config->trust_info);
527 #endif /* def FEATURE_TRUST */
528
529    freez(config->re_filterfile);
530    freez(config);
531 }
532
533
534 #ifdef FEATURE_GRACEFUL_TERMINATION
535 /*********************************************************************
536  *
537  * Function    :  unload_current_config_file
538  *
539  * Description :  Unloads current config file - reset to state at
540  *                beginning of program.
541  *
542  * Parameters  :  None
543  *
544  * Returns     :  N/A
545  *
546  *********************************************************************/
547 void unload_current_config_file(void)
548 {
549    if (current_configfile)
550    {
551       current_configfile->unloader = unload_configfile;
552       current_configfile = NULL;
553    }
554 }
555 #endif
556
557
558 /*********************************************************************
559  *
560  * Function    :  load_config
561  *
562  * Description :  Load the config file and all parameters.
563  *
564  * Parameters  :  None
565  *
566  * Returns     :  The configuration_spec, or NULL on error.
567  *
568  *********************************************************************/
569 struct configuration_spec * load_config(void)
570 {
571    char buf[BUFFER_SIZE];
572    char *p, *q;
573    FILE *configfp = NULL;
574    struct configuration_spec * config = NULL;
575    struct client_state * fake_csp;
576    struct file_list *fs;
577    unsigned long linenum = 0;
578    int i;
579
580    if ( !check_file_changed(current_configfile, configfile, &fs))
581    {
582       /* No need to load */
583       return ((struct configuration_spec *)current_configfile->f);
584    }
585    if (!fs)
586    {
587       log_error(LOG_LEVEL_FATAL, "can't check configuration file '%s':  %E",
588                 configfile);
589    }
590
591    log_error(LOG_LEVEL_INFO, "loading configuration file '%s':", configfile);
592
593 #ifdef FEATURE_TOGGLE
594    global_toggle_state      = 1;
595 #endif /* def FEATURE_TOGGLE */
596
597    fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config));
598
599    if (config==NULL)
600    {
601       freez(fs->filename);
602       freez(fs);
603       log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
604       /* Never get here - LOG_LEVEL_FATAL causes program exit */
605    }
606
607    /*
608     * This is backwards from how it's usually done.
609     * Following the usual pattern, "fs" would be stored in a member
610     * variable in "csp", and then we'd access "config" from "fs->f",
611     * using a cast.  However, "config" is used so often that a
612     * cast each time would be very ugly, and the extra indirection
613     * would waste CPU cycles.  Therefore we store "config" in
614     * "csp->config", and "fs" in "csp->config->config_file_list".
615     */
616    config->config_file_list = fs;
617
618    /*
619     * Set to defaults
620     */
621    config->multi_threaded    = 1;
622    config->hport             = HADDR_PORT;
623    config->buffer_limit      = 4096 * 1024;
624    config->usermanual        = strdup(USER_MANUAL_URL);
625    config->proxy_args        = strdup("");
626
627    if ((configfp = fopen(configfile, "r")) == NULL)
628    {
629       log_error(LOG_LEVEL_FATAL, "can't open configuration file '%s':  %E",
630               configfile);
631       /* Never get here - LOG_LEVEL_FATAL causes program exit */
632    }
633
634    while (read_config_line(buf, sizeof(buf), configfp, &linenum) != NULL)
635    {
636       char cmd[BUFFER_SIZE];
637       char arg[BUFFER_SIZE];
638       char tmp[BUFFER_SIZE];
639 #ifdef FEATURE_ACL
640       struct access_control_list *cur_acl;
641 #endif /* def FEATURE_ACL */
642       struct forward_spec *cur_fwd;
643       int vec_count;
644       char *vec[3];
645
646       strcpy(tmp, buf);
647
648       /* Copy command (i.e. up to space or tab) into cmd */
649       p = buf;
650       q = cmd;
651       while (*p && (*p != ' ') && (*p != '\t'))
652       {
653          *q++ = *p++;
654       }
655       *q = '\0';
656
657       /* Skip over the whitespace in buf */
658       while (*p && ((*p == ' ') || (*p == '\t')))
659       {
660          p++;
661       }
662
663       /* Copy the argument into arg */
664       strcpy(arg, p);
665
666       /* Should never happen, but check this anyway */
667       if (*cmd == '\0')
668       {
669          continue;
670       }
671
672       /* Make sure the command field is lower case */
673       for (p=cmd; *p; p++)
674       {
675          if (ijb_isupper(*p))
676          {
677             *p = ijb_tolower(*p);
678          }
679       }
680
681       /* Save the argument for show-proxy-args */
682       savearg(cmd, arg, config);
683
684
685       switch( hash_string( cmd ) )
686       {
687 /* *************************************************************************
688  * actionsfile actions-file-name
689  * In confdir by default
690  * *************************************************************************/
691          case hash_actions_file :
692             i = 0;
693             while ((i < MAX_ACTION_FILES) && (NULL != config->actions_file[i]))
694             {
695                i++;
696             }
697
698             if (i >= MAX_ACTION_FILES)
699             {
700                log_error(LOG_LEVEL_FATAL, "Too many 'actionsfile' directives in config file - limit is %d.\n"
701                   "(You can increase this limit by changing MAX_ACTION_FILES in project.h and recompiling).",
702                   MAX_ACTION_FILES);
703             }
704             config->actions_file_short[i] = strdup(arg);
705             p = malloc(strlen(arg) + sizeof(".action"));
706             if (p == NULL)
707             {
708                log_error(LOG_LEVEL_FATAL, "Out of memory");
709             }
710             strcpy(p, arg);
711             strcat(p, ".action");
712             config->actions_file[i] = make_path(config->confdir, p);
713             free(p);
714             continue;
715
716 /* *************************************************************************
717  * admin-address email-address
718  * *************************************************************************/
719          case hash_admin_address :
720             freez(config->admin_address);
721             config->admin_address = strdup(arg);
722             continue;
723
724 /* *************************************************************************
725  * buffer-limit n
726  * *************************************************************************/
727          case hash_buffer_limit :
728             config->buffer_limit = (size_t) 1024 * atoi(arg);
729             continue;
730
731 /* *************************************************************************
732  * confdir directory-name
733  * *************************************************************************/
734          case hash_confdir :
735             freez(config->confdir);
736             config->confdir = make_path( NULL, arg);
737             continue;
738
739 /* *************************************************************************
740  * debug n
741  * Specifies debug level, multiple values are ORed together.
742  * *************************************************************************/
743          case hash_debug :
744             config->debug |= atoi(arg);
745             continue;
746
747 /* *************************************************************************
748  * deny-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
749  * *************************************************************************/
750 #ifdef FEATURE_ACL
751          case hash_deny_access:
752             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
753
754             if ((vec_count != 1) && (vec_count != 2))
755             {
756                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
757                      "deny-access directive in configuration file.");
758                string_append(&config->proxy_args,
759                   "<br>\nWARNING: Wrong number of parameters for "
760                   "deny-access directive in configuration file.<br><br>\n");
761                continue;
762             }
763
764             /* allocate a new node */
765             cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
766
767             if (cur_acl == NULL)
768             {
769                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
770                /* Never get here - LOG_LEVEL_FATAL causes program exit */
771                continue;
772             }
773             cur_acl->action = ACL_DENY;
774
775             if (acl_addr(vec[0], cur_acl->src) < 0)
776             {
777                log_error(LOG_LEVEL_ERROR, "Invalid source IP for deny-access "
778                      "directive in configuration file: \"%s\"", vec[0]);
779                string_append(&config->proxy_args,
780                   "<br>\nWARNING: Invalid source IP for deny-access directive"
781                   " in configuration file: \"");
782                string_append(&config->proxy_args,
783                   vec[0]);
784                string_append(&config->proxy_args,
785                   "\"<br><br>\n");
786                freez(cur_acl);
787                continue;
788             }
789             if (vec_count == 2)
790             {
791                if (acl_addr(vec[1], cur_acl->dst) < 0)
792                {
793                   log_error(LOG_LEVEL_ERROR, "Invalid destination IP for deny-access "
794                         "directive in configuration file: \"%s\"", vec[0]);
795                   string_append(&config->proxy_args,
796                      "<br>\nWARNING: Invalid destination IP for deny-access directive"
797                      " in configuration file: \"");
798                   string_append(&config->proxy_args,
799                      vec[0]);
800                   string_append(&config->proxy_args,
801                      "\"<br><br>\n");
802                   freez(cur_acl);
803                   continue;
804                }
805             }
806
807             /*
808              * Add it to the list.  Note we reverse the list to get the
809              * behaviour the user expects.  With both the ACL and
810              * actions file, the last match wins.  However, the internal
811              * implementations are different:  The actions file is stored
812              * in the same order as the file, and scanned completely.
813              * With the ACL, we reverse the order as we load it, then
814              * when we scan it we stop as soon as we get a match.
815              */
816             cur_acl->next  = config->acl;
817             config->acl = cur_acl;
818
819             continue;
820 #endif /* def FEATURE_ACL */
821
822 /* *************************************************************************
823  * enable-edit-actions 0|1
824  * *************************************************************************/
825 #ifdef FEATURE_CGI_EDIT_ACTIONS
826          case hash_enable_edit_actions:
827             if ((*arg != '\0') && (0 != atoi(arg)))
828             {
829                config->feature_flags |= RUNTIME_FEATURE_CGI_EDIT_ACTIONS;
830             }
831             else
832             {
833                config->feature_flags &= ~RUNTIME_FEATURE_CGI_EDIT_ACTIONS;
834             }
835             continue;
836 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
837
838 /* *************************************************************************
839  * enable-remote-toggle 0|1
840  * *************************************************************************/
841 #ifdef FEATURE_CGI_EDIT_ACTIONS
842          case hash_enable_remote_toggle:
843             if ((*arg != '\0') && (0 != atoi(arg)))
844             {
845                config->feature_flags |= RUNTIME_FEATURE_CGI_TOGGLE;
846             }
847             else
848             {
849                config->feature_flags &= ~RUNTIME_FEATURE_CGI_TOGGLE;
850             }
851             continue;
852 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
853
854 /* *************************************************************************
855  * filterfile file-name
856  * In confdir by default.
857  * *************************************************************************/
858          case hash_filterfile :
859             if(config->re_filterfile)
860             {
861                log_error(LOG_LEVEL_ERROR, "Ignoring extraneous directive 'filterfile %s' "
862                   "in line %lu in configuration file (%s).", arg, linenum, configfile);
863                string_append(&config->proxy_args, 
864                   " <b><font color=\"red\">WARNING: extraneous directive, ignored</font></b>");
865                continue;
866             }
867             config->re_filterfile = make_path(config->confdir, arg);
868             continue;
869
870 /* *************************************************************************
871  * forward url-pattern (.|http-proxy-host[:port])
872  * *************************************************************************/
873          case hash_forward:
874             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
875
876             if (vec_count != 2)
877             {
878                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for forward "
879                      "directive in configuration file.");
880                string_append(&config->proxy_args,
881                   "<br>\nWARNING: Wrong number of parameters for "
882                   "forward directive in configuration file.");
883                continue;
884             }
885
886             /* allocate a new node */
887             cur_fwd = zalloc(sizeof(*cur_fwd));
888             if (cur_fwd == NULL)
889             {
890                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
891                /* Never get here - LOG_LEVEL_FATAL causes program exit */
892                continue;
893             }
894
895             cur_fwd->type = SOCKS_NONE;
896
897             /* Save the URL pattern */
898             if (create_url_spec(cur_fwd->url, vec[0]))
899             {
900                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward "
901                      "directive in configuration file.");
902                string_append(&config->proxy_args,
903                   "<br>\nWARNING: Bad URL specifier for "
904                   "forward directive in configuration file.");
905                continue;
906             }
907
908             /* Parse the parent HTTP proxy host:port */
909             p = vec[1];
910
911             if (strcmp(p, ".") != 0)
912             {
913                cur_fwd->forward_host = strdup(p);
914
915                if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
916                {
917                   *p++ = '\0';
918                   cur_fwd->forward_port = atoi(p);
919                }
920
921                if (cur_fwd->forward_port <= 0)
922                {
923                   cur_fwd->forward_port = 8000;
924                }
925             }
926
927             /* Add to list. */
928             cur_fwd->next = config->forward;
929             config->forward = cur_fwd;
930
931             continue;
932
933 /* *************************************************************************
934  * forward-socks4 url-pattern socks-proxy[:port] (.|http-proxy[:port])
935  * *************************************************************************/
936          case hash_forward_socks4:
937             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
938
939             if (vec_count != 3)
940             {
941                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
942                      "forward-socks4 directive in configuration file.");
943                string_append(&config->proxy_args,
944                   "<br>\nWARNING: Wrong number of parameters for "
945                   "forward-socks4 directive in configuration file.");
946                continue;
947             }
948
949             /* allocate a new node */
950             cur_fwd = zalloc(sizeof(*cur_fwd));
951             if (cur_fwd == NULL)
952             {
953                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
954                /* Never get here - LOG_LEVEL_FATAL causes program exit */
955                continue;
956             }
957
958             cur_fwd->type = SOCKS_4;
959
960             /* Save the URL pattern */
961             if (create_url_spec(cur_fwd->url, vec[0]))
962             {
963                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4 "
964                      "directive in configuration file.");
965                string_append(&config->proxy_args,
966                   "<br>\nWARNING: Bad URL specifier for "
967                   "forward-socks4 directive in configuration file.");
968                continue;
969             }
970
971             /* Parse the SOCKS proxy host[:port] */
972             p = vec[1];
973
974             if (strcmp(p, ".") != 0)
975             {
976                cur_fwd->gateway_host = strdup(p);
977
978                if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
979                {
980                   *p++ = '\0';
981                   cur_fwd->gateway_port = atoi(p);
982                }
983                if (cur_fwd->gateway_port <= 0)
984                {
985                   cur_fwd->gateway_port = 1080;
986                }
987             }
988
989             /* Parse the parent HTTP proxy host[:port] */
990             p = vec[2];
991
992             if (strcmp(p, ".") != 0)
993             {
994                cur_fwd->forward_host = strdup(p);
995
996                if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
997                {
998                   *p++ = '\0';
999                   cur_fwd->forward_port = atoi(p);
1000                }
1001
1002                if (cur_fwd->forward_port <= 0)
1003                {
1004                   cur_fwd->forward_port = 8000;
1005                }
1006             }
1007
1008             /* Add to list. */
1009             cur_fwd->next = config->forward;
1010             config->forward = cur_fwd;
1011
1012             continue;
1013
1014 /* *************************************************************************
1015  * forward-socks4a url-pattern socks-proxy[:port] (.|http-proxy[:port])
1016  * *************************************************************************/
1017          case hash_forward_socks4a:
1018             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
1019
1020             if (vec_count != 3)
1021             {
1022                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
1023                      "forward-socks4a directive in configuration file.");
1024                string_append(&config->proxy_args,
1025                   "<br>\nWARNING: Wrong number of parameters for "
1026                   "forward-socks4a directive in configuration file.");
1027                continue;
1028             }
1029
1030             /* allocate a new node */
1031             cur_fwd = zalloc(sizeof(*cur_fwd));
1032             if (cur_fwd == NULL)
1033             {
1034                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
1035                /* Never get here - LOG_LEVEL_FATAL causes program exit */
1036                continue;
1037             }
1038
1039             cur_fwd->type = SOCKS_4A;
1040
1041             /* Save the URL pattern */
1042             if (create_url_spec(cur_fwd->url, vec[0]))
1043             {
1044                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4a "
1045                      "directive in configuration file.");
1046                string_append(&config->proxy_args,
1047                   "<br>\nWARNING: Bad URL specifier for "
1048                   "forward-socks4a directive in configuration file.");
1049                continue;
1050             }
1051
1052             /* Parse the SOCKS proxy host[:port] */
1053             p = vec[1];
1054
1055             cur_fwd->gateway_host = strdup(p);
1056
1057             if (NULL != (p = strchr(cur_fwd->gateway_host, ':')))
1058             {
1059                *p++ = '\0';
1060                cur_fwd->gateway_port = atoi(p);
1061             }
1062             if (cur_fwd->gateway_port <= 0)
1063             {
1064                cur_fwd->gateway_port = 1080;
1065             }
1066
1067             /* Parse the parent HTTP proxy host[:port] */
1068             p = vec[2];
1069
1070             if (strcmp(p, ".") != 0)
1071             {
1072                cur_fwd->forward_host = strdup(p);
1073
1074                if (NULL != (p = strchr(cur_fwd->forward_host, ':')))
1075                {
1076                   *p++ = '\0';
1077                   cur_fwd->forward_port = atoi(p);
1078                }
1079
1080                if (cur_fwd->forward_port <= 0)
1081                {
1082                   cur_fwd->forward_port = 8000;
1083                }
1084             }
1085
1086             /* Add to list. */
1087             cur_fwd->next = config->forward;
1088             config->forward = cur_fwd;
1089
1090             continue;
1091
1092 /* *************************************************************************
1093  * jarfile jar-file-name
1094  * In logdir by default
1095  * *************************************************************************/
1096 #ifdef FEATURE_COOKIE_JAR
1097          case hash_jarfile :
1098             freez(config->jarfile);
1099             config->jarfile = make_path(config->logdir, arg);
1100             continue;
1101 #endif /* def FEATURE_COOKIE_JAR */
1102
1103 /* *************************************************************************
1104  * listen-address [ip][:port]
1105  * *************************************************************************/
1106          case hash_listen_address :
1107             freez(config->haddr);
1108             config->haddr = strdup(arg);
1109             continue;
1110
1111 /* *************************************************************************
1112  * logdir directory-name
1113  * *************************************************************************/
1114          case hash_logdir :
1115             freez(config->logdir);
1116             config->logdir = make_path(NULL, arg);
1117             continue;
1118
1119 /* *************************************************************************
1120  * logfile log-file-name
1121  * In logdir by default
1122  * *************************************************************************/
1123          case hash_logfile :
1124             freez(config->logfile);
1125             config->logfile = no_daemon ? NULL : make_path(config->logdir, arg);
1126             continue;
1127
1128 /* *************************************************************************
1129  * permit-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
1130  * *************************************************************************/
1131 #ifdef FEATURE_ACL
1132          case hash_permit_access:
1133             vec_count = ssplit(arg, " \t", vec, SZ(vec), 1, 1);
1134
1135             if ((vec_count != 1) && (vec_count != 2))
1136             {
1137                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
1138                      "permit-access directive in configuration file.");
1139                string_append(&config->proxy_args,
1140                   "<br>\nWARNING: Wrong number of parameters for "
1141                   "permit-access directive in configuration file.<br><br>\n");
1142
1143                continue;
1144             }
1145
1146             /* allocate a new node */
1147             cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
1148
1149             if (cur_acl == NULL)
1150             {
1151                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
1152                /* Never get here - LOG_LEVEL_FATAL causes program exit */
1153                continue;
1154             }
1155             cur_acl->action = ACL_PERMIT;
1156
1157             if (acl_addr(vec[0], cur_acl->src) < 0)
1158             {
1159                log_error(LOG_LEVEL_ERROR, "Invalid source IP for permit-access "
1160                      "directive in configuration file: \"%s\"", vec[0]);
1161                string_append(&config->proxy_args,
1162                   "<br>\nWARNING: Invalid source IP for permit-access directive"
1163                   " in configuration file: \"");
1164                string_append(&config->proxy_args,
1165                   vec[0]);
1166                string_append(&config->proxy_args,
1167                   "\"<br><br>\n");
1168                freez(cur_acl);
1169                continue;
1170             }
1171             if (vec_count == 2)
1172             {
1173                if (acl_addr(vec[1], cur_acl->dst) < 0)
1174                {
1175                   log_error(LOG_LEVEL_ERROR, "Invalid destination IP for "
1176                         "permit-access directive in configuration file: \"%s\"",
1177                         vec[0]);
1178                   string_append(&config->proxy_args,
1179                      "<br>\nWARNING: Invalid destination IP for permit-access directive"
1180                      " in configuration file: \"");
1181                   string_append(&config->proxy_args,
1182                      vec[0]);
1183                   string_append(&config->proxy_args,
1184                      "\"<br><br>\n");
1185                   freez(cur_acl);
1186                   continue;
1187                }
1188             }
1189
1190             /*
1191              * Add it to the list.  Note we reverse the list to get the
1192              * behaviour the user expects.  With both the ACL and
1193              * actions file, the last match wins.  However, the internal
1194              * implementations are different:  The actions file is stored
1195              * in the same order as the file, and scanned completely.
1196              * With the ACL, we reverse the order as we load it, then
1197              * when we scan it we stop as soon as we get a match.
1198              */
1199             cur_acl->next  = config->acl;
1200             config->acl = cur_acl;
1201
1202             continue;
1203 #endif /* def FEATURE_ACL */
1204
1205 /* *************************************************************************
1206  * proxy-info-url url
1207  * *************************************************************************/
1208          case hash_proxy_info_url :
1209             freez(config->proxy_info_url);
1210             config->proxy_info_url = strdup(arg);
1211             continue;
1212
1213 /* *************************************************************************
1214  * single-threaded
1215  * *************************************************************************/
1216          case hash_single_threaded :
1217             config->multi_threaded = 0;
1218             continue;
1219
1220 /* *************************************************************************
1221  * toggle (0|1)
1222  * *************************************************************************/
1223 #ifdef FEATURE_TOGGLE
1224          case hash_toggle :
1225             global_toggle_state = atoi(arg);
1226             continue;
1227 #endif /* def FEATURE_TOGGLE */
1228
1229 /* *************************************************************************
1230  * trust-info-url url
1231  * *************************************************************************/
1232 #ifdef FEATURE_TRUST
1233          case hash_trust_info_url :
1234             enlist(config->trust_info, arg);
1235             continue;
1236 #endif /* def FEATURE_TRUST */
1237
1238 /* *************************************************************************
1239  * trustfile filename
1240  * (In confdir by default.)
1241  * *************************************************************************/
1242 #ifdef FEATURE_TRUST
1243          case hash_trustfile :
1244             freez(config->trustfile);
1245             config->trustfile = make_path(config->confdir, arg);
1246             continue;
1247 #endif /* def FEATURE_TRUST */
1248
1249 /* *************************************************************************
1250  * usermanual url
1251  * *************************************************************************/
1252          case hash_usermanual :
1253             freez(config->usermanual);
1254             config->usermanual = strdup(arg);
1255             continue;
1256
1257 /* *************************************************************************
1258  * Win32 Console options:
1259  * *************************************************************************/
1260
1261 /* *************************************************************************
1262  * hide-console
1263  * *************************************************************************/
1264 #ifdef _WIN_CONSOLE
1265          case hash_hide_console :
1266             hideConsole = 1;
1267             continue;
1268 #endif /*def _WIN_CONSOLE*/
1269
1270
1271 /* *************************************************************************
1272  * Win32 GUI options:
1273  * *************************************************************************/
1274
1275 #if defined(_WIN32) && ! defined(_WIN_CONSOLE)
1276 /* *************************************************************************
1277  * activity-animation (0|1)
1278  * *************************************************************************/
1279          case hash_activity_animation :
1280             g_bShowActivityAnimation = atoi(arg);
1281             continue;
1282
1283 /* *************************************************************************
1284  *  close-button-minimizes (0|1)
1285  * *************************************************************************/
1286          case hash_close_button_minimizes :
1287             g_bCloseHidesWindow = atoi(arg);
1288             continue;
1289
1290 /* *************************************************************************
1291  * log-buffer-size (0|1)
1292  * *************************************************************************/
1293          case hash_log_buffer_size :
1294             g_bLimitBufferSize = atoi(arg);
1295             continue;
1296
1297 /* *************************************************************************
1298  * log-font-name fontnane
1299  * *************************************************************************/
1300          case hash_log_font_name :
1301             strcpy( g_szFontFaceName, arg );
1302             continue;
1303
1304 /* *************************************************************************
1305  * log-font-size n
1306  * *************************************************************************/
1307          case hash_log_font_size :
1308             g_nFontSize = atoi(arg);
1309             continue;
1310
1311 /* *************************************************************************
1312  * log-highlight-messages (0|1)
1313  * *************************************************************************/
1314          case hash_log_highlight_messages :
1315             g_bHighlightMessages = atoi(arg);
1316             continue;
1317
1318 /* *************************************************************************
1319  * log-max-lines n
1320  * *************************************************************************/
1321          case hash_log_max_lines :
1322             g_nMaxBufferLines = atoi(arg);
1323             continue;
1324
1325 /* *************************************************************************
1326  * log-messages (0|1)
1327  * *************************************************************************/
1328          case hash_log_messages :
1329             g_bLogMessages = atoi(arg);
1330             continue;
1331
1332 /* *************************************************************************
1333  * show-on-task-bar (0|1)
1334  * *************************************************************************/
1335          case hash_show_on_task_bar :
1336             g_bShowOnTaskBar = atoi(arg);
1337             continue;
1338
1339 #endif /* defined(_WIN32) && ! defined(_WIN_CONSOLE) */
1340
1341
1342 /* *************************************************************************
1343  * Warnings about unsupported features
1344  * *************************************************************************/
1345 #ifndef FEATURE_ACL
1346          case hash_deny_access:
1347 #endif /* ndef FEATURE_ACL */
1348 #ifndef FEATURE_CGI_EDIT_ACTIONS
1349          case hash_enable_edit_actions:
1350          case hash_enable_remote_toggle:
1351 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
1352 #ifndef FEATURE_COOKIE_JAR
1353          case hash_jarfile :
1354 #endif /* ndef FEATURE_COOKIE_JAR */
1355 #ifndef FEATURE_ACL
1356          case hash_permit_access:
1357 #endif /* ndef FEATURE_ACL */
1358 #ifndef FEATURE_TOGGLE
1359          case hash_toggle :
1360 #endif /* ndef FEATURE_TOGGLE */
1361 #ifndef FEATURE_TRUST
1362          case hash_trustfile :
1363          case hash_trust_info_url :
1364 #endif /* ndef FEATURE_TRUST */
1365
1366 #ifndef _WIN_CONSOLE
1367          case hash_hide_console :
1368 #endif /* ndef _WIN_CONSOLE */
1369
1370 #if defined(_WIN_CONSOLE) || ! defined(_WIN32)
1371          case hash_activity_animation :
1372          case hash_close_button_minimizes :
1373          case hash_log_buffer_size :
1374          case hash_log_font_name :
1375          case hash_log_font_size :
1376          case hash_log_highlight_messages :
1377          case hash_log_max_lines :
1378          case hash_log_messages :
1379          case hash_show_on_task_bar :
1380 #endif /* defined(_WIN_CONSOLE) || ! defined(_WIN32) */
1381             /* These warnings are annoying - so hide them. -- Jon */
1382             /* log_error(LOG_LEVEL_INFO, "Unsupported directive \"%s\" ignored.", cmd); */
1383             continue;
1384
1385 /* *************************************************************************/
1386          default :
1387 /* *************************************************************************/
1388             /*
1389              * I decided that I liked this better as a warning than an
1390              * error.  To change back to an error, just change log level
1391              * to LOG_LEVEL_FATAL.
1392              */
1393             log_error(LOG_LEVEL_ERROR, "Ignoring unrecognized directive '%s' (%luul) in line %lu "
1394                   "in configuration file (%s).",  buf, hash_string(cmd), linenum, configfile);
1395             string_append(&config->proxy_args,
1396                " <b><font color=\"red\">WARNING: unrecognized directive, ignored</font></b>");
1397             continue;
1398
1399 /* *************************************************************************/
1400       } /* end switch( hash_string(cmd) ) */
1401    } /* end while ( read_config_line(...) ) */
1402
1403    fclose(configfp);
1404
1405    if (NULL == config->proxy_args)
1406    {
1407       log_error(LOG_LEVEL_FATAL, "Out of memory loading config - insufficient memory for config->proxy_args");
1408    }
1409
1410    init_error_log(Argv[0], config->logfile, config->debug);
1411
1412    if (config->actions_file[0])
1413    {
1414       add_loader(load_actions_file, config);
1415    }
1416
1417    if (config->re_filterfile)
1418    {
1419       add_loader(load_re_filterfile, config);
1420    }
1421
1422 #ifdef FEATURE_TRUST
1423    if (config->trustfile)
1424    {
1425       add_loader(load_trustfile, config);
1426    }
1427 #endif /* def FEATURE_TRUST */
1428
1429 #ifdef FEATURE_COOKIE_JAR
1430    if ( NULL != config->jarfile )
1431    {
1432       if ( NULL == (config->jar = fopen(config->jarfile, "a")) )
1433       {
1434          log_error(LOG_LEVEL_FATAL, "can't open jarfile '%s': %E", config->jarfile);
1435          /* Never get here - LOG_LEVEL_FATAL causes program exit */
1436       }
1437       setbuf(config->jar, NULL);
1438    }
1439 #endif /* def FEATURE_COOKIE_JAR */
1440
1441    if ( NULL == config->haddr )
1442    {
1443       config->haddr = strdup( HADDR_DEFAULT );
1444    }
1445
1446    if ( NULL != config->haddr )
1447    {
1448       if (NULL != (p = strchr(config->haddr, ':')))
1449       {
1450          *p++ = '\0';
1451          if (*p)
1452          {
1453             config->hport = atoi(p);
1454          }
1455       }
1456
1457       if (config->hport <= 0)
1458       {
1459          *--p = ':';
1460          log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
1461          /* Never get here - LOG_LEVEL_FATAL causes program exit */
1462       }
1463       if (*config->haddr == '\0')
1464       {
1465          config->haddr = NULL;
1466       }
1467    }
1468
1469    /*
1470     * Want to run all the loaders once now.
1471     *
1472     * Need to set up a fake csp, so they can get to the config.
1473     */
1474    fake_csp = (struct client_state *) zalloc (sizeof(*fake_csp));
1475    fake_csp->config = config;
1476
1477    if (run_loader(fake_csp))
1478    {
1479       freez(fake_csp);
1480       log_error(LOG_LEVEL_FATAL, "A loader failed while loading config file. Exiting.");
1481       /* Never get here - LOG_LEVEL_FATAL causes program exit */
1482    }
1483    freez(fake_csp);
1484
1485 /* FIXME: this is a kludge for win32 */
1486 #if defined(_WIN32) && !defined (_WIN_CONSOLE)
1487
1488    g_default_actions_file  = config->actions_file[1]; /* FIXME Hope this is default.action */
1489    g_user_actions_file = config->actions_file[2]; /* FIXME Hope this is user.action */
1490    g_re_filterfile    = config->re_filterfile;
1491
1492 #ifdef FEATURE_TRUST
1493    g_trustfile        = config->trustfile;
1494 #endif /* def FEATURE_TRUST */
1495
1496
1497 #endif /* defined(_WIN32) && !defined (_WIN_CONSOLE) */
1498 /* FIXME: end kludge */
1499
1500
1501    config->need_bind = 1;
1502
1503    if (current_configfile)
1504    {
1505       struct configuration_spec * oldcfg = (struct configuration_spec *)
1506                                            current_configfile->f;
1507       /*
1508        * Check if config->haddr,hport == oldcfg->haddr,hport
1509        *
1510        * The following could be written more compactly as a single,
1511        * (unreadably long) if statement.
1512        */
1513       config->need_bind = 0;
1514       if (config->hport != oldcfg->hport)
1515       {
1516          config->need_bind = 1;
1517       }
1518       else if (config->haddr == NULL)
1519       {
1520          if (oldcfg->haddr != NULL)
1521          {
1522             config->need_bind = 1;
1523          }
1524       }
1525       else if (oldcfg->haddr == NULL)
1526       {
1527          config->need_bind = 1;
1528       }
1529       else if (0 != strcmp(config->haddr, oldcfg->haddr))
1530       {
1531          config->need_bind = 1;
1532       }
1533
1534       current_configfile->unloader = unload_configfile;
1535    }
1536
1537    fs->next = files->next;
1538    files->next = fs;
1539
1540    current_configfile = fs;
1541
1542    return (config);
1543 }
1544
1545
1546 /*********************************************************************
1547  *
1548  * Function    :  savearg
1549  *
1550  * Description :  Called from `load_config'.  It saves each non-empty
1551  *                and non-comment line from config into
1552  *                config->proxy_args.  This is used to create the
1553  *                show-proxy-args page.  On error, frees
1554  *                config->proxy_args and sets it to NULL
1555  *
1556  * Parameters  :
1557  *          1  :  command = config setting that was found
1558  *          2  :  argument = the setting's argument (if any)
1559  *          3  :  config = Configuration to save into.
1560  *
1561  * Returns     :  N/A
1562  *
1563  *********************************************************************/
1564 static void savearg(char *command, char *argument, struct configuration_spec * config)
1565 {
1566    char * buf;
1567    char * s;
1568
1569    assert(command);
1570    assert(*command);
1571    assert(argument);
1572
1573    /*
1574     * Add config option name embedded in
1575     * link to it's section in the user-manual
1576     */
1577    buf = strdup("\n<br><a href=\"");
1578    string_append(&buf, config->usermanual);
1579    string_append(&buf, CONFIG_HELP_PREFIX);
1580    string_join  (&buf, string_toupper(command));
1581    string_append(&buf, "\">");
1582    string_append(&buf, command);
1583    string_append(&buf, "</a> ");
1584
1585    if (NULL == buf)
1586    {
1587       freez(config->proxy_args);
1588       return;
1589    }
1590
1591    if ( (NULL != argument) && ('\0' != *argument) )
1592    {
1593       s = html_encode(argument);
1594       if (NULL == s)
1595       {
1596          freez(buf);
1597          freez(config->proxy_args);
1598          return;
1599       }
1600
1601       if (strncmpic(argument, "http://", 7) == 0)
1602       {
1603          string_append(&buf, "<a href=\"");
1604          string_append(&buf, s);
1605          string_append(&buf, "\">");
1606          string_join  (&buf, s);
1607          string_append(&buf, "</a>");
1608       }
1609       else
1610       {
1611          string_join  (&buf, s);
1612       }
1613    }
1614
1615    string_join(&config->proxy_args, buf);
1616 }
1617
1618
1619 /*
1620   Local Variables:
1621   tab-width: 3
1622   end:
1623 */