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