Ditch redundant code in unload_configfile().
[privoxy.git] / loadcfg.c
1 const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.109 2010/01/10 13:53:48 ler762 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-2009 the
12  *                Privoxy team. http://www.privoxy.org/
13  *
14  *                Based on the Internet Junkbuster originally written
15  *                by and Copyright (C) 1997 Anonymous Coders and
16  *                Junkbusters Corporation.  http://www.junkbusters.com
17  *
18  *                This program is free software; you can redistribute it
19  *                and/or modify it under the terms of the GNU General
20  *                Public License as published by the Free Software
21  *                Foundation; either version 2 of the License, or (at
22  *                your option) any later version.
23  *
24  *                This program is distributed in the hope that it will
25  *                be useful, but WITHOUT ANY WARRANTY; without even the
26  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
27  *                PARTICULAR PURPOSE.  See the GNU General Public
28  *                License for more details.
29  *
30  *                The GNU General Public License should be included with
31  *                this file.  If not, you can view it at
32  *                http://www.gnu.org/copyleft/gpl.html
33  *                or write to the Free Software Foundation, Inc., 59
34  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  *
36  *********************************************************************/
37
38
39 #include "config.h"
40
41 #include <stdio.h>
42 #include <sys/types.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <signal.h>
46 #include <fcntl.h>
47 #include <errno.h>
48 #include <ctype.h>
49 #include <assert.h>
50
51 #ifdef _WIN32
52
53 # ifndef STRICT
54 #  define STRICT
55 # endif
56 # include <windows.h>
57
58 # include "win32.h"
59 # ifndef _WIN_CONSOLE
60 #  include "w32log.h"
61 # endif /* ndef _WIN_CONSOLE */
62
63 #else /* ifndef _WIN32 */
64
65 #ifndef __OS2__
66 # include <unistd.h>
67 # include <sys/wait.h>
68 #endif
69 # include <sys/time.h>
70 # include <sys/stat.h>
71 # include <signal.h>
72
73 #endif
74
75 #include "loadcfg.h"
76 #include "list.h"
77 #include "jcc.h"
78 #include "filters.h"
79 #include "loaders.h"
80 #include "miscutil.h"
81 #include "errlog.h"
82 #include "ssplit.h"
83 #include "encode.h"
84 #include "urlmatch.h"
85 #include "cgi.h"
86 #include "gateway.h"
87
88 const char loadcfg_h_rcs[] = LOADCFG_H_VERSION;
89
90 /*
91  * Fix a problem with Solaris.  There should be no effect on other
92  * platforms.
93  * Solaris's isspace() is a macro which uses it's argument directly
94  * as an array index.  Therefore we need to make sure that high-bit
95  * characters generate +ve values, and ideally we also want to make
96  * the argument match the declared parameter type of "int".
97  */
98 #define ijb_isupper(__X) isupper((int)(unsigned char)(__X))
99 #define ijb_tolower(__X) tolower((int)(unsigned char)(__X))
100
101 #ifdef FEATURE_TOGGLE
102 /* Privoxy is enabled by default. */
103 int global_toggle_state = 1;
104 #endif /* def FEATURE_TOGGLE */
105
106 /* The filename of the configfile */
107 const char *configfile  = NULL;
108
109 /*
110  * CGI functions will later need access to the invocation args,
111  * so we will make argc and argv global.
112  */
113 int Argc = 0;
114 char * const * Argv = NULL;
115
116 static struct file_list *current_configfile = NULL;
117
118
119 /*
120  * This takes the "cryptic" hash of each keyword and aliases them to
121  * something a little more readable.  This also makes changing the
122  * hash values easier if they should change or the hash algorthm changes.
123  * Use the included "hash" program to find out what the hash will be
124  * for any string supplied on the command line.  (Or just put it in the
125  * config file and read the number from the error message in the log).
126  *
127  * Please keep this list sorted alphabetically (but with the Windows
128  * console and GUI specific options last).
129  */
130
131 #define hash_actions_file                1196306641ul /* "actionsfile" */
132 #define hash_accept_intercepted_requests 1513024973ul /* "accept-intercepted-requests" */
133 #define hash_admin_address               4112573064ul /* "admin-address" */
134 #define hash_allow_cgi_request_crunching  258915987ul /* "allow-cgi-request-crunching" */
135 #define hash_buffer_limit                1881726070ul /* "buffer-limit */
136 #define hash_confdir                        1978389ul /* "confdir" */
137 #define hash_connection_sharing          1348841265ul /* "connection-sharing" */
138 #define hash_debug                            78263ul /* "debug" */
139 #define hash_default_server_timeout      2530089913ul /* "default-server-timeout" */
140 #define hash_deny_access                 1227333715ul /* "deny-access" */
141 #define hash_enable_edit_actions         2517097536ul /* "enable-edit-actions" */
142 #define hash_enable_remote_toggle        2979744683ul /* "enable-remote-toggle" */
143 #define hash_enable_remote_http_toggle    110543988ul /* "enable-remote-http-toggle" */
144 #define hash_enforce_blocks              1862427469ul /* "enforce-blocks" */
145 #define hash_filterfile                   250887266ul /* "filterfile" */
146 #define hash_forward                        2029845ul /* "forward" */
147 #define hash_forward_socks4              3963965521ul /* "forward-socks4" */
148 #define hash_forward_socks4a             2639958518ul /* "forward-socks4a" */
149 #define hash_forward_socks5              3963965522ul /* "forward-socks5" */
150 #define hash_forwarded_connect_retries    101465292ul /* "forwarded-connect-retries" */
151 #define hash_handle_as_empty_returns_ok  1444873247ul /* "handle-as-empty-doc-returns-ok" */
152 #define hash_hostname                      10308071ul /* "hostname" */
153 #define hash_keep_alive_timeout          3878599515ul /* "keep-alive-timeout" */
154 #define hash_listen_address              1255650842ul /* "listen-address" */
155 #define hash_logdir                          422889ul /* "logdir" */
156 #define hash_logfile                        2114766ul /* "logfile" */
157 #define hash_max_client_connections      3595884446ul /* "max-client-connections" */
158 #define hash_permit_access               3587953268ul /* "permit-access" */
159 #define hash_proxy_info_url              3903079059ul /* "proxy-info-url" */
160 #define hash_single_threaded             4250084780ul /* "single-threaded" */
161 #define hash_socket_timeout              1809001761ul /* "socket-timeout" */
162 #define hash_split_large_cgi_forms        671658948ul /* "split-large-cgi-forms" */
163 #define hash_suppress_blocklists         1948693308ul /* "suppress-blocklists" */
164 #define hash_templdir                      11067889ul /* "templdir" */
165 #define hash_toggle                          447966ul /* "toggle" */
166 #define hash_trust_info_url               430331967ul /* "trust-info-url" */
167 #define hash_trustfile                     56494766ul /* "trustfile" */
168 #define hash_usermanual                  1416668518ul /* "user-manual" */
169 #define hash_activity_animation          1817904738ul /* "activity-animation" */
170 #define hash_close_button_minimizes      3651284693ul /* "close-button-minimizes" */
171 #define hash_hide_console                2048809870ul /* "hide-console" */
172 #define hash_log_buffer_size             2918070425ul /* "log-buffer-size" */
173 #define hash_log_font_name               2866730124ul /* "log-font-name" */
174 #define hash_log_font_size               2866731014ul /* "log-font-size" */
175 #define hash_log_highlight_messages      4032101240ul /* "log-highlight-messages" */
176 #define hash_log_max_lines               2868344173ul /* "log-max-lines" */
177 #define hash_log_messages                2291744899ul /* "log-messages" */
178 #define hash_show_on_task_bar             215410365ul /* "show-on-task-bar" */
179
180
181 static void savearg(char *command, char *argument, struct configuration_spec * config);
182
183 /*********************************************************************
184  *
185  * Function    :  unload_configfile
186  *
187  * Description :  Free the config structure and all components.
188  *
189  * Parameters  :
190  *          1  :  data: struct configuration_spec to unload
191  *
192  * Returns     :  N/A
193  *
194  *********************************************************************/
195 static void unload_configfile (void * data)
196 {
197    struct configuration_spec * config = (struct configuration_spec *)data;
198    struct forward_spec *cur_fwd = config->forward;
199    int i;
200
201 #ifdef FEATURE_ACL
202    struct access_control_list *cur_acl = config->acl;
203
204    while (cur_acl != NULL)
205    {
206       struct access_control_list * next_acl = cur_acl->next;
207       free(cur_acl);
208       cur_acl = next_acl;
209    }
210    config->acl = NULL;
211 #endif /* def FEATURE_ACL */
212
213    while (cur_fwd != NULL)
214    {
215       struct forward_spec * next_fwd = cur_fwd->next;
216       free_url_spec(cur_fwd->url);
217
218       freez(cur_fwd->gateway_host);
219       freez(cur_fwd->forward_host);
220       free(cur_fwd);
221       cur_fwd = next_fwd;
222    }
223    config->forward = NULL;
224
225    freez(config->confdir);
226    freez(config->logdir);
227    freez(config->templdir);
228    freez(config->hostname);
229
230    freez(config->haddr);
231    freez(config->logfile);
232
233    for (i = 0; i < MAX_AF_FILES; i++)
234    {
235       freez(config->actions_file_short[i]);
236       freez(config->actions_file[i]);
237       freez(config->re_filterfile_short[i]);
238       freez(config->re_filterfile[i]);
239    }
240
241    freez(config->admin_address);
242    freez(config->proxy_info_url);
243    freez(config->proxy_args);
244    freez(config->usermanual);
245
246 #ifdef FEATURE_TRUST
247    freez(config->trustfile);
248    list_remove_all(config->trust_info);
249 #endif /* def FEATURE_TRUST */
250
251    freez(config);
252 }
253
254
255 #ifdef FEATURE_GRACEFUL_TERMINATION
256 /*********************************************************************
257  *
258  * Function    :  unload_current_config_file
259  *
260  * Description :  Unloads current config file - reset to state at
261  *                beginning of program.
262  *
263  * Parameters  :  None
264  *
265  * Returns     :  N/A
266  *
267  *********************************************************************/
268 void unload_current_config_file(void)
269 {
270    if (current_configfile)
271    {
272       current_configfile->unloader = unload_configfile;
273       current_configfile = NULL;
274    }
275 }
276 #endif
277
278
279 /*********************************************************************
280  *
281  * Function    :  load_config
282  *
283  * Description :  Load the config file and all parameters.
284  *
285  *                XXX: more than thousand lines long
286  *                and thus in serious need of refactoring.
287  *
288  * Parameters  :  None
289  *
290  * Returns     :  The configuration_spec, or NULL on error.
291  *
292  *********************************************************************/
293 struct configuration_spec * load_config(void)
294 {
295    char buf[BUFFER_SIZE];
296    char *p, *q;
297    FILE *configfp = NULL;
298    struct configuration_spec * config = NULL;
299    struct client_state * fake_csp;
300    struct file_list *fs;
301    unsigned long linenum = 0;
302    int i;
303    char *logfile = NULL;
304
305    if (!check_file_changed(current_configfile, configfile, &fs))
306    {
307       /* No need to load */
308       return ((struct configuration_spec *)current_configfile->f);
309    }
310    if (NULL == fs)
311    {
312       log_error(LOG_LEVEL_FATAL,
313          "can't check configuration file '%s':  %E", configfile);
314       return NULL;
315    }
316
317    if (NULL != current_configfile)
318    {
319       log_error(LOG_LEVEL_INFO, "Reloading configuration file '%s'", configfile);
320    }
321
322 #ifdef FEATURE_TOGGLE
323    global_toggle_state = 1;
324 #endif /* def FEATURE_TOGGLE */
325
326    fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config));
327
328    if (NULL == config)
329    {
330       freez(fs->filename);
331       freez(fs);
332       log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
333       return NULL;
334    }
335
336    /*
337     * This is backwards from how it's usually done.
338     * Following the usual pattern, "fs" would be stored in a member
339     * variable in "csp", and then we'd access "config" from "fs->f",
340     * using a cast.  However, "config" is used so often that a
341     * cast each time would be very ugly, and the extra indirection
342     * would waste CPU cycles.  Therefore we store "config" in
343     * "csp->config", and "fs" in "csp->config->config_file_list".
344     */
345    config->config_file_list = fs;
346
347    /*
348     * Set to defaults
349     */
350    config->multi_threaded            = 1;
351    config->buffer_limit              = 4096 * 1024;
352    config->usermanual                = strdup(USER_MANUAL_URL);
353    config->proxy_args                = strdup("");
354    config->forwarded_connect_retries = 0;
355    config->max_client_connections    = 0;
356    config->socket_timeout            = 300; /* XXX: Should be a macro. */
357 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
358    config->default_server_timeout    = 0;
359    config->keep_alive_timeout        = DEFAULT_KEEP_ALIVE_TIMEOUT;
360    config->feature_flags            &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
361    config->feature_flags            &= ~RUNTIME_FEATURE_CONNECTION_SHARING;
362 #endif
363    config->feature_flags            &= ~RUNTIME_FEATURE_CGI_TOGGLE;
364    config->feature_flags            &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
365    config->feature_flags            &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
366    config->feature_flags            &= ~RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK;
367
368    configfp = fopen(configfile, "r");
369    if (NULL == configfp)
370    {
371       log_error(LOG_LEVEL_FATAL,
372          "can't open configuration file '%s':  %E", configfile);
373       /* Never get here - LOG_LEVEL_FATAL causes program exit */
374    }
375
376    while (read_config_line(buf, sizeof(buf), configfp, &linenum) != NULL)
377    {
378       char cmd[BUFFER_SIZE];
379       char arg[BUFFER_SIZE];
380       char tmp[BUFFER_SIZE];
381 #ifdef FEATURE_ACL
382       struct access_control_list *cur_acl;
383 #endif /* def FEATURE_ACL */
384       struct forward_spec *cur_fwd;
385       int vec_count;
386       char *vec[3];
387       unsigned long directive_hash;
388
389       strlcpy(tmp, buf, sizeof(tmp));
390
391       /* Copy command (i.e. up to space or tab) into cmd */
392       p = buf;
393       q = cmd;
394       while (*p && (*p != ' ') && (*p != '\t'))
395       {
396          *q++ = *p++;
397       }
398       *q = '\0';
399
400       /* Skip over the whitespace in buf */
401       while (*p && ((*p == ' ') || (*p == '\t')))
402       {
403          p++;
404       }
405
406       /* Copy the argument into arg */
407       strlcpy(arg, p, sizeof(arg));
408
409       /* Should never happen, but check this anyway */
410       if (*cmd == '\0')
411       {
412          continue;
413       }
414
415       /* Make sure the command field is lower case */
416       for (p = cmd; *p; p++)
417       {
418          if (ijb_isupper(*p))
419          {
420             *p = (char)ijb_tolower(*p);
421          }
422       }
423
424       directive_hash = hash_string(cmd);
425       switch (directive_hash)
426       {
427 /* *************************************************************************
428  * actionsfile actions-file-name
429  * In confdir by default
430  * *************************************************************************/
431          case hash_actions_file :
432             i = 0;
433             while ((i < MAX_AF_FILES) && (NULL != config->actions_file[i]))
434             {
435                i++;
436             }
437
438             if (i >= MAX_AF_FILES)
439             {
440                log_error(LOG_LEVEL_FATAL, "Too many 'actionsfile' directives in config file - limit is %d.\n"
441                   "(You can increase this limit by changing MAX_AF_FILES in project.h and recompiling).",
442                   MAX_AF_FILES);
443             }
444             config->actions_file_short[i] = strdup(arg);
445             config->actions_file[i] = make_path(config->confdir, arg);
446
447             break;
448 /* *************************************************************************
449  * accept-intercepted-requests
450  * *************************************************************************/
451          case hash_accept_intercepted_requests:
452             if ((*arg != '\0') && (0 != atoi(arg)))
453             {
454                config->feature_flags |= RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
455             }
456             else
457             {
458                config->feature_flags &= ~RUNTIME_FEATURE_ACCEPT_INTERCEPTED_REQUESTS;
459             }
460             break;
461
462 /* *************************************************************************
463  * admin-address email-address
464  * *************************************************************************/
465          case hash_admin_address :
466             freez(config->admin_address);
467             config->admin_address = strdup(arg);
468             break;
469
470 /* *************************************************************************
471  * allow-cgi-request-crunching
472  * *************************************************************************/
473          case hash_allow_cgi_request_crunching:
474             if ((*arg != '\0') && (0 != atoi(arg)))
475             {
476                config->feature_flags |= RUNTIME_FEATURE_CGI_CRUNCHING;
477             }
478             else
479             {
480                config->feature_flags &= ~RUNTIME_FEATURE_CGI_CRUNCHING;
481             }
482             break;
483
484 /* *************************************************************************
485  * buffer-limit n
486  * *************************************************************************/
487          case hash_buffer_limit :
488             config->buffer_limit = (size_t)(1024 * atoi(arg));
489             break;
490
491 /* *************************************************************************
492  * confdir directory-name
493  * *************************************************************************/
494          case hash_confdir :
495             freez(config->confdir);
496             config->confdir = make_path( NULL, arg);
497             break;
498
499 /* *************************************************************************
500  * connection-sharing (0|1)
501  * *************************************************************************/
502 #ifdef FEATURE_CONNECTION_SHARING
503          case hash_connection_sharing :
504             if ((*arg != '\0') && (0 != atoi(arg)))
505             {
506                config->feature_flags |= RUNTIME_FEATURE_CONNECTION_SHARING;
507             }
508             else
509             {
510                config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_SHARING;
511             }
512             break;
513 #endif
514
515 /* *************************************************************************
516  * debug n
517  * Specifies debug level, multiple values are ORed together.
518  * *************************************************************************/
519          case hash_debug :
520             config->debug |= atoi(arg);
521             break;
522
523 /* *************************************************************************
524  * default-server-timeout timeout
525  * *************************************************************************/
526 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
527          case hash_default_server_timeout :
528             if (*arg != '\0')
529             {
530                int timeout = atoi(arg);
531                if (0 < timeout)
532                {
533                   config->default_server_timeout = (unsigned int)timeout;
534                }
535                else
536                {
537                   log_error(LOG_LEVEL_FATAL,
538                      "Invalid default-server-timeout value: %s", arg);
539                }
540             }
541             break;
542 #endif
543
544 /* *************************************************************************
545  * deny-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
546  * *************************************************************************/
547 #ifdef FEATURE_ACL
548          case hash_deny_access:
549             strlcpy(tmp, arg, sizeof(tmp));
550             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
551
552             if ((vec_count != 1) && (vec_count != 2))
553             {
554                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
555                      "deny-access directive in configuration file.");
556                string_append(&config->proxy_args,
557                   "<br>\nWARNING: Wrong number of parameters for "
558                   "deny-access directive in configuration file.<br><br>\n");
559                break;
560             }
561
562             /* allocate a new node */
563             cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
564
565             if (cur_acl == NULL)
566             {
567                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
568                /* Never get here - LOG_LEVEL_FATAL causes program exit */
569                break;
570             }
571             cur_acl->action = ACL_DENY;
572
573             if (acl_addr(vec[0], cur_acl->src) < 0)
574             {
575                log_error(LOG_LEVEL_ERROR, "Invalid source address, port or netmask "
576                   "for deny-access directive in configuration file: \"%s\"", vec[0]);
577                string_append(&config->proxy_args,
578                   "<br>\nWARNING: Invalid source address, port or netmask "
579                   "for deny-access directive in configuration file: \"");
580                string_append(&config->proxy_args,
581                   vec[0]);
582                string_append(&config->proxy_args,
583                   "\"<br><br>\n");
584                freez(cur_acl);
585                break;
586             }
587             if (vec_count == 2)
588             {
589                if (acl_addr(vec[1], cur_acl->dst) < 0)
590                {
591                   log_error(LOG_LEVEL_ERROR, "Invalid destination address, port or netmask "
592                      "for deny-access directive in configuration file: \"%s\"", vec[1]);
593                   string_append(&config->proxy_args,
594                      "<br>\nWARNING: Invalid destination address, port or netmask "
595                      "for deny-access directive in configuration file: \"");
596                   string_append(&config->proxy_args,
597                      vec[1]);
598                   string_append(&config->proxy_args,
599                      "\"<br><br>\n");
600                   freez(cur_acl);
601                   break;
602                }
603             }
604 #ifdef HAVE_RFC2553
605             else
606             {
607                cur_acl->wildcard_dst = 1;
608             }
609 #endif /* def HAVE_RFC2553 */
610
611             /*
612              * Add it to the list.  Note we reverse the list to get the
613              * behaviour the user expects.  With both the ACL and
614              * actions file, the last match wins.  However, the internal
615              * implementations are different:  The actions file is stored
616              * in the same order as the file, and scanned completely.
617              * With the ACL, we reverse the order as we load it, then
618              * when we scan it we stop as soon as we get a match.
619              */
620             cur_acl->next  = config->acl;
621             config->acl = cur_acl;
622
623             break;
624 #endif /* def FEATURE_ACL */
625
626 /* *************************************************************************
627  * enable-edit-actions 0|1
628  * *************************************************************************/
629 #ifdef FEATURE_CGI_EDIT_ACTIONS
630          case hash_enable_edit_actions:
631             if ((*arg != '\0') && (0 != atoi(arg)))
632             {
633                config->feature_flags |= RUNTIME_FEATURE_CGI_EDIT_ACTIONS;
634             }
635             else
636             {
637                config->feature_flags &= ~RUNTIME_FEATURE_CGI_EDIT_ACTIONS;
638             }
639             break;
640 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
641
642 /* *************************************************************************
643  * enable-remote-toggle 0|1
644  * *************************************************************************/
645 #ifdef FEATURE_TOGGLE
646          case hash_enable_remote_toggle:
647             if ((*arg != '\0') && (0 != atoi(arg)))
648             {
649                config->feature_flags |= RUNTIME_FEATURE_CGI_TOGGLE;
650             }
651             else
652             {
653                config->feature_flags &= ~RUNTIME_FEATURE_CGI_TOGGLE;
654             }
655             break;
656 #endif /* def FEATURE_TOGGLE */
657
658 /* *************************************************************************
659  * enable-remote-http-toggle 0|1
660  * *************************************************************************/
661          case hash_enable_remote_http_toggle:
662             if ((*arg != '\0') && (0 != atoi(arg)))
663             {
664                config->feature_flags |= RUNTIME_FEATURE_HTTP_TOGGLE;
665             }
666             else
667             {
668                config->feature_flags &= ~RUNTIME_FEATURE_HTTP_TOGGLE;
669             }
670             break;
671
672 /* *************************************************************************
673  * enforce-blocks 0|1
674  * *************************************************************************/
675          case hash_enforce_blocks:
676 #ifdef FEATURE_FORCE_LOAD
677             if ((*arg != '\0') && (0 != atoi(arg)))
678             {
679                config->feature_flags |= RUNTIME_FEATURE_ENFORCE_BLOCKS;
680             }
681             else
682             {
683                config->feature_flags &= ~RUNTIME_FEATURE_ENFORCE_BLOCKS;
684             }
685 #else
686             log_error(LOG_LEVEL_ERROR, "Ignoring directive 'enforce-blocks'. "
687                "FEATURE_FORCE_LOAD is disabled, blocks will always be enforced.");
688 #endif /* def FEATURE_FORCE_LOAD */
689             break;
690
691 /* *************************************************************************
692  * filterfile file-name
693  * In confdir by default.
694  * *************************************************************************/
695          case hash_filterfile :
696             i = 0;
697             while ((i < MAX_AF_FILES) && (NULL != config->re_filterfile[i]))
698             {
699                i++;
700             }
701
702             if (i >= MAX_AF_FILES)
703             {
704                log_error(LOG_LEVEL_FATAL, "Too many 'filterfile' directives in config file - limit is %d.\n"
705                   "(You can increase this limit by changing MAX_AF_FILES in project.h and recompiling).",
706                   MAX_AF_FILES);
707             }
708             config->re_filterfile_short[i] = strdup(arg);
709             config->re_filterfile[i] = make_path(config->confdir, arg);
710
711             break;
712
713 /* *************************************************************************
714  * forward url-pattern (.|http-proxy-host[:port])
715  * *************************************************************************/
716          case hash_forward:
717             strlcpy(tmp, arg, sizeof(tmp));
718             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
719
720             if (vec_count != 2)
721             {
722                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for forward "
723                      "directive in configuration file.");
724                string_append(&config->proxy_args,
725                   "<br>\nWARNING: Wrong number of parameters for "
726                   "forward directive in configuration file.");
727                break;
728             }
729
730             /* allocate a new node */
731             cur_fwd = zalloc(sizeof(*cur_fwd));
732             if (cur_fwd == NULL)
733             {
734                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
735                /* Never get here - LOG_LEVEL_FATAL causes program exit */
736                break;
737             }
738
739             cur_fwd->type = SOCKS_NONE;
740
741             /* Save the URL pattern */
742             if (create_url_spec(cur_fwd->url, vec[0]))
743             {
744                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward "
745                      "directive in configuration file.");
746                string_append(&config->proxy_args,
747                   "<br>\nWARNING: Bad URL specifier for "
748                   "forward directive in configuration file.");
749                break;
750             }
751
752             /* Parse the parent HTTP proxy host:port */
753             p = vec[1];
754
755             if (strcmp(p, ".") != 0)
756             {
757                cur_fwd->forward_port = 8000;
758                parse_forwarder_address(p, &cur_fwd->forward_host,
759                   &cur_fwd->forward_port);
760             }
761
762             /* Add to list. */
763             cur_fwd->next = config->forward;
764             config->forward = cur_fwd;
765
766             break;
767
768 /* *************************************************************************
769  * forward-socks4 url-pattern socks-proxy[:port] (.|http-proxy[:port])
770  * *************************************************************************/
771          case hash_forward_socks4:
772             strlcpy(tmp, arg, sizeof(tmp));
773             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
774
775             if (vec_count != 3)
776             {
777                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
778                      "forward-socks4 directive in configuration file.");
779                string_append(&config->proxy_args,
780                   "<br>\nWARNING: Wrong number of parameters for "
781                   "forward-socks4 directive in configuration file.");
782                break;
783             }
784
785             /* allocate a new node */
786             cur_fwd = zalloc(sizeof(*cur_fwd));
787             if (cur_fwd == NULL)
788             {
789                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
790                /* Never get here - LOG_LEVEL_FATAL causes program exit */
791                break;
792             }
793
794             cur_fwd->type = SOCKS_4;
795
796             /* Save the URL pattern */
797             if (create_url_spec(cur_fwd->url, vec[0]))
798             {
799                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4 "
800                      "directive in configuration file.");
801                string_append(&config->proxy_args,
802                   "<br>\nWARNING: Bad URL specifier for "
803                   "forward-socks4 directive in configuration file.");
804                break;
805             }
806
807             /* Parse the SOCKS proxy host[:port] */
808             p = vec[1];
809
810             /* XXX: This check looks like a bug. */
811             if (strcmp(p, ".") != 0)
812             {
813                cur_fwd->gateway_port = 1080;
814                parse_forwarder_address(p, &cur_fwd->gateway_host,
815                   &cur_fwd->gateway_port);
816             }
817
818             /* Parse the parent HTTP proxy host[:port] */
819             p = vec[2];
820
821             if (strcmp(p, ".") != 0)
822             {
823                cur_fwd->forward_port = 8000;
824                parse_forwarder_address(p, &cur_fwd->forward_host,
825                   &cur_fwd->forward_port);
826             }
827
828             /* Add to list. */
829             cur_fwd->next = config->forward;
830             config->forward = cur_fwd;
831
832             break;
833
834 /* *************************************************************************
835  * forward-socks4a url-pattern socks-proxy[:port] (.|http-proxy[:port])
836  * *************************************************************************/
837          case hash_forward_socks4a:
838          case hash_forward_socks5:
839             strlcpy(tmp, arg, sizeof(tmp));
840             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
841
842             if (vec_count != 3)
843             {
844                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
845                      "forward-socks4a directive in configuration file.");
846                string_append(&config->proxy_args,
847                   "<br>\nWARNING: Wrong number of parameters for "
848                   "forward-socks4a directive in configuration file.");
849                break;
850             }
851
852             /* allocate a new node */
853             cur_fwd = zalloc(sizeof(*cur_fwd));
854             if (cur_fwd == NULL)
855             {
856                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
857                /* Never get here - LOG_LEVEL_FATAL causes program exit */
858                break;
859             }
860
861             if (directive_hash == hash_forward_socks4a)
862             {
863                cur_fwd->type = SOCKS_4A;
864             }
865             else
866             {
867                cur_fwd->type = SOCKS_5;
868             }
869
870             /* Save the URL pattern */
871             if (create_url_spec(cur_fwd->url, vec[0]))
872             {
873                log_error(LOG_LEVEL_ERROR, "Bad URL specifier for forward-socks4a "
874                      "directive in configuration file.");
875                string_append(&config->proxy_args,
876                   "<br>\nWARNING: Bad URL specifier for "
877                   "forward-socks4a directive in configuration file.");
878                break;
879             }
880
881             /* Parse the SOCKS proxy host[:port] */
882             p = vec[1];
883
884             cur_fwd->gateway_port = 1080;
885             parse_forwarder_address(p, &cur_fwd->gateway_host,
886                &cur_fwd->gateway_port);
887
888             /* Parse the parent HTTP proxy host[:port] */
889             p = vec[2];
890
891             if (strcmp(p, ".") != 0)
892             {
893                cur_fwd->forward_port = 8000;
894                parse_forwarder_address(p, &cur_fwd->forward_host,
895                   &cur_fwd->forward_port);
896             }
897
898             /* Add to list. */
899             cur_fwd->next = config->forward;
900             config->forward = cur_fwd;
901
902             break;
903
904 /* *************************************************************************
905  * forwarded-connect-retries n
906  * *************************************************************************/
907          case hash_forwarded_connect_retries :
908             config->forwarded_connect_retries = atoi(arg);
909             break;
910
911 /* *************************************************************************
912  * handle-as-empty-doc-returns-ok 0|1
913  *
914  * Workaround for firefox hanging on blocked javascript pages.
915  *   Block with the "+handle-as-empty-document" flag and set the
916  *   "handle-as-empty-doc-returns-ok" run-time config flag so that
917  *   Privoxy returns a 200/OK status instead of a 403/Forbidden status
918  *   to the browser for blocked pages.
919  ***************************************************************************/
920          case hash_handle_as_empty_returns_ok:
921             if ((*arg != '\0') && (0 != atoi(arg)))
922             {
923                config->feature_flags |= RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK;
924             }
925             else
926             {
927                config->feature_flags &= ~RUNTIME_FEATURE_EMPTY_DOC_RETURNS_OK;
928             }
929             break;
930
931 /* *************************************************************************
932  * hostname hostname-to-show-on-cgi-pages
933  * *************************************************************************/
934          case hash_hostname :
935             freez(config->hostname);
936             config->hostname = strdup(arg);
937             if (NULL == config->hostname)
938             {
939                log_error(LOG_LEVEL_FATAL, "Out of memory saving hostname.");
940             }
941             break;
942
943 /* *************************************************************************
944  * keep-alive-timeout timeout
945  * *************************************************************************/
946 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
947          case hash_keep_alive_timeout :
948             if (*arg != '\0')
949             {
950                int timeout = atoi(arg);
951                if (0 < timeout)
952                {
953                   config->feature_flags |= RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
954                   config->keep_alive_timeout = (unsigned int)timeout;
955                }
956                else
957                {
958                   config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
959                }
960             }
961             break;
962 #endif
963
964 /* *************************************************************************
965  * listen-address [ip][:port]
966  * *************************************************************************/
967          case hash_listen_address :
968             freez(config->haddr);
969             config->haddr = strdup(arg);
970             break;
971
972 /* *************************************************************************
973  * logdir directory-name
974  * *************************************************************************/
975          case hash_logdir :
976             freez(config->logdir);
977             config->logdir = make_path(NULL, arg);
978             break;
979
980 /* *************************************************************************
981  * logfile log-file-name
982  * In logdir by default
983  * *************************************************************************/
984          case hash_logfile :
985             if (daemon_mode)
986             {
987                logfile = make_path(config->logdir, arg);
988                if (NULL == logfile)
989                {
990                   log_error(LOG_LEVEL_FATAL, "Out of memory while creating logfile path");
991                }
992             }
993             break;
994
995 /* *************************************************************************
996  * max-client-connections number
997  * *************************************************************************/
998          case hash_max_client_connections :
999             if (*arg != '\0')
1000             {
1001                int max_client_connections = atoi(arg);
1002                if (0 <= max_client_connections)
1003                {
1004                   config->max_client_connections = max_client_connections;
1005                }
1006             }
1007             break;
1008
1009 /* *************************************************************************
1010  * permit-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
1011  * *************************************************************************/
1012 #ifdef FEATURE_ACL
1013          case hash_permit_access:
1014             strlcpy(tmp, arg, sizeof(tmp));
1015             vec_count = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
1016
1017             if ((vec_count != 1) && (vec_count != 2))
1018             {
1019                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
1020                      "permit-access directive in configuration file.");
1021                string_append(&config->proxy_args,
1022                   "<br>\nWARNING: Wrong number of parameters for "
1023                   "permit-access directive in configuration file.<br><br>\n");
1024
1025                break;
1026             }
1027
1028             /* allocate a new node */
1029             cur_acl = (struct access_control_list *) zalloc(sizeof(*cur_acl));
1030
1031             if (cur_acl == NULL)
1032             {
1033                log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
1034                /* Never get here - LOG_LEVEL_FATAL causes program exit */
1035                break;
1036             }
1037             cur_acl->action = ACL_PERMIT;
1038
1039             if (acl_addr(vec[0], cur_acl->src) < 0)
1040             {
1041                log_error(LOG_LEVEL_ERROR, "Invalid source address, port or netmask "
1042                   "for permit-access directive in configuration file: \"%s\"", vec[0]);
1043                string_append(&config->proxy_args,
1044                   "<br>\nWARNING: Invalid source address, port or netmask for "
1045                   "permit-access directive in configuration file: \"");
1046                string_append(&config->proxy_args,
1047                   vec[0]);
1048                string_append(&config->proxy_args,
1049                   "\"<br><br>\n");
1050                freez(cur_acl);
1051                break;
1052             }
1053             if (vec_count == 2)
1054             {
1055                if (acl_addr(vec[1], cur_acl->dst) < 0)
1056                {
1057                   log_error(LOG_LEVEL_ERROR, "Invalid destination address, port or netmask "
1058                      "for permit-access directive in configuration file: \"%s\"", vec[1]);
1059                   string_append(&config->proxy_args,
1060                      "<br>\nWARNING: Invalid destination address, port or netmask for "
1061                      "permit-access directive in configuration file: \"");
1062                   string_append(&config->proxy_args,
1063                      vec[1]);
1064                   string_append(&config->proxy_args,
1065                      "\"<br><br>\n");
1066                   freez(cur_acl);
1067                   break;
1068                }
1069             }
1070 #ifdef HAVE_RFC2553
1071             else
1072             {
1073                cur_acl->wildcard_dst = 1;
1074             }
1075 #endif /* def HAVE_RFC2553 */
1076
1077             /*
1078              * Add it to the list.  Note we reverse the list to get the
1079              * behaviour the user expects.  With both the ACL and
1080              * actions file, the last match wins.  However, the internal
1081              * implementations are different:  The actions file is stored
1082              * in the same order as the file, and scanned completely.
1083              * With the ACL, we reverse the order as we load it, then
1084              * when we scan it we stop as soon as we get a match.
1085              */
1086             cur_acl->next  = config->acl;
1087             config->acl = cur_acl;
1088
1089             break;
1090 #endif /* def FEATURE_ACL */
1091
1092 /* *************************************************************************
1093  * proxy-info-url url
1094  * *************************************************************************/
1095          case hash_proxy_info_url :
1096             freez(config->proxy_info_url);
1097             config->proxy_info_url = strdup(arg);
1098             break;
1099
1100 /* *************************************************************************
1101  * single-threaded
1102  * *************************************************************************/
1103          case hash_single_threaded :
1104             config->multi_threaded = 0;
1105             break;
1106
1107 /* *************************************************************************
1108  * socket-timeout numer_of_seconds
1109  * *************************************************************************/
1110          case hash_socket_timeout :
1111             if (*arg != '\0')
1112             {
1113                int socket_timeout = atoi(arg);
1114                if (0 < socket_timeout)
1115                {
1116                   config->socket_timeout = socket_timeout;
1117                }
1118                else
1119                {
1120                   log_error(LOG_LEVEL_FATAL,
1121                      "Invalid socket-timeout: '%s'", arg);
1122                }
1123             }
1124             break;
1125
1126 /* *************************************************************************
1127  * split-large-cgi-forms
1128  * *************************************************************************/
1129          case hash_split_large_cgi_forms :
1130             if ((*arg != '\0') && (0 != atoi(arg)))
1131             {
1132                config->feature_flags |= RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
1133             }
1134             else
1135             {
1136                config->feature_flags &= ~RUNTIME_FEATURE_SPLIT_LARGE_FORMS;
1137             }
1138             break;
1139
1140 /* *************************************************************************
1141  * templdir directory-name
1142  * *************************************************************************/
1143          case hash_templdir :
1144             freez(config->templdir);
1145             config->templdir = make_path(NULL, arg);
1146             break;
1147
1148 /* *************************************************************************
1149  * toggle (0|1)
1150  * *************************************************************************/
1151 #ifdef FEATURE_TOGGLE
1152          case hash_toggle :
1153             global_toggle_state = atoi(arg);
1154             break;
1155 #endif /* def FEATURE_TOGGLE */
1156
1157 /* *************************************************************************
1158  * trust-info-url url
1159  * *************************************************************************/
1160 #ifdef FEATURE_TRUST
1161          case hash_trust_info_url :
1162             enlist(config->trust_info, arg);
1163             break;
1164 #endif /* def FEATURE_TRUST */
1165
1166 /* *************************************************************************
1167  * trustfile filename
1168  * (In confdir by default.)
1169  * *************************************************************************/
1170 #ifdef FEATURE_TRUST
1171          case hash_trustfile :
1172             freez(config->trustfile);
1173             config->trustfile = make_path(config->confdir, arg);
1174             break;
1175 #endif /* def FEATURE_TRUST */
1176
1177 /* *************************************************************************
1178  * usermanual url
1179  * *************************************************************************/
1180          case hash_usermanual :
1181             /*
1182              * XXX: If this isn't the first config directive, the
1183              * show-status page links to the website documentation
1184              * for the directives that were already parsed. Lame.
1185              */
1186             freez(config->usermanual);
1187             config->usermanual = strdup(arg);
1188             break;
1189
1190 /* *************************************************************************
1191  * Win32 Console options:
1192  * *************************************************************************/
1193
1194 /* *************************************************************************
1195  * hide-console
1196  * *************************************************************************/
1197 #ifdef _WIN_CONSOLE
1198          case hash_hide_console :
1199             hideConsole = 1;
1200             break;
1201 #endif /*def _WIN_CONSOLE*/
1202
1203
1204 /* *************************************************************************
1205  * Win32 GUI options:
1206  * *************************************************************************/
1207
1208 #if defined(_WIN32) && ! defined(_WIN_CONSOLE)
1209 /* *************************************************************************
1210  * activity-animation (0|1)
1211  * *************************************************************************/
1212          case hash_activity_animation :
1213             g_bShowActivityAnimation = atoi(arg);
1214             break;
1215
1216 /* *************************************************************************
1217  *  close-button-minimizes (0|1)
1218  * *************************************************************************/
1219          case hash_close_button_minimizes :
1220             g_bCloseHidesWindow = atoi(arg);
1221             break;
1222
1223 /* *************************************************************************
1224  * log-buffer-size (0|1)
1225  * *************************************************************************/
1226          case hash_log_buffer_size :
1227             g_bLimitBufferSize = atoi(arg);
1228             break;
1229
1230 /* *************************************************************************
1231  * log-font-name fontname
1232  * *************************************************************************/
1233          case hash_log_font_name :
1234             if (strlcpy(g_szFontFaceName, arg,
1235                    sizeof(g_szFontFaceName)) >= sizeof(g_szFontFaceName))
1236             {
1237                log_error(LOG_LEVEL_FATAL,
1238                   "log-font-name argument '%s' is longer than %u characters.",
1239                   arg, sizeof(g_szFontFaceName)-1);
1240             }
1241             break;
1242
1243 /* *************************************************************************
1244  * log-font-size n
1245  * *************************************************************************/
1246          case hash_log_font_size :
1247             g_nFontSize = atoi(arg);
1248             break;
1249
1250 /* *************************************************************************
1251  * log-highlight-messages (0|1)
1252  * *************************************************************************/
1253          case hash_log_highlight_messages :
1254             g_bHighlightMessages = atoi(arg);
1255             break;
1256
1257 /* *************************************************************************
1258  * log-max-lines n
1259  * *************************************************************************/
1260          case hash_log_max_lines :
1261             g_nMaxBufferLines = atoi(arg);
1262             break;
1263
1264 /* *************************************************************************
1265  * log-messages (0|1)
1266  * *************************************************************************/
1267          case hash_log_messages :
1268             g_bLogMessages = atoi(arg);
1269             break;
1270
1271 /* *************************************************************************
1272  * show-on-task-bar (0|1)
1273  * *************************************************************************/
1274          case hash_show_on_task_bar :
1275             g_bShowOnTaskBar = atoi(arg);
1276             break;
1277
1278 #endif /* defined(_WIN32) && ! defined(_WIN_CONSOLE) */
1279
1280
1281 /* *************************************************************************
1282  * Warnings about unsupported features
1283  * *************************************************************************/
1284 #ifndef FEATURE_ACL
1285          case hash_deny_access:
1286 #endif /* ndef FEATURE_ACL */
1287 #ifndef FEATURE_CGI_EDIT_ACTIONS
1288          case hash_enable_edit_actions:
1289 #endif /* ndef FEATURE_CGI_EDIT_ACTIONS */
1290 #ifndef FEATURE_TOGGLE
1291          case hash_enable_remote_toggle:
1292 #endif /* ndef FEATURE_TOGGLE */
1293 #ifndef FEATURE_ACL
1294          case hash_permit_access:
1295 #endif /* ndef FEATURE_ACL */
1296 #ifndef FEATURE_TOGGLE
1297          case hash_toggle :
1298 #endif /* ndef FEATURE_TOGGLE */
1299 #ifndef FEATURE_TRUST
1300          case hash_trustfile :
1301          case hash_trust_info_url :
1302 #endif /* ndef FEATURE_TRUST */
1303
1304 #ifndef _WIN_CONSOLE
1305          case hash_hide_console :
1306 #endif /* ndef _WIN_CONSOLE */
1307
1308 #if defined(_WIN_CONSOLE) || ! defined(_WIN32)
1309          case hash_activity_animation :
1310          case hash_close_button_minimizes :
1311          case hash_log_buffer_size :
1312          case hash_log_font_name :
1313          case hash_log_font_size :
1314          case hash_log_highlight_messages :
1315          case hash_log_max_lines :
1316          case hash_log_messages :
1317          case hash_show_on_task_bar :
1318 #endif /* defined(_WIN_CONSOLE) || ! defined(_WIN32) */
1319             /* These warnings are annoying - so hide them. -- Jon */
1320             /* log_error(LOG_LEVEL_INFO, "Unsupported directive \"%s\" ignored.", cmd); */
1321             break;
1322
1323 /* *************************************************************************/
1324          default :
1325 /* *************************************************************************/
1326             /*
1327              * I decided that I liked this better as a warning than an
1328              * error.  To change back to an error, just change log level
1329              * to LOG_LEVEL_FATAL.
1330              */
1331             log_error(LOG_LEVEL_ERROR, "Ignoring unrecognized directive '%s' (%luul) in line %lu "
1332                   "in configuration file (%s).",  buf, directive_hash, linenum, configfile);
1333             string_append(&config->proxy_args,
1334                " <strong class='warning'>Warning: Ignoring unrecognized directive:</strong>");
1335             break;
1336
1337 /* *************************************************************************/
1338       } /* end switch( hash_string(cmd) ) */
1339
1340       /* Save the argument for the show-status page. */
1341       savearg(cmd, arg, config);
1342
1343    } /* end while ( read_config_line(...) ) */
1344
1345    fclose(configfp);
1346
1347    set_debug_level(config->debug);
1348
1349    freez(config->logfile);
1350
1351    if (daemon_mode)
1352    {
1353       if (NULL != logfile)
1354       {
1355          config->logfile = logfile;
1356          init_error_log(Argv[0], config->logfile);
1357       }
1358       else
1359       {
1360          disable_logging();
1361       }
1362    }
1363
1364 #ifdef FEATURE_CONNECTION_KEEP_ALIVE
1365    if (config->default_server_timeout > config->keep_alive_timeout)
1366    {
1367       log_error(LOG_LEVEL_ERROR,
1368          "Reducing the default-server-timeout from %d to the keep-alive-timeout %d.",
1369          config->default_server_timeout, config->keep_alive_timeout);
1370       config->default_server_timeout = config->keep_alive_timeout;
1371    }
1372 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
1373
1374 #ifdef FEATURE_CONNECTION_SHARING
1375    if (config->feature_flags & RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE)
1376    {
1377       if (config->multi_threaded)
1378       {
1379          set_keep_alive_timeout(config->keep_alive_timeout);
1380       }
1381       else
1382       {
1383          /*
1384           * While we could use keep-alive without multiple threads
1385           * if we didn't bother with enforcing the connection timeout,
1386           * that might make Tor users sad, even though they shouldn't
1387           * enable the single-threaded option anyway.
1388           *
1389           * XXX: We could still use Proxy-Connection: keep-alive.
1390           */
1391          config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_KEEP_ALIVE;
1392          log_error(LOG_LEVEL_ERROR,
1393             "Config option single-threaded disables connection keep-alive.");
1394       }
1395    }
1396    else if ((config->feature_flags & RUNTIME_FEATURE_CONNECTION_SHARING))
1397    {
1398       log_error(LOG_LEVEL_ERROR, "Config option connection-sharing "
1399          "has no effect if keep-alive-timeout isn't set.");
1400       config->feature_flags &= ~RUNTIME_FEATURE_CONNECTION_SHARING;
1401    }
1402 #endif /* def FEATURE_CONNECTION_SHARING */
1403
1404    if (NULL == config->proxy_args)
1405    {
1406       log_error(LOG_LEVEL_FATAL, "Out of memory loading config - insufficient memory for config->proxy_args");
1407    }
1408
1409    if (config->actions_file[0])
1410    {
1411       add_loader(load_action_files, config);
1412    }
1413
1414    if (config->re_filterfile[0])
1415    {
1416       add_loader(load_re_filterfiles, config);
1417    }
1418
1419 #ifdef FEATURE_TRUST
1420    if (config->trustfile)
1421    {
1422       add_loader(load_trustfile, config);
1423    }
1424 #endif /* def FEATURE_TRUST */
1425
1426    if ( NULL == config->haddr )
1427    {
1428       config->haddr = strdup( HADDR_DEFAULT );
1429    }
1430
1431    if ( NULL != config->haddr )
1432    {
1433       if ((*config->haddr == '[')
1434          && (NULL != (p = strchr(config->haddr, ']')))
1435          && (p[1] == ':')
1436          && (0 < (config->hport = atoi(p + 2))))
1437       {
1438          *p = '\0';
1439          memmove((void *)config->haddr, config->haddr + 1,
1440             (size_t)(p - config->haddr));
1441       }
1442       else if (NULL != (p = strchr(config->haddr, ':'))
1443          && (0 < (config->hport = atoi(p + 1))))
1444       {
1445          *p = '\0';
1446       }
1447       else
1448       {
1449          log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
1450          /* Never get here - LOG_LEVEL_FATAL causes program exit */
1451       }
1452       if (*config->haddr == '\0')
1453       {
1454          /*
1455           * Only the port specified. We stored it in config->hport
1456           * and don't need its text representation anymore.
1457           */
1458          freez(config->haddr);
1459       }
1460    }
1461
1462    /*
1463     * Want to run all the loaders once now.
1464     *
1465     * Need to set up a fake csp, so they can get to the config.
1466     */
1467    fake_csp = (struct client_state *) zalloc (sizeof(*fake_csp));
1468    fake_csp->config = config;
1469
1470    if (run_loader(fake_csp))
1471    {
1472       freez(fake_csp);
1473       log_error(LOG_LEVEL_FATAL, "A loader failed while loading config file. Exiting.");
1474       /* Never get here - LOG_LEVEL_FATAL causes program exit */
1475    }
1476    freez(fake_csp);
1477
1478 /* FIXME: this is a kludge for win32 */
1479 #if defined(_WIN32) && !defined (_WIN_CONSOLE)
1480
1481    g_default_actions_file = config->actions_file[1]; /* FIXME Hope this is default.action */
1482    g_user_actions_file = config->actions_file[2]; /* FIXME Hope this is user.action */
1483    g_re_filterfile    = config->re_filterfile[0]; /* FIXME Hope this is default.filter */
1484
1485 #ifdef FEATURE_TRUST
1486    g_trustfile        = config->trustfile;
1487 #endif /* def FEATURE_TRUST */
1488
1489
1490 #endif /* defined(_WIN32) && !defined (_WIN_CONSOLE) */
1491 /* FIXME: end kludge */
1492
1493
1494    config->need_bind = 1;
1495
1496    if (current_configfile)
1497    {
1498       struct configuration_spec * oldcfg = (struct configuration_spec *)
1499                                            current_configfile->f;
1500       /*
1501        * Check if config->haddr,hport == oldcfg->haddr,hport
1502        *
1503        * The following could be written more compactly as a single,
1504        * (unreadably long) if statement.
1505        */
1506       config->need_bind = 0;
1507       if (config->hport != oldcfg->hport)
1508       {
1509          config->need_bind = 1;
1510       }
1511       else if (config->haddr == NULL)
1512       {
1513          if (oldcfg->haddr != NULL)
1514          {
1515             config->need_bind = 1;
1516          }
1517       }
1518       else if (oldcfg->haddr == NULL)
1519       {
1520          config->need_bind = 1;
1521       }
1522       else if (0 != strcmp(config->haddr, oldcfg->haddr))
1523       {
1524          config->need_bind = 1;
1525       }
1526
1527       current_configfile->unloader = unload_configfile;
1528    }
1529
1530    fs->next = files->next;
1531    files->next = fs;
1532
1533    current_configfile = fs;
1534
1535    return (config);
1536 }
1537
1538
1539 /*********************************************************************
1540  *
1541  * Function    :  savearg
1542  *
1543  * Description :  Called from `load_config'.  It saves each non-empty
1544  *                and non-comment line from config into
1545  *                config->proxy_args.  This is used to create the
1546  *                show-proxy-args page.  On error, frees
1547  *                config->proxy_args and sets it to NULL
1548  *
1549  * Parameters  :
1550  *          1  :  command = config setting that was found
1551  *          2  :  argument = the setting's argument (if any)
1552  *          3  :  config = Configuration to save into.
1553  *
1554  * Returns     :  N/A
1555  *
1556  *********************************************************************/
1557 static void savearg(char *command, char *argument, struct configuration_spec * config)
1558 {
1559    char * buf;
1560    char * s;
1561
1562    assert(command);
1563    assert(argument);
1564
1565    /*
1566     * Add config option name embedded in
1567     * link to its section in the user-manual
1568     */
1569    buf = strdup("\n<a href=\"");
1570    if (!strncmpic(config->usermanual, "file://", 7) ||
1571        !strncmpic(config->usermanual, "http", 4))
1572    {
1573       string_append(&buf, config->usermanual);
1574    }
1575    else
1576    {
1577       string_append(&buf, "http://" CGI_SITE_2_HOST "/user-manual/");
1578    }
1579    string_append(&buf, CONFIG_HELP_PREFIX);
1580    string_join  (&buf, string_toupper(command));
1581    string_append(&buf, "\">");
1582    string_append(&buf, command);
1583    string_append(&buf, "</a> ");
1584
1585    if (NULL == buf)
1586    {
1587       freez(config->proxy_args);
1588       return;
1589    }
1590
1591    if ( (NULL != argument) && ('\0' != *argument) )
1592    {
1593       s = html_encode(argument);
1594       if (NULL == s)
1595       {
1596          freez(buf);
1597          freez(config->proxy_args);
1598          return;
1599       }
1600
1601       if (strncmpic(argument, "http://", 7) == 0)
1602       {
1603          string_append(&buf, "<a href=\"");
1604          string_append(&buf, s);
1605          string_append(&buf, "\">");
1606          string_join  (&buf, s);
1607          string_append(&buf, "</a>");
1608       }
1609       else
1610       {
1611          string_join  (&buf, s);
1612       }
1613    }
1614
1615    string_append(&buf, "<br>");
1616    string_join(&config->proxy_args, buf);
1617 }
1618
1619
1620 /*
1621   Local Variables:
1622   tab-width: 3
1623   end:
1624 */