Filled in a function comment.
[privoxy.git] / loadcfg.c
index e85f47e..82bd916 100644 (file)
--- a/loadcfg.c
+++ b/loadcfg.c
@@ -1,4 +1,4 @@
-const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.3 2001/05/20 01:21:20 jongfoster Exp $";
+const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.5 2001/05/25 22:34:30 jongfoster Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/loadcfg.c,v $
@@ -35,6 +35,53 @@ const char loadcfg_rcs[] = "$Id: loadcfg.c,v 1.3 2001/05/20 01:21:20 jongfoster
  *
  * Revisions   :
  *    $Log: loadcfg.c,v $
+ *    Revision 1.5  2001/05/25 22:34:30  jongfoster
+ *    Hard tabs->Spaces
+ *
+ *    Revision 1.4  2001/05/22 18:46:04  oes
+ *
+ *    - Enabled filtering banners by size rather than URL
+ *      by adding patterns that replace all standard banner
+ *      sizes with the "Junkbuster" gif to the re_filterfile
+ *
+ *    - Enabled filtering WebBugs by providing a pattern
+ *      which kills all 1x1 images
+ *
+ *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
+ *      which is selected by the (nonstandard and therefore
+ *      capital) letter 'U' in the option string.
+ *      It causes the quantifiers to be ungreedy by default.
+ *      Appending a ? turns back to greedy (!).
+ *
+ *    - Added a new interceptor ijb-send-banner, which
+ *      sends back the "Junkbuster" gif. Without imagelist or
+ *      MSIE detection support, or if tinygif = 1, or the
+ *      URL isn't recognized as an imageurl, a lame HTML
+ *      explanation is sent instead.
+ *
+ *    - Added new feature, which permits blocking remote
+ *      script redirects and firing back a local redirect
+ *      to the browser.
+ *      The feature is conditionally compiled, i.e. it
+ *      can be disabled with --disable-fast-redirects,
+ *      plus it must be activated by a "fast-redirects"
+ *      line in the config file, has its own log level
+ *      and of course wants to be displayed by show-proxy-args
+ *      Note: Boy, all the #ifdefs in 1001 locations and
+ *      all the fumbling with configure.in and acconfig.h
+ *      were *way* more work than the feature itself :-(
+ *
+ *    - Because a generic redirect template was needed for
+ *      this, tinygif = 3 now uses the same.
+ *
+ *    - Moved GIFs, and other static HTTP response templates
+ *      to project.h
+ *
+ *    - Some minor fixes
+ *
+ *    - Removed some >400 CRs again (Jon, you really worked
+ *      a lot! ;-)
+ *
  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
  *    Version 2.9.4 checkin.
  *    - Merged popupfile and cookiefile, and added control over PCRS
@@ -133,96 +180,19 @@ static const char VANILLA_WAFER[] =
 int g_bToggleIJB        = 1;   /* JunkBusters is enabled by default. */
 #endif
 
-int debug               = 0;
-int multi_threaded      = 1;
-
-#if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST)
-int tinygif             = 0;
-const char *tinygifurl  = NULL;
-#endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */
-
-const char *logfile     = NULL;
-
+/* The filename of the configfile */
 const char *configfile  = NULL;
 
-const char *blockfile   = NULL;
-const char *permissions_file  = NULL;
-const char *forwardfile = NULL;
-
-#ifdef ACL_FILES
-const char *aclfile     = NULL;
-#endif /* def ACL_FILES */
-
-#ifdef USE_IMAGE_LIST
-const char *imagefile   = NULL;
-#endif /* def USE_IMAGE_LIST */
-
-/*
- * Permissions to use for URLs not in the permissions list.
- */
-int default_permissions = PERMIT_RE_FILTER;
-
-#ifdef PCRS
-const char *re_filterfile = NULL;
-#endif /* def PCRS */
-
-#ifdef FAST_REDIRECTS
-int fast_redirects = 0;
-#endif /* def FAST_REDIRECTS */
-
-#ifdef TRUST_FILES
-const char *trustfile   = NULL;
-#endif /* def TRUST_FILES */
-
-#ifdef JAR_FILES
-const char *jarfile     = NULL;
-FILE *jar = NULL;
-#endif /* def JAR_FILES */
-
-const char *referrer    = NULL;
-const char *uagent      = NULL;
-const char *from        = NULL;
-
-#ifndef SPLIT_PROXY_ARGS
-const char *suppress_message = NULL;
-#endif /* ndef SPLIT_PROXY_ARGS */
-
-int suppress_vanilla_wafer = 0;
-int add_forwarded          = 0;
-
-struct list wafer_list[1];
-struct list xtra_list[1];
-
-#ifdef TRUST_FILES
-struct list trust_info[1];
-struct url_spec *trust_list[64];
-#endif /* def TRUST_FILES */
-
-/*
- * Port and IP to bind to.
- * Defaults to HADDR_DEFAULT:HADDR_PORT == 127.0.0.1:8000
- */
-const char *haddr = NULL;
-int         hport = 0;
-
-#ifndef SPLIT_PROXY_ARGS
-int suppress_blocklists = 0;  /* suppress listing sblock and simage */
-#endif /* ndef SPLIT_PROXY_ARGS */
-
-struct proxy_args proxy_args[1];
-
-int configret = 0;
-int config_changed = 0;
-
-
 /*
  * The load_config function is now going to call `init_proxy_args',
- * so it will need argc and argv.  Since load_config will also be
- * a signal handler, we need to have these globally available.
+ * so it will need argc and argv.  So we need to have these
+ * globally available.
  */
 int Argc = 0;
 const char **Argv = NULL;
 
+static struct file_list *current_configfile = NULL;
+
 
 /*
  * This takes the "cryptic" hash of each keyword and aliases them to
@@ -272,561 +242,572 @@ const char **Argv = NULL;
 #define hash_close_button_minimizes    3651284693ul
 
 
+
 /*********************************************************************
  *
- * Function    :  load_config
+ * Function    :  unload_configfile
  *
- * Description :  Load the config file and all parameters.
+ * Description :  Free the config structure and all components.
  *
  * Parameters  :
- *          1  :  signum : this can be the signal SIGHUP or 0 (if from main).
- *                In any case, we just ignore this and reload the config file.
+ *          1  :  data: struct configuration_spec to unload
  *
- * Returns     :  configret : 0 => Ok, everything else is an error.
- *                Note: we use configret since a signal handler cannot
- *                return a value, and this function does double duty.
- *                Ie. Is is called from main and from signal( SIGHUP );
+ * Returns     :  N/A
  *
  *********************************************************************/
-void load_config( int signum )
+void unload_configfile (void * data)
 {
-   char buf[BUFSIZ];
-   char *p, *q;
-   FILE *configfp = NULL;
-
-   configret = 0; /* FIXME: This is obsolete, always 0. */
-   config_changed = 1;
-
-   log_error(LOG_LEVEL_INFO, "loading configuration file '%s':", configfile);
-
-   init_proxy_args(Argc, Argv);
-
-
-   /* (Waste of memory [not quite a "leak"] here.  The 
-    * last blockfile/permissions file/... etc will not be 
-    * unloaded until we load a new one.  If the 
-    * block/... feature has been disabled in 
-    * the new config file, then we're wasting some 
-    * memory we could otherwise reclaim.
-    */
-
-   /* Disable all loaders. */
-   remove_all_loaders();
-
-   /*
-    * Reset to as close to startup state as we can.
-    * But leave changing the logfile until after we're done loading.
-    */
+   struct configuration_spec * config = (struct configuration_spec *)data;
 
 #ifdef JAR_FILES
-   if ( NULL != jar )
+   if ( NULL != config->jar )
    {
-      fclose( jar );
-      jar = NULL;
+      fclose( config->jar );
+      config->jar = NULL;
    }
 #endif /* def JAR_FILES */
-
-   debug             = 0;
-   multi_threaded    = 1;
-
-   default_permissions = PERMIT_RE_FILTER;
-
 #if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST)
-   tinygif           = 0;
-   freez((char *)tinygifurl);
+   freez((char *)config->tinygifurl);
 #endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */
 
-   suppress_vanilla_wafer = 0;
-   add_forwarded     = 0;
-   hport             = HADDR_PORT;
-
-#ifdef _WIN_CONSOLE
-   hideConsole       = 0;
-#endif /*def _WIN_CONSOLE*/
-
-#ifdef TOGGLE
-   g_bToggleIJB      = 1;
-#endif
+   freez((char *)config->from);
+   freez((char *)config->haddr);
+   freez((char *)config->uagent);
+   freez((char *)config->referrer);
+   freez((char *)config->logfile);
 
-#ifdef STATISTICS
-   urls_read         = 0;
-   urls_rejected     = 0;
-#endif /* def STATISTICS */
-
-#ifndef SPLIT_PROXY_ARGS
-   suppress_blocklists = 0;
-#endif /* ndef SPLIT_PROXY_ARGS */
-
-   freez((char *)from);
-   freez((char *)haddr);
-   freez((char *)uagent);
-   freez((char *)referrer);
-   freez((char *)logfile);
-
-
-   freez((char *)blockfile);
-   freez((char *)permissions_file);
-   freez((char *)forwardfile);
+   freez((char *)config->blockfile);
+   freez((char *)config->permissions_file);
+   freez((char *)config->forwardfile);
 
 #ifdef ACL_FILES
-   freez((char *)aclfile);
+   freez((char *)config->aclfile);
 #endif /* def ACL_FILES */
 
 #ifdef USE_IMAGE_LIST
-   freez((char *)imagefile);
+   freez((char *)config->imagefile);
 #endif /* def USE_IMAGE_LIST */
 
 #ifdef JAR_FILES
-   freez((char *)jarfile);
+   freez((char *)config->jarfile);
 #endif /* def JAR_FILES */
 
 #ifndef SPLIT_PROXY_ARGS
-   freez((char *)suppress_message);
+   freez((char *)config->suppress_message);
 #endif /* ndef SPLIT_PROXY_ARGS */
 
-#ifdef TRUST_FILES
-   freez((char *)trustfile);
-#endif /* def TRUST_FILES */
-
 #ifdef PCRS
-   freez((char *)re_filterfile);
+   freez((char *)config->re_filterfile);
 #endif /* def PCRS */
 
-#ifdef FAST_REDIRECTS
-   fast_redirects = 0;
-#endif /* def FAST_REDIRECTS */
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  load_config
+ *
+ * Description :  Load the config file and all parameters.
+ *
+ * Parameters  :
+ *          1  :  csp = Client state (the config member will be 
+ *                filled in by this function).
+ *
+ * Returns     :  0 => Ok, everything else is an error.
+ *
+ *********************************************************************/
+struct configuration_spec * load_config(void)
+{
+   char buf[BUFSIZ];
+   char *p, *q;
+   FILE *configfp = NULL;
+   struct configuration_spec * config = NULL;
+   int suppress_vanilla_wafer;
+   struct client_state * fake_csp;
+
+   struct file_list *fs;
 
-   if (NULL != configfile)
+   if (!check_file_changed(current_configfile, configfile, &fs))
    {
-      if ((configfp = fopen(configfile, "r")) == NULL)
-      {
-         log_error(LOG_LEVEL_FATAL, "can't open configuration file '%s':  %E",
-                 configfile);
-         /* Never get here - LOG_LEVEL_FATAL causes program exit */
-      }
+      /* No need to load */
+      return ((struct configuration_spec *)current_configfile->f);
+   }
+   if (!fs)
+   {
+      log_error(LOG_LEVEL_FATAL, "can't check configuration file '%s':  %E",
+                configfile);
    }
 
-   if (NULL != configfp)
+   log_error(LOG_LEVEL_INFO, "loading configuration file '%s':", configfile);
+
+#ifdef TOGGLE
+   g_bToggleIJB      = 1;
+#endif
+
+   fs->f = config = (struct configuration_spec *)zalloc(sizeof(*config));
+
+   if (config==NULL)
    {
-      memset (buf, 'j', sizeof(buf));
-      while (read_config_line(buf, sizeof(buf), configfp, NULL) != NULL)
-      {
-         char cmd[BUFSIZ];
-         char arg[BUFSIZ];
-         char tmp[BUFSIZ];
+      freez(fs->filename);
+      freez(fs);
+      log_error(LOG_LEVEL_FATAL, "can't allocate memory for configuration");
+      /* Never get here - LOG_LEVEL_FATAL causes program exit */
+   }
 
-         strcpy(tmp, buf);
+   /*
+    * This is backwards from how it's usually done.
+    * Following the usual pattern, "fs" would be stored in a member 
+    * variable in "csp", and then we'd access "config" from "fs->f",
+    * using a cast.  However, "config" is used so often that a 
+    * cast each time would be very ugly, and the extra indirection
+    * would waste CPU cycles.  Therefore we store "config" in
+    * "csp->config", and "fs" in "csp->config->config_file_list".
+    */
+   config->config_file_list = fs;
 
-         /* Copy command (i.e. up to space or tab) into cmd */
-         p = buf;
-         q = cmd;
-         while (*p && (*p != ' ') && (*p != '\t'))
-         {
-            *q++ = *p++;
-         }
-         *q = '\0';
+   init_proxy_args(Argc, Argv, config);
 
-         /* Skip over the whitespace in buf */
-         while (*p && ((*p == ' ') || (*p == '\t')))
-         {
-            p++;
-         }
+   /*
+    * Set to defaults
+    */
 
-         /* Copy the argument into arg */
-         strcpy(arg, p);
+   config->multi_threaded    = 1;
+   config->default_permissions = PERMIT_RE_FILTER;
+   config->hport             = HADDR_PORT;
 
-         /* Should never happen, but check this anyway */
-         if (*cmd == '\0')
-         {
-            continue;
-         }
+   if ((configfp = fopen(configfile, "r")) == NULL)
+   {
+      log_error(LOG_LEVEL_FATAL, "can't open configuration file '%s':  %E",
+              configfile);
+      /* Never get here - LOG_LEVEL_FATAL causes program exit */
+   }
+
+   while (read_config_line(buf, sizeof(buf), configfp, fs) != NULL)
+   {
+      char cmd[BUFSIZ];
+      char arg[BUFSIZ];
+      char tmp[BUFSIZ];
+
+      strcpy(tmp, buf);
+
+      /* Copy command (i.e. up to space or tab) into cmd */
+      p = buf;
+      q = cmd;
+      while (*p && (*p != ' ') && (*p != '\t'))
+      {
+         *q++ = *p++;
+      }
+      *q = '\0';
+
+      /* Skip over the whitespace in buf */
+      while (*p && ((*p == ' ') || (*p == '\t')))
+      {
+         p++;
+      }
+
+      /* Copy the argument into arg */
+      strcpy(arg, p);
+
+      /* Should never happen, but check this anyway */
+      if (*cmd == '\0')
+      {
+         continue;
+      }
 
-         /* Make sure the command field is lower case */
-         for (p=cmd; *p; p++)
+      /* Make sure the command field is lower case */
+      for (p=cmd; *p; p++)
+      {
+         if (ijb_isupper(*p))
          {
-            if (ijb_isupper(*p))
-            {
-               *p = ijb_tolower(*p);
-            }
+            *p = ijb_tolower(*p);
          }
+      }
 
-         /* Save the argument for show-proxy-args */
-         savearg(cmd, arg);
+      /* Save the argument for show-proxy-args */
+      savearg(cmd, arg, config);
 
 
-         switch( hash_string( cmd ) )
-         {
+      switch( hash_string( cmd ) )
+      {
 #ifdef TRUST_FILES
-            case hash_trustfile :
-               freez((char *)trustfile);
-               trustfile = strdup(arg);
-               continue;
+         case hash_trustfile :
+            freez((char *)config->trustfile);
+            config->trustfile = strdup(arg);
+            continue;
 
-            case hash_trust_info_url :
-               enlist(trust_info, arg);
-               continue;
+         case hash_trust_info_url :
+            enlist(config->trust_info, arg);
+            continue;
 #endif /* def TRUST_FILES */
 
-            case hash_debug :
-               debug |= atoi(arg);
-               continue;
+         case hash_debug :
+            config->debug |= atoi(arg);
+            continue;
 
 #if defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST)
-            case hash_tinygif :
-               freez((char *)tinygifurl);
-               tinygif = atoi(arg);
-               if(3 == tinygif)
+         case hash_tinygif :
+            freez((char *)config->tinygifurl);
+            config->tinygif = atoi(arg);
+            if(3 == config->tinygif)
+            {
+               p = arg;
+               while((*p >= '0') && (*p <= '9'))
                {
-                  p = arg;
-                  while((*p >= '0') && (*p <= '9'))
-                  {
-                     p++;
-                  }
-                  while((*p == ' ') || (*p == '\t'))
-                  {
-                     p++;
-                  }
-                  if (*p)
-                  {
-                     q = malloc(strlen(p) + 5);
-                     if (q)
-                     {
-                        strcpy(q, p);
-                        strcat(q, "\r\n\r\n");
-                        tinygifurl = q;
-                     }
-                  }
+                  p++;
                }
-               if ((tinygif != 1) && 
-                   (tinygif != 2) && 
-                   ((tinygif != 3) || (tinygifurl==NULL)) )
+               while((*p == ' ') || (*p == '\t'))
                {
-                  log_error(LOG_LEVEL_ERROR, "tinygif setting invalid.");
+                  p++;
                }
-               continue;
+               if (*p)
+               {
+                  q = malloc(strlen(p) + 5);
+                  if (q)
+                  {
+                     strcpy(q, p);
+                     strcat(q, "\r\n\r\n");
+                     config->tinygifurl = q;
+                  }
+               }
+            }
+            if ((config->tinygif != 1) && 
+                (config->tinygif != 2) && 
+                ((config->tinygif != 3) || (config->tinygifurl==NULL)) )
+            {
+               log_error(LOG_LEVEL_ERROR, "tinygif setting invalid.");
+            }
+            continue;
 #endif /* defined(DETECT_MSIE_IMAGES) || defined(USE_IMAGE_LIST) */
 
-            case hash_add_forwarded_header :
-               add_forwarded = 1;
-               continue;
+         case hash_add_forwarded_header :
+            config->add_forwarded = 1;
+            continue;
 
-            case hash_single_threaded :
-               multi_threaded = 0;
-               continue;
+         case hash_single_threaded :
+            config->multi_threaded = 0;
+            continue;
 
-            case hash_suppress_vanilla_wafer :
-               suppress_vanilla_wafer = 1;
-               continue;
+         case hash_suppress_vanilla_wafer :
+            suppress_vanilla_wafer = 1;
+            continue;
 
-            case hash_wafer :
-               enlist(wafer_list, arg);
-               continue;
+         case hash_wafer :
+            enlist(config->wafer_list, arg);
+            continue;
 
-            case hash_add_header :
-               enlist(xtra_list, arg);
-               continue;
+         case hash_add_header :
+            enlist(config->xtra_list, arg);
+            continue;
 
-            case hash_permissions_file :
-               freez((char *)permissions_file);
-               permissions_file = strdup(arg);
-               continue;
+         case hash_permissions_file :
+            freez((char *)config->permissions_file);
+            config->permissions_file = strdup(arg);
+            continue;
 
-            case hash_logfile :
-               freez((char *)logfile);
-               logfile = strdup(arg);
-               continue;
+         case hash_logfile :
+            freez((char *)config->logfile);
+            config->logfile = strdup(arg);
+            continue;
 
-            case hash_blockfile :
-               freez((char *)blockfile);
-               blockfile = strdup(arg);
-               continue;
+         case hash_blockfile :
+            freez((char *)config->blockfile);
+            config->blockfile = strdup(arg);
+            continue;
 
 #ifdef USE_IMAGE_LIST
-            case hash_imagefile :
-               freez((char *)imagefile);
-               imagefile = strdup(arg);
-               continue;
+         case hash_imagefile :
+            freez((char *)config->imagefile);
+            config->imagefile = strdup(arg);
+            continue;
 #endif /* def USE_IMAGE_LIST */
 
 #ifdef JAR_FILES
-            case hash_jarfile :
-               freez((char *)jarfile);
-               jarfile = strdup(arg);
-               continue;
+         case hash_jarfile :
+            freez((char *)config->jarfile);
+            config->jarfile = strdup(arg);
+            continue;
 #endif /* def JAR_FILES */
 
-            case hash_listen_address :
-               freez((char *)haddr);
-               haddr = strdup(arg);
-               continue;
+         case hash_listen_address :
+            freez((char *)config->haddr);
+            config->haddr = strdup(arg);
+            continue;
 
-            case hash_forwardfile :
-               freez((char *)forwardfile);
-               forwardfile = strdup(arg);
-               continue;
+         case hash_forwardfile :
+            freez((char *)config->forwardfile);
+            config->forwardfile = strdup(arg);
+            continue;
 
 #ifdef ACL_FILES
-            case hash_aclfile :
-               freez((char *)aclfile);
-               aclfile = strdup(arg);
-               continue;
+         case hash_aclfile :
+            freez((char *)config->aclfile);
+            config->aclfile = strdup(arg);
+            continue;
 #endif /* def ACL_FILES */
 
 #ifdef PCRS
-            case hash_re_filterfile :
-               freez((char *)re_filterfile);
-               re_filterfile = strdup(arg);
-               continue;
+         case hash_re_filterfile :
+            freez((char *)config->re_filterfile);
+            config->re_filterfile = strdup(arg);
+            continue;
 #endif /* def PCRS */
 
-            case hash_user_agent :
-               freez((char *)uagent);
-               uagent = strdup(arg);
-               continue;
+         case hash_user_agent :
+            freez((char *)config->uagent);
+            config->uagent = strdup(arg);
+            continue;
 
-               /*
-                * Offer choice of correct spelling according to dictionary,
-                * or the misspelling used in the HTTP spec.
-                */
-            case hash_referrer :
-            case hash_referer :
-               freez((char *)referrer);
-               referrer = strdup(arg);
-               continue;
+            /*
+             * Offer choice of correct spelling according to dictionary,
+             * or the misspelling used in the HTTP spec.
+             */
+         case hash_referrer :
+         case hash_referer :
+            freez((char *)config->referrer);
+            config->referrer = strdup(arg);
+            continue;
 
-            case hash_from :
-               freez((char *)from);
-               from = strdup(arg);
-               continue;
+         case hash_from :
+            freez((char *)config->from);
+            config->from = strdup(arg);
+            continue;
 
 #ifdef FAST_REDIRECTS
-                          case hash_fast_redirects :
-               fast_redirects = 1;
+         case hash_fast_redirects :
+               config->fast_redirects = 1;
                continue;
 #endif /* def FAST_REDIRECTS */
 
 #ifdef _WIN_CONSOLE
-            case hash_hide_console :
-               hideConsole = 1;
-               continue;
+         case hash_hide_console :
+            hideConsole = 1;
+            continue;
 #endif /*def _WIN_CONSOLE*/
 
 #ifndef SPLIT_PROXY_ARGS
-            case hash_suppress_blocklists :
-               if (arg[0] != '\0')
-               {
-                  suppress_message = strdup(arg);
-               }
-               else
-               {
-                  /* There will be NO reference in proxy-args. */
-                  suppress_message = NULL;
-               }
+         case hash_suppress_blocklists :
+            if (arg[0] != '\0')
+            {
+               config->suppress_message = strdup(arg);
+            }
+            else
+            {
+               /* There will be NO reference in proxy-args. */
+               config->suppress_message = NULL;
+            }
 
-               suppress_blocklists = 1;
-               continue;
+            config->suppress_blocklists = 1;
+            continue;
 #endif /* ndef SPLIT_PROXY_ARGS */
 
 #ifdef TOGGLE
-            case hash_toggle :
-               g_bToggleIJB = atoi(arg);
-               continue;
+         case hash_toggle :
+            g_bToggleIJB = atoi(arg);
+            continue;
 #endif /* def TOGGLE */
 
 #if defined(_WIN32) && ! defined(_WIN_CONSOLE)
-            case hash_activity_animation :
-               g_bShowActivityAnimation = atoi(arg);
-               continue;
+         case hash_activity_animation :
+            g_bShowActivityAnimation = atoi(arg);
+            continue;
 
-            case hash_log_messages :
-               g_bLogMessages = atoi(arg);
-               continue;
+         case hash_log_messages :
+            g_bLogMessages = atoi(arg);
+            continue;
 
-            case hash_log_highlight_messages :
-               g_bHighlightMessages = atoi(arg);
-               continue;
+         case hash_log_highlight_messages :
+            g_bHighlightMessages = atoi(arg);
+            continue;
 
-            case hash_log_buffer_size :
-               g_bLimitBufferSize = atoi(arg);
-               continue;
+         case hash_log_buffer_size :
+            g_bLimitBufferSize = atoi(arg);
+            continue;
 
-            case hash_log_max_lines :
-               g_nMaxBufferLines = atoi(arg);
-               continue;
+         case hash_log_max_lines :
+            g_nMaxBufferLines = atoi(arg);
+            continue;
 
-            case hash_log_font_name :
-               strcpy( g_szFontFaceName, arg );
-               continue;
+         case hash_log_font_name :
+            strcpy( g_szFontFaceName, arg );
+            continue;
 
-            case hash_log_font_size :
-               g_nFontSize = atoi(arg);
-               continue;
+         case hash_log_font_size :
+            g_nFontSize = atoi(arg);
+            continue;
 
-            case hash_show_on_task_bar :
-               g_bShowOnTaskBar = atoi(arg);
-               continue;
+         case hash_show_on_task_bar :
+            g_bShowOnTaskBar = atoi(arg);
+            continue;
 
-            case hash_close_button_minimizes :
-               g_bCloseHidesWindow = atoi(arg);
-               continue;
+         case hash_close_button_minimizes :
+            g_bCloseHidesWindow = atoi(arg);
+            continue;
 #endif /* defined(_WIN32) && ! defined(_WIN_CONSOLE) */
 
-            /* Warnings about unsupported features */
+         /* Warnings about unsupported features */
 
-#ifndef TRUST_FILES
-            case hash_trustfile :
-            case hash_trust_info_url :
-#endif /* ndef TRUST_FILES */
 #ifndef USE_IMAGE_LIST
-            case hash_imagefile :
+         case hash_imagefile :
 #endif /* ndef USE_IMAGE_LIST */
 #ifndef PCRS
-            case hash_re_filterfile :
+         case hash_re_filterfile :
 #endif /* ndef PCRS */
 #ifndef TOGGLE
-            case hash_toggle :
+         case hash_toggle :
 #endif /* ndef TOGGLE */
 #if defined(_WIN_CONSOLE) || ! defined(_WIN32)
-            case hash_activity_animation :
-            case hash_log_messages :
-            case hash_log_highlight_messages :
-            case hash_log_buffer_size :
-            case hash_log_max_lines :
-            case hash_log_font_name :
-            case hash_log_font_size :
-            case hash_show_on_task_bar :
-            case hash_close_button_minimizes :
+         case hash_activity_animation :
+         case hash_log_messages :
+         case hash_log_highlight_messages :
+         case hash_log_buffer_size :
+         case hash_log_max_lines :
+         case hash_log_font_name :
+         case hash_log_font_size :
+         case hash_show_on_task_bar :
+         case hash_close_button_minimizes :
 #endif /* defined(_WIN_CONSOLE) || ! defined(_WIN32) */
 #ifndef _WIN_CONSOLE
-            case hash_hide_console :
+         case hash_hide_console :
 #endif /* ndef _WIN_CONSOLE */
 #if !defined(DETECT_MSIE_IMAGES) && !defined(USE_IMAGE_LIST)
-            case hash_tinygif :
+         case hash_tinygif :
 #endif /* !defined(DETECT_MSIE_IMAGES) && !defined(USE_IMAGE_LIST) */
 #ifndef JAR_FILES
-            case hash_jarfile :
+         case hash_jarfile :
 #endif /* ndef JAR_FILES */
 #ifndef ACL_FILES
-            case hash_aclfile :
+         case hash_aclfile :
 #endif /* ndef ACL_FILES */
-
+#ifndef FAST_REDIRECTS
+         case hash_fast_redirects :
+#endif /* ndef FAST_REDIRECTS */
 #ifdef SPLIT_PROXY_ARGS
-            case hash_suppress_blocklists :
+         case hash_suppress_blocklists :
 #endif /* def SPLIT_PROXY_ARGS */
-               log_error(LOG_LEVEL_INFO, "Unsupported directive \"%s\" ignored.", cmd);
-               continue;
+            log_error(LOG_LEVEL_INFO, "Unsupported directive \"%s\" ignored.", cmd);
+            continue;
 
-            default :
-               /*
-                * I decided that I liked this better as a warning than an
-                * error.  To change back to an error, just change log level
-                * to LOG_LEVEL_FATAL.
-                */
-               log_error(LOG_LEVEL_ERROR, "Unrecognized directive (%lulu) in "
-                     "configuration file: \"%s\"", hash_string( cmd ), buf);
-               p = malloc( BUFSIZ );
-               if (p != NULL)
-               {
-                  sprintf( p, "<br>\nWARNING: unrecognized directive : %s<br><br>\n", buf );
-                  proxy_args->invocation = strsav( proxy_args->invocation, p );
-                  freez( p );
-               }
-               continue;
-         }
-      }
-      fclose(configfp);
-   }
+         default :
+            /*
+             * I decided that I liked this better as a warning than an
+             * error.  To change back to an error, just change log level
+             * to LOG_LEVEL_FATAL.
+             */
+            log_error(LOG_LEVEL_ERROR, "Unrecognized directive (%lulu) in "
+                  "configuration file: \"%s\"", hash_string( cmd ), buf);
+            p = malloc( BUFSIZ );
+            if (p != NULL)
+            {
+               sprintf( p, "<br>\nWARNING: unrecognized directive : %s<br><br>\n", buf );
+               config->proxy_args->invocation = strsav( config->proxy_args->invocation, p );
+               freez( p );
+            }
+            continue;
+      } /* end switch( hash_string(cmd) ) */
+   } /* end while ( read_config_line(...) ) */
 
-   init_error_log(Argv[0], logfile, debug);
+   fclose(configfp);
 
-   if (permissions_file)
+   init_error_log(Argv[0], config->logfile, config->debug);
+
+   if (config->permissions_file)
    {
-      add_loader(load_permissions_file);
+      add_loader(load_permissions_file, config);
    }
 
-   if (blockfile)
+   if (config->blockfile)
    {
-      add_loader(load_blockfile);
+      add_loader(load_blockfile, config);
    }
 
 #ifdef USE_IMAGE_LIST
-   if (imagefile)
+   if (config->imagefile)
    {
-      add_loader(load_imagefile);
+      add_loader(load_imagefile, config);
    }
 #endif /* def USE_IMAGE_LIST */
 
-#ifdef TRUST_FILES
-   if (trustfile)
+   if (config->forwardfile)
    {
-      add_loader(load_trustfile);
-   }
-#endif /* def TRUST_FILES */
-
-   if (forwardfile)
-   {
-      add_loader(load_forwardfile);
+      add_loader(load_forwardfile, config);
    }
 
 #ifdef ACL_FILES
-   if (aclfile)
+   if (config->aclfile)
    {
-      add_loader(load_aclfile);
+      add_loader(load_aclfile, config);
    }
 #endif /* def ACL_FILES */
 
 #ifdef PCRS
-   if (re_filterfile)
+   if (config->re_filterfile)
    {
-      add_loader(load_re_filterfile);
+      add_loader(load_re_filterfile, config);
    }
 #endif /* def PCRS */
+\r
+#ifdef TRUST_FILES\r
+   if (config->trustfile)\r
+   {\r
+      add_loader(load_trustfile, config);\r
+   }\r
+#endif\r
 
 #ifdef JAR_FILES
-   if ( NULL != jarfile )
+   if ( NULL != config->jarfile )
    {
-      if ( NULL == (jar = fopen(jarfile, "a")) )
+      if ( NULL == (config->jar = fopen(config->jarfile, "a")) )
       {
-         log_error(LOG_LEVEL_FATAL, "can't open jarfile '%s': %E", jarfile);
+         log_error(LOG_LEVEL_FATAL, "can't open jarfile '%s': %E", config->jarfile);
          /* Never get here - LOG_LEVEL_FATAL causes program exit */
       }
-      setbuf(jar, NULL);
+      setbuf(config->jar, NULL);
    }
 #endif /* def JAR_FILES */
 
-   if ( NULL == haddr )
+   if ( NULL == config->haddr )
    {
-      haddr = strdup( HADDR_DEFAULT );
+      config->haddr = strdup( HADDR_DEFAULT );
    }
 
-   if ( NULL != haddr )
+   if ( NULL != config->haddr )
    {
-      if ((p = strchr(haddr, ':')))
+      if ((p = strchr(config->haddr, ':')))
       {
          *p++ = '\0';
          if (*p)
          {
-            hport = atoi(p);
+            config->hport = atoi(p);
          }
       }
 
-      if (hport <= 0)
+      if (config->hport <= 0)
       {
          *--p = ':';
-         log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", haddr);
+         log_error(LOG_LEVEL_FATAL, "invalid bind port spec %s", config->haddr);
          /* Never get here - LOG_LEVEL_FATAL causes program exit */
       }
-      if (*haddr == '\0')
+      if (*config->haddr == '\0')
       {
-         haddr = NULL;
+         config->haddr = NULL;
       }
    }
 
-   if (run_loader(NULL))
+   /*
+    * Want to run all the loaders once now.
+    *
+    * Need to set up a fake csp, so they can get to the config.
+    */
+   fake_csp = (struct client_state *) zalloc (sizeof(*fake_csp));
+   fake_csp->config = config;
+
+   if (run_loader(fake_csp))
    {
+      freez(fake_csp);
       log_error(LOG_LEVEL_FATAL, "A loader failed while loading config file. Exiting.");
       /* Never get here - LOG_LEVEL_FATAL causes program exit */
    }
+   freez(fake_csp);
 
 #ifdef JAR_FILES
    /*
@@ -834,16 +815,89 @@ void load_config( int signum )
     * supplied any wafers, and the user has not told us to suppress the
     * vanilla wafer, then send the vanilla wafer.
     */
-   if ((jarfile != NULL)
-       && (wafer_list->next == NULL)
+   if ((config->jarfile != NULL)
+       && (config->wafer_list->next == NULL)
        && (suppress_vanilla_wafer == 0))
    {
-      enlist(wafer_list, VANILLA_WAFER);
+      enlist(config->wafer_list, VANILLA_WAFER);
    }
 #endif /* def JAR_FILES */
 
-   end_proxy_args();
+   end_proxy_args(config);
+
+#ifndef SPLIT_PROXY_ARGS
+   if (!suppress_blocklists)
+   {
+      fs->proxy_args = strsav(fs->proxy_args, "</pre>");
+   }
+#endif /* ndef SPLIT_PROXY_ARGS */
+
+/* FIXME: this is a kludge for win32 */
+#if defined(_WIN32) && !defined (_WIN_CONSOLE)
+
+   g_blockfile        = config->blockfile;
+   g_permissions_file = config->permissions_file;
+   g_forwardfile      = config->forwardfile;
+#ifdef ACL_FILES
+   g_aclfile          = config->aclfile;
+#endif /* def ACL_FILES */
+#ifdef USE_IMAGE_LIST
+   g_imagefile        = config->imagefile;
+#endif /* def USE_IMAGE_LIST */
+#ifdef PCRS\r
+   g_re_filterfile    = config->re_filterfile;\r
+#endif\r
+#ifdef TRUST_FILES\r
+   g_trustfile        = config->trustfile;\r
+#endif\r
+   
+
+#endif /* defined(_WIN32) && !defined (_WIN_CONSOLE) */
+/* FIXME: end kludge */
+
+
+   config->need_bind = 1;
+
+   if (current_configfile)
+   {
+      struct configuration_spec * oldcfg = (struct configuration_spec *)
+                                           current_configfile->f;
+      /*
+       * Check if config->haddr,hport == oldcfg->haddr,hport
+       *
+       * The following could be written more compactly as a single,
+       * (unreadably long) if statement.
+       */
+      config->need_bind = 0;
+      if (config->hport != oldcfg->hport)
+      {
+         config->need_bind = 1;
+      }
+      else if (config->haddr == NULL)
+      {
+         if (oldcfg->haddr != NULL)
+         {
+            config->need_bind = 1;
+         }
+      }
+      else if (oldcfg->haddr == NULL)
+      {
+         config->need_bind = 1;
+      }
+      else if (0 != strcmp(config->haddr, oldcfg->haddr))
+      {
+         config->need_bind = 1;
+      }
+
+      current_configfile->unloader = unload_configfile;
+   }
+
+   fs->next = files->next;
+   files->next = fs;
+
+   current_configfile = fs;
 
+   return (config);
 }