X-Git-Url: http://www.privoxy.org/gitweb/?p=privoxy.git;a=blobdiff_plain;f=cgiedit.c;h=0f0e46d31de3ab965ad02bfd7499f12e88e146ce;hp=fac1af9fd0aa807172cd884fe6f0a3d2a84657f7;hb=6936b62866a15b4f9da85854060f5d81c986631c;hpb=09879c3aa1c93b8da14d7d2ef91550a2cdd95f04 diff --git a/cgiedit.c b/cgiedit.c index fac1af9f..0f0e46d3 100644 --- a/cgiedit.c +++ b/cgiedit.c @@ -1,4 +1,4 @@ -const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.33 2002/04/24 02:17:47 oes Exp $"; +const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.40 2002/05/19 11:34:35 jongfoster Exp $"; /********************************************************************* * * File : $Source: /cvsroot/ijbswa/current/cgiedit.c,v $ @@ -42,6 +42,34 @@ const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.33 2002/04/24 02:17:47 oes Exp $" * * Revisions : * $Log: cgiedit.c,v $ + * Revision 1.40 2002/05/19 11:34:35 jongfoster + * Handling read-only actions files better - report the actual + * error, not "Out of memory"! + * + * Bug report: + * http://sourceforge.net/tracker/index.php?func=detail + * &aid=557905&group_id=11118&atid=111118 + * + * Revision 1.39 2002/05/12 21:39:15 jongfoster + * - Adding Doxygen-style comments to structures and #defines. + * - Correcting function comments + * + * Revision 1.38 2002/05/03 23:00:38 jongfoster + * Support for templates for "standard actions" buttons. + * See bug #549871 + * + * Revision 1.37 2002/04/30 11:14:52 oes + * Made csp the first parameter in *action_to_html + * + * Revision 1.36 2002/04/26 21:53:30 jongfoster + * Fixing a memory leak. (Near, but not caused by, my earlier commit). + * + * Revision 1.35 2002/04/26 21:50:02 jongfoster + * Honouring default exports in edit-actions-for-url-filter template. + * + * Revision 1.34 2002/04/26 12:54:17 oes + * Adaptions to changes in actions.c + * * Revision 1.33 2002/04/24 02:17:47 oes * - Moved get_char_param, get_string_param and get_number_param to cgi.c * - Comments @@ -261,23 +289,49 @@ const char cgiedit_h_rcs[] = CGIEDIT_H_VERSION; #ifdef FEATURE_CGI_EDIT_ACTIONS +/** + * A line in an editable_file. + */ struct file_line { + /** Next entry in the linked list */ struct file_line * next; + + /** The raw data, to write out if this line is unmodified. */ char * raw; + + /** Comments and/or whitespace to put before this line if it's modified + and then written out. */ char * prefix; + + /** The actual data, as a string. Line continuation and comment removal + are performed on the data read from file before it's stored here, so + it will be a single line of data. */ char * unprocessed; + + /** The type of data on this line. One of the FILE_LINE_xxx constants. */ int type; + /** The actual data, processed into some sensible data type. */ union { + + /** An action specification. */ struct action_spec action[1]; + /** A name=value pair. */ struct { + + /** The name in the name=value pair. */ char * name; + + /** The value in the name=value pair, as a string. */ char * svalue; + + /** The value in the name=value pair, as an integer. */ int ivalue; + } setting; /* Add more data types here... e.g. @@ -294,42 +348,65 @@ struct file_line */ } data; + }; +/** This file_line has not been processed yet. */ #define FILE_LINE_UNPROCESSED 1 + +/** This file_line is blank. Can only appear at the end of a file, due to + the way the parser works. */ #define FILE_LINE_BLANK 2 + +/** This file_line says {{alias}}. */ #define FILE_LINE_ALIAS_HEADER 3 + +/** This file_line defines an alias. */ #define FILE_LINE_ALIAS_ENTRY 4 + +/** This file_line defines an {action}. */ #define FILE_LINE_ACTION 5 + +/** This file_line specifies a URL pattern. */ #define FILE_LINE_URL 6 + +/** This file_line says {{settings}}. */ #define FILE_LINE_SETTINGS_HEADER 7 + +/** This file_line is in a {{settings}} block. */ #define FILE_LINE_SETTINGS_ENTRY 8 + +/** This file_line says {{description}}. */ #define FILE_LINE_DESCRIPTION_HEADER 9 + +/** This file_line is in a {{description}} block. */ #define FILE_LINE_DESCRIPTION_ENTRY 10 +/** + * A configuration file, in a format that can be edited and written back to + * disk. + */ struct editable_file { - struct file_line * 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. */ - 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 - * the browser's "back" button. Note that this is a - * time_t cast to an unsigned. When comparing, always - * cast the time_t to an unsigned, and *NOT* vice-versa. - * This may lose the top few bits, but they're not - * significant anyway. - */ - int newline; /* Newline convention - one of the NEWLINE_xxx constants. - * Note that changing this after the file has been - * read in will cause a mess. - */ - struct file_line * parse_error; /* On parse error, this is the offending line. */ - const char * parse_error_text; /* On parse error, this is the problem. - * (Statically allocated) */ + 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. */ + 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 + the browser's "back" button. Note that this is a + time_t cast to an unsigned. When comparing, always + cast the time_t to an unsigned, and *NOT* vice-versa. + This may lose the top few bits, but they're not + significant anyway. */ + int newline; /**< Newline convention - one of the NEWLINE_xxx constants. + Note that changing this after the file has been + read in will cause a mess. */ + struct file_line * parse_error; /**< On parse error, this is the offending line. */ + const char * parse_error_text; /**< On parse error, this is the problem. + (Statically allocated) */ }; /* FIXME: Following non-static functions should be prototyped in .h or made static */ @@ -361,6 +438,9 @@ jb_err cgi_error_parse(struct client_state *csp, jb_err cgi_error_file(struct client_state *csp, struct http_response *rsp, const char *filename); +jb_err cgi_error_file_read_only(struct client_state *csp, + struct http_response *rsp, + const char *filename); jb_err cgi_error_disabled(struct client_state *csp, struct http_response *rsp); @@ -406,6 +486,34 @@ static jb_err map_copy_parameter_url(struct map *out, const char *name); #endif /* unused function */ +/* Internal convenience functions */ +static char *section_target(const unsigned sectionid); + +/********************************************************************* + * + * Function : section_target + * + * Description : Given an unsigned (section id) n, produce a dynamically + * allocated string of the form #l, for use in link + * targets. + * + * Parameters : + * 1 : sectionid = start line number of section + * + * Returns : String with link target, or NULL if out of + * memory + * + *********************************************************************/ +static char *section_target(const unsigned sectionid) +{ + char buf[30]; + + snprintf(buf, 30, "#l%d", sectionid); + return(strdup(buf)); + +} + + /********************************************************************* * * Function : map_copy_parameter_html @@ -535,6 +643,7 @@ jb_err cgi_edit_actions_url_form(struct client_state *csp, struct editable_file * file; struct file_line * cur_line; unsigned line_number; + unsigned section_start_line_number = 0; jb_err err; assert(csp); @@ -563,6 +672,10 @@ jb_err cgi_edit_actions_url_form(struct client_state *csp, for (line_number = 1; (cur_line != NULL) && (line_number < patternid); line_number++) { + if (cur_line->type == FILE_LINE_ACTION) + { + section_start_line_number = line_number; + } cur_line = cur_line->next; } @@ -586,6 +699,7 @@ jb_err cgi_edit_actions_url_form(struct client_state *csp, 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); edit_free_file(file); @@ -689,6 +803,7 @@ jb_err cgi_edit_actions_remove_url_form(struct client_state *csp, struct editable_file * file; struct file_line * cur_line; unsigned line_number; + unsigned section_start_line_number = 0; jb_err err; assert(csp); @@ -717,6 +832,10 @@ jb_err cgi_edit_actions_remove_url_form(struct client_state *csp, for (line_number = 1; (cur_line != NULL) && (line_number < patternid); line_number++) { + if (cur_line->type == FILE_LINE_ACTION) + { + section_start_line_number = line_number; + } cur_line = cur_line->next; } @@ -738,8 +857,9 @@ jb_err cgi_edit_actions_remove_url_form(struct client_state *csp, err = map(exports, "f", 1, file->identifier, 1); if (!err) err = map(exports, "v", 1, file->version_str, 1); - if (!err) err = map(exports, "s", 1, url_encode(lookup(parameters, "s")), 0); + 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); edit_free_file(file); @@ -760,8 +880,7 @@ jb_err cgi_edit_actions_remove_url_form(struct client_state *csp, * Description : Write a complete file to disk. * * Parameters : - * 1 : filename = File to write to. - * 2 : file = Data structure to write. + * 1 : file = File to write. * * Returns : JB_ERR_OK on success * JB_ERR_FILE on error writing to file. @@ -1069,8 +1188,8 @@ static int match_actions_file_header_line(const char * line, const char * name) * Parameters : * 1 : line = String from file. Must not start with * whitespace (else infinite loop!) - * 2 : name = Destination for name - * 2 : name = Destination for value + * 2 : pname = Destination for name + * 2 : pvalue = Destination for value * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory @@ -1448,6 +1567,7 @@ jb_err edit_parse_actions_file(struct editable_file * file) * at EOF but it will not have been closed. * 2 : pfile = Destination for a linked list of file_lines. * Will be set to NULL on error. + * 3 : newline = How to handle newlines. * * Returns : JB_ERR_OK on success * JB_ERR_MEMORY on out-of-memory @@ -2213,6 +2333,51 @@ jb_err cgi_error_file(struct client_state *csp, } +/********************************************************************* + * + * Function : cgi_error_file + * + * Description : CGI function that is called when a file cannot be + * opened for writing by the CGI editor. + * + * Parameters : + * 1 : csp = Current client state (buffers, headers, etc...) + * 2 : rsp = http_response data structure for output + * 3 : filename = The file that we can't write to + * + * CGI Parameters : none + * + * Returns : JB_ERR_OK on success + * JB_ERR_MEMORY on out-of-memory error. + * + *********************************************************************/ +jb_err cgi_error_file_read_only(struct client_state *csp, + struct http_response *rsp, + const char *filename) +{ + struct map *exports; + jb_err err; + + assert(csp); + assert(rsp); + assert(filename); + + if (NULL == (exports = default_exports(csp, NULL))) + { + return JB_ERR_MEMORY; + } + + err = map(exports, "f", 1, html_encode(filename), 0); + if (err) + { + free_map(exports); + return err; + } + + return template_fill_for_cgi(csp, "cgi-error-file-read-only", exports, rsp); +} + + /********************************************************************* * * Function : cgi_error_disabled @@ -2384,12 +2549,31 @@ jb_err cgi_edit_actions_list(struct client_state *csp, { /* * Generate string with buttons to set actions for "/" to - * any predefined set of actions (named standard.*, propably + * any predefined set of actions (named standard.*, probably * residing in standard.action). - * FIXME: Shouldn't include hardwired HTML here, use line template instead! */ - buttons = strdup(" "); + err = template_load(csp, §ion_template, "edit-actions-list-button", 0); + if (err) + { + edit_free_file(file); + free_map(exports); + if (err == JB_ERR_FILE) + { + return cgi_error_no_template(csp, rsp, "edit-actions-list-button"); + } + return err; + } + + err = template_fill(§ion_template, exports); + if (err) + { + edit_free_file(file); + free_map(exports); + return err; + } + + buttons = strdup(""); for (i = 0; i < MAX_ACTION_FILES; i++) { if (((fl = csp->actions_list[i]) != NULL) && ((b = fl->f) != NULL)) @@ -2398,27 +2582,49 @@ jb_err cgi_edit_actions_list(struct client_state *csp, { if (!strncmp(b->url->spec, "standard.", 9) && *(b->url->spec + 9) != '\0') { - snprintf(buf, 150, "

