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