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