#! /bin/sh /usr/share/dpatch/dpatch-run ## 12_multiple-filters.dpatch ## by David Schmidt ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: Multiple filter file support @DPATCH@ diff -urNad privoxy~/actions.c privoxy/actions.c --- privoxy~/actions.c 2006-02-11 23:44:25.000000000 +0100 +++ privoxy/actions.c 2006-02-11 23:44:37.000000000 +0100 @@ -871,7 +871,7 @@ } -static struct file_list *current_actions_file[MAX_ACTION_FILES] = { +static struct file_list *current_actions_file[MAX_AF_FILES] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; @@ -894,7 +894,7 @@ { int i; - for (i = 0; i < MAX_ACTION_FILES; i++) + for (i = 0; i < MAX_AF_FILES; i++) { if (current_actions_file[i]) { @@ -979,7 +979,7 @@ int i; int result; - for (i = 0; i < MAX_ACTION_FILES; i++) + for (i = 0; i < MAX_AF_FILES; i++) { if (csp->config->actions_file[i]) { diff -urNad privoxy~/cgiedit.c privoxy/cgiedit.c --- privoxy~/cgiedit.c 2006-02-11 23:44:25.000000000 +0100 +++ privoxy/cgiedit.c 2006-02-11 23:44:37.000000000 +0100 @@ -2560,7 +2560,7 @@ } buttons = strdup(""); - for (i = 0; i < MAX_ACTION_FILES; i++) + for (i = 0; i < MAX_AF_FILES; i++) { if (((fl = csp->actions_list[i]) != NULL) && ((b = fl->f) != NULL)) { @@ -2958,8 +2958,8 @@ struct file_line * cur_line; unsigned line_number; jb_err err; - struct file_list *filter_file; struct re_filterfile_spec *filter_group; + int i, have_filters = 0; if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS)) { @@ -3008,10 +3008,15 @@ if (!err) err = actions_to_radio(exports, cur_line->data.action); - filter_file = csp->rlist; - filter_group = ((filter_file != NULL) ? filter_file->f : NULL); - - if (!err) err = map_conditional(exports, "any-filters-defined", (filter_group != NULL)); + for (i = 0; i < MAX_AF_FILES; i++) + { + if ((csp->rlist[i] != NULL) && (csp->rlist[i]->f != NULL)) + { + if (!err) err = map_conditional(exports, "any-filters-defined", 1); + have_filters = 1; + break; + } + } if (err) { @@ -3020,10 +3025,8 @@ return err; } - if (filter_group == NULL) - { + if (0 == have_filters) err = map(exports, "filter-params", 1, "", 1); - } else { /* We have some entries in the filter list */ @@ -3047,69 +3050,76 @@ result = strdup(""); - for (;(!err) && (filter_group != NULL); filter_group = filter_group->next) + for (i = 0; i < MAX_AF_FILES; i++) { - char current_mode = 'x'; - struct list_entry *filter_name; - char * this_line; - struct map *line_exports; - char number[20]; - - filter_name = cur_line->data.action->multi_add[ACTION_MULTI_FILTER]->first; - while ((filter_name != NULL) - && (0 != strcmp(filter_group->name, filter_name->str))) - { - filter_name = filter_name->next; - } - - if (filter_name != NULL) - { - current_mode = 'y'; - } - else + if ((csp->rlist[i] != NULL) && (csp->rlist[i]->f != NULL)) { - filter_name = cur_line->data.action->multi_remove[ACTION_MULTI_FILTER]->first; - while ((filter_name != NULL) - && (0 != strcmp(filter_group->name, filter_name->str))) - { - filter_name = filter_name->next; - } - if (filter_name != NULL) + filter_group = csp->rlist[i]->f; + for (;(!err) && (filter_group != NULL); filter_group = filter_group->next) { - current_mode = 'n'; - } - } + char current_mode = 'x'; + struct list_entry *filter_name; + char * this_line; + struct map *line_exports; + char number[20]; - /* Generate a unique serial number */ - snprintf(number, sizeof(number), "%x", index++); - number[sizeof(number) - 1] = '\0'; + filter_name = cur_line->data.action->multi_add[ACTION_MULTI_FILTER]->first; + while ((filter_name != NULL) + && (0 != strcmp(filter_group->name, filter_name->str))) + { + filter_name = filter_name->next; + } - line_exports = new_map(); - if (line_exports == NULL) - { - err = JB_ERR_MEMORY; - freez(result); - } - else - { - if (!err) err = map(line_exports, "index", 1, number, 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); + if (filter_name != NULL) + { + current_mode = 'y'; + } + else + { + filter_name = cur_line->data.action->multi_remove[ACTION_MULTI_FILTER]->first; + log_error(LOG_LEVEL_CGI, "cgiedit: filter_group->name: [%s]",filter_group->name); + while ((filter_name != NULL) + && (0 != strcmp(filter_group->name, filter_name->str))) + { + filter_name = filter_name->next; + } + if (filter_name != NULL) + { + current_mode = 'n'; + } + } - this_line = NULL; - if (!err) - { - this_line = strdup(filter_template); - if (this_line == NULL) err = JB_ERR_MEMORY; - } - if (!err) err = template_fill(&this_line, line_exports); - string_join(&result, this_line); + /* Generate a unique serial number */ + snprintf(number, sizeof(number), "%x", index++); + number[sizeof(number) - 1] = '\0'; - free_map(line_exports); + line_exports = new_map(); + if (line_exports == NULL) + { + err = JB_ERR_MEMORY; + freez(result); + } + else + { + if (!err) err = map(line_exports, "index", 1, number, 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; + if (!err) + { + this_line = strdup(filter_template); + if (this_line == NULL) err = JB_ERR_MEMORY; + } + if (!err) err = template_fill(&this_line, line_exports); + string_join(&result, this_line); + + free_map(line_exports); + } + } } } - freez(filter_template); if (!err) @@ -3213,7 +3223,7 @@ get_string_param(parameters, "p", &action_set_name); if (action_set_name != NULL) { - for (index = 0; index < MAX_ACTION_FILES; index++) + for (index = 0; index < MAX_AF_FILES; index++) { if (((fl = csp->actions_list[index]) != NULL) && ((b = fl->f) != NULL)) { diff -urNad privoxy~/cgisimple.c privoxy/cgisimple.c --- privoxy~/cgisimple.c 2006-02-11 23:44:37.000000000 +0100 +++ privoxy/cgisimple.c 2006-02-11 23:44:37.000000000 +0100 @@ -829,7 +829,7 @@ switch (*(lookup(parameters, "file"))) { case 'a': - if (!get_number_param(csp, parameters, "index", &i) && i < MAX_ACTION_FILES && csp->actions_list[i]) + if (!get_number_param(csp, parameters, "index", &i) && i < MAX_AF_FILES && csp->actions_list[i]) { filename = csp->actions_list[i]->filename; file_description = "Actions File"; @@ -837,9 +837,9 @@ break; case 'f': - if (csp->rlist) + if (!get_number_param(csp, parameters, "index", &i) && i < MAX_AF_FILES && csp->rlist[i]) { - filename = csp->rlist->filename; + filename = csp->rlist[i]->filename; file_description = "Filter File"; } break; @@ -954,7 +954,7 @@ * FIXME: Shouldn't include hardwired HTML here, use line template instead! */ s = strdup(""); - for (i = 0; i < MAX_ACTION_FILES; i++) + for (i = 0; i < MAX_AF_FILES; i++) { if (((fl = csp->actions_list[i]) != NULL) && ((b = fl->f) != NULL)) { @@ -983,13 +983,29 @@ if (!err) err = map(exports, "actions-filenames", 1, "None specified", 1); } - if (csp->rlist) + /* + * List all re_filterfiles in use, together with view options. + * FIXME: Shouldn't include hardwired HTML here, use line template instead! + */ + s = strdup(""); + for (i = 0; i < MAX_AF_FILES; i++) { - if (!err) err = map(exports, "re-filter-filename", 1, html_encode(csp->rlist->filename), 0); + if (((fl = csp->rlist[i]) != NULL) && ((b = fl->f) != NULL)) + { + if (!err) err = string_append(&s, ""); + if (!err) err = string_join(&s, html_encode(csp->rlist[i]->filename)); + snprintf(buf, 100, "View", i); + if (!err) err = string_append(&s, buf); + if (!err) err = string_append(&s, "\n"); + } + } + if (*s != '\0') + { + if (!err) err = map(exports, "re-filter-filename", 1, s, 0); } else { - if (!err) err = map(exports, "re-filter-filename", 1, "None specified", 1); + if (!err) err = map(exports, "re-filter-filename", 1, "None specified", 1); if (!err) err = map_block_killer(exports, "have-filterfile"); } @@ -1206,7 +1222,7 @@ matches = strdup(""); - for (i = 0; i < MAX_ACTION_FILES; i++) + for (i = 0; i < MAX_AF_FILES; i++) { if (NULL == csp->config->actions_file_short[i] || !strcmp(csp->config->actions_file_short[i], "standard")) continue; diff -urNad privoxy~/config privoxy/config --- privoxy~/config 2006-02-11 23:44:37.000000000 +0100 +++ privoxy/config 2006-02-11 23:44:37.000000000 +0100 @@ -182,7 +182,7 @@ # # Specifies: # -# The filter file to use +# The filter file(s) to use # # Type of value: # @@ -199,21 +199,23 @@ # # Notes: # -# The filter file contains content modification rules that use +# The filter files contain content modification rules that use # regular expressions. These rules permit powerful changes on the # content of Web pages, e.g., you could disable your favorite # JavaScript annoyances, re-write the actual displayed text, -# or just have some fun replacing "Microsoft" with "MicroSuck" -# wherever it appears on a Web page. +# or just have some fun playing buzzword bingo with a web page. # # The +filter{name} actions rely on the relevant filter (name) -# to be defined in the filter file! +# to be defined in a filter file! # # A pre-defined filter file called default.filter that contains # a bunch of handy filters for common problems is included in the # distribution. See the section on the filter action for a list. -# +# When adding your own, it is recommended you add them to the +# user.filter file. +# filterfile default.filter +#filterfile user.filter # # 1.5. logfile diff -urNad privoxy~/filters.c privoxy/filters.c --- privoxy~/filters.c 2006-02-11 23:44:25.000000000 +0100 +++ privoxy/filters.c 2006-02-11 23:44:37.000000000 +0100 @@ -1290,6 +1290,8 @@ struct re_filterfile_spec *b; struct list_entry *filtername; + int i, found_filters = 0; + /* * Sanity first */ @@ -1299,10 +1301,26 @@ } size = csp->iob->eod - csp->iob->cur; - if ( ( NULL == (fl = csp->rlist) ) || ( NULL == fl->f) ) + /* + * Need to check the set of re_filterfiles... + */ + for (i = 0; i < MAX_AF_FILES; i++) + { + fl = csp->rlist[i]; + if (NULL != fl) + { + if (NULL != fl->f) + { + found_filters = 1; + break; + } + } + } + + if (0 == found_filters) { log_error(LOG_LEVEL_ERROR, "Unable to get current state of regexp filtering."); - return(NULL); + return(NULL); } /* @@ -1320,6 +1338,11 @@ csp->flags |= CSP_FLAG_MODIFIED; } + for (i = 0; i < MAX_AF_FILES; i++) + { + fl = csp->rlist[i]; + if ((NULL == fl) || (NULL == fl->f)) + break; /* * For all applying +filter actions, look if a filter by that * name exists and if yes, execute it's pcrs_joblist on the @@ -1356,6 +1379,7 @@ } } } + } /* * If there were no hits, destroy our copy and let @@ -1536,7 +1560,7 @@ init_current_action(csp->action); - for (i = 0; i < MAX_ACTION_FILES; i++) + for (i = 0; i < MAX_AF_FILES; i++) { if (((fl = csp->actions_list[i]) == NULL) || ((b = fl->f) == NULL)) { diff -urNad privoxy~/loadcfg.c privoxy/loadcfg.c --- privoxy~/loadcfg.c 2006-02-11 23:44:37.000000000 +0100 +++ privoxy/loadcfg.c 2006-02-11 23:44:37.000000000 +0100 @@ -65,7 +65,7 @@ * - savearg now embeds option names in help links * * Revision 1.45 2002/04/24 02:11:54 oes - * Jon's multiple AF patch: Allow up to MAX_ACTION_FILES actionsfile options + * Jon's multiple AF patch: Allow up to MAX_AF_FILES actionsfile options * * Revision 1.44 2002/04/08 20:37:13 swa * fixed JB spelling @@ -510,7 +510,7 @@ freez(config->haddr); freez(config->logfile); - for (i = 0; i < MAX_ACTION_FILES; i++) + for (i = 0; i < MAX_AF_FILES; i++) { freez(config->actions_file_short[i]); freez(config->actions_file[i]); @@ -530,7 +530,11 @@ list_remove_all(config->trust_info); #endif /* def FEATURE_TRUST */ - freez(config->re_filterfile); + for (i = 0; i < MAX_AF_FILES; i++) + { + freez(config->re_filterfile[i]); + } + freez(config); } @@ -694,16 +698,16 @@ * *************************************************************************/ case hash_actions_file : i = 0; - while ((i < MAX_ACTION_FILES) && (NULL != config->actions_file[i])) + while ((i < MAX_AF_FILES) && (NULL != config->actions_file[i])) { i++; } - if (i >= MAX_ACTION_FILES) + if (i >= MAX_AF_FILES) { log_error(LOG_LEVEL_FATAL, "Too many 'actionsfile' directives in config file - limit is %d.\n" - "(You can increase this limit by changing MAX_ACTION_FILES in project.h and recompiling).", - MAX_ACTION_FILES); + "(You can increase this limit by changing MAX_AF_FILES in project.h and recompiling).", + MAX_AF_FILES); } config->actions_file_short[i] = strdup(arg); p = malloc(strlen(arg) + sizeof(".action")); @@ -860,15 +864,27 @@ * In confdir by default. * *************************************************************************/ case hash_filterfile : - if(config->re_filterfile) + i = 0; + while ((i < MAX_AF_FILES) && (NULL != config->re_filterfile[i])) { - log_error(LOG_LEVEL_ERROR, "Ignoring extraneous directive 'filterfile %s' " - "in line %lu in configuration file (%s).", arg, linenum, configfile); - string_append(&config->proxy_args, - " WARNING: extraneous directive, ignored"); - continue; + i++; } - config->re_filterfile = make_path(config->confdir, arg); + + if (i >= MAX_AF_FILES) + { + log_error(LOG_LEVEL_FATAL, "Too many 'filterfile' directives in config file - limit is %d.\n" + "(You can increase this limit by changing MAX_AF_FILES in project.h and recompiling).", + MAX_AF_FILES); + } + config->re_filterfile_short[i] = strdup(arg); + p = malloc(strlen(arg)); + if (p == NULL) + { + log_error(LOG_LEVEL_FATAL, "Out of memory"); + } + strcpy(p, arg); + config->re_filterfile[i] = make_path(config->confdir, p); + free(p); continue; /* ************************************************************************* diff -urNad privoxy~/loaders.c privoxy/loaders.c --- privoxy~/loaders.c 2006-02-11 23:44:25.000000000 +0100 +++ privoxy/loaders.c 2006-02-11 23:44:37.000000000 +0100 @@ -329,7 +329,12 @@ static struct file_list *current_trustfile = NULL; #endif /* def FEATURE_TRUST */ -static struct file_list *current_re_filterfile = NULL; +static int load_one_re_filterfile(struct client_state *csp, int fileid); + +static struct file_list *current_re_filterfile[MAX_AF_FILES] = { + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL +}; @@ -388,7 +393,7 @@ /* * Actions files */ - for (i = 0; i < MAX_ACTION_FILES; i++) + for (i = 0; i < MAX_AF_FILES; i++) { if (csp->actions_list[i]) { @@ -397,11 +402,14 @@ } /* - * Filter file + * Filter files */ - if (csp->rlist) + for (i = 0; i < MAX_AF_FILES; i++) { - csp->rlist->active = 1; + if (csp->rlist[i]) + { + csp->rlist[i]->active = 1; + } } /* @@ -1247,10 +1255,15 @@ *********************************************************************/ void unload_current_re_filterfile(void) { - if (current_re_filterfile) + int i; + + for (i = 0; i < MAX_AF_FILES; i++) { - current_re_filterfile->unloader = unload_re_filterfile; - current_re_filterfile = NULL; + if (current_re_filterfile[i]) + { + current_re_filterfile[i]->unloader = unload_re_filterfile; + current_re_filterfile[i] = NULL; + } } } #endif @@ -1273,6 +1286,46 @@ *********************************************************************/ int load_re_filterfile(struct client_state *csp) { + int i; + int result; + + for (i = 0; i < MAX_AF_FILES; i++) + { + if (csp->config->re_filterfile[i]) + { + result = load_one_re_filterfile(csp, i); + if (result) + { + return result; + } + } + else if (current_re_filterfile[i]) + { + current_re_filterfile[i]->unloader = unload_re_filterfile; + current_re_filterfile[i] = NULL; + } + } + + return 0; +} + +/********************************************************************* + * + * Function : load_one_re_filterfile + * + * Description : Load a re_filterfile. + * Generate a chained list of re_filterfile_spec's from + * the "FILTER: " blocks, compiling all their substitutions + * into chained lists of pcrs_job structs. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * + * Returns : 0 => Ok, everything else is an error. + * + *********************************************************************/ +int load_one_re_filterfile(struct client_state *csp, int fileid) +{ FILE *fp; struct re_filterfile_spec *new_bl, *bl = NULL; @@ -1286,11 +1339,12 @@ /* * No need to reload if unchanged */ - if (!check_file_changed(current_re_filterfile, csp->config->re_filterfile, &fs)) + log_error(LOG_LEVEL_RE_FILTER, "load_one_re_filterfile: checking: %s\n",csp->config->re_filterfile[fileid]); + if (!check_file_changed(current_re_filterfile[fileid], csp->config->re_filterfile[fileid], &fs)) { if (csp) { - csp->rlist = current_re_filterfile; + csp->rlist[fileid] = current_re_filterfile[fileid]; } return(0); } @@ -1302,7 +1356,7 @@ /* * Open the file or fail */ - if ((fp = fopen(csp->config->re_filterfile, "r")) == NULL) + if ((fp = fopen(csp->config->re_filterfile[fileid], "r")) == NULL) { goto load_re_filterfile_error; } @@ -1397,9 +1451,9 @@ /* * Schedule the now-obsolete old data for unloading */ - if ( NULL != current_re_filterfile ) + if ( NULL != current_re_filterfile[fileid] ) { - current_re_filterfile->unloader = unload_re_filterfile; + current_re_filterfile[fileid]->unloader = unload_re_filterfile; } /* @@ -1407,18 +1461,18 @@ */ fs->next = files->next; files->next = fs; - current_re_filterfile = fs; + current_re_filterfile[fileid] = fs; if (csp) { - csp->rlist = fs; + csp->rlist[fileid] = fs; } return( 0 ); load_re_filterfile_error: log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E", - csp->config->re_filterfile); + csp->config->re_filterfile[fileid]); return(-1); } diff -urNad privoxy~/project.h privoxy/project.h --- privoxy~/project.h 2006-02-11 23:44:25.000000000 +0100 +++ privoxy/project.h 2006-02-11 23:44:37.000000000 +0100 @@ -1010,10 +1010,10 @@ #define RC_FLAG_BLOCKED 0x20 /** - * Maximum number of actions files. This limit is arbitrary - it's just used + * Maximum number of actions/filter files. This limit is arbitrary - it's just used * to size an array. */ -#define MAX_ACTION_FILES 10 +#define MAX_AF_FILES 10 /** * The state of a Privoxy processing thread. @@ -1069,10 +1069,10 @@ char *x_forwarded; /** Actions files associated with this client */ - struct file_list *actions_list[MAX_ACTION_FILES]; + struct file_list *actions_list[MAX_AF_FILES]; - /** pcrs job file. */ - struct file_list *rlist; + /** pcrs job files. */ + struct file_list *rlist[MAX_AF_FILES]; /** Length after content modification. */ size_t content_length; @@ -1328,10 +1328,10 @@ const char *logdir; /** The full paths to the actions files. */ - const char *actions_file[MAX_ACTION_FILES]; + const char *actions_file[MAX_AF_FILES]; /** The short names of the actions files. */ - const char *actions_file_short[MAX_ACTION_FILES]; + const char *actions_file_short[MAX_AF_FILES]; /** The administrator's email address */ char *admin_address; @@ -1342,8 +1342,11 @@ /** URL to the user manual (on our website or local copy) */ char *usermanual; - /** The file name of the pcre filter file */ - const char *re_filterfile; + /** The file names of the pcre filter files. */ + const char *re_filterfile[MAX_AF_FILES]; + + /** The short names of the pcre filter files. */ + const char *re_filterfile_short[MAX_AF_FILES]; #ifdef FEATURE_COOKIE_JAR diff -urNad privoxy~/templates/show-status privoxy/templates/show-status --- privoxy~/templates/show-status 2006-02-11 23:44:25.000000000 +0100 +++ privoxy/templates/show-status 2006-02-11 23:44:37.000000000 +0100 @@ -149,17 +149,12 @@ @actions-filenames@ - + -
Filter File:Filter Files:
@re-filter-filename@ - - View - -