Introduce dynamic pcrs jobs that can resolve variables.
[privoxy.git] / loaders.c
1 const char loaders_rcs[] = "$Id: loaders.c,v 1.61 2007/04/15 16:39:21 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/loaders.c,v $
5  *
6  * Purpose     :  Functions to load and unload the various
7  *                configuration files.  Also contains code to manage
8  *                the list of active loaders, and to automatically
9  *                unload files that are no longer in use.
10  *
11  * Copyright   :  Written by and Copyright (C) 2001-2007 the SourceForge
12  *                Privoxy team. http://www.privoxy.org/
13  *
14  *                Based on the Internet Junkbuster originally written
15  *                by and Copyright (C) 1997 Anonymous Coders and
16  *                Junkbusters Corporation.  http://www.junkbusters.com
17  *
18  *                This program is free software; you can redistribute it
19  *                and/or modify it under the terms of the GNU General
20  *                Public License as published by the Free Software
21  *                Foundation; either version 2 of the License, or (at
22  *                your option) any later version.
23  *
24  *                This program is distributed in the hope that it will
25  *                be useful, but WITHOUT ANY WARRANTY; without even the
26  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
27  *                PARTICULAR PURPOSE.  See the GNU General Public
28  *                License for more details.
29  *
30  *                The GNU General Public License should be included with
31  *                this file.  If not, you can view it at
32  *                http://www.gnu.org/copyleft/gpl.html
33  *                or write to the Free Software Foundation, Inc., 59
34  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
35  *
36  * Revisions   :
37  *    $Log: loaders.c,v $
38  *    Revision 1.61  2007/04/15 16:39:21  fabiankeil
39  *    Introduce tags as alternative way to specify which
40  *    actions apply to a request. At the moment tags can be
41  *    created based on client and server headers.
42  *
43  *    Revision 1.60  2007/03/20 15:16:34  fabiankeil
44  *    Use dedicated header filter actions instead of abusing "filter".
45  *    Replace "filter-client-headers" and "filter-client-headers"
46  *    with "server-header-filter" and "client-header-filter".
47  *
48  *    Revision 1.59  2007/01/25 13:38:20  fabiankeil
49  *    Freez csp->error_message in sweep().
50  *
51  *    Revision 1.58  2006/12/31 14:25:20  fabiankeil
52  *    Fix gcc43 compiler warnings.
53  *
54  *    Revision 1.57  2006/12/21 12:22:22  fabiankeil
55  *    html_encode filter descriptions.
56  *
57  *    Have "Ignoring job ..." error messages
58  *    print the filter file name correctly.
59  *
60  *    Revision 1.56  2006/09/07 10:40:30  fabiankeil
61  *    Turns out trusted referrers above our arbitrary
62  *    limit are downgraded too ordinary trusted URLs.
63  *    Adjusted error message.
64  *
65  *    Revision 1.55  2006/09/07 10:25:39  fabiankeil
66  *    Fix typo.
67  *
68  *    Revision 1.54  2006/09/07 10:22:20  fabiankeil
69  *    If too many trusted referrers are used,
70  *    print only one error message instead of logging
71  *    every single trusted referrer above the arbitrary
72  *    limit.
73  *
74  *    Revision 1.53  2006/08/31 16:25:06  fabiankeil
75  *    Work around a buffer overflow that caused Privoxy to
76  *    segfault if too many trusted referrers were used. Good
77  *    enough for now, but should be replaced with a real
78  *    solution after the next release.
79  *
80  *    Revision 1.52  2006/07/18 14:48:46  david__schmidt
81  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
82  *    with what was really the latest development (the v_3_0_branch branch)
83  *
84  *    Revision 1.50.2.8  2006/01/30 15:16:25  david__schmidt
85  *    Remove a little residual debugging info
86  *
87  *    Revision 1.50.2.7  2006/01/29 23:10:56  david__schmidt
88  *    Multiple filter file support
89  *
90  *    Revision 1.50.2.6  2003/10/24 10:17:54  oes
91  *    Nit: Allowed tabs as separators in filter headings
92  *
93  *    Revision 1.50.2.5  2003/05/08 15:19:15  oes
94  *    sweep: Made loop structure of sweep step mirror that of mark step
95  *
96  *    Revision 1.50.2.4  2003/05/06 15:57:12  oes
97  *    Bugfix: Update last_active pointer in sweep() before
98  *    leaving an active client. Closes bugs #724395, #727882
99  *
100  *    Revision 1.50.2.3  2002/11/20 17:12:30  oes
101  *    Ooops, forgot one change.
102  *
103  *    Revision 1.50.2.2  2002/11/20 14:38:15  oes
104  *    Fixed delayed/incomplete freeing of client resources and
105  *    simplified loop structure in sweep.
106  *    Thanks to Oliver Stoeneberg for the hint.
107  *
108  *    Revision 1.50.2.1  2002/07/26 15:19:24  oes
109  *    - PCRS jobs now chained in order of appearance. Previous
110  *      reverse chaining was counter-intuitive.
111  *    - Changed loglevel of PCRS job compile errors to
112  *      LOG_LEVEL_ERROR
113  *
114  *    Revision 1.50  2002/04/24 02:12:16  oes
115  *    Jon's multiple AF patch: Sweep now takes care of all AFs
116  *
117  *    Revision 1.49  2002/04/19 16:53:25  jongfoster
118  *    Optimize away a function call by using an equivalent macro
119  *
120  *    Revision 1.48  2002/04/05 00:56:09  gliptak
121  *    Correcting typo to clean up on realloc failure
122  *
123  *    Revision 1.47  2002/03/26 22:29:55  swa
124  *    we have a new homepage!
125  *
126  *    Revision 1.46  2002/03/24 13:25:43  swa
127  *    name change related issues
128  *
129  *    Revision 1.45  2002/03/16 23:54:06  jongfoster
130  *    Adding graceful termination feature, to help look for memory leaks.
131  *    If you enable this (which, by design, has to be done by hand
132  *    editing config.h) and then go to http://i.j.b/die, then the program
133  *    will exit cleanly after the *next* request.  It should free all the
134  *    memory that was used.
135  *
136  *    Revision 1.44  2002/03/16 21:51:00  jongfoster
137  *    Fixing free(NULL).
138  *
139  *    Revision 1.43  2002/03/16 20:28:34  oes
140  *    Added descriptions to the filters so users will know what they select in the cgi editor
141  *
142  *    Revision 1.42  2002/03/13 00:27:05  jongfoster
143  *    Killing warnings
144  *
145  *    Revision 1.41  2002/03/12 01:42:50  oes
146  *    Introduced modular filters
147  *
148  *    Revision 1.40  2002/03/08 17:46:04  jongfoster
149  *    Fixing int/size_t warnings
150  *
151  *    Revision 1.39  2002/03/07 03:46:17  oes
152  *    Fixed compiler warnings
153  *
154  *    Revision 1.38  2002/03/06 22:54:35  jongfoster
155  *    Automated function-comment nitpicking.
156  *
157  *    Revision 1.37  2002/03/03 15:07:49  oes
158  *    Re-enabled automatic config reloading
159  *
160  *    Revision 1.36  2002/01/22 23:46:18  jongfoster
161  *    Moving edit_read_line() and simple_read_line() to loaders.c, and
162  *    extending them to support reading MS-DOS, Mac and UNIX style files
163  *    on all platforms.
164  *
165  *    Modifying read_config_line() (without changing it's prototype) to
166  *    be a trivial wrapper for edit_read_line().  This means that we have
167  *    one function to read a line and handle comments, which is common
168  *    between the initialization code and the edit interface.
169  *
170  *    Revision 1.35  2002/01/17 21:03:08  jongfoster
171  *    Moving all our URL and URL pattern parsing code to urlmatch.c.
172  *
173  *    Renaming free_url to free_url_spec, since it frees a struct url_spec.
174  *
175  *    Revision 1.34  2001/12/30 14:07:32  steudten
176  *    - Add signal handling (unix)
177  *    - Add SIGHUP handler (unix)
178  *    - Add creation of pidfile (unix)
179  *    - Add action 'top' in rc file (RH)
180  *    - Add entry 'SIGNALS' to manpage
181  *    - Add exit message to logfile (unix)
182  *
183  *    Revision 1.33  2001/11/13 00:16:38  jongfoster
184  *    Replacing references to malloc.h with the standard stdlib.h
185  *    (See ANSI or K&R 2nd Ed)
186  *
187  *    Revision 1.32  2001/11/07 00:02:13  steudten
188  *    Add line number in error output for lineparsing for
189  *    actionsfile and configfile.
190  *    Special handling for CLF added.
191  *
192  *    Revision 1.31  2001/10/26 17:39:01  oes
193  *    Removed csp->referrer
194  *    Moved ijb_isspace and ijb_tolower to project.h
195  *
196  *    Revision 1.30  2001/10/25 03:40:48  david__schmidt
197  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
198  *    threads to call select() simultaneously.  So, it's time to do a real, live,
199  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
200  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
201  *
202  *    Revision 1.29  2001/10/23 21:38:53  jongfoster
203  *    Adding error-checking to create_url_spec()
204  *
205  *    Revision 1.28  2001/10/07 15:40:39  oes
206  *    Replaced 6 boolean members of csp with one bitmap (csp->flags)
207  *
208  *    Revision 1.27  2001/09/22 16:36:59  jongfoster
209  *    Removing unused parameter fs from read_config_line()
210  *
211  *    Revision 1.26  2001/09/22 14:05:22  jongfoster
212  *    Bugfix: Multiple escaped "#" characters in a configuration
213  *    file are now permitted.
214  *    Also removing 3 unused headers.
215  *
216  *    Revision 1.25  2001/09/13 22:44:03  jongfoster
217  *    Adding {} to an if statement
218  *
219  *    Revision 1.24  2001/07/30 22:08:36  jongfoster
220  *    Tidying up #defines:
221  *    - All feature #defines are now of the form FEATURE_xxx
222  *    - Permanently turned off WIN_GUI_EDIT
223  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
224  *
225  *    Revision 1.23  2001/07/20 15:51:54  oes
226  *    Fixed indentation of prepocessor commands
227  *
228  *    Revision 1.22  2001/07/20 15:16:17  haroon
229  *    - per Guy's suggestion, added a while loop in sweep() to catch not just
230  *      the last inactive CSP but all other consecutive inactive CSPs after that
231  *      as well
232  *
233  *    Revision 1.21  2001/07/18 17:26:24  oes
234  *    Changed to conform to new pcrs interface
235  *
236  *    Revision 1.20  2001/07/17 13:07:01  oes
237  *    Fixed segv when last line in config files
238  *     lacked a terminating (\r)\n
239  *
240  *    Revision 1.19  2001/07/13 14:01:54  oes
241  *    Removed all #ifdef PCRS
242  *
243  *    Revision 1.18  2001/06/29 21:45:41  oes
244  *    Indentation, CRLF->LF, Tab-> Space
245  *
246  *    Revision 1.17  2001/06/29 13:31:51  oes
247  *    Various adaptions
248  *
249  *    Revision 1.16  2001/06/09 10:55:28  jongfoster
250  *    Changing BUFSIZ ==> BUFFER_SIZE
251  *
252  *    Revision 1.15  2001/06/07 23:14:14  jongfoster
253  *    Removing ACL and forward file loaders - these
254  *    files have been merged into the config file.
255  *    Cosmetic: Moving unloader funcs next to their
256  *    respective loader funcs
257  *
258  *    Revision 1.14  2001/06/01 03:27:04  oes
259  *    Fixed line continuation problem
260  *
261  *    Revision 1.13  2001/05/31 21:28:49  jongfoster
262  *    Removed all permissionsfile code - it's now called the actions
263  *    file, and (almost) all the code is in actions.c
264  *
265  *    Revision 1.12  2001/05/31 17:32:31  oes
266  *
267  *     - Enhanced domain part globbing with infix and prefix asterisk
268  *       matching and optional unanchored operation
269  *
270  *    Revision 1.11  2001/05/29 23:25:24  oes
271  *
272  *     - load_config_line() and load_permissions_file() now use chomp()
273  *
274  *    Revision 1.10  2001/05/29 09:50:24  jongfoster
275  *    Unified blocklist/imagelist/permissionslist.
276  *    File format is still under discussion, but the internal changes
277  *    are (mostly) done.
278  *
279  *    Also modified interceptor behaviour:
280  *    - We now intercept all URLs beginning with one of the following
281  *      prefixes (and *only* these prefixes):
282  *        * http://i.j.b/
283  *        * http://ijbswa.sf.net/config/
284  *        * http://ijbswa.sourceforge.net/config/
285  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
286  *    - Internal changes so that intercepted and fast redirect pages
287  *      are not replaced with an image.
288  *    - Interceptors now have the option to send a binary page direct
289  *      to the client. (i.e. ijb-send-banner uses this)
290  *    - Implemented show-url-info interceptor.  (Which is why I needed
291  *      the above interceptors changes - a typical URL is
292  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
293  *      The previous mechanism would not have intercepted that, and
294  *      if it had been intercepted then it then it would have replaced
295  *      it with an image.)
296  *
297  *    Revision 1.9  2001/05/26 17:12:07  jongfoster
298  *    Fatal errors loading configuration files now give better error messages.
299  *
300  *    Revision 1.8  2001/05/26 00:55:20  jongfoster
301  *    Removing duplicated code.  load_forwardfile() now uses create_url_spec()
302  *
303  *    Revision 1.7  2001/05/26 00:28:36  jongfoster
304  *    Automatic reloading of config file.
305  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
306  *    Most of the global variables have been moved to a new
307  *    struct configuration_spec, accessed through csp->config->globalname
308  *    Most of the globals remaining are used by the Win32 GUI.
309  *
310  *    Revision 1.6  2001/05/23 12:27:33  oes
311  *
312  *    Fixed ugly indentation of my last changes
313  *
314  *    Revision 1.5  2001/05/23 10:39:05  oes
315  *    - Added support for escaping the comment character
316  *      in config files by a backslash
317  *    - Added support for line continuation in config
318  *      files
319  *    - Fixed a buffer overflow bug with long config lines
320  *
321  *    Revision 1.4  2001/05/22 18:56:28  oes
322  *    CRLF -> LF
323  *
324  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
325  *    Version 2.9.4 checkin.
326  *    - Merged popupfile and cookiefile, and added control over PCRS
327  *      filtering, in new "permissionsfile".
328  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
329  *      file error you now get a message box (in the Win32 GUI) rather
330  *      than the program exiting with no explanation.
331  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
332  *      skipping.
333  *    - Removed tabs from "config"
334  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
335  *    - Bumped up version number.
336  *
337  *    Revision 1.2  2001/05/17 23:01:01  oes
338  *     - Cleaned CRLF's from the sources and related files
339  *
340  *    Revision 1.1.1.1  2001/05/15 13:58:59  oes
341  *    Initial import of version 2.9.3 source tree
342  *
343  *
344  *********************************************************************/
345 \f
346
347 #include "config.h"
348
349 #include <stdio.h>
350 #include <stdlib.h>
351 #include <sys/types.h>
352 #include <string.h>
353 #include <errno.h>
354 #include <sys/stat.h>
355 #include <ctype.h>
356 #include <assert.h>
357
358 #if !defined(_WIN32) && !defined(__OS2__)
359 #include <unistd.h>
360 #endif
361
362 #include "project.h"
363 #include "list.h"
364 #include "loaders.h"
365 #include "filters.h"
366 #include "parsers.h"
367 #include "jcc.h"
368 #include "miscutil.h"
369 #include "errlog.h"
370 #include "actions.h"
371 #include "urlmatch.h"
372 #include "encode.h"
373
374 const char loaders_h_rcs[] = LOADERS_H_VERSION;
375
376 /*
377  * Currently active files.
378  * These are also entered in the main linked list of files.
379  */
380
381 #ifdef FEATURE_TRUST
382 static struct file_list *current_trustfile      = NULL;
383 #endif /* def FEATURE_TRUST */
384
385 static int load_one_re_filterfile(struct client_state *csp, int fileid);
386
387 static struct file_list *current_re_filterfile[MAX_AF_FILES]  = {
388    NULL, NULL, NULL, NULL, NULL,
389    NULL, NULL, NULL, NULL, NULL
390 };
391
392 /*
393  * Pseudo filter type for load_one_re_filterfile
394  */
395 #define NO_NEW_FILTER -1
396
397
398 /*********************************************************************
399  *
400  * Function    :  sweep
401  *
402  * Description :  Basically a mark and sweep garbage collector, it is run
403  *                (by the parent thread) every once in a while to reclaim memory.
404  *
405  * It uses a mark and sweep strategy:
406  *   1) mark all files as inactive
407  *
408  *   2) check with each client:
409  *       if it is active,   mark its files as active
410  *       if it is inactive, free its resources
411  *
412  *   3) free the resources of all of the files that
413  *      are still marked as inactive (and are obsolete).
414  *
415  *   N.B. files that are not obsolete don't have an unloader defined.
416  *
417  * Parameters  :  None
418  *
419  * Returns     :  N/A
420  *
421  *********************************************************************/
422 void sweep(void)
423 {
424    struct file_list *fl, *nfl;
425    struct client_state *csp, *last_active;
426    int i;
427
428    /* clear all of the file's active flags */
429    for ( fl = files->next; NULL != fl; fl = fl->next )
430    {
431       fl->active = 0;
432    }
433
434    last_active = clients;
435    csp = clients->next;
436
437    while (NULL != csp)
438    {
439       if (csp->flags & CSP_FLAG_ACTIVE)
440       {
441          /* Mark this client's files as active */
442
443          /*
444           * Always have a configuration file.
445           * (Also note the slightly non-standard extra
446           * indirection here.)
447           */
448          csp->config->config_file_list->active = 1;
449
450          /* 
451           * Actions files
452           */
453          for (i = 0; i < MAX_AF_FILES; i++)
454          {
455             if (csp->actions_list[i])     
456             {
457                csp->actions_list[i]->active = 1;
458             }
459          }
460
461          /*
462           * Filter files
463           */
464          for (i = 0; i < MAX_AF_FILES; i++)
465          {
466             if (csp->rlist[i])     
467             {
468                csp->rlist[i]->active = 1;
469             }
470          }
471
472          /*
473           * Trust file
474           */
475 #ifdef FEATURE_TRUST
476          if (csp->tlist)
477          {
478             csp->tlist->active = 1;
479          }
480 #endif /* def FEATURE_TRUST */
481          
482          last_active = csp;
483          csp = csp->next;
484
485       }
486       else 
487       /*
488        * This client is not active. Free its resources.
489        */
490       {
491          last_active->next = csp->next;
492
493          freez(csp->ip_addr_str);
494          freez(csp->my_ip_addr_str);
495          freez(csp->my_hostname);
496          freez(csp->x_forwarded);
497          freez(csp->iob->buf);
498          freez(csp->error_message);
499
500          free_http_request(csp->http);
501
502          destroy_list(csp->headers);
503          destroy_list(csp->tags);
504          destroy_list(csp->cookie_list);
505
506          free_current_action(csp->action);
507
508 #ifdef FEATURE_STATISTICS
509          urls_read++;
510          if (csp->flags & CSP_FLAG_REJECTED)
511          {
512             urls_rejected++;
513          }
514 #endif /* def FEATURE_STATISTICS */
515
516          freez(csp);
517          
518          csp = last_active->next;
519       }
520    }
521
522    nfl = files;
523    fl = files->next;
524
525    while (fl != NULL)
526    {
527       if ( ( 0 == fl->active ) && ( NULL != fl->unloader ) )
528       {
529          nfl->next = fl->next;
530
531          (fl->unloader)(fl->f);
532
533          freez(fl->filename);
534          freez(fl);
535
536          fl = nfl->next;
537       }
538       else
539       {
540          nfl = fl;
541          fl = fl->next;
542       }
543    }
544
545 }
546
547
548 /*********************************************************************
549  *
550  * Function    :  check_file_changed
551  *
552  * Description :  Helper function to check if a file needs reloading.
553  *                If "current" is still current, return it.  Otherwise
554  *                allocates a new (zeroed) "struct file_list", fills
555  *                in the disk file name and timestamp, and returns it.
556  *
557  * Parameters  :
558  *          1  :  current = The file_list currently being used - will
559  *                          be checked to see if it is out of date.
560  *                          May be NULL (which is treated as out of
561  *                          date).
562  *          2  :  filename = Name of file to check.
563  *          3  :  newfl    = New file list. [Output only]
564  *                           This will be set to NULL, OR a struct
565  *                           file_list newly allocated on the
566  *                           heap, with the filename and lastmodified
567  *                           fields filled, and all others zeroed.
568  *
569  * Returns     :  If file unchanged: 0 (and sets newfl == NULL)
570  *                If file changed: 1 and sets newfl != NULL
571  *                On error: 1 and sets newfl == NULL
572  *
573  *********************************************************************/
574 int check_file_changed(const struct file_list * current,
575                        const char * filename,
576                        struct file_list ** newfl)
577 {
578    struct file_list *fs;
579    struct stat statbuf[1];
580
581    *newfl = NULL;
582
583    if (stat(filename, statbuf) < 0)
584    {
585       /* Error, probably file not found. */
586       return 1;
587    }
588
589    if (current
590        && (current->lastmodified == statbuf->st_mtime)
591        && (0 == strcmp(current->filename, filename)))
592    {
593       return 0;
594    }
595
596    fs = (struct file_list *)zalloc(sizeof(struct file_list));
597    if (fs == NULL)
598    {
599       /* Out of memory error */
600       return 1;
601    }
602
603
604    fs->filename = strdup(filename);
605    fs->lastmodified = statbuf->st_mtime;
606
607    if (fs->filename == NULL)
608    {
609       /* Out of memory error */
610       freez (fs);
611       return 1;
612    }
613    *newfl = fs;
614    return 1;
615 }
616
617
618 /*********************************************************************
619  *
620  * Function    :  simple_read_line
621  *
622  * Description :  Read a single line from a file and return it.
623  *                This is basically a version of fgets() that malloc()s
624  *                it's own line buffer.  Note that the buffer will
625  *                always be a multiple of BUFFER_SIZE bytes long.
626  *                Therefore if you are going to keep the string for
627  *                an extended period of time, you should probably
628  *                strdup() it and free() the original, to save memory.
629  *
630  *
631  * Parameters  :
632  *          1  :  dest = destination for newly malloc'd pointer to
633  *                line data.  Will be set to NULL on error.
634  *          2  :  fp = File to read from
635  *          3  :  newline = Standard for newlines in the file.
636  *                Will be unchanged if it's value on input is not
637  *                NEWLINE_UNKNOWN.
638  *                On output, may be changed from NEWLINE_UNKNOWN to
639  *                actual convention in file.
640  *
641  * Returns     :  JB_ERR_OK     on success
642  *                JB_ERR_MEMORY on out-of-memory
643  *                JB_ERR_FILE   on EOF.
644  *
645  *********************************************************************/
646 jb_err simple_read_line(FILE *fp, char **dest, int *newline)
647 {
648    size_t len = 0;
649    size_t buflen = BUFFER_SIZE;
650    char * buf;
651    char * p;
652    int ch;
653    int realnewline = NEWLINE_UNKNOWN;
654
655    if (NULL == (buf = malloc(buflen)))
656    {
657       return JB_ERR_MEMORY;
658    }
659
660    p = buf;
661
662 /*
663  * Character codes.  If you have a wierd compiler and the following are
664  * incorrect, you also need to fix NEWLINE() in loaders.h
665  */
666 #define CHAR_CR '\r' /* ASCII 13 */
667 #define CHAR_LF '\n' /* ASCII 10 */
668
669    for (;;)
670    {
671       ch = getc(fp);
672       if (ch == EOF)
673       {
674          if (len > 0)
675          {
676             *p = '\0';
677             *dest = buf;
678             return JB_ERR_OK;
679          }
680          else
681          {
682             free(buf);
683             *dest = NULL;
684             return JB_ERR_FILE;
685          }
686       }
687       else if (ch == CHAR_CR)
688       {
689          ch = getc(fp);
690          if (ch == CHAR_LF)
691          {
692             if (*newline == NEWLINE_UNKNOWN)
693             {
694                *newline = NEWLINE_DOS;
695             }
696          }
697          else
698          {
699             if (ch != EOF)
700             {
701                ungetc(ch, fp);
702             }
703             if (*newline == NEWLINE_UNKNOWN)
704             {
705                *newline = NEWLINE_MAC;
706             }
707          }
708          *p = '\0';
709          *dest = buf;
710          if (*newline == NEWLINE_UNKNOWN)
711          {
712             *newline = realnewline;
713          }
714          return JB_ERR_OK;
715       }
716       else if (ch == CHAR_LF)
717       {
718          *p = '\0';
719          *dest = buf;
720          if (*newline == NEWLINE_UNKNOWN)
721          {
722             *newline = NEWLINE_UNIX;
723          }
724          return JB_ERR_OK;
725       }
726       else if (ch == 0)
727       {
728          *p = '\0';
729          *dest = buf;
730          return JB_ERR_OK;
731       }
732
733       *p++ = (char)ch;
734
735       if (++len >= buflen)
736       {
737          buflen += BUFFER_SIZE;
738          if (NULL == (p = realloc(buf, buflen)))
739          {
740             free(buf);
741             return JB_ERR_MEMORY;
742          }
743          buf = p;
744          p = buf + len;
745       }
746    }
747 }
748
749
750 /*********************************************************************
751  *
752  * Function    :  edit_read_line
753  *
754  * Description :  Read a single non-empty line from a file and return
755  *                it.  Trims comments, leading and trailing whitespace
756  *                and respects escaping of newline and comment char.
757  *                Provides the line in 2 alternative forms: raw and
758  *                preprocessed.
759  *                - raw is the raw data read from the file.  If the
760  *                  line is not modified, then this should be written
761  *                  to the new file.
762  *                - prefix is any comments and blank lines that were
763  *                  read from the file.  If the line is modified, then
764  *                  this should be written out to the file followed
765  *                  by the modified data.  (If this string is non-empty
766  *                  then it will have a newline at the end).
767  *                - data is the actual data that will be parsed
768  *                  further by appropriate routines.
769  *                On EOF, the 3 strings will all be set to NULL and
770  *                0 will be returned.
771  *
772  * Parameters  :
773  *          1  :  fp = File to read from
774  *          2  :  raw_out = destination for newly malloc'd pointer to
775  *                raw line data.  May be NULL if you don't want it.
776  *          3  :  prefix_out = destination for newly malloc'd pointer to
777  *                comments.  May be NULL if you don't want it.
778  *          4  :  data_out = destination for newly malloc'd pointer to
779  *                line data with comments and leading/trailing spaces
780  *                removed, and line continuation performed.  May be
781  *                NULL if you don't want it.
782  *          5  :  newline = Standard for newlines in the file.
783  *                On input, set to value to use or NEWLINE_UNKNOWN.
784  *                On output, may be changed from NEWLINE_UNKNOWN to
785  *                actual convention in file.  May be NULL if you
786  *                don't want it.
787  *          6  :  line_number = Line number in file.  In "lines" as
788  *                reported by a text editor, not lines containing data.
789  *
790  * Returns     :  JB_ERR_OK     on success
791  *                JB_ERR_MEMORY on out-of-memory
792  *                JB_ERR_FILE   on EOF.
793  *
794  *********************************************************************/
795 jb_err edit_read_line(FILE *fp,
796                       char **raw_out,
797                       char **prefix_out,
798                       char **data_out,
799                       int *newline,
800                       unsigned long *line_number)
801 {
802    char *p;          /* Temporary pointer   */
803    char *linebuf;    /* Line read from file */
804    char *linestart;  /* Start of linebuf, usually first non-whitespace char */
805    int contflag = 0; /* Nonzero for line continuation - i.e. line ends '\' */
806    int is_empty = 1; /* Flag if not got any data yet */
807    char *raw    = NULL; /* String to be stored in raw_out    */
808    char *prefix = NULL; /* String to be stored in prefix_out */
809    char *data   = NULL; /* String to be stored in data_out   */
810    int scrapnewline;    /* Used for (*newline) if newline==NULL */
811    jb_err rval = JB_ERR_OK;
812
813    assert(fp);
814    assert(raw_out || data_out);
815    assert(newline == NULL
816        || *newline == NEWLINE_UNKNOWN
817        || *newline == NEWLINE_UNIX
818        || *newline == NEWLINE_DOS
819        || *newline == NEWLINE_MAC);
820
821    if (newline == NULL)
822    {
823       scrapnewline = NEWLINE_UNKNOWN;
824       newline = &scrapnewline;
825    }
826
827    /* Set output parameters to NULL */
828    if (raw_out)
829    {
830       *raw_out    = NULL;
831    }
832    if (prefix_out)
833    {
834       *prefix_out = NULL;
835    }
836    if (data_out)
837    {
838       *data_out   = NULL;
839    }
840
841    /* Set string variables to new, empty strings. */
842
843    if (raw_out)
844    {
845       if ((raw = malloc(1)) == NULL)
846       {
847          return JB_ERR_MEMORY;
848       }
849       *raw = '\0';
850    }
851    if (prefix_out)
852    {
853       if ((prefix = malloc(1)) == NULL)
854       {
855          freez(raw);
856          return JB_ERR_MEMORY;
857       }
858       *prefix = '\0';
859    }
860    if (data_out)
861    {
862       if ((data = malloc(1)) == NULL)
863       {
864          freez(raw);
865          freez(prefix);
866          return JB_ERR_MEMORY;
867       }
868       *data = '\0';
869    }
870
871    /* Main loop.  Loop while we need more data & it's not EOF. */
872
873    while ( (contflag || is_empty)
874         && (JB_ERR_OK == (rval = simple_read_line(fp, &linebuf, newline))))
875    {
876       if (line_number)
877       {
878          (*line_number)++;
879       }
880       if (raw)
881       {
882          string_append(&raw,linebuf);
883          if (string_append(&raw,NEWLINE(*newline)))
884          {
885             freez(prefix);
886             freez(data);
887             free(linebuf);
888             return JB_ERR_MEMORY;
889          }
890       }
891
892       /* Line continuation? Trim escape and set flag. */
893       p = linebuf + strlen(linebuf) - 1;
894       contflag = ((*linebuf != '\0') && (*p == '\\'));
895       if (contflag)
896       {
897          *p = '\0';
898       }
899
900       /* Trim leading spaces if we're at the start of the line */
901       linestart = linebuf;
902       if (*data == '\0')
903       {
904          /* Trim leading spaces */
905          while (*linestart && isspace((int)(unsigned char)*linestart))
906          {
907             linestart++;
908          }
909       }
910
911       /* Handle comment characters. */
912       p = linestart;
913       while ((p = strchr(p, '#')) != NULL)
914       {
915          /* Found a comment char.. */
916          if ((p != linebuf) && (*(p-1) == '\\'))
917          {
918             /* ..and it's escaped, left-shift the line over the escape. */
919             char *q = p - 1;
920             while ((*q = *(q + 1)) != '\0')
921             {
922                q++;
923             }
924             /* Now scan from just after the "#". */
925          }
926          else
927          {
928             /* Real comment.  Save it... */
929             if (p == linestart)
930             {
931                /* Special case:  Line only contains a comment, so all the
932                 * previous whitespace is considered part of the comment.
933                 * Undo the whitespace skipping, if any.
934                 */
935                linestart = linebuf;
936                p = linestart;
937             }
938             if (prefix)
939             {
940                string_append(&prefix,p);
941                if (string_append(&prefix, NEWLINE(*newline)))
942                {
943                   freez(raw);
944                   freez(data);
945                   free(linebuf);
946                   return JB_ERR_MEMORY;
947                }
948             }
949
950             /* ... and chop off the rest of the line */
951             *p = '\0';
952          }
953       } /* END while (there's a # character) */
954
955       /* Write to the buffer */
956       if (*linestart)
957       {
958          is_empty = 0;
959          if (data)
960          {
961             if (string_append(&data, linestart))
962             {
963                freez(raw);
964                freez(prefix);
965                free(linebuf);
966                return JB_ERR_MEMORY;
967             }
968          }
969       }
970
971       free(linebuf);
972    } /* END while(we need more data) */
973
974    /* Handle simple_read_line() errors - ignore EOF */
975    if ((rval != JB_ERR_OK) && (rval != JB_ERR_FILE))
976    {
977       freez(raw);
978       freez(prefix);
979       freez(data);
980       return rval;
981    }
982
983    if (raw ? (*raw == '\0') : is_empty)
984    {
985       /* EOF and no data there.  (Definition of "data" depends on whether
986        * the caller cares about "raw" or just "data").
987        */
988
989       freez(raw);
990       freez(prefix);
991       freez(data);
992
993       return JB_ERR_FILE;
994    }
995    else
996    {
997       /* Got at least some data */
998
999       /* Remove trailing whitespace */
1000       chomp(data);
1001
1002       if (raw_out)
1003       {
1004          *raw_out    = raw;
1005       }
1006       else
1007       {
1008          freez(raw);
1009       }
1010       if (prefix_out)
1011       {
1012          *prefix_out = prefix;
1013       }
1014       else
1015       {
1016          freez(prefix);
1017       }
1018       if (data_out)
1019       {
1020          *data_out   = data;
1021       }
1022       else
1023       {
1024          freez(data);
1025       }
1026       return JB_ERR_OK;
1027    }
1028 }
1029
1030
1031 /*********************************************************************
1032  *
1033  * Function    :  read_config_line
1034  *
1035  * Description :  Read a single non-empty line from a file and return
1036  *                it.  Trims comments, leading and trailing whitespace
1037  *                and respects escaping of newline and comment char.
1038  *
1039  * Parameters  :
1040  *          1  :  buf = Buffer to use.
1041  *          2  :  buflen = Size of buffer in bytes.
1042  *          3  :  fp = File to read from
1043  *          4  :  linenum = linenumber in file
1044  *
1045  * Returns     :  NULL on EOF or error
1046  *                Otherwise, returns buf.
1047  *
1048  *********************************************************************/
1049 char *read_config_line(char *buf, size_t buflen, FILE *fp, unsigned long *linenum)
1050 {
1051    jb_err err;
1052    char *buf2 = NULL;
1053    err = edit_read_line(fp, NULL, NULL, &buf2, NULL, linenum);
1054    if (err)
1055    {
1056       if (err == JB_ERR_MEMORY)
1057       {
1058          log_error(LOG_LEVEL_FATAL, "Out of memory loading a config file");
1059       }
1060       return NULL;
1061    }
1062    else
1063    {
1064       assert(buf2);
1065       assert(strlen(buf2) + 1U < buflen);
1066       strncpy(buf, buf2, buflen - 1);
1067       free(buf2);
1068       buf[buflen - 1] = '\0';
1069       return buf;
1070    }
1071 }
1072
1073
1074 #ifdef FEATURE_TRUST
1075 /*********************************************************************
1076  *
1077  * Function    :  unload_trustfile
1078  *
1079  * Description :  Unloads a trustfile.
1080  *
1081  * Parameters  :
1082  *          1  :  f = the data structure associated with the trustfile.
1083  *
1084  * Returns     :  N/A
1085  *
1086  *********************************************************************/
1087 static void unload_trustfile(void *f)
1088 {
1089    struct block_spec *cur = (struct block_spec *)f;
1090    struct block_spec *next;
1091
1092    while (cur != NULL)
1093    {
1094       next = cur->next;
1095
1096       free_url_spec(cur->url);
1097       free(cur);
1098
1099       cur = next;
1100    }
1101
1102 }
1103
1104
1105 #ifdef FEATURE_GRACEFUL_TERMINATION
1106 /*********************************************************************
1107  *
1108  * Function    :  unload_current_trust_file
1109  *
1110  * Description :  Unloads current trust file - reset to state at
1111  *                beginning of program.
1112  *
1113  * Parameters  :  None
1114  *
1115  * Returns     :  N/A
1116  *
1117  *********************************************************************/
1118 void unload_current_trust_file(void)
1119 {
1120    if (current_trustfile)
1121    {
1122       current_trustfile->unloader = unload_trustfile;
1123       current_trustfile = NULL;
1124    }
1125 }
1126 #endif /* FEATURE_GRACEFUL_TERMINATION */
1127
1128
1129 /*********************************************************************
1130  *
1131  * Function    :  load_trustfile
1132  *
1133  * Description :  Read and parse a trustfile and add to files list.
1134  *
1135  * Parameters  :
1136  *          1  :  csp = Current client state (buffers, headers, etc...)
1137  *
1138  * Returns     :  0 => Ok, everything else is an error.
1139  *
1140  *********************************************************************/
1141 int load_trustfile(struct client_state *csp)
1142 {
1143    FILE *fp;
1144
1145    struct block_spec *b, *bl;
1146    struct url_spec **tl;
1147
1148    char  buf[BUFFER_SIZE], *p, *q;
1149    int reject, trusted;
1150    struct file_list *fs;
1151    unsigned long linenum = 0;
1152    int trusted_referrers = 0;
1153
1154    if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs))
1155    {
1156       /* No need to load */
1157       if (csp)
1158       {
1159          csp->tlist = current_trustfile;
1160       }
1161       return(0);
1162    }
1163    if (!fs)
1164    {
1165       goto load_trustfile_error;
1166    }
1167
1168    fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1169    if (bl == NULL)
1170    {
1171       goto load_trustfile_error;
1172    }
1173
1174    if ((fp = fopen(csp->config->trustfile, "r")) == NULL)
1175    {
1176       goto load_trustfile_error;
1177    }
1178
1179    tl = csp->config->trust_list;
1180
1181    while (read_config_line(buf, sizeof(buf), fp, &linenum) != NULL)
1182    {
1183       trusted = 0;
1184       reject  = 1;
1185
1186       if (*buf == '+')
1187       {
1188          trusted = 1;
1189          *buf = '~';
1190       }
1191
1192       if (*buf == '~')
1193       {
1194          reject = 0;
1195          p = buf;
1196          q = p+1;
1197          while ((*p++ = *q++) != '\0')
1198          {
1199             /* nop */
1200          }
1201       }
1202
1203       /* skip blank lines */
1204       if (*buf == '\0')
1205       {
1206          continue;
1207       }
1208
1209       /* allocate a new node */
1210       if ((b = zalloc(sizeof(*b))) == NULL)
1211       {
1212          fclose(fp);
1213          goto load_trustfile_error;
1214       }
1215
1216       /* add it to the list */
1217       b->next  = bl->next;
1218       bl->next = b;
1219
1220       b->reject = reject;
1221
1222       /* Save the URL pattern */
1223       if (create_url_spec(b->url, buf))
1224       {
1225          fclose(fp);
1226          goto load_trustfile_error;
1227       }
1228
1229       /*
1230        * save a pointer to URL's spec in the list of trusted URL's, too
1231        */
1232       if (trusted)
1233       {
1234          if(++trusted_referrers < MAX_TRUSTED_REFERRERS)
1235          {
1236             *tl++ = b->url;
1237          }
1238       }
1239    }
1240
1241    if(trusted_referrers >= MAX_TRUSTED_REFERRERS) 
1242    {
1243       /*
1244        * FIXME: ... after Privoxy 3.0.4 is out.
1245        */
1246        log_error(LOG_LEVEL_ERROR, "Too many trusted referrers. Current limit is %d, you are using %d.\n"
1247           "  Additional trusted referrers are treated like ordinary trusted URLs.\n"
1248           "  (You can increase this limit by changing MAX_TRUSTED_REFERRERS in project.h and recompiling).",
1249           MAX_TRUSTED_REFERRERS, trusted_referrers);
1250    }
1251
1252    *tl = NULL;
1253
1254    fclose(fp);
1255
1256    /* the old one is now obsolete */
1257    if (current_trustfile)
1258    {
1259       current_trustfile->unloader = unload_trustfile;
1260    }
1261
1262    fs->next    = files->next;
1263    files->next = fs;
1264    current_trustfile = fs;
1265
1266    if (csp)
1267    {
1268       csp->tlist = fs;
1269    }
1270
1271    return(0);
1272
1273 load_trustfile_error:
1274    log_error(LOG_LEVEL_FATAL, "can't load trustfile '%s': %E",
1275              csp->config->trustfile);
1276    return(-1);
1277
1278 }
1279 #endif /* def FEATURE_TRUST */
1280
1281
1282 /*********************************************************************
1283  *
1284  * Function    :  unload_re_filterfile
1285  *
1286  * Description :  Unload the re_filter list by freeing all chained
1287  *                re_filterfile specs and their data.
1288  *
1289  * Parameters  :
1290  *          1  :  f = the data structure associated with the filterfile.
1291  *
1292  * Returns     :  N/A
1293  *
1294  *********************************************************************/
1295 static void unload_re_filterfile(void *f)
1296 {
1297    struct re_filterfile_spec *a, *b = (struct re_filterfile_spec *)f;
1298
1299    while (b != NULL)
1300    {
1301       a = b->next;
1302
1303       destroy_list(b->patterns);
1304       pcrs_free_joblist(b->joblist);
1305       freez(b->name);
1306       freez(b->description);
1307       freez(b);
1308
1309       b = a;
1310    }
1311
1312    return;
1313 }
1314
1315
1316 #ifdef FEATURE_GRACEFUL_TERMINATION
1317 /*********************************************************************
1318  *
1319  * Function    :  unload_current_re_filterfile
1320  *
1321  * Description :  Unloads current re_filter file - reset to state at
1322  *                beginning of program.
1323  *
1324  * Parameters  :  None
1325  *
1326  * Returns     :  N/A
1327  *
1328  *********************************************************************/
1329 void unload_current_re_filterfile(void)
1330 {
1331    int i;
1332
1333    for (i = 0; i < MAX_AF_FILES; i++)
1334    {
1335       if (current_re_filterfile[i])
1336       {
1337          current_re_filterfile[i]->unloader = unload_re_filterfile;
1338          current_re_filterfile[i] = NULL;
1339       }
1340    }
1341 }
1342 #endif
1343
1344
1345 /*********************************************************************
1346  *
1347  * Function    :  load_re_filterfile
1348  *
1349  * Description :  Load the re_filterfile. 
1350  *                Generate a chained list of re_filterfile_spec's from
1351  *                the "FILTER: " blocks, compiling all their substitutions
1352  *                into chained lists of pcrs_job structs.
1353  *
1354  * Parameters  :
1355  *          1  :  csp = Current client state (buffers, headers, etc...)
1356  *
1357  * Returns     :  0 => Ok, everything else is an error.
1358  *
1359  *********************************************************************/
1360 int load_re_filterfile(struct client_state *csp)
1361 {
1362    int i;
1363    int result;
1364
1365    for (i = 0; i < MAX_AF_FILES; i++)
1366    {
1367       if (csp->config->re_filterfile[i])
1368       {
1369          result = load_one_re_filterfile(csp, i);
1370          if (result)
1371          {
1372             return result;
1373          }
1374       }
1375       else if (current_re_filterfile[i])
1376       {
1377          current_re_filterfile[i]->unloader = unload_re_filterfile;
1378          current_re_filterfile[i] = NULL;
1379       }
1380    }
1381
1382    return 0;
1383 }
1384
1385
1386 /*********************************************************************
1387  *
1388  * Function    :  load_one_re_filterfile
1389  *
1390  * Description :  Load a re_filterfile. 
1391  *                Generate a chained list of re_filterfile_spec's from
1392  *                the "FILTER: " blocks, compiling all their substitutions
1393  *                into chained lists of pcrs_job structs.
1394  *
1395  * Parameters  :
1396  *          1  :  csp = Current client state (buffers, headers, etc...)
1397  *
1398  * Returns     :  0 => Ok, everything else is an error.
1399  *
1400  *********************************************************************/
1401 int load_one_re_filterfile(struct client_state *csp, int fileid)
1402 {
1403    FILE *fp;
1404
1405    struct re_filterfile_spec *new_bl, *bl = NULL;
1406    struct file_list *fs;
1407
1408    char  buf[BUFFER_SIZE];
1409    int error;
1410    unsigned long linenum = 0;
1411    pcrs_job *dummy, *lastjob = NULL;
1412
1413    /*
1414     * No need to reload if unchanged
1415     */
1416    if (!check_file_changed(current_re_filterfile[fileid], csp->config->re_filterfile[fileid], &fs))
1417    {
1418       if (csp)
1419       {
1420          csp->rlist[fileid] = current_re_filterfile[fileid];
1421       }
1422       return(0);
1423    }
1424    if (!fs)
1425    {
1426       goto load_re_filterfile_error;
1427    }
1428
1429    /* 
1430     * Open the file or fail
1431     */
1432    if ((fp = fopen(csp->config->re_filterfile[fileid], "r")) == NULL)
1433    {
1434       goto load_re_filterfile_error;
1435    }
1436
1437    /* 
1438     * Read line by line
1439     */
1440    while (read_config_line(buf, sizeof(buf), fp, &linenum) != NULL)
1441    {
1442       int new_filter = NO_NEW_FILTER;
1443
1444       if (strncmp(buf, "FILTER:", 7) == 0)
1445       {
1446          new_filter = FT_CONTENT_FILTER;
1447       }
1448       else if (strncmp(buf, "SERVER-HEADER-FILTER:", 21) == 0)
1449       {
1450          new_filter = FT_SERVER_HEADER_FILTER;
1451       }
1452       else if (strncmp(buf, "CLIENT-HEADER-FILTER:", 21) == 0)
1453       {
1454          new_filter = FT_CLIENT_HEADER_FILTER;
1455       }
1456       else if (strncmp(buf, "CLIENT-HEADER-TAGGER:", 21) == 0)
1457       {
1458          new_filter = FT_CLIENT_HEADER_TAGGER;
1459       }
1460       else if (strncmp(buf, "SERVER-HEADER-TAGGER:", 21) == 0)
1461       {
1462          new_filter = FT_SERVER_HEADER_TAGGER;
1463       }
1464
1465       /*
1466        * If this is the head of a new filter block, make it a
1467        * re_filterfile spec of its own and chain it to the list:
1468        */
1469       if (new_filter != NO_NEW_FILTER)
1470       {
1471          new_bl = (struct re_filterfile_spec  *)zalloc(sizeof(*bl));
1472          if (new_bl == NULL)
1473          {
1474             goto load_re_filterfile_error;
1475          }
1476          if (new_filter == FT_CONTENT_FILTER)
1477          {
1478             new_bl->name = chomp(buf + 7);
1479          }
1480          else
1481          {
1482             new_bl->name = chomp(buf + 21);
1483          }
1484          new_bl->type = new_filter;
1485
1486          /*
1487           * If a filter description is available,
1488           * encode it to HTML and save it.
1489           */
1490          if (NULL != (new_bl->description = strpbrk(new_bl->name, " \t")))
1491          {
1492             *new_bl->description++ = '\0';
1493             new_bl->description = html_encode(chomp(new_bl->description));
1494             if (NULL == new_bl->description)
1495             {
1496                new_bl->description = strdup("Out of memory while encoding this filter's description to HTML");
1497             }
1498          }
1499          else
1500          {
1501             new_bl->description = strdup("No description available for this filter");
1502          }
1503
1504          new_bl->name = strdup(chomp(new_bl->name));
1505          
1506          /*
1507           * If this is the first filter block, chain it
1508           * to the file_list rather than its (nonexistant)
1509           * predecessor
1510           */
1511          if (fs->f == NULL)
1512          {
1513             fs->f = new_bl;
1514          }
1515          else
1516          {
1517             bl->next = new_bl;
1518          }
1519          bl = new_bl;
1520
1521          log_error(LOG_LEVEL_RE_FILTER, "Reading in filter \"%s\" (\"%s\")", bl->name, bl->description);
1522
1523          continue;
1524       }
1525
1526       /* 
1527        * Else, save the expression, make it a pcrs_job
1528        * and chain it into the current filter's joblist 
1529        */
1530       if (bl != NULL)
1531       {
1532          error = enlist(bl->patterns, buf);
1533          if (JB_ERR_MEMORY == error)
1534          {
1535             log_error(LOG_LEVEL_FATAL,
1536                "Out of memory while enlisting re_filter job \'%s\' for filter %s.", buf, bl->name);
1537          }
1538          assert(JB_ERR_OK == error);
1539
1540          if (pcrs_job_is_dynamic(buf))
1541          {
1542             /*
1543              * Dynamic pattern that might contain variables
1544              * and has to be recompiled for every request
1545              */
1546             if (bl->joblist != NULL)
1547             {
1548                 pcrs_free_joblist(bl->joblist);
1549                 bl->joblist = NULL;
1550             }
1551             bl->dynamic = 1;
1552             log_error(LOG_LEVEL_RE_FILTER,
1553                "Adding dynamic re_filter job \'%s\' to filter %s succeeded.", buf, bl->name);
1554             continue;             
1555          }
1556          else if (bl->dynamic)
1557          {
1558             /*
1559              * A previous job was dynamic and as we
1560              * recompile the whole filter anyway, it
1561              * makes no sense to compile this job now.
1562              */
1563             log_error(LOG_LEVEL_RE_FILTER,
1564                "Adding static re_filter job \'%s\' to dynamic filter %s succeeded.", buf, bl->name);
1565             continue;
1566          }
1567
1568          if ((dummy = pcrs_compile_command(buf, &error)) == NULL)
1569          {
1570             log_error(LOG_LEVEL_ERROR,
1571                "Adding re_filter job \'%s\' to filter %s failed with error %d.", buf, bl->name, error);
1572             continue;
1573          }
1574          else
1575          {
1576             if (bl->joblist == NULL)
1577             {
1578                bl->joblist = dummy;
1579             }
1580             else
1581             {
1582                lastjob->next = dummy;
1583             }
1584             lastjob = dummy;
1585             log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job \'%s\' to filter %s succeeded.", buf, bl->name);
1586          }
1587       }
1588       else
1589       {
1590          log_error(LOG_LEVEL_ERROR, "Ignoring job %s outside filter block in %s, line %d",
1591             buf, csp->config->re_filterfile[fileid], linenum);
1592       }
1593    }
1594
1595    fclose(fp);
1596
1597    /* 
1598     * Schedule the now-obsolete old data for unloading
1599     */
1600    if ( NULL != current_re_filterfile[fileid] )
1601    {
1602       current_re_filterfile[fileid]->unloader = unload_re_filterfile;
1603    }
1604
1605    /*
1606     * Chain this file into the global list of loaded files
1607     */
1608    fs->next    = files->next;
1609    files->next = fs;
1610    current_re_filterfile[fileid] = fs;
1611
1612    if (csp)
1613    {
1614       csp->rlist[fileid] = fs;
1615    }
1616
1617    return( 0 );
1618
1619 load_re_filterfile_error:
1620    log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E",
1621              csp->config->re_filterfile[fileid]);
1622    return(-1);
1623
1624 }
1625
1626
1627 /*********************************************************************
1628  *
1629  * Function    :  add_loader
1630  *
1631  * Description :  Called from `load_config'.  Called once for each input
1632  *                file found in config.
1633  *
1634  * Parameters  :
1635  *          1  :  loader = pointer to a function that can parse and load
1636  *                the appropriate config file.
1637  *          2  :  config = The configuration_spec to add the loader to.
1638  *
1639  * Returns     :  N/A
1640  *
1641  *********************************************************************/
1642 void add_loader(int (*loader)(struct client_state *),
1643                 struct configuration_spec * config)
1644 {
1645    int i;
1646
1647    for (i=0; i < NLOADERS; i++)
1648    {
1649       if (config->loaders[i] == NULL)
1650       {
1651          config->loaders[i] = loader;
1652          break;
1653       }
1654    }
1655
1656 }
1657
1658
1659 /*********************************************************************
1660  *
1661  * Function    :  run_loader
1662  *
1663  * Description :  Called from `load_config' and `listen_loop'.  This
1664  *                function keeps the "csp" current with any file mods
1665  *                since the last loop.  If a file is unchanged, the
1666  *                loader functions do NOT reload the file.
1667  *
1668  * Parameters  :
1669  *          1  :  csp = Current client state (buffers, headers, etc...)
1670  *                      Must be non-null.  Reads: "csp->config"
1671  *                      Writes: various data members.
1672  *
1673  * Returns     :  0 => Ok, everything else is an error.
1674  *
1675  *********************************************************************/
1676 int run_loader(struct client_state *csp)
1677 {
1678    int ret = 0;
1679    int i;
1680
1681    for (i=0; i < NLOADERS; i++)
1682    {
1683       if (csp->config->loaders[i] == NULL)
1684       {
1685          break;
1686       }
1687       ret |= (csp->config->loaders[i])(csp);
1688    }
1689    return(ret);
1690
1691 }
1692
1693
1694 /*
1695   Local Variables:
1696   tab-width: 3
1697   end:
1698 */