Sync.
[privoxy.git] / cgiedit.c
index 4caaeaf..55499c8 100644 (file)
--- a/cgiedit.c
+++ b/cgiedit.c
@@ -1,4 +1,4 @@
-const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.17 2002/03/16 14:26:42 jongfoster Exp $";
+const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.32 2002/04/19 16:55:31 jongfoster Exp $";
 /*********************************************************************
  *
  * File        :  $Source: /cvsroot/ijbswa/current/cgiedit.c,v $
@@ -16,7 +16,7 @@ const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.17 2002/03/16 14:26:42 jongfoster
  *                Stick to the short names in this file for consistency.
  *
  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
- *                IJBSWA team.  http://ijbswa.sourceforge.net
+ *                Privoxy team. http://www.privoxy.org/
  *
  *                Based on the Internet Junkbuster originally written
  *                by and Copyright (C) 1997 Anonymous Coders and
@@ -42,6 +42,57 @@ const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.17 2002/03/16 14:26:42 jongfoster
  *
  * Revisions   :
  *    $Log: cgiedit.c,v $
+ *    Revision 1.32  2002/04/19 16:55:31  jongfoster
+ *    Fixing newline problems.  If we do our own text file newline
+ *    mangling, we don't want the library to do any, so we need to
+ *    open the files in *binary* mode.
+ *
+ *    Revision 1.31  2002/04/18 19:21:08  jongfoster
+ *    Added code to detect "conventional" action files, that start
+ *    with a set of actions for all URLs (the pattern "/").
+ *    These are special-cased in the "edit-actions-list" CGI, so
+ *    that a special UI can be written for them.
+ *
+ *    Revision 1.30  2002/04/10 13:38:35  oes
+ *    load_template signature changed
+ *
+ *    Revision 1.29  2002/04/08 16:59:08  oes
+ *    Fixed comment
+ *
+ *    Revision 1.28  2002/03/27 12:30:29  oes
+ *    Deleted unsused variable
+ *
+ *    Revision 1.27  2002/03/26 23:06:04  jongfoster
+ *    Removing duplicate @ifs on the toggle page
+ *
+ *    Revision 1.26  2002/03/26 22:59:17  jongfoster
+ *    Fixing /toggle to display status consistently.
+ *
+ *    Revision 1.25  2002/03/26 22:29:54  swa
+ *    we have a new homepage!
+ *
+ *    Revision 1.24  2002/03/24 15:23:33  jongfoster
+ *    Name changes
+ *
+ *    Revision 1.23  2002/03/24 13:32:41  swa
+ *    name change related issues
+ *
+ *    Revision 1.22  2002/03/24 13:25:43  swa
+ *    name change related issues
+ *
+ *    Revision 1.21  2002/03/22 18:02:48  jongfoster
+ *    Fixing remote toggle
+ *
+ *    Revision 1.20  2002/03/16 20:28:34  oes
+ *    Added descriptions to the filters so users will know what they select in the cgi editor
+ *
+ *    Revision 1.19  2002/03/16 18:38:14  jongfoster
+ *    Stopping stupid or malicious users from breaking the actions
+ *    file using the web-based editor.
+ *
+ *    Revision 1.18  2002/03/16 14:57:44  jongfoster
+ *    Full support for enabling/disabling modular filters.
+ *
  *    Revision 1.17  2002/03/16 14:26:42  jongfoster
  *    First version of modular filters support - READ ONLY!
  *    Fixing a double-free bug in the out-of-memory handling in map_radio().
@@ -174,7 +225,6 @@ const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.17 2002/03/16 14:26:42 jongfoster
 #include <ctype.h>
 #include <string.h>
 #include <assert.h>
-#include <limits.h>
 #include <sys/stat.h>
 
 #ifdef _WIN32
@@ -250,7 +300,7 @@ struct file_line
 struct editable_file
 {
    struct file_line * lines;
-   const char * filename;     /* Full pathname - e.g. "/etc/junkbuster/wibble.action" */
+   const char * filename;     /* Full pathname - e.g. "/etc/privoxy/wibble.action" */
    const char * identifier;   /* Filename stub - e.g. "wibble".  Use for CGI param. */
                               /* Pre-encoded with url_encode() for ease of use. */
    const char * version_str;  /* Last modification time, as a string.  For CGI param */
