Deleted config.h and pcrs/chartables.h because they are auto
[privoxy.git] / loaders.c
1 const char loaders_rcs[] = "$Id: loaders.c,v 1.3 2001/05/20 01:21:20 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.3  2001/05/20 01:21:20  jongfoster
39  *    Version 2.9.4 checkin.
40  *    - Merged popupfile and cookiefile, and added control over PCRS
41  *      filtering, in new "permissionsfile".
42  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
43  *      file error you now get a message box (in the Win32 GUI) rather
44  *      than the program exiting with no explanation.
45  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
46  *      skipping.
47  *    - Removed tabs from "config"
48  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
49  *    - Bumped up version number.
50  *
51  *    Revision 1.2  2001/05/17 23:01:01  oes
52  *     - Cleaned CRLF's from the sources and related files
53  *
54  *    Revision 1.1.1.1  2001/05/15 13:58:59  oes
55  *    Initial import of version 2.9.3 source tree
56  *
57  *
58  *********************************************************************/
59 \f
60
61 #include "config.h"
62
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <sys/types.h>
66 #include <string.h>
67 #include <malloc.h>
68 #include <errno.h>
69 #include <sys/stat.h>
70 #include <ctype.h>
71
72 #ifndef _WIN32
73 #include <unistd.h>
74 #endif
75
76 #include "project.h"
77 #include "loaders.h"
78 #include "encode.h"
79 #include "filters.h"
80 #include "parsers.h"
81 #include "jcc.h"
82 #include "ssplit.h"
83 #include "miscutil.h"
84 #include "errlog.h"
85 #include "gateway.h"
86
87 #ifndef SPLIT_PROXY_ARGS
88 /* For strsav */
89 #include "showargs.h"
90 #endif /* ndef SPLIT_PROXY_ARGS */
91
92 const char loaders_h_rcs[] = LOADERS_H_VERSION;
93
94 /* Fix a problem with Solaris.  There should be no effect on other
95  * platforms.
96  * Solaris's isspace() is a macro which uses it's argument directly
97  * as an array index.  Therefore we need to make sure that high-bit
98  * characters generate +ve values, and ideally we also want to make
99  * the argument match the declared parameter type of "int".
100  */
101 #define ijb_isspace(__X) isspace((int)(unsigned char)(__X))
102
103
104 #define NLOADERS 8
105 static int (*loaders[NLOADERS])(struct client_state *);
106
107
108 /*
109  * Currently active files.
110  * These are also entered in the main linked list of files.
111  */
112 static struct file_list *current_blockfile      = NULL;
113 static struct file_list *current_permissions_file  = NULL;
114 static struct file_list *current_forwardfile    = NULL;
115
116 #ifdef ACL_FILES
117 static struct file_list *current_aclfile        = NULL;
118 #endif /* def ACL_FILES */
119
120 #ifdef USE_IMAGE_LIST
121 static struct file_list *current_imagefile      = NULL;
122 #endif /* def USE_IMAGE_LIST */
123
124 #ifdef TRUST_FILES
125 static struct file_list *current_trustfile      = NULL;
126 #endif /* def TRUST_FILES */
127
128 #ifdef PCRS
129 static struct file_list *current_re_filterfile  = NULL;
130 #endif /* def PCRS */
131
132
133 static int create_url_spec(struct url_spec * url, char * buf);
134
135
136 /*********************************************************************
137  *
138  * Function    :  sweep
139  *
140  * Description :  Basically a mark and sweep garbage collector, it is run
141  *                (by the parent thread) every once in a while to reclaim memory.
142  *
143  * It uses a mark and sweep strategy:
144  *   1) mark all files as inactive
145  *
146  *   2) check with each client:
147  *       if it is active,   mark its files as active
148  *       if it is inactive, free its resources
149  *
150  *   3) free the resources of all of the files that
151  *      are still marked as inactive (and are obsolete).
152  *
153  *   N.B. files that are not obsolete don't have an unloader defined.
154  *
155  * Parameters  :  None
156  *
157  * Returns     :  N/A
158  *
159  *********************************************************************/
160 void sweep(void)
161 {
162    struct file_list *fl, *nfl;
163    struct client_state *csp, *ncsp;
164
165    /* clear all of the file's active flags */
166    for ( fl = files->next; NULL != fl; fl = fl->next )
167    {
168       fl->active = 0;
169    }
170
171    for (csp = clients; csp && (ncsp = csp->next) ; csp = csp->next)
172    {
173       if (ncsp->active)
174       {
175          /* mark this client's files as active */
176
177          if (ncsp->blist)     /* block files */
178          {
179             ncsp->blist->active = 1;
180          }
181
182          if (ncsp->permissions_list)     /* permissions files */
183          {
184             ncsp->permissions_list->active = 1;
185          }
186
187          if (ncsp->flist)     /* forward files */
188          {
189             ncsp->flist->active = 1;
190          }
191
192 #ifdef ACL_FILES
193          if (ncsp->alist)     /* acl files */
194          {
195             ncsp->alist->active = 1;
196          }
197 #endif /* def ACL_FILES */
198
199 #ifdef USE_IMAGE_LIST
200          if (ncsp->ilist)     /* image files */
201          {
202             ncsp->ilist->active = 1;
203          }
204 #endif /* def USE_IMAGE_LIST */
205
206 #ifdef PCRS
207          if (ncsp->rlist)     /* perl re files */
208          {
209             ncsp->rlist->active = 1;
210          }
211 #endif /* def PCRS */
212
213 #ifdef TRUST_FILES
214          if (ncsp->tlist)     /* trust files */
215          {
216             ncsp->tlist->active = 1;
217          }
218 #endif /* def TRUST_FILES */
219
220       }
221       else
222       {
223          /* this client one is not active, release its resources */
224          csp->next = ncsp->next;
225
226          freez(ncsp->ip_addr_str);
227          freez(ncsp->referrer);
228          freez(ncsp->x_forwarded);
229          freez(ncsp->ip_addr_str);
230          freez(ncsp->iob->buf);
231
232          free_http_request(ncsp->http);
233
234          destroy_list(ncsp->headers);
235          destroy_list(ncsp->cookie_list);
236
237 #ifdef STATISTICS
238          urls_read++;
239          if (ncsp->rejected)
240          {
241             urls_rejected++;
242          }
243 #endif /* def STATISTICS */
244
245          freez(ncsp);
246       }
247    }
248
249    for (fl = files; fl && (nfl = fl->next) ; fl = fl->next)
250    {
251       if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
252       {
253          fl->next = nfl->next;
254
255          (nfl->unloader)(nfl->f);
256
257 #ifndef SPLIT_PROXY_ARGS
258          freez(nfl->proxy_args);
259 #endif /* ndef SPLIT_PROXY_ARGS */
260
261          freez(nfl->filename);
262
263          freez(nfl);
264       }
265    }
266
267 }
268
269
270 /*********************************************************************
271  *
272  * Function    :  create_url_spec
273  *
274  * Description :  Creates a "url_spec" structure from a string.
275  *                When finished, free with unload_url().
276  *
277  * Parameters  :
278  *          1  :  url = Target url_spec to be filled in.  Must be
279  *                      zeroed out before the call (e.g. using zalloc).
280  *          2  :  buf = Source pattern, null terminated.  NOTE: The
281  *                      contents of this buffer are destroyed by this
282  *                      function.  If this function succeeds, the
283  *                      buffer is copied to url->spec.  If this
284  *                      function fails, the contents of the buffer
285  *                      are lost forever.
286  *
287  * Returns     :  0 => Ok, everything else is an error.
288  *
289  *********************************************************************/
290 static int create_url_spec(struct url_spec * url, char * buf)
291 {
292    char *p;
293    struct url_spec tmp_url[1];
294
295    /* paranoia - should never happen. */
296    if ((url == NULL) || (buf == NULL))
297    {
298       return 1;
299    }
300
301    /* save a copy of the orignal specification */
302    if ((url->spec = strdup(buf)) == NULL)
303    {
304       return 1;
305    }
306
307    if ((p = strchr(buf, '/')))
308    {
309       if (NULL == (url->path = strdup(p)))
310       {
311          freez(url->spec);
312          return 1;
313       }
314       url->pathlen = strlen(url->path);
315       *p = '\0';
316    }
317    else
318    {
319       url->path    = NULL;
320       url->pathlen = 0;
321    }
322 #ifdef REGEX
323    if (url->path)
324    {
325       int errcode;
326       char rebuf[BUFSIZ];
327
328       if (NULL == (url->preg = zalloc(sizeof(*url->preg))))
329       {
330          freez(url->spec);
331          freez(url->path);
332          return 1;
333       }
334
335       sprintf(rebuf, "^(%s)", url->path);
336
337       errcode = regcomp(url->preg, rebuf,
338             (REG_EXTENDED|REG_NOSUB|REG_ICASE));
339       if (errcode)
340       {
341          size_t errlen =
342             regerror(errcode,
343                url->preg, buf, sizeof(buf));
344
345          buf[errlen] = '\0';
346
347          log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
348                  url->spec, buf);
349
350          freez(url->spec);
351          freez(url->path);
352          freez(url->preg);
353
354          return 1;
355       }
356    }
357 #endif
358    if ((p = strchr(buf, ':')) == NULL)
359    {
360       url->port = 0;
361    }
362    else
363    {
364       *p++ = '\0';
365       url->port = atoi(p);
366    }
367
368    if ((url->domain = strdup(buf)) == NULL)
369    {
370       freez(url->spec);
371       freez(url->path);
372 #ifdef REGEX
373       freez(url->preg);
374 #endif /* def REGEX */
375       return 1;
376    }
377
378    /* split domain into components */
379
380    *tmp_url = dsplit(url->domain);
381    url->dbuf = tmp_url->dbuf;
382    url->dcnt = tmp_url->dcnt;
383    url->dvec = tmp_url->dvec;
384
385    return 0; /* OK */
386 }
387
388
389 /*********************************************************************
390  *
391  * Function    :  unload_url
392  *
393  * Description :  Called from the "unloaders".  Freez the url
394  *                structure elements.
395  *
396  * Parameters  :
397  *          1  :  url = pointer to a url_spec structure.
398  *
399  * Returns     :  N/A
400  *
401  *********************************************************************/
402 static void unload_url(struct url_spec *url)
403 {
404    if (url == NULL) return;
405
406    freez(url->spec);
407    freez(url->domain);
408    freez(url->dbuf);
409    freez(url->dvec);
410    freez(url->path);
411 #ifdef REGEX
412    if (url->preg)
413    {
414       regfree(url->preg);
415       freez(url->preg);
416    }
417 #endif
418
419 }
420
421
422 #ifdef ACL_FILES
423 /*********************************************************************
424  *
425  * Function    :  unload_aclfile
426  *
427  * Description :  Unloads an aclfile.
428  *
429  * Parameters  :
430  *          1  :  f = the data structure associated with the aclfile.
431  *
432  * Returns     :  N/A
433  *
434  *********************************************************************/
435 static void unload_aclfile(void *f)
436 {
437    struct access_control_list *b = (struct access_control_list *)f;
438    if (b == NULL) return;
439
440    unload_aclfile(b->next);
441
442    freez(b);
443
444 }
445 #endif /* def ACL_FILES */
446
447 /*********************************************************************
448  *
449  * Function    :  unload_blockfile
450  *
451  * Description :  Unloads a blockfile.
452  *
453  * Parameters  :
454  *          1  :  f = the data structure associated with the blockfile.
455  *
456  * Returns     :  N/A
457  *
458  *********************************************************************/
459 static void unload_blockfile(void *f)
460 {
461    struct block_spec *b = (struct block_spec *)f;
462    if (b == NULL) return;
463
464    unload_blockfile(b->next);
465
466    unload_url(b->url);
467
468    freez(b);
469
470 }
471
472
473 #ifdef USE_IMAGE_LIST
474 /*********************************************************************
475  *
476  * Function    :  unload_imagefile
477  *
478  * Description :  Unloads an imagefile.
479  *
480  * Parameters  :
481  *          1  :  f = the data structure associated with the imagefile.
482  *
483  * Returns     :  N/A
484  *
485  *********************************************************************/
486 static void unload_imagefile(void *f)
487 {
488    struct block_spec *b = (struct block_spec *)f;
489    if (b == NULL) return;
490
491    unload_imagefile(b->next);
492
493    unload_url(b->url);
494
495    freez(b);
496
497 }
498 #endif /* def USE_IMAGE_LIST */
499
500
501 /*********************************************************************
502  *
503  * Function    :  unload_permissions_file
504  *
505  * Description :  Unloads a permissions file.
506  *
507  * Parameters  :
508  *          1  :  file_data = the data structure associated with the
509  *                            permissions file.
510  *
511  * Returns     :  N/A
512  *
513  *********************************************************************/
514 static void unload_permissions_file(void *file_data)
515 {
516    struct permissions_spec * next;
517    struct permissions_spec * cur = (struct permissions_spec *)file_data;
518    while (cur != NULL)
519    {
520       next = cur->next;
521       unload_url(cur->url);
522       freez(cur);
523       cur = next;
524    }
525
526 }
527
528
529 #ifdef TRUST_FILES
530 /*********************************************************************
531  *
532  * Function    :  unload_trustfile
533  *
534  * Description :  Unloads a trustfile.
535  *
536  * Parameters  :
537  *          1  :  f = the data structure associated with the trustfile.
538  *
539  * Returns     :  N/A
540  *
541  *********************************************************************/
542 static void unload_trustfile(void *f)
543 {
544    struct block_spec *b = (struct block_spec *)f;
545    if (b == NULL) return;
546
547    unload_trustfile(b->next);
548
549    unload_url(b->url);
550
551    freez(b);
552
553 }
554 #endif /* def TRUST_FILES */
555
556
557 /*********************************************************************
558  *
559  * Function    :  unload_forwardfile
560  *
561  * Description :  Unloads a forwardfile.
562  *
563  * Parameters  :
564  *          1  :  f = the data structure associated with the forwardfile.
565  *
566  * Returns     :  N/A
567  *
568  *********************************************************************/
569 static void unload_forwardfile(void *f)
570 {
571    struct forward_spec *b = (struct forward_spec *)f;
572    if (b == NULL) return;
573
574    unload_forwardfile(b->next);
575
576    unload_url(b->url);
577
578    freez(b->gw->gateway_host);
579    freez(b->gw->forward_host);
580
581    freez(b);
582
583 }
584
585
586 #ifdef PCRS
587 /*********************************************************************
588  *
589  * Function    :  unload_re_filterfile
590  *
591  * Description :  Unload the re_filter list.
592  *
593  * Parameters  :
594  *          1  :  f = the data structure associated with the filterfile.
595  *
596  * Returns     :  N/A
597  *
598  *********************************************************************/
599 static void unload_re_filterfile(void *f)
600 {
601    pcrs_job *joblist;
602    struct re_filterfile_spec *b = (struct re_filterfile_spec *)f;
603
604    if (b == NULL) return;
605
606    destroy_list(b->patterns);
607
608    joblist = b->joblist;
609    while ( NULL != (joblist = pcrs_free_job(joblist)) ) {}
610
611    freez(b);
612
613 }
614 #endif /* def PCRS */
615
616
617 /*********************************************************************
618  *
619  * Function    :  check_file_changed
620  *
621  * Description :  Helper function to check if a file needs reloading.
622  *                If "current" is still current, return it.  Otherwise
623  *                allocates a new (zeroed) "struct file_list", fills 
624  *                in the disk file name and timestamp, and returns it.
625  *
626  * Parameters  :
627  *          1  :  current = The file_list currently being used - will
628  *                          be checked to see if it is out of date. 
629  *                          May be NULL (which is treated as out of
630  *                          date).
631  *          2  :  filename = Name of file to check.
632  *          3  :  newfl    = New file list. [Output only]
633  *                           This will be set to NULL, OR a struct
634  *                           file_list newly allocated on the
635  *                           heap, with the filename and lastmodified
636  *                           fields filled, standard header giving file
637  *                           name in proxy_args, and all others zeroed.
638  *                           (proxy_args is only filled in if !defined
639  *                           SPLIT_PROXY_ARGS and !suppress_blocklists).
640  *
641  * Returns     :  If file unchanged: 0 (and sets newfl == NULL)
642  *                If file changed: 1 and sets newfl != NULL
643  *                On error: 1 and sets newfl == NULL
644  *
645  *********************************************************************/
646 static int check_file_changed(const struct file_list * current,
647                               const char * filename,
648                               struct file_list ** newfl)
649 {
650    struct file_list *fs;
651    struct stat statbuf[1];
652
653    *newfl = NULL;
654
655    if (stat(filename, statbuf) < 0)
656    {
657       /* Error, probably file not found. */
658       return 1;
659    }
660
661    if (current
662        && (current->lastmodified == statbuf->st_mtime)
663        && (0 == strcmp(current->filename, filename)))
664    {
665       return 0;
666    }
667
668    fs = (struct file_list *)zalloc(sizeof(struct file_list));
669
670    if (fs == NULL)
671    {
672       /* Out of memory error */
673       return 1;
674    }
675
676    fs->filename = strdup(filename);
677    fs->lastmodified = statbuf->st_mtime;
678
679    if (fs->filename == NULL)
680    {
681       /* Out of memory error */
682       freez (fs);
683       return 1;
684    }
685
686 #ifndef SPLIT_PROXY_ARGS
687    if (!suppress_blocklists)
688    {
689       char * p = html_encode(filename);
690       if (p)
691       {
692          fs->proxy_args = strsav(fs->proxy_args, "<h2>The file `");
693          fs->proxy_args = strsav(fs->proxy_args, p);
694          fs->proxy_args = strsav(fs->proxy_args, 
695             "' contains the following patterns</h2>\n");
696          freez(p);
697       }
698       fs->proxy_args = strsav(fs->proxy_args, "<pre>");
699    }
700 #endif /* ndef SPLIT_PROXY_ARGS */
701
702    *newfl = fs;
703    return 1;
704 }
705
706
707 /*********************************************************************
708  *
709  * Function    :  read_config_line
710  *
711  * Description :  Read a single non-empty line from a file and return
712  *                it.  Trims comments, leading and trailing whitespace.
713  *                Also wites the file to fs->proxy_args.
714  *
715  * Parameters  :
716  *          1  :  buf = Buffer to use.
717  *          2  :  buflen = Size of buffer in bytes.
718  *          3  :  fp = File to read from
719  *          4  :  fs = File will be written to fs->proxy_args.  May
720  *                be NULL to disable this feature.
721  *
722  * Returns     :  NULL on EOF or error
723  *                Otherwise, returns buf.
724  *
725  *********************************************************************/
726 char *read_config_line(char *buf, int buflen, FILE *fp, struct file_list *fs)
727 {
728    char *p, *q;
729    char linebuf[BUFSIZ];
730
731    while (fgets(linebuf, sizeof(linebuf), fp))
732    {
733 #ifndef SPLIT_PROXY_ARGS
734       if (fs && !suppress_blocklists)
735       {
736          char *html_line = html_encode(linebuf);
737          if (html_line != NULL)
738          {
739             fs->proxy_args = strsav(fs->proxy_args, html_line);
740             freez(html_line);
741          }
742          fs->proxy_args = strsav(fs->proxy_args, "<br>");
743       }
744 #endif /* ndef SPLIT_PROXY_ARGS */
745
746       /* Trim off newline and any comment */
747       if ((p = strpbrk(linebuf, "\r\n#")) != NULL)
748       {
749          *p = '\0';
750       }
751       
752       /* Trim leading whitespace */
753       p = linebuf;
754       while (*p && ijb_isspace(*p))
755       {
756          *p++;
757       }
758
759       if (*p)
760       {
761          /* There is something other than whitespace on the line. */
762
763          /* Move the data to the start of buf */
764          if (p != linebuf)
765          {
766             /* strcpy that can cope with overlap. */
767             q = linebuf;
768             while ((*q++ = *p++) != '\0')
769             {
770                /* Do nothing */
771             }
772          }
773
774          /* Trim trailing whitespace */
775          p = linebuf + strlen(linebuf) - 1;
776
777          /*
778           * Note: the (p >= linebuf) below is paranoia, it's not really needed.
779           * When p == linebuf then ijb_isspace(*p) will be false and we'll drop
780           * out of the loop.
781           */
782          while ((p >= linebuf) && ijb_isspace(*p))
783          {
784             p--;
785          }
786          p[1] = '\0';
787
788          /* More paranoia.  This if statement is always true. */
789          if (*linebuf)
790          {
791             strcpy(buf, linebuf);
792             return buf;
793          }
794       }
795    }
796
797    /* EOF */
798    return NULL;
799 }
800
801
802 #ifdef ACL_FILES
803 /*********************************************************************
804  *
805  * Function    :  load_aclfile
806  *
807  * Description :  Read and parse an aclfile and add to files list.
808  *
809  * Parameters  :
810  *          1  :  csp = Current client state (buffers, headers, etc...)
811  *
812  * Returns     :  0 => Ok, everything else is an error.
813  *
814  *********************************************************************/
815 int load_aclfile(struct client_state *csp)
816 {
817    FILE *fp;
818    char buf[BUFSIZ], *v[3], *p;
819    int i;
820    struct access_control_list *a, *bl;
821    struct file_list *fs;
822
823    if (!check_file_changed(current_aclfile, aclfile, &fs))
824    {
825       /* No need to load */
826       if (csp)
827       {
828          csp->alist = current_aclfile;
829       }
830       return(0);
831    }
832    if (!fs)
833    {
834       goto load_aclfile_error;
835    }
836
837    fs->f = bl = (struct access_control_list *)zalloc(sizeof(*bl));
838    if (bl == NULL)
839    {
840       freez(fs->filename);
841       freez(fs);
842       goto load_aclfile_error;
843    }
844
845    fp = fopen(aclfile, "r");
846
847    if (fp == NULL)
848    {
849       goto load_aclfile_error;
850    }
851
852    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
853    {
854       i = ssplit(buf, " \t", v, SZ(v), 1, 1);
855
856       /* allocate a new node */
857       a = (struct access_control_list *) zalloc(sizeof(*a));
858
859       if (a == NULL)
860       {
861          fclose(fp);
862          freez(fs->f);
863          freez(fs->filename);
864          freez(fs);
865          goto load_aclfile_error;
866       }
867
868       /* add it to the list */
869       a->next  = bl->next;
870       bl->next = a;
871
872       switch (i)
873       {
874          case 3:
875             if (acl_addr(v[2], a->dst) < 0)
876             {
877                goto load_aclfile_error;
878             }
879             /* no break */
880
881          case 2:
882             if (acl_addr(v[1], a->src) < 0)
883             {
884                goto load_aclfile_error;
885             }
886
887             p = v[0];
888             if (strcmpic(p, "permit") == 0)
889             {
890                a->action = ACL_PERMIT;
891                break;
892             }
893
894             if (strcmpic(p, "deny") == 0)
895             {
896                a->action = ACL_DENY;
897                break;
898             }
899             /* no break */
900
901          default:
902             goto load_aclfile_error;
903       }
904    }
905
906    fclose(fp);
907
908 #ifndef SPLIT_PROXY_ARGS
909    if (!suppress_blocklists)
910    {
911       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
912    }
913 #endif /* ndef SPLIT_PROXY_ARGS */
914
915    if (current_aclfile)
916    {
917       current_aclfile->unloader = unload_aclfile;
918    }
919
920    fs->next = files->next;
921    files->next = fs;
922    current_aclfile = fs;
923
924    if (csp)
925    {
926       csp->alist = fs;
927    }
928
929    return(0);
930
931 load_aclfile_error:
932    log_error(LOG_LEVEL_ERROR, "can't load access control list %s: %E", aclfile);
933    return(-1);
934
935 }
936 #endif /* def ACL_FILES */
937
938
939 /*********************************************************************
940  *
941  * Function    :  load_blockfile
942  *
943  * Description :  Read and parse a blockfile and add to files list.
944  *
945  * Parameters  :
946  *          1  :  csp = Current client state (buffers, headers, etc...)
947  *
948  * Returns     :  0 => Ok, everything else is an error.
949  *
950  *********************************************************************/
951 int load_blockfile(struct client_state *csp)
952 {
953    FILE *fp;
954
955    struct block_spec *b, *bl;
956    char  buf[BUFSIZ], *p, *q;
957    int reject;
958    struct file_list *fs;
959
960    if (!check_file_changed(current_blockfile, blockfile, &fs))
961    {
962       /* No need to load */
963       if (csp)
964       {
965          csp->blist = current_blockfile;
966       }
967       return(0);
968    }
969    if (!fs)
970    {
971       goto load_blockfile_error;
972    }
973
974    fs->f = bl = (struct block_spec *) zalloc(sizeof(*bl));
975    if (bl == NULL)
976    {
977       goto load_blockfile_error;
978    }
979
980    if ((fp = fopen(blockfile, "r")) == NULL)
981    {
982       goto load_blockfile_error;
983    }
984
985    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
986    {
987       reject = 1;
988
989       if (*buf == '~')
990       {
991          reject = 0;
992          p = buf;
993          q = p+1;
994          while ((*p++ = *q++))
995          {
996             /* nop */
997          }
998       }
999
1000       /* skip lines containing only ~ */
1001       if (*buf == '\0')
1002       {
1003          continue;
1004       }
1005
1006       /* allocate a new node */
1007       if ((b = zalloc(sizeof(*b))) == NULL)
1008       {
1009          fclose(fp);
1010          goto load_blockfile_error;
1011       }
1012
1013       /* add it to the list */
1014       b->next  = bl->next;
1015       bl->next = b;
1016
1017       b->reject = reject;
1018
1019       /* Save the URL pattern */
1020       if (create_url_spec(b->url, buf))
1021       {
1022          fclose(fp);
1023          goto load_blockfile_error;
1024       }
1025    }
1026
1027    fclose(fp);
1028
1029 #ifndef SPLIT_PROXY_ARGS
1030    if (!suppress_blocklists)
1031    {
1032       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1033    }
1034 #endif /* ndef SPLIT_PROXY_ARGS */
1035
1036    /* the old one is now obsolete */
1037    if (current_blockfile)
1038    {
1039       current_blockfile->unloader = unload_blockfile;
1040    }
1041
1042    fs->next    = files->next;
1043    files->next = fs;
1044    current_blockfile = fs;
1045
1046    if (csp)
1047    {
1048       csp->blist = fs;
1049    }
1050
1051    return(0);
1052
1053 load_blockfile_error:
1054    log_error(LOG_LEVEL_ERROR, "can't load blockfile '%s': %E", blockfile);
1055    return(-1);
1056
1057 }
1058
1059
1060 #ifdef USE_IMAGE_LIST
1061 /*********************************************************************
1062  *
1063  * Function    :  load_imagefile
1064  *
1065  * Description :  Read and parse an imagefile and add to files list.
1066  *
1067  * Parameters  :
1068  *          1  :  csp = Current client state (buffers, headers, etc...)
1069  *
1070  * Returns     :  0 => Ok, everything else is an error.
1071  *
1072  *********************************************************************/
1073 int load_imagefile(struct client_state *csp)
1074 {
1075    FILE *fp;
1076
1077    struct block_spec *b, *bl;
1078    char  buf[BUFSIZ], *p, *q;
1079    int reject;
1080    struct file_list *fs;
1081
1082    if (!check_file_changed(current_imagefile, imagefile, &fs))
1083    {
1084       /* No need to load */
1085       if (csp)
1086       {
1087          csp->ilist = current_imagefile;
1088       }
1089       return(0);
1090    }
1091    if (!fs)
1092    {
1093       goto load_imagefile_error;
1094    }
1095
1096    fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1097    if (bl == NULL)
1098    {
1099       goto load_imagefile_error;
1100    }
1101
1102    if ((fp = fopen(imagefile, "r")) == NULL)
1103    {
1104       goto load_imagefile_error;
1105    }
1106
1107    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1108    {
1109       reject = 1;
1110
1111       if (*buf == '~')
1112       {
1113          reject = 0;
1114          p = buf;
1115          q = p+1;
1116          while ((*p++ = *q++))
1117          {
1118             /* nop */
1119          }
1120       }
1121
1122       /* skip lines containing only ~ */
1123       if (*buf == '\0')
1124       {
1125          continue;
1126       }
1127
1128       /* allocate a new node */
1129       if ((b = zalloc(sizeof(*b))) == NULL)
1130       {
1131          fclose(fp);
1132          goto load_imagefile_error;
1133       }
1134
1135       /* add it to the list */
1136       b->next  = bl->next;
1137       bl->next = b;
1138
1139       b->reject = reject;
1140
1141       /* Save the URL pattern */
1142       if (create_url_spec(b->url, buf))
1143       {
1144          fclose(fp);
1145          goto load_imagefile_error;
1146       }
1147    }
1148
1149    fclose(fp);
1150
1151 #ifndef SPLIT_PROXY_ARGS
1152    if (!suppress_blocklists)
1153    {
1154       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1155    }
1156 #endif /* ndef SPLIT_PROXY_ARGS */
1157
1158    /* the old one is now obsolete */
1159    if (current_imagefile)
1160    {
1161       current_imagefile->unloader = unload_imagefile;
1162    }
1163
1164    fs->next    = files->next;
1165    files->next = fs;
1166    current_imagefile = fs;
1167
1168    if (csp)
1169    {
1170       csp->ilist = fs;
1171    }
1172
1173    return(0);
1174
1175 load_imagefile_error:
1176    log_error(LOG_LEVEL_ERROR, "can't load imagefile '%s': %E", imagefile);
1177    return(-1);
1178
1179 }
1180 #endif /* def USE_IMAGE_LIST */
1181
1182
1183 /*********************************************************************
1184  *
1185  * Function    :  load_permissions_file
1186  *
1187  * Description :  Read and parse a permissions file and add to files
1188  *                list.
1189  *
1190  * Parameters  :
1191  *          1  :  csp = Current client state (buffers, headers, etc...)
1192  *
1193  * Returns     :  0 => Ok, everything else is an error.
1194  *
1195  *********************************************************************/
1196 int load_permissions_file(struct client_state *csp)
1197 {
1198    FILE *fp;
1199
1200    struct permissions_spec *b, *bl;
1201    char  buf[BUFSIZ], *p, *q;
1202    int permissions;
1203    struct file_list *fs;
1204    int i;
1205
1206    if (!check_file_changed(current_permissions_file, permissions_file, &fs))
1207    {
1208       /* No need to load */
1209       if (csp)
1210       {
1211          csp->permissions_list = current_permissions_file;
1212       }
1213       return(0);
1214    }
1215    if (!fs)
1216    {
1217       goto load_permissions_error;
1218    }
1219
1220    fs->f = bl = (struct permissions_spec *)zalloc(sizeof(*bl));
1221    if (bl == NULL)
1222    {
1223       goto load_permissions_error;
1224    }
1225
1226    if ((fp = fopen(permissions_file, "r")) == NULL)
1227    {
1228       goto load_permissions_error;
1229    }
1230
1231
1232    /*
1233     * default_permissions is set in this file.
1234     *
1235     * Reset it to default first.
1236     */
1237    default_permissions = PERMIT_RE_FILTER;
1238
1239    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1240    {
1241       p = buf;
1242
1243       permissions = PERMIT_COOKIE_SET | PERMIT_COOKIE_READ | PERMIT_POPUPS;
1244
1245       /*
1246        * FIXME: for() loop is a kludge.  Want to loop around until we
1247        * find a non-control character.  Assume there will be at most 4
1248        * characters.
1249        */
1250       for (i = 0; i < 4; i++)
1251       {
1252          switch ((int)*p)
1253          {
1254             case '>':
1255                /*
1256                 * Allow cookies to be read by the server, but do
1257                 * not allow them to be set.
1258                 */
1259                permissions = (permissions & ~PERMIT_COOKIE_SET);
1260                p++;
1261                break;
1262
1263             case '<':
1264                /*
1265                 * Allow server to set cookies but do not let the
1266                 * server read them.
1267                 */
1268                permissions = (permissions & ~PERMIT_COOKIE_READ);
1269                p++;
1270                break;
1271
1272             case '^':
1273                /*
1274                 * Block popups
1275                 */
1276                permissions = (permissions & ~PERMIT_POPUPS);
1277                p++;
1278                break;
1279
1280             case '%':
1281                /*
1282                 * Permit filtering using PCRS
1283                 */
1284                permissions = (permissions | PERMIT_RE_FILTER);
1285                p++;
1286                break;
1287
1288             case '~':
1289                /*
1290                 * All of the above (maximum filtering).
1291                 */
1292                permissions = PERMIT_RE_FILTER;
1293                p++;
1294                break;
1295
1296             default:
1297                /*
1298                 * FIXME: Should break out of the loop here.
1299                 */
1300                break;
1301          }
1302       }
1303
1304       /*
1305        * Elide any of the "special" chars from the
1306        * front of the pattern
1307        */
1308       q = buf;
1309       if (p > q)
1310       {
1311          while ((*q++ = *p++) != '\0')
1312          {
1313             /* nop */
1314          }
1315       }
1316
1317       /* a lines containing only "special" chars sets default */
1318       if (*buf == '\0')
1319       {
1320          default_permissions = permissions;
1321          continue;
1322       }
1323
1324       /* allocate a new node */
1325       if (((b = zalloc(sizeof(*b))) == NULL)
1326       )
1327       {
1328          fclose(fp);
1329          goto load_permissions_error;
1330       }
1331
1332       /* add it to the list */
1333       b->next  = bl->next;
1334       bl->next = b;
1335
1336       /* Save flags */
1337       b->permissions = permissions;
1338
1339       /* Save the URL pattern */
1340       if (create_url_spec(b->url, buf))
1341       {
1342          fclose(fp);
1343          goto load_permissions_error;
1344       }
1345    }
1346
1347    fclose(fp);
1348
1349 #ifndef SPLIT_PROXY_ARGS
1350    if (!suppress_blocklists)
1351    {
1352       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1353    }
1354 #endif /* ndef SPLIT_PROXY_ARGS */
1355
1356    /* the old one is now obsolete */
1357    if (current_permissions_file)
1358    {
1359       current_permissions_file->unloader = unload_permissions_file;
1360    }
1361
1362    fs->next    = files->next;
1363    files->next = fs;
1364    current_permissions_file = fs;
1365
1366    if (csp)
1367    {
1368       csp->permissions_list = fs;
1369    }
1370
1371    return(0);
1372
1373 load_permissions_error:
1374    log_error(LOG_LEVEL_ERROR, "can't load permissions file '%s': %E", permissions_file);
1375    return(-1);
1376
1377 }
1378
1379
1380 #ifdef TRUST_FILES
1381 /*********************************************************************
1382  *
1383  * Function    :  load_trustfile
1384  *
1385  * Description :  Read and parse a trustfile and add to files list.
1386  *
1387  * Parameters  :
1388  *          1  :  csp = Current client state (buffers, headers, etc...)
1389  *
1390  * Returns     :  0 => Ok, everything else is an error.
1391  *
1392  *********************************************************************/
1393 int load_trustfile(struct client_state *csp)
1394 {
1395    FILE *fp;
1396
1397    struct block_spec *b, *bl;
1398    struct url_spec **tl;
1399
1400    char  buf[BUFSIZ], *p, *q;
1401    int reject, trusted;
1402    struct file_list *fs;
1403
1404    if (!check_file_changed(current_trustfile, trustfile, &fs))
1405    {
1406       /* No need to load */
1407       if (csp)
1408       {
1409          csp->tlist = current_trustfile;
1410       }
1411       return(0);
1412    }
1413    if (!fs)
1414    {
1415       goto load_trustfile_error;
1416    }
1417
1418    fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1419    if (bl == NULL)
1420    {
1421       goto load_trustfile_error;
1422    }
1423
1424    if ((fp = fopen(trustfile, "r")) == NULL)
1425    {
1426       goto load_trustfile_error;
1427    }
1428
1429    tl = trust_list;
1430
1431    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1432    {
1433       trusted = 0;
1434       reject  = 1;
1435
1436       if (*buf == '+')
1437       {
1438          trusted = 1;
1439          *buf = '~';
1440       }
1441
1442       if (*buf == '~')
1443       {
1444          reject = 0;
1445          p = buf;
1446          q = p+1;
1447          while ((*p++ = *q++))
1448          {
1449             /* nop */
1450          }
1451       }
1452
1453       /* skip blank lines */
1454       if (*buf == '\0')
1455       {
1456          continue;
1457       }
1458
1459       /* allocate a new node */
1460       if ((b = zalloc(sizeof(*b))) == NULL)
1461       {
1462          fclose(fp);
1463          goto load_trustfile_error;
1464       }
1465
1466       /* add it to the list */
1467       b->next  = bl->next;
1468       bl->next = b;
1469
1470       b->reject = reject;
1471
1472       /* Save the URL pattern */
1473       if (create_url_spec(b->url, buf))
1474       {
1475          fclose(fp);
1476          goto load_trustfile_error;
1477       }
1478
1479       /*
1480        * save a pointer to URL's spec in the list of trusted URL's, too
1481        */
1482       if (trusted)
1483       {
1484          *tl++ = b->url;
1485       }
1486    }
1487
1488    *tl = NULL;
1489
1490    fclose(fp);
1491
1492 #ifndef SPLIT_PROXY_ARGS
1493    if (!suppress_blocklists)
1494    {
1495       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1496    }
1497 #endif /* ndef SPLIT_PROXY_ARGS */
1498
1499    /* the old one is now obsolete */
1500    if (current_trustfile)
1501    {
1502       current_trustfile->unloader = unload_trustfile;
1503    }
1504
1505    fs->next    = files->next;
1506    files->next = fs;
1507    current_trustfile = fs;
1508
1509    if (csp)
1510    {
1511       csp->tlist = fs;
1512    }
1513
1514    return(0);
1515
1516 load_trustfile_error:
1517    log_error(LOG_LEVEL_ERROR, "can't load trustfile '%s': %E", trustfile);
1518    return(-1);
1519
1520 }
1521 #endif /* def TRUST_FILES */
1522
1523
1524 /*********************************************************************
1525  *
1526  * Function    :  load_forwardfile
1527  *
1528  * Description :  Read and parse a forwardfile and add to files list.
1529  *
1530  * Parameters  :
1531  *          1  :  csp = Current client state (buffers, headers, etc...)
1532  *
1533  * Returns     :  0 => Ok, everything else is an error.
1534  *
1535  *********************************************************************/
1536 int load_forwardfile(struct client_state *csp)
1537 {
1538    FILE *fp;
1539
1540    struct forward_spec *b, *bl;
1541    char  buf[BUFSIZ], *p, *q, *tmp;
1542    char  *vec[4];
1543    int port, n, reject;
1544    struct file_list *fs;
1545    const struct gateway *gw;
1546    struct url_spec url[1];
1547
1548    if (!check_file_changed(current_forwardfile, forwardfile, &fs))
1549    {
1550       /* No need to load */
1551       if (csp)
1552       {
1553          csp->flist = current_forwardfile;
1554       }
1555       return(0);
1556    }
1557    if (!fs)
1558    {
1559       goto load_forwardfile_error;
1560    }
1561
1562    fs->f = bl = (struct forward_spec  *)zalloc(sizeof(*bl));
1563
1564    if ((fs == NULL) || (bl == NULL))
1565    {
1566       goto load_forwardfile_error;
1567    }
1568
1569    if ((fp = fopen(forwardfile, "r")) == NULL)
1570    {
1571       goto load_forwardfile_error;
1572    }
1573
1574    tmp = NULL;
1575
1576    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1577    {
1578       freez(tmp);
1579
1580       tmp = strdup(buf);
1581
1582       n = ssplit(tmp, " \t", vec, SZ(vec), 1, 1);
1583
1584       if (n != 4)
1585       {
1586          log_error(LOG_LEVEL_ERROR, "error in forwardfile: %s", buf);
1587          continue;
1588       }
1589
1590       strcpy(buf, vec[0]);
1591
1592       reject = 1;
1593
1594       if (*buf == '~')
1595       {
1596          reject = 0;
1597          p = buf;
1598          q = p+1;
1599          while ((*p++ = *q++))
1600          {
1601             /* nop */
1602          }
1603       }
1604
1605       /* skip lines containing only ~ */
1606       if (*buf == '\0')
1607       {
1608          continue;
1609       }
1610
1611       /* allocate a new node */
1612       if (((b = zalloc(sizeof(*b))) == NULL)
1613 #ifdef REGEX
1614       || ((b->url->preg = zalloc(sizeof(*b->url->preg))) == NULL)
1615 #endif
1616       )
1617       {
1618          fclose(fp);
1619          goto load_forwardfile_error;
1620       }
1621
1622       /* add it to the list */
1623       b->next  = bl->next;
1624       bl->next = b;
1625
1626       /* save a copy of the orignal specification */
1627       if ((b->url->spec = strdup(buf)) == NULL)
1628       {
1629          fclose(fp);
1630          goto load_forwardfile_error;
1631       }
1632
1633       b->reject = reject;
1634
1635       if ((p = strchr(buf, '/')))
1636       {
1637          b->url->path    = strdup(p);
1638          b->url->pathlen = strlen(b->url->path);
1639          *p = '\0';
1640       }
1641       else
1642       {
1643          b->url->path    = NULL;
1644          b->url->pathlen = 0;
1645       }
1646 #ifdef REGEX
1647       if (b->url->path)
1648       {
1649          int errcode;
1650          char rebuf[BUFSIZ];
1651
1652          sprintf(rebuf, "^(%s)", b->url->path);
1653
1654          errcode = regcomp(b->url->preg, rebuf,
1655                (REG_EXTENDED|REG_NOSUB|REG_ICASE));
1656
1657          if (errcode)
1658          {
1659             size_t errlen = regerror(errcode, b->url->preg, buf, sizeof(buf));
1660
1661             buf[errlen] = '\0';
1662
1663             log_error(LOG_LEVEL_ERROR, "error compiling %s: %s",
1664                     b->url->spec, buf);
1665             fclose(fp);
1666             goto load_forwardfile_error;
1667          }
1668       }
1669       else
1670       {
1671          freez(b->url->preg);
1672       }
1673 #endif
1674       if ((p = strchr(buf, ':')) == NULL)
1675       {
1676          port = 0;
1677       }
1678       else
1679       {
1680          *p++ = '\0';
1681          port = atoi(p);
1682       }
1683
1684       b->url->port = port;
1685
1686       if ((b->url->domain = strdup(buf)) == NULL)
1687       {
1688          fclose(fp);
1689          goto load_forwardfile_error;
1690       }
1691
1692       /* split domain into components */
1693       *url = dsplit(b->url->domain);
1694       b->url->dbuf = url->dbuf;
1695       b->url->dcnt = url->dcnt;
1696       b->url->dvec = url->dvec;
1697
1698       /* now parse the gateway specs */
1699
1700       p = vec[2];
1701
1702       for (gw = gateways; gw->name; gw++)
1703       {
1704          if (strcmp(gw->name, p) == 0)
1705          {
1706             break;
1707          }
1708       }
1709
1710       if (gw->name == NULL)
1711       {
1712          goto load_forwardfile_error;
1713       }
1714
1715       /* save this as the gateway type */
1716       *b->gw = *gw;
1717
1718       /* now parse the gateway host[:port] spec */
1719       p = vec[3];
1720
1721       if (strcmp(p, ".") != 0)
1722       {
1723          b->gw->gateway_host = strdup(p);
1724
1725          if ((p = strchr(b->gw->gateway_host, ':')))
1726          {
1727             *p++ = '\0';
1728             b->gw->gateway_port = atoi(p);
1729          }
1730
1731          if (b->gw->gateway_port <= 0)
1732          {
1733             goto load_forwardfile_error;
1734          }
1735       }
1736
1737       /* now parse the forwarding spec */
1738       p = vec[1];
1739
1740       if (strcmp(p, ".") != 0)
1741       {
1742          b->gw->forward_host = strdup(p);
1743
1744          if ((p = strchr(b->gw->forward_host, ':')))
1745          {
1746             *p++ = '\0';
1747             b->gw->forward_port = atoi(p);
1748          }
1749
1750          if (b->gw->forward_port <= 0)
1751          {
1752             b->gw->forward_port = 8000;
1753          }
1754       }
1755    }
1756
1757    freez(tmp);
1758
1759    fclose(fp);
1760
1761 #ifndef SPLIT_PROXY_ARGS
1762    if (!suppress_blocklists)
1763    {
1764       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1765    }
1766 #endif /* ndef SPLIT_PROXY_ARGS */
1767
1768    /* the old one is now obsolete */
1769    if (current_forwardfile)
1770    {
1771       current_forwardfile->unloader = unload_forwardfile;
1772    }
1773
1774    fs->next    = files->next;
1775    files->next = fs;
1776    current_forwardfile = fs;
1777
1778    if (csp)
1779    {
1780       csp->flist = fs;
1781    }
1782
1783    return(0);
1784
1785 load_forwardfile_error:
1786    log_error(LOG_LEVEL_ERROR, "can't load forwardfile '%s': %E", forwardfile);
1787    return(-1);
1788
1789 }
1790
1791
1792 #ifdef PCRS
1793 /*********************************************************************
1794  *
1795  * Function    :  load_re_filterfile
1796  *
1797  * Description :  Load the re_filterfile. Each non-comment, non-empty
1798  *                line is instantly added to the joblist, which is
1799  *                a chained list of pcrs_job structs.
1800  *
1801  * Parameters  :
1802  *          1  :  csp = Current client state (buffers, headers, etc...)
1803  *
1804  * Returns     :  0 => Ok, everything else is an error.
1805  *
1806  *********************************************************************/
1807 int load_re_filterfile(struct client_state *csp)
1808 {
1809    FILE *fp;
1810
1811    struct re_filterfile_spec *bl;
1812    struct file_list *fs;
1813
1814    char  buf[BUFSIZ];
1815    int error;
1816    pcrs_job *dummy;
1817
1818    if (!check_file_changed(current_re_filterfile, re_filterfile, &fs))
1819    {
1820       /* No need to load */
1821       if (csp)
1822       {
1823          csp->rlist = current_re_filterfile;
1824       }
1825       return(0);
1826    }
1827    if (!fs)
1828    {
1829       goto load_re_filterfile_error;
1830    }
1831
1832    fs->f = bl = (struct re_filterfile_spec  *)zalloc(sizeof(*bl));
1833    if (bl == NULL)
1834    {
1835       goto load_re_filterfile_error;
1836    }
1837
1838    /* Open the file or fail */
1839    if ((fp = fopen(re_filterfile, "r")) == NULL)
1840    {
1841       goto load_re_filterfile_error;
1842    }
1843
1844    /* Read line by line */
1845    while (read_config_line(buf, sizeof(buf), fp, fs) != NULL)
1846    {
1847       enlist( bl->patterns, buf );
1848
1849       /* We have a meaningful line -> make it a job */
1850       if ((dummy = pcrs_make_job(buf, &error)) == NULL)
1851       {
1852          log_error(LOG_LEVEL_RE_FILTER, 
1853                "Adding re_filter job %s failed with error %d.", buf, error);
1854          continue;
1855       }
1856       else
1857       {
1858          dummy->next = bl->joblist;
1859          bl->joblist = dummy;
1860          log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job %s succeeded.", buf);
1861       }
1862    }
1863
1864    fclose(fp);
1865
1866 #ifndef SPLIT_PROXY_ARGS
1867    if (!suppress_blocklists)
1868    {
1869       fs->proxy_args = strsav(fs->proxy_args, "</pre>");
1870    }
1871 #endif /* ndef SPLIT_PROXY_ARGS */
1872
1873    /* the old one is now obsolete */
1874    if ( NULL != current_re_filterfile )
1875    {
1876       current_re_filterfile->unloader = unload_re_filterfile;
1877    }
1878
1879    fs->next    = files->next;
1880    files->next = fs;
1881    current_re_filterfile = fs;
1882
1883    if (csp)
1884    {
1885       csp->rlist = fs;
1886    }
1887
1888    return( 0 );
1889
1890 load_re_filterfile_error:
1891    log_error(LOG_LEVEL_ERROR, "can't load re_filterfile '%s': %E", re_filterfile);
1892    return(-1);
1893
1894 }
1895 #endif /* def PCRS */
1896
1897
1898 /*********************************************************************
1899  *
1900  * Function    :  add_loader
1901  *
1902  * Description :  Called from `load_config'.  Called once for each input
1903  *                file found in config.
1904  *
1905  * Parameters  :
1906  *          1  :  loader = pointer to a function that can parse and load
1907  *                the appropriate config file.
1908  *
1909  * Returns     :  N/A
1910  *
1911  *********************************************************************/
1912 void add_loader(int (*loader)(struct client_state *))
1913 {
1914    int i;
1915
1916    for (i=0; i < NLOADERS; i++)
1917    {
1918       if (loaders[i] == NULL)
1919       {
1920          loaders[i] = loader;
1921          break;
1922       }
1923    }
1924
1925 }
1926
1927
1928 /*********************************************************************
1929  *
1930  * Function    :  run_loader
1931  *
1932  * Description :  Called from `load_config' and `listen_loop'.  This
1933  *                function keeps the "csp" current with any file mods
1934  *                since the last loop.  If a file is unchanged, the
1935  *                loader functions do NOT reload the file.
1936  *
1937  * Parameters  :
1938  *          1  :  csp = Current client state (buffers, headers, etc...)
1939  *
1940  * Returns     :  0 => Ok, everything else is an error.
1941  *
1942  *********************************************************************/
1943 int run_loader(struct client_state *csp)
1944 {
1945    int ret = 0;
1946    int i;
1947
1948    for (i=0; i < NLOADERS; i++)
1949    {
1950       if (loaders[i] == NULL)
1951       {
1952          break;
1953       }
1954       ret |= (loaders[i])(csp);
1955    }
1956    return(ret);
1957
1958 }
1959
1960
1961 /*********************************************************************
1962  *
1963  * Function    :  remove_all_loaders
1964  *
1965  * Description :  Remove all loaders from the list.
1966  *
1967  * Parameters  :  N/A
1968  *
1969  * Returns     :  N/A
1970  *
1971  *********************************************************************/
1972 void remove_all_loaders(void)
1973 {
1974    memset( loaders, 0, sizeof( loaders ) );
1975 }
1976
1977
1978 /*
1979   Local Variables:
1980   tab-width: 3
1981   end:
1982 */