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