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