If change-x-forwarded-for{add} is used and the client
[privoxy.git] / loaders.c
1 const char loaders_rcs[] = "$Id: loaders.c,v 1.68 2008/09/19 15:26:28 fabiankeil 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-2007 the SourceForge
12  *                Privoxy team. http://www.privoxy.org/
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.68  2008/09/19 15:26:28  fabiankeil
39  *    Add change-x-forwarded-for{} action to block or add
40  *    X-Forwarded-For headers. Mostly based on code removed
41  *    before 3.0.7.
42  *
43  *    Revision 1.67  2008/03/30 14:52:08  fabiankeil
44  *    Rename load_actions_file() and load_re_filterfile()
45  *    as they load multiple files "now".
46  *
47  *    Revision 1.66  2008/03/21 11:16:30  fabiankeil
48  *    Garbage-collect csp->my_ip_addr_str and csp->my_hostname.
49  *
50  *    Revision 1.65  2007/12/07 18:29:23  fabiankeil
51  *    Remove now-obsolete csp member x_forwarded.
52  *
53  *    Revision 1.64  2007/06/01 14:12:38  fabiankeil
54  *    Add unload_forward_spec() in preparation for forward-override{}.
55  *
56  *    Revision 1.63  2007/05/14 10:41:15  fabiankeil
57  *    Ditch the csp member cookie_list[] which isn't used anymore.
58  *
59  *    Revision 1.62  2007/04/30 15:02:18  fabiankeil
60  *    Introduce dynamic pcrs jobs that can resolve variables.
61  *
62  *    Revision 1.61  2007/04/15 16:39:21  fabiankeil
63  *    Introduce tags as alternative way to specify which
64  *    actions apply to a request. At the moment tags can be
65  *    created based on client and server headers.
66  *
67  *    Revision 1.60  2007/03/20 15:16:34  fabiankeil
68  *    Use dedicated header filter actions instead of abusing "filter".
69  *    Replace "filter-client-headers" and "filter-client-headers"
70  *    with "server-header-filter" and "client-header-filter".
71  *
72  *    Revision 1.59  2007/01/25 13:38:20  fabiankeil
73  *    Freez csp->error_message in sweep().
74  *
75  *    Revision 1.58  2006/12/31 14:25:20  fabiankeil
76  *    Fix gcc43 compiler warnings.
77  *
78  *    Revision 1.57  2006/12/21 12:22:22  fabiankeil
79  *    html_encode filter descriptions.
80  *
81  *    Have "Ignoring job ..." error messages
82  *    print the filter file name correctly.
83  *
84  *    Revision 1.56  2006/09/07 10:40:30  fabiankeil
85  *    Turns out trusted referrers above our arbitrary
86  *    limit are downgraded too ordinary trusted URLs.
87  *    Adjusted error message.
88  *
89  *    Revision 1.55  2006/09/07 10:25:39  fabiankeil
90  *    Fix typo.
91  *
92  *    Revision 1.54  2006/09/07 10:22:20  fabiankeil
93  *    If too many trusted referrers are used,
94  *    print only one error message instead of logging
95  *    every single trusted referrer above the arbitrary
96  *    limit.
97  *
98  *    Revision 1.53  2006/08/31 16:25:06  fabiankeil
99  *    Work around a buffer overflow that caused Privoxy to
100  *    segfault if too many trusted referrers were used. Good
101  *    enough for now, but should be replaced with a real
102  *    solution after the next release.
103  *
104  *    Revision 1.52  2006/07/18 14:48:46  david__schmidt
105  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
106  *    with what was really the latest development (the v_3_0_branch branch)
107  *
108  *    Revision 1.50.2.8  2006/01/30 15:16:25  david__schmidt
109  *    Remove a little residual debugging info
110  *
111  *    Revision 1.50.2.7  2006/01/29 23:10:56  david__schmidt
112  *    Multiple filter file support
113  *
114  *    Revision 1.50.2.6  2003/10/24 10:17:54  oes
115  *    Nit: Allowed tabs as separators in filter headings
116  *
117  *    Revision 1.50.2.5  2003/05/08 15:19:15  oes
118  *    sweep: Made loop structure of sweep step mirror that of mark step
119  *
120  *    Revision 1.50.2.4  2003/05/06 15:57:12  oes
121  *    Bugfix: Update last_active pointer in sweep() before
122  *    leaving an active client. Closes bugs #724395, #727882
123  *
124  *    Revision 1.50.2.3  2002/11/20 17:12:30  oes
125  *    Ooops, forgot one change.
126  *
127  *    Revision 1.50.2.2  2002/11/20 14:38:15  oes
128  *    Fixed delayed/incomplete freeing of client resources and
129  *    simplified loop structure in sweep.
130  *    Thanks to Oliver Stoeneberg for the hint.
131  *
132  *    Revision 1.50.2.1  2002/07/26 15:19:24  oes
133  *    - PCRS jobs now chained in order of appearance. Previous
134  *      reverse chaining was counter-intuitive.
135  *    - Changed loglevel of PCRS job compile errors to
136  *      LOG_LEVEL_ERROR
137  *
138  *    Revision 1.50  2002/04/24 02:12:16  oes
139  *    Jon's multiple AF patch: Sweep now takes care of all AFs
140  *
141  *    Revision 1.49  2002/04/19 16:53:25  jongfoster
142  *    Optimize away a function call by using an equivalent macro
143  *
144  *    Revision 1.48  2002/04/05 00:56:09  gliptak
145  *    Correcting typo to clean up on realloc failure
146  *
147  *    Revision 1.47  2002/03/26 22:29:55  swa
148  *    we have a new homepage!
149  *
150  *    Revision 1.46  2002/03/24 13:25:43  swa
151  *    name change related issues
152  *
153  *    Revision 1.45  2002/03/16 23:54:06  jongfoster
154  *    Adding graceful termination feature, to help look for memory leaks.
155  *    If you enable this (which, by design, has to be done by hand
156  *    editing config.h) and then go to http://i.j.b/die, then the program
157  *    will exit cleanly after the *next* request.  It should free all the
158  *    memory that was used.
159  *
160  *    Revision 1.44  2002/03/16 21:51:00  jongfoster
161  *    Fixing free(NULL).
162  *
163  *    Revision 1.43  2002/03/16 20:28:34  oes
164  *    Added descriptions to the filters so users will know what they select in the cgi editor
165  *
166  *    Revision 1.42  2002/03/13 00:27:05  jongfoster
167  *    Killing warnings
168  *
169  *    Revision 1.41  2002/03/12 01:42:50  oes
170  *    Introduced modular filters
171  *
172  *    Revision 1.40  2002/03/08 17:46:04  jongfoster
173  *    Fixing int/size_t warnings
174  *
175  *    Revision 1.39  2002/03/07 03:46:17  oes
176  *    Fixed compiler warnings
177  *
178  *    Revision 1.38  2002/03/06 22:54:35  jongfoster
179  *    Automated function-comment nitpicking.
180  *
181  *    Revision 1.37  2002/03/03 15:07:49  oes
182  *    Re-enabled automatic config reloading
183  *
184  *    Revision 1.36  2002/01/22 23:46:18  jongfoster
185  *    Moving edit_read_line() and simple_read_line() to loaders.c, and
186  *    extending them to support reading MS-DOS, Mac and UNIX style files
187  *    on all platforms.
188  *
189  *    Modifying read_config_line() (without changing it's prototype) to
190  *    be a trivial wrapper for edit_read_line().  This means that we have
191  *    one function to read a line and handle comments, which is common
192  *    between the initialization code and the edit interface.
193  *
194  *    Revision 1.35  2002/01/17 21:03:08  jongfoster
195  *    Moving all our URL and URL pattern parsing code to urlmatch.c.
196  *
197  *    Renaming free_url to free_url_spec, since it frees a struct url_spec.
198  *
199  *    Revision 1.34  2001/12/30 14:07:32  steudten
200  *    - Add signal handling (unix)
201  *    - Add SIGHUP handler (unix)
202  *    - Add creation of pidfile (unix)
203  *    - Add action 'top' in rc file (RH)
204  *    - Add entry 'SIGNALS' to manpage
205  *    - Add exit message to logfile (unix)
206  *
207  *    Revision 1.33  2001/11/13 00:16:38  jongfoster
208  *    Replacing references to malloc.h with the standard stdlib.h
209  *    (See ANSI or K&R 2nd Ed)
210  *
211  *    Revision 1.32  2001/11/07 00:02:13  steudten
212  *    Add line number in error output for lineparsing for
213  *    actionsfile and configfile.
214  *    Special handling for CLF added.
215  *
216  *    Revision 1.31  2001/10/26 17:39:01  oes
217  *    Removed csp->referrer
218  *    Moved ijb_isspace and ijb_tolower to project.h
219  *
220  *    Revision 1.30  2001/10/25 03:40:48  david__schmidt
221  *    Change in porting tactics: OS/2's EMX porting layer doesn't allow multiple
222  *    threads to call select() simultaneously.  So, it's time to do a real, live,
223  *    native OS/2 port.  See defines for __EMX__ (the porting layer) vs. __OS2__
224  *    (native). Both versions will work, but using __OS2__ offers multi-threading.
225  *
226  *    Revision 1.29  2001/10/23 21:38:53  jongfoster
227  *    Adding error-checking to create_url_spec()
228  *
229  *    Revision 1.28  2001/10/07 15:40:39  oes
230  *    Replaced 6 boolean members of csp with one bitmap (csp->flags)
231  *
232  *    Revision 1.27  2001/09/22 16:36:59  jongfoster
233  *    Removing unused parameter fs from read_config_line()
234  *
235  *    Revision 1.26  2001/09/22 14:05:22  jongfoster
236  *    Bugfix: Multiple escaped "#" characters in a configuration
237  *    file are now permitted.
238  *    Also removing 3 unused headers.
239  *
240  *    Revision 1.25  2001/09/13 22:44:03  jongfoster
241  *    Adding {} to an if statement
242  *
243  *    Revision 1.24  2001/07/30 22:08:36  jongfoster
244  *    Tidying up #defines:
245  *    - All feature #defines are now of the form FEATURE_xxx
246  *    - Permanently turned off WIN_GUI_EDIT
247  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
248  *
249  *    Revision 1.23  2001/07/20 15:51:54  oes
250  *    Fixed indentation of prepocessor commands
251  *
252  *    Revision 1.22  2001/07/20 15:16:17  haroon
253  *    - per Guy's suggestion, added a while loop in sweep() to catch not just
254  *      the last inactive CSP but all other consecutive inactive CSPs after that
255  *      as well
256  *
257  *    Revision 1.21  2001/07/18 17:26:24  oes
258  *    Changed to conform to new pcrs interface
259  *
260  *    Revision 1.20  2001/07/17 13:07:01  oes
261  *    Fixed segv when last line in config files
262  *     lacked a terminating (\r)\n
263  *
264  *    Revision 1.19  2001/07/13 14:01:54  oes
265  *    Removed all #ifdef PCRS
266  *
267  *    Revision 1.18  2001/06/29 21:45:41  oes
268  *    Indentation, CRLF->LF, Tab-> Space
269  *
270  *    Revision 1.17  2001/06/29 13:31:51  oes
271  *    Various adaptions
272  *
273  *    Revision 1.16  2001/06/09 10:55:28  jongfoster
274  *    Changing BUFSIZ ==> BUFFER_SIZE
275  *
276  *    Revision 1.15  2001/06/07 23:14:14  jongfoster
277  *    Removing ACL and forward file loaders - these
278  *    files have been merged into the config file.
279  *    Cosmetic: Moving unloader funcs next to their
280  *    respective loader funcs
281  *
282  *    Revision 1.14  2001/06/01 03:27:04  oes
283  *    Fixed line continuation problem
284  *
285  *    Revision 1.13  2001/05/31 21:28:49  jongfoster
286  *    Removed all permissionsfile code - it's now called the actions
287  *    file, and (almost) all the code is in actions.c
288  *
289  *    Revision 1.12  2001/05/31 17:32:31  oes
290  *
291  *     - Enhanced domain part globbing with infix and prefix asterisk
292  *       matching and optional unanchored operation
293  *
294  *    Revision 1.11  2001/05/29 23:25:24  oes
295  *
296  *     - load_config_line() and load_permissions_file() now use chomp()
297  *
298  *    Revision 1.10  2001/05/29 09:50:24  jongfoster
299  *    Unified blocklist/imagelist/permissionslist.
300  *    File format is still under discussion, but the internal changes
301  *    are (mostly) done.
302  *
303  *    Also modified interceptor behaviour:
304  *    - We now intercept all URLs beginning with one of the following
305  *      prefixes (and *only* these prefixes):
306  *        * http://i.j.b/
307  *        * http://ijbswa.sf.net/config/
308  *        * http://ijbswa.sourceforge.net/config/
309  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
310  *    - Internal changes so that intercepted and fast redirect pages
311  *      are not replaced with an image.
312  *    - Interceptors now have the option to send a binary page direct
313  *      to the client. (i.e. ijb-send-banner uses this)
314  *    - Implemented show-url-info interceptor.  (Which is why I needed
315  *      the above interceptors changes - a typical URL is
316  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
317  *      The previous mechanism would not have intercepted that, and
318  *      if it had been intercepted then it then it would have replaced
319  *      it with an image.)
320  *
321  *    Revision 1.9  2001/05/26 17:12:07  jongfoster
322  *    Fatal errors loading configuration files now give better error messages.
323  *
324  *    Revision 1.8  2001/05/26 00:55:20  jongfoster
325  *    Removing duplicated code.  load_forwardfile() now uses create_url_spec()
326  *
327  *    Revision 1.7  2001/05/26 00:28:36  jongfoster
328  *    Automatic reloading of config file.
329  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
330  *    Most of the global variables have been moved to a new
331  *    struct configuration_spec, accessed through csp->config->globalname
332  *    Most of the globals remaining are used by the Win32 GUI.
333  *
334  *    Revision 1.6  2001/05/23 12:27:33  oes
335  *
336  *    Fixed ugly indentation of my last changes
337  *
338  *    Revision 1.5  2001/05/23 10:39:05  oes
339  *    - Added support for escaping the comment character
340  *      in config files by a backslash
341  *    - Added support for line continuation in config
342  *      files
343  *    - Fixed a buffer overflow bug with long config lines
344  *
345  *    Revision 1.4  2001/05/22 18:56:28  oes
346  *    CRLF -> LF
347  *
348  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
349  *    Version 2.9.4 checkin.
350  *    - Merged popupfile and cookiefile, and added control over PCRS
351  *      filtering, in new "permissionsfile".
352  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
353  *      file error you now get a message box (in the Win32 GUI) rather
354  *      than the program exiting with no explanation.
355  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
356  *      skipping.
357  *    - Removed tabs from "config"
358  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
359  *    - Bumped up version number.
360  *
361  *    Revision 1.2  2001/05/17 23:01:01  oes
362  *     - Cleaned CRLF's from the sources and related files
363  *
364  *    Revision 1.1.1.1  2001/05/15 13:58:59  oes
365  *    Initial import of version 2.9.3 source tree
366  *
367  *
368  *********************************************************************/
369 \f
370
371 #include "config.h"
372
373 #include <stdio.h>
374 #include <stdlib.h>
375 #include <sys/types.h>
376 #include <string.h>
377 #include <errno.h>
378 #include <sys/stat.h>
379 #include <ctype.h>
380 #include <assert.h>
381
382 #if !defined(_WIN32) && !defined(__OS2__)
383 #include <unistd.h>
384 #endif
385
386 #include "project.h"
387 #include "list.h"
388 #include "loaders.h"
389 #include "filters.h"
390 #include "parsers.h"
391 #include "jcc.h"
392 #include "miscutil.h"
393 #include "errlog.h"
394 #include "actions.h"
395 #include "urlmatch.h"
396 #include "encode.h"
397
398 const char loaders_h_rcs[] = LOADERS_H_VERSION;
399
400 /*
401  * Currently active files.
402  * These are also entered in the main linked list of files.
403  */
404
405 #ifdef FEATURE_TRUST
406 static struct file_list *current_trustfile      = NULL;
407 #endif /* def FEATURE_TRUST */
408
409 static int load_one_re_filterfile(struct client_state *csp, int fileid);
410
411 static struct file_list *current_re_filterfile[MAX_AF_FILES]  = {
412    NULL, NULL, NULL, NULL, NULL,
413    NULL, NULL, NULL, NULL, NULL
414 };
415
416 /*
417  * Pseudo filter type for load_one_re_filterfile
418  */
419 #define NO_NEW_FILTER -1
420
421
422 /*********************************************************************
423  *
424  * Function    :  sweep
425  *
426  * Description :  Basically a mark and sweep garbage collector, it is run
427  *                (by the parent thread) every once in a while to reclaim memory.
428  *
429  * It uses a mark and sweep strategy:
430  *   1) mark all files as inactive
431  *
432  *   2) check with each client:
433  *       if it is active,   mark its files as active
434  *       if it is inactive, free its resources
435  *
436  *   3) free the resources of all of the files that
437  *      are still marked as inactive (and are obsolete).
438  *
439  *   N.B. files that are not obsolete don't have an unloader defined.
440  *
441  * Parameters  :  None
442  *
443  * Returns     :  N/A
444  *
445  *********************************************************************/
446 void sweep(void)
447 {
448    struct file_list *fl, *nfl;
449    struct client_state *csp, *last_active;
450    int i;
451
452    /* clear all of the file's active flags */
453    for ( fl = files->next; NULL != fl; fl = fl->next )
454    {
455       fl->active = 0;
456    }
457
458    last_active = clients;
459    csp = clients->next;
460
461    while (NULL != csp)
462    {
463       if (csp->flags & CSP_FLAG_ACTIVE)
464       {
465          /* Mark this client's files as active */
466
467          /*
468           * Always have a configuration file.
469           * (Also note the slightly non-standard extra
470           * indirection here.)
471           */
472          csp->config->config_file_list->active = 1;
473
474          /* 
475           * Actions files
476           */
477          for (i = 0; i < MAX_AF_FILES; i++)
478          {
479             if (csp->actions_list[i])     
480             {
481                csp->actions_list[i]->active = 1;
482             }
483          }
484
485          /*
486           * Filter files
487           */
488          for (i = 0; i < MAX_AF_FILES; i++)
489          {
490             if (csp->rlist[i])     
491             {
492                csp->rlist[i]->active = 1;
493             }
494          }
495
496          /*
497           * Trust file
498           */
499 #ifdef FEATURE_TRUST
500          if (csp->tlist)
501          {
502             csp->tlist->active = 1;
503          }
504 #endif /* def FEATURE_TRUST */
505          
506          last_active = csp;
507          csp = csp->next;
508
509       }
510       else 
511       /*
512        * This client is not active. Free its resources.
513        */
514       {
515          last_active->next = csp->next;
516
517          freez(csp->ip_addr_str);
518          freez(csp->iob->buf);
519          freez(csp->error_message);
520
521          if (csp->action->flags & ACTION_FORWARD_OVERRIDE &&
522              NULL != csp->fwd)
523          {
524             unload_forward_spec(csp->fwd);
525          }
526          free_http_request(csp->http);
527
528          destroy_list(csp->headers);
529          destroy_list(csp->tags);
530
531          free_current_action(csp->action);
532
533 #ifdef FEATURE_STATISTICS
534          urls_read++;
535          if (csp->flags & CSP_FLAG_REJECTED)
536          {
537             urls_rejected++;
538          }
539 #endif /* def FEATURE_STATISTICS */
540
541          freez(csp);
542          
543          csp = last_active->next;
544       }
545    }
546
547    nfl = files;
548    fl = files->next;
549
550    while (fl != NULL)
551    {
552       if ( ( 0 == fl->active ) && ( NULL != fl->unloader ) )
553       {
554          nfl->next = fl->next;
555
556          (fl->unloader)(fl->f);
557
558          freez(fl->filename);
559          freez(fl);
560
561          fl = nfl->next;
562       }
563       else
564       {
565          nfl = fl;
566          fl = fl->next;
567       }
568    }
569
570 }
571
572
573 /*********************************************************************
574  *
575  * Function    :  check_file_changed
576  *
577  * Description :  Helper function to check if a file needs reloading.
578  *                If "current" is still current, return it.  Otherwise
579  *                allocates a new (zeroed) "struct file_list", fills
580  *                in the disk file name and timestamp, and returns it.
581  *
582  * Parameters  :
583  *          1  :  current = The file_list currently being used - will
584  *                          be checked to see if it is out of date.
585  *                          May be NULL (which is treated as out of
586  *                          date).
587  *          2  :  filename = Name of file to check.
588  *          3  :  newfl    = New file list. [Output only]
589  *                           This will be set to NULL, OR a struct
590  *                           file_list newly allocated on the
591  *                           heap, with the filename and lastmodified
592  *                           fields filled, and all others zeroed.
593  *
594  * Returns     :  If file unchanged: 0 (and sets newfl == NULL)
595  *                If file changed: 1 and sets newfl != NULL
596  *                On error: 1 and sets newfl == NULL
597  *
598  *********************************************************************/
599 int check_file_changed(const struct file_list * current,
600                        const char * filename,
601                        struct file_list ** newfl)
602 {
603    struct file_list *fs;
604    struct stat statbuf[1];
605
606    *newfl = NULL;
607
608    if (stat(filename, statbuf) < 0)
609    {
610       /* Error, probably file not found. */
611       return 1;
612    }
613
614    if (current
615        && (current->lastmodified == statbuf->st_mtime)
616        && (0 == strcmp(current->filename, filename)))
617    {
618       return 0;
619    }
620
621    fs = (struct file_list *)zalloc(sizeof(struct file_list));
622    if (fs == NULL)
623    {
624       /* Out of memory error */
625       return 1;
626    }
627
628
629    fs->filename = strdup(filename);
630    fs->lastmodified = statbuf->st_mtime;
631
632    if (fs->filename == NULL)
633    {
634       /* Out of memory error */
635       freez (fs);
636       return 1;
637    }
638    *newfl = fs;
639    return 1;
640 }
641
642
643 /*********************************************************************
644  *
645  * Function    :  simple_read_line
646  *
647  * Description :  Read a single line from a file and return it.
648  *                This is basically a version of fgets() that malloc()s
649  *                it's own line buffer.  Note that the buffer will
650  *                always be a multiple of BUFFER_SIZE bytes long.
651  *                Therefore if you are going to keep the string for
652  *                an extended period of time, you should probably
653  *                strdup() it and free() the original, to save memory.
654  *
655  *
656  * Parameters  :
657  *          1  :  dest = destination for newly malloc'd pointer to
658  *                line data.  Will be set to NULL on error.
659  *          2  :  fp = File to read from
660  *          3  :  newline = Standard for newlines in the file.
661  *                Will be unchanged if it's value on input is not
662  *                NEWLINE_UNKNOWN.
663  *                On output, may be changed from NEWLINE_UNKNOWN to
664  *                actual convention in file.
665  *
666  * Returns     :  JB_ERR_OK     on success
667  *                JB_ERR_MEMORY on out-of-memory
668  *                JB_ERR_FILE   on EOF.
669  *
670  *********************************************************************/
671 jb_err simple_read_line(FILE *fp, char **dest, int *newline)
672 {
673    size_t len = 0;
674    size_t buflen = BUFFER_SIZE;
675    char * buf;
676    char * p;
677    int ch;
678    int realnewline = NEWLINE_UNKNOWN;
679
680    if (NULL == (buf = malloc(buflen)))
681    {
682       return JB_ERR_MEMORY;
683    }
684
685    p = buf;
686
687 /*
688  * Character codes.  If you have a wierd compiler and the following are
689  * incorrect, you also need to fix NEWLINE() in loaders.h
690  */
691 #define CHAR_CR '\r' /* ASCII 13 */
692 #define CHAR_LF '\n' /* ASCII 10 */
693
694    for (;;)
695    {
696       ch = getc(fp);
697       if (ch == EOF)
698       {
699          if (len > 0)
700          {
701             *p = '\0';
702             *dest = buf;
703             return JB_ERR_OK;
704          }
705          else
706          {
707             free(buf);
708             *dest = NULL;
709             return JB_ERR_FILE;
710          }
711       }
712       else if (ch == CHAR_CR)
713       {
714          ch = getc(fp);
715          if (ch == CHAR_LF)
716          {
717             if (*newline == NEWLINE_UNKNOWN)
718             {
719                *newline = NEWLINE_DOS;
720             }
721          }
722          else
723          {
724             if (ch != EOF)
725             {
726                ungetc(ch, fp);
727             }
728             if (*newline == NEWLINE_UNKNOWN)
729             {
730                *newline = NEWLINE_MAC;
731             }
732          }
733          *p = '\0';
734          *dest = buf;
735          if (*newline == NEWLINE_UNKNOWN)
736          {
737             *newline = realnewline;
738          }
739          return JB_ERR_OK;
740       }
741       else if (ch == CHAR_LF)
742       {
743          *p = '\0';
744          *dest = buf;
745          if (*newline == NEWLINE_UNKNOWN)
746          {
747             *newline = NEWLINE_UNIX;
748          }
749          return JB_ERR_OK;
750       }
751       else if (ch == 0)
752       {
753          *p = '\0';
754          *dest = buf;
755          return JB_ERR_OK;
756       }
757
758       *p++ = (char)ch;
759
760       if (++len >= buflen)
761       {
762          buflen += BUFFER_SIZE;
763          if (NULL == (p = realloc(buf, buflen)))
764          {
765             free(buf);
766             return JB_ERR_MEMORY;
767          }
768          buf = p;
769          p = buf + len;
770       }
771    }
772 }
773
774
775 /*********************************************************************
776  *
777  * Function    :  edit_read_line
778  *
779  * Description :  Read a single non-empty line from a file and return
780  *                it.  Trims comments, leading and trailing whitespace
781  *                and respects escaping of newline and comment char.
782  *                Provides the line in 2 alternative forms: raw and
783  *                preprocessed.
784  *                - raw is the raw data read from the file.  If the
785  *                  line is not modified, then this should be written
786  *                  to the new file.
787  *                - prefix is any comments and blank lines that were
788  *                  read from the file.  If the line is modified, then
789  *                  this should be written out to the file followed
790  *                  by the modified data.  (If this string is non-empty
791  *                  then it will have a newline at the end).
792  *                - data is the actual data that will be parsed
793  *                  further by appropriate routines.
794  *                On EOF, the 3 strings will all be set to NULL and
795  *                0 will be returned.
796  *
797  * Parameters  :
798  *          1  :  fp = File to read from
799  *          2  :  raw_out = destination for newly malloc'd pointer to
800  *                raw line data.  May be NULL if you don't want it.
801  *          3  :  prefix_out = destination for newly malloc'd pointer to
802  *                comments.  May be NULL if you don't want it.
803  *          4  :  data_out = destination for newly malloc'd pointer to
804  *                line data with comments and leading/trailing spaces
805  *                removed, and line continuation performed.  May be
806  *                NULL if you don't want it.
807  *          5  :  newline = Standard for newlines in the file.
808  *                On input, set to value to use or NEWLINE_UNKNOWN.
809  *                On output, may be changed from NEWLINE_UNKNOWN to
810  *                actual convention in file.  May be NULL if you
811  *                don't want it.
812  *          6  :  line_number = Line number in file.  In "lines" as
813  *                reported by a text editor, not lines containing data.
814  *
815  * Returns     :  JB_ERR_OK     on success
816  *                JB_ERR_MEMORY on out-of-memory
817  *                JB_ERR_FILE   on EOF.
818  *
819  *********************************************************************/
820 jb_err edit_read_line(FILE *fp,
821                       char **raw_out,
822                       char **prefix_out,
823                       char **data_out,
824                       int *newline,
825                       unsigned long *line_number)
826 {
827    char *p;          /* Temporary pointer   */
828    char *linebuf;    /* Line read from file */
829    char *linestart;  /* Start of linebuf, usually first non-whitespace char */
830    int contflag = 0; /* Nonzero for line continuation - i.e. line ends '\' */
831    int is_empty = 1; /* Flag if not got any data yet */
832    char *raw    = NULL; /* String to be stored in raw_out    */
833    char *prefix = NULL; /* String to be stored in prefix_out */
834    char *data   = NULL; /* String to be stored in data_out   */
835    int scrapnewline;    /* Used for (*newline) if newline==NULL */
836    jb_err rval = JB_ERR_OK;
837
838    assert(fp);
839    assert(raw_out || data_out);
840    assert(newline == NULL
841        || *newline == NEWLINE_UNKNOWN
842        || *newline == NEWLINE_UNIX
843        || *newline == NEWLINE_DOS
844        || *newline == NEWLINE_MAC);
845
846    if (newline == NULL)
847    {
848       scrapnewline = NEWLINE_UNKNOWN;
849       newline = &scrapnewline;
850    }
851
852    /* Set output parameters to NULL */
853    if (raw_out)
854    {
855       *raw_out    = NULL;
856    }
857    if (prefix_out)
858    {
859       *prefix_out = NULL;
860    }
861    if (data_out)
862    {
863       *data_out   = NULL;
864    }
865
866    /* Set string variables to new, empty strings. */
867
868    if (raw_out)
869    {
870       if ((raw = malloc(1)) == NULL)
871       {
872          return JB_ERR_MEMORY;
873       }
874       *raw = '\0';
875    }
876    if (prefix_out)
877    {
878       if ((prefix = malloc(1)) == NULL)
879       {
880          freez(raw);
881          return JB_ERR_MEMORY;
882       }
883       *prefix = '\0';
884    }
885    if (data_out)
886    {
887       if ((data = malloc(1)) == NULL)
888       {
889          freez(raw);
890          freez(prefix);
891          return JB_ERR_MEMORY;
892       }
893       *data = '\0';
894    }
895
896    /* Main loop.  Loop while we need more data & it's not EOF. */
897
898    while ( (contflag || is_empty)
899         && (JB_ERR_OK == (rval = simple_read_line(fp, &linebuf, newline))))
900    {
901       if (line_number)
902       {
903          (*line_number)++;
904       }
905       if (raw)
906       {
907          string_append(&raw,linebuf);
908          if (string_append(&raw,NEWLINE(*newline)))
909          {
910             freez(prefix);
911             freez(data);
912             free(linebuf);
913             return JB_ERR_MEMORY;
914          }
915       }
916
917       /* Line continuation? Trim escape and set flag. */
918       p = linebuf + strlen(linebuf) - 1;
919       contflag = ((*linebuf != '\0') && (*p == '\\'));
920       if (contflag)
921       {
922          *p = '\0';
923       }
924
925       /* Trim leading spaces if we're at the start of the line */
926       linestart = linebuf;
927       if (*data == '\0')
928       {
929          /* Trim leading spaces */
930          while (*linestart && isspace((int)(unsigned char)*linestart))
931          {
932             linestart++;
933          }
934       }
935
936       /* Handle comment characters. */
937       p = linestart;
938       while ((p = strchr(p, '#')) != NULL)
939       {
940          /* Found a comment char.. */
941          if ((p != linebuf) && (*(p-1) == '\\'))
942          {
943             /* ..and it's escaped, left-shift the line over the escape. */
944             char *q = p - 1;
945             while ((*q = *(q + 1)) != '\0')
946             {
947                q++;
948             }
949             /* Now scan from just after the "#". */
950          }
951          else
952          {
953             /* Real comment.  Save it... */
954             if (p == linestart)
955             {
956                /* Special case:  Line only contains a comment, so all the
957                 * previous whitespace is considered part of the comment.
958                 * Undo the whitespace skipping, if any.
959                 */
960                linestart = linebuf;
961                p = linestart;
962             }
963             if (prefix)
964             {
965                string_append(&prefix,p);
966                if (string_append(&prefix, NEWLINE(*newline)))
967                {
968                   freez(raw);
969                   freez(data);
970                   free(linebuf);
971                   return JB_ERR_MEMORY;
972                }
973             }
974
975             /* ... and chop off the rest of the line */
976             *p = '\0';
977          }
978       } /* END while (there's a # character) */
979
980       /* Write to the buffer */
981       if (*linestart)
982       {
983          is_empty = 0;
984          if (data)
985          {
986             if (string_append(&data, linestart))
987             {
988                freez(raw);
989                freez(prefix);
990                free(linebuf);
991                return JB_ERR_MEMORY;
992             }
993          }
994       }
995
996       free(linebuf);
997    } /* END while(we need more data) */
998
999    /* Handle simple_read_line() errors - ignore EOF */
1000    if ((rval != JB_ERR_OK) && (rval != JB_ERR_FILE))
1001    {
1002       freez(raw);
1003       freez(prefix);
1004       freez(data);
1005       return rval;
1006    }
1007
1008    if (raw ? (*raw == '\0') : is_empty)
1009    {
1010       /* EOF and no data there.  (Definition of "data" depends on whether
1011        * the caller cares about "raw" or just "data").
1012        */
1013
1014       freez(raw);
1015       freez(prefix);
1016       freez(data);
1017
1018       return JB_ERR_FILE;
1019    }
1020    else
1021    {
1022       /* Got at least some data */
1023
1024       /* Remove trailing whitespace */
1025       chomp(data);
1026
1027       if (raw_out)
1028       {
1029          *raw_out    = raw;
1030       }
1031       else
1032       {
1033          freez(raw);
1034       }
1035       if (prefix_out)
1036       {
1037          *prefix_out = prefix;
1038       }
1039       else
1040       {
1041          freez(prefix);
1042       }
1043       if (data_out)
1044       {
1045          *data_out   = data;
1046       }
1047       else
1048       {
1049          freez(data);
1050       }
1051       return JB_ERR_OK;
1052    }
1053 }
1054
1055
1056 /*********************************************************************
1057  *
1058  * Function    :  read_config_line
1059  *
1060  * Description :  Read a single non-empty line from a file and return
1061  *                it.  Trims comments, leading and trailing whitespace
1062  *                and respects escaping of newline and comment char.
1063  *
1064  * Parameters  :
1065  *          1  :  buf = Buffer to use.
1066  *          2  :  buflen = Size of buffer in bytes.
1067  *          3  :  fp = File to read from
1068  *          4  :  linenum = linenumber in file
1069  *
1070  * Returns     :  NULL on EOF or error
1071  *                Otherwise, returns buf.
1072  *
1073  *********************************************************************/
1074 char *read_config_line(char *buf, size_t buflen, FILE *fp, unsigned long *linenum)
1075 {
1076    jb_err err;
1077    char *buf2 = NULL;
1078    err = edit_read_line(fp, NULL, NULL, &buf2, NULL, linenum);
1079    if (err)
1080    {
1081       if (err == JB_ERR_MEMORY)
1082       {
1083          log_error(LOG_LEVEL_FATAL, "Out of memory loading a config file");
1084       }
1085       return NULL;
1086    }
1087    else
1088    {
1089       assert(buf2);
1090       assert(strlen(buf2) + 1U < buflen);
1091       strncpy(buf, buf2, buflen - 1);
1092       free(buf2);
1093       buf[buflen - 1] = '\0';
1094       return buf;
1095    }
1096 }
1097
1098
1099 #ifdef FEATURE_TRUST
1100 /*********************************************************************
1101  *
1102  * Function    :  unload_trustfile
1103  *
1104  * Description :  Unloads a trustfile.
1105  *
1106  * Parameters  :
1107  *          1  :  f = the data structure associated with the trustfile.
1108  *
1109  * Returns     :  N/A
1110  *
1111  *********************************************************************/
1112 static void unload_trustfile(void *f)
1113 {
1114    struct block_spec *cur = (struct block_spec *)f;
1115    struct block_spec *next;
1116
1117    while (cur != NULL)
1118    {
1119       next = cur->next;
1120
1121       free_url_spec(cur->url);
1122       free(cur);
1123
1124       cur = next;
1125    }
1126
1127 }
1128
1129
1130 #ifdef FEATURE_GRACEFUL_TERMINATION
1131 /*********************************************************************
1132  *
1133  * Function    :  unload_current_trust_file
1134  *
1135  * Description :  Unloads current trust file - reset to state at
1136  *                beginning of program.
1137  *
1138  * Parameters  :  None
1139  *
1140  * Returns     :  N/A
1141  *
1142  *********************************************************************/
1143 void unload_current_trust_file(void)
1144 {
1145    if (current_trustfile)
1146    {
1147       current_trustfile->unloader = unload_trustfile;
1148       current_trustfile = NULL;
1149    }
1150 }
1151 #endif /* FEATURE_GRACEFUL_TERMINATION */
1152
1153
1154 /*********************************************************************
1155  *
1156  * Function    :  load_trustfile
1157  *
1158  * Description :  Read and parse a trustfile and add to files list.
1159  *
1160  * Parameters  :
1161  *          1  :  csp = Current client state (buffers, headers, etc...)
1162  *
1163  * Returns     :  0 => Ok, everything else is an error.
1164  *
1165  *********************************************************************/
1166 int load_trustfile(struct client_state *csp)
1167 {
1168    FILE *fp;
1169
1170    struct block_spec *b, *bl;
1171    struct url_spec **tl;
1172
1173    char  buf[BUFFER_SIZE], *p, *q;
1174    int reject, trusted;
1175    struct file_list *fs;
1176    unsigned long linenum = 0;
1177    int trusted_referrers = 0;
1178
1179    if (!check_file_changed(current_trustfile, csp->config->trustfile, &fs))
1180    {
1181       /* No need to load */
1182       if (csp)
1183       {
1184          csp->tlist = current_trustfile;
1185       }
1186       return(0);
1187    }
1188    if (!fs)
1189    {
1190       goto load_trustfile_error;
1191    }
1192
1193    fs->f = bl = (struct block_spec *)zalloc(sizeof(*bl));
1194    if (bl == NULL)
1195    {
1196       goto load_trustfile_error;
1197    }
1198
1199    if ((fp = fopen(csp->config->trustfile, "r")) == NULL)
1200    {
1201       goto load_trustfile_error;
1202    }
1203
1204    tl = csp->config->trust_list;
1205
1206    while (read_config_line(buf, sizeof(buf), fp, &linenum) != NULL)
1207    {
1208       trusted = 0;
1209       reject  = 1;
1210
1211       if (*buf == '+')
1212       {
1213          trusted = 1;
1214          *buf = '~';
1215       }
1216
1217       if (*buf == '~')
1218       {
1219          reject = 0;
1220          p = buf;
1221          q = p+1;
1222          while ((*p++ = *q++) != '\0')
1223          {
1224             /* nop */
1225          }
1226       }
1227
1228       /* skip blank lines */
1229       if (*buf == '\0')
1230       {
1231          continue;
1232       }
1233
1234       /* allocate a new node */
1235       if ((b = zalloc(sizeof(*b))) == NULL)
1236       {
1237          fclose(fp);
1238          goto load_trustfile_error;
1239       }
1240
1241       /* add it to the list */
1242       b->next  = bl->next;
1243       bl->next = b;
1244
1245       b->reject = reject;
1246
1247       /* Save the URL pattern */
1248       if (create_url_spec(b->url, buf))
1249       {
1250          fclose(fp);
1251          goto load_trustfile_error;
1252       }
1253
1254       /*
1255        * save a pointer to URL's spec in the list of trusted URL's, too
1256        */
1257       if (trusted)
1258       {
1259          if(++trusted_referrers < MAX_TRUSTED_REFERRERS)
1260          {
1261             *tl++ = b->url;
1262          }
1263       }
1264    }
1265
1266    if(trusted_referrers >= MAX_TRUSTED_REFERRERS) 
1267    {
1268       /*
1269        * FIXME: ... after Privoxy 3.0.4 is out.
1270        */
1271        log_error(LOG_LEVEL_ERROR, "Too many trusted referrers. Current limit is %d, you are using %d.\n"
1272           "  Additional trusted referrers are treated like ordinary trusted URLs.\n"
1273           "  (You can increase this limit by changing MAX_TRUSTED_REFERRERS in project.h and recompiling).",
1274           MAX_TRUSTED_REFERRERS, trusted_referrers);
1275    }
1276
1277    *tl = NULL;
1278
1279    fclose(fp);
1280
1281    /* the old one is now obsolete */
1282    if (current_trustfile)
1283    {
1284       current_trustfile->unloader = unload_trustfile;
1285    }
1286
1287    fs->next    = files->next;
1288    files->next = fs;
1289    current_trustfile = fs;
1290
1291    if (csp)
1292    {
1293       csp->tlist = fs;
1294    }
1295
1296    return(0);
1297
1298 load_trustfile_error:
1299    log_error(LOG_LEVEL_FATAL, "can't load trustfile '%s': %E",
1300              csp->config->trustfile);
1301    return(-1);
1302
1303 }
1304 #endif /* def FEATURE_TRUST */
1305
1306
1307 /*********************************************************************
1308  *
1309  * Function    :  unload_re_filterfile
1310  *
1311  * Description :  Unload the re_filter list by freeing all chained
1312  *                re_filterfile specs and their data.
1313  *
1314  * Parameters  :
1315  *          1  :  f = the data structure associated with the filterfile.
1316  *
1317  * Returns     :  N/A
1318  *
1319  *********************************************************************/
1320 static void unload_re_filterfile(void *f)
1321 {
1322    struct re_filterfile_spec *a, *b = (struct re_filterfile_spec *)f;
1323
1324    while (b != NULL)
1325    {
1326       a = b->next;
1327
1328       destroy_list(b->patterns);
1329       pcrs_free_joblist(b->joblist);
1330       freez(b->name);
1331       freez(b->description);
1332       freez(b);
1333
1334       b = a;
1335    }
1336
1337    return;
1338 }
1339
1340 /*********************************************************************
1341  *
1342  * Function    :  unload_forward_spec
1343  *
1344  * Description :  Unload the forward spec settings by freeing all 
1345  *                memory referenced by members and the memory for
1346  *                the spec itself.
1347  *
1348  * Parameters  :
1349  *          1  :  fwd = the forward spec.
1350  *
1351  * Returns     :  N/A
1352  *
1353  *********************************************************************/
1354 void unload_forward_spec(struct forward_spec *fwd)
1355 {
1356    free_url_spec(fwd->url);
1357    freez(fwd->gateway_host);
1358    freez(fwd->forward_host);
1359    free(fwd);
1360
1361    return;
1362 }
1363
1364
1365 #ifdef FEATURE_GRACEFUL_TERMINATION
1366 /*********************************************************************
1367  *
1368  * Function    :  unload_current_re_filterfile
1369  *
1370  * Description :  Unloads current re_filter file - reset to state at
1371  *                beginning of program.
1372  *
1373  * Parameters  :  None
1374  *
1375  * Returns     :  N/A
1376  *
1377  *********************************************************************/
1378 void unload_current_re_filterfile(void)
1379 {
1380    int i;
1381
1382    for (i = 0; i < MAX_AF_FILES; i++)
1383    {
1384       if (current_re_filterfile[i])
1385       {
1386          current_re_filterfile[i]->unloader = unload_re_filterfile;
1387          current_re_filterfile[i] = NULL;
1388       }
1389    }
1390 }
1391 #endif
1392
1393
1394 /*********************************************************************
1395  *
1396  * Function    :  load_re_filterfiles
1397  *
1398  * Description :  Loads all the filterfiles. 
1399  *                Generate a chained list of re_filterfile_spec's from
1400  *                the "FILTER: " blocks, compiling all their substitutions
1401  *                into chained lists of pcrs_job structs.
1402  *
1403  * Parameters  :
1404  *          1  :  csp = Current client state (buffers, headers, etc...)
1405  *
1406  * Returns     :  0 => Ok, everything else is an error.
1407  *
1408  *********************************************************************/
1409 int load_re_filterfiles(struct client_state *csp)
1410 {
1411    int i;
1412    int result;
1413
1414    for (i = 0; i < MAX_AF_FILES; i++)
1415    {
1416       if (csp->config->re_filterfile[i])
1417       {
1418          result = load_one_re_filterfile(csp, i);
1419          if (result)
1420          {
1421             return result;
1422          }
1423       }
1424       else if (current_re_filterfile[i])
1425       {
1426          current_re_filterfile[i]->unloader = unload_re_filterfile;
1427          current_re_filterfile[i] = NULL;
1428       }
1429    }
1430
1431    return 0;
1432 }
1433
1434
1435 /*********************************************************************
1436  *
1437  * Function    :  load_one_re_filterfile
1438  *
1439  * Description :  Load a re_filterfile. 
1440  *                Generate a chained list of re_filterfile_spec's from
1441  *                the "FILTER: " blocks, compiling all their substitutions
1442  *                into chained lists of pcrs_job structs.
1443  *
1444  * Parameters  :
1445  *          1  :  csp = Current client state (buffers, headers, etc...)
1446  *
1447  * Returns     :  0 => Ok, everything else is an error.
1448  *
1449  *********************************************************************/
1450 int load_one_re_filterfile(struct client_state *csp, int fileid)
1451 {
1452    FILE *fp;
1453
1454    struct re_filterfile_spec *new_bl, *bl = NULL;
1455    struct file_list *fs;
1456
1457    char  buf[BUFFER_SIZE];
1458    int error;
1459    unsigned long linenum = 0;
1460    pcrs_job *dummy, *lastjob = NULL;
1461
1462    /*
1463     * No need to reload if unchanged
1464     */
1465    if (!check_file_changed(current_re_filterfile[fileid], csp->config->re_filterfile[fileid], &fs))
1466    {
1467       if (csp)
1468       {
1469          csp->rlist[fileid] = current_re_filterfile[fileid];
1470       }
1471       return(0);
1472    }
1473    if (!fs)
1474    {
1475       goto load_re_filterfile_error;
1476    }
1477
1478    /* 
1479     * Open the file or fail
1480     */
1481    if ((fp = fopen(csp->config->re_filterfile[fileid], "r")) == NULL)
1482    {
1483       goto load_re_filterfile_error;
1484    }
1485
1486    /* 
1487     * Read line by line
1488     */
1489    while (read_config_line(buf, sizeof(buf), fp, &linenum) != NULL)
1490    {
1491       int new_filter = NO_NEW_FILTER;
1492
1493       if (strncmp(buf, "FILTER:", 7) == 0)
1494       {
1495          new_filter = FT_CONTENT_FILTER;
1496       }
1497       else if (strncmp(buf, "SERVER-HEADER-FILTER:", 21) == 0)
1498       {
1499          new_filter = FT_SERVER_HEADER_FILTER;
1500       }
1501       else if (strncmp(buf, "CLIENT-HEADER-FILTER:", 21) == 0)
1502       {
1503          new_filter = FT_CLIENT_HEADER_FILTER;
1504       }
1505       else if (strncmp(buf, "CLIENT-HEADER-TAGGER:", 21) == 0)
1506       {
1507          new_filter = FT_CLIENT_HEADER_TAGGER;
1508       }
1509       else if (strncmp(buf, "SERVER-HEADER-TAGGER:", 21) == 0)
1510       {
1511          new_filter = FT_SERVER_HEADER_TAGGER;
1512       }
1513
1514       /*
1515        * If this is the head of a new filter block, make it a
1516        * re_filterfile spec of its own and chain it to the list:
1517        */
1518       if (new_filter != NO_NEW_FILTER)
1519       {
1520          new_bl = (struct re_filterfile_spec  *)zalloc(sizeof(*bl));
1521          if (new_bl == NULL)
1522          {
1523             goto load_re_filterfile_error;
1524          }
1525          if (new_filter == FT_CONTENT_FILTER)
1526          {
1527             new_bl->name = chomp(buf + 7);
1528          }
1529          else
1530          {
1531             new_bl->name = chomp(buf + 21);
1532          }
1533          new_bl->type = new_filter;
1534
1535          /*
1536           * If a filter description is available,
1537           * encode it to HTML and save it.
1538           */
1539          if (NULL != (new_bl->description = strpbrk(new_bl->name, " \t")))
1540          {
1541             *new_bl->description++ = '\0';
1542             new_bl->description = html_encode(chomp(new_bl->description));
1543             if (NULL == new_bl->description)
1544             {
1545                new_bl->description = strdup("Out of memory while encoding this filter's description to HTML");
1546             }
1547          }
1548          else
1549          {
1550             new_bl->description = strdup("No description available for this filter");
1551          }
1552
1553          new_bl->name = strdup(chomp(new_bl->name));
1554          
1555          /*
1556           * If this is the first filter block, chain it
1557           * to the file_list rather than its (nonexistant)
1558           * predecessor
1559           */
1560          if (fs->f == NULL)
1561          {
1562             fs->f = new_bl;
1563          }
1564          else
1565          {
1566             bl->next = new_bl;
1567          }
1568          bl = new_bl;
1569
1570          log_error(LOG_LEVEL_RE_FILTER, "Reading in filter \"%s\" (\"%s\")", bl->name, bl->description);
1571
1572          continue;
1573       }
1574
1575       /* 
1576        * Else, save the expression, make it a pcrs_job
1577        * and chain it into the current filter's joblist 
1578        */
1579       if (bl != NULL)
1580       {
1581          error = enlist(bl->patterns, buf);
1582          if (JB_ERR_MEMORY == error)
1583          {
1584             log_error(LOG_LEVEL_FATAL,
1585                "Out of memory while enlisting re_filter job \'%s\' for filter %s.", buf, bl->name);
1586          }
1587          assert(JB_ERR_OK == error);
1588
1589          if (pcrs_job_is_dynamic(buf))
1590          {
1591             /*
1592              * Dynamic pattern that might contain variables
1593              * and has to be recompiled for every request
1594              */
1595             if (bl->joblist != NULL)
1596             {
1597                 pcrs_free_joblist(bl->joblist);
1598                 bl->joblist = NULL;
1599             }
1600             bl->dynamic = 1;
1601             log_error(LOG_LEVEL_RE_FILTER,
1602                "Adding dynamic re_filter job \'%s\' to filter %s succeeded.", buf, bl->name);
1603             continue;             
1604          }
1605          else if (bl->dynamic)
1606          {
1607             /*
1608              * A previous job was dynamic and as we
1609              * recompile the whole filter anyway, it
1610              * makes no sense to compile this job now.
1611              */
1612             log_error(LOG_LEVEL_RE_FILTER,
1613                "Adding static re_filter job \'%s\' to dynamic filter %s succeeded.", buf, bl->name);
1614             continue;
1615          }
1616
1617          if ((dummy = pcrs_compile_command(buf, &error)) == NULL)
1618          {
1619             log_error(LOG_LEVEL_ERROR,
1620                "Adding re_filter job \'%s\' to filter %s failed with error %d.", buf, bl->name, error);
1621             continue;
1622          }
1623          else
1624          {
1625             if (bl->joblist == NULL)
1626             {
1627                bl->joblist = dummy;
1628             }
1629             else
1630             {
1631                lastjob->next = dummy;
1632             }
1633             lastjob = dummy;
1634             log_error(LOG_LEVEL_RE_FILTER, "Adding re_filter job \'%s\' to filter %s succeeded.", buf, bl->name);
1635          }
1636       }
1637       else
1638       {
1639          log_error(LOG_LEVEL_ERROR, "Ignoring job %s outside filter block in %s, line %d",
1640             buf, csp->config->re_filterfile[fileid], linenum);
1641       }
1642    }
1643
1644    fclose(fp);
1645
1646    /* 
1647     * Schedule the now-obsolete old data for unloading
1648     */
1649    if ( NULL != current_re_filterfile[fileid] )
1650    {
1651       current_re_filterfile[fileid]->unloader = unload_re_filterfile;
1652    }
1653
1654    /*
1655     * Chain this file into the global list of loaded files
1656     */
1657    fs->next    = files->next;
1658    files->next = fs;
1659    current_re_filterfile[fileid] = fs;
1660
1661    if (csp)
1662    {
1663       csp->rlist[fileid] = fs;
1664    }
1665
1666    return( 0 );
1667
1668 load_re_filterfile_error:
1669    log_error(LOG_LEVEL_FATAL, "can't load re_filterfile '%s': %E",
1670              csp->config->re_filterfile[fileid]);
1671    return(-1);
1672
1673 }
1674
1675
1676 /*********************************************************************
1677  *
1678  * Function    :  add_loader
1679  *
1680  * Description :  Called from `load_config'.  Called once for each input
1681  *                file found in config.
1682  *
1683  * Parameters  :
1684  *          1  :  loader = pointer to a function that can parse and load
1685  *                the appropriate config file.
1686  *          2  :  config = The configuration_spec to add the loader to.
1687  *
1688  * Returns     :  N/A
1689  *
1690  *********************************************************************/
1691 void add_loader(int (*loader)(struct client_state *),
1692                 struct configuration_spec * config)
1693 {
1694    int i;
1695
1696    for (i=0; i < NLOADERS; i++)
1697    {
1698       if (config->loaders[i] == NULL)
1699       {
1700          config->loaders[i] = loader;
1701          break;
1702       }
1703    }
1704
1705 }
1706
1707
1708 /*********************************************************************
1709  *
1710  * Function    :  run_loader
1711  *
1712  * Description :  Called from `load_config' and `listen_loop'.  This
1713  *                function keeps the "csp" current with any file mods
1714  *                since the last loop.  If a file is unchanged, the
1715  *                loader functions do NOT reload the file.
1716  *
1717  * Parameters  :
1718  *          1  :  csp = Current client state (buffers, headers, etc...)
1719  *                      Must be non-null.  Reads: "csp->config"
1720  *                      Writes: various data members.
1721  *
1722  * Returns     :  0 => Ok, everything else is an error.
1723  *
1724  *********************************************************************/
1725 int run_loader(struct client_state *csp)
1726 {
1727    int ret = 0;
1728    int i;
1729
1730    for (i=0; i < NLOADERS; i++)
1731    {
1732       if (csp->config->loaders[i] == NULL)
1733       {
1734          break;
1735       }
1736       ret |= (csp->config->loaders[i])(csp);
1737    }
1738    return(ret);
1739
1740 }
1741
1742
1743 /*
1744   Local Variables:
1745   tab-width: 3
1746   end:
1747 */