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