diff --git a/GNUmakefile.in b/GNUmakefile.in
index 9476426..ad8aa17 100644
--- a/GNUmakefile.in
+++ b/GNUmakefile.in
@@ -253,6 +253,11 @@ REGEX_SRC    =
 REGEX_OBJS   = $(REGEX_SRC:.c=.@OBJEXT@)
 REGEX_HDRS   = $(REGEX_SRC:.c=.h)
 
+# Required tag
+RTAG_SRC     = @REQUIRED_TAG_ONLY@requiredtag.c
+RTAG_OBJS    = @REQUIRED_TAG_ONLY@$(RTAG_SRC:.c=.@OBJEXT@)
+RTAG_HDRS    = @REQUIRED_TAG_ONLY@requiredtag.h
+
 # Dependencies introduced by #include "project.h".
 PROJECT_H_DEPS = project.h $(REGEX_HDRS) $(PCRS_HDRS)
 
@@ -262,9 +267,9 @@ SOCKET_LIB   = @SOCKET_LIB@
 # PThreads library, if needed.
 PTHREAD_LIB  = @PTHREAD_ONLY@@PTHREAD_LIB@
 
-SRCS         = $(C_SRC) $(CLIENT_TAG_SRC) $(FUZZ_SRC) $(W32_SRC) $(PCRS_SRC) $(REGEX_SRC) $(SSL_SRC) $(MBEDTLS_SRC) $(OPENSSL_SRC)
-OBJS         = $(C_OBJS) $(CLIENT_TAG_OBJS) $(FUZZ_OBJS) $(W32_OBJS) $(PCRS_OBJS) $(REGEX_OBJS) $(SSL_OBJS) $(MBEDTLS_OBJS) $(OPENSSL_OBJS)
-HDRS         = $(C_HDRS) $(W32_HDRS) $(PCRS_HDRS) $(REGEX_HDRS) $(SSL_HDRS) $(MBEDTLS_HDRS) $(OPENSSL_HDRS)
+SRCS         = $(C_SRC) $(CLIENT_TAG_SRC) $(FUZZ_SRC) $(W32_SRC) $(PCRS_SRC) $(REGEX_SRC) $(SSL_SRC) $(MBEDTLS_SRC) $(OPENSSL_SRC)  $(RTAG_SRC)
+OBJS         = $(C_OBJS) $(CLIENT_TAG_OBJS) $(FUZZ_OBJS) $(W32_OBJS) $(PCRS_OBJS) $(REGEX_OBJS) $(SSL_OBJS) $(MBEDTLS_OBJS) $(OPENSSL_OBJS) $(RTAG_OBJS)
+HDRS         = $(C_HDRS) $(W32_HDRS) $(PCRS_HDRS) $(REGEX_HDRS) $(SSL_HDRS) $(MBEDTLS_HDRS) $(OPENSSL_HDRS) $(RTAG_HDRS)
 LIBS         = @LIBS@ $(W32_LIB) $(SOCKET_LIB) $(PTHREAD_LIB)
 
 
@@ -746,6 +751,9 @@ ssl.@OBJEXT@: ssl.c ssl.h ssl_common.h config.h $(PROJECT_H_DEPS) encode.h errlo
 openssl.@OBJEXT@: openssl.c ssl.h ssl_common.h config.h $(PROJECT_H_DEPS) encode.h errlog.h jcc.h miscutil.h
 ssl_common.@OBJEXT@: ssl_common.c ssl.h ssl_common.h config.h $(PROJECT_H_DEPS) errlog.h miscutil.h
 
+# required tag
+required.tag.@OBJEXT@: requiredtag.c requiredtag.h config.h $(PROJECT_H_DEPS) errlog.h miscutil.h
+
 # PCRS
 pcrs.@OBJEXT@: pcrs.c pcrs.h config.h
 
diff --git a/acconfig.h b/acconfig.h
index dbf443b..3c3cfe5 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -54,11 +54,21 @@
  */
 #undef VERSION_POINT
 
+/*
+ * Patchlevel
+ */
+#undef PATCHLEVEL
+
 /*
  * Version number, as a string
  */
 #undef VERSION
 
+/*
+ * Version number of referenced document, as a string
+ */
+#undef DOC_VERSION
+
 /*
  * Status of the code: "alpha", "beta" or "stable".
  */
@@ -180,6 +190,26 @@
  */
 #undef FEATURE_TRUST
 
+/*
+ * Enables add-referer action and extended parameters for hide-referer action.
+ */
+#undef FEATURE_ADD_REFERER
+
+/*
+ * Enables forward class selection.
+ */
+#undef FEATURE_FORWARD_CLASS
+
+/*
+ * Enables manual tagger.
+ */
+#undef FEATURE_MANUAL_TAGGER
+
+/*
+ * Enables required tag.
+ */
+#undef FEATURE_REQUIRED_TAG
+
 /*
  * Defined on Solaris only.  Makes the system libraries thread safe.
  */
diff --git a/actionlist.h b/actionlist.h
index d95b822..c30c738 100644
--- a/actionlist.h
+++ b/actionlist.h
@@ -51,6 +51,13 @@
 #endif /* ndef DEFINE_CGI_PARAM_RADIO */
 
 DEFINE_ACTION_MULTI      ("add-header",                 ACTION_MULTI_ADD_HEADER)
+DEFINE_ACTION_STRING     ("add-referrer",               ACTION_ADD_REFERER,    ACTION_STRING_ADD_REFERER)
+DEFINE_CGI_PARAM_RADIO   ("add-referrer",               ACTION_ADD_REFERER,    ACTION_STRING_ADD_REFERER,       "self", 4)
+DEFINE_CGI_PARAM_RADIO   ("add-referrer",               ACTION_ADD_REFERER,    ACTION_STRING_ADD_REFERER,       "index", 3)
+DEFINE_CGI_PARAM_RADIO   ("add-referrer",               ACTION_ADD_REFERER,    ACTION_STRING_ADD_REFERER,       "directory", 2)
+DEFINE_CGI_PARAM_RADIO   ("add-referrer",               ACTION_ADD_REFERER,    ACTION_STRING_ADD_REFERER,       "forge", 1)
+DEFINE_CGI_PARAM_RADIO   ("add-referrer",               ACTION_ADD_REFERER,    ACTION_STRING_ADD_REFERER,       "block", 0)
+DEFINE_CGI_PARAM_CUSTOM  ("add-referrer",               ACTION_ADD_REFERER,    ACTION_STRING_ADD_REFERER,       "http://www.privoxy.org/")
 DEFINE_ACTION_STRING     ("block",                      ACTION_BLOCK, ACTION_STRING_BLOCK)
 DEFINE_CGI_PARAM_NO_RADIO("block",                      ACTION_BLOCK, ACTION_STRING_BLOCK, "No reason specified.")
 DEFINE_ACTION_STRING     ("change-x-forwarded-for",     ACTION_CHANGE_X_FORWARDED_FOR,  ACTION_STRING_CHANGE_X_FORWARDED_FOR)
@@ -102,6 +109,9 @@ DEFINE_ACTION_STRING     ("hide-if-modified-since",     ACTION_HIDE_IF_MODIFIED_
 DEFINE_CGI_PARAM_RADIO   ("hide-if-modified-since",     ACTION_HIDE_IF_MODIFIED_SINCE, ACTION_STRING_IF_MODIFIED_SINCE, "block", 0)
 DEFINE_CGI_PARAM_CUSTOM  ("hide-if-modified-since",     ACTION_HIDE_IF_MODIFIED_SINCE, ACTION_STRING_IF_MODIFIED_SINCE, "-1")
 DEFINE_ACTION_STRING     ("hide-referrer",              ACTION_HIDE_REFERER,    ACTION_STRING_REFERER)
+DEFINE_CGI_PARAM_RADIO   ("hide-referrer",              ACTION_HIDE_REFERER,    ACTION_STRING_REFERER,       "self", 6)
+DEFINE_CGI_PARAM_RADIO   ("hide-referrer",              ACTION_HIDE_REFERER,    ACTION_STRING_REFERER,       "index", 5)
+DEFINE_CGI_PARAM_RADIO   ("hide-referrer",              ACTION_HIDE_REFERER,    ACTION_STRING_REFERER,       "directory", 4)
 DEFINE_CGI_PARAM_RADIO   ("hide-referrer",              ACTION_HIDE_REFERER,    ACTION_STRING_REFERER,       "conditional-forge", 3)
 DEFINE_CGI_PARAM_RADIO   ("hide-referrer",              ACTION_HIDE_REFERER,    ACTION_STRING_REFERER,       "conditional-block", 2)
 DEFINE_CGI_PARAM_RADIO   ("hide-referrer",              ACTION_HIDE_REFERER,    ACTION_STRING_REFERER,       "forge", 1)
@@ -138,6 +148,7 @@ DEFINE_ACTION_MULTI      ("suppress-tag",               ACTION_MULTI_SUPPRESS_TA
 /*
  * Alternative spellings
  */
+DEFINE_ACTION_STRING     ("add-referer",    ACTION_ADD_REFERER,     ACTION_STRING_ADD_REFERER)
 DEFINE_ACTION_STRING     ("hide-referer",   ACTION_HIDE_REFERER,    ACTION_STRING_REFERER)
 DEFINE_ACTION_BOOL       ("prevent-keeping-cookies", ACTION_SESSION_COOKIES_ONLY)
 
diff --git a/actions.c b/actions.c
index 7fbcd3a..28d6d70 100644
--- a/actions.c
+++ b/actions.c
@@ -55,6 +55,9 @@
 #include "cgi.h"
 #include "ssplit.h"
 #include "filters.h"
+#ifdef FEATURE_REQUIRED_TAG
+#include "requiredtag.h"
+#endif /* def FEATURE_REQUIRED_TAG */
 
 /*
  * We need the main list of options.
@@ -783,6 +786,36 @@ jb_err merge_current_action (struct current_action_spec *dest,
    return err;
 }
 
+#ifdef FEATURE_MANUAL_TAGGER
+/*********************************************************************
+ *
+ * Function    :  update_action_bits_for_all_tags
+ *
+ * Description :  Updates the action bits based on all matching tags.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  0 if no tag matched, or
+ *                1 otherwise
+ *
+ *********************************************************************/
+int update_action_bits_for_all_tags(struct client_state *csp)
+{
+   struct list_entry *tag;
+   int updated = 0;
+
+   for (tag = csp->tags->first; tag != NULL; tag = tag->next)
+   {
+      if (update_action_bits_for_tag(csp, tag->str))
+      {
+         updated = 1;
+      }
+   }
+
+   return updated;
+}
+#endif
 
 /*********************************************************************
  *
@@ -822,6 +855,30 @@ int update_action_bits_for_tag(struct client_state *csp, const char *tag)
       /* and through all the action patterns, */
       for (b = b->next; NULL != b; b = b->next)
       {
+#ifdef FEATURE_REQUIRED_TAG
+         if (b->rtags)
+         {
+            /* when required tags are set, check if all required tags are matched. */
+            if (0 == match_req_tag_list(b->rtags, csp->tags))
+            {
+               /* skip when not matched. */
+               continue;
+            }
+
+            /* when all required tags are matched, re-check URL patterns. */
+            if (url_match(b->url, csp->http))
+            {
+               if (merge_current_action(csp->action, b->action))
+               {
+                  log_error(LOG_LEVEL_ERROR,
+                     "Out of memory while changing action bits");
+               }
+               /* and signal the change. */
+               updated = 1;
+            }
+         }
+#endif
+
          /* skip everything but TAG patterns, */
          if (!(b->url->flags & PATTERN_SPEC_TAG_PATTERN))
          {
@@ -1014,6 +1071,18 @@ void unload_actions_file(void *file_data)
           */
          free_action_spec(cur->action);
       }
+#ifdef FEATURE_REQUIRED_TAG
+      if ((next == NULL) || (next->rtags != cur->rtags))
+      {
+         /*
+          * As the required tags might be shared,
+          * we can only free them if the current
+          * required tag is the last one, or if the
+          * next one is using different settings.
+          */
+         free_req_tag_list(cur->rtags);
+      }
+#endif /* def FEATURE_REQUIRED_TAG */
       freez(cur);
       cur = next;
    }
@@ -1240,7 +1309,12 @@ int load_one_actions_file(struct client_state *csp, int fileid)
       MODE_SETTINGS      = 2,
       MODE_DESCRIPTION   = 3,
       MODE_ALIAS         = 4,
+#ifdef FEATURE_REQUIRED_TAG
+      MODE_ACTIONS       = 5,
+      MODE_REQUIRED_TAGS = 6
+#else
       MODE_ACTIONS       = 5
+#endif
    } mode;
 
    FILE *fp;
@@ -1252,6 +1326,10 @@ int load_one_actions_file(struct client_state *csp, int fileid)
    int cur_action_used = 0;
    struct action_alias * alias_list = NULL;
    unsigned long linenum = 0;
+#ifdef FEATURE_REQUIRED_TAG
+   struct req_tag_list * cur_req_tag = NULL;
+   int cur_req_tag_used = 0;
+#endif /* def FEATURE_REQUIRED_TAG */
    mode = MODE_START_OF_FILE;
 
    if (!check_file_changed(current_actions_file[fileid], csp->config->actions_file[fileid], &fs))
@@ -1382,6 +1460,24 @@ int load_one_actions_file(struct client_state *csp, int fileid)
                }
                mode = MODE_ALIAS;
             }
