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