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