+#ifdef FEATURE_REQUIRED_TAG
+            else if (0 == strcmpic(start, "required"))
+            {
+               /* free old required tags */
+               if (cur_req_tag)
+               {
+                  if (!cur_req_tag_used)
+                  {
+                     free_req_tag_list(cur_req_tag);
+                  }
+                  cur_req_tag = NULL;
+               }
+               cur_req_tag_used = 0;
+
+               /* set mode */
+               mode    = MODE_REQUIRED_TAGS;
+            }
+#endif
             else
             {
                /* invalid {{something}} block */
@@ -1593,6 +1689,12 @@ int load_one_actions_file(struct client_state *csp, int fileid)
                csp->config->actions_file[fileid], linenum, buf);
             return 1; /* never get here */
          }
+#ifdef FEATURE_REQUIRED_TAG
+         perm->rtags = cur_req_tag;
+         if (cur_req_tag) {
+            cur_req_tag_used = 1;
+         }
+#endif /* def FEATURE_REQUIRED_TAG */
 
          /* add it to the list */
          last_perm->next = perm;
@@ -1607,6 +1709,31 @@ int load_one_actions_file(struct client_state *csp, int fileid)
             csp->config->actions_file[fileid], linenum, buf);
          return 1; /* never get here */
       }
+#ifdef FEATURE_REQUIRED_TAG
+      else if (mode == MODE_REQUIRED_TAGS)
+      {
+         struct req_tag_list *temp;
+         temp = (struct req_tag_list *)zalloc(sizeof(*temp));
+         if (temp == NULL)
+         {
+            fclose(fp);
+            log_error(LOG_LEVEL_FATAL,
+               "can't load actions file '%s': out of memory",
+               csp->config->actions_file[fileid]);
+            return 1; /* never get here */
+         }
+         if (init_req_tag_list(temp, buf) != JB_ERR_OK)
+         {
+            fclose(fp);
+            log_error(LOG_LEVEL_FATAL,
+               "can't load actions file '%s': invalid required tag configuration",
+               csp->config->actions_file[fileid]);
+            return 1; /* never get here */
+         }
+         temp->next = cur_req_tag;
+         cur_req_tag = temp;
+      }
+#endif /* def FEATURE_REQUIRED_TAG */
       else
       {
          /* How did we get here? This is impossible! */
@@ -1626,6 +1753,12 @@ int load_one_actions_file(struct client_state *csp, int fileid)
       free_action_spec(cur_action);
    }
    free_alias_list(alias_list);
+#ifdef FEATURE_REQUIRED_TAG
+   if (!cur_req_tag_used)
+   {
+      free_req_tag_list(cur_req_tag);
+   }
+#endif /* def FEATURE_REQUIRED_TAG */
 
    /* the old one is now obsolete */
    if (current_actions_file[fileid])
diff --git a/actions.h b/actions.h
index 618bc25..87242d1 100644
--- a/actions.h
+++ b/actions.h
@@ -59,6 +59,9 @@ extern void init_action(struct action_spec *dest);
 extern void free_action(struct action_spec *src);
 extern jb_err merge_actions (struct action_spec *dest,
                              const struct action_spec *src);
