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