X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=actions.c;h=38ddfc9a034cf76a7df340b4c1935a16128c26b7;hp=00b4bced8c2c142fb6ecb57138257a8b200fe267;hb=932f6a29501949c99204c8f2ed8ae7d9704e53af;hpb=cf3a392e800fb9f901b62e342c676d4574d53803 diff --git a/actions.c b/actions.c index 00b4bced..38ddfc9a 100644 --- a/actions.c +++ b/actions.c @@ -1,12 +1,11 @@ -const char actions_rcs[] = "$Id: actions.c,v 1.59 2010/05/26 23:01:47 ler762 Exp $"; +const char actions_rcs[] = "$Id: actions.c,v 1.83 2012/06/08 15:15:11 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/actions.c,v $ * * Purpose : Declares functions to work with actions files - * Functions declared include: FIXME * - * Copyright : Written by and Copyright (C) 2001-2008 the SourceForge + * Copyright : Written by and Copyright (C) 2001-2011 the * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written @@ -70,11 +69,13 @@ const char actions_h_rcs[] = ACTIONS_H_VERSION; * an enumerated type (well, the preprocessor equivalent). Here are * the values: */ -#define AV_NONE 0 /* +opt -opt */ -#define AV_ADD_STRING 1 /* +stropt{string} */ -#define AV_REM_STRING 2 /* -stropt */ -#define AV_ADD_MULTI 3 /* +multiopt{string} +multiopt{string2} */ -#define AV_REM_MULTI 4 /* -multiopt{string} -multiopt */ +enum action_value_type { + AV_NONE = 0, /* +opt -opt */ + AV_ADD_STRING = 1, /* +stropt{string} */ + AV_REM_STRING = 2, /* -stropt */ + AV_ADD_MULTI = 3, /* +multiopt{string} +multiopt{string2} */ + AV_REM_MULTI = 4 /* -multiopt{string} -multiopt */ +}; /* * We need a structure to hold the name, flag changes, @@ -83,10 +84,10 @@ const char actions_h_rcs[] = ACTIONS_H_VERSION; struct action_name { const char * name; - unsigned long mask; /* a bit set to "0" = remove action */ - unsigned long add; /* a bit set to "1" = add action */ - int takes_value; /* an AV_... constant */ - int index; /* index into strings[] or multi[] */ + unsigned long mask; /* a bit set to "0" = remove action */ + unsigned long add; /* a bit set to "1" = add action */ + enum action_value_type value_type; /* an AV_... constant */ + int index; /* index into strings[] or multi[] */ }; /* @@ -319,7 +320,7 @@ void free_action (struct action_spec *src) * Function : get_action_token * * Description : Parses a line for the first action. - * Modifies it's input array, doesn't allocate memory. + * Modifies its input array, doesn't allocate memory. * e.g. given: * *line=" +abc{def} -ghi " * Returns: @@ -434,7 +435,7 @@ jb_err get_action_token(char **line, char **name, char **value) *********************************************************************/ static int action_used_to_be_valid(const char *action) { - static const char *formerly_valid_actions[] = { + static const char * const formerly_valid_actions[] = { "inspect-jpegs", "kill-popups", "send-vanilla-wafer", @@ -500,7 +501,7 @@ jb_err get_actions(char *line, /* Check for standard action name */ const struct action_name * action = action_names; - while ( (action->name != NULL) && (0 != strcmpic(action->name, option)) ) + while ((action->name != NULL) && (0 != strcmpic(action->name, option))) { action++; } @@ -511,7 +512,7 @@ jb_err get_actions(char *line, cur_action->add &= action->mask; cur_action->add |= action->add; - switch (action->takes_value) + switch (action->value_type) { case AV_NONE: /* ignore any option. */ @@ -522,7 +523,7 @@ jb_err get_actions(char *line, if ((value == NULL) || (*value == '\0')) { - if (0 != strcmpic(action->name, "block")) + if (0 == strcmpic(action->name, "+block")) { /* * XXX: Temporary backwards compatibility hack. @@ -581,8 +582,8 @@ jb_err get_actions(char *line, struct list * remove_p = cur_action->multi_remove[action->index]; struct list * add_p = cur_action->multi_add[action->index]; - if ( (value == NULL) || (*value == '\0') - || ((*value == '*') && (value[1] == '\0')) ) + if ((value == NULL) || (*value == '\0') + || ((*value == '*') && (value[1] == '\0'))) { /* * no option, or option == "*". @@ -597,7 +598,7 @@ jb_err get_actions(char *line, { /* Valid option - remove only 1 option */ - if ( !cur_action->multi_remove_all[action->index] ) + if (!cur_action->multi_remove_all[action->index]) { /* there isn't a catch-all in the remove list already */ err = enlist_unique(remove_p, value, 0); @@ -621,7 +622,7 @@ jb_err get_actions(char *line, /* try user aliases. */ const struct action_alias * alias = alias_list; - while ( (alias != NULL) && (0 != strcmpic(alias->name, option)) ) + while ((alias != NULL) && (0 != strcmpic(alias->name, option))) { alias = alias->next; } @@ -772,36 +773,6 @@ jb_err merge_current_action (struct current_action_spec *dest, return err; } -#if 0 -/********************************************************************* - * - * 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 /********************************************************************* * @@ -1033,6 +1004,108 @@ int load_action_files(struct client_state *csp) return 0; } + +/********************************************************************* + * + * Function : referenced_filters_are_missing + * + * Description : Checks if any filters of a certain type referenced + * in an action spec are missing. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : cur_action = The action spec to check. + * 3 : multi_index = The index where to look for the filter. + * 4 : filter_type = The filter type the caller is interested in. + * + * Returns : 0 => All referenced filters exists, everything else is an error. + * + *********************************************************************/ +static int referenced_filters_are_missing(const struct client_state *csp, + const struct action_spec *cur_action, int multi_index, enum filter_type filter_type) +{ + int i; + struct file_list *fl; + struct re_filterfile_spec *b; + struct list_entry *filtername; + + for (filtername = cur_action->multi_add[multi_index]->first; + filtername; filtername = filtername->next) + { + int filter_found = 0; + for (i = 0; i < MAX_AF_FILES; i++) + { + fl = csp->rlist[i]; + if ((NULL == fl) || (NULL == fl->f)) + { + continue; + } + + for (b = fl->f; b; b = b->next) + { + if (b->type != filter_type) + { + continue; + } + if (strcmp(b->name, filtername->str) == 0) + { + filter_found = 1; + } + } + } + if (!filter_found) + { + log_error(LOG_LEVEL_ERROR, "Missing filter '%s'", filtername->str); + return 1; + } + } + + return 0; + +} + + +/********************************************************************* + * + * Function : action_spec_is_valid + * + * Description : Should eventually figure out if an action spec + * is valid, but currently only checks that the + * referenced filters are accounted for. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : cur_action = The action spec to check. + * + * Returns : 0 => No problems detected, everything else is an error. + * + *********************************************************************/ +static int action_spec_is_valid(struct client_state *csp, const struct action_spec *cur_action) +{ + struct { + int multi_index; + enum filter_type filter_type; + } filter_map[] = { + {ACTION_MULTI_FILTER, FT_CONTENT_FILTER}, + {ACTION_MULTI_CLIENT_HEADER_FILTER, FT_CLIENT_HEADER_FILTER}, + {ACTION_MULTI_SERVER_HEADER_FILTER, FT_SERVER_HEADER_FILTER}, + {ACTION_MULTI_CLIENT_HEADER_TAGGER, FT_CLIENT_HEADER_TAGGER}, + {ACTION_MULTI_SERVER_HEADER_TAGGER, FT_SERVER_HEADER_TAGGER} + }; + int errors = 0; + int i; + + for (i = 0; i < SZ(filter_map); i++) + { + errors += referenced_filters_are_missing(csp, cur_action, + filter_map[i].multi_index, filter_map[i].filter_type); + } + + return errors; + +} + + /********************************************************************* * * Function : load_one_actions_file @@ -1055,23 +1128,24 @@ static int load_one_actions_file(struct client_state *csp, int fileid) * Note: Keep these in the order they occur in the file, they are * sometimes tested with <= */ -#define MODE_START_OF_FILE 1 -#define MODE_SETTINGS 2 -#define MODE_DESCRIPTION 3 -#define MODE_ALIAS 4 -#define MODE_ACTIONS 5 - - int mode = MODE_START_OF_FILE; + enum { + MODE_START_OF_FILE = 1, + MODE_SETTINGS = 2, + MODE_DESCRIPTION = 3, + MODE_ALIAS = 4, + MODE_ACTIONS = 5 + } mode; FILE *fp; struct url_actions *last_perm; struct url_actions *perm; - char buf[BUFFER_SIZE]; + char *buf; struct file_list *fs; struct action_spec * cur_action = NULL; int cur_action_used = 0; struct action_alias * alias_list = NULL; unsigned long linenum = 0; + mode = MODE_START_OF_FILE; if (!check_file_changed(current_actions_file[fileid], csp->config->actions_file[fileid], &fs)) { @@ -1104,7 +1178,7 @@ static int load_one_actions_file(struct client_state *csp, int fileid) log_error(LOG_LEVEL_INFO, "Loading actions file: %s", csp->config->actions_file[fileid]); - while (read_config_line(buf, sizeof(buf), fp, &linenum) != NULL) + while (read_config_line(fp, &linenum, &buf) != NULL) { if (*buf == '{') { @@ -1120,7 +1194,7 @@ static int load_one_actions_file(struct client_state *csp, int fileid) /* too short */ fclose(fp); log_error(LOG_LEVEL_FATAL, - "can't load actions file '%s': invalid line (%lu): %s", + "can't load actions file '%s': invalid line (%lu): %s", csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } @@ -1221,11 +1295,11 @@ static int load_one_actions_file(struct client_state *csp, int fileid) { /* It's an actions block */ - char actions_buf[BUFFER_SIZE]; + char *actions_buf; char * end; /* set mode */ - mode = MODE_ACTIONS; + mode = MODE_ACTIONS; /* free old action */ if (cur_action) @@ -1248,8 +1322,23 @@ static int load_one_actions_file(struct client_state *csp, int fileid) } init_action(cur_action); - /* trim { */ - strlcpy(actions_buf, buf + 1, sizeof(actions_buf)); + /* + * Copy the buffer before messing with it as we may need the + * unmodified version in for the fatal error messages. Given + * that this is not a common event, we could instead simply + * read the line again. + * + * buf + 1 to skip the leading '{' + */ + actions_buf = strdup(buf + 1); + if (actions_buf == 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 */ + } /* check we have a trailing } and then trim it */ end = actions_buf + strlen(actions_buf) - 1; @@ -1257,8 +1346,9 @@ static int load_one_actions_file(struct client_state *csp, int fileid) { /* No closing } */ fclose(fp); - log_error(LOG_LEVEL_FATAL, - "can't load actions file '%s': invalid line (%lu): %s", + freez(actions_buf); + log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': " + "Missing trailing '}' in action section starting at line (%lu): %s", csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } @@ -1271,11 +1361,21 @@ static int load_one_actions_file(struct client_state *csp, int fileid) { /* error */ fclose(fp); - log_error(LOG_LEVEL_FATAL, - "can't load actions file '%s': invalid line (%lu): %s", + freez(actions_buf); + log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': " + "can't completely parse the action section starting at line (%lu): %s", csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } + + if (action_spec_is_valid(csp, cur_action)) + { + log_error(LOG_LEVEL_ERROR, "Invalid action section in file '%s', " + "starting at line %lu: %s", + csp->config->actions_file[fileid], linenum, buf); + } + + freez(actions_buf); } } else if (mode == MODE_SETTINGS) @@ -1299,8 +1399,8 @@ static int load_one_actions_file(struct client_state *csp, int fileid) csp->config->actions_file[fileid]); return 1; /* never get here */ } - - num_fields = ssplit(version_string, ".", fields, 3, TRUE, FALSE); + + num_fields = ssplit(version_string, ".", fields, SZ(fields)); if (num_fields < 1 || atoi(fields[0]) == 0) { @@ -1308,14 +1408,14 @@ static int load_one_actions_file(struct client_state *csp, int fileid) "While loading actions file '%s': invalid line (%lu): %s", csp->config->actions_file[fileid], linenum, buf); } - else if ( atoi(fields[0]) > VERSION_MAJOR - || (num_fields > 1 && atoi(fields[1]) > VERSION_MINOR) - || (num_fields > 2 && atoi(fields[2]) > VERSION_POINT)) + else if ( (atoi(fields[0]) > VERSION_MAJOR) + || ((num_fields > 1) && (atoi(fields[1]) > VERSION_MINOR)) + || ((num_fields > 2) && (atoi(fields[2]) > VERSION_POINT))) { fclose(fp); log_error(LOG_LEVEL_FATAL, "Actions file '%s', line %lu requires newer Privoxy version: %s", - csp->config->actions_file[fileid], linenum, buf ); + csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } free(version_string); @@ -1429,7 +1529,7 @@ static int load_one_actions_file(struct client_state *csp, int fileid) { fclose(fp); log_error(LOG_LEVEL_FATAL, - "can't load actions file '%s': line %lu: cannot create URL pattern from: %s", + "can't load actions file '%s': line %lu: cannot create URL or TAG pattern from: %s", csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } @@ -1443,7 +1543,7 @@ static int load_one_actions_file(struct client_state *csp, int fileid) /* oops - please have a {} line as 1st line in file. */ fclose(fp); log_error(LOG_LEVEL_FATAL, - "can't load actions file '%s': first needed line (%lu) is invalid: %s", + "can't load actions file '%s': line %lu should begin with a '{': %s", csp->config->actions_file[fileid], linenum, buf); return 1; /* never get here */ } @@ -1456,6 +1556,7 @@ static int load_one_actions_file(struct client_state *csp, int fileid) csp->config->actions_file[fileid], mode); return 1; /* never get here */ } + freez(buf); } fclose(fp); @@ -1489,7 +1590,7 @@ static int load_one_actions_file(struct client_state *csp, int fileid) * * Description : Converts a actionsfile entry from the internal * structure into a text line. The output is split - * into one line for each action with line continuation. + * into one line for each action with line continuation. * * Parameters : * 1 : action = The action to format. @@ -1574,7 +1675,7 @@ char * actions_to_text(const struct action_spec *action) * Function : actions_to_html * * Description : Converts a actionsfile entry from numeric form - * ("mask" and "add") to a
-seperated HTML string + * ("mask" and "add") to a
-separated HTML string * in which each action is linked to its chapter in * the user manual. * @@ -1680,12 +1781,12 @@ char * actions_to_html(const struct client_state *csp, * * Function : current_actions_to_html * - * Description : Converts a curren action spec to a
seperated HTML + * Description : Converts a curren action spec to a
separated HTML * text in which each action is linked to its chapter in * the user manual. * * Parameters : - * 1 : csp = Client state (for config) + * 1 : csp = Client state (for config) * 2 : action = Current action spec to be converted * * Returns : A string. Caller must free it. @@ -1770,3 +1871,69 @@ char *current_action_to_html(const struct client_state *csp, } return result; } + + +/********************************************************************* + * + * Function : action_to_line_of_text + * + * Description : Converts a action spec to a single text line + * listing the enabled actions. + * + * Parameters : + * 1 : action = Current action spec to be converted + * + * Returns : A string. Caller must free it. + * Out-of-memory errors are fatal. + * + *********************************************************************/ +char *actions_to_line_of_text(const struct current_action_spec *action) +{ + char buffer[200]; + struct list_entry *lst; + char *active; + const unsigned long flags = action->flags; + + active = strdup_or_die(""); + +#define DEFINE_ACTION_BOOL(__name, __bit) \ + if (flags & __bit) \ + { \ + snprintf(buffer, sizeof(buffer), "+%s ", __name); \ + string_append(&active, buffer); \ + } \ + +#define DEFINE_ACTION_STRING(__name, __bit, __index) \ + if (flags & __bit) \ + { \ + snprintf(buffer, sizeof(buffer), "+%s{%s} ", \ + __name, action->string[__index]); \ + string_append(&active, buffer); \ + } \ + +#define DEFINE_ACTION_MULTI(__name, __index) \ + lst = action->multi[__index]->first; \ + while (lst != NULL) \ + { \ + snprintf(buffer, sizeof(buffer), "+%s{%s} ", \ + __name, lst->str); \ + string_append(&active, buffer); \ + lst = lst->next; \ + } \ + +#define DEFINE_ACTION_ALIAS 0 /* No aliases for output */ + +#include "actionlist.h" + +#undef DEFINE_ACTION_MULTI +#undef DEFINE_ACTION_STRING +#undef DEFINE_ACTION_BOOL +#undef DEFINE_ACTION_ALIAS + + if (active == NULL) + { + log_error(LOG_LEVEL_FATAL, "Out of memory in action_to_line_of_text()"); + } + + return active; +}