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