+#ifdef FEATURE_MANUAL_TAGGER
+extern int update_action_bits_for_all_tags(struct client_state *csp);
+#endif
 extern int update_action_bits_for_tag(struct client_state *csp, const char *tag);
 extern jb_err check_negative_tag_patterns(struct client_state *csp, unsigned int flag);
 extern jb_err copy_action (struct action_spec *dest,
diff --git a/cgi.c b/cgi.c
index 5d7b702..df070b0 100644
--- a/cgi.c
+++ b/cgi.c
@@ -129,6 +129,12 @@ static const struct cgi_dispatcher cgi_dispatchers[] = {
          NULL,
          FALSE },
 #endif
+#ifdef FEATURE_FORWARD_CLASS
+   { "forward-class",
+         cgi_forward_class,
+         "View & change the forward class state",
+         FALSE },
+#endif /* def FEATURE_FORWARD_CLASS */
 #ifdef FEATURE_CGI_EDIT_ACTIONS
    { "edit-actions", /* Edit the actions list */
          cgi_edit_actions,
@@ -593,7 +599,7 @@ static struct http_response *dispatch_known_cgi(struct client_state * csp,
          else
          {
             /*
-             * Else, modify toggle calls so that they only display
+             * Else, modify toggle or forward-class calls so that they only display
              * the status, and deny all other calls.
              */
             if (0 == strcmp(path_copy, "toggle"))
@@ -601,6 +607,11 @@ static struct http_response *dispatch_known_cgi(struct client_state * csp,
                unmap(param_list, "set");
                err = (d->handler)(csp, rsp, param_list);
             }
+            else if (0 == strcmp(path_copy, "forward-class"))
+            {
+               map(param_list, "untrust", 1, "yes", 1);
+               err = (d->handler)(csp, rsp, param_list);
+            }
             else
             {
                err = cgi_error_disabled(csp, rsp);
diff --git a/cgiedit.c b/cgiedit.c
index e73d5ee..f9b5e31 100644
--- a/cgiedit.c
+++ b/cgiedit.c
@@ -4128,6 +4128,211 @@ jb_err cgi_edit_actions_section_add(struct client_state *csp,
 }
 
 
+#ifdef FEATURE_FORWARD_CLASS
+/*********************************************************************
+ *
+ * Function    :  cgi_forward_class
+ *
+ * Description :  CGI function that show and edit forward class state
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *          2  :  rsp = http_response data structure for output
+ *          3  :  parameters = map of cgi parameters
+ *
+ * CGI Parameters :
+ * <classname> : If present, how to change toggle setting:
+ *               "enable", "disable", "toggle", or none (default).
+ *        mini : If present, use mini reply template.
+ *
+ * Returns     :  JB_ERR_OK     on success
+ *                JB_ERR_MEMORY on out-of-memory
+ *
+ *********************************************************************/
+jb_err cgi_forward_class(struct client_state *csp,
+                         struct http_response *rsp,
+                         const struct map *parameters)
+{
+   struct map *exports;
+   struct map *section_exports;
+   char mode;
+   const char *template_name;
+   int i;
+   char *state_template;
+   char *state;
+   char *bookmarklet_template;
+   char *bookmarklet;
+   char *s;
+   jb_err err;
+   int *forward_class_state;
+   int forward_class[MAX_FORWARD_CLASSES];
+   int is_update;
+
+   assert(csp);
+   assert(rsp);
+   assert(parameters);
+
+   if (NULL == (exports = default_exports(csp, "forward-class")))
+   {
+      return JB_ERR_MEMORY;
+   }
+
+   if (get_char_param(parameters, "untrust"))
+   {
+      if (get_char_param(parameters, "mini"))
+      {
+         forward_class_state = forward_class;
+         is_update = 1;
+         map_conditional(exports, "forward-class-changing", 1);
+      }
+      else
+      {
+         forward_class_state = global_forward_class_state;
+         is_update = 0;
+         map_conditional(exports, "forward-class-changing", 0);
+      }
+   }
+   else
+   {
+      forward_class_state = global_forward_class_state;
+     is_update = 1;
+         map_conditional(exports, "forward-class-changing", 0);
+   }
+   /* Update forward class state */
+   if (is_update)
+   {
+      for (i = 0; i < MAX_FORWARD_CLASSES; i++)
+      {
+         if (csp->config->forward_class[i].name)
+         {
+            mode = get_char_param(parameters, csp->config->forward_class[i].name);
+
+            if (mode == 'E')
+            {
+               /* Enable */
+               forward_class_state[i] = 1;
+            }
+            else if (mode == 'D')
+            {
+               /* Disable */
+               forward_class_state[i] = 0;
+            }
+            else if (mode == 'T')
+            {
+               /* Toggle */
+               forward_class_state[i] = !global_forward_class_state[i];
+            }
+            else
+            {
+               /* Keep */
+               forward_class_state[i] = global_forward_class_state[i];
+            }
+         }
+      }
+   }
+
+   err = template_load(csp, &state_template, "forward-class-state", 0);
+   if (err)
+   {
+      if (err == JB_ERR_FILE)
+      {
+         free_map(exports);
+         return cgi_error_no_template(csp, rsp, "forward-class-state");
+      }
+      return err;
+   }
+
+  err = template_load(csp, &bookmarklet_template, "forward-class-bookmarklet", 0);
+   if (err)
+   {
+      if (err == JB_ERR_FILE)
+      {
+         free_map(exports);
+         free(state_template);
+         return cgi_error_no_template(csp, rsp, "forward-class-bookmarklet");
+      }
+      return err;
+   }
+
+   state = strdup("");
+   bookmarklet = strdup("");
+   for (i = 0; i < MAX_FORWARD_CLASSES; i++)
+   {
+      if (csp->config->forward_class[i].name != NULL)
+      {
+         if (err || (NULL == (section_exports = new_map())))
+         {
+            free_map(exports);
+            free(state_template);
+            free(bookmarklet_template);
+            free(state);
+            free(bookmarklet);
+            return JB_ERR_MEMORY;
+         }
+
+         err = map(section_exports, "forward-class-name", 1, csp->config->forward_class[i].name, 1);
+         if (forward_class_state[i])
+         {
+            if (!err) err = map_block_keep(section_exports, "forward-class-enabled");
+            if (!err) err = map_block_killer(section_exports, "forward-class-disabled");
+         }
+         else
+         {
+            if (!err) err = map_block_killer(section_exports, "forward-class-enabled");
+            if (!err) err = map_block_keep(section_exports, "forward-class-disabled");
+         }
+
+         if (err || (NULL == (s = strdup(state_template))))
+         {
+            free_map(exports);
+            free_map(section_exports);
+            free(state_template);
+            free(bookmarklet_template);
+            free(state);
+            free(bookmarklet);
+            return JB_ERR_MEMORY;
+         }
+         if (!err) err = template_fill(&s, section_exports);
+         if (!err) err = string_join(&state, s);
+         if (err || (NULL == (s = strdup(bookmarklet_template))))
+         {
+            free_map(exports);
+            free_map(section_exports);
+            free(state_template);
+            free(bookmarklet_template);
+            free(state);
+            free(bookmarklet);
+            return JB_ERR_MEMORY;
+         }
+         if (!err) err = template_fill(&s, section_exports);
+         free_map(section_exports);
+         if (!err) err = string_join(&bookmarklet, s);
+      }
+   }
+   freez(state_template);
+   freez(bookmarklet_template);
+   if (!err) err = map(exports, "state", 1, state, 0);
+   if (!err) err = map(exports, "bookmarklet", 1, bookmarklet, 0);
+
+   if (err)
+   {
+      free_map(exports);
+      free(state_template);
+      free(bookmarklet_template);
+      free(state);
+      free(bookmarklet);
+      return JB_ERR_MEMORY;
+   }
+
+   template_name = (get_char_param(parameters, "mini")
+                 ? "forward-class-mini"
+                 : "forward-class");
+
+   return template_fill_for_cgi(csp, template_name, exports, rsp);
+}
+#endif /* def FEATURE_FORWARD_CLASS */
+
+
 /*********************************************************************
  *
  * Function    :  cgi_edit_actions_section_swap
diff --git a/cgiedit.h b/cgiedit.h
index 3b86410..855494e 100644
--- a/cgiedit.h
+++ b/cgiedit.h
@@ -82,6 +82,16 @@ extern jb_err cgi_edit_actions_section_add   (struct client_state *csp,
 extern jb_err cgi_edit_actions_section_swap  (struct client_state *csp,
                                               struct http_response *rsp,
                                               const struct map *parameters);
+#ifdef FEATURE_FORWARD_CLASS
+extern jb_err cgi_forward_class(struct client_state *csp,
+                                 struct http_response *rsp,
+                                 const struct map *parameters);
+#endif /* def FEATURE_FORWARD_CLASS */
+#ifdef FEATURE_MANUAL_TAGGER
+extern jb_err cgi_manual_tagger(struct client_state *csp,
+                                struct http_response *rsp,
+                                const struct map *parameters);
+#endif /* def FEATURE_MANUAL_TAGGER */
 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
 #ifdef FEATURE_TOGGLE
 extern jb_err cgi_toggle(struct client_state *csp,
diff --git a/cgisimple.c b/cgisimple.c
index 961510f..1ed808b 100644
--- a/cgisimple.c
+++ b/cgisimple.c
@@ -62,6 +62,9 @@
 #ifdef FEATURE_CLIENT_TAGS
 #include "client-tags.h"
 #endif
+#ifdef FEATURE_REQUIRED_TAG
+#include "requiredtag.h"
+#endif
 
 static jb_err show_defines(struct map *exports);
 static jb_err cgi_show_file(struct client_state *csp,
@@ -1761,7 +1764,11 @@ jb_err cgi_show_url_info(struct client_state *csp,
 
          for (; (b != NULL) && (matches != NULL); b = b->next)
          {
+#ifdef FEATURE_REQUIRED_TAG
+            if ((b->rtags == NULL || match_req_tag_list(b->rtags, csp->tags)) && url_match(b->url, url_to_query))
+#else
             if (url_match(b->url, url_to_query))
+#endif
             {
                string_append(&matches, "<tr><td>{");
                string_join  (&matches, actions_to_html(csp, b->action));
@@ -2201,6 +2208,38 @@ static jb_err show_defines(struct map *exports)
          1,
 #else
          0,
+#endif
+      },
+      {
+         "FEATURE_ADD_REFERER",
+#ifdef FEATURE_ADD_REFERER
+         1,
+#else
+         0,
+#endif
+      },
+      {
+         "FEATURE_FORWARD_CLASS",
+#ifdef FEATURE_FORWARD_CLASS
+         1,
+#else
+         0,
+#endif
+      },
+      {
+         "FEATURE_MANUAL_TAGGER",
+#ifdef FEATURE_MANUAL_TAGGER
+         1,
+#else
+         0,
+#endif
+      },
+      {
+         "FEATURE_REQUIRED_TAG",
+#ifdef FEATURE_REQUIRED_TAG
+         1,
+#else
+         0,
 #endif
       }
    };
diff --git a/configure.in b/configure.in
index a483dd8..776d878 100644
--- a/configure.in
+++ b/configure.in
@@ -82,6 +82,7 @@ VERSION_MAJOR=3
 VERSION_MINOR=0
 VERSION_POINT=34
 CODE_STATUS="stable"
+PATCHLEVEL=2
 
 dnl Timestamp (date +%s) used by the mtree-spec target.
 dnl Should be updated before releases but forgetting it isn't critical.
@@ -94,6 +95,7 @@ dnl =================================================================
 AC_SUBST(VERSION_MAJOR)
 AC_SUBST(VERSION_MINOR)
 AC_SUBST(VERSION_POINT)
+AC_SUBST(PATCHLEVEL)
 AC_SUBST(CODE_STATUS)
 AC_SUBST(SOURCE_DATE_EPOCH)
 
@@ -101,7 +103,9 @@ dnl
 AC_DEFINE_UNQUOTED(VERSION_MAJOR,${VERSION_MAJOR})
 AC_DEFINE_UNQUOTED(VERSION_MINOR,${VERSION_MINOR})
 AC_DEFINE_UNQUOTED(VERSION_POINT,${VERSION_POINT})
-AC_DEFINE_UNQUOTED(VERSION,"${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_POINT}")
+AC_DEFINE_UNQUOTED(PATCHLEVEL,${PATCHLEVEL})
+AC_DEFINE_UNQUOTED(VERSION,"${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_POINT}-y${PATCHLEVEL}")
+AC_DEFINE_UNQUOTED(DOC_VERSION,"${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_POINT}")
 AC_DEFINE_UNQUOTED(CODE_STATUS,"${CODE_STATUS}")
 
 dnl =================================================================
@@ -1056,6 +1060,38 @@ dnl AC_ARG_ENABLE(dynamic-pcrs,
 dnl [  --disable-dynamic-pcrs          Use the built-in, static pcrs, even if libpcrs is available],
 dnl [ if test $enableval = "no"; then have_pcrs=no; fi ])
 
+AC_ARG_ENABLE(add-referer,
+[  --disable-add-referer           Don't support add-referer action and extended paramters
+                                  for hide-referer action.],
+[if test $enableval = yes; then
+  AC_DEFINE(FEATURE_ADD_REFERER)
+fi],
+AC_DEFINE(FEATURE_ADD_REFERER))
+
+AC_ARG_ENABLE(forward-class,
+[  --disable-forward-class         Prevents forward class selection.],
+[if test $enableval = yes; then
+  AC_DEFINE(FEATURE_FORWARD_CLASS)
+fi],
+AC_DEFINE(FEATURE_FORWARD_CLASS))
+
+AC_ARG_ENABLE(manual-tagger,
+[  --disable-manual-tagger         Prevents manual tagger.],
+[if test $enableval = yes; then
+  AC_DEFINE(FEATURE_MANUAL_TAGGER)
+fi],
+AC_DEFINE(FEATURE_MANUAL_TAGGER))
+
+AC_ARG_ENABLE(required-tag,
+[  --disable-required-tag          Prevents required tag.],
+[if test $enableval = yes; then
+  AC_DEFINE(FEATURE_REQUIRED_TAG)
+  REQUIRED_TAG_ONLY=
+else
+  REQUIRED_TAG_ONLY=#
+fi],
+AC_DEFINE(FEATURE_REQUIRED_TAG))
+AC_SUBST(REQUIRED_TAG_ONLY)
 
 dnl ====================================================
 dnl This check is incomplete. For mingw32 zlib is found
diff --git a/filters.c b/filters.c
index 21ee44d..550981a 100644
--- a/filters.c
+++ b/filters.c
@@ -2820,6 +2820,10 @@ void get_url_actions(struct client_state *csp, struct http_request *http)
 
    init_current_action(csp->action);
 
+#ifdef FEATURE_MANUAL_TAGGER
+   update_action_bits_for_all_tags(csp);
+#endif
+
    for (i = 0; i < MAX_AF_FILES; i++)
    {
       if (((fl = csp->actions_list[i]) == NULL) || ((b = fl->f) == NULL))
@@ -2833,7 +2837,6 @@ void get_url_actions(struct client_state *csp, struct http_request *http)
       apply_url_actions(csp->action, http, b);
 #endif
    }
-
    return;
 }
 
@@ -2867,7 +2870,12 @@ static void apply_url_actions(struct current_action_spec *action,
 
    for (b = b->next; NULL != b; b = b->next)
    {
+#ifdef FEATURE_REQUIRED_TAG
+      /* Required tag is checked at another place. */
+      if (!b->rtags && url_match(b->url, http))
+#else /* def FEATURE_REQUIRED_TAG */
       if (url_match(b->url, http))
+#endif /* def FEATURE_REQUIRED_TAG */
       {
          merge_current_action(action, b->action);
       }
@@ -3050,7 +3058,11 @@ const struct forward_spec *forward_url(struct client_state *csp,
 
    while (fwd != NULL)
    {
+#ifdef FEATURE_FORWARD_CLASS
+      if (fwd->forward_class >= 0 && fwd->forward_class < MAX_FORWARD_CLASSES && csp->forward_class_state[fwd->forward_class] && url_match(fwd->url, http))
+#else
       if (url_match(fwd->url, http))
+#endif
       {
          return fwd;
       }
diff --git a/jbsockets.c b/jbsockets.c
index 1c4db68..cbfe464 100644
--- a/jbsockets.c
+++ b/jbsockets.c
@@ -53,6 +53,10 @@
 #include <windows.h>
 #include <sys/timeb.h>
 #include <io.h>
+#ifdef socklen_t
+#undef socklen_t
+#endif
+#include <ws2tcpip.h>
 
 #else
 
diff --git a/jcc.c b/jcc.c
index 4b69424..edb3a0f 100644
--- a/jcc.c
+++ b/jcc.c
@@ -4563,14 +4563,29 @@ static void chat(struct client_state *csp)
    freez(csp->headers->first->str);
    build_request_line(csp, fwd, &csp->headers->first->str);
 
-   if (fwd->forward_host)
+   if (fwd->gateway_host)
    {
-      log_error(LOG_LEVEL_CONNECT, "via [%s]:%d to: %s",
-         fwd->forward_host, fwd->forward_port, http->hostport);
+      if (fwd->forward_host)
+      {
+         log_error(LOG_LEVEL_CONNECT, "via SOCKS [%s]:%d via [%s]:%d to: %s",
+            fwd->gateway_host, fwd->gateway_port, fwd->forward_host, fwd->forward_port, http->hostport);
+      }
+      else
+      {
+         log_error(LOG_LEVEL_CONNECT, "via SOCKS [%s]:%d to %s", fwd->gateway_host, fwd->gateway_port, http->hostport);
+      }
    }
    else
    {
-      log_error(LOG_LEVEL_CONNECT, "to %s", http->hostport);
+      if (fwd->forward_host)
+      {
+         log_error(LOG_LEVEL_CONNECT, "via [%s]:%d to: %s",
+            fwd->forward_host, fwd->forward_port, http->hostport);
+      }
+      else
+      {
+         log_error(LOG_LEVEL_CONNECT, "to %s", http->hostport);
+      }
    }
 
    /* here we connect to the server, gateway, or the forwarder */
@@ -6306,6 +6321,21 @@ static void listen_loop(void)
          csp->flags |= CSP_FLAG_TOGGLED_ON;
       }
 
+#ifdef FEATURE_FORWARD_CLASS
+/* We need to set global forward class status to client associated status */
+      {
+        int i;
+         for(i = 0; i < MAX_FORWARD_CLASSES; i++) {
+            csp->forward_class_state[i] = global_forward_class_state[i];
+         }
+      }
+#endif /* def FEATURE_FORWARD_CLASS */
+
+#ifdef FEATURE_MANUAL_TAGGER
+/* We need to set global manual tagger status to client associated status */
+      list_duplicate(csp->tags, global_manual_tagger);
+#endif /* def FEATURE_MANUAL_TAGGER */
+
       if (run_loader(csp))
       {
          log_error(LOG_LEVEL_FATAL, "a loader failed - must exit");
diff --git a/loadcfg.c b/loadcfg.c
index 4efa2ea..85658c1 100644
--- a/loadcfg.c
+++ b/loadcfg.c
@@ -103,6 +103,15 @@
 int global_toggle_state = 1;
 #endif /* def FEATURE_TOGGLE */
 
+#ifdef FEATURE_FORWARD_CLASS
+int global_forward_class_state[MAX_FORWARD_CLASSES] = { 1 };
+#endif /* def FEATURE_FORWARD_CLASS */
+
+#ifdef FEATURE_MANUAL_TAGGER
+struct list global_manual_tagger_[1];
+struct list* global_manual_tagger = global_manual_tagger_;
+#endif /* def FEATURE_MANUAL_TAGGER */
+
 /* The filename of the configfile */
 const char *configfile  = NULL;
 
@@ -157,6 +166,7 @@ static struct file_list *current_configfile = NULL;
 #define hash_enforce_blocks              1862427469U /* "enforce-blocks" */
 #define hash_filterfile                   250887266U /* "filterfile" */
 #define hash_forward                        2029845U /* "forward" */
+#define hash_forward_class               1651776168U /* "forward-class" */
 #define hash_forward_socks4              3963965521U /* "forward-socks4" */
 #define hash_forward_socks4a             2639958518U /* "forward-socks4a" */
 #define hash_forward_socks5              3963965522U /* "forward-socks5" */
@@ -169,6 +179,7 @@ static struct file_list *current_configfile = NULL;
 #define hash_listen_backlog              1255655735U /* "listen-backlog" */
 #define hash_logdir                          422889U /* "logdir" */
 #define hash_logfile                        2114766U /* "logfile" */
+#define hash_manual_tagger               2633089997U /* "manual-tagger" */
 #define hash_max_client_connections      3595884446U /* "max-client-connections" */
 #define hash_permit_access               3587953268U /* "permit-access" */
 #define hash_proxy_info_url              3903079059U /* "proxy-info-url" */
@@ -258,6 +269,21 @@ static void unload_configfile (void * data)
    }
    freez(config->logfile);
 
+#ifdef FEATURE_FORWARD_CLASS
+   for (i = 0; i < MAX_FORWARD_CLASSES; i++)
+   {
+      freez(config->forward_class[i].name);
+   }
+#endif /* def FEATURE_FORWARD_CLASS */
+
+#ifdef FEATURE_MANUAL_TAGGER
+   for (i = 0; i < MAX_MANUAL_TAGGERS; i++)
+   {
+      freez(config->manual_tagger[i].name);
+      freez(config->manual_tagger[i].tag);
+   }
+#endif /* def FEATURE_MANUAL_TAGGER */
+
    for (i = 0; i < MAX_AF_FILES; i++)
    {
       freez(config->actions_file_short[i]);
@@ -611,6 +637,17 @@ struct configuration_spec * load_config(void)
    global_toggle_state = 1;
 #endif /* def FEATURE_TOGGLE */
 
+#ifdef FEATURE_FORWARD_CLASS
+   for(i = 0; i < MAX_FORWARD_CLASSES; i++)
+   {
+      global_forward_class_state[i] = 0;
+   }
+#endif /* def FEATURE_FORWARD_CLASS */
+
+#ifdef FEATURE_MANUAL_TAGGER
+   list_remove_all(global_manual_tagger);
+#endif /* def FEATURE_MANUAL_TAGGER */
+
    fs->f = config = zalloc_or_die(sizeof(*config));
 
    /*
@@ -697,7 +734,11 @@ struct configuration_spec * load_config(void)
 #endif /* def FEATURE_ACL */
       struct forward_spec *cur_fwd;
       int vec_count;
+#ifdef FEATURE_FORWARD_CLASS
+      char *vec[4];
+#else  /* def FEATURE_FORWARD_CLASS */
       char *vec[3];
+#endif  /* def FEATURE_FORWARD_CLASS */
       unsigned int directive_hash;
 
       strlcpy(tmp, buf, sizeof(tmp));
@@ -1160,7 +1201,11 @@ struct configuration_spec * load_config(void)
             strlcpy(tmp, arg, sizeof(tmp));
             vec_count = ssplit(tmp, " \t", vec, SZ(vec));
 
+#ifdef FEATURE_FORWARD_CLASS
+            if (vec_count != 2 && vec_count != 3)
+#else  /* def FEATURE_FORWARD_CLASS */
             if (vec_count != 2)
+#endif  /* def FEATURE_FORWARD_CLASS */
             {
                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for forward "
                      "directive in configuration file.");
@@ -1197,12 +1242,65 @@ struct configuration_spec * load_config(void)
                   NULL, NULL);
             }
 
+#ifdef FEATURE_FORWARD_CLASS
+            /* Set forward class */
+            if (vec_count == 3) {
+               cur_fwd->forward_class = atoi(vec[2]);
+               if(cur_fwd->forward_class > MAX_FORWARD_CLASSES) {
+                 log_error(LOG_LEVEL_ERROR, "Forward class number for forward directive in configuration file is more than limit - the limit is %d.\n"
+                    "(You can increase this limit by changing MAX_FORWARD_CLASSES in project.h and recompiling).",
+                    MAX_FORWARD_CLASSES);
+                 string_append(&config->proxy_args,
+                    "<br>\nWARNING: Forward class number for forward directive"
+                    " in configuration file is more than limit.");
+                 break;
+               }
+            } else {
+               cur_fwd->forward_class = 0;
+            }
+#endif /* def FEATURE_FORWARD_CLASS */
+
             /* Add to list. */
             cur_fwd->next = config->forward;
             config->forward = cur_fwd;
 
             break;
 
+#ifdef FEATURE_FORWARD_CLASS
+/* *************************************************************************
+ * forward-class class-name default-status
+ * *************************************************************************/
+         case hash_forward_class:
+            i = 0;
+            while ((i < MAX_FORWARD_CLASSES) && (NULL != config->forward_class[i].name))
+            {
+               i++;
+            }
+
+            if (i >= MAX_FORWARD_CLASSES)
+            {
+               log_error(LOG_LEVEL_FATAL, "Too many 'forward-class' directives in config file - limit is %d.\n"
+                  "(You can increase this limit by changing MAX_FORWARD_CLASSES in project.h and recompiling).",
+                  MAX_FORWARD_CLASSES);
+            }
+
+            strlcpy(tmp, arg, sizeof(tmp));
+            vec_count = ssplit(tmp, " \t", vec, SZ(vec));
+            if (vec_count != 2)
+            {
+               log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for forward class "
+                     "directive in configuration file.");
+               string_append(&config->proxy_args,
+                  "<br>\nWARNING: Wrong number of parameters for "
+                  "forward class directive in configuration file.");
+               break;
+            }
+
+            config->forward_class[i].name = strdup(vec[0]);
+            config->forward_class[i].state = global_forward_class_state[i] = atoi(vec[1]);
+            break;
+#endif /* def FEATURE_FORWARD_CLASS */
+
 /* *************************************************************************
  * forward-socks4 url-pattern socks-proxy[:port] (.|http-proxy[:port])
  * *************************************************************************/
@@ -1210,7 +1308,11 @@ struct configuration_spec * load_config(void)
             strlcpy(tmp, arg, sizeof(tmp));
             vec_count = ssplit(tmp, " \t", vec, SZ(vec));
 
+#ifdef FEATURE_FORWARD_CLASS
+            if (vec_count != 3 && vec_count != 4)
+#else /* def FEATURE_FORWARD_CLASS */
             if (vec_count != 3)
+#endif /* def FEATURE_FORWARD_CLASS */
             {
                log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for "
                      "forward-socks4 directive in configuration file.");
@@ -1259,6 +1361,24 @@ struct configuration_spec * load_config(void)
                   NULL, NULL);
             }
 
+#ifdef FEATURE_FORWARD_CLASS
+            /* Set forward class */
+            if (vec_count == 4) {
+               cur_fwd->forward_class = atoi(vec[3]);
+               if(cur_fwd->forward_class > MAX_FORWARD_CLASSES) {
+                 log_error(LOG_LEVEL_ERROR, "Forward class number for forward directive in configuration file is more than limit - the limit is %d.\n"
+                    "(You can increase this limit by changing MAX_FORWARD_CLASSES in project.h and recompiling).",
+                    MAX_FORWARD_CLASSES);
+                 string_append(&config->proxy_args,
+                    "<br>\nWARNING: Forward class number for forward-socks4 directive"
+                    " in configuration file is more than limit.");
+                 continue;
+              }
+            } else {
+               cur_fwd->forward_class = 0;
+            }
+#endif /* def FEATURE_FORWARD_CLASS */
+
             /* Add to list. */
             cur_fwd->next = config->forward;
             config->forward = cur_fwd;
@@ -1274,7 +1394,11 @@ struct configuration_spec * load_config(void)
             strlcpy(tmp, arg, sizeof(tmp));
             vec_count = ssplit(tmp, " \t", vec, SZ(vec));
 
+#ifdef FEATURE_FORWARD_CLASS
+            if (vec_count != 3 && vec_count != 4)
+#else /* def FEATURE_FORWARD_CLASS */
             if (vec_count != 3)
+#endif /* def FEATURE_FORWARD_CLASS */
             {
                log_error(LOG_LEVEL_ERROR,
                   "Wrong number of parameters for %s in configuration file.",
@@ -1338,6 +1462,24 @@ struct configuration_spec * load_config(void)
                   NULL, NULL);
             }
 
+#ifdef FEATURE_FORWARD_CLASS
+            /* Set forward class */
+            if (vec_count == 4) {
+               cur_fwd->forward_class = atoi(vec[3]);
+               if(cur_fwd->forward_class > MAX_FORWARD_CLASSES) {
+                 log_error(LOG_LEVEL_ERROR, "Forward class number for forward directive in configuration file is more than limit - the limit is %d.\n"
+                    "(You can increase this limit by changing MAX_FORWARD_CLASSES in project.h and recompiling).",
+                    MAX_FORWARD_CLASSES);
+                 string_append(&config->proxy_args,
+                    "<br>\nWARNING: Forward class number for forward-socks4a directive"
+                    " in configuration file is more than limit.");
+                 continue;
+               }
+            } else {
+               cur_fwd->forward_class = 0;
+            }
+#endif /* def FEATURE_FORWARD_CLASS */
+
             /* Add to list. */
             cur_fwd->next = config->forward;
             config->forward = cur_fwd;
@@ -1499,6 +1641,44 @@ struct configuration_spec * load_config(void)
             break;
          }
 
+/* *************************************************************************
+ * manual-tagger display-name tag default-state
+ * *************************************************************************/
+#ifdef FEATURE_MANUAL_TAGGER
+         case hash_manual_tagger :
+            i = 0;
+            while ((i < MAX_MANUAL_TAGGERS) && (NULL != config->manual_tagger[i].name))
+            {
+               i++;
+            }
+
+            if (i >= MAX_MANUAL_TAGGERS)
+            {
+               log_error(LOG_LEVEL_FATAL, "Too many 'manual-tagger' directives in config file - limit is %d.\n"
+                  "(You can increase this limit by changing MAX_MANUAL_TAGGERS in project.h and recompiling).",
+                  MAX_MANUAL_TAGGERS);
+            }
+
+            vec_count = ssplit(arg, " \t", vec, SZ(vec));
+            if (vec_count != 3)
+            {
+               log_error(LOG_LEVEL_ERROR, "Wrong number of parameters for manual-tagger "
+                     "directive in configuration file.");
+               string_append(&config->proxy_args,
+                  "<br>\nWARNING: Wrong number of parameters for "
+                  "manual-tagger directive in configuration file.");
+               continue;
+            }
+
+            config->manual_tagger[i].name  = strdup(vec[0]);
+            config->manual_tagger[i].tag   = strdup(vec[1]);
+            config->manual_tagger[i].state = atoi(vec[2]);
+            if(config->manual_tagger[i].state) {
+               enlist_unique(global_manual_tagger, config->manual_tagger[i].tag, 0);
+            }
+            continue;
+#endif /* def FEATURE_MANUAL_TAGGER */
+
 /* *************************************************************************
  * permit-access source-ip[/significant-bits] [dest-ip[/significant-bits]]
  * *************************************************************************/
@@ -1924,6 +2104,12 @@ struct configuration_spec * load_config(void)
 #ifndef FEATURE_TOGGLE
          case hash_enable_remote_toggle:
 #endif /* ndef FEATURE_TOGGLE */
+#ifndef FEATURE_FORWARD_CLASS
+         case hash_forward_class :
+#endif /* ndef FEATURE_FORWARD_CLASS */
+#ifndef FEATURE_MANUAL_TAGGER
+         case hash_manual_tagger :
+#endif /* ndef FEATURE_MANUAL_TAGGER */
 #ifndef FEATURE_ACL
          case hash_permit_access:
 #endif /* ndef FEATURE_ACL */
@@ -2144,6 +2330,17 @@ struct configuration_spec * load_config(void)
    g_trustfile        = config->trustfile;
 #endif /* def FEATURE_TRUST */
 
+#ifdef FEATURE_FORWARD_CLASS
+   if(config->forward_class[0].name == NULL) {
+      config->forward_class[0].name = strdup("Default");
+      global_forward_class_state[0] = config->forward_class[0].state = 1;
+   }
+   g_forward_class = config->forward_class;
+#endif /* def FEATURE_FORWARD_CLASS */
+
+#ifdef FEATURE_MANUAL_TAGGER
+   g_manual_tagger = config->manual_tagger;
+#endif /* def FEATURE_MANUAL_TAGGER */
 
 #endif /* defined(_WIN32) && !defined (_WIN_CONSOLE) */
 /* FIXME: end kludge */
diff --git a/loadcfg.h b/loadcfg.h
index ac0b0bd..a0a410d 100644
--- a/loadcfg.h
+++ b/loadcfg.h
@@ -47,6 +47,16 @@ struct configuration_spec;
 extern int global_toggle_state;
 #endif /* def FEATURE_TOGGLE */
 
+#ifdef FEATURE_FORWARD_CLASS
+/* Unfortunately, project.h is required by MAX_FORWARD_CLASSES */
+#include "project.h"
+extern int global_forward_class_state[MAX_FORWARD_CLASSES];
+#endif /* def FEATURE_FORWARD_CLASS */
+
+#ifdef FEATURE_MANUAL_TAGGER
+extern struct list* global_manual_tagger;
+#endif /* def FEATURE_MANUAL_TAGGER */
+
 extern const char *configfile;
 
 
diff --git a/parsers.c b/parsers.c
index 1cb46df..3f20faa 100644
--- a/parsers.c
+++ b/parsers.c
@@ -74,7 +74,7 @@
 
 #include "project.h"
 
-#ifdef FEATURE_PTHREAD
+#if defined(FEATURE_PTHREAD) || defined(_WIN32)
 #include "jcc.h"
 /* jcc.h is for mutex semapores only */
 #endif /* def FEATURE_PTHREAD */
@@ -154,11 +154,18 @@ static jb_err server_connection_adder(struct client_state *csp);
 static jb_err server_proxy_connection_adder(struct client_state *csp);
 #endif /* def FEATURE_CONNECTION_KEEP_ALIVE */
 static jb_err proxy_authentication(struct client_state *csp, char **header);
+#ifdef FEATURE_ADD_REFERER
+static jb_err client_referrer_adder   (struct client_state *csp);
+#endif /* def FEATURE_ADD_REFERER */
 
-static jb_err create_forged_referrer(char **header, const char *hostport);
-static jb_err create_fake_referrer(char **header, const char *fake_referrer);
+static jb_err create_forged_referrer(char **header, const char *hostport, int is_add);
+static jb_err create_fake_referrer(char **header, const char *fake_referrer, int is_add);
 static jb_err handle_conditional_hide_referrer_parameter(char **header,
    const char *host, const int parameter_conditional_block);
+#ifdef FEATURE_ADD_REFERER
+static jb_err create_forged_referrer2(char **header, const char *url, int is_index, int is_add);
+static jb_err create_filtered_referrer(char **header, const char *url, const char *regex, int is_add);
+#endif
 static void create_content_length_header(unsigned long long content_length,
                                          char *header, size_t buffer_length);
 
@@ -240,6 +247,9 @@ static const struct parsers server_patterns[] = {
 static const add_header_func_ptr add_client_headers[] = {
    client_host_adder,
    client_x_forwarded_for_adder,
+#ifdef FEATURE_ADD_REFERER
+   client_referrer_adder,
+#endif
    client_xtra_adder,
    client_connection_header_adder,
    NULL
@@ -3148,16 +3158,114 @@ static jb_err client_referrer(struct client_state *csp, char **header)
    }
    else if (0 == strcmpic(parameter, "forge"))
    {
-      return create_forged_referrer(header, csp->http->hostport);
+      return create_forged_referrer(header, csp->http->hostport, 0 /* hide */);
+   }
+#ifdef FEATURE_ADD_REFERER
+   else if (0 == strcmpic(parameter, "directory"))
+   {
+      return create_forged_referrer2(header, csp->http->url, 0 /* index */, 0 /* hide */);
+   }
+   else if (0 == strcmpic(parameter, "index"))
+   {
+      return create_forged_referrer2(header, csp->http->url, 1 /* index */, 0 /* hide */);
    }
+   else if (0 == strcmpic(parameter, "self"))
+   {
+      *header = strdup("Referer: ");
+      string_append(header, csp->http->url);
+
+      log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header);
+
+      return (*header == NULL) ? JB_ERR_MEMORY : JB_ERR_OK;
+   }
+   else if ('%' == *parameter && 's' == parameter[1])
+   {
+      return create_filtered_referrer(header, csp->http->url, parameter + 1, 0 /* hide */);
+   }
+#endif /* def FEATURE_ADD_REFERER */
    else
    {
       /* interpret parameter as user-supplied referer to fake */
-      return create_fake_referrer(header, parameter);
+      return create_fake_referrer(header, parameter, 0 /* hide */);
    }
 }
 
 
+#ifdef FEATURE_ADD_REFERER
+/*********************************************************************
+ *
+ * Function    :  client_referrer_adder
+ *
+ * Description :  Adds a Referer header field if it is missing.
+ *                Called from `sed'.
+ *
+ * Parameters  :
+ *          1  :  csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns     :  JB_ERR_OK on success, or
+ *                JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+jb_err client_referrer_adder(struct client_state *csp)
+{
+   const char *parameter;
+   char *header = NULL;
+   jb_err err = JB_ERR_OK;
+
+   /*
+    * Are we adding referer?
+    */
+   if ((csp->action->flags & ACTION_ADD_REFERER) == 0)
+   {
+      return JB_ERR_OK;
+   }
+
+   parameter = csp->action->string[ACTION_STRING_ADD_REFERER];
+
+   if ((parameter == NULL) || (0 == strcmpic(parameter, "block")) )
+   {
+      /*
+       * Blocking referer
+       */
+      log_error(LOG_LEVEL_HEADER, "Referer crunched!");
+      return JB_ERR_OK;
+   }
+   else if (0 == strcmpic(parameter, "forge"))
+   {
+      err = create_forged_referrer(&header, csp->http->hostport, 1 /* add */);
+   }
+   else if (0 == strcmpic(parameter, "directory"))
+   {
+      err = create_forged_referrer2(&header, csp->http->url, 0 /* dir */, 1 /* add */);
+   }
+   else if (0 == strcmpic(parameter, "index"))
+   {
+      err = create_forged_referrer2(&header, csp->http->url, 1 /* index */, 1 /* add */);
+   }
+   else if (0 == strcmpic(parameter, "self"))
+   {
+      header = strdup(csp->http->url);
+   }
+   else if ('%' == *parameter && 's' == parameter[1])
+   {
+      err = create_filtered_referrer(&header, csp->http->url, parameter + 1, 1 /* add */);
+   }
+   else
+   {
+      err = create_fake_referrer(&header, parameter, 1 /* add */);
+   }
+
+   if(err == JB_ERR_OK)
+   {
+      log_error(LOG_LEVEL_HEADER, "addh-unique: Referer: %s", header);
+      err = enlist_unique_header(csp->headers, "Referer", header);
+      freez(header);
+   }
+   return err;
+}
+#endif /* def FEATURE_ADD_REFERER */
+
+
 /*********************************************************************
  *
  * Function    :  client_accept_language
@@ -4835,16 +4943,18 @@ jb_err get_destination_from_https_headers(const struct list *headers, struct htt
  * Parameters  :
  *          1  :  header   = Pointer to header pointer
  *          2  :  hostport = Host and optionally port as string
+ *          3  :  is_add   = Boolean to signal whether add or hide
+ *                           (0 : hide / 1 : add)
  *
  * Returns     :  JB_ERR_OK in case of success, or
  *                JB_ERR_MEMORY in case of memory problems.
  *
  *********************************************************************/
-static jb_err create_forged_referrer(char **header, const char *hostport)
+static jb_err create_forged_referrer(char **header, const char *hostport, int is_add)
 {
     assert(NULL == *header);
 
-    *header = strdup("Referer: http://");
+    *header = strdup(is_add ? "http://" : "Referer: http://");
     string_append(header, hostport);
     string_append(header, "/");
 
@@ -4853,7 +4963,14 @@ static jb_err create_forged_referrer(char **header, const char *hostport)
        return JB_ERR_MEMORY;
     }
 
-    log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header);
+   if (is_add)
+   {
+      log_error(LOG_LEVEL_HEADER, "addh-unique: Referer: %s", *header);
+   }
+   else
+   {
+      log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header);
+   }
 
     return JB_ERR_OK;
 
@@ -4870,29 +4987,45 @@ static jb_err create_forged_referrer(char **header, const char *hostport)
  * Parameters  :
  *          1  :  header   = Pointer to header pointer
  *          2  :  hosthost = Referrer to fake
+ *          3  :  is_add   = Boolean to signal whether add or hide
+ *                           (0 : hide / 1 : add)
  *
  * Returns     :  JB_ERR_OK in case of success, or
  *                JB_ERR_MEMORY in case of memory problems.
  *
  *********************************************************************/
-static jb_err create_fake_referrer(char **header, const char *fake_referrer)
+static jb_err create_fake_referrer(char **header, const char *fake_referrer, int is_add)
 {
    assert(NULL == *header);
 
    if ((0 != strncmpic(fake_referrer, "http://", 7)) && (0 != strncmpic(fake_referrer, "https://", 8)))
    {
       log_error(LOG_LEVEL_HEADER,
-         "Parameter: +hide-referrer{%s} is a bad idea, but I don't care.", fake_referrer);
+         "Parameter: +%s-referrer{%s} is a bad idea, but I don't care.", is_add ? "add" : "hide", fake_referrer);
+   }
+
+   if(is_add) {
+      *header = strdup(fake_referrer);
+   }
+   else
+   {
+      *header = strdup("Referer: ");
+      string_append(header, fake_referrer);
    }
-   *header = strdup("Referer: ");
-   string_append(header, fake_referrer);
 
    if (NULL == *header)
    {
       return JB_ERR_MEMORY;
    }
 
-   log_error(LOG_LEVEL_HEADER, "Referer replaced with: %s", *header);
+   if (is_add)
+   {
+      log_error(LOG_LEVEL_HEADER, "addh-unique: Referer: %s", *header);
+   }
+   else
+   {
+      log_error(LOG_LEVEL_HEADER, "Referer replaced with: %s", *header);
+   }
 
    return JB_ERR_OK;
 
@@ -4904,10 +5037,9 @@ static jb_err create_fake_referrer(char **header, const char *fake_referrer)
  * Function    :  handle_conditional_hide_referrer_parameter
  *
  * Description :  Helper for client_referrer to crunch or forge
- *                the referrer header if the host has changed.
  *
  * Parameters  :
- *          1  :  header = Pointer to header pointer
+ *          1  :  header   = Pointer to header pointer
  *          2  :  host   = The target host (may include the port)
  *          3  :  parameter_conditional_block = Boolean to signal
  *                if we're in conditional-block mode. If not set,
@@ -4951,7 +5083,7 @@ static jb_err handle_conditional_hide_referrer_parameter(char **header,
       {
          freez(*header);
          freez(referer);
-         return create_forged_referrer(header, host);
+         return create_forged_referrer(header, host, 0 /* hide */);
       }
    }
    freez(referer);
@@ -4989,6 +5121,141 @@ static void create_content_length_header(unsigned long long content_length,
 }
 
 
+#ifdef FEATURE_ADD_REFERER
+/*********************************************************************
+ *
+ * Function    :  create_forged_referrer2
+ *
+ * Description :  Helper for client_referrer to forge a referer as
+ *                'http://[hostname:port/dir/index.html' or
+ *                'http://[hostname:port/dir/' to fool stupid
+ *                checks for in-site links
+ *
+ * Parameters  :
+ *          1  :  header   = Pointer to header pointer
+ *          2  :  url      = Target URL
+ *          3  :  is_index = Boolean to signal whether index or
+ *                           directory (0 : directory / 1 : index)
+ *          4  :  is_add   = Boolean to signal whether add or hide
+ *                           (0 : hide / 1 : add)
+ *
+ * Returns     :  JB_ERR_OK in case of success, or
+ *                JB_ERR_MEMORY in case of memory problems.
+ *
+ *********************************************************************/
+static jb_err create_forged_referrer2( char **header, const char *url, int is_index, int is_add )
+{
+   char *temp_url, *idx, *end;
+
+   assert(NULL == *header);
+
+   if(is_add) {
+      temp_url = strdup(url);
+   }
+   else
+   {
+      temp_url = strdup("Referer: ");
+      string_append(&temp_url, url);
+   }
+
+   if (NULL == temp_url)
+   {
+      return JB_ERR_MEMORY;
+   }
+
+   for(idx = temp_url, end = NULL; *idx != '\0' && *idx != '?'; idx++)
+      if(*idx == '/') end = idx;
+
+   if(end == NULL)
+   {
+      *idx = '\0';
+      string_append(&temp_url, "/");
+   }
+   else
+   {
+      *++end = '\0';
+   }
+
+   *header = strdup(temp_url);
+   freez(temp_url);
+   if(is_index)
+   {
+     string_append(header, "index.html");
+   }
+
+   if (NULL == *header)
+   {
+      return JB_ERR_MEMORY;
+   }
+
+   if (is_add)
+   {
+      log_error(LOG_LEVEL_HEADER, "addh-unique: Referer: %s", *header);
+   }
+   else
+   {
+      log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header);
+   }
+   return JB_ERR_OK;
+}
+
+/*********************************************************************
+ *
+ * Function    :  create_filtered_referrer
+ *
+ * Description :  Helper for client_referrer to filter a referer by regex
+ *
+ * Parameters  :
+ *          1  :  header = Pointer to header pointer
+ *          2  :  url    = Target URL
+ *          3  :  regex  = Regular expression
+ *          4  :  is_add = Boolean to signal whether add or hide
+ *                         (0 : hide / 1 : add)
+ *
+ * Returns     :  JB_ERR_OK in case of success, or
+ *                JB_ERR_MEMORY in case of memory problems.
+ *
+ *********************************************************************/
+static jb_err create_filtered_referrer( char **header, const char *url, const char *regex, int is_add )
+{
+   char *temp_url = NULL;
+   int hits;
+
+   assert(NULL == *header);
+   assert(url);
+   assert(regex);
+
+   temp_url = pcrs_execute_single_command(url, regex, &hits);
+
+   if(is_add)
+   {
+      *header = strdup(temp_url);
+   }
+   else
+   {
+      *header = strdup("Referer: ");
+      string_append(header, temp_url);
+   }
+   freez(temp_url);
+
+   if (NULL == *header)
+   {
+      return JB_ERR_MEMORY;
+   }
+
+   if (is_add)
+   {
+      log_error(LOG_LEVEL_HEADER, "addh-unique: Referer: %s", *header);
+   }
+   else
+   {
+      log_error(LOG_LEVEL_HEADER, "Referer forged to: %s", *header);
+   }
+   return JB_ERR_OK;
+}
+#endif
+
+
 /*********************************************************************
  *
  * Function    :  get_expected_content_length
diff --git a/project.h b/project.h
index e8bb678..97dc6e1 100644
--- a/project.h
+++ b/project.h
@@ -575,6 +575,9 @@ struct iob
 #define ACTION_HTTPS_INSPECTION                      0x20000000UL
 /** Action bitmap: Turn certificates verification off */
 #define ACTION_IGNORE_CERTIFICATE_ERRORS             0x40000000UL