@@ -318,15 +368,13 @@ static jb_err get_file_name_param(struct client_state *csp,
                                   const char *suffix,
                                   char **pfilename,
                                   const char **pparam);
-static jb_err get_number_param(struct client_state *csp,
-                               const struct map *parameters,
-                               char *name,
-                               unsigned *pvalue);
+
 static jb_err get_url_spec_param(struct client_state *csp,
                                  const struct map *parameters,
                                  const char *name,
                                  char **pvalue);
 
+
 /* Internal actionsfile <==> HTML conversion functions */
 static jb_err map_radio(struct map * exports,
                         const char * optionname,
@@ -398,7 +446,7 @@ static jb_err map_copy_parameter_html(struct map *out,
 #if 0 /* unused function */
 /*********************************************************************
  *
- * Function    :  map_copy_parameter_html
+ * Function    :  map_copy_parameter_url
  *
  * Description :  Copy a CGI parameter from one map to another, URL
  *                encoding it.
@@ -722,11 +770,7 @@ jb_err edit_write_file(struct editable_file * file)
    assert(file);
    assert(file->filename);
 
-#if defined(AMIGA) || defined(__OS2__)
-   if (NULL == (fp = fopen(file->filename, "w")))
-#else
-   if (NULL == (fp = fopen(file->filename, "wt")))
-#endif /* def AMIGA */
+   if (NULL == (fp = fopen(file->filename, "wb")))
    {
       return JB_ERR_FILE;
    }
@@ -895,7 +939,7 @@ void edit_free_file(struct editable_file * file)
 
 /*********************************************************************
  *
- * Function    :  edit_free_file
+ * Function    :  edit_free_file_lines
  *
  * Description :  Free an entire linked list of file lines.
  *
@@ -1553,11 +1597,7 @@ jb_err edit_read_file(struct client_state *csp,
       }
    }
 
-#if defined(AMIGA) || defined(__OS2__)
-   if (NULL == (fp = fopen(filename,"r")))
-#else
-   if (NULL == (fp = fopen(filename,"rt")))
-#endif /* def AMIGA */
+   if (NULL == (fp = fopen(filename,"rb")))
    {
       free(filename);
       return JB_ERR_FILE;
@@ -1756,9 +1796,7 @@ static jb_err get_file_name_param(struct client_state *csp,
 {
    const char *param;
    const char *s;
-#if 0 /* Patch to make 3.0.0 work properly. */
    char *name;
-#endif /* 0 - Patch to make 3.0.0 work properly. */
    char *fullpath;
    char ch;
    int len;
@@ -1802,13 +1840,6 @@ static jb_err get_file_name_param(struct client_state *csp,
       }
    }
 
-   /*
-    * FIXME Following is a hack to make 3.0.0 work properly.
-    * Change "#if 0" --> "#if 1" below when we have modular action
-    * files.
-    *    -- Jon
-    */
-#if 0 /* Patch to make 3.0.0 work properly. */
    /* Append extension */
    name = malloc(len + strlen(suffix) + 1);
    if (name == NULL)
@@ -1821,16 +1852,7 @@ static jb_err get_file_name_param(struct client_state *csp,
    /* Prepend path */
    fullpath = make_path(csp->config->confdir, name);
    free(name);
-#else /* 1 - Patch to make 3.0.0 work properly. */
-   if ((csp->actions_list == NULL)
-    || (csp->actions_list->filename == NULL))
-   {
-      return JB_ERR_CGI_PARAMS;
-   }
 
-   fullpath = ( (csp->actions_list && csp->actions_list->filename)
-             ? strdup(csp->actions_list->filename) : NULL);
-#endif /* 1 - Patch to make 3.0.0 work properly. */
    if (fullpath == NULL)
    {
       return JB_ERR_MEMORY;
@@ -1843,83 +1865,6 @@ static jb_err get_file_name_param(struct client_state *csp,
 }
 
 
-/*********************************************************************
- *
- * Function    :  get_number_param
- *
- * Description :  Get a non-negative integer from the parameters
- *                passed to a CGI function.
- *
- * Parameters  :
- *          1  :  csp = Current client state (buffers, headers, etc...)
- *          2  :  parameters = map of cgi parameters
- *          3  :  name = Name of CGI parameter to read
- *          4  :  pvalue = destination for value.
- *                         Set to -1 on error.
- *
- * Returns     :  JB_ERR_OK         on success
- *                JB_ERR_MEMORY     on out-of-memory
- *                JB_ERR_CGI_PARAMS if the parameter was not specified
- *                                  or is not valid.
- *
- *********************************************************************/
-static jb_err get_number_param(struct client_state *csp,
-                               const struct map *parameters,
-                               char *name,
-                               unsigned *pvalue)
-{
-   const char *param;
-   char ch;
-   unsigned value;
-
-   assert(csp);
-   assert(parameters);
-   assert(name);
-   assert(pvalue);
-
-   *pvalue = 0; 
-
-   param = lookup(parameters, name);
-   if (!*param)
-   {
-      return JB_ERR_CGI_PARAMS;
-   }
-
-   /* We don't use atoi because I want to check this carefully... */
-
-   value = 0;
-   while ((ch = *param++) != '\0')
-   {
-      if ((ch < '0') || (ch > '9'))
-      {
-         return JB_ERR_CGI_PARAMS;
-      }
-
-      ch -= '0';
-
-      /* Note:
-       *
-       * <limits.h> defines UINT_MAX
-       *
-       * (UINT_MAX - ch) / 10 is the largest number that
-       *     can be safely multiplied by 10 then have ch added.
-       */
-      if (value > ((UINT_MAX - (unsigned)ch) / 10U))
-      {
-         return JB_ERR_CGI_PARAMS;
-      }
-
-      value = value * 10 + ch;
-   }
-
-   /* Success */
-   *pvalue = value;
-
-   return JB_ERR_OK;
-
-}
-
-
 /*********************************************************************
  *
  * Function    :  get_url_spec_param
@@ -2262,10 +2207,10 @@ jb_err cgi_error_file(struct client_state *csp,
 
 /*********************************************************************
  *
- * Function    :  cgi_error_bad_param
+ * Function    :  cgi_error_disabled
  *
- * Description :  CGI function that is called if the parameters
- *                (query string) for a CGI were wrong.
+ * Description :  CGI function that is called if the actions editor
+ *                is called although it's disabled in config
  *
  * Parameters  :
  *          1  :  csp = Current client state (buffers, headers, etc...)
@@ -2323,13 +2268,13 @@ jb_err cgi_edit_actions(struct client_state *csp,
    }
 
    /* FIXME: Incomplete */
-   rsp->status = strdup("302 Local Redirect from Junkbuster");
+   rsp->status = strdup("302 Local Redirect from Privoxy");
    if (rsp->status == NULL)
    {
       return JB_ERR_MEMORY;
    }
    if (enlist_unique_header(rsp->headers, "Location",
-      CGI_PREFIX "edit-actions-list?f=ijb"))
+      CGI_PREFIX "edit-actions-list?f=default"))
    {
       free(rsp->status);
       rsp->status = NULL;
@@ -2370,7 +2315,7 @@ jb_err cgi_edit_actions_list(struct client_state *csp,
    char * url_template;
    char * sections;
    char * urls;
-   char buf[50];
+   char buf[150];
    char * s;
    struct map * exports;
    struct map * section_exports;
@@ -2379,7 +2324,10 @@ jb_err cgi_edit_actions_list(struct client_state *csp,
    struct file_line * cur_line;
    unsigned line_number = 0;
    unsigned prev_section_line_number = ((unsigned) (-1));
-   int url_1_2;
+   int i, url_1_2;
+   struct file_list * fl;
+   struct url_actions * b;
+   char * buttons = NULL;
    jb_err err;
 
    if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
@@ -2387,6 +2335,13 @@ jb_err cgi_edit_actions_list(struct client_state *csp,
       return cgi_error_disabled(csp, rsp);
    }
 
+   if (NULL == (exports = default_exports(csp, NULL)))
+   {
+      edit_free_file(file);
+      return JB_ERR_MEMORY;
+   }
+
+   /* Load actions file */
    err = edit_read_actions_file(csp, rsp, parameters, 0, &file);
    if (err)
    {
@@ -2394,15 +2349,99 @@ jb_err cgi_edit_actions_list(struct client_state *csp,
       return (err == JB_ERR_FILE ? JB_ERR_OK : err);
    }
 
-   if (NULL == (exports = default_exports(csp, NULL)))
+   /* Find start of actions in file */
+   cur_line = file->lines;
+   line_number = 1;
+   while ((cur_line != NULL) && (cur_line->type != FILE_LINE_ACTION))
    {
-      edit_free_file(file);
-      return JB_ERR_MEMORY;
+      cur_line = cur_line->next;
+      line_number++;
+   }
+
+   /*
+    * Conventional actions files should have a match all block
+    * at the start:
+    * cur_line             = {...global actions...}
+    * cur_line->next       = /
+    * cur_line->next->next = {...actions...} or EOF
+    */
+   if ( (cur_line != NULL)
+     && (cur_line->type == FILE_LINE_ACTION)
+     && (cur_line->next != NULL)
+     && (cur_line->next->type == FILE_LINE_URL)
+     && (0 == strcmp(cur_line->next->unprocessed, "/"))
+     && ( (cur_line->next->next == NULL)
+       || (cur_line->next->next->type != FILE_LINE_URL)
+      ) )
+   {
+      /*
+       * Generate string with buttons to set actions for "/" to
+       * any predefined set of actions (named standard.*, propably
+       * residing in standard.action).
+       * FIXME: Shouldn't include hardwired HTML here, use line template instead!
+       */
+
+      buttons = strdup(" ");
+      for (i = 0; i < MAX_ACTION_FILES; i++)
+      {
+         if (((fl = csp->actions_list[i]) != NULL) && ((b = fl->f) != NULL))
+         {
+            for (b = b->next; NULL != b; b = b->next)
+            {
+               if (!strncmp(b->url->spec, "standard.", 9) && *(b->url->spec + 9) != '\0')
+               {
+                  snprintf(buf, 150, "<p><a name=\"l@s@\" href=\"eas?f=@f@&amp;v=@v@&amp;s=@all-urls-s@&amp;p=%s\">Set"
+                                     " to %s</a></p>", b->url->spec + 9, b->url->spec + 9);
+                  if (!err) err = string_append(&buttons, buf);
+               }
+            }
+         }
+      }
+      if (!err) err = map(exports, "all-urls-buttons", 1, buttons, 0);
+
+      /*
+       * Conventional actions file, supply extra editing help.
+       * (e.g. don't allow them to make it an unconventional one).
+       */
+      err = map_conditional(exports, "all-urls-present", 1);
+
+      snprintf(buf, 150, "%d", line_number);
+      if (!err) err = map(exports, "all-urls-s", 1, buf, 1);
+      snprintf(buf, 150, "%d", line_number + 2);
+      if (!err) err = map(exports, "all-urls-s-next", 1, buf, 1);
+      if (!err) err = map(exports, "all-urls-actions", 1,
+                          actions_to_html(cur_line->data.action), 0);
+
+       /* Skip the 2 lines */
+      cur_line = cur_line->next->next;
+      line_number += 2;
+
+      /*
+       * Note that prev_section_line_number is NOT set here.
+       * This is deliberate and not a bug.  It stops a "Move up"
+       * option appearing on the next section.  Clicking "Move
+       * up" would make the actions file unconventional, which
+       * we don't want, so we hide this option.
+       */
+   }
+   else
+   {
+      /*
+       * Non-standard actions file - does not begin with
+       * the "All URLs" section.
+       */
+      err = map_conditional(exports, "all-urls-present", 0);
    }
 
+   /* Set up global exports */
+
    err = map(exports, "f", 1, file->identifier, 1);
    if (!err) err = map(exports, "v", 1, file->version_str, 1);
 
+   /* Discourage private additions to default.action */
+
+   if (!err) err = map_conditional(exports, "default-action",
+                                   (strcmp("default", lookup(parameters, "f")) == 0));
    if (err)
    {
       edit_free_file(file);
@@ -2412,7 +2451,9 @@ jb_err cgi_edit_actions_list(struct client_state *csp,
 
    /* Should do all global exports above this point */
 
-   err = template_load(csp, &section_template, "edit-actions-list-section");
+   /* Load templates */
+
+   err = template_load(csp, &section_template, "edit-actions-list-section", 0);
    if (err)
    {
       edit_free_file(file);
@@ -2424,7 +2465,7 @@ jb_err cgi_edit_actions_list(struct client_state *csp,
       return err;
    }
 
-   err = template_load(csp, &url_template, "edit-actions-list-url");
+   err = template_load(csp, &url_template, "edit-actions-list-url", 0);
    if (err)
    {
       free(section_template);
@@ -2456,15 +2497,6 @@ jb_err cgi_edit_actions_list(struct client_state *csp,
       return err;
    }
 
-   /* Find start of actions in file */
-   cur_line = file->lines;
-   line_number = 1;
-   while ((cur_line != NULL) && (cur_line->type != FILE_LINE_ACTION))
-   {
-      cur_line = cur_line->next;
-      line_number++;
-   }
-
    if (NULL == (sections = strdup("")))
    {
       free(section_template);
@@ -2486,7 +2518,7 @@ jb_err cgi_edit_actions_list(struct client_state *csp,
          return JB_ERR_MEMORY;
       }
 
-      snprintf(buf, 50, "%d", line_number);
+      snprintf(buf, 150, "%d", line_number);
       err = map(section_exports, "s", 1, buf, 1);
       if (!err) err = map(section_exports, "actions", 1,
                           actions_to_html(cur_line->data.action), 0);
@@ -2506,7 +2538,7 @@ jb_err cgi_edit_actions_list(struct client_state *csp,
       if (prev_section_line_number != ((unsigned)(-1)))
       {
          /* Not last section */
-         snprintf(buf, 50, "%d", prev_section_line_number);
+         snprintf(buf, 150, "%d", prev_section_line_number);
          if (!err) err = map(section_exports, "s-prev", 1, buf, 1);
          if (!err) err = map_block_keep(section_exports, "s-prev-exists");
       }
@@ -2560,10 +2592,10 @@ jb_err cgi_edit_actions_list(struct client_state *csp,
             return JB_ERR_MEMORY;
          }
 
-         snprintf(buf, 50, "%d", line_number);
+         snprintf(buf, 150, "%d", line_number);
          err = map(url_exports, "p", 1, buf, 1);
 
-         snprintf(buf, 50, "%d", url_1_2);
+         snprintf(buf, 150, "%d", url_1_2);
          if (!err) err = map(url_exports, "url-1-2", 1, buf, 1);
 
          if (!err) err = map(url_exports, "url-html", 1,
@@ -2630,7 +2662,7 @@ jb_err cgi_edit_actions_list(struct client_state *csp,
         && (cur_line->type == FILE_LINE_ACTION))
       {
          /* Not last section */
-         snprintf(buf, 50, "%d", line_number);
+         snprintf(buf, 150, "%d", line_number);
          if (!err) err = map(section_exports, "s-next", 1, buf, 1);
          if (!err) err = map_block_keep(section_exports, "s-next-exists");
       }
@@ -2698,7 +2730,7 @@ jb_err cgi_edit_actions_list(struct client_state *csp,
 
 /*********************************************************************
  *
- * Function    :  cgi_edit_actions
+ * Function    :  cgi_edit_actions_for_url
  *
  * Description :  CGI function that edits the Actions list.
  *
@@ -2798,7 +2830,7 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp,
       int index = 0;
       char * filter_template;
 
-      err = template_load(csp, &filter_template, "edit-actions-for-url-filter");
+      err = template_load(csp, &filter_template, "edit-actions-for-url-filter", 0);
       if (err)
       {
          edit_free_file(file);
@@ -2822,7 +2854,7 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp,
 
          filter_name = cur_line->data.action->multi_add[ACTION_MULTI_FILTER]->first;
          while ((filter_name != NULL)
-             && (0 != strcmp(filter_group->filtername, filter_name->str)))
+             && (0 != strcmp(filter_group->name, filter_name->str)))
          {
               filter_name = filter_name->next;
          }
@@ -2835,7 +2867,7 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp,
          {
             filter_name = cur_line->data.action->multi_remove[ACTION_MULTI_FILTER]->first;
             while ((filter_name != NULL)
-                && (0 != strcmp(filter_group->filtername, filter_name->str)))
+                && (0 != strcmp(filter_group->name, filter_name->str)))
             {
                  filter_name = filter_name->next;
             }
@@ -2858,7 +2890,8 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp,
          else
          {
             if (!err) err = map(line_exports, "index", 1, number, 1);
-            if (!err) err = map(line_exports, "name",  1, filter_group->filtername, 1);
+            if (!err) err = map(line_exports, "name",  1, filter_group->name, 1);
+            if (!err) err = map(line_exports, "description",  1, filter_group->description, 1);
             if (!err) err = map_radio(line_exports, "this-filter", "ynx", current_mode);
 
             this_line = NULL;
@@ -2931,7 +2964,10 @@ jb_err cgi_edit_actions_submit(struct client_state *csp,
    char * target;
    jb_err err;
    int index;
+   const char * action_set_name;
    char ch;
+   struct file_list * fl;
+   struct url_actions * b;
 
    if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
    {
@@ -2968,7 +3004,33 @@ jb_err cgi_edit_actions_submit(struct client_state *csp,
       return JB_ERR_CGI_PARAMS;
    }
 
-   err = actions_from_radio(parameters, cur_line->data.action);
+   get_string_param(parameters, "p", &action_set_name);
+   if (action_set_name != NULL)
+   {
+      for (index = 0; index < MAX_ACTION_FILES; index++)
+      {
+         if (((fl = csp->actions_list[index]) != NULL) && ((b = fl->f) != NULL))
+         {
+            for (b = b->next; NULL != b; b = b->next)
+            {
+               if (!strncmp(b->url->spec, "standard.", 9) && !strcmp(b->url->spec + 9, action_set_name))
+               {
+                  copy_action(cur_line->data.action, b->action); 
+                  goto found;
+               }
+            }
+         }
+      }
+      edit_free_file(file);
+      return JB_ERR_CGI_PARAMS;
+
+      found: ;
+   }
+   else
+   {
+      err = actions_from_radio(parameters, cur_line->data.action);
+   }
+
    if(err)
    {
       /* Out of memory */
@@ -2976,7 +3038,7 @@ jb_err cgi_edit_actions_submit(struct client_state *csp,
       return err;
    }
 
-   ch = ijb_toupper((int)lookup(parameters, "filter_all")[0]);
+   ch = get_char_param(parameters, "filter_all");
    if (ch == 'N')
    {
       list_remove_all(cur_line->data.action->multi_add[ACTION_MULTI_FILTER]);
@@ -2988,7 +3050,7 @@ jb_err cgi_edit_actions_submit(struct client_state *csp,
       cur_line->data.action->multi_remove_all[ACTION_MULTI_FILTER] = 0;
    }
 
-   for (index = 0; ; index++)
+   for (index = 0; !err; index++)
    {
       char key_value[30];
       char key_name[30];
@@ -3001,16 +3063,16 @@ jb_err cgi_edit_actions_submit(struct client_state *csp,
       snprintf(key_name, sizeof(key_name), "filter_n%x", index);
       key_name[sizeof(key_name) - 1] = '\0';
 
-      name = lookup(parameters, key_name);
+      err = get_string_param(parameters, key_name, &name);
+      if (err) break;
 
-      if (*name == '\0')
+      if (name == NULL)
       {
          /* End of list */
          break;
       }
 
-
-      value = ijb_toupper((int)lookup(parameters, key_value)[0]);
+      value = get_char_param(parameters, key_value);
       if (value == 'Y')
       {
          list_remove_item(cur_line->data.action->multi_add[ACTION_MULTI_FILTER], name);
@@ -3093,7 +3155,7 @@ jb_err cgi_edit_actions_submit(struct client_state *csp,
       return JB_ERR_MEMORY;
    }
 
-   rsp->status = strdup("302 Local Redirect from Junkbuster");
+   rsp->status = strdup("302 Local Redirect from Privoxy");
    if (rsp->status == NULL)
    {
       free(target);
@@ -3215,7 +3277,7 @@ jb_err cgi_edit_actions_url(struct client_state *csp,
       return JB_ERR_MEMORY;
    }
 
-   rsp->status = strdup("302 Local Redirect from Junkbuster");
+   rsp->status = strdup("302 Local Redirect from Privoxy");
    if (rsp->status == NULL)
    {
       free(target);
@@ -3354,7 +3416,7 @@ jb_err cgi_edit_actions_add_url(struct client_state *csp,
       return JB_ERR_MEMORY;
    }
 
-   rsp->status = strdup("302 Local Redirect from Junkbuster");
+   rsp->status = strdup("302 Local Redirect from Privoxy");
    if (rsp->status == NULL)
    {
       free(target);
@@ -3470,7 +3532,7 @@ jb_err cgi_edit_actions_remove_url(struct client_state *csp,
       return JB_ERR_MEMORY;
    }
 
-   rsp->status = strdup("302 Local Redirect from Junkbuster");
+   rsp->status = strdup("302 Local Redirect from Privoxy");
    if (rsp->status == NULL)
    {
       free(target);
@@ -3602,7 +3664,7 @@ jb_err cgi_edit_actions_section_remove(struct client_state *csp,
       return JB_ERR_MEMORY;
    }
 
-   rsp->status = strdup("302 Local Redirect from Junkbuster");
+   rsp->status = strdup("302 Local Redirect from Privoxy");
    if (rsp->status == NULL)
    {
       free(target);
@@ -3776,7 +3838,7 @@ jb_err cgi_edit_actions_section_add(struct client_state *csp,
       return JB_ERR_MEMORY;
    }
 
-   rsp->status = strdup("302 Local Redirect from Junkbuster");
+   rsp->status = strdup("302 Local Redirect from Privoxy");
    if (rsp->status == NULL)
    {
       free(target);
@@ -3975,7 +4037,7 @@ jb_err cgi_edit_actions_section_swap(struct client_state *csp,
       return JB_ERR_MEMORY;
    }
 
-   rsp->status = strdup("302 Local Redirect from Junkbuster");
+   rsp->status = strdup("302 Local Redirect from Privoxy");
    if (rsp->status == NULL)
    {
       free(target);
@@ -4016,7 +4078,6 @@ jb_err cgi_toggle(struct client_state *csp,
    struct map *exports;
    char mode;
    const char *template_name;
-   jb_err err;
 
    assert(csp);
    assert(rsp);
@@ -4027,37 +4088,30 @@ jb_err cgi_toggle(struct client_state *csp,
       return cgi_error_disabled(csp, rsp);
    }
 
-   if (NULL == (exports = default_exports(csp, "toggle")))
-   {
-      return JB_ERR_MEMORY;
-   }
-
-   mode = *(lookup(parameters, "set"));
+   mode = get_char_param(parameters, "set");
 
-   if (mode == 'e')
+   if (mode == 'E')
    {
       /* Enable */
       g_bToggleIJB = 1;
    }
-   else if (mode == 'd')
+   else if (mode == 'D')
    {
       /* Disable */
       g_bToggleIJB = 0;
    }
-   else if (mode == 't')
+   else if (mode == 'T')
    {
       /* Toggle */
       g_bToggleIJB = !g_bToggleIJB;
    }
 
-   err = map_conditional(exports, "enabled", g_bToggleIJB);
-   if (err)
+   if (NULL == (exports = default_exports(csp, "toggle")))
    {
-      free_map(exports);
-      return err;
+      return JB_ERR_MEMORY;
    }
 
-   template_name = (*(lookup(parameters, "mini"))
+   template_name = (get_char_param(parameters, "mini")
                  ? "toggle-mini"
                  : "toggle");
 
@@ -4257,6 +4311,7 @@ static jb_err actions_from_radio(const struct map * parameters,
    char * param_dup;
    char ch;
    const char * js_name;
+   jb_err err = JB_ERR_OK;
 
    assert(parameters);
    assert(action);
@@ -4279,8 +4334,7 @@ static jb_err actions_from_radio(const struct map * parameters,
 
 #define DEFINE_ACTION_BOOL(name, bit)                 \
    JAVASCRIPTIFY(js_name, name);                      \
-   param = lookup(parameters, js_name);               \
-   ch = ijb_toupper(param[0]);                        \
+   ch = get_char_param(parameters, js_name);          \
    if (ch == 'Y')                                     \
    {                                                  \
       action->add  |= bit;                            \
@@ -4299,18 +4353,18 @@ static jb_err actions_from_radio(const struct map * parameters,
 
 #define DEFINE_ACTION_STRING(name, bit, index)                 \
    JAVASCRIPTIFY(js_name, name);                               \
-   param = lookup(parameters, js_name);                        \
-   ch = ijb_toupper(param[0]);                                 \
+   ch = get_char_param(parameters, js_name);                   \
    if (ch == 'Y')                                              \
    {                                                           \
+      param = NULL;                                            \
       JAVASCRIPTIFY(js_name, name "-mode");                    \
-      param = lookup(parameters, js_name);                     \
-      if ((*param == '\0') || (0 == strcmp(param, "CUSTOM")))  \
-      {                                                        \
-         JAVASCRIPTIFY(js_name, name "-param");                \
-         param = lookup(parameters, js_name);                  \
+      if (!err) err = get_string_param(parameters, js_name, &param);    \
+      if ((param == NULL) || (0 == strcmp(param, "CUSTOM")))            \
+      {                                                                 \
+         JAVASCRIPTIFY(js_name, name "-param");                         \
+         if (!err) err = get_string_param(parameters, js_name, &param); \
       }                                                        \
-      if (*param != '\0')                                      \
+      if (param != NULL)                                       \
       {                                                        \
          if (NULL == (param_dup = strdup(param)))              \
          {                                                     \
@@ -4343,8 +4397,7 @@ static jb_err actions_from_radio(const struct map * parameters,
 
 #define DEFINE_ACTION_MULTI(name, index)                       \
    JAVASCRIPTIFY(js_name, name);                               \
-   param = lookup(parameters, js_name);                        \
-   ch = ijb_toupper((int)param[0]);                            \
+   ch = get_char_param(parameters, js_name);                   \
    if (ch == 'Y')                                              \
    {                                                           \
       /* FIXME */                                              \
@@ -4374,7 +4427,7 @@ static jb_err actions_from_radio(const struct map * parameters,
 
    first_time = 0;
 
-   return JB_ERR_OK;
+   return err;
 }