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