use buildroot, export init to separate file (better manageability)
[privoxy.git] / loaders.c
1 const char loaders_rcs[] = "$Id: loaders.c,v 1.14 2001/06/01 03:27:04 oes 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 the SourceForge
12  *                IJBSWA team.  http://ijbswa.sourceforge.net
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.14  2001/06/01 03:27:04  oes
39  *    Fixed line continuation problem
40  *
41  *    Revision 1.13  2001/05/31 21:28:49  jongfoster
42  *    Removed all permissionsfile code - it's now called the actions
43  *    file, and (almost) all the code is in actions.c
44  *
45  *    Revision 1.12  2001/05/31 17:32:31  oes
46  *
47  *     - Enhanced domain part globbing with infix and prefix asterisk
48  *       matching and optional unanchored operation
49  *
50  *    Revision 1.11  2001/05/29 23:25:24  oes
51  *
52  *     - load_config_line() and load_permissions_file() now use chomp()
53  *
54  *    Revision 1.10  2001/05/29 09:50:24  jongfoster
55  *    Unified blocklist/imagelist/permissionslist.
56  *    File format is still under discussion, but the internal changes
57  *    are (mostly) done.
58  *
59  *    Also modified interceptor behaviour:
60  *    - We now intercept all URLs beginning with one of the following
61  *      prefixes (and *only* these prefixes):
62  *        * http://i.j.b/
63  *        * http://ijbswa.sf.net/config/
64  *        * http://ijbswa.sourceforge.net/config/
65  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
66  *    - Internal changes so that intercepted and fast redirect pages
67  *      are not replaced with an image.
68  *    - Interceptors now have the option to send a binary page direct
69  *      to the client. (i.e. ijb-send-banner uses this)
70  *    - Implemented show-url-info interceptor.  (Which is why I needed
71  *      the above interceptors changes - a typical URL is
72  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
73  *      The previous mechanism would not have intercepted that, and
74  *      if it had been intercepted then it then it would have replaced
75  *      it with an image.)
76  *
77  *    Revision 1.9  2001/05/26 17:12:07  jongfoster
78  *    Fatal errors loading configuration files now give better error messages.
79  *
80  *    Revision 1.8  2001/05/26 00:55:20  jongfoster
81  *    Removing duplicated code.  load_forwardfile() now uses create_url_spec()
82  *
83  *    Revision 1.7  2001/05/26 00:28:36  jongfoster
84  *    Automatic reloading of config file.
85  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
86  *    Most of the global variables have been moved to a new
87  *    struct configuration_spec, accessed through csp->config->globalname
88  *    Most of the globals remaining are used by the Win32 GUI.
89  *
90  *    Revision 1.6  2001/05/23 12:27:33  oes
91  *
92  *    Fixed ugly indentation of my last changes
93  *
94  *    Revision 1.5  2001/05/23 10:39:05  oes
95  *    - Added support for escaping the comment character
96  *      in config files by a backslash
97  *    - Added support for line continuation in config
98  *      files
99  *    - Fixed a buffer overflow bug with long config lines
100  *
101  *    Revision 1.4  2001/05/22 18:56:28  oes
102  *    CRLF -> LF
103  *
104  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
105  *    Version 2.9.4 checkin.
106  *    - Merged popupfile and cookiefile, and added control over PCRS
107  *      filtering, in new "permissionsfile".
108  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
109  *      file error you now get a message box (in the Win32 GUI) rather
110  *      than the program exiting with no explanation.
111  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
112  *      skipping.
113  *    - Removed tabs from "config"
114  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
115  *    - Bumped up version number.
116  *
117  *    Revision 1.2  2001/05/17 23:01:01  oes
118  *     - Cleaned CRLF's from the sources and related files
119  *
120  *    Revision 1.1.1.1  2001/05/15 13:58:59  oes
121  *    Initial import of version 2.9.3 source tree
122  *
123  *
124  *********************************************************************/
125 \f
126
127 #include "config.h"
128
129 #include <stdio.h>
130 #include <stdlib.h>
131 #include <sys/types.h>
132 #include <string.h>
133 #include <malloc.h>
134 #include <errno.h>
135 #include <sys/stat.h>
136 #include <ctype.h>
137
138 #ifndef _WIN32
139 #include <unistd.h>
140 #endif
141
142 #include "project.h"
143 #include "list.h"
144 #include "loaders.h"
145 #include "encode.h"
146 #include "filters.h"
147 #include "parsers.h"
148 #include "jcc.h"
149 #include "ssplit.h"
150 #include "miscutil.h"
151 #include "errlog.h"
152 #include "gateway.h"
153 #include "actions.h"
154
155 #ifndef SPLIT_PROXY_ARGS
156 /* For strsav */
157 #include "showargs.h"
158 #endif /* ndef SPLIT_PROXY_ARGS */
159
160 const char loaders_h_rcs[] = LOADERS_H_VERSION;
161
162 /* Fix a problem with Solaris.  There should be no effect on other
163  * platforms.
164  * Solaris's isspace() is a macro which uses it's argument directly
165  * as an array index.  Therefore we need to make sure that high-bit
166  * characters generate +ve values, and ideally we also want to make
167  * the argument match the declared parameter type of "int".
168  */
169 #define ijb_isspace(__X) isspace((int)(unsigned char)(__X))
170
171
172 /*
173  * Currently active files.
174  * These are also entered in the main linked list of files.
175  */
176
177 #ifdef TRUST_FILES
178 static struct file_list *current_trustfile      = NULL;
179 #endif /* def TRUST_FILES */
180
181 #ifdef PCRS
182 static struct file_list *current_re_filterfile  = NULL;
183 #endif /* def PCRS */
184
185
186 /*********************************************************************
187  *
188  * Function    :  sweep
189  *
190  * Description :  Basically a mark and sweep garbage collector, it is run
191  *                (by the parent thread) every once in a while to reclaim memory.
192  *
193  * It uses a mark and sweep strategy:
194  *   1) mark all files as inactive
195  *
196  *   2) check with each client:
197  *       if it is active,   mark its files as active
198  *       if it is inactive, free its resources
199  *
200  *   3) free the resources of all of the files that
201  *      are still marked as inactive (and are obsolete).
202  *
203  *   N.B. files that are not obsolete don't have an unloader defined.
204  *
205  * Parameters  :  None
206  *
207  * Returns     :  N/A
208  *
209  *********************************************************************/
210 void sweep(void)
211 {
212    struct file_list *fl, *nfl;
213    struct client_state *csp, *ncsp;
214
215    /* clear all of the file's active flags */
216    for ( fl = files->next; NULL != fl; fl = fl->next )
217    {
218       fl->active = 0;
219    }
220
221    for (csp = clients; csp && (ncsp = csp->next) ; csp = csp->next)
222    {
223       if (ncsp->active)
224       {
225          /* mark this client's files as active */
226
227          /*
228           * Always have a configuration file.
229           * (Also note the slightly non-standard extra
230           * indirection here.)
231           */
232          ncsp->config->config_file_list->active = 1;
233
234          if (ncsp->actions_list)     /* actions files */
235          {
236             ncsp->actions_list->active = 1;
237          }
238
239 #ifdef PCRS
240          if (ncsp->rlist)     /* perl re files */
241          {
242             ncsp->rlist->active = 1;
243          }
244 #endif /* def PCRS */
245
246 #ifdef TRUST_FILES
247          if (ncsp->tlist)     /* trust files */
248          {
249             ncsp->tlist->active = 1;
250          }
251 #endif /* def TRUST_FILES */
252
253       }
254       else
255       {
256          /* this client one is not active, release its resources */
257          csp->next = ncsp->next;
258
259          freez(ncsp->ip_addr_str);
260 #ifdef TRUST_FILES
261          freez(ncsp->referrer);
262 #endif /* def TRUST_FILES */
263          freez(ncsp->x_forwarded);
264          freez(ncsp->iob->buf);
265
266          free_http_request(ncsp->http);
267
268          destroy_list(ncsp->headers);
269          destroy_list(ncsp->cookie_list);
270
271          free_current_action(ncsp->action);
272
273 #ifdef STATISTICS
274          urls_read++;
275          if (ncsp->rejected)
276          {
277             urls_rejected++;
278          }
279 #endif /* def STATISTICS */
280
281          freez(ncsp);
282       }
283    }
284
285    for (fl = files; fl && (nfl = fl->next) ; fl = fl->next)
286    {
287       if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
288       {
289          fl->next = nfl->next;
290
291          (nfl->unloader)(nfl->f);
292
293 #ifndef SPLIT_PROXY_ARGS
294          freez(nfl->proxy_args);
295 #endif /* ndef SPLIT_PROXY_ARGS */
296
297          freez(nfl->filename);
298
299          freez(nfl);
300       }
301    }
302
303 }
304
305
306 /*********************************************************************
307  *
308  * Function    :  create_url_spec
309  *
310  * Description :  Creates a "url_spec" structure from a string.
311  *                When finished, free with unload_url().
312  *
313  * Parameters  :
314  *          1  :  url = Target url_spec to be filled in.  Must be
315  *                      zeroed out before the call (e.g. using zalloc).
316  *          2  :  buf = Source pattern, null terminated.  NOTE: The
317  *                      contents of this buffer are destroyed by this
318  *                      function.  If this function succeeds, the
319  *                      buffer is copied to url->spec.  If this
320  *                      function fails, the contents of the buffer
321  *                      are lost forever.
322  *
323  * Returns     :  0 => Ok, everything else is an error.
324  *
325  *********************************************************************/
326 int create_url_spec(struct url_spec * url, char * buf)
327 {
328    char *p;
329    struct url_spec tmp_url[1];
330
331    /* paranoia - should never happen. */
332    if ((url == NULL) || (buf == NULL))
333    {
334       return 1;
335    }
336
337    /* save a copy of the orignal specification */
338    if ((url->spec = strdup(buf)) == NULL)
339    {
340       return 1;
341    }
342
343    if ((p = strchr(buf, '/')))
344    {
345       if (NULL == (url->path = strdup(p)))
346       {
347          freez(url->spec);
348          return 1;
349       }
350       url->pathlen = strlen(url->path);
351       *p = '\0';
352    }
353    else
354    {
355       url->path    = NULL;
356       url->pathlen = 0;
357    }
358 #ifdef REGEX
359    if (url->path)
360    {
361       int errcode;
362       char rebuf[BUFSIZ];
363
364       if (NULL == (url->preg = zalloc(sizeof(*url->preg))))
365       {
366          freez(url->spec);
367          freez(url->path);
368          return 1;
369       }
370
371       sprintf(rebuf, "^(%s)", url->path);
372
373       errcode = regcomp(url->preg, rebuf,
374             (REG_EXTENDED|REG_NOSUB|REG_ICASE));
375       if (errcode)
376       {
377          size_t errlen =
378             regerror(errcode,
379                url->preg, buf, sizeof(buf));
380
381          buf[errlen] = '\0';
382
383          log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
384                  url->spec, buf);
385
386          freez(url->spec);
387          freez(url->path);
388          freez(url->preg);
389
390          return 1;
391       }
392    }
393 #endif
394    if ((p = strchr(buf, ':')) == NULL)
395    {
396       url->port = 0;
397    }
398    else
399    {
400       *p++ = '\0';
401       url->port = atoi(p);
402    }
403
404    if ((url->domain = strdup(buf)) == NULL)
405    {
406       freez(url->spec);
407       freez(url->path);
408 #ifdef REGEX
409       freez(url->preg);
410 #endif /* def REGEX */
411       return 1;
412    }
413
414    /* split domain into components */
415
416    *tmp_url = dsplit(url->domain);
417    url->dbuf = tmp_url->dbuf;
418    url->dcnt = tmp_url->dcnt;
419    url->dvec = tmp_url->dvec;
420    url->unanchored = tmp_url->unanchored;
421
422    return 0; /* OK */
423 }
424
425
426 /*********************************************************************
427  *
428  * Function    :  free_url
429  *
430  * Description :  Called from the "unloaders".  Freez the url
431  *                structure elements.
432  *
433  * Parameters  :
434  *          1  :  url = pointer to a url_spec structure.
435  *
436  * Returns     :  N/A
437  *
438  *********************************************************************/
439 void free_url(struct url_spec *url)
440 {
441    if (url == NULL) return;
442
443    freez(url->spec);
444    freez(url->domain);
445    freez(url->dbuf);
446    freez(url->dvec);
447    freez(url->path);
448 #ifdef REGEX
449    if (url->preg)
450    {
451       regfree(url->preg);
452       freez(url->preg);
453    }
454 #endif
455
456 }
457
458
459 /*********************************************************************
460  *
461  * Function    :  check_file_changed
462  *
463  * Description :  Helper function to check if a file needs reloading.
464  *                If "current" is still current, return it.  Otherwise
465  *                allocates a new (zeroed) "struct file_list", fills 
466  *                in the disk file name and timestamp, and returns it.
467  *
468  * Parameters  :
469  *          1  :  current = The file_list currently being used - will
470  *                          be checked to see if it is out of date. 
471  *                          May be NULL (which is treated as out of
472  *                          date).
473  *          2  :  filename = Name of file to check.
474  *          3  :  newfl    = New file list. [Output only]
475  *                           This will be set to NULL, OR a struct
476  *                           file_list newly allocated on the
477  *                           heap, with the filename and lastmodified
478  *                           fields filled, standard header giving file
479  *                           name in proxy_args, and all others zeroed.
480  *                           (proxy_args is only filled in if !defined
481  *                           SPLIT_PROXY_ARGS and !suppress_blocklists).
482  *
483  * Returns     :  If file unchanged: 0 (and sets newfl == NULL)
484  *                If file changed: 1 and sets newfl != NULL
485  *                On error: 1 and sets newfl == NULL
486  *
487  *********************************************************************/
488 int check_file_changed(const struct file_list * current,
489                        const char * filename,
490                        struct file_list ** newfl)
491 {
492    struct file_list *fs;
493    struct stat statbuf[1];
494
495    *newfl = NULL;
496
497    if (stat(filename, statbuf) < 0)
498    {
499       /* Error, probably file not found. */
500       return 1;
501    }
502
503    if (current
504        && (current->lastmodified == statbuf->st_mtime)
505        && (0 == strcmp(current->filename, filename)))
506    {
507       return 0;
508    }
509
510    fs = (struct file_list *)zalloc(sizeof(struct file_list));
511
512    if (fs == NULL)
513    {
514       /* Out of memory error */
515       return 1;
516    }
517
518    fs->filename = strdup(filename);
519    fs->lastmodified = statbuf->st_mtime;
520
521    if (fs->filename == NULL)
522    {
523       /* Out of memory error */
524       freez (fs);
525       return 1;
526    }
527
528 #ifndef SPLIT_PROXY_ARGS
529    if (!suppress_blocklists)
530    {
531       char * p = html_encode(filename);
532       if (p)
533       {
534          fs->proxy_args = strsav(fs->proxy_args, "<h2>The file `");
535          fs->proxy_args = strsav(fs->proxy_args, p);
536          fs->proxy_args = strsav(fs->proxy_args, 
537             "' contains the following patterns</h2>\n");
538          freez(p);
539       }
540       fs->proxy_args = strsav(fs->proxy_args, "<pre>");
541    }
542 #endif /* ndef SPLIT_PROXY_ARGS */
543
544    *newfl = fs;
545    return 1;
546 }
547
548
549 /*********************************************************************
550  *
551  * Function    :  read_config_line
552  *
553  * Description :  Read a single non-empty line from a file and return
554  *                it.  Trims comments, leading and trailing whitespace
555  *                and respects escaping of newline and comment char.
556  *                Also writes the file to fs->proxy_args.
557  *
558  * Parameters  :
559  *          1  :  buf = Buffer to use.
560  *          2  :  buflen = Size of buffer in bytes.
561  *          3  :  fp = File to read from
562  *          4  :  fs = File will be written to fs->proxy_args.  May
563  *                be NULL to disable this feature.
564  *
565  * Returns     :  NULL on EOF or error
566  *                Otherwise, returns buf.
567  *
568  *********************************************************************/
569 char *read_config_line(char *buf, int buflen, FILE *fp, struct file_list *fs)
570 {
571    char *p, *q;
572    char linebuf[BUFSIZ];
573    int contflag = 0;
574
575    *buf = '\0';
576
577    while (fgets(linebuf, sizeof(linebuf), fp))
578    {
579 #ifndef SPLIT_PROXY_ARGS
580       if (fs && !suppress_blocklists)
581       {
582          char *html_line = html_encode(linebuf);
583          if (html_line != NULL)
584          {
585             fs->proxy_args = strsav(fs->proxy_args, html_line);
586             freez(html_line);
587          }
588          fs->proxy_args = strsav(fs->proxy_args, "<br>");
589       }
590 #endif /* ndef SPLIT_PROXY_ARGS */
591
592       /* Trim off newline */
593       if ((p = strpbrk(linebuf, "\r\n")) != NULL)
594       {
595          *p = '\0';
596       }
597
598       /* Line continuation? Trim escape and set flag. */
599       if ((p != linebuf) && (*--p == '\\'))
600       {
601          contflag = 1;
602          *p = '\0';
603       }
604
605       /* If there's a comment char.. */
606       if ((p = strpbrk(linebuf, "#")) != NULL)
607       {
608          /* ..and it's escaped, left-shift the line over the escape. */
609          if ((p != linebuf) && (*(p-1) == '\\'))
610          {
611             q = p-1;
612             while ((*q++ = *p++) != '\0') /* nop */;
613          }
614          /* Else, chop off the rest of the line */
615          else
616          {
617             *p = '\0';
618          }
619       }
620
621       /* Write to the buffer */
622       if (*linebuf)
623       {
624          strncat(buf, linebuf, buflen - strlen(buf));
625       }
626
627       /* Continue? */
628       if (contflag)
629       {
630          contflag = 0;
631                         continue;
632       }
633
634       /* Remove leading and trailing whitespace */         
635       chomp(buf);
636
637       if (*buf)
638       {
639          return buf;
640       }
641    }
642
643    /* EOF */
644    return NULL;
645
646 }
647
648
649 #ifdef TRUST_FILES
650 /*********************************************************************
651  *
652  * Function    :  unload_trustfile
653  *
654  * Description :  Unloads a trustfile.
655  *
656  * Parameters  :
657  *          1  :  f = the data structure associated with the trustfile.
658  *
659  * Returns     :  N/A
660  *
661  *********************************************************************/
662 static void unload_trustfile(void *f)
663 {
664    struct block_spec *b = (struct block_spec *)f;
665    if (b == NULL) return;
666
667    unload_trustfile(b->next);
668
669    free_url(b->url);
670
671    freez(b);
672
673 }
674
675
676 /*********************************************************************
677  *
678  * Function    :  load_trustfile
679  *
680  * Description :  Read and parse a trustfile and add to files list.
681  *
682  * Parameters  :
683  *          1  :  csp = Current client state (buffers, headers, etc...)
684  *
685  * Returns     :  0 => Ok, everything else is an error.
686  *
687  *********************************************************************/
688 int load_trustfile(struct client_state *csp)
689 {
690    FILE *fp;
691
692    struct block_spec *b, *bl;
693    struct url_spec **tl;
694
695    char  buf[BUFSIZ], *p, *q;
696    int reject, trusted;
697    struct file_list *fs;
698
699    if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs))
700    {
701       /* No need to load */
702       if (csp)
703       {
704          csp->tlist = current_trustfile;
705       }
706       return(0);
707    }
708    if (!fs)
709    {
710       goto load_trustfile_error;
711    }
712
713    fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
714    if (bl == NULL)
715    {
716       goto load_trustfile_error;
717    }
718
719    if ((fp = fopen(csp->config->trustfile, "r")) == NULL)
720    {
721       goto load_trustfile_error;
722    }
723
724    tl = csp->config->trust_list;
725
726    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
727    {
728       trusted = 0;
729       reject  = 1;
730
731       if (*buf == '+')
732       {
733          trusted = 1;
734          *buf = '~';
735       }
736
737       if (*buf == '~')
738       {
739          reject = 0;
740          p = buf;
741          q = p+1;
742          while ((*p++ = *q++))
743          {
744             /* nop */
745          }
746       }
747
748       /* skip blank lines */
749       if (*buf == '\0')
750       {
751          continue;
752       }
753
754       /* allocate a new node */
755       if ((b = zalloc(sizeof(*b))) == NULL)
756       {
757          fclose(fp);
758          goto load_trustfile_error;
759       }
760
761       /* add it to the list */
762       b->next  = bl->next;
763       bl->next = b;
764
765       b->reject = reject;
766
767       /* Save the URL pattern */
768       if (create_url_spec(b->url, buf))
769       {
770          fclose(fp);
771          goto load_trustfile_error;
772       }
773
774       /*
775        * save a pointer to URL's spec in the list of trusted URL's, too
776        */
777       if (trusted)
778       {
779          *tl++ = b->url;
780       }
781    }
782
783    *tl = NULL;
784
785    fclose(fp);
786
787 #ifndef SPLIT_PROXY_ARGS
788    if (!suppress_blocklists)
789    {
790       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
791    }
792 #endif /* ndef SPLIT_PROXY_ARGS */
793
794    /* the old one is now obsolete */
795    if (current_trustfile)
796    {
797       current_trustfile->unloader = unload_trustfile;
798    }
799
800    fs->next    = files->next;
801    files->next = fs;
802    current_trustfile = fs;
803
804    if (csp)
805    {
806       csp->tlist = fs;
807    }
808
809    return(0);
810
811 load_trustfile_error:
812    log_error(LOG_LEVEL_FATAL, "can't load trustfile '%s': %E",
813              csp->config->trustfile);
814    return(-1);
815
816 }
817 #endif /* def TRUST_FILES */
818
819
820 #ifdef PCRS
821 /*********************************************************************
822  *
823  * Function    :  unload_re_filterfile
824  *
825  * Description :  Unload the re_filter list.
826  *
827  * Parameters  :
828  *          1  :  f = the data structure associated with the filterfile.
829  *
830  * Returns     :  N/A
831  *
832  *********************************************************************/
833 static void unload_re_filterfile(void *f)
834 {
835    pcrs_job *joblist;
836    struct re_filterfile_spec *b = (struct re_filterfile_spec *)f;
837
838    if (b == NULL) return;
839
840    destroy_list(b->patterns);
841
842    joblist = b->joblist;
843    while ( NULL != (joblist = pcrs_free_job(joblist)) ) {}
844
845    freez(b);
846
847 }
848
849 /*********************************************************************
850  *
851  * Function    :  load_re_filterfile
852  *
853  * Description :  Load the re_filterfile. Each non-comment, non-empty
854  *                line is instantly added to the joblist, which is
855  *                a chained list of pcrs_job structs.
856  *
857  * Parameters  :
858  *          1  :  csp = Current client state (buffers, headers, etc...)
859  *
860  * Returns     :  0 => Ok, everything else is an error.
861  *
862  *********************************************************************/
863 int load_re_filterfile(struct client_state *csp)
864 {
865    FILE *fp;
866
867    struct re_filterfile_spec *bl;
868    struct file_list *fs;
869
870    char  buf[BUFSIZ];
871    int error;
872    pcrs_job *dummy;
873
874    if (!check_file_changed(current_re_filterfile, csp->config->re_filterfile, &fs))
875    {
876       /* No need to load */
877       if (csp)
878       {
879          csp->rlist = current_re_filterfile;
880       }
881       return(0);
882    }
883    if (!fs)
884    {
885       goto load_re_filterfile_error;
886    }
887
888    fs->f = bl = (struct re_filterfile_spec  *)zalloc(sizeof(*bl));
889    if (bl == NULL)
890    {
891       goto load_re_filterfile_error;
892    }
893
894    /* Open the file or fail */
895    if ((fp = fopen(csp->config->re_filterfile, "r")) == NULL)
896    {
897       goto load_re_filterfile_error;
898    }
899
900    /* Read line by line */
901    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
902    {
903       enlist( bl->patterns, buf );
904
905       /* We have a meaningful line -> make it a job */
906       if ((dummy = pcrs_make_job(buf, &error)) == NULL)
907       {
908          log_error(LOG_LEVEL_RE_FILTER, 
909                "Adding re_filter job %s failed with error %d.", buf, error);
910          continue;
911       }
912       else
913       {
914          dummy->next = bl->joblist;
915          bl->joblist = dummy;
916          log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job %s succeeded.", buf);
917       }
918    }
919
920    fclose(fp);
921
922 #ifndef SPLIT_PROXY_ARGS
923    if (!suppress_blocklists)
924    {
925       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
926    }
927 #endif /* ndef SPLIT_PROXY_ARGS */
928
929    /* the old one is now obsolete */
930    if ( NULL != current_re_filterfile )
931    {
932       current_re_filterfile->unloader = unload_re_filterfile;
933    }
934
935    fs->next    = files->next;
936    files->next = fs;
937    current_re_filterfile = fs;
938
939    if (csp)
940    {
941       csp->rlist = fs;
942    }
943
944    return( 0 );
945
946 load_re_filterfile_error:
947    log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E", 
948              csp->config->re_filterfile);
949    return(-1);
950
951 }
952 #endif /* def PCRS */
953
954
955 /*********************************************************************
956  *
957  * Function    :  add_loader
958  *
959  * Description :  Called from `load_config'.  Called once for each input
960  *                file found in config.
961  *
962  * Parameters  :
963  *          1  :  loader = pointer to a function that can parse and load
964  *                the appropriate config file.
965  *          2  :  config = The configuration_spec to add the loader to.
966  *
967  * Returns     :  N/A
968  *
969  *********************************************************************/
970 void add_loader(int (*loader)(struct client_state *), 
971                 struct configuration_spec * config)
972 {
973    int i;
974
975    for (i=0; i < NLOADERS; i++)
976    {
977       if (config->loaders[i] == NULL)
978       {
979          config->loaders[i] = loader;
980          break;
981       }
982    }
983
984 }
985
986
987 /*********************************************************************
988  *
989  * Function    :  run_loader
990  *
991  * Description :  Called from `load_config' and `listen_loop'.  This
992  *                function keeps the "csp" current with any file mods
993  *                since the last loop.  If a file is unchanged, the
994  *                loader functions do NOT reload the file.
995  *
996  * Parameters  :
997  *          1  :  csp = Current client state (buffers, headers, etc...)
998  *                      Must be non-null.  Reads: "csp->config"
999  *                      Writes: various data members.
1000  *
1001  * Returns     :  0 => Ok, everything else is an error.
1002  *
1003  *********************************************************************/
1004 int run_loader(struct client_state *csp)
1005 {
1006    int ret = 0;
1007    int i;
1008
1009    for (i=0; i < NLOADERS; i++)
1010    {
1011       if (csp->config->loaders[i] == NULL)
1012       {
1013          break;
1014       }
1015       ret |= (csp->config->loaders[i])(csp);
1016    }
1017    return(ret);
1018
1019 }
1020
1021
1022 /*
1023   Local Variables:
1024   tab-width: 3
1025   end:
1026 */