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