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