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