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