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