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