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