+ for (i = 0; i < ACTION_STRING_COUNT; i++)
+ {
+ freez(src->string[i]);
+ }
+
+ for (i = 0; i < ACTION_MULTI_COUNT; i++)
+ {
+ destroy_list(src->multi[i]);
+ }
+
+ memset(src, '\0', sizeof(*src));
+}
+
+
+static struct file_list *current_actions_file[MAX_AF_FILES] = {
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL
+};
+
+
+#ifdef FEATURE_GRACEFUL_TERMINATION
+/*********************************************************************
+ *
+ * Function : unload_current_actions_file
+ *
+ * Description : Unloads current actions file - reset to state at
+ * beginning of program.
+ *
+ * Parameters : None
+ *
+ * Returns : N/A
+ *
+ *********************************************************************/
+void unload_current_actions_file(void)
+{
+ int i;
+
+ for (i = 0; i < MAX_AF_FILES; i++)
+ {
+ if (current_actions_file[i])
+ {
+ current_actions_file[i]->unloader = unload_actions_file;
+ current_actions_file[i] = NULL;
+ }
+ }
+}
+#endif /* FEATURE_GRACEFUL_TERMINATION */
+
+
+/*********************************************************************
+ *
+ * Function : unload_actions_file
+ *
+ * Description : Unloads an actions module.
+ *
+ * Parameters :
+ * 1 : file_data = the data structure associated with the
+ * actions file.
+ *
+ * Returns : N/A
+ *
+ *********************************************************************/
+void unload_actions_file(void *file_data)
+{
+ struct url_actions * next;
+ struct url_actions * cur = (struct url_actions *)file_data;
+ while (cur != NULL)
+ {
+ next = cur->next;
+ free_pattern_spec(cur->url);
+ if ((next == NULL) || (next->action != cur->action))
+ {
+ /*
+ * As the action settings might be shared,
+ * we can only free them if the current
+ * url pattern is the last one, or if the
+ * next one is using different settings.
+ */
+ free_action_spec(cur->action);
+ }
+ freez(cur);
+ cur = next;
+ }
+}
+
+
+/*********************************************************************
+ *
+ * Function : free_alias_list
+ *
+ * Description : Free memory used by a list of aliases.
+ *
+ * Parameters :
+ * 1 : alias_list = Linked list to free.
+ *
+ * Returns : N/A
+ *
+ *********************************************************************/
+void free_alias_list(struct action_alias *alias_list)
+{
+ while (alias_list != NULL)
+ {
+ struct action_alias * next = alias_list->next;
+ alias_list->next = NULL;
+ freez(alias_list->name);
+ free_action(alias_list->action);
+ free(alias_list);
+ alias_list = next;
+ }
+}
+
+
+/*********************************************************************
+ *
+ * Function : load_action_files
+ *
+ * Description : Read and parse all the action files and add to files
+ * list.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ *
+ * Returns : 0 => Ok, everything else is an error.
+ *
+ *********************************************************************/
+int load_action_files(struct client_state *csp)
+{
+ int i;
+ int result;
+
+ for (i = 0; i < MAX_AF_FILES; i++)
+ {
+ if (csp->config->actions_file[i])
+ {
+ result = load_one_actions_file(csp, i);
+ if (result)
+ {
+ return result;
+ }
+ }
+ else if (current_actions_file[i])
+ {
+ current_actions_file[i]->unloader = unload_actions_file;
+ current_actions_file[i] = NULL;
+ }
+ }
+
+ return 0;
+}
+
+
+/*********************************************************************
+ *
+ * Function : referenced_filters_are_missing
+ *
+ * Description : Checks if any filters of a certain type referenced
+ * in an action spec are missing.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : cur_action = The action spec to check.
+ * 3 : multi_index = The index where to look for the filter.
+ * 4 : filter_type = The filter type the caller is interested in.
+ *
+ * Returns : 0 => All referenced filters 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 filter '%s'", filtername->str);
+ return 1;
+ }
+ }
+
+ return 0;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function : action_spec_is_valid
+ *
+ * Description : Should eventually figure out if an action spec
+ * is valid, but currently only checks that the
+ * referenced filters are accounted for.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : cur_action = The action spec to check.
+ *
+ * Returns : 0 => No problems detected, everything else is an error.
+ *
+ *********************************************************************/
+static int action_spec_is_valid(struct client_state *csp, const struct action_spec *cur_action)
+{
+ struct {
+ int multi_index;
+ enum filter_type filter_type;
+ } filter_map[] = {
+ {ACTION_MULTI_FILTER, FT_CONTENT_FILTER},
+ {ACTION_MULTI_CLIENT_HEADER_FILTER, FT_CLIENT_HEADER_FILTER},
+ {ACTION_MULTI_SERVER_HEADER_FILTER, FT_SERVER_HEADER_FILTER},
+ {ACTION_MULTI_CLIENT_HEADER_TAGGER, FT_CLIENT_HEADER_TAGGER},
+ {ACTION_MULTI_SERVER_HEADER_TAGGER, FT_SERVER_HEADER_TAGGER}
+ };
+ int errors = 0;
+ int i;
+
+ for (i = 0; i < SZ(filter_map); i++)
+ {
+ errors += referenced_filters_are_missing(csp, cur_action,
+ filter_map[i].multi_index, filter_map[i].filter_type);
+ }
+
+ return errors;
+
+}
+
+
+/*********************************************************************
+ *
+ * Function : load_one_actions_file
+ *
+ * Description : Read and parse a action file and add to files
+ * list.
+ *
+ * Parameters :
+ * 1 : csp = Current client state (buffers, headers, etc...)
+ * 2 : fileid = File index to load.
+ *
+ * Returns : 0 => Ok, everything else is an error.
+ *
+ *********************************************************************/
+static int load_one_actions_file(struct client_state *csp, int fileid)
+{
+
+ /*
+ * Parser mode.
+ * Note: Keep these in the order they occur in the file, they are
+ * sometimes tested with <=
+ */
+ enum {
+ MODE_START_OF_FILE = 1,
+ MODE_SETTINGS = 2,
+ MODE_DESCRIPTION = 3,
+ MODE_ALIAS = 4,
+ MODE_ACTIONS = 5
+ } mode;
+
+ FILE *fp;