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