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