Set" - " to %s

", b->url->spec + 9, b->url->spec + 9); - if (!err) err = string_append(&buttons, buf); + if (err || (NULL == (section_exports = new_map()))) + { + freez(buttons); + free(section_template); + edit_free_file(file); + free_map(exports); + return JB_ERR_MEMORY; + } + + err = map(section_exports, "button-name", 1, b->url->spec + 9, 1); + + if (err || (NULL == (s = strdup(section_template)))) + { + free_map(section_exports); + freez(buttons); + free(section_template); + edit_free_file(file); + free_map(exports); + return JB_ERR_MEMORY; + } + + if (!err) err = template_fill(&s, section_exports); + free_map(section_exports); + if (!err) err = string_join(&buttons, s); } } } } + freez(section_template); 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); + if (!err) 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, csp), 0); + actions_to_html(csp, cur_line->data.action), 0); /* Skip the 2 lines */ cur_line = cur_line->next->next; @@ -2438,12 +2644,12 @@ jb_err cgi_edit_actions_list(struct client_state *csp, * Non-standard actions file - does not begin with * the "All URLs" section. */ - err = map_conditional(exports, "all-urls-present", 0); + if (!err) 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, "f", 1, file->identifier, 1); if (!err) err = map(exports, "v", 1, file->version_str, 1); /* Discourage private additions to default.action */ @@ -2529,7 +2735,7 @@ jb_err cgi_edit_actions_list(struct client_state *csp, 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, csp), 0); + actions_to_html(csp, cur_line->data.action), 0); if ( (!err) && (cur_line->next != NULL) @@ -2850,6 +3056,8 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, return err; } + err = template_fill(&filter_template, exports); + result = strdup(""); for (;(!err) && (filter_group != NULL); filter_group = filter_group->next) @@ -2914,6 +3122,9 @@ jb_err cgi_edit_actions_for_url(struct client_state *csp, free_map(line_exports); } } + + freez(filter_template); + if (!err) { err = map(exports, "filter-params", 1, result, 0); @@ -3148,12 +3359,19 @@ jb_err cgi_edit_actions_submit(struct client_state *csp, if (err) { /* Error writing file */ + if (err == JB_ERR_FILE) + { + /* Read-only file. */ + err = cgi_error_file_read_only(csp, rsp, file->identifier); + } edit_free_file(file); return err; } target = strdup(CGI_PREFIX "edit-actions-list?f="); string_append(&target, file->identifier); + string_join(&target, section_target(sectionid)); + edit_free_file(file); @@ -3210,6 +3428,7 @@ jb_err cgi_edit_actions_url(struct client_state *csp, struct editable_file * file; struct file_line * cur_line; unsigned line_number; + unsigned section_start_line_number = 0; char * target; jb_err err; @@ -3247,6 +3466,10 @@ jb_err cgi_edit_actions_url(struct client_state *csp, while ((cur_line != NULL) && (line_number < patternid)) { + if (cur_line->type == FILE_LINE_ACTION) + { + section_start_line_number = line_number; + } cur_line = cur_line->next; line_number++; } @@ -3270,12 +3493,18 @@ jb_err cgi_edit_actions_url(struct client_state *csp, if (err) { /* Error writing file */ + if (err == JB_ERR_FILE) + { + /* Read-only file. */ + err = cgi_error_file_read_only(csp, rsp, file->identifier); + } edit_free_file(file); return err; } target = strdup(CGI_PREFIX "edit-actions-list?f="); string_append(&target, file->identifier); + string_join(&target, section_target(section_start_line_number)); edit_free_file(file); @@ -3409,12 +3638,18 @@ jb_err cgi_edit_actions_add_url(struct client_state *csp, if (err) { /* Error writing file */ + if (err == JB_ERR_FILE) + { + /* Read-only file. */ + err = cgi_error_file_read_only(csp, rsp, file->identifier); + } edit_free_file(file); return err; } target = strdup(CGI_PREFIX "edit-actions-list?f="); string_append(&target, file->identifier); + string_join(&target, section_target(sectionid)); edit_free_file(file); @@ -3469,6 +3704,7 @@ jb_err cgi_edit_actions_remove_url(struct client_state *csp, struct file_line * cur_line; struct file_line * prev_line; unsigned line_number; + unsigned section_start_line_number = 0; char * target; jb_err err; @@ -3496,6 +3732,10 @@ jb_err cgi_edit_actions_remove_url(struct client_state *csp, while ((cur_line != NULL) && (line_number < patternid)) { + if (cur_line->type == FILE_LINE_ACTION) + { + section_start_line_number = line_number; + } prev_line = cur_line; cur_line = cur_line->next; line_number++; @@ -3525,12 +3765,18 @@ jb_err cgi_edit_actions_remove_url(struct client_state *csp, if (err) { /* Error writing file */ + if (err == JB_ERR_FILE) + { + /* Read-only file. */ + err = cgi_error_file_read_only(csp, rsp, file->identifier); + } edit_free_file(file); return err; } target = strdup(CGI_PREFIX "edit-actions-list?f="); string_append(&target, file->identifier); + string_join(&target, section_target(section_start_line_number)); edit_free_file(file); @@ -3657,6 +3903,11 @@ jb_err cgi_edit_actions_section_remove(struct client_state *csp, if (err) { /* Error writing file */ + if (err == JB_ERR_FILE) + { + /* Read-only file. */ + err = cgi_error_file_read_only(csp, rsp, file->identifier); + } edit_free_file(file); return err; } @@ -3831,6 +4082,11 @@ jb_err cgi_edit_actions_section_add(struct client_state *csp, if (err) { /* Error writing file */ + if (err == JB_ERR_FILE) + { + /* Read-only file. */ + err = cgi_error_file_read_only(csp, rsp, file->identifier); + } edit_free_file(file); return err; } @@ -4029,6 +4285,11 @@ jb_err cgi_edit_actions_section_swap(struct client_state *csp, if (err) { /* Error writing file */ + if (err == JB_ERR_FILE) + { + /* Read-only file. */ + err = cgi_error_file_read_only(csp, rsp, file->identifier); + } edit_free_file(file); return err; }