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