Complain about every block action without reason found.
[privoxy.git] / actions.c
1 const char actions_rcs[] = "$Id: actions.c,v 1.50 2008/03/30 14:52:00 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/actions.c,v $
5  *
6  * Purpose     :  Declares functions to work with actions files
7  *                Functions declared include: FIXME
8  *
9  * Copyright   :  Written by and Copyright (C) 2001-2008 the SourceForge
10  *                Privoxy team. http://www.privoxy.org/
11  *
12  *                Based on the Internet Junkbuster originally written
13  *                by and Copyright (C) 1997 Anonymous Coders and
14  *                Junkbusters Corporation.  http://www.junkbusters.com
15  *
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.
21  *
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.
27  *
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.
33  *
34  * Revisions   :
35  *    $Log: actions.c,v $
36  *    Revision 1.50  2008/03/30 14:52:00  fabiankeil
37  *    Rename load_actions_file() and load_re_filterfile()
38  *    as they load multiple files "now".
39  *
40  *    Revision 1.49  2008/03/29 12:13:45  fabiankeil
41  *    Remove send-wafer and send-vanilla-wafer actions.
42  *
43  *    Revision 1.48  2008/03/28 18:17:14  fabiankeil
44  *    In action_used_to_be_valid(), loop through an array of formerly
45  *    valid actions instead of using an OR-chain of strcmpic() calls.
46  *
47  *    Revision 1.47  2008/03/28 15:13:37  fabiankeil
48  *    Remove inspect-jpegs action.
49  *
50  *    Revision 1.46  2008/03/27 18:27:20  fabiankeil
51  *    Remove kill-popups action.
52  *
53  *    Revision 1.45  2008/03/24 11:21:02  fabiankeil
54  *    Share the action settings for multiple patterns in the same
55  *    section so we waste less memory for gigantic block lists
56  *    (and load them slightly faster). Reported by Franz Schwartau.
57  *
58  *    Revision 1.44  2008/03/04 18:30:34  fabiankeil
59  *    Remove the treat-forbidden-connects-like-blocks action. We now
60  *    use the "blocked" page for forbidden CONNECT requests by default.
61  *
62  *    Revision 1.43  2008/03/01 14:00:43  fabiankeil
63  *    Let the block action take the reason for the block
64  *    as argument and show it on the "blocked" page.
65  *
66  *    Revision 1.42  2008/02/09 15:15:38  fabiankeil
67  *    List active and inactive actions in the show-url-info's
68  *    "Final results" section separately. Patch submitted by Lee
69  *    in #1830056, modified to list active actions first.
70  *
71  *    Revision 1.41  2008/01/28 20:17:40  fabiankeil
72  *    - Mark some parameters as immutable.
73  *    - Hide update_action_bits_for_all_tags() while it's unused.
74  *
75  *    Revision 1.40  2007/05/21 10:26:50  fabiankeil
76  *    - Use strlcpy() instead of strcpy().
77  *    - Provide a reason why loading the actions
78  *      file might have failed.
79  *
80  *    Revision 1.39  2007/04/17 18:21:45  fabiankeil
81  *    Split update_action_bits() into
82  *    update_action_bits_for_all_tags()
83  *    and update_action_bits_for_tag().
84  *
85  *    Revision 1.38  2007/04/15 16:39:20  fabiankeil
86  *    Introduce tags as alternative way to specify which
87  *    actions apply to a request. At the moment tags can be
88  *    created based on client and server headers.
89  *
90  *    Revision 1.37  2007/03/11 15:56:12  fabiankeil
91  *    Add kludge to log unknown aliases and actions before exiting.
92  *
93  *    Revision 1.36  2006/12/28 17:15:42  fabiankeil
94  *    Fix gcc43 conversion warning.
95  *
96  *    Revision 1.35  2006/07/18 14:48:45  david__schmidt
97  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
98  *    with what was really the latest development (the v_3_0_branch branch)
99  *
100  *    Revision 1.32.2.6  2006/01/29 23:10:56  david__schmidt
101  *    Multiple filter file support
102  *
103  *    Revision 1.32.2.5  2005/06/09 01:18:41  david__schmidt
104  *    Tweaks to conditionally include pthread.h if FEATURE_PTHREAD is enabled -
105  *    this becomes important when jcc.h gets included later down the line.
106  *
107  *    Revision 1.32.2.4  2003/12/03 10:33:11  oes
108  *    - Implemented Privoxy version requirement through
109  *      for-privoxy-version= statement in {{settings}}
110  *      block
111  *    - Fix for unchecked out-of-memory condition
112  *
113  *    Revision 1.32.2.3  2003/02/28 12:52:10  oes
114  *    Fixed memory leak reported by Dan Price in Bug #694713
115  *
116  *    Revision 1.32.2.2  2002/11/20 14:36:55  oes
117  *    Extended unload_current_actions_file() to multiple AFs.
118  *    Thanks to Oliver Stoeneberg for the hint.
119  *
120  *    Revision 1.32.2.1  2002/05/26 12:13:16  roro
121  *    Change unsigned to unsigned long in actions_name struct.  This closes
122  *    SourceForge Bug #539284.
123  *
124  *    Revision 1.32  2002/05/12 21:36:29  jongfoster
125  *    Correcting function comments
126  *
127  *    Revision 1.31  2002/05/06 07:56:50  oes
128  *    Made actions_to_html independent of FEATURE_CGI_EDIT_ACTIONS
129  *
130  *    Revision 1.30  2002/04/30 11:14:52  oes
131  *    Made csp the first parameter in *action_to_html
132  *
133  *    Revision 1.29  2002/04/26 19:30:54  jongfoster
134  *    - current_action_to_html(): Adding help link for the "-" form of
135  *      one-string actions.
136  *    - Some actions had "<br>-", some "<br> -" (note the space).
137  *      Standardizing on no space.
138  *    - Greatly simplifying some of the code by using string_join()
139  *      where appropriate.
140  *
141  *    Revision 1.28  2002/04/26 12:53:15  oes
142  *     - CGI AF editor now writes action lines split into
143  *       single lines with line continuation
144  *     - actions_to_html now embeds each action name in
145  *       link to chapter
146  *     - current_action_to_text is now called current_action_to_html
147  *       and acts like actions_to_html
148  *
149  *    Revision 1.27  2002/04/24 02:10:31  oes
150  *     - Jon's patch for multiple AFs:
151  *       - split load_actions_file, add load_one_actions_file
152  *       - make csp->actions_list files an array
153  *       - remember file id with each action
154  *     - Copy_action now frees dest action before copying
155  *
156  *    Revision 1.26  2002/03/26 22:29:54  swa
157  *    we have a new homepage!
158  *
159  *    Revision 1.25  2002/03/24 13:25:43  swa
160  *    name change related issues
161  *
162  *    Revision 1.24  2002/03/16 23:54:06  jongfoster
163  *    Adding graceful termination feature, to help look for memory leaks.
164  *    If you enable this (which, by design, has to be done by hand
165  *    editing config.h) and then go to http://i.j.b/die, then the program
166  *    will exit cleanly after the *next* request.  It should free all the
167  *    memory that was used.
168  *
169  *    Revision 1.23  2002/03/07 03:46:16  oes
170  *    Fixed compiler warnings
171  *
172  *    Revision 1.22  2002/01/21 00:27:02  jongfoster
173  *    Allowing free_action(NULL).
174  *    Moving the functions that #include actionlist.h to the end of the file,
175  *    because the Visual C++ 97 debugger gets extremely confused if you try
176  *    to debug any code that comes after them in the file.
177  *
178  *    Revision 1.21  2002/01/17 20:54:44  jongfoster
179  *    Renaming free_url to free_url_spec, since it frees a struct url_spec.
180  *
181  *    Revision 1.20  2001/11/22 21:56:49  jongfoster
182  *    Making action_spec->flags into an unsigned long rather than just an
183  *    unsigned int.
184  *    Fixing a bug in the display of -add-header and -wafer
185  *
186  *    Revision 1.19  2001/11/13 00:14:07  jongfoster
187  *    Fixing stupid bug now I've figured out what || means.
188  *    (It always returns 0 or 1, not one of it's paramaters.)
189  *
190  *    Revision 1.18  2001/11/07 00:06:06  steudten
191  *    Add line number in error output for lineparsing for
192  *    actionsfile.
193  *
194  *    Revision 1.17  2001/10/25 03:40:47  david__schmidt
195  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
196  *    threads to call select() simultaneously.  So, it's time to do a real, live,
197  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
198  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
199  *
200  *    Revision 1.16  2001/10/23 21:30:30  jongfoster
201  *    Adding error-checking to selected functions.
202  *
203  *    Revision 1.15  2001/10/14 21:58:22  jongfoster
204  *    Adding support for the CGI-based editor:
205  *    - Exported get_actions()
206  *    - Added new function free_alias_list()
207  *    - Added support for {{settings}} and {{description}} blocks
208  *      in the actions file.  They are currently ignored.
209  *    - Added restriction to only one {{alias}} block which must appear
210  *      first in the file, to simplify the editor's rewriting rules.
211  *    - Note that load_actions_file() is no longer used by the CGI-based
212  *      editor, but some of the other routines in this file are.
213  *
214  *    Revision 1.14  2001/09/22 16:36:59  jongfoster
215  *    Removing unused parameter fs from read_config_line()
216  *
217  *    Revision 1.13  2001/09/16 15:47:37  jongfoster
218  *    First version of CGI-based edit interface.  This is very much a
219  *    work-in-progress, and you can't actually use it to edit anything
220  *    yet.  You must #define FEATURE_CGI_EDIT_ACTIONS for these changes
221  *    to have any effect.
222  *
223  *    Revision 1.12  2001/09/16 13:21:27  jongfoster
224  *    Changes to use new list functions.
225  *
226  *    Revision 1.11  2001/09/14 00:17:32  jongfoster
227  *    Tidying up memory allocation. New function init_action().
228  *
229  *    Revision 1.10  2001/09/10 10:14:34  oes
230  *    Removing unused variable
231  *
232  *    Revision 1.9  2001/07/30 22:08:36  jongfoster
233  *    Tidying up #defines:
234  *    - All feature #defines are now of the form FEATURE_xxx
235  *    - Permanently turned off WIN_GUI_EDIT
236  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
237  *
238  *    Revision 1.8  2001/06/29 13:19:52  oes
239  *    Removed logentry from cancelled commit
240  *
241  *    Revision 1.7  2001/06/09 10:55:28  jongfoster
242  *    Changing BUFSIZ ==> BUFFER_SIZE
243  *
244  *    Revision 1.6  2001/06/07 23:04:34  jongfoster
245  *    Made get_actions() static.
246  *
247  *    Revision 1.5  2001/06/03 19:11:48  oes
248  *    adapted to new enlist_unique arg format
249  *
250  *    Revision 1.4  2001/06/01 20:03:42  jongfoster
251  *    Better memory management - current_action->strings[] now
252  *    contains copies of the strings, not the original.
253  *
254  *    Revision 1.3  2001/06/01 18:49:17  jongfoster
255  *    Replaced "list_share" with "list" - the tiny memory gain was not
256  *    worth the extra complexity.
257  *
258  *    Revision 1.2  2001/05/31 21:40:00  jongfoster
259  *    Removing some commented out, obsolete blocks of code.
260  *
261  *    Revision 1.1  2001/05/31 21:16:46  jongfoster
262  *    Moved functions to process the action list into this new file.
263  *
264  *
265  *********************************************************************/
266 \f
267
268 #include "config.h"
269
270 #include <stdio.h>
271 #include <string.h>
272 #include <assert.h>
273 #include <stdlib.h>
274
275 #ifdef FEATURE_PTHREAD
276 #include <pthread.h>
277 #endif
278
279 #include "project.h"
280 #include "jcc.h"
281 #include "list.h"
282 #include "actions.h"
283 #include "miscutil.h"
284 #include "errlog.h"
285 #include "loaders.h"
286 #include "encode.h"
287 #include "urlmatch.h"
288 #include "cgi.h"
289 #include "ssplit.h"
290
291 const char actions_h_rcs[] = ACTIONS_H_VERSION;
292
293
294 /*
295  * We need the main list of options.
296  *
297  * First, we need a way to tell between boolean, string, and multi-string
298  * options.  For string and multistring options, we also need to be
299  * able to tell the difference between a "+" and a "-".  (For bools,
300  * the "+"/"-" information is encoded in "add" and "mask").  So we use
301  * an enumerated type (well, the preprocessor equivalent).  Here are
302  * the values:
303  */
304 #define AV_NONE       0 /* +opt -opt */
305 #define AV_ADD_STRING 1 /* +stropt{string} */
306 #define AV_REM_STRING 2 /* -stropt */
307 #define AV_ADD_MULTI  3 /* +multiopt{string} +multiopt{string2} */
308 #define AV_REM_MULTI  4 /* -multiopt{string} -multiopt          */
309
310 /*
311  * We need a structure to hold the name, flag changes,
312  * type, and string index.
313  */
314 struct action_name
315 {
316    const char * name;
317    unsigned long mask;   /* a bit set to "0" = remove action */
318    unsigned long add;    /* a bit set to "1" = add action */
319    int takes_value;      /* an AV_... constant */
320    int index;            /* index into strings[] or multi[] */
321 };
322
323 /*
324  * And with those building blocks in place, here's the array.
325  */
326 static const struct action_name action_names[] =
327 {
328    /*
329     * Well actually there's no data here - it's in actionlist.h
330     * This keeps it together to make it easy to change.
331     *
332     * Here's the macros used to format it:
333     */
334 #define DEFINE_ACTION_MULTI(name,index)                   \
335    { "+" name, ACTION_MASK_ALL, 0, AV_ADD_MULTI, index }, \
336    { "-" name, ACTION_MASK_ALL, 0, AV_REM_MULTI, index },
337 #define DEFINE_ACTION_STRING(name,flag,index)                 \
338    { "+" name, ACTION_MASK_ALL, flag, AV_ADD_STRING, index }, \
339    { "-" name, ~flag, 0, AV_REM_STRING, index },
340 #define DEFINE_ACTION_BOOL(name,flag)   \
341    { "+" name, ACTION_MASK_ALL, flag }, \
342    { "-" name, ~flag, 0 },
343 #define DEFINE_ACTION_ALIAS 1 /* Want aliases please */
344
345 #include "actionlist.h"
346
347 #undef DEFINE_ACTION_MULTI
348 #undef DEFINE_ACTION_STRING
349 #undef DEFINE_ACTION_BOOL
350 #undef DEFINE_ACTION_ALIAS
351
352    { NULL, 0, 0 } /* End marker */
353 };
354
355
356 static int load_one_actions_file(struct client_state *csp, int fileid);
357
358
359 /*********************************************************************
360  *
361  * Function    :  merge_actions
362  *
363  * Description :  Merge two actions together.
364  *                Similar to "dest += src".
365  *
366  * Parameters  :
367  *          1  :  dest = Actions to modify.
368  *          2  :  src = Action to add.
369  *
370  * Returns     :  JB_ERR_OK or JB_ERR_MEMORY
371  *
372  *********************************************************************/
373 jb_err merge_actions (struct action_spec *dest,
374                       const struct action_spec *src)
375 {
376    int i;
377    jb_err err;
378
379    dest->mask &= src->mask;
380    dest->add  &= src->mask;
381    dest->add  |= src->add;
382
383    for (i = 0; i < ACTION_STRING_COUNT; i++)
384    {
385       char * str = src->string[i];
386       if (str)
387       {
388          freez(dest->string[i]);
389          dest->string[i] = strdup(str);
390          if (NULL == dest->string[i])
391          {
392             return JB_ERR_MEMORY;
393          }
394       }
395    }
396
397    for (i = 0; i < ACTION_MULTI_COUNT; i++)
398    {
399       if (src->multi_remove_all[i])
400       {
401          /* Remove everything from dest */
402          list_remove_all(dest->multi_remove[i]);
403          dest->multi_remove_all[i] = 1;
404
405          err = list_duplicate(dest->multi_add[i], src->multi_add[i]);
406       }
407       else if (dest->multi_remove_all[i])
408       {
409          /*
410           * dest already removes everything, so we only need to worry
411           * about what we add.
412           */
413          list_remove_list(dest->multi_add[i], src->multi_remove[i]);
414          err = list_append_list_unique(dest->multi_add[i], src->multi_add[i]);
415       }
416       else
417       {
418          /* No "remove all"s to worry about. */
419          list_remove_list(dest->multi_add[i], src->multi_remove[i]);
420          err = list_append_list_unique(dest->multi_remove[i], src->multi_remove[i]);
421          if (!err) err = list_append_list_unique(dest->multi_add[i], src->multi_add[i]);
422       }
423
424       if (err)
425       {
426          return err;
427       }
428    }
429
430    return JB_ERR_OK;
431 }
432
433
434 /*********************************************************************
435  *
436  * Function    :  copy_action
437  *
438  * Description :  Copy an action_specs.
439  *                Similar to "dest = src".
440  *
441  * Parameters  :
442  *          1  :  dest = Destination of copy.
443  *          2  :  src = Source for copy.
444  *
445  * Returns     :  N/A
446  *
447  *********************************************************************/
448 jb_err copy_action (struct action_spec *dest,
449                     const struct action_spec *src)
450 {
451    int i;
452    jb_err err = JB_ERR_OK;
453
454    free_action(dest);
455    memset(dest, '\0', sizeof(*dest));
456
457    dest->mask = src->mask;
458    dest->add  = src->add;
459
460    for (i = 0; i < ACTION_STRING_COUNT; i++)
461    {
462       char * str = src->string[i];
463       if (str)
464       {
465          str = strdup(str);
466          if (!str)
467          {
468             return JB_ERR_MEMORY;
469          }
470          dest->string[i] = str;
471       }
472    }
473
474    for (i = 0; i < ACTION_MULTI_COUNT; i++)
475    {
476       dest->multi_remove_all[i] = src->multi_remove_all[i];
477       err = list_duplicate(dest->multi_remove[i], src->multi_remove[i]);
478       if (err)
479       {
480          return err;
481       }
482       err = list_duplicate(dest->multi_add[i],    src->multi_add[i]);
483       if (err)
484       {
485          return err;
486       }
487    }
488    return err;
489 }
490
491 /*********************************************************************
492  *
493  * Function    :  free_action_spec
494  *
495  * Description :  Frees an action_spec and the memory used by it.
496  *
497  * Parameters  :
498  *          1  :  src = Source to free.
499  *
500  * Returns     :  N/A
501  *
502  *********************************************************************/
503 void free_action_spec(struct action_spec *src)
504 {
505    free_action(src);
506    freez(src);
507 }
508
509
510 /*********************************************************************
511  *
512  * Function    :  free_action
513  *
514  * Description :  Destroy an action_spec.  Frees memory used by it,
515  *                except for the memory used by the struct action_spec
516  *                itself.
517  *
518  * Parameters  :
519  *          1  :  src = Source to free.
520  *
521  * Returns     :  N/A
522  *
523  *********************************************************************/
524 void free_action (struct action_spec *src)
525 {
526    int i;
527
528    if (src == NULL)
529    {
530       return;
531    }
532
533    for (i = 0; i < ACTION_STRING_COUNT; i++)
534    {
535       freez(src->string[i]);
536    }
537
538    for (i = 0; i < ACTION_MULTI_COUNT; i++)
539    {
540       destroy_list(src->multi_remove[i]);
541       destroy_list(src->multi_add[i]);
542    }
543
544    memset(src, '\0', sizeof(*src));
545 }
546
547
548 /*********************************************************************
549  *
550  * Function    :  get_action_token
551  *
552  * Description :  Parses a line for the first action.
553  *                Modifies it's input array, doesn't allocate memory.
554  *                e.g. given:
555  *                *line="  +abc{def}  -ghi "
556  *                Returns:
557  *                *line="  -ghi "
558  *                *name="+abc"
559  *                *value="def"
560  *
561  * Parameters  :
562  *          1  :  line = [in] The line containing the action.
563  *                       [out] Start of next action on line, or
564  *                       NULL if we reached the end of line before
565  *                       we found an action.
566  *          2  :  name = [out] Start of action name, null
567  *                       terminated.  NULL on EOL
568  *          3  :  value = [out] Start of action value, null
569  *                        terminated.  NULL if none or EOL.
570  *
571  * Returns     :  JB_ERR_OK => Ok
572  *                JB_ERR_PARSE => Mismatched {} (line was trashed anyway)
573  *
574  *********************************************************************/
575 jb_err get_action_token(char **line, char **name, char **value)
576 {
577    char * str = *line;
578    char ch;
579
580    /* set default returns */
581    *line = NULL;
582    *name = NULL;
583    *value = NULL;
584
585    /* Eat any leading whitespace */
586    while ((*str == ' ') || (*str == '\t'))
587    {
588       str++;
589    }
590
591    if (*str == '\0')
592    {
593       return 0;
594    }
595
596    if (*str == '{')
597    {
598       /* null name, just value is prohibited */
599       return JB_ERR_PARSE;
600    }
601
602    *name = str;
603
604    /* parse option */
605    while (((ch = *str) != '\0') &&
606           (ch != ' ') && (ch != '\t') && (ch != '{'))
607    {
608       if (ch == '}')
609       {
610          /* error, '}' without '{' */
611          return JB_ERR_PARSE;
612       }
613       str++;
614    }
615    *str = '\0';
616
617    if (ch != '{')
618    {
619       /* no value */
620       if (ch == '\0')
621       {
622          /* EOL - be careful not to run off buffer */
623          *line = str;
624       }
625       else
626       {
627          /* More to parse next time. */
628          *line = str + 1;
629       }
630       return JB_ERR_OK;
631    }
632
633    str++;
634    *value = str;
635
636    str = strchr(str, '}');
637    if (str == NULL)
638    {
639       /* error */
640       *value = NULL;
641       return JB_ERR_PARSE;
642    }
643
644    /* got value */
645    *str = '\0';
646    *line = str + 1;
647
648    chomp(*value);
649
650    return JB_ERR_OK;
651 }
652
653 /*********************************************************************
654  *
655  * Function    :  action_used_to_be_valid
656  *
657  * Description :  Checks if unrecognized actions were valid in earlier
658  *                releases.
659  *
660  * Parameters  :
661  *          1  :  action = The string containing the action to check.
662  *
663  * Returns     :  True if yes, otherwise false.
664  *
665  *********************************************************************/
666 static int action_used_to_be_valid(const char *action)
667 {
668    static const char *formerly_valid_actions[] = {
669       "inspect-jpegs",
670       "kill-popups",
671       "send-vanilla-wafer",
672       "send-wafer",
673       "treat-forbidden-connects-like-blocks",
674       "vanilla-wafer",
675       "wafer"
676    };
677    int i;
678
679    for (i = 0; i < SZ(formerly_valid_actions); i++)
680    {
681       if (0 == strcmpic(action, formerly_valid_actions[i]))
682       {
683          return TRUE;
684       }
685    }
686
687    return FALSE;
688 }
689
690 /*********************************************************************
691  *
692  * Function    :  get_actions
693  *
694  * Description :  Parses a list of actions.
695  *
696  * Parameters  :
697  *          1  :  line = The string containing the actions.
698  *                       Will be written to by this function.
699  *          2  :  alias_list = Custom alias list, or NULL for none.
700  *          3  :  cur_action = Where to store the action.  Caller
701  *                             allocates memory.
702  *
703  * Returns     :  JB_ERR_OK => Ok
704  *                JB_ERR_PARSE => Parse error (line was trashed anyway)
705  *                nonzero => Out of memory (line was trashed anyway)
706  *
707  *********************************************************************/
708 jb_err get_actions(char *line,
709                    struct action_alias * alias_list,
710                    struct action_spec *cur_action)
711 {
712    jb_err err;
713    init_action(cur_action);
714    cur_action->mask = ACTION_MASK_ALL;
715
716    while (line)
717    {
718       char * option = NULL;
719       char * value = NULL;
720
721       err = get_action_token(&line, &option, &value);
722       if (err)
723       {
724          return err;
725       }
726
727       if (option)
728       {
729          /* handle option in 'option' */
730
731          /* Check for standard action name */
732          const struct action_name * action = action_names;
733
734          while ( (action->name != NULL) && (0 != strcmpic(action->name, option)) )
735          {
736             action++;
737          }
738          if (action->name != NULL)
739          {
740             /* Found it */
741             cur_action->mask &= action->mask;
742             cur_action->add  &= action->mask;
743             cur_action->add  |= action->add;
744
745             switch (action->takes_value)
746             {
747             case AV_NONE:
748                /* ignore any option. */
749                break;
750             case AV_ADD_STRING:
751                {
752                   /* add single string. */
753
754                   if ((value == NULL) || (*value == '\0'))
755                   {
756                      if (0 != strcmpic(action->name, "block"))
757                      {
758                         /*
759                          * XXX: Temporary backwards compatibility hack.
760                          * XXX: should include line number.
761                          */
762                         value = "No reason specified.";
763                         log_error(LOG_LEVEL_ERROR, "block action without "
764                            "reason found. This may become a fatal error"
765                            "in future versions.");
766                      }
767                      else
768                      {
769                         return JB_ERR_PARSE;
770                      }
771                   }
772                   /* FIXME: should validate option string here */
773                   freez (cur_action->string[action->index]);
774                   cur_action->string[action->index] = strdup(value);
775                   if (NULL == cur_action->string[action->index])
776                   {
777                      return JB_ERR_MEMORY;
778                   }
779                   break;
780                }
781             case AV_REM_STRING:
782                {
783                   /* remove single string. */
784
785                   freez (cur_action->string[action->index]);
786                   break;
787                }
788             case AV_ADD_MULTI:
789                {
790                   /* append multi string. */
791
792                   struct list * remove_p = cur_action->multi_remove[action->index];
793                   struct list * add_p    = cur_action->multi_add[action->index];
794
795                   if ((value == NULL) || (*value == '\0'))
796                   {
797                      return JB_ERR_PARSE;
798                   }
799
800                   list_remove_item(remove_p, value);
801                   err = enlist_unique(add_p, value, 0);
802                   if (err)
803                   {
804                      return err;
805                   }
806                   break;
807                }
808             case AV_REM_MULTI:
809                {
810                   /* remove multi string. */
811
812                   struct list * remove_p = cur_action->multi_remove[action->index];
813                   struct list * add_p    = cur_action->multi_add[action->index];
814
815                   if ( (value == NULL) || (*value == '\0')
816                      || ((*value == '*') && (value[1] == '\0')) )
817                   {
818                      /*
819                       * no option, or option == "*".
820                       *
821                       * Remove *ALL*.
822                       */
823                      list_remove_all(remove_p);
824                      list_remove_all(add_p);
825                      cur_action->multi_remove_all[action->index] = 1;
826                   }
827                   else
828                   {
829                      /* Valid option - remove only 1 option */
830
831                      if ( !cur_action->multi_remove_all[action->index] )
832                      {
833                         /* there isn't a catch-all in the remove list already */
834                         err = enlist_unique(remove_p, value, 0);
835                         if (err)
836                         {
837                            return err;
838                         }
839                      }
840                      list_remove_item(add_p, value);
841                   }
842                   break;
843                }
844             default:
845                /* Shouldn't get here unless there's memory corruption. */
846                assert(0);
847                return JB_ERR_PARSE;
848             }
849          }
850          else
851          {
852             /* try user aliases. */
853             const struct action_alias * alias = alias_list;
854
855             while ( (alias != NULL) && (0 != strcmpic(alias->name, option)) )
856             {
857                alias = alias->next;
858             }
859             if (alias != NULL)
860             {
861                /* Found it */
862                merge_actions(cur_action, alias->action);
863             }
864             else if ((2 < strlen(option)) && action_used_to_be_valid(option+1))
865             {
866                log_error(LOG_LEVEL_ERROR, "Action '%s' is no longer valid "
867                   "in this Privoxy release. Ignored.", option+1);
868             }
869             else
870             {
871                /* Bad action name */
872                /*
873                 * XXX: This is a fatal error and Privoxy will later on exit
874                 * in load_one_actions_file() because of an "invalid line".
875                 *
876                 * It would be preferable to name the offending option in that
877                 * error message, but currently there is no way to do that and
878                 * we have to live with two error messages for basically the
879                 * same reason.
880                 */
881                log_error(LOG_LEVEL_ERROR, "Unknown action or alias: %s", option);
882                return JB_ERR_PARSE;
883             }
884          }
885       }
886    }
887
888    return JB_ERR_OK;
889 }
890
891
892 /*********************************************************************
893  *
894  * Function    :  init_current_action
895  *
896  * Description :  Zero out an action.
897  *
898  * Parameters  :
899  *          1  :  dest = An uninitialized current_action_spec.
900  *
901  * Returns     :  N/A
902  *
903  *********************************************************************/
904 void init_current_action (struct current_action_spec *dest)
905 {
906    memset(dest, '\0', sizeof(*dest));
907
908    dest->flags = ACTION_MOST_COMPATIBLE;
909 }
910
911
912 /*********************************************************************
913  *
914  * Function    :  init_action
915  *
916  * Description :  Zero out an action.
917  *
918  * Parameters  :
919  *          1  :  dest = An uninitialized action_spec.
920  *
921  * Returns     :  N/A
922  *
923  *********************************************************************/
924 void init_action (struct action_spec *dest)
925 {
926    memset(dest, '\0', sizeof(*dest));
927 }
928
929
930 /*********************************************************************
931  *
932  * Function    :  merge_current_action
933  *
934  * Description :  Merge two actions together.
935  *                Similar to "dest += src".
936  *                Differences between this and merge_actions()
937  *                is that this one doesn't allocate memory for
938  *                strings (so "src" better be in memory for at least
939  *                as long as "dest" is, and you'd better free
940  *                "dest" using "free_current_action").
941  *                Also, there is no  mask or remove lists in dest.
942  *                (If we're applying it to a URL, we don't need them)
943  *
944  * Parameters  :
945  *          1  :  dest = Current actions, to modify.
946  *          2  :  src = Action to add.
947  *
948  * Returns  0  :  no error
949  *        !=0  :  error, probably JB_ERR_MEMORY.
950  *
951  *********************************************************************/
952 jb_err merge_current_action (struct current_action_spec *dest,
953                              const struct action_spec *src)
954 {
955    int i;
956    jb_err err = JB_ERR_OK;
957
958    dest->flags  &= src->mask;
959    dest->flags  |= src->add;
960
961    for (i = 0; i < ACTION_STRING_COUNT; i++)
962    {
963       char * str = src->string[i];
964       if (str)
965       {
966          str = strdup(str);
967          if (!str)
968          {
969             return JB_ERR_MEMORY;
970          }
971          freez(dest->string[i]);
972          dest->string[i] = str;
973       }
974    }
975
976    for (i = 0; i < ACTION_MULTI_COUNT; i++)
977    {
978       if (src->multi_remove_all[i])
979       {
980          /* Remove everything from dest, then add src->multi_add */
981          err = list_duplicate(dest->multi[i], src->multi_add[i]);
982          if (err)
983          {
984             return err;
985          }
986       }
987       else
988       {
989          list_remove_list(dest->multi[i], src->multi_remove[i]);
990          err = list_append_list_unique(dest->multi[i], src->multi_add[i]);
991          if (err)
992          {
993             return err;
994          }
995       }
996    }
997    return err;
998 }
999
1000 #if 0
1001 /*********************************************************************
1002  *
1003  * Function    :  update_action_bits_for_all_tags
1004  *
1005  * Description :  Updates the action bits based on all matching tags.
1006  *
1007  * Parameters  :
1008  *          1  :  csp = Current client state (buffers, headers, etc...)
1009  *
1010  * Returns     :  0 if no tag matched, or
1011  *                1 otherwise
1012  *
1013  *********************************************************************/
1014 int update_action_bits_for_all_tags(struct client_state *csp)
1015 {
1016    struct list_entry *tag;
1017    int updated = 0;
1018
1019    for (tag = csp->tags->first; tag != NULL; tag = tag->next)
1020    {
1021       if (update_action_bits_for_tag(csp, tag->str))
1022       {
1023          updated = 1;
1024       }
1025    }
1026
1027    return updated;
1028 }
1029 #endif
1030
1031 /*********************************************************************
1032  *
1033  * Function    :  update_action_bits_for_tag
1034  *
1035  * Description :  Updates the action bits based on the action sections
1036  *                whose tag patterns match a provided tag.
1037  *
1038  * Parameters  :
1039  *          1  :  csp = Current client state (buffers, headers, etc...)
1040  *          2  :  tag = The tag on which the update should be based on
1041  *
1042  * Returns     :  0 if no tag matched, or
1043  *                1 otherwise
1044  *
1045  *********************************************************************/
1046 int update_action_bits_for_tag(struct client_state *csp, const char *tag)
1047 {
1048    struct file_list *fl;
1049    struct url_actions *b;
1050
1051    int updated = 0;
1052    int i;
1053
1054    assert(tag);
1055    assert(list_contains_item(csp->tags, tag));
1056
1057    /* Run through all action files, */
1058    for (i = 0; i < MAX_AF_FILES; i++)
1059    {
1060       if (((fl = csp->actions_list[i]) == NULL) || ((b = fl->f) == NULL))
1061       {
1062          /* Skip empty files */
1063          continue;
1064       }
1065
1066       /* and through all the action patterns, */
1067       for (b = b->next; NULL != b; b = b->next)
1068       {
1069          /* skip the URL patterns, */
1070          if (NULL == b->url->tag_regex)
1071          {
1072             continue;
1073          }
1074
1075          /* and check if one of the tag patterns matches the tag, */
1076          if (0 == regexec(b->url->tag_regex, tag, 0, NULL, 0))
1077          {
1078             /* if it does, update the action bit map, */
1079             if (merge_current_action(csp->action, b->action))
1080             {
1081                log_error(LOG_LEVEL_ERROR,
1082                   "Out of memorey while changing action bits");
1083             }
1084             /* and signal the change. */
1085             updated = 1;
1086          }
1087       }
1088    }
1089
1090    return updated;
1091 }
1092
1093
1094 /*********************************************************************
1095  *
1096  * Function    :  free_current_action
1097  *
1098  * Description :  Free memory used by a current_action_spec.
1099  *                Does not free the current_action_spec itself.
1100  *
1101  * Parameters  :
1102  *          1  :  src = Source to free.
1103  *
1104  * Returns     :  N/A
1105  *
1106  *********************************************************************/
1107 void free_current_action (struct current_action_spec *src)
1108 {
1109    int i;
1110
1111    for (i = 0; i < ACTION_STRING_COUNT; i++)
1112    {
1113       freez(src->string[i]);
1114    }
1115
1116    for (i = 0; i < ACTION_MULTI_COUNT; i++)
1117    {
1118       destroy_list(src->multi[i]);
1119    }
1120
1121    memset(src, '\0', sizeof(*src));
1122 }
1123
1124
1125 static struct file_list *current_actions_file[MAX_AF_FILES]  = {
1126    NULL, NULL, NULL, NULL, NULL,
1127    NULL, NULL, NULL, NULL, NULL
1128 };
1129
1130
1131 #ifdef FEATURE_GRACEFUL_TERMINATION
1132 /*********************************************************************
1133  *
1134  * Function    :  unload_current_actions_file
1135  *
1136  * Description :  Unloads current actions file - reset to state at
1137  *                beginning of program.
1138  *
1139  * Parameters  :  None
1140  *
1141  * Returns     :  N/A
1142  *
1143  *********************************************************************/
1144 void unload_current_actions_file(void)
1145 {
1146    int i;
1147
1148    for (i = 0; i < MAX_AF_FILES; i++)
1149    {
1150       if (current_actions_file[i])
1151       {
1152          current_actions_file[i]->unloader = unload_actions_file;
1153          current_actions_file[i] = NULL;
1154       }
1155    }
1156 }
1157 #endif /* FEATURE_GRACEFUL_TERMINATION */
1158
1159
1160 /*********************************************************************
1161  *
1162  * Function    :  unload_actions_file
1163  *
1164  * Description :  Unloads an actions module.
1165  *
1166  * Parameters  :
1167  *          1  :  file_data = the data structure associated with the
1168  *                            actions file.
1169  *
1170  * Returns     :  N/A
1171  *
1172  *********************************************************************/
1173 void unload_actions_file(void *file_data)
1174 {
1175    struct url_actions * next;
1176    struct url_actions * cur = (struct url_actions *)file_data;
1177    while (cur != NULL)
1178    {
1179       next = cur->next;
1180       free_url_spec(cur->url);
1181       if ((next == NULL) || (next->action != cur->action))
1182       {
1183          /*
1184           * As the action settings might be shared,
1185           * we can only free them if the current
1186           * url pattern is the last one, or if the
1187           * next one is using different settings.
1188           */
1189          free_action_spec(cur->action);
1190       }
1191       freez(cur);
1192       cur = next;
1193    }
1194 }
1195
1196
1197 /*********************************************************************
1198  *
1199  * Function    :  free_alias_list
1200  *
1201  * Description :  Free memory used by a list of aliases.
1202  *
1203  * Parameters  :
1204  *          1  :  alias_list = Linked list to free.
1205  *
1206  * Returns     :  N/A
1207  *
1208  *********************************************************************/
1209 void free_alias_list(struct action_alias *alias_list)
1210 {
1211    while (alias_list != NULL)
1212    {
1213       struct action_alias * next = alias_list->next;
1214       alias_list->next = NULL;
1215       freez(alias_list->name);
1216       free_action(alias_list->action);
1217       free(alias_list);
1218       alias_list = next;
1219    }
1220 }
1221
1222
1223 /*********************************************************************
1224  *
1225  * Function    :  load_action_files
1226  *
1227  * Description :  Read and parse all the action files and add to files
1228  *                list.
1229  *
1230  * Parameters  :
1231  *          1  :  csp = Current client state (buffers, headers, etc...)
1232  *
1233  * Returns     :  0 => Ok, everything else is an error.
1234  *
1235  *********************************************************************/
1236 int load_action_files(struct client_state *csp)
1237 {
1238    int i;
1239    int result;
1240
1241    for (i = 0; i < MAX_AF_FILES; i++)
1242    {
1243       if (csp->config->actions_file[i])
1244       {
1245          result = load_one_actions_file(csp, i);
1246          if (result)
1247          {
1248             return result;
1249          }
1250       }
1251       else if (current_actions_file[i])
1252       {
1253          current_actions_file[i]->unloader = unload_actions_file;
1254          current_actions_file[i] = NULL;
1255       }
1256    }
1257
1258    return 0;
1259 }
1260
1261 /*********************************************************************
1262  *
1263  * Function    :  load_one_actions_file
1264  *
1265  * Description :  Read and parse a action file and add to files
1266  *                list.
1267  *
1268  * Parameters  :
1269  *          1  :  csp = Current client state (buffers, headers, etc...)
1270  *          2  :  fileid = File index to load.
1271  *
1272  * Returns     :  0 => Ok, everything else is an error.
1273  *
1274  *********************************************************************/
1275 static int load_one_actions_file(struct client_state *csp, int fileid)
1276 {
1277
1278    /*
1279     * Parser mode.
1280     * Note: Keep these in the order they occur in the file, they are
1281     * sometimes tested with <=
1282     */
1283 #define MODE_START_OF_FILE 1
1284 #define MODE_SETTINGS      2
1285 #define MODE_DESCRIPTION   3
1286 #define MODE_ALIAS         4
1287 #define MODE_ACTIONS       5
1288
1289    int mode = MODE_START_OF_FILE;
1290
1291    FILE *fp;
1292    struct url_actions *last_perm;
1293    struct url_actions *perm;
1294    char  buf[BUFFER_SIZE];
1295    struct file_list *fs;
1296    struct action_spec * cur_action = NULL;
1297    int cur_action_used = 0;
1298    struct action_alias * alias_list = NULL;
1299    unsigned long linenum = 0;
1300
1301    if (!check_file_changed(current_actions_file[fileid], csp->config->actions_file[fileid], &fs))
1302    {
1303       /* No need to load */
1304       csp->actions_list[fileid] = current_actions_file[fileid];
1305       return 0;
1306    }
1307    if (!fs)
1308    {
1309       log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': %E. "
1310          "Note that beginning with Privoxy 3.0.7, actions files have to be specified "
1311          "with their complete file names.", csp->config->actions_file[fileid]);
1312       return 1; /* never get here */
1313    }
1314
1315    fs->f = last_perm = (struct url_actions *)zalloc(sizeof(*last_perm));
1316    if (last_perm == NULL)
1317    {
1318       log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': out of memory!",
1319                 csp->config->actions_file[fileid]);
1320       return 1; /* never get here */
1321    }
1322
1323    if ((fp = fopen(csp->config->actions_file[fileid], "r")) == NULL)
1324    {
1325       log_error(LOG_LEVEL_FATAL, "can't load actions file '%s': error opening file: %E",
1326                 csp->config->actions_file[fileid]);
1327       return 1; /* never get here */
1328    }
1329
1330    while (read_config_line(buf, sizeof(buf), fp, &linenum) != NULL)
1331    {
1332       if (*buf == '{')
1333       {
1334          /* It's a header block */
1335          if (buf[1] == '{')
1336          {
1337             /* It's {{settings}} or {{alias}} */
1338             size_t len = strlen(buf);
1339             char * start = buf + 2;
1340             char * end = buf + len - 1;
1341             if ((len < 5) || (*end-- != '}') || (*end-- != '}'))
1342             {
1343                /* too short */
1344                fclose(fp);
1345                log_error(LOG_LEVEL_FATAL,
1346                   "can't load actions file '%s': invalid line (%lu): %s", 
1347                   csp->config->actions_file[fileid], linenum, buf);
1348                return 1; /* never get here */
1349             }
1350
1351             /* Trim leading and trailing whitespace. */
1352             end[1] = '\0';
1353             chomp(start);
1354
1355             if (*start == '\0')
1356             {
1357                /* too short */
1358                fclose(fp);
1359                log_error(LOG_LEVEL_FATAL,
1360                   "can't load actions file '%s': invalid line (%lu): {{ }}",
1361                   csp->config->actions_file[fileid], linenum);
1362                return 1; /* never get here */
1363             }
1364
1365             /*
1366              * An actionsfile can optionally contain the following blocks.
1367              * They *MUST* be in this order, to simplify processing:
1368              *
1369              * {{settings}}
1370              * name=value...
1371              *
1372              * {{description}}
1373              * ...free text, format TBD, but no line may start with a '{'...
1374              *
1375              * {{alias}}
1376              * name=actions...
1377              *
1378              * The actual actions must be *after* these special blocks.
1379              * None of these special blocks may be repeated.
1380              *
1381              */
1382             if (0 == strcmpic(start, "settings"))
1383             {
1384                /* it's a {{settings}} block */
1385                if (mode >= MODE_SETTINGS)
1386                {
1387                   /* {{settings}} must be first thing in file and must only
1388                    * appear once.
1389                    */
1390                   fclose(fp);
1391                   log_error(LOG_LEVEL_FATAL,
1392                      "can't load actions file '%s': line %lu: {{settings}} must only appear once, and it must be before anything else.",
1393                      csp->config->actions_file[fileid], linenum);
1394                }
1395                mode = MODE_SETTINGS;
1396             }
1397             else if (0 == strcmpic(start, "description"))
1398             {
1399                /* it's a {{description}} block */
1400                if (mode >= MODE_DESCRIPTION)
1401                {
1402                   /* {{description}} is a singleton and only {{settings}} may proceed it
1403                    */
1404                   fclose(fp);
1405                   log_error(LOG_LEVEL_FATAL,
1406                      "can't load actions file '%s': line %lu: {{description}} must only appear once, and only a {{settings}} block may be above it.",
1407                      csp->config->actions_file[fileid], linenum);
1408                }
1409                mode = MODE_DESCRIPTION;
1410             }
1411             else if (0 == strcmpic(start, "alias"))
1412             {
1413                /* it's an {{alias}} block */
1414                if (mode >= MODE_ALIAS)
1415                {
1416                   /* {{alias}} must be first thing in file, possibly after
1417                    * {{settings}} and {{description}}
1418                    *
1419                    * {{alias}} must only appear once.
1420                    *
1421                    * Note that these are new restrictions introduced in
1422                    * v2.9.10 in order to make actionsfile editing simpler.
1423                    * (Otherwise, reordering actionsfile entries without
1424                    * completely rewriting the file becomes non-trivial)
1425                    */
1426                   fclose(fp);
1427                   log_error(LOG_LEVEL_FATAL,
1428                      "can't load actions file '%s': line %lu: {{alias}} must only appear once, and it must be before all actions.",
1429                      csp->config->actions_file[fileid], linenum);
1430                }
1431                mode = MODE_ALIAS;
1432             }
1433             else
1434             {
1435                /* invalid {{something}} block */
1436                fclose(fp);
1437                log_error(LOG_LEVEL_FATAL,
1438                   "can't load actions file '%s': invalid line (%lu): {{%s}}",
1439                   csp->config->actions_file[fileid], linenum, start);
1440                return 1; /* never get here */
1441             }
1442          }
1443          else
1444          {
1445             /* It's an actions block */
1446
1447             char  actions_buf[BUFFER_SIZE];
1448             char * end;
1449
1450             /* set mode */
1451             mode    = MODE_ACTIONS;
1452
1453             /* free old action */
1454             if (cur_action)
1455             {
1456                if (!cur_action_used)
1457                {
1458                   free_action_spec(cur_action);
1459                }
1460                cur_action = NULL;
1461             }
1462             cur_action_used = 0;
1463             cur_action = (struct action_spec *)zalloc(sizeof(*cur_action));
1464             if (cur_action == NULL)
1465             {
1466                fclose(fp);
1467                log_error(LOG_LEVEL_FATAL,
1468                   "can't load actions file '%s': out of memory",
1469                   csp->config->actions_file[fileid]);
1470                return 1; /* never get here */
1471             }
1472             init_action(cur_action);
1473
1474             /* trim { */
1475             strlcpy(actions_buf, buf + 1, sizeof(actions_buf));
1476
1477             /* check we have a trailing } and then trim it */
1478             end = actions_buf + strlen(actions_buf) - 1;
1479             if (*end != '}')
1480             {
1481                /* No closing } */
1482                fclose(fp);
1483                log_error(LOG_LEVEL_FATAL,
1484                   "can't load actions file '%s': invalid line (%lu): %s",
1485                   csp->config->actions_file[fileid], linenum, buf);
1486                return 1; /* never get here */
1487             }
1488             *end = '\0';
1489
1490             /* trim any whitespace immediately inside {} */
1491             chomp(actions_buf);
1492
1493             if (get_actions(actions_buf, alias_list, cur_action))
1494             {
1495                /* error */
1496                fclose(fp);
1497                log_error(LOG_LEVEL_FATAL,
1498                   "can't load actions file '%s': invalid line (%lu): %s",
1499                   csp->config->actions_file[fileid], linenum, buf);
1500                return 1; /* never get here */
1501             }
1502          }
1503       }
1504       else if (mode == MODE_SETTINGS)
1505       {
1506          /*
1507           * Part of the {{settings}} block.
1508           * For now only serves to check if the file's minimum Privoxy
1509           * version requirement is met, but we may want to read & check
1510           * permissions when we go multi-user.
1511           */
1512          if (!strncmp(buf, "for-privoxy-version=", 20))
1513          {
1514             char *version_string, *fields[3];
1515             int num_fields;
1516
1517             if ((version_string = strdup(buf + 20)) == NULL)
1518             {
1519                fclose(fp);
1520                log_error(LOG_LEVEL_FATAL,
1521                          "can't load actions file '%s': out of memory!",
1522                          csp->config->actions_file[fileid]);
1523                return 1; /* never get here */
1524             }
1525             
1526             num_fields = ssplit(version_string, ".", fields, 3, TRUE, FALSE);
1527
1528             if (num_fields < 1 || atoi(fields[0]) == 0)
1529             {
1530                log_error(LOG_LEVEL_ERROR,
1531                  "While loading actions file '%s': invalid line (%lu): %s",
1532                   csp->config->actions_file[fileid], linenum, buf);
1533             }
1534             else if (                      atoi(fields[0]) > VERSION_MAJOR
1535                      || (num_fields > 1 && atoi(fields[1]) > VERSION_MINOR)
1536                      || (num_fields > 2 && atoi(fields[2]) > VERSION_POINT))
1537             {
1538                fclose(fp);
1539                log_error(LOG_LEVEL_FATAL,
1540                          "Actions file '%s', line %lu requires newer Privoxy version: %s",
1541                          csp->config->actions_file[fileid], linenum, buf );
1542                return 1; /* never get here */
1543             }
1544             free(version_string);
1545          }
1546       }
1547       else if (mode == MODE_DESCRIPTION)
1548       {
1549          /*
1550           * Part of the {{description}} block.
1551           * Ignore for now.
1552           */
1553       }
1554       else if (mode == MODE_ALIAS)
1555       {
1556          /*
1557           * define an alias
1558           */
1559          char  actions_buf[BUFFER_SIZE];
1560          struct action_alias * new_alias;
1561
1562          char * start = strchr(buf, '=');
1563          char * end = start;
1564
1565          if ((start == NULL) || (start == buf))
1566          {
1567             log_error(LOG_LEVEL_FATAL,
1568                "can't load actions file '%s': invalid alias line (%lu): %s",
1569                csp->config->actions_file[fileid], linenum, buf);
1570             return 1; /* never get here */
1571          }
1572
1573          if ((new_alias = zalloc(sizeof(*new_alias))) == NULL)
1574          {
1575             fclose(fp);
1576             log_error(LOG_LEVEL_FATAL,
1577                "can't load actions file '%s': out of memory!",
1578                csp->config->actions_file[fileid]);
1579             return 1; /* never get here */
1580          }
1581
1582          /* Eat any the whitespace before the '=' */
1583          end--;
1584          while ((*end == ' ') || (*end == '\t'))
1585          {
1586             /*
1587              * we already know we must have at least 1 non-ws char
1588              * at start of buf - no need to check
1589              */
1590             end--;
1591          }
1592          end[1] = '\0';
1593
1594          /* Eat any the whitespace after the '=' */
1595          start++;
1596          while ((*start == ' ') || (*start == '\t'))
1597          {
1598             start++;
1599          }
1600          if (*start == '\0')
1601          {
1602             log_error(LOG_LEVEL_FATAL,
1603                "can't load actions file '%s': invalid alias line (%lu): %s",
1604                csp->config->actions_file[fileid], linenum, buf);
1605             return 1; /* never get here */
1606          }
1607
1608          if ((new_alias->name = strdup(buf)) == NULL)
1609          {
1610             fclose(fp);
1611             log_error(LOG_LEVEL_FATAL,
1612                "can't load actions file '%s': out of memory!",
1613                csp->config->actions_file[fileid]);
1614             return 1; /* never get here */
1615          }
1616
1617          strlcpy(actions_buf, start, sizeof(actions_buf));
1618
1619          if (get_actions(actions_buf, alias_list, new_alias->action))
1620          {
1621             /* error */
1622             fclose(fp);
1623             log_error(LOG_LEVEL_FATAL,
1624                "can't load actions file '%s': invalid alias line (%lu): %s = %s",
1625                csp->config->actions_file[fileid], linenum, buf, start);
1626             return 1; /* never get here */
1627          }
1628
1629          /* add to list */
1630          new_alias->next = alias_list;
1631          alias_list = new_alias;
1632       }
1633       else if (mode == MODE_ACTIONS)
1634       {
1635          /* it's a URL pattern */
1636
1637          /* allocate a new node */
1638          if ((perm = zalloc(sizeof(*perm))) == NULL)
1639          {
1640             fclose(fp);
1641             log_error(LOG_LEVEL_FATAL,
1642                "can't load actions file '%s': out of memory!",
1643                csp->config->actions_file[fileid]);
1644             return 1; /* never get here */
1645          }
1646
1647          perm->action = cur_action;
1648          cur_action_used = 1;
1649
1650          /* Save the URL pattern */
1651          if (create_url_spec(perm->url, buf))
1652          {
1653             fclose(fp);
1654             log_error(LOG_LEVEL_FATAL,
1655                "can't load actions file '%s': line %lu: cannot create URL pattern from: %s",
1656                csp->config->actions_file[fileid], linenum, buf);
1657             return 1; /* never get here */
1658          }
1659
1660          /* add it to the list */
1661          last_perm->next = perm;
1662          last_perm = perm;
1663       }
1664       else if (mode == MODE_START_OF_FILE)
1665       {
1666          /* oops - please have a {} line as 1st line in file. */
1667          fclose(fp);
1668          log_error(LOG_LEVEL_FATAL,
1669             "can't load actions file '%s': first needed line (%lu) is invalid: %s",
1670             csp->config->actions_file[fileid], linenum, buf);
1671          return 1; /* never get here */
1672       }
1673       else
1674       {
1675          /* How did we get here? This is impossible! */
1676          fclose(fp);
1677          log_error(LOG_LEVEL_FATAL,
1678             "can't load actions file '%s': INTERNAL ERROR - mode = %d",
1679             csp->config->actions_file[fileid], mode);
1680          return 1; /* never get here */
1681       }
1682    }
1683
1684    fclose(fp);
1685
1686    if (!cur_action_used)
1687    {
1688       free_action_spec(cur_action);
1689    }
1690    free_alias_list(alias_list);
1691
1692    /* the old one is now obsolete */
1693    if (current_actions_file[fileid])
1694    {
1695       current_actions_file[fileid]->unloader = unload_actions_file;
1696    }
1697
1698    fs->next    = files->next;
1699    files->next = fs;
1700    current_actions_file[fileid] = fs;
1701
1702    csp->actions_list[fileid] = fs;
1703
1704    return(0);
1705
1706 }
1707
1708
1709 /*********************************************************************
1710  *
1711  * Function    :  actions_to_text
1712  *
1713  * Description :  Converts a actionsfile entry from the internal
1714  *                structure into a text line.  The output is split
1715  *                into one line for each action with line continuation. 
1716  *
1717  * Parameters  :
1718  *          1  :  action = The action to format.
1719  *
1720  * Returns     :  A string.  Caller must free it.
1721  *                NULL on out-of-memory error.
1722  *
1723  *********************************************************************/
1724 char * actions_to_text(const struct action_spec *action)
1725 {
1726    unsigned mask = action->mask;
1727    unsigned add  = action->add;
1728    char * result = strdup("");
1729    struct list_entry * lst;
1730
1731    /* sanity - prevents "-feature +feature" */
1732    mask |= add;
1733
1734
1735 #define DEFINE_ACTION_BOOL(__name, __bit)          \
1736    if (!(mask & __bit))                            \
1737    {                                               \
1738       string_append(&result, " -" __name " \\\n"); \
1739    }                                               \
1740    else if (add & __bit)                           \
1741    {                                               \
1742       string_append(&result, " +" __name " \\\n"); \
1743    }
1744
1745 #define DEFINE_ACTION_STRING(__name, __bit, __index)   \
1746    if (!(mask & __bit))                                \
1747    {                                                   \
1748       string_append(&result, " -" __name " \\\n");     \
1749    }                                                   \
1750    else if (add & __bit)                               \
1751    {                                                   \
1752       string_append(&result, " +" __name "{");         \
1753       string_append(&result, action->string[__index]); \
1754       string_append(&result, "} \\\n");                \
1755    }
1756
1757 #define DEFINE_ACTION_MULTI(__name, __index)         \
1758    if (action->multi_remove_all[__index])            \
1759    {                                                 \
1760       string_append(&result, " -" __name " \\\n");   \
1761    }                                                 \
1762    else                                              \
1763    {                                                 \
1764       lst = action->multi_remove[__index]->first;    \
1765       while (lst)                                    \
1766       {                                              \
1767          string_append(&result, " -" __name "{");    \
1768          string_append(&result, lst->str);           \
1769          string_append(&result, "} \\\n");           \
1770          lst = lst->next;                            \
1771       }                                              \
1772    }                                                 \
1773    lst = action->multi_add[__index]->first;          \
1774    while (lst)                                       \
1775    {                                                 \
1776       string_append(&result, " +" __name "{");       \
1777       string_append(&result, lst->str);              \
1778       string_append(&result, "} \\\n");              \
1779       lst = lst->next;                               \
1780    }
1781
1782 #define DEFINE_ACTION_ALIAS 0 /* No aliases for output */
1783
1784 #include "actionlist.h"
1785
1786 #undef DEFINE_ACTION_MULTI
1787 #undef DEFINE_ACTION_STRING
1788 #undef DEFINE_ACTION_BOOL
1789 #undef DEFINE_ACTION_ALIAS
1790
1791    return result;
1792 }
1793
1794
1795 /*********************************************************************
1796  *
1797  * Function    :  actions_to_html
1798  *
1799  * Description :  Converts a actionsfile entry from numeric form
1800  *                ("mask" and "add") to a <br>-seperated HTML string
1801  *                in which each action is linked to its chapter in
1802  *                the user manual.
1803  *
1804  * Parameters  :
1805  *          1  :  csp    = Client state (for config)
1806  *          2  :  action = Action spec to be converted
1807  *
1808  * Returns     :  A string.  Caller must free it.
1809  *                NULL on out-of-memory error.
1810  *
1811  *********************************************************************/
1812 char * actions_to_html(const struct client_state *csp,
1813                        const struct action_spec *action)
1814 {
1815    unsigned mask = action->mask;
1816    unsigned add  = action->add;
1817    char * result = strdup("");
1818    struct list_entry * lst;
1819
1820    /* sanity - prevents "-feature +feature" */
1821    mask |= add;
1822
1823
1824 #define DEFINE_ACTION_BOOL(__name, __bit)       \
1825    if (!(mask & __bit))                         \
1826    {                                            \
1827       string_append(&result, "\n<br>-");        \
1828       string_join(&result, add_help_link(__name, csp->config)); \
1829    }                                            \
1830    else if (add & __bit)                        \
1831    {                                            \
1832       string_append(&result, "\n<br>+");        \
1833       string_join(&result, add_help_link(__name, csp->config)); \
1834    }
1835
1836 #define DEFINE_ACTION_STRING(__name, __bit, __index) \
1837    if (!(mask & __bit))                              \
1838    {                                                 \
1839       string_append(&result, "\n<br>-");             \
1840       string_join(&result, add_help_link(__name, csp->config)); \
1841    }                                                 \
1842    else if (add & __bit)                             \
1843    {                                                 \
1844       string_append(&result, "\n<br>+");             \
1845       string_join(&result, add_help_link(__name, csp->config)); \
1846       string_append(&result, "{");                   \
1847       string_join(&result, html_encode(action->string[__index])); \
1848       string_append(&result, "}");                   \
1849    }
1850
1851 #define DEFINE_ACTION_MULTI(__name, __index)          \
1852    if (action->multi_remove_all[__index])             \
1853    {                                                  \
1854       string_append(&result, "\n<br>-");              \
1855       string_join(&result, add_help_link(__name, csp->config)); \
1856    }                                                  \
1857    else                                               \
1858    {                                                  \
1859       lst = action->multi_remove[__index]->first;     \
1860       while (lst)                                     \
1861       {                                               \
1862          string_append(&result, "\n<br>-");           \
1863          string_join(&result, add_help_link(__name, csp->config)); \
1864          string_append(&result, "{");                 \
1865          string_join(&result, html_encode(lst->str)); \
1866          string_append(&result, "}");                 \
1867          lst = lst->next;                             \
1868       }                                               \
1869    }                                                  \
1870    lst = action->multi_add[__index]->first;           \
1871    while (lst)                                        \
1872    {                                                  \
1873       string_append(&result, "\n<br>+");              \
1874       string_join(&result, add_help_link(__name, csp->config)); \
1875       string_append(&result, "{");                    \
1876       string_join(&result, html_encode(lst->str));    \
1877       string_append(&result, "}");                    \
1878       lst = lst->next;                                \
1879    }
1880
1881 #define DEFINE_ACTION_ALIAS 0 /* No aliases for output */
1882
1883 #include "actionlist.h"
1884
1885 #undef DEFINE_ACTION_MULTI
1886 #undef DEFINE_ACTION_STRING
1887 #undef DEFINE_ACTION_BOOL
1888 #undef DEFINE_ACTION_ALIAS
1889
1890    /* trim leading <br> */
1891    if (result && *result)
1892    {
1893       char * s = result;
1894       result = strdup(result + 5);
1895       free(s);
1896    }
1897
1898    return result;
1899 }
1900
1901
1902 /*********************************************************************
1903  *
1904  * Function    :  current_actions_to_html
1905  *
1906  * Description :  Converts a curren action spec to a <br> seperated HTML
1907  *                text in which each action is linked to its chapter in
1908  *                the user manual.
1909  *
1910  * Parameters  :
1911  *          1  :  csp    = Client state (for config) 
1912  *          2  :  action = Current action spec to be converted
1913  *
1914  * Returns     :  A string.  Caller must free it.
1915  *                NULL on out-of-memory error.
1916  *
1917  *********************************************************************/
1918 char *current_action_to_html(const struct client_state *csp,
1919                              const struct current_action_spec *action)
1920 {
1921    unsigned long flags  = action->flags;
1922    struct list_entry * lst;
1923    char *result   = strdup("");
1924    char *active   = strdup("");
1925    char *inactive = strdup("");
1926
1927 #define DEFINE_ACTION_BOOL(__name, __bit)  \
1928    if (flags & __bit)                      \
1929    {                                       \
1930       string_append(&active, "\n<br>+");   \
1931       string_join(&active, add_help_link(__name, csp->config)); \
1932    }                                       \
1933    else                                    \
1934    {                                       \
1935       string_append(&inactive, "\n<br>-"); \
1936       string_join(&inactive, add_help_link(__name, csp->config)); \
1937    }
1938
1939 #define DEFINE_ACTION_STRING(__name, __bit, __index)   \
1940    if (flags & __bit)                                  \
1941    {                                                   \
1942       string_append(&active, "\n<br>+");               \
1943       string_join(&active, add_help_link(__name, csp->config)); \
1944       string_append(&active, "{");                     \
1945       string_join(&active, html_encode(action->string[__index])); \
1946       string_append(&active, "}");                     \
1947    }                                                   \
1948    else                                                \
1949    {                                                   \
1950       string_append(&inactive, "\n<br>-");             \
1951       string_join(&inactive, add_help_link(__name, csp->config)); \
1952    }
1953
1954 #define DEFINE_ACTION_MULTI(__name, __index)           \
1955    lst = action->multi[__index]->first;                \
1956    if (lst == NULL)                                    \
1957    {                                                   \
1958       string_append(&inactive, "\n<br>-");             \
1959       string_join(&inactive, add_help_link(__name, csp->config)); \
1960    }                                                   \
1961    else                                                \
1962    {                                                   \
1963       while (lst)                                      \
1964       {                                                \
1965          string_append(&active, "\n<br>+");            \
1966          string_join(&active, add_help_link(__name, csp->config)); \
1967          string_append(&active, "{");                  \
1968          string_join(&active, html_encode(lst->str));  \
1969          string_append(&active, "}");                  \
1970          lst = lst->next;                              \
1971       }                                                \
1972    }
1973
1974 #define DEFINE_ACTION_ALIAS 0 /* No aliases for output */
1975
1976 #include "actionlist.h"
1977
1978 #undef DEFINE_ACTION_MULTI
1979 #undef DEFINE_ACTION_STRING
1980 #undef DEFINE_ACTION_BOOL
1981 #undef DEFINE_ACTION_ALIAS
1982
1983    if (active != NULL)
1984    {
1985       string_append(&result, active);
1986       freez(active);
1987    }
1988    string_append(&result, "\n<br>");
1989    if (inactive != NULL)
1990    {
1991       string_append(&result, inactive);
1992       freez(inactive);
1993    }
1994    return result;
1995 }