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