1 const char actions_rcs[] = "$Id: actions.c,v 1.24 2002/03/16 23:54:06 jongfoster Exp $";
2 /*********************************************************************
4 * File : $Source: /cvsroot/ijbswa/current/actions.c,v $
6 * Purpose : Declares functions to work with actions files
7 * Functions declared include: FIXME
9 * Copyright : Written by and Copyright (C) 2001 the SourceForge
10 * Privoxy team. http://ijbswa.sourceforge.net
12 * Based on the Internet Junkbuster originally written
13 * by and Copyright (C) 1997 Anonymous Coders and
14 * Junkbusters Corporation. http://www.junkbusters.com
16 * This program is free software; you can redistribute it
17 * and/or modify it under the terms of the GNU General
18 * Public License as published by the Free Software
19 * Foundation; either version 2 of the License, or (at
20 * your option) any later version.
22 * This program is distributed in the hope that it will
23 * be useful, but WITHOUT ANY WARRANTY; without even the
24 * implied warranty of MERCHANTABILITY or FITNESS FOR A
25 * PARTICULAR PURPOSE. See the GNU General Public
26 * License for more details.
28 * The GNU General Public License should be included with
29 * this file. If not, you can view it at
30 * http://www.gnu.org/copyleft/gpl.html
31 * or write to the Free Software Foundation, Inc., 59
32 * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
36 * Revision 1.24 2002/03/16 23:54:06 jongfoster
37 * Adding graceful termination feature, to help look for memory leaks.
38 * If you enable this (which, by design, has to be done by hand
39 * editing config.h) and then go to http://i.j.b/die, then the program
40 * will exit cleanly after the *next* request. It should free all the
41 * memory that was used.
43 * Revision 1.23 2002/03/07 03:46:16 oes
44 * Fixed compiler warnings
46 * Revision 1.22 2002/01/21 00:27:02 jongfoster
47 * Allowing free_action(NULL).
48 * Moving the functions that #include actionlist.h to the end of the file,
49 * because the Visual C++ 97 debugger gets extremely confused if you try
50 * to debug any code that comes after them in the file.
52 * Revision 1.21 2002/01/17 20:54:44 jongfoster
53 * Renaming free_url to free_url_spec, since it frees a struct url_spec.
55 * Revision 1.20 2001/11/22 21:56:49 jongfoster
56 * Making action_spec->flags into an unsigned long rather than just an
58 * Fixing a bug in the display of -add-header and -wafer
60 * Revision 1.19 2001/11/13 00:14:07 jongfoster
61 * Fixing stupid bug now I've figured out what || means.
62 * (It always returns 0 or 1, not one of it's paramaters.)
64 * Revision 1.18 2001/11/07 00:06:06 steudten
65 * Add line number in error output for lineparsing for
68 * Revision 1.17 2001/10/25 03:40:47 david__schmidt
69 * Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
70 * threads to call select() simultaneously. So, it's time to do a real, live,
71 * native OS/2 port. See defines for __EMX__ (the porting layer) vs. __OS2__
72 * (native). Both versions will work, but using __OS2__ offers multi-threading.
74 * Revision 1.16 2001/10/23 21:30:30 jongfoster
75 * Adding error-checking to selected functions.
77 * Revision 1.15 2001/10/14 21:58:22 jongfoster
78 * Adding support for the CGI-based editor:
79 * - Exported get_actions()
80 * - Added new function free_alias_list()
81 * - Added support for {{settings}} and {{description}} blocks
82 * in the actions file. They are currently ignored.
83 * - Added restriction to only one {{alias}} block which must appear
84 * first in the file, to simplify the editor's rewriting rules.
85 * - Note that load_actions_file() is no longer used by the CGI-based
86 * editor, but some of the other routines in this file are.
88 * Revision 1.14 2001/09/22 16:36:59 jongfoster
89 * Removing unused parameter fs from read_config_line()
91 * Revision 1.13 2001/09/16 15:47:37 jongfoster
92 * First version of CGI-based edit interface. This is very much a
93 * work-in-progress, and you can't actually use it to edit anything
94 * yet. You must #define FEATURE_CGI_EDIT_ACTIONS for these changes
97 * Revision 1.12 2001/09/16 13:21:27 jongfoster
98 * Changes to use new list functions.
100 * Revision 1.11 2001/09/14 00:17:32 jongfoster
101 * Tidying up memory allocation. New function init_action().
103 * Revision 1.10 2001/09/10 10:14:34 oes
104 * Removing unused variable
106 * Revision 1.9 2001/07/30 22:08:36 jongfoster
107 * Tidying up #defines:
108 * - All feature #defines are now of the form FEATURE_xxx
109 * - Permanently turned off WIN_GUI_EDIT
110 * - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
112 * Revision 1.8 2001/06/29 13:19:52 oes
113 * Removed logentry from cancelled commit
115 * Revision 1.7 2001/06/09 10:55:28 jongfoster
116 * Changing BUFSIZ ==> BUFFER_SIZE
118 * Revision 1.6 2001/06/07 23:04:34 jongfoster
119 * Made get_actions() static.
121 * Revision 1.5 2001/06/03 19:11:48 oes
122 * adapted to new enlist_unique arg format
124 * Revision 1.4 2001/06/01 20:03:42 jongfoster
125 * Better memory management - current_action->strings[] now
126 * contains copies of the strings, not the original.
128 * Revision 1.3 2001/06/01 18:49:17 jongfoster
129 * Replaced "list_share" with "list" - the tiny memory gain was not
130 * worth the extra complexity.
132 * Revision 1.2 2001/05/31 21:40:00 jongfoster
133 * Removing some commented out, obsolete blocks of code.
135 * Revision 1.1 2001/05/31 21:16:46 jongfoster
136 * Moved functions to process the action list into this new file.
139 *********************************************************************/
153 #include "miscutil.h"
156 #ifdef FEATURE_CGI_EDIT_ACTIONS
158 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
159 #include "urlmatch.h"
161 const char actions_h_rcs[] = ACTIONS_H_VERSION;
165 * We need the main list of options.
167 * First, we need a way to tell between boolean, string, and multi-string
168 * options. For string and multistring options, we also need to be
169 * able to tell the difference between a "+" and a "-". (For bools,
170 * the "+"/"-" information is encoded in "add" and "mask"). So we use
171 * an enumerated type (well, the preprocessor equivalent). Here are
174 #define AV_NONE 0 /* +opt -opt */
175 #define AV_ADD_STRING 1 /* +stropt{string} */
176 #define AV_REM_STRING 2 /* -stropt */
177 #define AV_ADD_MULTI 3 /* +multiopt{string} +multiopt{string2} */
178 #define AV_REM_MULTI 4 /* -multiopt{string} -multiopt */
181 * We need a structure to hold the name, flag changes,
182 * type, and string index.
187 unsigned mask; /* a bit set to "0" = remove action */
188 unsigned add; /* a bit set to "1" = add action */
189 int takes_value; /* an AV_... constant */
190 int index; /* index into strings[] or multi[] */
194 * And with those building blocks in place, here's the array.
196 static const struct action_name action_names[] =
199 * Well actually there's no data here - it's in actionlist.h
200 * This keeps it together to make it easy to change.
202 * Here's the macros used to format it:
204 #define DEFINE_ACTION_MULTI(name,index) \
205 { "+" name, ACTION_MASK_ALL, 0, AV_ADD_MULTI, index }, \
206 { "-" name, ACTION_MASK_ALL, 0, AV_REM_MULTI, index },
207 #define DEFINE_ACTION_STRING(name,flag,index) \
208 { "+" name, ACTION_MASK_ALL, flag, AV_ADD_STRING, index }, \
209 { "-" name, ~flag, 0, AV_REM_STRING, index },
210 #define DEFINE_ACTION_BOOL(name,flag) \
211 { "+" name, ACTION_MASK_ALL, flag }, \
212 { "-" name, ~flag, 0 },
213 #define DEFINE_ACTION_ALIAS 1 /* Want aliases please */
215 #include "actionlist.h"
217 #undef DEFINE_ACTION_MULTI
218 #undef DEFINE_ACTION_STRING
219 #undef DEFINE_ACTION_BOOL
220 #undef DEFINE_ACTION_ALIAS
222 { NULL, 0, 0 } /* End marker */
226 /*********************************************************************
228 * Function : merge_actions
230 * Description : Merge two actions together.
231 * Similar to "cur_action += new_action".
234 * 1 : cur_action = Current actions, to modify.
235 * 2 : new_action = Action to add.
237 * Returns : JB_ERR_OK or JB_ERR_MEMORY
239 *********************************************************************/
240 jb_err merge_actions (struct action_spec *dest,
241 const struct action_spec *src)
246 dest->mask &= src->mask;
247 dest->add &= src->mask;
248 dest->add |= src->add;
250 for (i = 0; i < ACTION_STRING_COUNT; i++)
252 char * str = src->string[i];
255 freez(dest->string[i]);
256 dest->string[i] = strdup(str);
257 if (NULL == dest->string[i])
259 return JB_ERR_MEMORY;
264 for (i = 0; i < ACTION_MULTI_COUNT; i++)
266 if (src->multi_remove_all[i])
268 /* Remove everything from dest */
269 list_remove_all(dest->multi_remove[i]);
270 dest->multi_remove_all[i] = 1;
272 err = list_duplicate(dest->multi_add[i], src->multi_add[i]);
274 else if (dest->multi_remove_all[i])
277 * dest already removes everything, so we only need to worry
280 list_remove_list(dest->multi_add[i], src->multi_remove[i]);
281 err = list_append_list_unique(dest->multi_add[i], src->multi_add[i]);
285 /* No "remove all"s to worry about. */
286 list_remove_list(dest->multi_add[i], src->multi_remove[i]);
287 err = list_append_list_unique(dest->multi_remove[i], src->multi_remove[i]);
288 if (!err) err = list_append_list_unique(dest->multi_add[i], src->multi_add[i]);
301 /*********************************************************************
303 * Function : copy_action
305 * Description : Copy an action_specs.
306 * Similar to "cur_action = new_action".
307 * Note that dest better not contain valid data
308 * - it's overwritten, not freed.
311 * 1 : dest = Destination of copy.
312 * 2 : src = Source for copy.
316 *********************************************************************/
317 jb_err copy_action (struct action_spec *dest,
318 const struct action_spec *src)
321 jb_err err = JB_ERR_OK;
323 memset(dest, '\0', sizeof(*dest));
325 dest->mask = src->mask;
326 dest->add = src->add;
328 for (i = 0; i < ACTION_STRING_COUNT; i++)
330 char * str = src->string[i];
336 return JB_ERR_MEMORY;
338 dest->string[i] = str;
342 for (i = 0; i < ACTION_MULTI_COUNT; i++)
344 dest->multi_remove_all[i] = src->multi_remove_all[i];
345 err = list_duplicate(dest->multi_remove[i], src->multi_remove[i]);
350 err = list_duplicate(dest->multi_add[i], src->multi_add[i]);
360 /*********************************************************************
362 * Function : free_action
364 * Description : Destroy an action_spec. Frees memory used by it,
365 * except for the memory used by the struct action_spec
369 * 1 : src = Source to free.
373 *********************************************************************/
374 void free_action (struct action_spec *src)
383 for (i = 0; i < ACTION_STRING_COUNT; i++)
385 freez(src->string[i]);
388 for (i = 0; i < ACTION_MULTI_COUNT; i++)
390 destroy_list(src->multi_remove[i]);
391 destroy_list(src->multi_add[i]);
394 memset(src, '\0', sizeof(*src));
398 /*********************************************************************
400 * Function : get_action_token
402 * Description : Parses a line for the first action.
403 * Modifies it's input array, doesn't allocate memory.
405 * *line=" +abc{def} -ghi "
412 * 1 : line = [in] The line containing the action.
413 * [out] Start of next action on line, or
414 * NULL if we reached the end of line before
415 * we found an action.
416 * 2 : name = [out] Start of action name, null
417 * terminated. NULL on EOL
418 * 3 : value = [out] Start of action value, null
419 * terminated. NULL if none or EOL.
421 * Returns : JB_ERR_OK => Ok
422 * JB_ERR_PARSE => Mismatched {} (line was trashed anyway)
424 *********************************************************************/
425 jb_err get_action_token(char **line, char **name, char **value)
430 /* set default returns */
435 /* Eat any leading whitespace */
436 while ((*str == ' ') || (*str == '\t'))
448 /* null name, just value is prohibited */
455 while (((ch = *str) != '\0') &&
456 (ch != ' ') && (ch != '\t') && (ch != '{'))
460 /* error, '}' without '{' */
472 /* EOL - be careful not to run off buffer */
477 /* More to parse next time. */
486 str = strchr(str, '}');
504 /*********************************************************************
506 * Function : get_actions
508 * Description : Parses a list of actions.
511 * 1 : line = The string containing the actions.
512 * Will be written to by this function.
513 * 2 : aliases = Custom alias list, or NULL for none.
514 * 3 : cur_action = Where to store the action. Caller
517 * Returns : JB_ERR_OK => Ok
518 * JB_ERR_PARSE => Parse error (line was trashed anyway)
519 * nonzero => Out of memory (line was trashed anyway)
521 *********************************************************************/
522 jb_err get_actions(char *line,
523 struct action_alias * alias_list,
524 struct action_spec *cur_action)
527 init_action(cur_action);
528 cur_action->mask = ACTION_MASK_ALL;
532 char * option = NULL;
535 err = get_action_token(&line, &option, &value);
543 /* handle option in 'option' */
545 /* Check for standard action name */
546 const struct action_name * action = action_names;
548 while ( (action->name != NULL) && (0 != strcmpic(action->name, option)) )
552 if (action->name != NULL)
555 cur_action->mask &= action->mask;
556 cur_action->add &= action->mask;
557 cur_action->add |= action->add;
559 switch (action->takes_value)
562 /* ignore any option. */
566 /* add single string. */
568 if ((value == NULL) || (*value == '\0'))
572 /* FIXME: should validate option string here */
573 freez (cur_action->string[action->index]);
574 cur_action->string[action->index] = strdup(value);
575 if (NULL == cur_action->string[action->index])
577 return JB_ERR_MEMORY;
583 /* remove single string. */
585 freez (cur_action->string[action->index]);
590 /* append multi string. */
592 struct list * remove_p = cur_action->multi_remove[action->index];
593 struct list * add_p = cur_action->multi_add[action->index];
595 if ((value == NULL) || (*value == '\0'))
600 list_remove_item(remove_p, value);
601 err = enlist_unique(add_p, value, 0);
610 /* remove multi string. */
612 struct list * remove_p = cur_action->multi_remove[action->index];
613 struct list * add_p = cur_action->multi_add[action->index];
615 if ( (value == NULL) || (*value == '\0')
616 || ((*value == '*') && (value[1] == '\0')) )
619 * no option, or option == "*".
623 list_remove_all(remove_p);
624 list_remove_all(add_p);
625 cur_action->multi_remove_all[action->index] = 1;
629 /* Valid option - remove only 1 option */
631 if ( !cur_action->multi_remove_all[action->index] )
633 /* there isn't a catch-all in the remove list already */
634 err = enlist_unique(remove_p, value, 0);
640 list_remove_item(add_p, value);
645 /* Shouldn't get here unless there's memory corruption. */
652 /* try user aliases. */
653 const struct action_alias * alias = alias_list;
655 while ( (alias != NULL) && (0 != strcmpic(alias->name, option)) )
662 merge_actions(cur_action, alias->action);
666 /* Bad action name */
677 /*********************************************************************
679 * Function : init_current_action
681 * Description : Zero out an action.
684 * 1 : dest = An uninitialized current_action_spec.
688 *********************************************************************/
689 void init_current_action (struct current_action_spec *dest)
691 memset(dest, '\0', sizeof(*dest));
693 dest->flags = ACTION_MOST_COMPATIBLE;
697 /*********************************************************************
699 * Function : init_action
701 * Description : Zero out an action.
704 * 1 : dest = An uninitialized action_spec.
708 *********************************************************************/
709 void init_action (struct action_spec *dest)
711 memset(dest, '\0', sizeof(*dest));
715 /*********************************************************************
717 * Function : merge_current_action
719 * Description : Merge two actions together.
720 * Similar to "dest += src".
721 * Differences between this and merge_actions()
722 * is that this one doesn't allocate memory for
723 * strings (so "src" better be in memory for at least
724 * as long as "dest" is, and you'd better free
725 * "dest" using "free_current_action").
726 * Also, there is no mask or remove lists in dest.
727 * (If we're applying it to a URL, we don't need them)
730 * 1 : dest = Current actions, to modify.
731 * 2 : src = Action to add.
733 * Returns 0 : no error
734 * !=0 : error, probably JB_ERR_MEMORY.
736 *********************************************************************/
737 jb_err merge_current_action (struct current_action_spec *dest,
738 const struct action_spec *src)
741 jb_err err = JB_ERR_OK;
743 dest->flags &= src->mask;
744 dest->flags |= src->add;
746 for (i = 0; i < ACTION_STRING_COUNT; i++)
748 char * str = src->string[i];
754 return JB_ERR_MEMORY;
756 freez(dest->string[i]);
757 dest->string[i] = str;
761 for (i = 0; i < ACTION_MULTI_COUNT; i++)
763 if (src->multi_remove_all[i])
765 /* Remove everything from dest, then add src->multi_add */
766 err = list_duplicate(dest->multi[i], src->multi_add[i]);
774 list_remove_list(dest->multi[i], src->multi_remove[i]);
775 err = list_append_list_unique(dest->multi[i], src->multi_add[i]);
786 /*********************************************************************
788 * Function : free_current_action
790 * Description : Free memory used by a current_action_spec.
791 * Does not free the current_action_spec itself.
794 * 1 : src = Source to free.
798 *********************************************************************/
799 void free_current_action (struct current_action_spec *src)
803 for (i = 0; i < ACTION_STRING_COUNT; i++)
805 freez(src->string[i]);
808 for (i = 0; i < ACTION_MULTI_COUNT; i++)
810 destroy_list(src->multi[i]);
813 memset(src, '\0', sizeof(*src));
817 static struct file_list *current_actions_file = NULL;
820 #ifdef FEATURE_GRACEFUL_TERMINATION
821 /*********************************************************************
823 * Function : unload_current_actions_file
825 * Description : Unloads current actions file - reset to state at
826 * beginning of program.
832 *********************************************************************/
833 void unload_current_actions_file(void)
835 if (current_actions_file)
837 current_actions_file->unloader = unload_actions_file;
838 current_actions_file = NULL;
841 #endif /* FEATURE_GRACEFUL_TERMINATION */
844 /*********************************************************************
846 * Function : unload_actions_file
848 * Description : Unloads an actions module.
851 * 1 : file_data = the data structure associated with the
856 *********************************************************************/
857 void unload_actions_file(void *file_data)
859 struct url_actions * next;
860 struct url_actions * cur = (struct url_actions *)file_data;
864 free_url_spec(cur->url);
865 free_action(cur->action);
873 /*********************************************************************
875 * Function : free_alias_list
877 * Description : Free memory used by a list of aliases.
880 * 1 : alias_list = Linked list to free.
884 *********************************************************************/
885 void free_alias_list(struct action_alias *alias_list)
887 while (alias_list != NULL)
889 struct action_alias * next = alias_list->next;
890 alias_list->next = NULL;
891 freez(alias_list->name);
892 free_action(alias_list->action);
899 /*********************************************************************
901 * Function : load_actions_file
903 * Description : Read and parse a action file and add to files
907 * 1 : csp = Current client state (buffers, headers, etc...)
909 * Returns : 0 => Ok, everything else is an error.
911 *********************************************************************/
912 int load_actions_file(struct client_state *csp)
917 * Note: Keep these in the order they occur in the file, they are
918 * sometimes tested with <=
920 #define MODE_START_OF_FILE 1
921 #define MODE_SETTINGS 2
922 #define MODE_DESCRIPTION 3
924 #define MODE_ACTIONS 5
926 int mode = MODE_START_OF_FILE;
929 struct url_actions *last_perm;
930 struct url_actions *perm;
931 char buf[BUFFER_SIZE];
932 struct file_list *fs;
933 struct action_spec * cur_action = NULL;
934 int cur_action_used = 0;
935 struct action_alias * alias_list = NULL;
936 unsigned long linenum = 0;
938 if (!check_file_changed(current_actions_file, csp->config->actions_file, &fs))
940 /* No need to load */
943 csp->actions_list = current_actions_file;
949 log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': error finding file: %E",
950 csp->config->actions_file);
951 return 1; /* never get here */
954 fs->f = last_perm = (struct url_actions *)zalloc(sizeof(*last_perm));
955 if (last_perm == NULL)
957 log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': out of memory!",
958 csp->config->actions_file);
959 return 1; /* never get here */
962 if ((fp = fopen(csp->config->actions_file, "r")) == NULL)
964 log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': error opening file: %E",
965 csp->config->actions_file);
966 return 1; /* never get here */
969 while (read_config_line(buf, sizeof(buf), fp, &linenum) != NULL)
973 /* It's a header block */
976 /* It's {{settings}} or {{alias}} */
977 int len = strlen(buf);
978 char * start = buf + 2;
979 char * end = buf + len - 1;
980 if ((len < 5) || (*end-- != '}') || (*end-- != '}'))
984 log_error(LOG_LEVEL_FATAL,
985 "can't load actions file '%s': invalid line (%lu): %s",
986 csp->config->actions_file, linenum, buf);
987 return 1; /* never get here */
990 /* Trim leading and trailing whitespace. */
998 log_error(LOG_LEVEL_FATAL,
999 "can't load actions file '%s': invalid line (%lu): {{ }}",
1000 csp->config->actions_file, linenum);
1001 return 1; /* never get here */
1005 * An actionsfile can optionally contain the following blocks.
1006 * They *MUST* be in this order, to simplify processing:
1012 * ...free text, format TBD, but no line may start with a '{'...
1017 * The actual actions must be *after* these special blocks.
1018 * None of these special blocks may be repeated.
1021 if (0 == strcmpic(start, "settings"))
1023 /* it's a {{settings}} block */
1024 if (mode >= MODE_SETTINGS)
1026 /* {{settings}} must be first thing in file and must only
1030 log_error(LOG_LEVEL_FATAL,
1031 "can't load actions file '%s': line %lu: {{settings}} must only appear once, and it must be before anything else.",
1032 csp->config->actions_file, linenum);
1034 mode = MODE_SETTINGS;
1036 else if (0 == strcmpic(start, "description"))
1038 /* it's a {{description}} block */
1039 if (mode >= MODE_DESCRIPTION)
1041 /* {{description}} is a singleton and only {{settings}} may proceed it
1044 log_error(LOG_LEVEL_FATAL,
1045 "can't load actions file '%s': line %lu: {{description}} must only appear once, and only a {{settings}} block may be above it.",
1046 csp->config->actions_file, linenum);
1048 mode = MODE_DESCRIPTION;
1050 else if (0 == strcmpic(start, "alias"))
1052 /* it's an {{alias}} block */
1053 if (mode >= MODE_ALIAS)
1055 /* {{alias}} must be first thing in file, possibly after
1056 * {{settings}} and {{description}}
1058 * {{alias}} must only appear once.
1060 * Note that these are new restrictions introduced in
1061 * v2.9.10 in order to make actionsfile editing simpler.
1062 * (Otherwise, reordering actionsfile entries without
1063 * completely rewriting the file becomes non-trivial)
1066 log_error(LOG_LEVEL_FATAL,
1067 "can't load actions file '%s': line %lu: {{alias}} must only appear once, and it must be before all actions.",
1068 csp->config->actions_file, linenum);
1074 /* invalid {{something}} block */
1076 log_error(LOG_LEVEL_FATAL,
1077 "can't load actions file '%s': invalid line (%lu): {{%s}}",
1078 csp->config->actions_file, linenum, start);
1079 return 1; /* never get here */
1084 /* It's an actions block */
1086 char actions_buf[BUFFER_SIZE];
1090 mode = MODE_ACTIONS;
1092 /* free old action */
1095 if (!cur_action_used)
1097 free_action(cur_action);
1102 cur_action_used = 0;
1103 cur_action = (struct action_spec *)zalloc(sizeof(*cur_action));
1104 if (cur_action == NULL)
1107 log_error(LOG_LEVEL_FATAL,
1108 "can't load actions file '%s': out of memory",
1109 csp->config->actions_file);
1110 return 1; /* never get here */
1112 init_action(cur_action);
1115 strcpy(actions_buf, buf + 1);
1117 /* check we have a trailing } and then trim it */
1118 end = actions_buf + strlen(actions_buf) - 1;
1123 log_error(LOG_LEVEL_FATAL,
1124 "can't load actions file '%s': invalid line (%lu): %s",
1125 csp->config->actions_file, linenum, buf);
1126 return 1; /* never get here */
1130 /* trim any whitespace immediately inside {} */
1133 if (get_actions(actions_buf, alias_list, cur_action))
1137 log_error(LOG_LEVEL_FATAL,
1138 "can't load actions file '%s': invalid line (%lu): %s",
1139 csp->config->actions_file, linenum, buf);
1140 return 1; /* never get here */
1144 else if (mode == MODE_SETTINGS)
1147 * Part of the {{settings}} block.
1148 * Ignore for now, but we may want to read & check permissions
1149 * when we go multi-user.
1152 else if (mode == MODE_DESCRIPTION)
1155 * Part of the {{description}} block.
1159 else if (mode == MODE_ALIAS)
1164 char actions_buf[BUFFER_SIZE];
1165 struct action_alias * new_alias;
1167 char * start = strchr(buf, '=');
1170 if ((start == NULL) || (start == buf))
1172 log_error(LOG_LEVEL_FATAL,
1173 "can't load actions file '%s': invalid alias line (%lu): %s",
1174 csp->config->actions_file, linenum, buf);
1175 return 1; /* never get here */
1178 if ((new_alias = zalloc(sizeof(*new_alias))) == NULL)
1181 log_error(LOG_LEVEL_FATAL,
1182 "can't load actions file '%s': out of memory!",
1183 csp->config->actions_file);
1184 return 1; /* never get here */
1187 /* Eat any the whitespace before the '=' */
1189 while ((*end == ' ') || (*end == '\t'))
1192 * we already know we must have at least 1 non-ws char
1193 * at start of buf - no need to check
1199 /* Eat any the whitespace after the '=' */
1201 while ((*start == ' ') || (*start == '\t'))
1207 log_error(LOG_LEVEL_FATAL,
1208 "can't load actions file '%s': invalid alias line (%lu): %s",
1209 csp->config->actions_file, linenum, buf);
1210 return 1; /* never get here */
1213 new_alias->name = strdup(buf);
1215 strcpy(actions_buf, start);
1217 if (get_actions(actions_buf, alias_list, new_alias->action))
1221 log_error(LOG_LEVEL_FATAL,
1222 "can't load actions file '%s': invalid alias line (%lu): %s = %s",
1223 csp->config->actions_file, linenum, buf, start);
1224 return 1; /* never get here */
1228 new_alias->next = alias_list;
1229 alias_list = new_alias;
1231 else if (mode == MODE_ACTIONS)
1233 /* it's a URL pattern */
1235 /* allocate a new node */
1236 if ((perm = zalloc(sizeof(*perm))) == NULL)
1239 log_error(LOG_LEVEL_FATAL,
1240 "can't load actions file '%s': out of memory!",
1241 csp->config->actions_file);
1242 return 1; /* never get here */
1246 copy_action (perm->action, cur_action);
1248 /* Save the URL pattern */
1249 if (create_url_spec(perm->url, buf))
1252 log_error(LOG_LEVEL_FATAL,
1253 "can't load actions file '%s': line %lu: cannot create URL pattern from: %s",
1254 csp->config->actions_file, linenum, buf);
1255 return 1; /* never get here */
1258 /* add it to the list */
1259 last_perm->next = perm;
1262 else if (mode == MODE_START_OF_FILE)
1264 /* oops - please have a {} line as 1st line in file. */
1266 log_error(LOG_LEVEL_FATAL,
1267 "can't load actions file '%s': first needed line (%lu) is invalid: %s",
1268 csp->config->actions_file, linenum, buf);
1269 return 1; /* never get here */
1273 /* How did we get here? This is impossible! */
1275 log_error(LOG_LEVEL_FATAL,
1276 "can't load actions file '%s': INTERNAL ERROR - mode = %d",
1277 csp->config->actions_file, mode);
1278 return 1; /* never get here */
1284 free_action(cur_action);
1286 free_alias_list(alias_list);
1288 /* the old one is now obsolete */
1289 if (current_actions_file)
1291 current_actions_file->unloader = unload_actions_file;
1294 fs->next = files->next;
1296 current_actions_file = fs;
1300 csp->actions_list = fs;
1308 /*********************************************************************
1310 * Function : actions_to_text
1312 * Description : Converts a actionsfile entry from numeric form
1313 * ("mask" and "add") to text.
1316 * 1 : mask = As from struct url_actions
1317 * 2 : add = As from struct url_actions
1319 * Returns : A string. Caller must free it.
1320 * NULL on out-of-memory error.
1322 *********************************************************************/
1323 char * actions_to_text(struct action_spec *action)
1325 unsigned mask = action->mask;
1326 unsigned add = action->add;
1327 char * result = strdup("");
1328 struct list_entry * lst;
1330 /* sanity - prevents "-feature +feature" */
1334 #define DEFINE_ACTION_BOOL(__name, __bit) \
1335 if (!(mask & __bit)) \
1337 string_append(&result, " -" __name); \
1339 else if (add & __bit) \
1341 string_append(&result, " +" __name); \
1344 #define DEFINE_ACTION_STRING(__name, __bit, __index) \
1345 if (!(mask & __bit)) \
1347 string_append(&result, " -" __name); \
1349 else if (add & __bit) \
1351 string_append(&result, " +" __name "{"); \
1352 string_append(&result, action->string[__index]); \
1353 string_append(&result, "}"); \
1356 #define DEFINE_ACTION_MULTI(__name, __index) \
1357 if (action->multi_remove_all[__index]) \
1359 string_append(&result, " -" __name); \
1363 lst = action->multi_remove[__index]->first; \
1366 string_append(&result, " -" __name "{"); \
1367 string_append(&result, lst->str); \
1368 string_append(&result, "}"); \
1372 lst = action->multi_add[__index]->first; \
1375 string_append(&result, " +" __name "{"); \
1376 string_append(&result, lst->str); \
1377 string_append(&result, "}"); \
1381 #define DEFINE_ACTION_ALIAS 0 /* No aliases for output */
1383 #include "actionlist.h"
1385 #undef DEFINE_ACTION_MULTI
1386 #undef DEFINE_ACTION_STRING
1387 #undef DEFINE_ACTION_BOOL
1388 #undef DEFINE_ACTION_ALIAS
1394 #ifdef FEATURE_CGI_EDIT_ACTIONS
1395 /*********************************************************************
1397 * Function : actions_to_html
1399 * Description : Converts a actionsfile entry from numeric form
1400 * ("mask" and "add") to a <br>-seperated HTML string.
1403 * 1 : mask = As from struct url_actions
1404 * 2 : add = As from struct url_actions
1406 * Returns : A string. Caller must free it.
1407 * NULL on out-of-memory error.
1409 *********************************************************************/
1410 char * actions_to_html(struct action_spec *action)
1412 unsigned mask = action->mask;
1413 unsigned add = action->add;
1414 char * result = strdup("");
1416 struct list_entry * lst;
1418 /* sanity - prevents "-feature +feature" */
1422 #define DEFINE_ACTION_BOOL(__name, __bit) \
1423 if (!(mask & __bit)) \
1425 string_append(&result, "\n<br>-" __name); \
1427 else if (add & __bit) \
1429 string_append(&result, "\n<br>+" __name); \
1432 #define DEFINE_ACTION_STRING(__name, __bit, __index) \
1433 if (!(mask & __bit)) \
1435 string_append(&result, "\n<br>-" __name); \
1437 else if (add & __bit) \
1439 string_append(&result, "\n<br>+" __name "{"); \
1440 if (NULL == result) \
1444 enc_str = html_encode(action->string[__index]);\
1445 if (NULL == enc_str) \
1450 string_append(&result, enc_str); \
1452 string_append(&result, "}"); \
1455 #define DEFINE_ACTION_MULTI(__name, __index) \
1456 if (action->multi_remove_all[__index]) \
1458 string_append(&result, "\n<br>-" __name); \
1462 lst = action->multi_remove[__index]->first; \
1465 string_append(&result, "\n<br>-" __name "{");\
1466 if (NULL == result) \
1470 enc_str = html_encode(lst->str); \
1471 if (NULL == enc_str) \
1476 string_append(&result, enc_str); \
1478 string_append(&result, "}"); \
1482 lst = action->multi_add[__index]->first; \
1485 string_append(&result, "\n<br>+" __name "{"); \
1486 if (NULL == result) \
1490 enc_str = html_encode(lst->str); \
1491 if (NULL == enc_str) \
1496 string_append(&result, enc_str); \
1498 string_append(&result, "}"); \
1502 #define DEFINE_ACTION_ALIAS 0 /* No aliases for output */
1504 #include "actionlist.h"
1506 #undef DEFINE_ACTION_MULTI
1507 #undef DEFINE_ACTION_STRING
1508 #undef DEFINE_ACTION_BOOL
1509 #undef DEFINE_ACTION_ALIAS
1511 /* trim leading <br> */
1512 if (result && *result)
1515 result = strdup(result + 5);
1521 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
1524 /*********************************************************************
1526 * Function : current_actions_to_text
1528 * Description : Converts a actionsfile entry to text.
1531 * 1 : action = Action
1533 * Returns : A string. Caller must free it.
1534 * NULL on out-of-memory error.
1536 *********************************************************************/
1537 char * current_action_to_text(struct current_action_spec *action)
1539 unsigned long flags = action->flags;
1540 char * result = strdup("");
1541 struct list_entry * lst;
1543 #define DEFINE_ACTION_BOOL(__name, __bit) \
1544 if (flags & __bit) \
1546 string_append(&result, " +" __name); \
1550 string_append(&result, " -" __name); \
1553 #define DEFINE_ACTION_STRING(__name, __bit, __index) \
1554 if (flags & __bit) \
1556 string_append(&result, " +" __name "{"); \
1557 string_append(&result, action->string[__index]); \
1558 string_append(&result, "}"); \
1562 string_append(&result, " -" __name); \
1565 #define DEFINE_ACTION_MULTI(__name, __index) \
1566 lst = action->multi[__index]->first; \
1569 string_append(&result, " -" __name); \
1575 string_append(&result, " +" __name "{"); \
1576 string_append(&result, lst->str); \
1577 string_append(&result, "}"); \
1582 #define DEFINE_ACTION_ALIAS 0 /* No aliases for output */
1584 #include "actionlist.h"
1586 #undef DEFINE_ACTION_MULTI
1587 #undef DEFINE_ACTION_STRING
1588 #undef DEFINE_ACTION_BOOL
1589 #undef DEFINE_ACTION_ALIAS