+/** Action bitmap: Add "Referer" header.  (sic - follow HTTP, not English). */
+#define ACTION_ADD_REFERER                           0x80000000UL
+
 
 /** Action string index: How to deanimate GIFs */
 #define ACTION_STRING_DEANIMATE             0
@@ -616,8 +619,10 @@ struct iob
 #define ACTION_STRING_LIMIT_COOKIE_LIFETIME 18
 /** Action string index: how many milliseconds writes should be delayed. */
 #define ACTION_STRING_DELAY_RESPONSE       19
+/** Action string index: Completion string for "Referer:" header */
+#define ACTION_STRING_ADD_REFERER          20
 /** Number of string actions. */
-#define ACTION_STRING_COUNT                20
+#define ACTION_STRING_COUNT                21
 
 
 /* To make the ugly hack in sed easier to understand */
@@ -698,6 +703,19 @@ struct action_spec
    struct list multi_add[ACTION_MULTI_COUNT][1];
 };
 
+#ifdef FEATURE_REQUIRED_TAG
+/**
+ * A required tag list entry.
+ *
+ * This is a linked list.
+ */
+struct req_tag_list
+{
+   regex_t *tag_regex;         /**< Regex for tag matching      */
+
+   struct req_tag_list *next;  /**< The next entry in the list. */
+};
+#endif /* def FEATURE_REQUIRED_TAG */
 
 /**
  * This structure is used to store action files.
@@ -715,6 +733,13 @@ struct url_actions
                                     the list entry before or after the current
                                     one and can't be free'd willy nilly. */
 
