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