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