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