-const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.37 2002/04/30 11:14:52 oes Exp $";
+const char cgiedit_rcs[] = "$Id: cgiedit.c,v 1.43 2006/07/18 14:48:45 david__schmidt Exp $";
/*********************************************************************
*
* File : $Source: /cvsroot/ijbswa/current/cgiedit.c,v $
*
* Revisions :
* $Log: cgiedit.c,v $
+ * Revision 1.43 2006/07/18 14:48:45 david__schmidt
+ * Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
+ * with what was really the latest development (the v_3_0_branch branch)
+ *
+ * Revision 1.41.2.12 2006/01/30 15:16:25 david__schmidt
+ * Remove a little residual debugging info
+ *
+ * Revision 1.41.2.11 2006/01/29 23:10:56 david__schmidt
+ * Multiple filter file support
+ *
+ * Revision 1.41.2.10 2005/07/04 03:13:43 david__schmidt
+ * Undo some damaging memory leak patches
+ *
+ * Revision 1.41.2.9 2005/07/04 00:31:04 david__schmidt
+ * Removing a double free
+ *
+ * Revision 1.41.2.8 2005/05/07 21:50:54 david__schmidt
+ * A few memory leaks plugged (mostly on error paths)
+ *
+ * Revision 1.41.2.7 2004/02/17 13:30:23 oes
+ * Moved cgi_error_disabled() from cgiedit.c to
+ * cgi.c to re-enable build with --disable-editor.
+ * Fixes Bug #892744. Thanks to Matthew Fischer
+ * for spotting.
+ *
+ * Revision 1.41.2.6 2003/12/18 08:13:48 oes
+ * One line lost in last commit
+ *
+ * Revision 1.41.2.5 2003/12/17 16:33:47 oes
+ * - All edit functions that redirect back to the list page
+ * now use cgi_redirect
+ * - All redirects now contain useless parameter "foo", whose
+ * value are raw seconds since epoch, in order to force
+ * Opera and Konqueror to properly reload the list. Closes
+ * bug #859993
+ *
+ * Revision 1.41.2.4 2003/03/11 11:53:59 oes
+ * Cosmetic: Renamed cryptic variable
+ *
+ * Revision 1.41.2.3 2002/11/12 15:01:41 oes
+ * Fix: Don't free uninitialized struct editable_file
+ *
+ * Revision 1.41.2.2 2002/08/05 20:02:59 oes
+ * Bugfix: "Insert new section at top" did not work properly if first non-comment line in file was of type FILE_LINE_ACTION
+ *
+ * Revision 1.41.2.1 2002/08/02 12:43:14 oes
+ * Fixed bug #588514: first_time now set on a per-string basis in actions_from_radio; javascriptify now called on copies
+ *
+ * Revision 1.41 2002/05/21 19:09:45 oes
+ * - Made Add/Edit/Remove URL Submit and Cancel
+ * buttons jump back to relevant section in eal
+ * - Bugfix: remove-url-form needs p export
+ *
+ * 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
*
#include "miscutil.h"
#include "errlog.h"
#include "loaders.h"
+#ifdef FEATURE_TOGGLE
+/* loadcfg.h is for global_toggle_state only */
#include "loadcfg.h"
-/* loadcfg.h is for g_bToggleIJB only */
+#endif /* def FEATURE_TOGGLE */
#include "urlmatch.h"
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.
*/
} 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 */
jb_err cgi_error_file(struct client_state *csp,
struct http_response *rsp,
const char *filename);
-jb_err cgi_error_disabled(struct client_state *csp,
- struct http_response *rsp);
+jb_err cgi_error_file_read_only(struct client_state *csp,
+ struct http_response *rsp,
+ const char *filename);
/* Internal arbitrary config file support functions */
static jb_err edit_read_file_lines(FILE *fp, struct file_line ** pfile, int *newline);
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<n>, 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
struct editable_file * file;
struct file_line * cur_line;
unsigned line_number;
+ unsigned section_start_line_number = 0;
jb_err err;
assert(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;
}
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);
struct editable_file * file;
struct file_line * cur_line;
unsigned line_number;
+ unsigned section_start_line_number = 0;
jb_err err;
assert(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;
}
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);
* 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.
* 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
* 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
/*********************************************************************
*
- * Function : cgi_error_disabled
+ * Function : cgi_error_file
*
- * Description : CGI function that is called if the actions editor
- * is called although it's disabled in config
+ * 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
*
* JB_ERR_MEMORY on out-of-memory error.
*
*********************************************************************/
-jb_err cgi_error_disabled(struct client_state *csp,
- struct http_response *rsp)
+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;
}
- return template_fill_for_cgi(csp, "cgi-error-disabled", exports, rsp);
+ 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);
}
}
/* FIXME: Incomplete */
- 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=default"))
- {
- free(rsp->status);
- rsp->status = NULL;
- return JB_ERR_MEMORY;
- }
- return JB_ERR_OK;
+ return cgi_redirect(rsp, CGI_PREFIX "edit-actions-list?f=default");
+
}
if (NULL == (exports = default_exports(csp, NULL)))
{
- edit_free_file(file);
return JB_ERR_MEMORY;
}
}
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))
{
/* Could also do section-specific exports here, but it wouldn't be as fast */
+ snprintf(buf, 150, "%d", line_number);
+ if (!err) err = map(section_exports, "s-next", 1, buf, 1);
+
if ( (cur_line != NULL)
&& (cur_line->type == FILE_LINE_ACTION))
{
/* Not last section */
- 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");
}
else
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))
{
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)
{
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 */
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)
+ if ((csp->rlist[i] != NULL) && (csp->rlist[i]->f != NULL))
{
- current_mode = 'y';
- }
- else
- {
- 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];
+
+ 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;
+ }
- /* Generate a unique serial number */
- snprintf(number, sizeof(number), "%x", index++);
- number[sizeof(number) - 1] = '\0';
+ if (filter_name != NULL)
+ {
+ current_mode = 'y';
+ }
+ else
+ {
+ 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)
+ {
+ current_mode = 'n';
+ }
+ }
- 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);
+ /* Generate a unique serial number */
+ snprintf(number, sizeof(number), "%x", index++);
+ number[sizeof(number) - 1] = '\0';
- 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);
+ 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);
+ free_map(line_exports);
+ }
+ }
}
}
-
freez(filter_template);
if (!err)
struct editable_file * file;
struct file_line * cur_line;
unsigned line_number;
- char * target;
+ char target[1024];
jb_err err;
int index;
const char * action_set_name;
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))
{
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);
+ snprintf(target, 1024, CGI_PREFIX "edit-actions-list?foo=%lu&f=%s#l%d",
+ (long) time(NULL), file->identifier, sectionid);
edit_free_file(file);
- if (target == NULL)
- {
- /* Out of memory */
- return JB_ERR_MEMORY;
- }
-
- rsp->status = strdup("302 Local Redirect from Privoxy");
- if (rsp->status == NULL)
- {
- free(target);
- return JB_ERR_MEMORY;
- }
- err = enlist_unique_header(rsp->headers, "Location", target);
- free(target);
-
- return err;
+ return cgi_redirect(rsp, target);
}
struct editable_file * file;
struct file_line * cur_line;
unsigned line_number;
- char * target;
+ unsigned section_start_line_number = 0;
+ char target[1024];
jb_err err;
+ assert(csp);
+ assert(rsp);
+ assert(parameters);
+
if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
{
return cgi_error_disabled(csp, rsp);
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++;
}
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);
+ snprintf(target, 1024, CGI_PREFIX "edit-actions-list?foo=%lu&f=%s#l%d",
+ (long) time(NULL), file->identifier, section_start_line_number);
edit_free_file(file);
- if (target == NULL)
- {
- /* Out of memory */
- return JB_ERR_MEMORY;
- }
-
- rsp->status = strdup("302 Local Redirect from Privoxy");
- if (rsp->status == NULL)
- {
- free(target);
- return JB_ERR_MEMORY;
- }
- err = enlist_unique_header(rsp->headers, "Location", target);
- free(target);
-
- return err;
+ return cgi_redirect(rsp, target);
}
struct editable_file * file;
struct file_line * cur_line;
unsigned line_number;
- char * target;
+ char target[1024];
jb_err err;
if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
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);
+ snprintf(target, 1024, CGI_PREFIX "edit-actions-list?foo=%lu&f=%s#l%d",
+ (long) time(NULL), file->identifier, sectionid);
edit_free_file(file);
- if (target == NULL)
- {
- /* Out of memory */
- return JB_ERR_MEMORY;
- }
-
- rsp->status = strdup("302 Local Redirect from Privoxy");
- if (rsp->status == NULL)
- {
- free(target);
- return JB_ERR_MEMORY;
- }
- err = enlist_unique_header(rsp->headers, "Location", target);
- free(target);
-
- return err;
+ return cgi_redirect(rsp, target);
}
struct file_line * cur_line;
struct file_line * prev_line;
unsigned line_number;
- char * target;
+ unsigned section_start_line_number = 0;
+ char target[1024];
jb_err err;
if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
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++;
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);
+ snprintf(target, 1024, CGI_PREFIX "edit-actions-list?foo=%lu&f=%s#l%d",
+ (long) time(NULL), file->identifier, section_start_line_number);
edit_free_file(file);
- if (target == NULL)
- {
- /* Out of memory */
- return JB_ERR_MEMORY;
- }
-
- rsp->status = strdup("302 Local Redirect from Privoxy");
- if (rsp->status == NULL)
- {
- free(target);
- return JB_ERR_MEMORY;
- }
- err = enlist_unique_header(rsp->headers, "Location", target);
- free(target);
-
- return err;
+ return cgi_redirect(rsp, target);
}
struct file_line * cur_line;
struct file_line * prev_line;
unsigned line_number;
- char * target;
+ char target[1024];
jb_err err;
if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
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);
+ snprintf(target, 1024, CGI_PREFIX "edit-actions-list?foo=%lu&f=%s",
+ (long) time(NULL), file->identifier);
edit_free_file(file);
- if (target == NULL)
- {
- /* Out of memory */
- return JB_ERR_MEMORY;
- }
-
- rsp->status = strdup("302 Local Redirect from Privoxy");
- if (rsp->status == NULL)
- {
- free(target);
- return JB_ERR_MEMORY;
- }
- err = enlist_unique_header(rsp->headers, "Location", target);
- free(target);
-
- return err;
+ return cgi_redirect(rsp, target);
}
struct editable_file * file;
struct file_line * cur_line;
unsigned line_number;
- char * target;
+ char target[1024];
jb_err err;
if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
line_number = 1;
cur_line = file->lines;
- if (sectionid < 1U)
+ if (sectionid <= 1U)
{
/* Add to start of file */
- if (cur_line != NULL)
+ if (cur_line != NULL && cur_line->type != FILE_LINE_ACTION)
{
/* There's something in the file, find the line before the first
* action.
line_number++;
}
}
+ else
+ {
+ /* File starts with action line, so insert at top */
+ cur_line = NULL;
+ }
}
else
{
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);
+ snprintf(target, 1024, CGI_PREFIX "edit-actions-list?foo=%lu&f=%s",
+ (long) time(NULL), file->identifier);
edit_free_file(file);
- if (target == NULL)
- {
- /* Out of memory */
- return JB_ERR_MEMORY;
- }
-
- rsp->status = strdup("302 Local Redirect from Privoxy");
- if (rsp->status == NULL)
- {
- free(target);
- return JB_ERR_MEMORY;
- }
- err = enlist_unique_header(rsp->headers, "Location", target);
- free(target);
-
- return err;
+ return cgi_redirect(rsp, target);
}
struct file_line * line_end_section2;
struct file_line * line_after_section2;
unsigned line_number;
- char * target;
+ char target[1024];
jb_err err;
if (0 == (csp->config->feature_flags & RUNTIME_FEATURE_CGI_EDIT_ACTIONS))
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;
}
} /* END if (section1 != section2) */
- target = strdup(CGI_PREFIX "edit-actions-list?f=");
- string_append(&target, file->identifier);
+ snprintf(target, 1024, CGI_PREFIX "edit-actions-list?foo=%lu&f=%s",
+ (long) time(NULL), file->identifier);
edit_free_file(file);
- if (target == NULL)
- {
- /* Out of memory */
- return JB_ERR_MEMORY;
- }
-
- rsp->status = strdup("302 Local Redirect from Privoxy");
- if (rsp->status == NULL)
- {
- free(target);
- return JB_ERR_MEMORY;
- }
- err = enlist_unique_header(rsp->headers, "Location", target);
- free(target);
-
- return err;
+ return cgi_redirect(rsp, target);
}
-
+#ifdef FEATURE_TOGGLE
/*********************************************************************
*
* Function : cgi_toggle
if (mode == 'E')
{
/* Enable */
- g_bToggleIJB = 1;
+ global_toggle_state = 1;
}
else if (mode == 'D')
{
/* Disable */
- g_bToggleIJB = 0;
+ global_toggle_state = 0;
}
else if (mode == 'T')
{
/* Toggle */
- g_bToggleIJB = !g_bToggleIJB;
+ global_toggle_state = !global_toggle_state;
}
if (NULL == (exports = default_exports(csp, "toggle")))
return template_fill_for_cgi(csp, template_name, exports, rsp);
}
-
+#endif /* def FEATURE_TOGGLE */
/*********************************************************************
*
static jb_err actions_from_radio(const struct map * parameters,
struct action_spec *action)
{
- static int first_time = 1;
const char * param;
char * param_dup;
char ch;
* but in this case we're safe and don't need semaphores.
* Be careful if you modify this function.
* - Jon
+ * The js_name_arr's are never free()d, but this is no
+ * problem, since they will only be created once and
+ * used by all threads thereafter. -oes
*/
#define JAVASCRIPTIFY(dest_var, string) \
{ \
- static char js_name_arr[] = string; \
+ static int first_time = 1; \
+ static char *js_name_arr; \
if (first_time) \
{ \
+ js_name_arr = strdup(string); \
javascriptify(js_name_arr); \
} \
dest_var = js_name_arr; \
+ first_time = 0; \
} \
#define DEFINE_ACTION_BOOL(name, bit) \
#undef DEFINE_ACTION_ALIAS
#undef JAVASCRIPTIFY
- first_time = 0;
-
return err;
}