X-Git-Url: http://www.privoxy.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=cgiedit.c;h=2fb01eef808aa0b5562268fb7170886c24f18a13;hb=3789d801f6b08697f16edd034108a544f183ef31;hp=c50ad20ff812a712a04ae9f85c6627f88f9e4c6b;hpb=a37d7a0cdcf83a6119e778c4cd8ab3e8dbd818bc;p=privoxy.git diff --git a/cgiedit.c b/cgiedit.c index c50ad20f..2fb01eef 100644 --- a/cgiedit.c +++ b/cgiedit.c @@ -1,4 +1,4 @@ -const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.44 2006/12/09 13:49:16 fabiankeil Exp $"; +const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.50 2007/03/29 11:40:34 fabiankeil Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/cgiedit.c,v $ @@ -15,7 +15,7 @@ const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.44 2006/12/09 13:49:16 fabiankeil * * Stick to the short names in this file for consistency. * - * Copyright : Written by and Copyright (C) 2001 the SourceForge + * Copyright : Written by and Copyright (C) 2001-2007 the SourceForge * Privoxy team. http://www.privoxy.org/ * * Based on the Internet Junkbuster originally written @@ -42,6 +42,30 @@ const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.44 2006/12/09 13:49:16 fabiankeil * * Revisions : * $Log: cgiedit.c,v $ + * Revision 1.50 2007/03/29 11:40:34 fabiankeil + * Divide @filter-params@ into @client-header-filter-params@ + * @content-filter-params@ and @server-header-filter-params@. + * + * Revision 1.49 2007/03/20 15:16:34 fabiankeil + * Use dedicated header filter actions instead of abusing "filter". + * Replace "filter-client-headers" and "filter-client-headers" + * with "server-header-filter" and "client-header-filter". + * + * Revision 1.48 2007/02/13 14:35:25 fabiankeil + * Replace hash escaping code to prevent + * crashes, memory and file corruption. + * + * Revision 1.47 2006/12/28 18:04:25 fabiankeil + * Fixed gcc43 conversion warnings. + * + * Revision 1.46 2006/12/27 18:44:52 fabiankeil + * Stop shadowing string.h's index(). + * + * Revision 1.45 2006/12/21 12:57:48 fabiankeil + * Add config option "split-large-forms" + * to work around the browser bug reported + * in BR #1570678. + * * Revision 1.44 2006/12/09 13:49:16 fabiankeil * Fix configure option --disable-toggle. * Thanks to Peter Thoenen for reporting this. @@ -450,8 +474,7 @@ struct editable_file { struct file_line * lines; /**< The contents of the file. A linked list of lines. */ 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. */ + int identifier; /**< The file name's position in csp->config->actions_file[]. */ const char * version_str; /**< Last modification time, as a string. For CGI param. */ /**< Can be used in URL without using url_param(). */ unsigned version; /**< Last modification time - prevents chaos with @@ -474,7 +497,6 @@ struct editable_file jb_err edit_read_file(struct client_state *csp, const struct map *parameters, int require_version, - const char *suffix, struct editable_file **pfile); jb_err edit_write_file(struct editable_file * file); void edit_free_file(struct editable_file * file); @@ -510,13 +532,6 @@ static int match_actions_file_header_line(const char * line, const char * name); static jb_err split_line_on_equals(const char * line, char ** pname, char ** pvalue); /* Internal parameter parsing functions */ -static jb_err get_file_name_param(struct client_state *csp, - const struct map *parameters, - const char *param_name, - const char *suffix, - char **pfilename, - const char **pparam); - static jb_err get_url_spec_param(struct client_state *csp, const struct map *parameters, const char *name, @@ -554,6 +569,10 @@ static char *section_target(const unsigned sectionid); * allocated string of the form #l, for use in link * targets. * + * XXX: The hash should be moved into the templates + * to make this function more generic and render + * stringify() obsolete. + * * Parameters : * 1 : sectionid = start line number of section * @@ -571,6 +590,27 @@ static char *section_target(const unsigned sectionid) } +/********************************************************************* + * + * Function : stringify + * + * Description : Convert a number into a dynamically allocated string. + * + * Parameters : + * 1 : number = The number to convert. + * + * Returns : String with link target, or NULL if out of memory + * + *********************************************************************/ +static char *stringify(const int number) +{ + char buf[6]; + + snprintf(buf, sizeof(buf), "%i", number); + return strdup(buf); +} + + /********************************************************************* * * Function : map_copy_parameter_html @@ -668,6 +708,7 @@ static jb_err map_copy_parameter_url(struct map *out, } #endif /* 0 - unused function */ + /********************************************************************* * * Function : cgi_edit_actions_url_form @@ -681,7 +722,7 @@ static jb_err map_copy_parameter_url(struct map *out, * 3 : parameters = map of cgi parameters * * CGI Parameters - * f : (filename) Identifies the file to edit + * i : (action index) Identifies the file to edit * v : (version) File's last-modified time * p : (pattern) Line number of pattern to edit * @@ -752,7 +793,7 @@ jb_err cgi_edit_actions_url_form(struct client_state *csp, return JB_ERR_MEMORY; } - err = map(exports, "f", 1, file->identifier, 1); + err = map(exports, "f", 1, stringify(file->identifier), 0); if (!err) err = map(exports, "v", 1, file->version_str, 1); if (!err) err = map(exports, "p", 1, url_encode(lookup(parameters, "p")), 0); if (!err) err = map(exports, "u", 1, html_encode(cur_line->unprocessed), 0); @@ -841,7 +882,7 @@ jb_err cgi_edit_actions_add_url_form(struct client_state *csp, * 3 : parameters = map of cgi parameters * * CGI Parameters : - * f : (filename) Identifies the file to edit + * f : (number) The action file identifier. * v : (version) File's last-modified time * p : (pattern) Line number of pattern to edit * @@ -912,11 +953,12 @@ jb_err cgi_edit_actions_remove_url_form(struct client_state *csp, return JB_ERR_MEMORY; } - err = map(exports, "f", 1, file->identifier, 1); + err = map(exports, "f", 1, stringify(file->identifier), 0); if (!err) err = map(exports, "v", 1, file->version_str, 1); if (!err) err = map(exports, "p", 1, url_encode(lookup(parameters, "p")), 0); if (!err) err = map(exports, "u", 1, html_encode(cur_line->unprocessed), 0); if (!err) err = map(exports, "jumptarget", 1, section_target(section_start_line_number), 0); + if (!err) err = map(exports, "actions-file", 1, html_encode(file->filename), 0); edit_free_file(file); @@ -990,7 +1032,7 @@ jb_err edit_write_file(struct editable_file * file) { /* Must quote '#' characters */ int numhash = 0; - int len; + size_t len; char * src; char * dest; char * str; @@ -1005,29 +1047,44 @@ jb_err edit_write_file(struct editable_file * file) assert(numhash > 0); /* Allocate new memory for string */ - len = strlen(cur_line->unprocessed); - if (NULL == (str = malloc((size_t) len + 1 + numhash))) + len = strlen(cur_line->unprocessed) + (size_t)numhash; + if (NULL == (str = malloc(len + 1))) { /* Uh oh, just trashed file! */ fclose(fp); return JB_ERR_MEMORY; } - /* Loop through string from end */ - src = cur_line->unprocessed + len; - dest = str + len + numhash; - for ( ; len >= 0; len--) + /* Copy string but quote hashes */ + src = cur_line->unprocessed; + dest = str; + while (*src) { - if ((*dest-- = *src--) == '#') + if (*src == '#') { - *dest-- = '\\'; + *dest++ = '\\'; numhash--; assert(numhash >= 0); } + *dest++ = *src++; } + *dest = '\0'; + assert(numhash == 0); - assert(src + 1 == cur_line->unprocessed); - assert(dest + 1 == str); + assert(strlen(str) == len); + assert(str == dest - len); + assert(src - len <= cur_line->unprocessed); + + if ((strlen(str) != len) || (numhash != 0)) + { + /* + * Escaping didn't work as expected, go spread the news. + * Only reached in non-debugging builds. + */ + log_error(LOG_LEVEL_ERROR, + "Looks like hash escaping failed. %s might be corrupted now.", + file->filename); + } if (fputs(str, fp) < 0) { @@ -1110,8 +1167,6 @@ void edit_free_file(struct editable_file * file) } edit_free_file_lines(file->lines); - freez(file->filename); - freez(file->identifier); freez(file->version_str); file->version = 0; file->parse_error_text = NULL; /* Statically allocated */ @@ -1288,7 +1343,7 @@ static jb_err split_line_on_equals(const char * line, char ** pname, char ** pva name_end--; } - name_len = name_end - line + 1; /* Length excluding \0 */ + name_len = (size_t)(name_end - line) + 1; /* Length excluding \0 */ if (NULL == (*pname = (char *) malloc(name_len + 1))) { return JB_ERR_MEMORY; @@ -1706,13 +1761,11 @@ jb_err edit_read_file_lines(FILE *fp, struct file_line ** pfile, int *newline) * 1 : csp = Current client state (buffers, headers, etc...) * 2 : parameters = map of cgi parameters. * 3 : require_version = true to check "ver" parameter. - * 4 : suffix = File extension, e.g. ".action". - * 5 : pfile = Destination for the file. Will be set + * 4 : pfile = Destination for the file. Will be set * to NULL on error. * * CGI Parameters : - * filename : The name of the file to read, without the - * path or ".action" extension. + * f : The action file identifier. * ver : (Only if require_version is nonzero) * Timestamp of the actions file. If wrong, this * function fails with JB_ERR_MODIFIED. @@ -1731,19 +1784,18 @@ jb_err edit_read_file_lines(FILE *fp, struct file_line ** pfile, int *newline) jb_err edit_read_file(struct client_state *csp, const struct map *parameters, int require_version, - const char *suffix, struct editable_file **pfile) { struct file_line * lines; FILE * fp; jb_err err; - char * filename; - const char * identifier; + const char * filename = NULL; struct editable_file * file; unsigned version = 0; struct stat statbuf[1]; char version_buf[22]; int newline = NEWLINE_UNKNOWN; + int i; assert(csp); assert(parameters); @@ -1751,17 +1803,24 @@ jb_err edit_read_file(struct client_state *csp, *pfile = NULL; - err = get_file_name_param(csp, parameters, "f", suffix, - &filename, &identifier); - if (err) + if ((JB_ERR_OK == get_number_param(csp, parameters, "f", &i)) + && (i < MAX_AF_FILES) && (NULL != csp->config->actions_file[i])) { - return err; + /* + * i is guaranteed to be non-negative because + * get_number_param returned JB_ERR_OK. + * + * XXX: This comment wouldn't be necessary if + * get_number_param's fourth parameter would simply + * be changed to unsigned. I don't see the point of + * overloading its meaning to signal problems. + */ + filename = csp->config->actions_file[i]; } - if (stat(filename, statbuf) < 0) + if (filename == NULL || stat(filename, statbuf) < 0) { /* Error, probably file not found. */ - free(filename); return JB_ERR_FILE; } version = (unsigned) statbuf->st_mtime; @@ -1772,7 +1831,6 @@ jb_err edit_read_file(struct client_state *csp, err = get_number_param(csp, parameters, "v", &specified_version); if (err) { - free(filename); return err; } @@ -1784,7 +1842,6 @@ jb_err edit_read_file(struct client_state *csp, if (NULL == (fp = fopen(filename,"rb"))) { - free(filename); return JB_ERR_FILE; } @@ -1794,14 +1851,12 @@ jb_err edit_read_file(struct client_state *csp, if (err) { - free(filename); return err; } file = (struct editable_file *) zalloc(sizeof(*file)); if (err) { - free(filename); edit_free_file_lines(lines); return err; } @@ -1810,13 +1865,7 @@ jb_err edit_read_file(struct client_state *csp, file->newline = newline; file->filename = filename; file->version = version; - file->identifier = url_encode(identifier); - - if (file->identifier == NULL) - { - edit_free_file(file); - return JB_ERR_MEMORY; - } + file->identifier = i; /* Correct file->version_str */ freez(file->version_str); @@ -1856,8 +1905,7 @@ jb_err edit_read_file(struct client_state *csp, * to NULL on error. * * CGI Parameters : - * filename : The name of the actions file to read, without the - * path or ".action" extension. + * f : The actions file identifier. * ver : (Only if require_version is nonzero) * Timestamp of the actions file. If wrong, this * function fails with JB_ERR_MODIFIED. @@ -1887,7 +1935,7 @@ jb_err edit_read_actions_file(struct client_state *csp, *pfile = NULL; - err = edit_read_file(csp, parameters, require_version, ".action", &file); + err = edit_read_file(csp, parameters, require_version, &file); if (err) { /* Try to handle if possible */ @@ -1934,6 +1982,10 @@ jb_err edit_read_actions_file(struct client_state *csp, } +#if 0 +/* + * Currently not needed, but may become useful again in the future. + */ /********************************************************************* * * Function : get_file_name_param @@ -1984,7 +2036,7 @@ static jb_err get_file_name_param(struct client_state *csp, char *name; char *fullpath; char ch; - int len; + size_t len; assert(csp); assert(parameters); @@ -2048,6 +2100,7 @@ static jb_err get_file_name_param(struct client_state *csp, return JB_ERR_OK; } +#endif /*0*/ /********************************************************************* @@ -2241,7 +2294,7 @@ static jb_err map_radio(struct map * exports, } } - *p = value; + *p = (char)value; return map(exports, buf, 0, "checked", 1); } @@ -2326,7 +2379,7 @@ jb_err cgi_error_parse(struct client_state *csp, return JB_ERR_MEMORY; } - err = map(exports, "f", 1, file->identifier, 1); + err = map(exports, "f", 1, stringify(file->identifier), 0); if (!err) err = map(exports, "parse-error", 1, html_encode(file->parse_error_text), 0); cur_line = file->parse_error; @@ -2392,7 +2445,7 @@ jb_err cgi_error_file(struct client_state *csp, /********************************************************************* * - * Function : cgi_error_file + * Function : cgi_error_file_read_only * * Description : CGI function that is called when a file cannot be * opened for writing by the CGI editor. @@ -2660,13 +2713,14 @@ jb_err cgi_edit_actions_list(struct client_state *csp, /* Set up global exports */ - if (!err) err = map(exports, "f", 1, file->identifier, 1); + if (!err) err = map(exports, "actions-file", 1, html_encode(file->filename), 0); + if (!err) err = map(exports, "f", 1, stringify(file->identifier), 0); 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)); + (strstr("default.action", file->filename) != NULL)); if (err) { edit_free_file(file); @@ -3027,7 +3081,7 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, return JB_ERR_MEMORY; } - err = map(exports, "f", 1, file->identifier, 1); + err = map(exports, "f", 1, stringify(file->identifier), 0); if (!err) err = map(exports, "v", 1, file->version_str, 1); if (!err) err = map(exports, "s", 1, url_encode(lookup(parameters, "s")), 0); @@ -3080,13 +3134,19 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, } if (0 == have_filters) + { err = map(exports, "filter-params", 1, "", 1); + } else { - /* We have some entries in the filter list */ - char * result; - int index = 0; - char * filter_template; + /* + * List available filters and their settings. + */ + char *content_filter_params; + char *server_header_filter_params; + char *client_header_filter_params; + char *filter_template; + int filter_identifier = 0; err = template_load(csp, &filter_template, "edit-actions-for-url-filter", 0); if (err) @@ -3102,7 +3162,9 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, err = template_fill(&filter_template, exports); - result = strdup(""); + content_filter_params = strdup(""); + server_header_filter_params = strdup(""); + client_header_filter_params = strdup(""); for (i = 0; i < MAX_AF_FILES; i++) { @@ -3112,12 +3174,49 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, for (;(!err) && (filter_group != NULL); filter_group = filter_group->next) { char current_mode = 'x'; + char number[20]; + int multi_action_index = 0; struct list_entry *filter_name; - char * this_line; struct map *line_exports; - char number[20]; + char *this_line; + char *filter_type; + char *abbr_filter_type; + char *anchor; + char **current_params; + + switch (filter_group->type) + { + case FT_CONTENT_FILTER: + /* XXX: Should we call it content-filter instead? */ + filter_type = "filter"; + abbr_filter_type = "F"; + multi_action_index = ACTION_MULTI_FILTER; + anchor = "FILTER"; + current_params = &content_filter_params; + break; + case FT_SERVER_HEADER_FILTER: + filter_type = "server-header-filter"; + abbr_filter_type = "S"; + multi_action_index = ACTION_MULTI_SERVER_HEADER_FILTER; + current_params = &server_header_filter_params; + anchor = "SERVER-HEADER-FILTER"; /* XXX: no documentation available yet */ + break; + case FT_CLIENT_HEADER_FILTER: + filter_type = "client-header-filter"; + abbr_filter_type = "C"; + multi_action_index = ACTION_MULTI_CLIENT_HEADER_FILTER; + current_params = &client_header_filter_params; + anchor = "CLIENT-HEADER-FILTER"; /* XXX: no documentation available yet */ + break; + default: + log_error(LOG_LEVEL_FATAL, + "cgi_edit_actions_for_url: Unknown filter type: %u for filter %s.", + filter_group->type, filter_group->name); + /* Not reached. */ + } + assert(multi_action_index); - filter_name = cur_line->data.action->multi_add[ACTION_MULTI_FILTER]->first; + filter_name = cur_line->data.action->multi_add[multi_action_index]->first; while ((filter_name != NULL) && (0 != strcmp(filter_group->name, filter_name->str))) { @@ -3130,7 +3229,7 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, } else { - filter_name = cur_line->data.action->multi_remove[ACTION_MULTI_FILTER]->first; + filter_name = cur_line->data.action->multi_remove[multi_action_index]->first; while ((filter_name != NULL) && (0 != strcmp(filter_group->name, filter_name->str))) { @@ -3143,14 +3242,14 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, } /* Generate a unique serial number */ - snprintf(number, sizeof(number), "%x", index++); + snprintf(number, sizeof(number), "%x", filter_identifier++); number[sizeof(number) - 1] = '\0'; line_exports = new_map(); if (line_exports == NULL) { err = JB_ERR_MEMORY; - freez(result); + freez(*current_params); /* XXX: really necessary? */ } else { @@ -3158,6 +3257,9 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, 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 (!err) err = map(line_exports, "filter-type", 1, filter_type, 1); + if (!err) err = map(line_exports, "abbr-filter-type", 1, abbr_filter_type, 1); + if (!err) err = map(line_exports, "anchor", 1, anchor, 1); this_line = NULL; if (!err) @@ -3166,7 +3268,7 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, if (this_line == NULL) err = JB_ERR_MEMORY; } if (!err) err = template_fill(&this_line, line_exports); - string_join(&result, this_line); + string_join(current_params, this_line); free_map(line_exports); } @@ -3175,13 +3277,14 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, } freez(filter_template); - if (!err) - { - err = map(exports, "filter-params", 1, result, 0); - } - else + if (!err) err = map(exports, "content-filter-params", 1, content_filter_params, 0); + if (!err) err = map(exports, "server-header-filter-params", 1, server_header_filter_params, 0); + if (!err) err = map(exports, "client-header-filter-params", 1, client_header_filter_params, 0); + if (err) { - freez(result); + freez(content_filter_params); + freez(server_header_filter_params); + freez(client_header_filter_params); } } @@ -3232,7 +3335,7 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, unsigned line_number; char target[1024]; jb_err err; - int index; + int filter_identifier; const char * action_set_name; char ch; struct file_list * fl; @@ -3276,9 +3379,9 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, get_string_param(parameters, "p", &action_set_name); if (action_set_name != NULL) { - for (index = 0; index < MAX_AF_FILES; index++) + for (filter_identifier = 0; filter_identifier < MAX_AF_FILES; filter_identifier++) { - if (((fl = csp->actions_list[index]) != NULL) && ((b = fl->f) != NULL)) + if (((fl = csp->actions_list[filter_identifier]) != NULL) && ((b = fl->f) != NULL)) { for (b = b->next; NULL != b; b = b->next) { @@ -3319,18 +3422,29 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, cur_line->data.action->multi_remove_all[ACTION_MULTI_FILTER] = 0; } - for (index = 0; !err; index++) + for (filter_identifier = 0; !err; filter_identifier++) { char key_value[30]; char key_name[30]; + char key_type[30]; const char *name; - char value; + char value; /* + * Filter state. Valid states are: 'Y' (active), + * 'N' (inactive) and 'X' (no change). + * XXX: bad name. + */ + char type; /* + * Abbreviated filter type. Valid types are: 'F' (content filter), + * 'S' (server-header filter) and 'C' (client-header filter). + */ + int multi_action_index = 0; /* Generate the keys */ - snprintf(key_value, sizeof(key_value), "filter_r%x", index); - key_value[sizeof(key_value) - 1] = '\0'; - snprintf(key_name, sizeof(key_name), "filter_n%x", index); - key_name[sizeof(key_name) - 1] = '\0'; + snprintf(key_value, sizeof(key_value), "filter_r%x", filter_identifier); + key_value[sizeof(key_value) - 1] = '\0'; /* XXX: Why? */ + snprintf(key_name, sizeof(key_name), "filter_n%x", filter_identifier); + key_name[sizeof(key_name) - 1] = '\0'; /* XXX: Why? */ + snprintf(key_type, sizeof(key_type), "filter_t%x", filter_identifier); err = get_string_param(parameters, key_name, &name); if (err) break; @@ -3341,26 +3455,45 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, break; } + type = get_char_param(parameters, key_type); + switch (type) + { + case 'F': + multi_action_index = ACTION_MULTI_FILTER; + break; + case 'S': + multi_action_index = ACTION_MULTI_SERVER_HEADER_FILTER; + break; + case 'C': + multi_action_index = ACTION_MULTI_CLIENT_HEADER_FILTER; + break; + default: + log_error(LOG_LEVEL_ERROR, + "Unknown filter type: %c for filter %s. Filter ignored.", type, name); + continue; + } + assert(multi_action_index); + value = get_char_param(parameters, key_value); if (value == 'Y') { - list_remove_item(cur_line->data.action->multi_add[ACTION_MULTI_FILTER], name); - if (!err) err = enlist(cur_line->data.action->multi_add[ACTION_MULTI_FILTER], name); - list_remove_item(cur_line->data.action->multi_remove[ACTION_MULTI_FILTER], name); + list_remove_item(cur_line->data.action->multi_add[multi_action_index], name); + if (!err) err = enlist(cur_line->data.action->multi_add[multi_action_index], name); + list_remove_item(cur_line->data.action->multi_remove[multi_action_index], name); } else if (value == 'N') { - list_remove_item(cur_line->data.action->multi_add[ACTION_MULTI_FILTER], name); - if (!cur_line->data.action->multi_remove_all[ACTION_MULTI_FILTER]) + list_remove_item(cur_line->data.action->multi_add[multi_action_index], name); + if (!cur_line->data.action->multi_remove_all[multi_action_index]) { - list_remove_item(cur_line->data.action->multi_remove[ACTION_MULTI_FILTER], name); - if (!err) err = enlist(cur_line->data.action->multi_remove[ACTION_MULTI_FILTER], name); + list_remove_item(cur_line->data.action->multi_remove[multi_action_index], name); + if (!err) err = enlist(cur_line->data.action->multi_remove[multi_action_index], name); } } else if (value == 'X') { - list_remove_item(cur_line->data.action->multi_add[ACTION_MULTI_FILTER], name); - list_remove_item(cur_line->data.action->multi_remove[ACTION_MULTI_FILTER], name); + list_remove_item(cur_line->data.action->multi_add[multi_action_index], name); + list_remove_item(cur_line->data.action->multi_remove[multi_action_index], name); } } @@ -3412,13 +3545,13 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, if (err == JB_ERR_FILE) { /* Read-only file. */ - err = cgi_error_file_read_only(csp, rsp, file->identifier); + err = cgi_error_file_read_only(csp, rsp, file->filename); } edit_free_file(file); return err; } - snprintf(target, 1024, CGI_PREFIX "edit-actions-list?foo=%lu&f=%s#l%d", + snprintf(target, sizeof(target), CGI_PREFIX "edit-actions-list?foo=%lu&f=%i#l%d", (long) time(NULL), file->identifier, sectionid); edit_free_file(file); @@ -3533,13 +3666,13 @@ jb_err cgi_edit_actions_url(struct client_state *csp, if (err == JB_ERR_FILE) { /* Read-only file. */ - err = cgi_error_file_read_only(csp, rsp, file->identifier); + err = cgi_error_file_read_only(csp, rsp, file->filename); } edit_free_file(file); return err; } - snprintf(target, 1024, CGI_PREFIX "edit-actions-list?foo=%lu&f=%s#l%d", + snprintf(target, sizeof(target), CGI_PREFIX "edit-actions-list?foo=%lu&f=%i#l%d", (long) time(NULL), file->identifier, section_start_line_number); edit_free_file(file); @@ -3662,13 +3795,13 @@ jb_err cgi_edit_actions_add_url(struct client_state *csp, if (err == JB_ERR_FILE) { /* Read-only file. */ - err = cgi_error_file_read_only(csp, rsp, file->identifier); + err = cgi_error_file_read_only(csp, rsp, file->filename); } edit_free_file(file); return err; } - snprintf(target, 1024, CGI_PREFIX "edit-actions-list?foo=%lu&f=%s#l%d", + snprintf(target, sizeof(target), CGI_PREFIX "edit-actions-list?foo=%lu&f=%i#l%d", (long) time(NULL), file->identifier, sectionid); edit_free_file(file); @@ -3773,13 +3906,13 @@ jb_err cgi_edit_actions_remove_url(struct client_state *csp, if (err == JB_ERR_FILE) { /* Read-only file. */ - err = cgi_error_file_read_only(csp, rsp, file->identifier); + err = cgi_error_file_read_only(csp, rsp, file->filename); } edit_free_file(file); return err; } - snprintf(target, 1024, CGI_PREFIX "edit-actions-list?foo=%lu&f=%s#l%d", + snprintf(target, sizeof(target), CGI_PREFIX "edit-actions-list?foo=%lu&f=%i#l%d", (long) time(NULL), file->identifier, section_start_line_number); edit_free_file(file); @@ -3895,13 +4028,13 @@ jb_err cgi_edit_actions_section_remove(struct client_state *csp, if (err == JB_ERR_FILE) { /* Read-only file. */ - err = cgi_error_file_read_only(csp, rsp, file->identifier); + err = cgi_error_file_read_only(csp, rsp, file->filename); } edit_free_file(file); return err; } - snprintf(target, 1024, CGI_PREFIX "edit-actions-list?foo=%lu&f=%s", + snprintf(target, sizeof(target), CGI_PREFIX "edit-actions-list?foo=%lu&f=%i", (long) time(NULL), file->identifier); edit_free_file(file); @@ -4064,13 +4197,13 @@ jb_err cgi_edit_actions_section_add(struct client_state *csp, if (err == JB_ERR_FILE) { /* Read-only file. */ - err = cgi_error_file_read_only(csp, rsp, file->identifier); + err = cgi_error_file_read_only(csp, rsp, file->filename); } edit_free_file(file); return err; } - snprintf(target, 1024, CGI_PREFIX "edit-actions-list?foo=%lu&f=%s", + snprintf(target, sizeof(target), CGI_PREFIX "edit-actions-list?foo=%lu&f=%i", (long) time(NULL), file->identifier); edit_free_file(file); @@ -4252,14 +4385,14 @@ jb_err cgi_edit_actions_section_swap(struct client_state *csp, if (err == JB_ERR_FILE) { /* Read-only file. */ - err = cgi_error_file_read_only(csp, rsp, file->identifier); + err = cgi_error_file_read_only(csp, rsp, file->filename); } edit_free_file(file); return err; } } /* END if (section1 != section2) */ - snprintf(target, 1024, CGI_PREFIX "edit-actions-list?foo=%lu&f=%s", + snprintf(target, sizeof(target), CGI_PREFIX "edit-actions-list?foo=%lu&f=%i", (long) time(NULL), file->identifier); edit_free_file(file);