+#ifdef FEATURE_REQUIRED_TAG
+   struct req_tag_list *rtags; /**< Required tags that might be shared with
+                                    the list entry before or after the current
+                                    one and can't be free'd willy nilly. */
+
+#endif /* def FEATURE_REQUIRED_TAG */
+
    struct url_actions *next;   /**< Next action section in file, or NULL. */
 };
 
@@ -969,6 +994,22 @@ struct reusable_connection
  */
 #define MAX_AF_FILES 100
 
+#ifdef FEATURE_FORWARD_CLASS
+/**
+ * Maximum number of forward classes.  This limit is arbitrary - it's just used
+ * to size an array.
+ */
+#define MAX_FORWARD_CLASSES 10
+#endif /* def FEATURE_FORWARD_CLASS */
+
+#ifdef FEATURE_MANUAL_TAGGER
+/**
+ * Maximum number of manual taggers.  This limit is arbitrary - it's just used
+ * to size an array.
+ */
+#define MAX_MANUAL_TAGGERS 10
+#endif /* def FEATURE_MANUAL_TAGGER */
+
 /**
  * Maximum number of sockets to listen to.  This limit is arbitrary - it's just used
  * to size an array.
@@ -1145,6 +1186,11 @@ struct client_state
     */
    struct certs_chain server_certs_chain;
 #endif
+
+#ifdef FEATURE_FORWARD_CLASS
+   /** Forward class state associated with this client */
+   int forward_class_state[MAX_FORWARD_CLASSES];
+#endif /* def FEATURE_FORWARD_CLASS */
 };
 
 /**
@@ -1283,10 +1329,45 @@ struct forward_spec
    /** Parent HTTP proxy port. */
    int   forward_port;
 
+#ifdef FEATURE_FORWARD_CLASS
+   /** Forward class for selection. */
+   int   forward_class;
+#endif /* def FEATURE_FORWARD_CLASS */
+
    /** Next entry in the linked list. */
    struct forward_spec *next;
 };
 
+#ifdef FEATURE_FORWARD_CLASS
+#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, 0, NULL, 0, 0, NULL }
+#else /* def FEATURE_FORWARD_CLASS */
+#define FORWARD_SPEC_INITIALIZER { { URL_SPEC_INITIALIZER }, 0, NULL, 0, NULL, 0, NULL }
+#endif /* def FEATURE_FORWARD_CLASS */
+
+#ifdef FEATURE_FORWARD_CLASS
+struct forward_class_spec
+{
+   /** Class name. */
+   char *name;
+
+   /** State of selection. */
+   int   state;
+};
+#endif /* def FEATURE_FORWARD_CLASS */
+
+#ifdef FEATURE_MANUAL_TAGGER
+struct manual_tagger_spec
+{
+   /** Tagger name. */
+   char *name;
+
+   /** Tag. */
+   char *tag;
+
+   /** Default state. */
+   int   state;
+};
+#endif /* def FEATURE_MANUAL_TAGGER */
 
 /* Supported filter types */
 enum filter_type
