X-Git-Url: http://www.privoxy.org/gitweb/?a=blobdiff_plain;ds=inline;f=actions.c;h=7905231f3ee4c5e3925ed8e5ca861034d35957d1;hb=b9806a317e5ebb2de178414a7622011a406e42ff;hp=5b321145bb344d6f1b20bdf044443f2278f8c43e;hpb=e6a771dacfb7cce3e202e06cb46612cf5d35d920;p=privoxy.git
diff --git a/actions.c b/actions.c
index 5b321145..7905231f 100644
--- a/actions.c
+++ b/actions.c
@@ -1,13 +1,11 @@
-const char actions_rcs[] = "$Id: actions.c,v 1.62 2011/02/14 16:01:20 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-2011 the
- * Privoxy team. http://www.privoxy.org/
+ * Copyright : Written by and Copyright (C) 2001-2016 the
+ * Privoxy team. https://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
* by and Copyright (C) 1997 Anonymous Coders and
@@ -56,9 +54,7 @@ const char actions_rcs[] = "$Id: actions.c,v 1.62 2011/02/14 16:01:20 fabiankeil
#include "urlmatch.h"
#include "cgi.h"
#include "ssplit.h"
-
-const char actions_h_rcs[] = ACTIONS_H_VERSION;
-
+#include "filters.h"
/*
* We need the main list of options.
@@ -70,11 +66,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 +81,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[] */
};
/*
@@ -122,7 +120,10 @@ static const struct action_name action_names[] =
};
-static int load_one_actions_file(struct client_state *csp, int fileid);
+#ifndef FUZZ
+static
+#endif
+int load_one_actions_file(struct client_state *csp, int fileid);
/*********************************************************************
@@ -155,11 +156,7 @@ jb_err merge_actions (struct action_spec *dest,
if (str)
{
freez(dest->string[i]);
- dest->string[i] = strdup(str);
- if (NULL == dest->string[i])
- {
- return JB_ERR_MEMORY;
- }
+ dest->string[i] = strdup_or_die(str);
}
}
@@ -211,7 +208,7 @@ jb_err merge_actions (struct action_spec *dest,
* 1 : dest = Destination of copy.
* 2 : src = Source for copy.
*
- * Returns : N/A
+ * Returns : JB_ERR_OK or JB_ERR_MEMORY
*
*********************************************************************/
jb_err copy_action (struct action_spec *dest,
@@ -231,11 +228,7 @@ jb_err copy_action (struct action_spec *dest,
char * str = src->string[i];
if (str)
{
- str = strdup(str);
- if (!str)
- {
- return JB_ERR_MEMORY;
- }
+ str = strdup_or_die(str);
dest->string[i] = str;
}
}
@@ -319,7 +312,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:
@@ -402,7 +395,17 @@ jb_err get_action_token(char **line, char **name, char **value)
str++;
*value = str;
- str = strchr(str, '}');
+ /* The value ends with the first non-escaped closing curly brace */
+ while ((str = strchr(str, '}')) != NULL)
+ {
+ if (str[-1] == '\\')
+ {
+ /* Overwrite the '\' so the action doesn't see it. */
+ string_move(str-1, str);
+ continue;
+ }
+ break;
+ }
if (str == NULL)
{
/* error */
@@ -434,7 +437,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 +503,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,10 +514,16 @@ 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. */
+ if (value != NULL)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Action %s does not take parameters but %s was given.",
+ action->name, value);
+ return JB_ERR_PARSE;
+ }
break;
case AV_ADD_STRING:
{
@@ -538,6 +547,12 @@ jb_err get_actions(char *line,
return JB_ERR_PARSE;
}
}
+#ifdef FEATURE_EXTENDED_STATISTICS
+ if (0 == strcmpic(action->name, "+block"))
+ {
+ register_block_reason_for_statistics(value);
+ }
+#endif
/* FIXME: should validate option string here */
freez (cur_action->string[action->index]);
cur_action->string[action->index] = strdup(value);
@@ -581,8 +596,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 +612,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 +636,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;
}
@@ -738,11 +753,7 @@ jb_err merge_current_action (struct current_action_spec *dest,
char * str = src->string[i];
if (str)
{
- str = strdup(str);
- if (!str)
- {
- return JB_ERR_MEMORY;
- }
+ str = strdup_or_die(str);
freez(dest->string[i]);
dest->string[i] = str;
}
@@ -772,36 +783,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
/*********************************************************************
*
@@ -841,14 +822,14 @@ int update_action_bits_for_tag(struct client_state *csp, const char *tag)
/* and through all the action patterns, */
for (b = b->next; NULL != b; b = b->next)
{
- /* skip the URL patterns, */
- if (NULL == b->url->tag_regex)
+ /* skip everything but TAG patterns, */
+ if (!(b->url->flags & PATTERN_SPEC_TAG_PATTERN))
{
continue;
}
/* and check if one of the tag patterns matches the tag, */
- if (0 == regexec(b->url->tag_regex, tag, 0, NULL, 0))
+ if (0 == regexec(b->url->pattern.tag_regex, tag, 0, NULL, 0))
{
/* if it does, update the action bit map, */
if (merge_current_action(csp->action, b->action))
@@ -866,6 +847,76 @@ int update_action_bits_for_tag(struct client_state *csp, const char *tag)
}
+/*********************************************************************
+ *
+ * Function : check_negative_tag_patterns
+ *
+ * Description : Updates the action bits based on NO-*-TAG patterns.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : flag = The tag pattern type
+ *
+ * Returns : JB_ERR_OK in case off success, or
+ * JB_ERR_MEMORY on out-of-memory error.
+ *
+ *********************************************************************/
+jb_err check_negative_tag_patterns(struct client_state *csp, unsigned int flag)
+{
+ struct list_entry *tag;
+ struct file_list *fl;
+ struct url_actions *b = NULL;
+ int i;
+
+ for (i = 0; i < MAX_AF_FILES; i++)
+ {
+ fl = csp->actions_list[i];
+ if ((fl == NULL) || ((b = fl->f) == NULL))
+ {
+ continue;
+ }
+ for (b = b->next; NULL != b; b = b->next)
+ {
+ int tag_found = 0;
+ if (0 == (b->url->flags & flag))
+ {
+ continue;
+ }
+ for (tag = csp->tags->first; NULL != tag; tag = tag->next)
+ {
+ if (0 == regexec(b->url->pattern.tag_regex, tag->str, 0, NULL, 0))
+ {
+ /*
+ * The pattern matches at least one tag, thus the action
+ * section doesn't apply and we don't need to look at the
+ * other tags.
+ */
+ tag_found = 1;
+ break;
+ }
+ }
+ if (!tag_found)
+ {
+ /*
+ * The pattern doesn't match any tags,
+ * thus the action section applies.
+ */
+ if (merge_current_action(csp->action, b->action))
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Out of memory while changing action bits");
+ return JB_ERR_MEMORY;
+ }
+ log_error(LOG_LEVEL_HEADER, "Updated action bits based on: %s",
+ b->url->spec);
+ }
+ }
+ }
+
+ return JB_ERR_OK;
+}
+
+
/*********************************************************************
*
* Function : free_current_action
@@ -952,7 +1003,7 @@ void unload_actions_file(void *file_data)
while (cur != NULL)
{
next = cur->next;
- free_url_spec(cur->url);
+ free_pattern_spec(cur->url);
if ((next == NULL) || (next->action != cur->action))
{
/*
@@ -1033,6 +1084,125 @@ int load_action_files(struct client_state *csp)
return 0;
}
+
+/*********************************************************************
+ *
+ * Function : filter_type_to_string
+ *
+ * Description : Converts a filter type enum into a string.
+ *
+ * Parameters :
+ * 1 : filter_type = filter_type as enum
+ *
+ * Returns : Pointer to static string.
+ *
+ *********************************************************************/
+static const char *filter_type_to_string(enum filter_type filter_type)
+{
+ switch (filter_type)
+ {
+ case FT_CONTENT_FILTER:
+ return "content filter";
+ case FT_CLIENT_HEADER_FILTER:
+ return "client-header filter";
+ case FT_SERVER_HEADER_FILTER:
+ return "server-header filter";
+ case FT_CLIENT_HEADER_TAGGER:
+ return "client-header tagger";
+ case FT_SERVER_HEADER_TAGGER:
+ return "server-header tagger";
+#ifdef FEATURE_EXTERNAL_FILTERS
+ case FT_EXTERNAL_CONTENT_FILTER:
+ return "external content filter";
+#endif
+ case FT_SUPPRESS_TAG:
+ return "suppress tag filter";
+ case FT_INVALID_FILTER:
+ return "invalid filter type";
+ }
+
+ return "unknown filter type";
+
+}
+
+/*********************************************************************
+ *
+ * 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 exist, 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)
+{
+ struct list_entry *filtername;
+
+ for (filtername = cur_action->multi_add[multi_index]->first;
+ filtername; filtername = filtername->next)
+ {
+ if (NULL == get_filter(csp, filtername->str, filter_type))
+ {
+ log_error(LOG_LEVEL_ERROR, "Missing %s '%s'",
+ filter_type_to_string(filter_type), 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
@@ -1047,7 +1217,10 @@ int load_action_files(struct client_state *csp)
* Returns : 0 => Ok, everything else is an error.
*
*********************************************************************/
-static int load_one_actions_file(struct client_state *csp, int fileid)
+#ifndef FUZZ
+static
+#endif
+int load_one_actions_file(struct client_state *csp, int fileid)
{
/*
@@ -1088,13 +1261,7 @@ static int load_one_actions_file(struct client_state *csp, int fileid)
return 1; /* never get here */
}
- fs->f = last_perm = (struct url_actions *)zalloc(sizeof(*last_perm));
- if (last_perm == NULL)
- {
- log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': out of memory!",
- csp->config->actions_file[fileid]);
- return 1; /* never get here */
- }
+ fs->f = last_perm = zalloc_or_die(sizeof(*last_perm));
if ((fp = fopen(csp->config->actions_file[fileid], "r")) == NULL)
{
@@ -1121,7 +1288,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 */
}
@@ -1222,7 +1389,7 @@ 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 */
@@ -1238,28 +1405,31 @@ static int load_one_actions_file(struct client_state *csp, int fileid)
cur_action = NULL;
}
cur_action_used = 0;
- cur_action = (struct action_spec *)zalloc(sizeof(*cur_action));
- if (cur_action == 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 */
- }
+ cur_action = zalloc_or_die(sizeof(*cur_action));
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 = end = strdup_or_die(buf + 1);
/* check we have a trailing } and then trim it */
- end = actions_buf + strlen(actions_buf) - 1;
+ if (strlen(actions_buf))
+ {
+ end += strlen(actions_buf) - 1;
+ }
if (*end != '}')
{
/* 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 */
}
@@ -1272,11 +1442,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)
@@ -1292,16 +1472,9 @@ static int load_one_actions_file(struct client_state *csp, int fileid)
char *version_string, *fields[3];
int num_fields;
- if ((version_string = strdup(buf + 20)) == 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 */
- }
-
- num_fields = ssplit(version_string, ".", fields, 3, TRUE, FALSE);
+ version_string = strdup_or_die(buf + 20);
+
+ num_fields = ssplit(version_string, ".", fields, SZ(fields));
if (num_fields < 1 || atoi(fields[0]) == 0)
{
@@ -1309,14 +1482,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);
@@ -1348,14 +1521,7 @@ static int load_one_actions_file(struct client_state *csp, int fileid)
return 1; /* never get here */
}
- if ((new_alias = zalloc(sizeof(*new_alias))) == 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 */
- }
+ new_alias = zalloc_or_die(sizeof(*new_alias));
/* Eat any the whitespace before the '=' */
end--;
@@ -1383,14 +1549,7 @@ static int load_one_actions_file(struct client_state *csp, int fileid)
return 1; /* never get here */
}
- if ((new_alias->name = strdup(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 */
- }
+ new_alias->name = strdup_or_die(buf);
strlcpy(actions_buf, start, sizeof(actions_buf));
@@ -1413,24 +1572,17 @@ static int load_one_actions_file(struct client_state *csp, int fileid)
/* it's an URL pattern */
/* allocate a new node */
- if ((perm = zalloc(sizeof(*perm))) == 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 */
- }
+ perm = zalloc_or_die(sizeof(*perm));
perm->action = cur_action;
cur_action_used = 1;
/* Save the URL pattern */
- if (create_url_spec(perm->url, buf))
+ if (create_pattern_spec(perm->url, buf))
{
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 */
}
@@ -1444,7 +1596,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 */
}
@@ -1491,7 +1643,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.
@@ -1504,7 +1656,7 @@ char * actions_to_text(const struct action_spec *action)
{
unsigned long mask = action->mask;
unsigned long add = action->add;
- char *result = strdup("");
+ char *result = strdup_or_die("");
struct list_entry * lst;
/* sanity - prevents "-feature +feature" */
@@ -1576,7 +1728,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.
*
@@ -1593,7 +1745,7 @@ char * actions_to_html(const struct client_state *csp,
{
unsigned long mask = action->mask;
unsigned long add = action->add;
- char *result = strdup("");
+ char *result = strdup_or_die("");
struct list_entry * lst;
/* sanity - prevents "-feature +feature" */
@@ -1682,12 +1834,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 current 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.
@@ -1699,9 +1851,9 @@ char *current_action_to_html(const struct client_state *csp,
{
unsigned long flags = action->flags;
struct list_entry * lst;
- char *result = strdup("");
- char *active = strdup("");
- char *inactive = strdup("");
+ char *result = strdup_or_die("");
+ char *active = strdup_or_die("");
+ char *inactive = strdup_or_die("");
#define DEFINE_ACTION_BOOL(__name, __bit) \
if (flags & __bit) \
@@ -1772,3 +1924,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;
+}