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