@@ -1543,6 +1624,11 @@ struct configuration_spec
    /** Information about parent proxies (forwarding). */
    struct forward_spec *forward;
 
+#ifdef FEATURE_FORWARD_CLASS
+   /** Information about parent proxy (forwarding) classes. */
+   struct forward_class_spec forward_class[MAX_FORWARD_CLASSES];
+#endif /* def FEATURE_FORWARD_CLASS */
+
    /** Number of retries in case a forwarded connection attempt fails */
    int forwarded_connect_retries;
 
@@ -1567,6 +1653,11 @@ struct configuration_spec
    /** All options from the config file, HTML-formatted. */
    char *proxy_args;
 
+#ifdef FEATURE_MANUAL_TAGGER
+   /** Information about manual taggers. */
+   struct manual_tagger_spec manual_tagger[MAX_MANUAL_TAGGERS];
+#endif /* def FEATURE_MANUAL_TAGGER */
+
    /** The configuration file object. */
    struct file_list *config_file_list;
 
@@ -1620,7 +1711,7 @@ struct configuration_spec
 #define HOME_PAGE_URL     "https://www.privoxy.org/"
 
 /** URL for the Privoxy user manual. */
-#define USER_MANUAL_URL   HOME_PAGE_URL VERSION "/user-manual/"
+#define USER_MANUAL_URL   HOME_PAGE_URL DOC_VERSION "/user-manual/"
 
 /** Prefix for actions help links  (append to USER_MANUAL_URL). */
 #define ACTIONS_HELP_PREFIX "actions-file.html#"
diff --git a/requiredtag.c b/requiredtag.c
new file mode 100644
index 0000000..c8ff514
--- /dev/null
+++ b/requiredtag.c
@@ -0,0 +1,85 @@
+#include <assert.h>
+
+#include "project.h"
+#include "requiredtag.h"
+#include "errlog.h"
+#include "miscutil.h"
+
+jb_err init_req_tag_list(struct req_tag_list *tags, const char* pattern)
+{
+   int errcode;
+   char ebuf[BUFFER_SIZE];
+
+   tags->next = NULL;
+
+   tags->tag_regex = zalloc(sizeof(*tags->tag_regex));
+   if (NULL == tags->tag_regex)
+   {
+      return JB_ERR_MEMORY;
+   }
+
+   errcode = regcomp(tags->tag_regex, pattern, (REG_EXTENDED|REG_NOSUB|REG_ICASE));
+
+   if (errcode)
+   {
+      size_t errlen = regerror(errcode, tags->tag_regex, ebuf, sizeof(ebuf));
+      if (errlen > (sizeof(ebuf) - (size_t)1))
+      {
+         errlen = sizeof(ebuf) - (size_t)1;
+      }
+      log_error(LOG_LEVEL_ERROR, "error compiling %s : %s",
+         pattern, ebuf);
+
+      return JB_ERR_PARSE;
+   }
+
+   return JB_ERR_OK;
+}
+
+void free_req_tag_list(struct req_tag_list *tags)
+{
+   struct req_tag_list *temp;
+
+   if (tags == NULL) return;
+
+   while(tags)
+   {
+      if (tags->tag_regex)
+      {
+         regfree(tags->tag_regex);
+         freez(tags->tag_regex);
+      }
+      temp = tags;
+      tags = tags->next;
+      freez(temp);
+   }
+}
+
+static int match_req_tag(struct req_tag_list *rtags, struct list *tags)
+{
+   struct list_entry *tag;
+
+   for (tag = tags->first; tag != NULL; tag = tag->next)
+   {
+      if (0 == regexec(rtags->tag_regex, tag->str, 0, NULL, 0))
+      {
+         return 1;
+      }
+   }
+   return 0;
+}
+
+int match_req_tag_list(struct req_tag_list *rtags, struct list *tags)
+{
+   assert(rtags);
+
+   while(rtags)
+   {
+      if (0 == match_req_tag(rtags, tags))
+      {
+         return 0;
+      }
+      rtags = rtags->next;
+   }
+   return 1;
+}
diff --git a/requiredtag.h b/requiredtag.h
new file mode 100644
index 0000000..badd6de
--- /dev/null
+++ b/requiredtag.h
@@ -0,0 +1,22 @@
+#ifndef REQUIREDTAG_H_INCLUDED
+#define REQUIREDTAG_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern jb_err init_req_tag_list(struct req_tag_list *tags, const char* pattern);
+extern void free_req_tag_list(struct req_tag_list *tags);
+extern int match_req_tag_list(struct req_tag_list *rtags, struct list *tags);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ndef REQUIREDTAG_H_INCLUDED */
+
+/*
+  Local Variables:
+  tab-width: 3
+  end:
+*/
diff --git a/templates/edit-actions-for-url b/templates/edit-actions-for-url
index a79850d..cd9494f 100644
--- a/templates/edit-actions-for-url
+++ b/templates/edit-actions-for-url
@@ -174,6 +174,18 @@ function show_hide_referrer_opts(tf)
     target.style.display = (tf ? "" : "none");
 }
 
