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