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