+function show_add_referrer_opts(tf)
+{
+   if (document.getElementById) {
+        target = document.getElementById("hide_referrer_opts");
+    } else if (document.all) {
+        target = document.hide_referrer_opts;
+    } else {
+        return;
+    }
+    target.style.display = (tf ? "" : "none");
+}
+
 function show_user_agent_opts(tf)
 {
     if (document.getElementById) {
@@ -287,6 +299,52 @@ function show_limit_connect_opts(tf)
       <td class="action"><a href="@user-manual@@actions-help-prefix@ADD-HEADER">add-header</a></td>
       <td>Adds HTTP headers.</td>
     </tr>
+    <tr class="bg1" align="left" valign="top">
+      <td class="en1" align="center" valign="middle"><input type="radio"
+        name="add_referrer" id="add_referrer_y" value="Y" @add-referrer-y@
+        onclick="show_add_referrer_opts(true)"></td>
+      <td class="dis1" align="center" valign="middle"><input type="radio"
+        name="add_referrer" id="add_referrer_n" value="N" @add-referrer-n@
+        onclick="show_add_referrer_opts(false)"></td>
+      <td class="noc1" align="center" valign="middle"><input type="radio"
+        name="add_referrer" id="add_referrer_x" value="X" @add-referrer-x@
+        onclick="show_add_referrer_opts(false)"
+        ></td>
+      <td class="action"><a href="@user-manual@@actions-help-prefix@add-REFERRER">add-referrer</a></td>
+      <td>Helps prevent tracking by not sending the URL of the previous web
+        page.&nbsp;</td>
+    </tr>
+    <tr class="bg1" align="left" valign="top" id="add_referrer_opts">
+      <td class="en1">&nbsp;</td>
+      <td class="dis1">&nbsp;</td>
+      <td class="noc1">&nbsp;</td>
+      <td>&nbsp;</td>
+      <td>
+        <input type="radio" name="add_referrer_mode" value="index"
+        onclick="add_referrer_param_disable(true)"
+        @add-referrer-param-index@ id="add_referrer_mode_index"><label
+        for="add_referrer_mode_index">Fake as index.html in same directory.</label><br>
+        <input type="radio" name="add_referrer_mode" value="directory"
+        onclick="add_referrer_param_disable(true)"
+        @add-referrer-param-directory@ id="add_referrer_mode_directory"><label
+        for="add_referrer_mode_directory">Fake as directory including the file.</label><br>
+        <input type="radio" name="add_referrer_mode" value="self"
+        onclick="add_referrer_param_disable(true)"
+        @add-referrer-param-self@ id="add_referrer_mode_self"><label
+        for="add_referrer_mode_self">Fake as the URL of the file.</label><br>
+        <input type="radio" name="add_referrer_mode" value="forge"
+        onclick="add_referrer_param_disable(true)"
+        @add-referrer-param-forge@ id="add_referrer_mode_forge"><label
+        for="add_referrer_mode_forge">Fake as the root directory of the
+        site</label> (fools checks for in-site links.)<br>
+        <input type="radio" name="add_referrer_mode" value="CUSTOM"
+        onclick="add_referrer_param_disable(false)"
+        @add-referrer-param-custom@ id="add_referrer_mode_set"><label
+        for="add_referrer_mode_set">Fake as this web address:</label><br>
+        <input type="text" name="add_referrer_param" 
+        id="add_referrer_param" size="40"
+        value="@add-referrer-param@"></td>
+    </tr>
     <tr class="bg1" align="left" valign="top" id="add-header_opts">
       <td class="en1">&nbsp;</td>
       <td class="dis1">&nbsp;</td>
@@ -936,6 +994,18 @@ function show_limit_connect_opts(tf)
         @hide-referrer-param-conditional-forge@ id="hide_referrer_mode_conditional-forge"><label
         for="hide_referrer_mode_conditional-forge">Forge referrer if host has
         changed, but don't touch in-site referrers.</label><br>
+        <input type="radio" name="hide_referrer_mode" value="index"
+        onclick="hide_referrer_param_disable(true)"
+        @hide-referrer-param-index@ id="hide_referrer_mode_index"><label
+        for="hide_referrer_mode_index">Fake as index.html in same directory.</label><br>
+        <input type="radio" name="hide_referrer_mode" value="directory"
+        onclick="hide_referrer_param_disable(true)"
+        @hide-referrer-param-directory@ id="hide_referrer_mode_directory"><label
+        for="hide_referrer_mode_directory">Fake as directory including the file.</label><br>
+        <input type="radio" name="hide_referrer_mode" value="self"
+        onclick="hide_referrer_param_disable(true)"
+        @hide-referrer-param-self@ id="hide_referrer_mode_self"><label
+        for="hide_referrer_mode_self">Fake as the URL of the file.</label><br>
       </td>
     </tr>
     <tr class="bg1" align="left" valign="top">
diff --git a/templates/forward-class b/templates/forward-class
new file mode 100644
index 0000000..7fa8cce
--- /dev/null
+++ b/templates/forward-class
@@ -0,0 +1,210 @@
+##########################################################
+#
+# Forward class output template for Privoxy.
+#
+#
+# USING HTML TEMPLATES:
+# ---------------------
+#
+# Template files are written win plain HTML, with a few
+# additions:
+#
+# - Lines that start with a '#' character like this one
+#   are ignored
+#
+# - Each item in the below list of exported symbols will
+#   be replaced by dynamically generated text, if they
+#   are enclosed in '@'-characters. E.g. The string @version@
+#   will be replaced by the version number of Privoxy.
+#
+# - One special application of this is to make whole blocks
+#   of the HTML template disappear if the condition <name>
+#   is not given. Simply enclose the block between the two
+#   strings @if-<name>start and if-<name>-end@. The strings
+#   should be placed in HTML comments (<!-- -->), so the
+#   html structure won't be messed when the magic happens.
+#
+# USABLE SYMBOLS IN THIS TEMPLATE:
+# --------------------------------
+#
+#  my-ip-addr:
+#    The IP-address that the client used to reach this proxy
+#  my-hostname:
+#    The hostname associated with my-ip-addr
+#  admin-address:
+#    The email address of the pxoxy's administrator, as configured
+#    in the config file
+#  default-cgi:
+#    The URL for the "main menu" builtin CGI of this proxy
+#  menu:
+#    List of <li> elements linking to the other available CGIs
+#  version:
+#    The version number of the proxy software
+#  code-status:
+#    The development status of the proxy software: "alpha", "beta",
+#    or "stable".
+#  homepage:
+#    The URL of the SourceForge ijbswa project, who maintains this
+#    software.
+#
+# CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS:
+# ------------------------------------------------------------------
+#
+#  unstable:
+#    this is an alpha or beta release of the proxy software
+#  have-adminaddr-info:
+#    An e-mail address for the local Privoxy adminstrator has
+#    been specified and is available through the "admin-address"
+#    symbol
+#  have-proxy-info:
+#    A URL for online documentation about this proxy has been
+#    specified and is available through the "proxy-info-url"
+#    symbol
+#  have-help-info:
+#    If either have-proxy-info is true or have-adminaddr-info is
+#    true, have-help-info is true.  Used to conditionally include
+#    a grey box for any and all help info.
+#  @if-enabled-display-then@ on @else-not-enabled-display@ off @endif-enabled-display@
+#
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+
+<head>
+  <title>@if-enabled-display-then@Enabled@else-not-enabled-display@Disabled@endif-enabled-display@ - Privoxy@@my-hostname@</title>
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <meta http-equiv="Content-Script-Type" content="text/javascript">
+  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <meta name="robots" content="noindex,nofollow">
+  <link rel="stylesheet" type="text/css" href="@default-cgi@send-stylesheet">
+  <script type="text/javascript">
+<!--
+function sync()
+{
+   var bookmarklet = document.links['bookmarklet'];
+   var form = document.getElementById('bookmarklet-form');
+   var inputs = form.getElementsByTagName('input');
+   bookmarklet.href = "javascript:void(window.open('http://config.privoxy.org/forward-class?mini=y";
+   for(i=0; i<inputs.length; i++)
+   {
+      if(inputs[i].type == 'radio')
+      {
+         if(inputs[i].checked)
+         {
+            if(inputs[i].value == 'toggle' || inputs[i].value == 'enabled' || inputs[i].value == 'disabled')
+            {
+               bookmarklet.href += '&' + inputs[i].name + '=' + inputs[i].value;
+            }
+         }
+      }
+   }
+   bookmarklet.href += "','ijbforwardstatus','width=350,height=350,resizable=yes,scrollbars=no,toolbar=no,location=no,directories=no,status=no,menubar=no,copyhistory=no').focus());";
+   return true;
+}
+//-->
+  </script>
+</head>
+
+<body>
+
+  <table cellpadding="20" cellspacing="10" border="0" width="100%">
+    <tr>
+      <td class="title">
+
+#include mod-title
+
+      </td>
+    </tr>
+
+<!-- @if-unstable-start -->
+# This will only appear if CODE_STATUS is "alpha" or "beta". See configure.in
+    <tr>
+      <td class="warning">
+
+#include mod-unstable-warning
+
+      </td>
+    </tr>
+<!-- if-unstable-end@ -->
+
+    <tr>
+      <td class="box">
+        <h2>Forward class state:</h2>
+        <form method="get" action="@default-cgi@forward-class">
+          <table border="1">
+            <tr><th>Forward class</th><th>Enabled</th><th>Disabled</th></tr>
+            @state@
+          </table>
+          <p><input type="submit" value="Change"></p>
+        </form>
+      </td>
+    </tr>
+
+    <tr>
+      <td class="box">
+        <h2>Bookmarklets</h2>
+          <p>Here are some bookmarklets to allow you to easily access a
+            "mini" version of this page.  They are known to work with MS
+            Internet Explorer, Netscape and Mozilla, but should work equally
+            well in other browsers which support JavaScript.  They are designed
+            to run directly from your bookmarks - <b>not</b> by clicking the
+            links below (although that will work for testing).
+          </p>
+          <p>To save them, right-click the link and choose
+            "Add to Favorites" (IE) or "Add Bookmark" (Netscape).  You
+            will get a warning that the bookmark "may not be safe" - just
+            click OK.  Then you can run the Bookmarklet directly from your
+            favourites/bookmarks.  For even faster access, you can put
+            them on the "Links" bar (IE) or the "Personal Toolbar"
+            (Netscape), and run them with a single click.
+          </p>
+
+          <form id="bookmarklet-form" action="">
+            <table border="1">
+              <tr><th>Forward class</th><th>Enabled</th><th>Disabled</th><th>Toggle</th><th>Keep</th></tr>
+              @bookmarklet@
+            </table>
+          </form>
+          <p><a href="javascript:void(window.open('http://config.privoxy.org/forward-class?mini=y','ijbforwardstatus','width=350,height=350,resizable=yes,scrollbars=no,toolbar=no,location=no,directories=no,status=no,menubar=no,copyhistory=no').focus());" id="bookmarklet">Privoxy - Forward class</a></p>
+
+         <p>
+            <b>Credit:</b> The site which gave us the general idea for these
+            bookmarklets is <a href="http://www.bookmarklets.com/">www.bookmarklets.com</a>.
+            They have <a href="http://www.bookmarklets.com/about/">more information</a> about them.
+          </p>
+       </td>
+    </tr>
+
+    <tr>
+      <td class="box">
+        <h2>More Privoxy:</h2>
+        <ul>@menu@<li><a href="@user-manual@">Documentation</a></li></ul>
+      </td>
+    </tr>
+
+    <tr>
+      <td class="info">
+
+#include mod-support-and-service
+
+      </td>
+    </tr>
+
+<!-- @if-have-help-info-start -->
+    <tr>
+      <td class="info">
+
+#include mod-local-help
+
+      </td>
+    </tr>
+<!-- if-have-help-info-end@ -->
+
+     <tr>
+      <td>
+        <p class="small">Valid <a href="http://validator.w3.org/">HTML 4.01 Strict</a></p>
+      </td>
+    </tr>
+  </table>
+
+</body>
+</html>
diff --git a/templates/forward-class-bookmarklet b/templates/forward-class-bookmarklet
new file mode 100644
index 0000000..34778de
--- /dev/null
+++ b/templates/forward-class-bookmarklet
@@ -0,0 +1 @@
+<tr><td>@forward-class-name@</td><td><input type="radio" name="@forward-class-name@" value="enabled" onClick="sync()"></td><td><input type="radio" name="@forward-class-name@" value="disabled" onClick="sync()"></td><td><input type="radio" name="@forward-class-name@" value="toggle" onClick="sync()"></td><td><input type="radio" name="@forward-class-name@" value="keep" onClick="sync()" checked></td></tr>
diff --git a/templates/forward-class-mini b/templates/forward-class-mini
new file mode 100644
index 0000000..6e6720a
--- /dev/null
+++ b/templates/forward-class-mini
@@ -0,0 +1,95 @@
+##########################################################
+#
+# Toggle Output template for Privoxy.
+#
+#
+# USING HTML TEMPLATES:
+# ---------------------
+#
+# Template files are written win plain HTML, with a few
+# additions:
+#
+# - Lines that start with a '#' character like this one
+#   are ignored
+#
+# - Each item in the below list of exported symbols will
+#   be replaced by dynamically generated text, if they
+#   are enclosed in '@'-characters. E.g. The string @version@
+#   will be replaced by the version number of Privoxy.
+#
+# - One special application of this is to make whole blocks
+#   of the HTML template disappear if the condition <name>
+#   is not given. Simply enclose the block between the two
+#   strings @if-<name>start and if-<name>-end@. The strings
+#   should be placed in HTML comments (<!-- -->), so the
+#   html structure won't be messed when the magic happens.
+#
+# USABLE SYMBOLS IN THIS TEMPLATE:
+# --------------------------------
+#
+#  my-ip-addr:
+#    The IP-address that the client used to reach this proxy
+#  my-hostname:
+#    The hostname associated with my-ip-addr
+#  admin-address:
+#    The email address of the pxoxy's administrator, as configured
+#    in the config file
+#  default-cgi:
+#    The URL for the "main menu" builtin CGI of this proxy
+#  menu:
+#    List of <li> elements linking to the other available CGIs
+#  version:
+#    The version number of the proxy software
+#  code-status:
+#    The development status of the proxy software: "alpha", "beta",
+#    or "stable".
+#  homepage:
+#    The URL of the SourceForge ijbswa project, who maintains this
+#    software.
+#
+# CONDITIONAL SYMBOLS FOR THIS TEMPLATE AND THEIR DEPANDANT SYMBOLS:
+# ------------------------------------------------------------------
+#
+#  unstable:
+#    this is an alpha or beta release of the proxy software
+#  have-adminaddr-info:
+#    An e-mail address for the local Privoxy adminstrator has
+#    been specified and is available through the "admin-address"
+#    symbol
+#  have-proxy-info:
+#    A URL for online documentation about this proxy has been
+#    specified and is available through the "proxy-info-url"
+#    symbol
+#  have-help-info:
+#    If either have-proxy-info is true or have-adminaddr-info is
+#    true, have-help-info is true.  Used to conditionally include
+#    a grey box for any and all help info.
+#  @if-enabled-display-then@ on @else-not-enabled-display@ off @endif-enabled-display@
+#
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+
+<head>
+  <title>Forward class - Privoxy@@my-hostname@</title>
+  <meta http-equiv="Content-Style-Type" content="text/css">
+  <meta http-equiv="Content-Script-Type" content="text/javascript">
+  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+  <meta name="robots" content="noindex,nofollow">
+  <link rel="stylesheet" type="text/css" href="@default-cgi@send-stylesheet">
+</head>
+
+<body>
+  <div class="box"><a href="@default-cgi@" target="_blank">Privoxy</a> Forward class state <b>@if-forward-class-changing-then@will be changed to@else-not-forward-class-changing@is@endif-forward-class-changing@</b>
+    <form method="get" action="@default-cgi@forward-class">
+      <input type="hidden" name="mini" value="y">
+      <table border="1">
+        <tr><th>Forward class</th><th>Enabled</th><th>Disabled</th></tr>
+        @state@
+      </table><br>
+      <input type="submit" value="Change">
+      <input type="button" value="Show state" onClick="location.href='http://config.privoxy.org/forward-class?mini=y';">
+      <input type="button" value="Close" onClick="window.close();">
+    </form>
+  </div>
+</body>
+</html>
diff --git a/templates/forward-class-state b/templates/forward-class-state
new file mode 100644
index 0000000..7ac110d
--- /dev/null
+++ b/templates/forward-class-state
@@ -0,0 +1 @@
+<tr><td>@forward-class-name@</td><td><input type="radio" name="@forward-class-name@" value="enabled" @if-forward-class-enabled-start@checked@if-forward-class-enabled-end@></td><td><input type="radio" name="@forward-class-name@" value="disabled" @if-forward-class-disabled-start@checked@if-forward-class-disabled-end@></td></tr>
diff --git a/templates/show-status b/templates/show-status
index e8708c6..b0bfe6d 100644
--- a/templates/show-status
+++ b/templates/show-status
@@ -398,6 +398,26 @@
               <td>Allows to decompress gzip and zlib compressed documents for filtering.
                 Requires external zlib library.</td>
             </tr>
+            <tr>
+              <td><code>FEATURE_ADD_REFERER</code></td>
+              <td>@if-FEATURE_ADD_REFERER-then@ Yes @else-not-FEATURE_ADD_REFERER@ No @endif-FEATURE_ADD_REFERER@</td>
+              <td>Enables add-referer action and extended parameters for hide-referer action.</td>
+            </tr>
+            <tr>
+              <td><code>FEATURE_FORWARD_CLASS</code></td>
+              <td>@if-FEATURE_FORWARD_CLASS-then@ Yes @else-not-FEATURE_FORWARD_CLASS@ No @endif-FEATURE_FORWARD_CLASS@</td>
+              <td>Enables forward class selection.</td>
+            </tr>
+            <tr>
+              <td><code>FEATURE_MANUAL_TAGGER</code></td>
+              <td>@if-FEATURE_MANUAL_TAGGER-then@ Yes @else-not-FEATURE_MANUAL_TAGGER@ No @endif-FEATURE_MANUAL_TAGGER@</td>
+              <td>Enables manual tagger.</td>
+            </tr>
+            <tr>
+              <td><code>FEATURE_REQUIRED_TAG</code></td>
+              <td>@if-FEATURE_REQUIRED_TAG-then@ Yes @else-not-FEATURE_REQUIRED_TAG@ No @endif-FEATURE_REQUIRED_TAG@</td>
+              <td>Enables required tag.</td>
+            </tr>
           </table>
       </td>
     </tr>
diff --git a/w32.rc b/w32.rc
index ab38a44..af0cde1 100644
--- a/w32.rc
+++ b/w32.rc
@@ -91,8 +91,8 @@ IDI_OFF                 ICON    DISCARDABLE     "icons/off.ico"
 #ifndef _MAC
 
 VS_VERSION_INFO VERSIONINFO
- FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_POINT,0
- PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_POINT,0
+ FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_POINT,PATCHLEVEL
+ PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_POINT,PATCHLEVEL
  FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
  FILEFLAGS 0x1L
@@ -147,6 +147,20 @@ BEGIN
             MENUITEM "&Trust list",                   ID_TOOLS_EDITTRUST
 #endif /* def FEATURE_TRUST */
         END
+#ifdef FEATURE_MANUAL_TAGGER
+        MENUITEM                              SEPARATOR
+        POPUP "&Tag.."
+        BEGIN
+            MENUITEM                                  SEPARATOR
+        END
+#endif /* def FEATURE_MANUAL_TAGGER */
+#ifdef FEATURE_FORWARD_CLASS
+        MENUITEM                              SEPARATOR
+        POPUP "&Forward.."
+        BEGIN
+            MENUITEM                                  SEPARATOR
+        END
+#endif /* FEATURE_FORWARD_CLASS */
         MENUITEM                              SEPARATOR
 #ifdef FEATURE_TOGGLE
         MENUITEM "&Enable",                   ID_TOGGLE_ENABLED, CHECKED
@@ -180,6 +194,20 @@ BEGIN
         MENUITEM "&Enable",                     ID_TOGGLE_ENABLED, CHECKED
         MENUITEM                                SEPARATOR
 #endif /* def FEATURE_TOGGLE */
+#ifdef FEATURE_MANUAL_TAGGER
+        POPUP "&Tag.."
+        BEGIN
+            MENUITEM                            SEPARATOR
+        END
+        MENUITEM                                SEPARATOR
+#endif /* def FEATURE_MANUAL_TAGGER */
+#ifdef FEATURE_FORWARD_CLASS
+        POPUP "&Forward.."
+        BEGIN
+            MENUITEM                            SEPARATOR
+        END
+        MENUITEM                                SEPARATOR
+#endif /* def FEATURE_FORWARD_CLASS */
         MENUITEM "Edit Main &Configuration",      ID_TOOLS_EDITCONFIG
         MENUITEM "Edit &Default Actions",         ID_TOOLS_EDITDEFAULTACTIONS
         MENUITEM "Edit &User Actions",            ID_TOOLS_EDITUSERACTIONS
diff --git a/w32log.c b/w32log.c
index c7e3540..8d83230 100644
--- a/w32log.c
+++ b/w32log.c
@@ -53,6 +53,9 @@
 #include "miscutil.h"
 #include "errlog.h"
 #include "loadcfg.h"
+#ifdef FEATURE_MANUAL_TAGGER
+#include "list.h"
+#endif
 
 #ifndef _WIN_CONSOLE /* entire file */
 
@@ -131,6 +134,12 @@ const char * g_user_filterfile = NULL;
 #ifdef FEATURE_TRUST
 const char * g_trustfile = NULL;
 #endif /* def FEATURE_TRUST */
+#ifdef FEATURE_FORWARD_CLASS
+struct forward_class_spec* g_forward_class = NULL;
+#endif /* def FEATURE_FORWARD_CLASS */
+#ifdef FEATURE_MANUAL_TAGGER
+struct manual_tagger_spec* g_manual_tagger = NULL;
+#endif /* def FEATURE_MANUAL_TAGGER */
 
 /* FIXME: end kludge */
 
@@ -217,6 +226,10 @@ static int g_nAnimFrame;
 static BOOL g_bClipPending = FALSE;
 static int g_nRichEditVersion = 0;
 
+#if defined(FEATURE_FORWARD_CLASS) || defined(FEATURE_MANUAL_TAGGER)
+static UINT g_uQueryMessage;
+#endif
+
 /*
  * Private functions
  */
@@ -230,9 +243,16 @@ static void LogClipBuffer(void);
 static void LogCreatePatternMatchingBuffers(void);
 static void LogDestroyPatternMatchingBuffers(void);
 static int LogPutStringNoMatch(const char *pszText, int style);
+#ifdef FEATURE_MANUAL_TAGGER
+static HMENU GetTagSubMenu(HMENU hmenu);
+static void SetTagSubMenu(HMENU hmenu);
+#endif /* def FEATURE_MANUAL_TAGGER */
+#ifdef FEATURE_FORWARD_CLASS
+static HMENU GetForwardSubMenu(HMENU hmenu);
+static void SetForwardSubMenu(HMENU hmenu);
+#endif /* def FEATURE_FORWARD_CLASS */
 static void SetIdleIcon(void);
 
-
 /*********************************************************************
  *
  * Function    :  InitLogWindow
@@ -268,6 +288,10 @@ BOOL InitLogWindow(void)
    /* Create a critical section to protect multi-threaded access to certain things */
    InitializeCriticalSection(&g_criticalsection);
 
+#if defined(FEATURE_FORWARD_CLASS) || defined(FEATURE_MANUAL_TAGGER)
+   g_uQueryMessage = RegisterWindowMessage("PrivoxyEnhancedQueryMessage");
+#endif
+
    return TRUE;
 
 }
@@ -999,6 +1023,25 @@ void OnLogCommand(int nCommand)
          break;
 
       default:
+#ifdef FEATURE_FORWARD_CLASS
+         if(ID_FORWARD_CLASS <= nCommand && nCommand < ID_FORWARD_CLASS + MAX_FORWARD_CLASSES) {
+            global_forward_class_state[nCommand - ID_FORWARD_CLASS] = ! global_forward_class_state[nCommand - ID_FORWARD_CLASS];
+            break;
+         }
+#endif /* def FEATURE_FORWARD_CLASS */
+#ifdef FEATURE_MANUAL_TAGGER
+         if(ID_MANUAL_TAGGER <= nCommand && nCommand < ID_MANUAL_TAGGER + MAX_MANUAL_TAGGERS) {
+            if(list_contains_item(global_manual_tagger, g_manual_tagger[nCommand - ID_MANUAL_TAGGER].tag))
+            {
+               list_remove_item(global_manual_tagger, g_manual_tagger[nCommand - ID_MANUAL_TAGGER].tag);
+            }
+            else
+            {
+               enlist_unique(global_manual_tagger, g_manual_tagger[nCommand - ID_MANUAL_TAGGER].tag, 0);
+            }
+            break;
+         }
+#endif /* def FEATURE_MANUAL_TAGGER */
          /* DO NOTHING */
          break;
    }
