Fixed %pre scriptlet. And, as a bonus, you can even understand it now. :-)
[privoxy.git] / loaders.c
1 const char loaders_rcs[] = "$Id: loaders.c,v 1.38 2002/03/06 22:54:35 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.38  2002/03/06 22:54:35  jongfoster
39  *    Automated function-comment nitpicking.
40  *
41  *    Revision 1.37  2002/03/03 15:07:49  oes
42  *    Re-enabled automatic config reloading
43  *
44  *    Revision 1.36  2002/01/22 23:46:18  jongfoster
45  *    Moving edit_read_line() and simple_read_line() to loaders.c, and
46  *    extending them to support reading MS-DOS, Mac and UNIX style files
47  *    on all platforms.
48  *
49  *    Modifying read_config_line() (without changing it's prototype) to
50  *    be a trivial wrapper for edit_read_line().  This means that we have
51  *    one function to read a line and handle comments, which is common
52  *    between the initialization code and the edit interface.
53  *
54  *    Revision 1.35  2002/01/17 21:03:08  jongfoster
55  *    Moving all our URL and URL pattern parsing code to urlmatch.c.
56  *
57  *    Renaming free_url to free_url_spec, since it frees a struct url_spec.
58  *
59  *    Revision 1.34  2001/12/30 14:07:32  steudten
60  *    - Add signal handling (unix)
61  *    - Add SIGHUP handler (unix)
62  *    - Add creation of pidfile (unix)
63  *    - Add action 'top' in rc file (RH)
64  *    - Add entry 'SIGNALS' to manpage
65  *    - Add exit message to logfile (unix)
66  *
67  *    Revision 1.33  2001/11/13 00:16:38  jongfoster
68  *    Replacing references to malloc.h with the standard stdlib.h
69  *    (See ANSI or K&R 2nd Ed)
70  *
71  *    Revision 1.32  2001/11/07 00:02:13  steudten
72  *    Add line number in error output for lineparsing for
73  *    actionsfile and configfile.
74  *    Special handling for CLF added.
75  *
76  *    Revision 1.31  2001/10/26 17:39:01  oes
77  *    Removed csp->referrer
78  *    Moved ijb_isspace and ijb_tolower to project.h
79  *
80  *    Revision 1.30  2001/10/25 03:40:48  david__schmidt
81  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
82  *    threads to call select() simultaneously.  So, it's time to do a real, live,
83  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
84  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
85  *
86  *    Revision 1.29  2001/10/23 21:38:53  jongfoster
87  *    Adding error-checking to create_url_spec()
88  *
89  *    Revision 1.28  2001/10/07 15:40:39  oes
90  *    Replaced 6 boolean members of csp with one bitmap (csp->flags)
91  *
92  *    Revision 1.27  2001/09/22 16:36:59  jongfoster
93  *    Removing unused parameter fs from read_config_line()
94  *
95  *    Revision 1.26  2001/09/22 14:05:22  jongfoster
96  *    Bugfix: Multiple escaped "#" characters in a configuration
97  *    file are now permitted.
98  *    Also removing 3 unused headers.
99  *
100  *    Revision 1.25  2001/09/13 22:44:03  jongfoster
101  *    Adding {} to an if statement
102  *
103  *    Revision 1.24  2001/07/30 22:08:36  jongfoster
104  *    Tidying up #defines:
105  *    - All feature #defines are now of the form FEATURE_xxx
106  *    - Permanently turned off WIN_GUI_EDIT
107  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
108  *
109  *    Revision 1.23  2001/07/20 15:51:54  oes
110  *    Fixed indentation of prepocessor commands
111  *
112  *    Revision 1.22  2001/07/20 15:16:17  haroon
113  *    - per Guy's suggestion, added a while loop in sweep() to catch not just
114  *      the last inactive CSP but all other consecutive inactive CSPs after that
115  *      as well
116  *
117  *    Revision 1.21  2001/07/18 17:26:24  oes
118  *    Changed to conform to new pcrs interface
119  *
120  *    Revision 1.20  2001/07/17 13:07:01  oes
121  *    Fixed segv when last line in config files
122  *     lacked a terminating (\r)\n
123  *
124  *    Revision 1.19  2001/07/13 14:01:54  oes
125  *    Removed all #ifdef PCRS
126  *
127  *    Revision 1.18  2001/06/29 21:45:41  oes
128  *    Indentation, CRLF->LF, Tab-> Space
129  *
130  *    Revision 1.17  2001/06/29 13:31:51  oes
131  *    Various adaptions
132  *
133  *    Revision 1.16  2001/06/09 10:55:28  jongfoster
134  *    Changing BUFSIZ ==> BUFFER_SIZE
135  *
136  *    Revision 1.15  2001/06/07 23:14:14  jongfoster
137  *    Removing ACL and forward file loaders - these
138  *    files have been merged into the config file.
139  *    Cosmetic: Moving unloader funcs next to their
140  *    respective loader funcs
141  *
142  *    Revision 1.14  2001/06/01 03:27:04  oes
143  *    Fixed line continuation problem
144  *
145  *    Revision 1.13  2001/05/31 21:28:49  jongfoster
146  *    Removed all permissionsfile code - it's now called the actions
147  *    file, and (almost) all the code is in actions.c
148  *
149  *    Revision 1.12  2001/05/31 17:32:31  oes
150  *
151  *     - Enhanced domain part globbing with infix and prefix asterisk
152  *       matching and optional unanchored operation
153  *
154  *    Revision 1.11  2001/05/29 23:25:24  oes
155  *
156  *     - load_config_line() and load_permissions_file() now use chomp()
157  *
158  *    Revision 1.10  2001/05/29 09:50:24  jongfoster
159  *    Unified blocklist/imagelist/permissionslist.
160  *    File format is still under discussion, but the internal changes
161  *    are (mostly) done.
162  *
163  *    Also modified interceptor behaviour:
164  *    - We now intercept all URLs beginning with one of the following
165  *      prefixes (and *only* these prefixes):
166  *        * http://i.j.b/
167  *        * http://ijbswa.sf.net/config/
168  *        * http://ijbswa.sourceforge.net/config/
169  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
170  *    - Internal changes so that intercepted and fast redirect pages
171  *      are not replaced with an image.
172  *    - Interceptors now have the option to send a binary page direct
173  *      to the client. (i.e. ijb-send-banner uses this)
174  *    - Implemented show-url-info interceptor.  (Which is why I needed
175  *      the above interceptors changes - a typical URL is
176  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
177  *      The previous mechanism would not have intercepted that, and
178  *      if it had been intercepted then it then it would have replaced
179  *      it with an image.)
180  *
181  *    Revision 1.9  2001/05/26 17:12:07  jongfoster
182  *    Fatal errors loading configuration files now give better error messages.
183  *
184  *    Revision 1.8  2001/05/26 00:55:20  jongfoster
185  *    Removing duplicated code.  load_forwardfile() now uses create_url_spec()
186  *
187  *    Revision 1.7  2001/05/26 00:28:36  jongfoster
188  *    Automatic reloading of config file.
189  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
190  *    Most of the global variables have been moved to a new
191  *    struct configuration_spec, accessed through csp->config->globalname
192  *    Most of the globals remaining are used by the Win32 GUI.
193  *
194  *    Revision 1.6  2001/05/23 12:27:33  oes
195  *
196  *    Fixed ugly indentation of my last changes
197  *
198  *    Revision 1.5  2001/05/23 10:39:05  oes
199  *    - Added support for escaping the comment character
200  *      in config files by a backslash
201  *    - Added support for line continuation in config
202  *      files
203  *    - Fixed a buffer overflow bug with long config lines
204  *
205  *    Revision 1.4  2001/05/22 18:56:28  oes
206  *    CRLF -> LF
207  *
208  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
209  *    Version 2.9.4 checkin.
210  *    - Merged popupfile and cookiefile, and added control over PCRS
211  *      filtering, in new "permissionsfile".
212  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
213  *      file error you now get a message box (in the Win32 GUI) rather
214  *      than the program exiting with no explanation.
215  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
216  *      skipping.
217  *    - Removed tabs from "config"
218  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
219  *    - Bumped up version number.
220  *
221  *    Revision 1.2  2001/05/17 23:01:01  oes
222  *     - Cleaned CRLF's from the sources and related files
223  *
224  *    Revision 1.1.1.1  2001/05/15 13:58:59  oes
225  *    Initial import of version 2.9.3 source tree
226  *
227  *
228  *********************************************************************/
229 \f
230
231 #include "config.h"
232
233 #include <stdio.h>
234 #include <stdlib.h>
235 #include <sys/types.h>
236 #include <string.h>
237 #include <errno.h>
238 #include <sys/stat.h>
239 #include <ctype.h>
240 #include <assert.h>
241
242 #if !defined(_WIN32) && !defined(__OS2__)
243 #include <unistd.h>
244 #endif
245
246 #include "project.h"
247 #include "list.h"
248 #include "loaders.h"
249 #include "filters.h"
250 #include "parsers.h"
251 #include "jcc.h"
252 #include "miscutil.h"
253 #include "errlog.h"
254 #include "actions.h"
255 #include "urlmatch.h"
256
257 const char loaders_h_rcs[] = LOADERS_H_VERSION;
258
259 /*
260  * Currently active files.
261  * These are also entered in the main linked list of files.
262  */
263
264 #ifdef FEATURE_TRUST
265 static struct file_list *current_trustfile      = NULL;
266 #endif /* def FEATURE_TRUST */
267
268 static struct file_list *current_re_filterfile  = NULL;
269
270
271
272 /*********************************************************************
273  *
274  * Function    :  sweep
275  *
276  * Description :  Basically a mark and sweep garbage collector, it is run
277  *                (by the parent thread) every once in a while to reclaim memory.
278  *
279  * It uses a mark and sweep strategy:
280  *   1) mark all files as inactive
281  *
282  *   2) check with each client:
283  *       if it is active,   mark its files as active
284  *       if it is inactive, free its resources
285  *
286  *   3) free the resources of all of the files that
287  *      are still marked as inactive (and are obsolete).
288  *
289  *   N.B. files that are not obsolete don't have an unloader defined.
290  *
291  * Parameters  :  None
292  *
293  * Returns     :  N/A
294  *
295  *********************************************************************/
296 void sweep(void)
297 {
298    struct file_list *fl, *nfl;
299    struct client_state *csp, *ncsp;
300
301    /* clear all of the file's active flags */
302    for ( fl = files->next; NULL != fl; fl = fl->next )
303    {
304       fl->active = 0;
305    }
306
307    for (csp = clients; csp && (ncsp = csp->next) ; csp = csp->next)
308    {
309       if (ncsp->flags & CSP_FLAG_ACTIVE)
310       {
311          /* mark this client's files as active */
312
313          /*
314           * Always have a configuration file.
315           * (Also note the slightly non-standard extra
316           * indirection here.)
317           */
318          ncsp->config->config_file_list->active = 1;
319
320          if (ncsp->actions_list)     /* actions files */
321          {
322             ncsp->actions_list->active = 1;
323          }
324
325          if (ncsp->rlist)     /* pcrsjob files */
326          {
327             ncsp->rlist->active = 1;
328          }
329
330 #ifdef FEATURE_TRUST
331          if (ncsp->tlist)     /* trust files */
332          {
333             ncsp->tlist->active = 1;
334          }
335 #endif /* def FEATURE_TRUST */
336
337       }
338       else
339       /*
340        * this client is not active, release its resources
341        * and the ones of all inactive clients that might
342        * follow it
343        */
344       {
345          while (!(ncsp->flags & CSP_FLAG_ACTIVE))
346          {
347             csp->next = ncsp->next;
348
349             freez(ncsp->ip_addr_str);
350             freez(ncsp->my_ip_addr_str);
351             freez(ncsp->my_hostname);
352             freez(ncsp->x_forwarded);
353             freez(ncsp->iob->buf);
354
355             free_http_request(ncsp->http);
356
357             destroy_list(ncsp->headers);
358             destroy_list(ncsp->cookie_list);
359
360             free_current_action(ncsp->action);
361
362 #ifdef FEATURE_STATISTICS
363             urls_read++;
364             if (ncsp->flags & CSP_FLAG_REJECTED)
365             {
366                urls_rejected++;
367             }
368 #endif /* def FEATURE_STATISTICS */
369
370             freez(ncsp);
371
372             /* are there any more in sequence after it? */
373             if( !(ncsp = csp->next) )
374                break;
375          }
376       }
377    }
378
379    for (fl = files; fl && (nfl = fl->next) ; fl = fl->next)
380    {
381       if ( ( 0 == nfl->active ) && ( NULL != nfl->unloader ) )
382       {
383          fl->next = nfl->next;
384
385          (nfl->unloader)(nfl->f);
386
387          freez(nfl->filename);
388
389          freez(nfl);
390       }
391    }
392
393 }
394
395
396 /*********************************************************************
397  *
398  * Function    :  check_file_changed
399  *
400  * Description :  Helper function to check if a file needs reloading.
401  *                If "current" is still current, return it.  Otherwise
402  *                allocates a new (zeroed) "struct file_list", fills
403  *                in the disk file name and timestamp, and returns it.
404  *
405  * Parameters  :
406  *          1  :  current = The file_list currently being used - will
407  *                          be checked to see if it is out of date.
408  *                          May be NULL (which is treated as out of
409  *                          date).
410  *          2  :  filename = Name of file to check.
411  *          3  :  newfl    = New file list. [Output only]
412  *                           This will be set to NULL, OR a struct
413  *                           file_list newly allocated on the
414  *                           heap, with the filename and lastmodified
415  *                           fields filled, and all others zeroed.
416  *
417  * Returns     :  If file unchanged: 0 (and sets newfl == NULL)
418  *                If file changed: 1 and sets newfl != NULL
419  *                On error: 1 and sets newfl == NULL
420  *
421  *********************************************************************/
422 int check_file_changed(const struct file_list * current,
423                        const char * filename,
424                        struct file_list ** newfl)
425 {
426    struct file_list *fs;
427    struct stat statbuf[1];
428
429    *newfl = NULL;
430
431    if (stat(filename, statbuf) < 0)
432    {
433       /* Error, probably file not found. */
434       return 1;
435    }
436
437    if (current
438        && (current->lastmodified == statbuf->st_mtime)
439        && (0 == strcmp(current->filename, filename)))
440    {
441       return 0;
442    }
443
444    fs = (struct file_list *)zalloc(sizeof(struct file_list));
445    if (fs == NULL)
446    {
447       /* Out of memory error */
448       return 1;
449    }
450
451    fs->filename = strdup(filename);
452    fs->lastmodified = statbuf->st_mtime;
453
454    if (fs->filename == NULL)
455    {
456       /* Out of memory error */
457       freez (fs);
458       return 1;
459    }
460    *newfl = fs;
461    return 1;
462 }
463
464
465 /*********************************************************************
466  *
467  * Function    :  simple_read_line
468  *
469  * Description :  Read a single line from a file and return it.
470  *                This is basically a version of fgets() that malloc()s
471  *                it's own line buffer.  Note that the buffer will
472  *                always be a multiple of BUFFER_SIZE bytes long.
473  *                Therefore if you are going to keep the string for
474  *                an extended period of time, you should probably
475  *                strdup() it and free() the original, to save memory.
476  *
477  *
478  * Parameters  :
479  *          1  :  dest = destination for newly malloc'd pointer to
480  *                line data.  Will be set to NULL on error.
481  *          2  :  fp = File to read from
482  *          3  :  newline = Standard for newlines in the file.
483  *                Will be unchanged if it's value on input is not
484  *                NEWLINE_UNKNOWN.
485  *                On output, may be changed from NEWLINE_UNKNOWN to
486  *                actual convention in file.
487  *
488  * Returns     :  JB_ERR_OK     on success
489  *                JB_ERR_MEMORY on out-of-memory
490  *                JB_ERR_FILE   on EOF.
491  *
492  *********************************************************************/
493 jb_err simple_read_line(FILE *fp, char **dest, int *newline)
494 {
495    int len = 0;
496    size_t buflen = BUFFER_SIZE;
497    char * buf;
498    char * p;
499    int ch;
500    int realnewline = NEWLINE_UNKNOWN;
501
502    if (NULL == (buf = malloc(buflen)))
503    {
504       return JB_ERR_MEMORY;
505    }
506
507    p = buf;
508
509 /*
510  * Character codes.  If you have a wierd compiler and the following are
511  * incorrect, you also need to fix NEWLINE() in loaders.h
512  */
513 #define CHAR_CR '\r' /* ASCII 13 */
514 #define CHAR_LF '\n' /* ASCII 10 */
515
516    while (FOREVER)
517    {
518       ch = fgetc(fp);
519       if (ch == EOF)
520       {
521          if (len > 0)
522          {
523             *p = '\0';
524             *dest = buf;
525             return JB_ERR_OK;
526          }
527          else
528          {
529             free(buf);
530             *dest = NULL;
531             return JB_ERR_FILE;
532          }
533       }
534       else if (ch == CHAR_CR)
535       {
536          ch = getc(fp);
537          if (ch == CHAR_LF)
538          {
539             if (*newline == NEWLINE_UNKNOWN)
540             {
541                *newline = NEWLINE_DOS;
542             }
543          }
544          else
545          {
546             if (ch != EOF)
547             {
548                ungetc(ch, fp);
549             }
550             if (*newline == NEWLINE_UNKNOWN)
551             {
552                *newline = NEWLINE_MAC;
553             }
554          }
555          *p = '\0';
556          *dest = buf;
557          if (*newline == NEWLINE_UNKNOWN)
558          {
559             *newline = realnewline;
560          }
561          return JB_ERR_OK;
562       }
563       else if (ch == CHAR_LF)
564       {
565          *p = '\0';
566          *dest = buf;
567          if (*newline == NEWLINE_UNKNOWN)
568          {
569             *newline = NEWLINE_UNIX;
570          }
571          return JB_ERR_OK;
572       }
573       else if (ch == 0)
574       {
575          *p = '\0';
576          *dest = buf;
577          return JB_ERR_OK;
578       }
579
580       *p++ = ch;
581
582       if (++len >= buflen)
583       {
584          buflen += BUFFER_SIZE;
585          if (NULL == (p = realloc(buf, buflen)));
586          {
587             free(buf);
588             return JB_ERR_MEMORY;
589          }
590          buf = p;
591          p = buf + len;
592       }
593    }
594 }
595
596
597 /*********************************************************************
598  *
599  * Function    :  edit_read_line
600  *
601  * Description :  Read a single non-empty line from a file and return
602  *                it.  Trims comments, leading and trailing whitespace
603  *                and respects escaping of newline and comment char.
604  *                Provides the line in 2 alternative forms: raw and
605  *                preprocessed.
606  *                - raw is the raw data read from the file.  If the
607  *                  line is not modified, then this should be written
608  *                  to the new file.
609  *                - prefix is any comments and blank lines that were
610  *                  read from the file.  If the line is modified, then
611  *                  this should be written out to the file followed
612  *                  by the modified data.  (If this string is non-empty
613  *                  then it will have a newline at the end).
614  *                - data is the actual data that will be parsed
615  *                  further by appropriate routines.
616  *                On EOF, the 3 strings will all be set to NULL and
617  *                0 will be returned.
618  *
619  * Parameters  :
620  *          1  :  fp = File to read from
621  *          2  :  raw_out = destination for newly malloc'd pointer to
622  *                raw line data.  May be NULL if you don't want it.
623  *          3  :  prefix_out = destination for newly malloc'd pointer to
624  *                comments.  May be NULL if you don't want it.
625  *          4  :  data_out = destination for newly malloc'd pointer to
626  *                line data with comments and leading/trailing spaces
627  *                removed, and line continuation performed.  May be
628  *                NULL if you don't want it.
629  *          5  :  newline = Standard for newlines in the file.
630  *                On input, set to value to use or NEWLINE_UNKNOWN.
631  *                On output, may be changed from NEWLINE_UNKNOWN to
632  *                actual convention in file.  May be NULL if you
633  *                don't want it.
634  *          6  :  line_number = Line number in file.  In "lines" as
635  *                reported by a text editor, not lines containing data.
636  *
637  * Returns     :  JB_ERR_OK     on success
638  *                JB_ERR_MEMORY on out-of-memory
639  *                JB_ERR_FILE   on EOF.
640  *
641  *********************************************************************/
642 jb_err edit_read_line(FILE *fp,
643                       char **raw_out,
644                       char **prefix_out,
645                       char **data_out,
646                       int *newline,
647                       unsigned long *line_number)
648 {
649    char *p;          /* Temporary pointer   */
650    char *linebuf;    /* Line read from file */
651    char *linestart;  /* Start of linebuf, usually first non-whitespace char */
652    int contflag = 0; /* Nonzero for line continuation - i.e. line ends '\' */
653    int is_empty = 1; /* Flag if not got any data yet */
654    char *raw    = NULL; /* String to be stored in raw_out    */
655    char *prefix = NULL; /* String to be stored in prefix_out */
656    char *data   = NULL; /* String to be stored in data_out   */
657    int scrapnewline;    /* Used for (*newline) if newline==NULL */
658    jb_err rval = JB_ERR_OK;
659
660    assert(fp);
661    assert(raw_out || data_out);
662    assert(newline == NULL
663        || *newline == NEWLINE_UNKNOWN
664        || *newline == NEWLINE_UNIX
665        || *newline == NEWLINE_DOS
666        || *newline == NEWLINE_MAC);
667
668    if (newline == NULL)
669    {
670       scrapnewline = NEWLINE_UNKNOWN;
671       newline = &scrapnewline;
672    }
673
674    /* Set output parameters to NULL */
675    if (raw_out)
676    {
677       *raw_out    = NULL;
678    }
679    if (prefix_out)
680    {
681       *prefix_out = NULL;
682    }
683    if (data_out)
684    {
685       *data_out   = NULL;
686    }
687
688    /* Set string variables to new, empty strings. */
689
690    if (raw_out)
691    {
692       if ((raw = malloc(1)) == NULL)
693       {
694          return JB_ERR_MEMORY;
695       }
696       *raw = '\0';
697    }
698    if (prefix_out)
699    {
700       if ((prefix = malloc(1)) == NULL)
701       {
702          freez(raw);
703          return JB_ERR_MEMORY;
704       }
705       *prefix = '\0';
706    }
707    if (data_out)
708    {
709       if ((data = malloc(1)) == NULL)
710       {
711          freez(raw);
712          freez(prefix);
713          return JB_ERR_MEMORY;
714       }
715       *data = '\0';
716    }
717
718    /* Main loop.  Loop while we need more data & it's not EOF. */
719
720    while ( (contflag || is_empty)
721         && (JB_ERR_OK == (rval = simple_read_line(fp, &linebuf, newline))))
722    {
723       if (line_number)
724       {
725          (*line_number)++;
726       }
727       if (raw)
728       {
729          string_append(&raw,linebuf);
730          if (string_append(&raw,NEWLINE(*newline)))
731          {
732             freez(prefix);
733             freez(data);
734             free(linebuf);
735             return JB_ERR_MEMORY;
736          }
737       }
738
739       /* Line continuation? Trim escape and set flag. */
740       p = linebuf + strlen(linebuf) - 1;
741       contflag = ((*linebuf != '\0') && (*p == '\\'));
742       if (contflag)
743       {
744          *p = '\0';
745       }
746
747       /* Trim leading spaces if we're at the start of the line */
748       linestart = linebuf;
749       if (*data == '\0')
750       {
751          /* Trim leading spaces */
752          while (*linestart && isspace((int)(unsigned char)*linestart))
753          {
754             linestart++;
755          }
756       }
757
758       /* Handle comment characters. */
759       p = linestart;
760       while ((p = strchr(p, '#')) != NULL)
761       {
762          /* Found a comment char.. */
763          if ((p != linebuf) && (*(p-1) == '\\'))
764          {
765             /* ..and it's escaped, left-shift the line over the escape. */
766             char *q = p - 1;
767             while ((*q = *(q + 1)) != '\0')
768             {
769                q++;
770             }
771             /* Now scan from just after the "#". */
772          }
773          else
774          {
775             /* Real comment.  Save it... */
776             if (p == linestart)
777             {
778                /* Special case:  Line only contains a comment, so all the
779                 * previous whitespace is considered part of the comment.
780                 * Undo the whitespace skipping, if any.
781                 */
782                linestart = linebuf;
783                p = linestart;
784             }
785             if (prefix)
786             {
787                string_append(&prefix,p);
788                if (string_append(&prefix, NEWLINE(*newline)))
789                {
790                   freez(raw);
791                   freez(data);
792                   free(linebuf);
793                   return JB_ERR_MEMORY;
794                }
795             }
796
797             /* ... and chop off the rest of the line */
798             *p = '\0';
799          }
800       } /* END while (there's a # character) */
801
802       /* Write to the buffer */
803       if (*linestart)
804       {
805          is_empty = 0;
806          if (data)
807          {
808             if (string_append(&data, linestart))
809             {
810                freez(raw);
811                freez(prefix);
812                free(linebuf);
813                return JB_ERR_MEMORY;
814             }
815          }
816       }
817
818       free(linebuf);
819    } /* END while(we need more data) */
820
821    /* Handle simple_read_line() errors - ignore EOF */
822    if ((rval != JB_ERR_OK) && (rval != JB_ERR_FILE))
823    {
824       freez(raw);
825       freez(prefix);
826       freez(data);
827       return rval;
828    }
829
830    if (raw ? (*raw == '\0') : is_empty)
831    {
832       /* EOF and no data there.  (Definition of "data" depends on whether
833        * the caller cares about "raw" or just "data").
834        */
835
836       free(raw);
837       free(prefix);
838       free(data);
839
840       return JB_ERR_FILE;
841    }
842    else
843    {
844       /* Got at least some data */
845
846       /* Remove trailing whitespace */
847       chomp(data);
848
849       if (raw_out)
850       {
851          *raw_out    = raw;
852       }
853       else
854       {
855          free(raw);
856       }
857       if (prefix_out)
858       {
859          *prefix_out = prefix;
860       }
861       else
862       {
863          free(prefix);
864       }
865       if (data_out)
866       {
867          *data_out   = data;
868       }
869       else
870       {
871          free(data);
872       }
873       return JB_ERR_OK;
874    }
875 }
876
877
878 /*********************************************************************
879  *
880  * Function    :  read_config_line
881  *
882  * Description :  Read a single non-empty line from a file and return
883  *                it.  Trims comments, leading and trailing whitespace
884  *                and respects escaping of newline and comment char.
885  *
886  * Parameters  :
887  *          1  :  buf = Buffer to use.
888  *          2  :  buflen = Size of buffer in bytes.
889  *          3  :  fp = File to read from
890  *          4  :  linenum = linenumber in file
891  *
892  * Returns     :  NULL on EOF or error
893  *                Otherwise, returns buf.
894  *
895  *********************************************************************/
896 char *read_config_line(char *buf, size_t buflen, FILE *fp, unsigned long *linenum)
897 {
898    jb_err err;
899    char *buf2 = NULL;
900    err = edit_read_line(fp, NULL, NULL, &buf2, NULL, linenum);
901    if (err)
902    {
903       if (err == JB_ERR_MEMORY)
904       {
905          log_error(LOG_LEVEL_FATAL, "Out of memory loading a config file");
906       }
907       return NULL;
908    }
909    else
910    {
911       assert(buf2);
912       assert(strlen(buf2) + 1U < buflen);
913       strncpy(buf, buf2, buflen - 1);
914       free(buf2);
915       buf[buflen - 1] = '\0';
916       return buf;
917    }
918 }
919
920
921 #ifdef FEATURE_TRUST
922 /*********************************************************************
923  *
924  * Function    :  unload_trustfile
925  *
926  * Description :  Unloads a trustfile.
927  *
928  * Parameters  :
929  *          1  :  f = the data structure associated with the trustfile.
930  *
931  * Returns     :  N/A
932  *
933  *********************************************************************/
934 static void unload_trustfile(void *f)
935 {
936    struct block_spec *b = (struct block_spec *)f;
937    if (b == NULL) return;
938
939    unload_trustfile(b->next); /* Stack is cheap, isn't it? */
940
941    free_url_spec(b->url);
942
943    freez(b);
944
945 }
946
947
948 /*********************************************************************
949  *
950  * Function    :  load_trustfile
951  *
952  * Description :  Read and parse a trustfile and add to files list.
953  *
954  * Parameters  :
955  *          1  :  csp = Current client state (buffers, headers, etc...)
956  *
957  * Returns     :  0 => Ok, everything else is an error.
958  *
959  *********************************************************************/
960 int load_trustfile(struct client_state *csp)
961 {
962    FILE *fp;
963
964    struct block_spec *b, *bl;
965    struct url_spec **tl;
966
967    char  buf[BUFFER_SIZE], *p, *q;
968    int reject, trusted;
969    struct file_list *fs;
970    unsigned long linenum = 0;
971
972    if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs))
973    {
974       /* No need to load */
975       if (csp)
976       {
977          csp->tlist = current_trustfile;
978       }
979       return(0);
980    }
981    if (!fs)
982    {
983       goto load_trustfile_error;
984    }
985
986    fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
987    if (bl == NULL)
988    {
989       goto load_trustfile_error;
990    }
991
992    if ((fp = fopen(csp->config->trustfile, "r")) == NULL)
993    {
994       goto load_trustfile_error;
995    }
996
997    tl = csp->config->trust_list;
998
999    while (read_config_line(buf, sizeof(buf), fp, &linenum) != NULL)
1000    {
1001       trusted = 0;
1002       reject  = 1;
1003
1004       if (*buf == '+')
1005       {
1006          trusted = 1;
1007          *buf = '~';
1008       }
1009
1010       if (*buf == '~')
1011       {
1012          reject = 0;
1013          p = buf;
1014          q = p+1;
1015          while ((*p++ = *q++))
1016          {
1017             /* nop */
1018          }
1019       }
1020
1021       /* skip blank lines */
1022       if (*buf == '\0')
1023       {
1024          continue;
1025       }
1026
1027       /* allocate a new node */
1028       if ((b = zalloc(sizeof(*b))) == NULL)
1029       {
1030          fclose(fp);
1031          goto load_trustfile_error;
1032       }
1033
1034       /* add it to the list */
1035       b->next  = bl->next;
1036       bl->next = b;
1037
1038       b->reject = reject;
1039
1040       /* Save the URL pattern */
1041       if (create_url_spec(b->url, buf))
1042       {
1043          fclose(fp);
1044          goto load_trustfile_error;
1045       }
1046
1047       /*
1048        * save a pointer to URL's spec in the list of trusted URL's, too
1049        */
1050       if (trusted)
1051       {
1052          *tl++ = b->url;
1053          /* FIXME BUFFER OVERFLOW if >=64 entries */
1054       }
1055    }
1056
1057    *tl = NULL;
1058
1059    fclose(fp);
1060
1061    /* the old one is now obsolete */
1062    if (current_trustfile)
1063    {
1064       current_trustfile->unloader = unload_trustfile;
1065    }
1066
1067    fs->next    = files->next;
1068    files->next = fs;
1069    current_trustfile = fs;
1070
1071    if (csp)
1072    {
1073       csp->tlist = fs;
1074    }
1075
1076    return(0);
1077
1078 load_trustfile_error:
1079    log_error(LOG_LEVEL_FATAL, "can't load trustfile '%s': %E",
1080              csp->config->trustfile);
1081    return(-1);
1082
1083 }
1084 #endif /* def FEATURE_TRUST */
1085
1086
1087 /*********************************************************************
1088  *
1089  * Function    :  unload_re_filterfile
1090  *
1091  * Description :  Unload the re_filter list.
1092  *
1093  * Parameters  :
1094  *          1  :  f = the data structure associated with the filterfile.
1095  *
1096  * Returns     :  N/A
1097  *
1098  *********************************************************************/
1099 static void unload_re_filterfile(void *f)
1100 {
1101    struct re_filterfile_spec *b = (struct re_filterfile_spec *)f;
1102
1103    if (b == NULL)
1104    {
1105       return;
1106    }
1107
1108    destroy_list(b->patterns);
1109    pcrs_free_joblist(b->joblist);
1110    freez(b);
1111
1112    return;
1113 }
1114
1115 /*********************************************************************
1116  *
1117  * Function    :  load_re_filterfile
1118  *
1119  * Description :  Load the re_filterfile. Each non-comment, non-empty
1120  *                line is instantly added to the joblist, which is
1121  *                a chained list of pcrs_job structs.
1122  *
1123  * Parameters  :
1124  *          1  :  csp = Current client state (buffers, headers, etc...)
1125  *
1126  * Returns     :  0 => Ok, everything else is an error.
1127  *
1128  *********************************************************************/
1129 int load_re_filterfile(struct client_state *csp)
1130 {
1131    FILE *fp;
1132
1133    struct re_filterfile_spec *bl;
1134    struct file_list *fs;
1135
1136    char  buf[BUFFER_SIZE];
1137    int error;
1138    unsigned long linenum = 0;
1139    pcrs_job *dummy;
1140
1141    if (!check_file_changed(current_re_filterfile, csp->config->re_filterfile, &fs))
1142    {
1143       /* No need to load */
1144       if (csp)
1145       {
1146          csp->rlist = current_re_filterfile;
1147       }
1148       return(0);
1149    }
1150    if (!fs)
1151    {
1152       goto load_re_filterfile_error;
1153    }
1154
1155    fs->f = bl = (struct re_filterfile_spec  *)zalloc(sizeof(*bl));
1156    if (bl == NULL)
1157    {
1158       goto load_re_filterfile_error;
1159    }
1160
1161    /* Open the file or fail */
1162    if ((fp = fopen(csp->config->re_filterfile, "r")) == NULL)
1163    {
1164       goto load_re_filterfile_error;
1165    }
1166
1167    /* Read line by line */
1168    while (read_config_line(buf, sizeof(buf), fp, &linenum) != NULL)
1169    {
1170       enlist( bl->patterns, buf );
1171
1172       /* We have a meaningful line -> make it a job */
1173       if ((dummy = pcrs_compile_command(buf, &error)) == NULL)
1174       {
1175          log_error(LOG_LEVEL_RE_FILTER,
1176                "Adding re_filter job %s failed with error %d.", buf, error);
1177          continue;
1178       }
1179       else
1180       {
1181          dummy->next = bl->joblist;
1182          bl->joblist = dummy;
1183          log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job %s succeeded.", buf);
1184       }
1185    }
1186
1187    fclose(fp);
1188
1189    /* the old one is now obsolete */
1190    if ( NULL != current_re_filterfile )
1191    {
1192       current_re_filterfile->unloader = unload_re_filterfile;
1193    }
1194
1195    fs->next    = files->next;
1196    files->next = fs;
1197    current_re_filterfile = fs;
1198
1199    if (csp)
1200    {
1201       csp->rlist = fs;
1202    }
1203
1204    return( 0 );
1205
1206 load_re_filterfile_error:
1207    log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E",
1208              csp->config->re_filterfile);
1209    return(-1);
1210
1211 }
1212
1213
1214 /*********************************************************************
1215  *
1216  * Function    :  add_loader
1217  *
1218  * Description :  Called from `load_config'.  Called once for each input
1219  *                file found in config.
1220  *
1221  * Parameters  :
1222  *          1  :  loader = pointer to a function that can parse and load
1223  *                the appropriate config file.
1224  *          2  :  config = The configuration_spec to add the loader to.
1225  *
1226  * Returns     :  N/A
1227  *
1228  *********************************************************************/
1229 void add_loader(int (*loader)(struct client_state *),
1230                 struct configuration_spec * config)
1231 {
1232    int i;
1233
1234    for (i=0; i < NLOADERS; i++)
1235    {
1236       if (config->loaders[i] == NULL)
1237       {
1238          config->loaders[i] = loader;
1239          break;
1240       }
1241    }
1242
1243 }
1244
1245
1246 /*********************************************************************
1247  *
1248  * Function    :  run_loader
1249  *
1250  * Description :  Called from `load_config' and `listen_loop'.  This
1251  *                function keeps the "csp" current with any file mods
1252  *                since the last loop.  If a file is unchanged, the
1253  *                loader functions do NOT reload the file.
1254  *
1255  * Parameters  :
1256  *          1  :  csp = Current client state (buffers, headers, etc...)
1257  *                      Must be non-null.  Reads: "csp->config"
1258  *                      Writes: various data members.
1259  *
1260  * Returns     :  0 => Ok, everything else is an error.
1261  *
1262  *********************************************************************/
1263 int run_loader(struct client_state *csp)
1264 {
1265    int ret = 0;
1266    int i;
1267
1268    for (i=0; i < NLOADERS; i++)
1269    {
1270       if (csp->config->loaders[i] == NULL)
1271       {
1272          break;
1273       }
1274       ret |= (csp->config->loaders[i])(csp);
1275    }
1276    return(ret);
1277
1278 }
1279
1280
1281 /*
1282   Local Variables:
1283   tab-width: 3
1284   end:
1285 */