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