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