@@ -1041,6 +1084,15 @@ void OnLogInitMenu(HMENU hmenu)
 #endif /* def FEATURE_TOGGLE */
    CheckMenuItem(hmenu, ID_TOGGLE_SHOWWINDOW, MF_BYCOMMAND | (g_bShowLogWindow ? MF_CHECKED : MF_UNCHECKED));
 
+#ifdef FEATURE_MANUAL_TAGGER
+   /* Set manual tagger sub menu */
+   SetTagSubMenu(hmenu);
+#endif /* def FEATURE_MANUAL_TAGGER */
+#ifdef FEATURE_FORWARD_CLASS
+   /* Set forward class sub menu */
+   SetForwardSubMenu(hmenu);
+#endif /* def FEATURE_FORWARD_CLASS */
+
 }
 
 
@@ -1087,6 +1139,226 @@ void OnLogTimer(int nTimer)
 }
 
 
+#if defined(FEATURE_FORWARD_CLASS) || defined(FEATURE_MANUAL_TAGGER)
+/*********************************************************************
+ *
+ * Function    :  OnLogQuery
+ *
+ * Description :  Handler for PrivoxyEnhancedQueryMessage messages.
+ *
+ * Parameters  :
+ *          1  :  nID = query target and command
+ *                (ID_FORWARD_CLASS or ID_MANUAL_TAGGER) +
+ *                0 = query max count (defult 10)
+ *                1 = get status
+ *                2 = set status by lParam
+ *          2  :  uParam = lParam for query type 2
+ *
+ * Returns     :  if query type = 0,
+ *                   returns MAX_FORWARD_CLASSES or MAX_MANUAL_TAGGERS
+ *                if query type = 1,
+ *                   returns packed bits flag of global_forward_class_state
+ *                   or global_manual_tagger
+ *                   LSB represents ID 0
+ *                if query type = 2, returns set state
+ *
+ *********************************************************************/
+LRESULT OnLogQuery(int nID, unsigned int uParam)
+{
+   int i;
+   unsigned int uResult = 0;
+
+   switch (nID)
+   {
+      /* forward class */ /* assuming MAX_FORWARD_CLASSES <= 32 */
+      case ID_FORWARD_CLASS:
+         return MAX_FORWARD_CLASSES;
+
+      case ID_FORWARD_CLASS + 1: /* get */
+         for (i = 0; i < MAX_FORWARD_CLASSES; i++)
+         {
+            if (global_forward_class_state[i])
+            {
+               uResult |= (1U << i);
+            }
+         }
+         return uResult;
+
+      case ID_FORWARD_CLASS + 2: /* set */
+         for (i = 0; i < MAX_FORWARD_CLASSES; i++)
+         {
+            global_forward_class_state[i] = (uParam & 1U);
+            if (global_forward_class_state[i])
+            {
+               uResult |= (1U << i);
+            }
+            uParam >>= 1;
+         }
+         return uResult;
+
+      /* manual tagger */ /* assuming MAX_MANUAL_TAGGERS <= 32 */
+      case ID_MANUAL_TAGGER:
+         return MAX_MANUAL_TAGGERS;
+
+      case ID_MANUAL_TAGGER + 1: /* get */
+         for (i = 0; i < MAX_MANUAL_TAGGERS; i++)
+         {
+            if (g_manual_tagger[i].name
+                  && list_contains_item(global_manual_tagger, g_manual_tagger[i].tag))
+            {
+               uResult |= (1U << i);
+            }
+         }
+         return uResult;
+
+      case ID_MANUAL_TAGGER + 2: /* set */
+         list_remove_all(global_manual_tagger);
+         for (i = 0; i < MAX_MANUAL_TAGGERS; i++)
+         {
+            if (g_manual_tagger[i].name && (uParam & 1u))
+            {
+               enlist_unique(global_manual_tagger, g_manual_tagger[i].tag, 0);
+               uResult |= (1U << i);
+            }
+            uParam >>= 1;
+         }
+         return uResult;
+   }
+   return 0; // not reached
+}
+#endif
+
+
+#ifdef FEATURE_MANUAL_TAGGER
+/*********************************************************************
+ *
+ * Function    :  GetTagSubMenu
+ *
+ * Description :  Extract tag sub menu
+ *
+ * Parameters  :
+ *          1  :  hmenu = Handle of menu containing tag sub menu
+ *
+ * Returns     :  Handle of tag sub menu
+ *
+ *********************************************************************/
+HMENU GetTagSubMenu(HMENU hmenu)
+{
+   char szItemName[256];
+   int nMax = GetMenuItemCount(hmenu), i;
+   MENUITEMINFO mii = { sizeof(MENUITEMINFO), MIIM_SUBMENU | MIIM_STRING };
+   mii.dwTypeData = szItemName;
+   mii.cch = sizeof(szItemName);
+
+   for(i = 0; i < nMax; i++) {
+      GetMenuItemInfo(hmenu, i, TRUE, &mii);
+      if(mii.hSubMenu && lstrcmp("&Options", mii.dwTypeData) == 0) {
+         return GetTagSubMenu(mii.hSubMenu);
+      }
+      if(mii.hSubMenu && lstrcmp("&Tag..", mii.dwTypeData) == 0) {
+         return mii.hSubMenu;
+      }
+      mii.cch = sizeof(szItemName);
+   }
+   return NULL;
+}
+
+/*********************************************************************
+ *
+ * Function    :  SetTagSubMenu
+ *
+ * Description :  Add items into tag sub menu
+ *
+ * Parameters  :
+ *          1  :  hmenu = Handle of menu containing tag sub menu
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void SetTagSubMenu(HMENU hmenu)
+{
+   int nMax, i;
+   hmenu = GetTagSubMenu(hmenu);
+
+   if(hmenu == NULL) return;
+
+   nMax = GetMenuItemCount(hmenu);
+   for(i = 0; i < nMax; i++) {
+      RemoveMenu(hmenu, 0, MF_BYPOSITION);
+   }
+
+   for(i = 0; g_manual_tagger[i].name != NULL && i < MAX_MANUAL_TAGGERS; i++) {
+      AppendMenu(hmenu, MF_STRING | (list_contains_item(global_manual_tagger, g_manual_tagger[i].tag) ? MF_CHECKED : MF_UNCHECKED), ID_MANUAL_TAGGER + i, g_manual_tagger[i].name);
+   }
+}
+#endif /* def FEATURE_MANUAL_TAGGER */
+
+
+#ifdef FEATURE_FORWARD_CLASS
+/*********************************************************************
+ *
+ * Function    :  GetForwardSubMenu
+ *
+ * Description :  Extract forward sub menu
+ *
+ * Parameters  :
+ *          1  :  hmenu = Handle of menu containing forward sub menu
+ *
+ * Returns     :  Handle of forward sub menu
+ *
+ *********************************************************************/
+HMENU GetForwardSubMenu(HMENU hmenu)
+{
+   char szItemName[256];
+   int nMax = GetMenuItemCount(hmenu), i;
+   MENUITEMINFO mii = { sizeof(MENUITEMINFO), MIIM_SUBMENU | MIIM_STRING };
+   mii.dwTypeData = szItemName;
+   mii.cch = sizeof(szItemName);
+
+   for(i = 0; i < nMax; i++) {
+      GetMenuItemInfo(hmenu, i, TRUE, &mii);
+      if(mii.hSubMenu && lstrcmp("&Options", mii.dwTypeData) == 0) {
+         return GetForwardSubMenu(mii.hSubMenu);
+      }
+      if(mii.hSubMenu && lstrcmp("&Forward..", mii.dwTypeData) == 0) {
+         return mii.hSubMenu;
+      }
+      mii.cch = sizeof(szItemName);
+   }
+   return NULL;
+}
+
+
+/*********************************************************************
+ *
+ * Function    :  SetForwardSubMenu
+ *
+ * Description :  Add items into forward sub menu
+ *
+ * Parameters  :
+ *          1  :  hmenu = Handle of menu containing forward sub menu
+ *
+ * Returns     :  N/A
+ *
+ *********************************************************************/
+void SetForwardSubMenu(HMENU hmenu)
+{
+   int nMax, i;
+   hmenu = GetForwardSubMenu(hmenu);
+
+   if(hmenu == NULL) return;
+
+   nMax = GetMenuItemCount(hmenu);
+   for(i = 0; i < nMax; i++) {
+      RemoveMenu(hmenu, 0, MF_BYPOSITION);
+   }
+   for(i = 0; g_forward_class[i].name != NULL && i < MAX_FORWARD_CLASSES; i++) {
+      AppendMenu(hmenu, MF_STRING | (global_forward_class_state[i] ? MF_CHECKED : MF_UNCHECKED), ID_FORWARD_CLASS + i, g_forward_class[i].name);
+   }
+}
+#endif /* def FEATURE_FORWARD_CLASS */
+
+
 /*********************************************************************
  *
  * Function    :  SetIdleIcon
@@ -1233,6 +1505,12 @@ LRESULT CALLBACK LogWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPara
          }
          break;
    }
+#if defined(FEATURE_FORWARD_CLASS) || defined(FEATURE_MANUAL_TAGGER)
+   if (uMsg == g_uQueryMessage)
+   {
+      return OnLogQuery(wParam, lParam);
+   }
+#endif
 
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
 
diff --git a/w32log.h b/w32log.h
index 1c80c09..df485f9 100644
--- a/w32log.h
+++ b/w32log.h
@@ -73,6 +73,12 @@ extern const char * g_user_filterfile;
 #ifdef FEATURE_TRUST
 extern const char * g_trustfile;
 #endif /* def FEATURE_TRUST */
+#ifdef FEATURE_FORWARD_CLASS
+extern struct forward_class_spec* g_forward_class;
+#endif /* def FEATURE_FORWARD_CLASS */
+#ifdef FEATURE_MANUAL_TAGGER
+extern struct manual_tagger_spec* g_manual_tagger;
+#endif /* def FEATURE_MANUAL_TAGGER */
 
 /* FIXME: end kludge */
 
diff --git a/w32res.h b/w32res.h
index 90ff6b9..9aeaa52 100644
--- a/w32res.h
+++ b/w32res.h
@@ -83,6 +83,16 @@
 
 #endif /* ndef W32RES_H_INCLUDED */
 
+#ifdef FEATURE_FORWARD_CLASS
+/* ID until ID_FORWARD_CLASS + MAX_FORWARD_CLASSES - 1 are reserved. */
+#define ID_FORWARD_CLASS                  6000
+#endif /* def FEATURE_FORWARD_CLASS */
+
+#ifdef FEATURE_MANUAL_TAGGER
+/* ID until ID_MANUAL_TAGGER + MAX_MANUAL_TAGGERS - 1 are reserved. */
+#define ID_MANUAL_TAGGER                  7000
+#endif /* def FEATURE_MANUAL_TAGGER */
+
 /*
   Local Variables:
   tab-width: 3
