Removed many options from the config file and into the
[privoxy.git] / project.h
1 #ifndef _PROJECT_H
2 #define _PROJECT_H
3 #define PROJECT_H_VERSION "$Id: project.h,v 1.8 2001/05/29 20:09:15 joergs Exp $"
4 /*********************************************************************
5  *
6  * File        :  $Source: /cvsroot/ijbswa/current/project.h,v $
7  *
8  * Purpose     :  Defines data structures which are widely used in the
9  *                project.  Does not define any variables or functions
10  *                (though it does declare some macros).
11  *
12  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
13  *                IJBSWA team.  http://ijbswa.sourceforge.net
14  *
15  *                Based on the Internet Junkbuster originally written
16  *                by and Copyright (C) 1997 Anonymous Coders and 
17  *                Junkbusters Corporation.  http://www.junkbusters.com
18  *
19  *                This program is free software; you can redistribute it 
20  *                and/or modify it under the terms of the GNU General
21  *                Public License as published by the Free Software
22  *                Foundation; either version 2 of the License, or (at
23  *                your option) any later version.
24  *
25  *                This program is distributed in the hope that it will
26  *                be useful, but WITHOUT ANY WARRANTY; without even the
27  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
28  *                PARTICULAR PURPOSE.  See the GNU General Public
29  *                License for more details.
30  *
31  *                The GNU General Public License should be included with
32  *                this file.  If not, you can view it at
33  *                http://www.gnu.org/copyleft/gpl.html
34  *                or write to the Free Software Foundation, Inc., 59
35  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
36  *
37  * Revisions   :
38  *    $Log: project.h,v $
39  *    Revision 1.8  2001/05/29 20:09:15  joergs
40  *    HTTP_REDIRECT_TEMPLATE fixed.
41  *
42  *    Revision 1.7  2001/05/29 09:50:24  jongfoster
43  *    Unified blocklist/imagelist/permissionslist.
44  *    File format is still under discussion, but the internal changes
45  *    are (mostly) done.
46  *
47  *    Also modified interceptor behaviour:
48  *    - We now intercept all URLs beginning with one of the following
49  *      prefixes (and *only* these prefixes):
50  *        * http://i.j.b/
51  *        * http://ijbswa.sf.net/config/
52  *        * http://ijbswa.sourceforge.net/config/
53  *    - New interceptors "home page" - go to http://i.j.b/ to see it.
54  *    - Internal changes so that intercepted and fast redirect pages
55  *      are not replaced with an image.
56  *    - Interceptors now have the option to send a binary page direct
57  *      to the client. (i.e. ijb-send-banner uses this)
58  *    - Implemented show-url-info interceptor.  (Which is why I needed
59  *      the above interceptors changes - a typical URL is
60  *      "http://i.j.b/show-url-info?url=www.somesite.com/banner.gif".
61  *      The previous mechanism would not have intercepted that, and
62  *      if it had been intercepted then it then it would have replaced
63  *      it with an image.)
64  *
65  *    Revision 1.6  2001/05/27 22:17:04  oes
66  *
67  *    - re_process_buffer no longer writes the modified buffer
68  *      to the client, which was very ugly. It now returns the
69  *      buffer, which it is then written by chat.
70  *
71  *    - content_length now adjusts the Content-Length: header
72  *      for modified documents rather than crunch()ing it.
73  *      (Length info in csp->content_length, which is 0 for
74  *      unmodified documents)
75  *
76  *    - For this to work, sed() is called twice when filtering.
77  *
78  *    Revision 1.5  2001/05/26 00:28:36  jongfoster
79  *    Automatic reloading of config file.
80  *    Removed obsolete SIGHUP support (Unix) and Reload menu option (Win32).
81  *    Most of the global variables have been moved to a new
82  *    struct configuration_spec, accessed through csp->config->globalname
83  *    Most of the globals remaining are used by the Win32 GUI.
84  *
85  *    Revision 1.4  2001/05/22 18:46:04  oes
86  *
87  *    - Enabled filtering banners by size rather than URL
88  *      by adding patterns that replace all standard banner
89  *      sizes with the "Junkbuster" gif to the re_filterfile
90  *
91  *    - Enabled filtering WebBugs by providing a pattern
92  *      which kills all 1x1 images
93  *
94  *    - Added support for PCRE_UNGREEDY behaviour to pcrs,
95  *      which is selected by the (nonstandard and therefore
96  *      capital) letter 'U' in the option string.
97  *      It causes the quantifiers to be ungreedy by default.
98  *      Appending a ? turns back to greedy (!).
99  *
100  *    - Added a new interceptor ijb-send-banner, which
101  *      sends back the "Junkbuster" gif. Without imagelist or
102  *      MSIE detection support, or if tinygif = 1, or the
103  *      URL isn't recognized as an imageurl, a lame HTML
104  *      explanation is sent instead.
105  *
106  *    - Added new feature, which permits blocking remote
107  *      script redirects and firing back a local redirect
108  *      to the browser.
109  *      The feature is conditionally compiled, i.e. it
110  *      can be disabled with --disable-fast-redirects,
111  *      plus it must be activated by a "fast-redirects"
112  *      line in the config file, has its own log level
113  *      and of course wants to be displayed by show-proxy-args
114  *      Note: Boy, all the #ifdefs in 1001 locations and
115  *      all the fumbling with configure.in and acconfig.h
116  *      were *way* more work than the feature itself :-(
117  *
118  *    - Because a generic redirect template was needed for
119  *      this, tinygif = 3 now uses the same.
120  *
121  *    - Moved GIFs, and other static HTTP response templates
122  *      to project.h
123  *
124  *    - Some minor fixes
125  *
126  *    - Removed some >400 CRs again (Jon, you really worked
127  *      a lot! ;-)
128  *
129  *    Revision 1.3  2001/05/20 01:21:20  jongfoster
130  *    Version 2.9.4 checkin.
131  *    - Merged popupfile and cookiefile, and added control over PCRS
132  *      filtering, in new "permissionsfile".
133  *    - Implemented LOG_LEVEL_FATAL, so that if there is a configuration
134  *      file error you now get a message box (in the Win32 GUI) rather
135  *      than the program exiting with no explanation.
136  *    - Made killpopup use the PCRS MIME-type checking and HTTP-header
137  *      skipping.
138  *    - Removed tabs from "config"
139  *    - Moved duplicated url parsing code in "loaders.c" to a new funcition.
140  *    - Bumped up version number.
141  *
142  *    Revision 1.2  2001/05/17 23:01:01  oes
143  *     - Cleaned CRLF's from the sources and related files
144  *
145  *    Revision 1.1.1.1  2001/05/15 13:59:03  oes
146  *    Initial import of version 2.9.3 source tree
147  *
148  *
149  *********************************************************************/
150 \f
151
152 /* Declare struct FILE for vars and funcs. */
153 #include <stdio.h>
154
155 /* Need time_t for file_list */
156 #include <time.h>
157
158 /*
159  * Include appropriate regular expression libraries.
160  *
161  * PCRS           ==> Include pcre
162  * REGEX && PCRE  ==> Include pcre and pcreposix
163  * REGEX && !PCRE ==> Include gnu_regex
164  *
165  * STATIC  ==> Use  #include "pcre.h"  (compiling at same time)
166  * !STATIC ==> Use  #include <pcre.h>  (System library)
167  *
168  */
169 #if (defined(REGEX) && defined(PCRE)) || defined(PCRS)
170 #  ifdef STATIC
171 #    include "pcre.h"
172 #  else
173 #    include <pcre.h>
174 #  endif
175 #endif /* (defined(REGEX) && defined(PCRE)) || defined(PCRS) */
176
177 #if defined(REGEX) && defined(PCRE)
178 #  ifdef STATIC
179 #    include "pcreposix.h"
180 #  else
181 #    include <pcreposix.h>
182 #  endif
183 #endif /* defined(REGEX) && defined(PCRE) */
184
185 #if defined(REGEX) && !defined(PCRE)
186 #  include "gnu_regex.h"
187 #endif
188
189 #ifdef PCRS
190 #include "pcrs.h"
191 #endif /* def PCRS */
192
193 #ifdef AMIGA 
194 #include "amiga.h" 
195 #endif /* def AMIGA */
196
197 #ifdef __cplusplus
198 extern "C" {
199 #endif
200
201 #define FOREVER 1
202
203 /* Default IP and port to listen on */
204 #define HADDR_DEFAULT   "127.0.0.1"
205 #define HADDR_PORT      8000
206
207
208 /* Need this for struct gateway */
209 struct client_state;
210
211 /* Need this for struct client_state */
212 struct configuration_spec;
213
214
215 struct http_request
216 {
217    char *cmd;
218    char *gpc;
219    char *host;
220    int   port;
221    char *path;
222    char *ver;
223    char *hostport; /* "host[:port]" */
224    int   ssl;
225 };
226
227 struct gateway
228 {
229    /* generic attributes */
230    char *name;
231    int (*conn)(const struct gateway *, struct http_request *, struct client_state *);
232    int   type;
233
234    /* domain specific attributes */
235    char *gateway_host;
236    int   gateway_port;
237
238    char *forward_host;
239    int   forward_port;
240 };
241
242
243 /* Generic linked list of strings */
244 struct list
245 {
246    char *str;
247    struct list *last;
248    struct list *next;
249 };
250
251
252 /* An I/O buffer */
253 struct iob
254 {
255    char *buf;
256    char *cur;
257    char *eod;
258 };
259
260
261 #define IOB_PEEK(CSP) ((CSP->iob->cur > CSP->iob->eod) ? (CSP->iob->eod - CSP->iob->cur) : 0)
262 #define IOB_RESET(CSP) if(CSP->iob->buf) free(CSP->iob->buf); memset(CSP->iob, '\0', sizeof(CSP->iob));
263
264
265 /* Constants defining bitmask for csp->accept_types */
266
267 #ifdef DETECT_MSIE_IMAGES
268
269 /* MSIE detected by user-agent string */
270 #define ACCEPT_TYPE_IS_MSIE     0x0001
271
272 /*
273  * *If* this is MSIE, it wants an image.  (Or this is a shift-reload, or
274  * it's got an image from this URL before...  yuck!)
275  * Only meaningful if ACCEPT_TYPE_IS_MSIE set 
276  */
277 #define ACCEPT_TYPE_MSIE_IMAGE  0x0002
278
279 /*
280  * *If* this is MSIE, it wants a HTML document.
281  * Only meaningful if ACCEPT_TYPE_IS_MSIE set
282  */
283 #define ACCEPT_TYPE_MSIE_HTML   0x0004
284
285 #endif /* def DETECT_MSIE_IMAGES */
286
287
288 struct client_state
289 {
290    /* The proxy's configuration */
291    struct configuration_spec * config;
292
293
294    /* The permissions that the current URL has */
295    int  permissions;
296
297
298    /* socket to talk to client (web browser) */
299    int  cfd;
300
301    /* socket to talk to server (web server or proxy) */
302    int  sfd;
303
304
305 #ifdef STATISTICS
306    /* 1 if this URL was rejected, 0 otherwise. Allows actual stats inc to 
307     * occur in main thread only for thread-safety. 
308     */
309    int  rejected;
310 #endif /* def STATISTICS */
311
312 #ifdef FORCE_LOAD
313    int force;
314 #endif /* def FORCE_LOAD */
315
316 #ifdef TOGGLE
317    int   toggled_on;
318 #endif /* def TOGGLE */
319
320    /*
321     * Client PC's IP address, as reported by the accept()_ function.
322     * Both as string and number
323     */
324    char *ip_addr_str;
325    long  ip_addr_long;
326
327 #ifdef TRUST_FILES
328    /* The referer in this request, if one was specified. */
329    char *referrer;
330 #endif /* def TRUST_FILES */
331
332 #if defined(DETECT_MSIE_IMAGES)
333    /* Types the client will accept.
334     * Bitmask - see ACCEPT_TYPE_XXX constants.
335     */
336    int accept_types;
337 #endif /* defined(DETECT_MSIE_IMAGES) */
338
339    /* The URL that was requested */
340    struct http_request http[1];
341
342    /* An I/O buffer used for buffering data read from the client */
343    struct iob iob[1];
344
345    /* List of all headers for this request */
346    struct list headers[1];
347
348    /* List of all cookies for this request */
349    struct list cookie_list[1];
350
351 #if defined(PCRS) || defined(KILLPOPUPS)
352    /* Nonzero if this has a text MIME type */
353    int is_text;
354 #endif /* defined(PCRS) || defined(KILLPOPUPS) */
355
356    /* The "X-Forwarded-For:" header sent by the client */
357    char   *x_forwarded;
358
359    /*
360     * Nonzero if this client is processing data.
361     * Set to zero when the thread associated with this structure dies.
362     */
363    int active;
364
365    /* files associated with this client */
366    struct file_list *flist;   /* forwardfile */
367    struct file_list *permissions_list;
368
369
370 #ifdef ACL_FILES
371    struct file_list *alist;   /* aclfile */
372 #endif /* def ACL_FILES */
373
374 #ifdef PCRS
375      struct file_list *rlist;   /* Perl re_filterfile */
376      size_t content_length;     /* Length after processing */ 
377 #endif /* def PCRS */
378
379 #ifdef TRUST_FILES
380    struct file_list *tlist;   /* trustfile */
381 #endif /* def TRUST_FILES */
382
383    struct client_state *next;
384 };
385
386
387 struct parsers
388 {
389    char *str;
390    char  len;
391    char *(*parser)(const struct parsers *, char *, struct client_state *);
392 };
393
394
395 struct interceptors
396 {
397    char *str;
398    char  len;
399    char *(*interceptor)(struct http_request *http, struct client_state *csp);
400 };
401
402
403 /* A URL pattern */
404 struct url_spec
405 {
406    char  *spec;
407    char  *domain;
408    char  *dbuf;
409    char **dvec;
410    int    dcnt;
411    int    unanchored;
412
413    char *path;
414    int   pathlen;
415    int   port;
416 #ifdef REGEX
417    regex_t *preg;
418 #endif
419 };
420
421
422 struct file_list
423 {
424    /*
425     * this is a pointer to the data structures associated with the file.
426     * Read-only once the structure has been created.
427     */
428    void *f;
429    
430    /* Normally NULL.  When we are finished with file (i.e. when we have
431     * loaded a new one), set to a pointer to an unloader function.
432     * Unloader will be called by sweep() (called from main loop) when
433     * all clients using this file are done.  This prevents threading 
434     * problems.
435     */
436    void (*unloader)(void *);
437
438    /* Used internally by sweep().  Do not access from elsewhere. */
439    int active;
440
441 #ifndef SPLIT_PROXY_ARGS
442    /* String to be displayed as part of show-proxy-args display.
443     * Read-only once the structure has been created.
444     */
445    char *proxy_args;
446 #endif /* ndef SPLIT_PROXY_ARGS */
447
448    /* Following variables allow us to check if file has been changed.
449     * Read-only once the structure has been created.
450     */
451    time_t lastmodified;
452    char * filename;
453
454    /* Pointer to next entry in the linked list of all "file_list"s.
455     * This linked list is so that sweep() can navigate it.
456     * Since sweep() can remove items from the list, we must be careful
457     * to only access this value from main thread (when we know sweep
458     * won't be running).
459     */
460    struct file_list *next;
461 };
462
463
464 #ifdef TRUST_FILES
465 struct block_spec
466 {
467    struct url_spec url[1];
468    int    reject;
469    struct block_spec *next;
470 };
471 #endif /* def TRUST_FILES */
472
473
474 #define PERMIT_COOKIE_SET      0x0001U
475 #define PERMIT_COOKIE_READ     0x0002U
476 #define PERMIT_RE_FILTER       0x0004U
477 #define PERMIT_POPUPS          0x0008U
478 #define PERMIT_REFERER         0x0010U /* sic - follow HTTP, not English */
479 #define PERMIT_FAST_REDIRECTS  0x0020U
480 #define PERMIT_BLOCK           0x0040U
481 #define PERMIT_IMAGE           0x0080U
482
483 #define PERMIT_USER_AGENT      PERMIT_COOKIE_SET /* FIXME  Alias this for now */
484
485 #define PERMIT_MASK_ALL        (~0U)
486
487 #define PERMIT_MOST_COMPATIBLE (PERMIT_COOKIE_SET | PERMIT_COOKIE_READ | \
488    PERMIT_REFERER | PERMIT_POPUPS | PERMIT_USER_AGENT)
489
490 struct permissions_spec
491 {
492    struct url_spec url[1];
493    unsigned mask;   /* a bit set to "0" = remove permission */
494    unsigned add;    /* a bit set to "1" = add permission */
495    struct permissions_spec * next;
496 };
497
498
499 struct forward_spec
500 {
501    struct url_spec url[1];
502    struct gateway gw[1];
503    struct forward_spec *next;
504 };
505
506
507 #ifdef PCRS
508 struct re_filterfile_spec
509 {
510    struct list patterns[1];
511    /* See README.re_filter */
512    pcrs_job *joblist;
513 };
514 #endif /* def PCRS */
515
516
517 #ifdef ACL_FILES
518 #define ACL_PERMIT   1  /* accept connection request */
519 #define ACL_DENY     2  /* reject connection request */
520
521 struct access_control_addr
522 {
523    unsigned long addr;
524    unsigned long mask;
525    unsigned long port;
526 };
527
528 struct access_control_list
529 {
530    struct access_control_addr src[1];
531    struct access_control_addr dst[1];
532
533    short action;
534    struct access_control_list *next;
535 };
536 #endif /* def ACL_FILES */
537
538
539 /* Maximum number of loaders (permissions, block, forward, acl...) */
540 #define NLOADERS 8
541
542 /*
543  * Data loaded from the configuration file.
544  *
545  * (Anomaly: toggle is still handled through a global, not this structure)
546  */
547 struct configuration_spec
548 {
549    int debug;
550    int multi_threaded;
551
552 #ifdef IMAGE_BLOCKING
553    int tinygif;
554    const char *tinygifurl;
555 #endif /* def IMAGE_BLOCKING */
556
557    const char *logfile;
558
559    const char *permissions_file;
560    const char *forwardfile;
561
562 #ifdef ACL_FILES
563    const char *aclfile;
564 #endif /* def ACL_FILES */
565
566 #ifdef PCRS
567    const char *re_filterfile;
568 #endif /* def PCRS */
569
570    /*
571     * Permissions to use for URLs not in the permissions list.
572     */
573    int default_permissions;
574
575 #ifdef JAR_FILES
576    const char * jarfile;
577    FILE * jar;
578 #endif /* def JAR_FILES */
579
580    const char *referrer;
581    const char *uagent;
582    const char *from;
583
584    int add_forwarded;
585
586    struct list wafer_list[1];
587    struct list xtra_list[1];
588
589    /*
590     * Port and IP to bind to.
591     * Defaults to HADDR_DEFAULT:HADDR_PORT == 127.0.0.1:8000
592     */
593    const char *haddr;
594    int         hport;
595
596 #ifndef SPLIT_PROXY_ARGS
597    const char *suppress_message;
598 #endif /* ndef SPLIT_PROXY_ARGS */
599
600 #ifndef SPLIT_PROXY_ARGS
601    /* suppress listing config files */
602    int suppress_blocklists;
603 #endif /* ndef SPLIT_PROXY_ARGS */
604
605 #ifdef TRUST_FILES
606    const char * trustfile;
607
608    struct list trust_info[1];
609    struct url_spec *trust_list[64];
610 #endif /* def TRUST_FILES */
611
612    /* Various strings for show-proxy-args */
613    char *proxy_args_header;
614    char *proxy_args_invocation;
615    char *proxy_args_gateways;
616    char *proxy_args_trailer;
617
618    /* the configuration file object. */
619    struct file_list *config_file_list;
620
621    /* List of loaders */
622    int (*loaders[NLOADERS])(struct client_state *);
623
624    /* bool, nonzero if we need to bind() to the new port */
625    int need_bind;
626 };
627
628
629 #define SZ(X)  (sizeof(X) / sizeof(*X))
630
631 #define WHITEBG   "<body bgcolor=\"#ffffff\" link=\"#000078\" alink=\"#ff0022\" vlink=\"#787878\">\n"
632 #define BODY      "<body bgcolor=\"#f8f8f0\" link=\"#000078\" alink=\"#ff0022\" vlink=\"#787878\">\n"
633 #define BANNER    "<strong>Internet J<small>UNK<i><font color=\"red\">BUSTER</font></i></small></strong>"
634
635 #ifdef FORCE_LOAD
636 #define FORCE_PREFIX "/IJB-FORCE-LOAD"
637 #endif /* def FORCE_LOAD */
638
639 #define HOME_PAGE_URL  "http://ijbswa.sourceforge.net/"
640 #define REDIRECT_URL HOME_PAGE_URL "redirect.php?v=" VERSION "&to="
641
642 static const char CFAIL[] =
643    "HTTP/1.0 503 Connect failed\n"
644    "Content-Type: text/html\n\n"
645    "<html>\n"
646    "<head>\n"
647    "<title>Internet Junkbuster: Connect failed</title>\n"
648    "</head>\n"
649    BODY
650    "<h1><center>"
651    BANNER
652    "</center></h1>"
653    "TCP connection to '%s' failed: %s.\n<br>"
654    "</body>\n"
655    "</html>\n";
656
657 static const char CNXDOM[] =
658    "HTTP/1.0 404 Non-existent domain\n"
659    "Content-Type: text/html\n\n"
660    "<html>\n"
661    "<head>\n"
662    "<title>Internet Junkbuster: Non-existent domain</title>\n"
663    "</head>\n"
664    BODY
665    "<h1><center>"
666    BANNER
667    "</center></h1>"
668    "No such domain: %s\n"
669    "</body>\n"
670    "</html>\n";
671
672 static const char CNOBANNER[] =
673    "HTTP/1.0 200 No Banner\n"
674    "Content-Type: text/html\n\n"
675    "<html>\n"
676    "<head>\n"
677    "<title>Internet Junkbuster: No Banner</title>\n"
678    "</head>\n"
679    BODY
680    "<h1><center>"
681    BANNER
682    "</h1>"
683    "You asked for a banner that this proxy can't produce because either configuration does not permit.\n<br>"
684    "or the URL didn't end with .gif\n"
685    "</center></body>\n"
686    "</html>\n";
687
688 static const char CSUCCEED[] =
689    "HTTP/1.0 200 Connection established\n"
690    "Proxy-Agent: IJ/" VERSION "\n\n";
691
692 static const char CHEADER[] =
693    "HTTP/1.0 400 Invalid header received from browser\n\n";
694
695 static const char SHEADER[] =
696    "HTTP/1.0 502 Invalid header received from server\n\n";
697
698 #ifdef IMAGE_BLOCKING
699
700 /*
701  * Hint: You can encode your own GIFs like that:
702  * perl -e 'while (read STDIN, $c, 1) { printf("\\%.3o,", unpack("C", $c)); }'
703  */
704
705 static const char BLANKGIF[] =
706    "HTTP/1.0 200 OK\r\n"
707    "Pragma: no-cache\r\n"
708    "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\r\n"
709    "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\r\n"
710    "Content-type: image/gif\r\n\r\n"
711    "GIF89a\001\000\001\000\200\000\000\377\377\377\000\000"
712    "\000!\371\004\001\000\000\000\000,\000\000\000\000\001"
713    "\000\001\000\000\002\002D\001\000;";
714
715 static const char JBGIF[] =
716    "HTTP/1.0 200 OK\r\n"
717    "Pragma: no-cache\r\n"
718    "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\r\n"
719    "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\r\n"
720    "Content-type: image/gif\r\n\r\n"
721    "GIF89aD\000\013\000\360\000\000\000\000\000\377\377\377!"
722    "\371\004\001\000\000\001\000,\000\000\000\000D\000\013\000"
723    "\000\002a\214\217\251\313\355\277\000\200G&K\025\316hC\037"
724    "\200\234\230Y\2309\235S\230\266\206\372J\253<\3131\253\271"
725    "\270\215\342\254\013\203\371\202\264\334P\207\332\020o\266"
726    "N\215I\332=\211\312\3513\266:\026AK)\364\370\365aobr\305"
727    "\372\003S\275\274k2\354\254z\347?\335\274x\306^9\374\276"
728    "\037Q\000\000;";
729
730 #endif /* def IMAGE_BLOCKING */
731
732 #if defined(FAST_REDIRECTS) || defined(IMAGE_BLOCKING)
733
734 static const char HTTP_REDIRECT_TEMPLATE[] =
735       "HTTP/1.0 302 Local Redirect from Junkbuster\r\n" 
736       "Pragma: no-cache\r\n"
737       "Last-Modified: Thu Jul 31, 1997 07:42:22 pm GMT\r\n"
738       "Expires:       Thu Jul 31, 1997 07:42:22 pm GMT\r\n"
739       "Location: %s\r\n\r\n";
740
741 #endif /*  defined(FAST_REDIRECTS) || defined(IMAGE_BLOCKING) */
742
743 #ifdef __cplusplus
744 } /* extern "C" */
745 #endif
746
747 #endif /* ndef _PROJECT_H */
748
749 /*
750   Local Variables:
751   tab-width: 3
752   end:
753 */