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