Renaming config files
[privoxy.git] / cgisimple.c
1 const char cgisimple_rcs[] = "$Id: cgisimple.c,v 1.18 2002/03/12 01:44:49 oes Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/cgisimple.c,v $
5  *
6  * Purpose     :  Simple CGIs to get information about JunkBuster's
7  *                status.
8  *                
9  *                Functions declared include:
10  * 
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: cgisimple.c,v $
39  *    Revision 1.18  2002/03/12 01:44:49  oes
40  *    Changed default for "blocked" image from jb logo to checkboard pattern
41  *
42  *    Revision 1.17  2002/03/08 16:43:18  oes
43  *    Added choice beween GIF and PNG built-in images
44  *
45  *    Revision 1.16  2002/03/07 03:48:38  oes
46  *     - Changed built-in images from GIF to PNG
47  *       (with regard to Unisys patent issue)
48  *     - Added a 4x4 pattern PNG which is less intrusive
49  *       than the logo but also clearly marks the deleted banners
50  *
51  *    Revision 1.15  2002/03/06 22:54:35  jongfoster
52  *    Automated function-comment nitpicking.
53  *
54  *    Revision 1.14  2002/03/02 04:14:50  david__schmidt
55  *    Clean up a little CRLF unpleasantness that suddenly appeared
56  *
57  *    Revision 1.13  2002/02/21 00:10:37  jongfoster
58  *    Adding send-banner?type=auto option
59  *
60  *    Revision 1.12  2002/01/23 01:03:32  jongfoster
61  *    Fixing gcc [CygWin] compiler warnings
62  *
63  *    Revision 1.11  2002/01/23 00:01:04  jongfoster
64  *    Adding cgi_transparent_gif() for http://i.j.b/t
65  *    Adding missing html_encode() to many CGI functions.
66  *    Adding urlmatch.[ch] to http://i.j.b/show-version
67  *
68  *    Revision 1.10  2002/01/17 21:10:37  jongfoster
69  *    Changes to cgi_show_url_info to use new matching code from urlmatch.c.
70  *    Also fixing a problem in the same function with improperly quoted URLs
71  *    in output HTML, and adding code to handle https:// URLs correctly.
72  *
73  *    Revision 1.9  2001/11/30 23:09:15  jongfoster
74  *    Now reports on FEATURE_CGI_EDIT_ACTIONS
75  *    Removing FEATURE_DENY_GZIP from template
76  *
77  *    Revision 1.8  2001/11/13 00:14:07  jongfoster
78  *    Fixing stupid bug now I've figured out what || means.
79  *    (It always returns 0 or 1, not one of it's paramaters.)
80  *
81  *    Revision 1.7  2001/10/23 21:48:19  jongfoster
82  *    Cleaning up error handling in CGI functions - they now send back
83  *    a HTML error page and should never cause a FATAL error.  (Fixes one
84  *    potential source of "denial of service" attacks).
85  *
86  *    CGI actions file editor that works and is actually useful.
87  *
88  *    Ability to toggle JunkBuster remotely using a CGI call.
89  *
90  *    You can turn off both the above features in the main configuration
91  *    file, e.g. if you are running a multi-user proxy.
92  *
93  *    Revision 1.6  2001/10/14 22:00:32  jongfoster
94  *    Adding support for a 404 error when an invalid CGI page is requested.
95  *
96  *    Revision 1.5  2001/10/07 15:30:41  oes
97  *    Removed FEATURE_DENY_GZIP
98  *
99  *    Revision 1.4  2001/10/02 15:31:12  oes
100  *    Introduced show-request cgi
101  *
102  *    Revision 1.3  2001/09/22 16:34:44  jongfoster
103  *    Removing unneeded #includes
104  *
105  *    Revision 1.2  2001/09/19 18:01:11  oes
106  *    Fixed comments; cosmetics
107  *
108  *    Revision 1.1  2001/09/16 17:08:54  jongfoster
109  *    Moving simple CGI functions from cgi.c to new file cgisimple.c
110  *
111  *
112  **********************************************************************/
113 \f
114
115 #include "config.h"
116
117 #include <stdio.h>
118 #include <sys/types.h>
119 #include <stdlib.h>
120 #include <ctype.h>
121 #include <string.h>
122 #include <assert.h>
123
124 #ifdef _WIN32
125 #define snprintf _snprintf
126 #endif /* def _WIN32 */
127
128 #include "project.h"
129 #include "cgi.h"
130 #include "cgisimple.h"
131 #include "list.h"
132 #include "encode.h"
133 #include "jcc.h"
134 #include "filters.h"
135 #include "actions.h"
136 #include "miscutil.h"
137 #include "loadcfg.h"
138 #include "parsers.h"
139 #include "urlmatch.h"
140
141 const char cgisimple_h_rcs[] = CGISIMPLE_H_VERSION;
142
143
144 static char *show_rcs(void);
145 static jb_err show_defines(struct map *exports);
146
147
148 /*********************************************************************
149  *
150  * Function    :  cgi_default
151  *
152  * Description :  CGI function that is called if no action was given.
153  *                Lists menu of available unhidden CGIs.
154  *               
155  * Parameters  :
156  *          1  :  csp = Current client state (buffers, headers, etc...)
157  *          2  :  rsp = http_response data structure for output
158  *          3  :  parameters = map of cgi parameters
159  *
160  * CGI Parameters : none
161  *
162  * Returns     :  JB_ERR_OK on success
163  *                JB_ERR_MEMORY on out-of-memory
164  *                (Problems other than out-of-memory should be
165  *                handled by this routine - it should set the
166  *                rsp appropriately and return "success")
167  *
168  *********************************************************************/
169 jb_err cgi_default(struct client_state *csp,
170                    struct http_response *rsp,
171                    const struct map *parameters)
172 {
173    char *tmp;
174    struct map *exports;
175
176    assert(csp);
177    assert(rsp);
178    assert(parameters);
179
180    if (NULL == (exports = default_exports(csp, "")))
181    {
182       return JB_ERR_MEMORY;
183    }
184
185    /* If there were other parameters, export a dump as "cgi-parameters" */
186    if (parameters->first)
187    {
188       tmp = strdup("<p>What made you think this cgi takes parameters?\n"
189                    "Anyway, here they are, in case you're interested:</p>\n");
190       string_join(&tmp, dump_map(parameters));
191       if (tmp == NULL)
192       {
193          free_map(exports);
194          return JB_ERR_MEMORY;
195       }
196       if (map(exports, "cgi-parameters", 1, tmp, 0))
197       {
198          return JB_ERR_MEMORY;
199       }
200    }
201    else
202    {
203       if (map(exports, "cgi-parameters", 1, "", 1))
204       {
205          return JB_ERR_MEMORY;
206       }
207    }
208
209    return template_fill_for_cgi(csp, "default", exports, rsp);
210 }
211
212
213
214
215 /*********************************************************************
216  *
217  * Function    :  cgi_error_404
218  *
219  * Description :  CGI function that is called if an unknown action was
220  *                given.
221  *               
222  * Parameters  :
223  *          1  :  csp = Current client state (buffers, headers, etc...)
224  *          2  :  rsp = http_response data structure for output
225  *          3  :  parameters = map of cgi parameters
226  *
227  * CGI Parameters : none
228  *
229  * Returns     :  JB_ERR_OK on success
230  *                JB_ERR_MEMORY on out-of-memory error.  
231  *
232  *********************************************************************/
233 jb_err cgi_error_404(struct client_state *csp,
234                      struct http_response *rsp,
235                      const struct map *parameters)
236 {
237    struct map *exports;
238
239    assert(csp);
240    assert(rsp);
241    assert(parameters);
242
243    if (NULL == (exports = default_exports(csp, NULL)))
244    {
245       return JB_ERR_MEMORY;
246    }
247
248    rsp->status = strdup("404 JunkBuster configuration page not found");
249    if (rsp->status == NULL)
250    {
251       free_map(exports);
252       return JB_ERR_MEMORY;
253    }
254
255    return template_fill_for_cgi(csp, "cgi-error-404", exports, rsp);
256 }
257
258
259 #ifdef FEATURE_GRACEFUL_TERMINATION
260 /*********************************************************************
261  *
262  * Function    :  cgi_die
263  *
264  * Description :  CGI function to shut down JunkBuster.
265  *                NOTE: Turning this on in a production build
266  *                would be a BAD idea.  An EXTREMELY BAD idea.
267  *                In short, don't do it.
268  *               
269  * Parameters  :
270  *          1  :  csp = Current client state (buffers, headers, etc...)
271  *          2  :  rsp = http_response data structure for output
272  *          3  :  parameters = map of cgi parameters
273  *
274  * CGI Parameters : none
275  *
276  * Returns     :  JB_ERR_OK on success
277  *                JB_ERR_MEMORY on out-of-memory error.  
278  *
279  *********************************************************************/
280 jb_err cgi_die (struct client_state *csp,
281                 struct http_response *rsp,
282                 const struct map *parameters)
283 {
284    assert(csp);
285    assert(rsp);
286    assert(parameters);
287
288    /* quit */
289    g_terminate = 1;
290
291    /*
292     * I don't really care what gets sent back to the browser.
293     * Take the easy option - "out of memory" page.
294     */
295
296    return JB_ERR_MEMORY;
297 }
298 #endif /* def FEATURE_GRACEFUL_TERMINATION */
299
300
301 /*********************************************************************
302  *
303  * Function    :  cgi_show_request
304  *
305  * Description :  Show the client's request and what sed() would have
306  *                made of it.
307  *               
308  * Parameters  :
309  *          1  :  csp = Current client state (buffers, headers, etc...)
310  *          2  :  rsp = http_response data structure for output
311  *          3  :  parameters = map of cgi parameters
312  *
313  * CGI Parameters : none
314  *
315  * Returns     :  JB_ERR_OK on success
316  *                JB_ERR_MEMORY on out-of-memory error.  
317  *
318  *********************************************************************/
319 jb_err cgi_show_request(struct client_state *csp,
320                         struct http_response *rsp,
321                         const struct map *parameters)
322 {
323    char *p;
324    struct map *exports;
325
326    assert(csp);
327    assert(rsp);
328    assert(parameters);
329
330    if (NULL == (exports = default_exports(csp, "show-request")))
331    {
332       return JB_ERR_MEMORY;
333    }
334    
335    /*
336     * Repair the damage done to the IOB by get_header()
337     */
338    for (p = csp->iob->buf; p < csp->iob->eod; p++)
339    {
340       if (*p == '\0') *p = '\n';
341    }
342
343    /*
344     * Export the original client's request and the one we would
345     * be sending to the server if this wasn't a CGI call
346     */
347
348    if (map(exports, "client-request", 1, html_encode(csp->iob->buf), 0))
349    {
350       free_map(exports);
351       return JB_ERR_MEMORY;
352    }
353
354    if (map(exports, "processed-request", 1, html_encode_and_free_original(
355       sed(client_patterns, add_client_headers, csp)), 0))
356    {
357       free_map(exports);
358       return JB_ERR_MEMORY;
359    }
360
361    return template_fill_for_cgi(csp, "show-request", exports, rsp);
362 }
363
364
365 /*********************************************************************
366  *
367  * Function    :  cgi_send_banner
368  *
369  * Description :  CGI function that returns a banner. 
370  *
371  * Parameters  :
372  *          1  :  csp = Current client state (buffers, headers, etc...)
373  *          2  :  rsp = http_response data structure for output
374  *          3  :  parameters = map of cgi parameters
375  *
376  * CGI Parameters :
377  *           type : Selects the type of banner between "trans", "logo",
378  *                  and "auto". Defaults to "logo" if absent or invalid.
379  *                  "auto" means to select as if we were image-blocking.
380  *                  (Only the first character really counts).
381  *
382  * Returns     :  JB_ERR_OK on success
383  *                JB_ERR_MEMORY on out-of-memory error.  
384  *
385  *********************************************************************/
386 jb_err cgi_send_banner(struct client_state *csp,
387                        struct http_response *rsp,
388                        const struct map *parameters)
389 {
390    char imagetype = lookup(parameters, "type")[0];
391
392    if (imagetype == 'a') /* auto */
393    {
394       /* Default to logo */
395       imagetype = 'p';
396 #ifdef FEATURE_IMAGE_BLOCKING
397       if ((csp->action->flags & ACTION_IMAGE_BLOCKER) != 0)
398       {
399          /* determine HOW images should be blocked */
400          const char * p = csp->action->string[ACTION_STRING_IMAGE_BLOCKER];
401
402          /* and handle accordingly: */
403          if ((p != NULL) && (0 == strcmpic(p, "blank")))
404          {
405             imagetype = 'b';
406          }
407          else if ((p != NULL) && (0 == strcmpic(p, "pattern")))
408          {
409             imagetype = 'p';
410          }
411       }
412 #endif /* def FEATURE_IMAGE_BLOCKING */
413    }
414       
415    if ((imagetype == 'b') || (imagetype == 't')) /* blank / transparent */
416    {
417       rsp->body = bindup(image_blank_data, image_blank_length);
418       rsp->content_length = image_blank_length;
419
420    }
421    else  if (imagetype == 'l') /* logo */
422    {
423       rsp->body = bindup(image_logo_data, image_logo_length);
424       rsp->content_length = image_logo_length;
425    }   
426    else /* pattern */
427    {
428       rsp->body = bindup(image_pattern_data, image_pattern_length);
429       rsp->content_length = image_pattern_length;
430    }   
431
432    if (rsp->body == NULL)
433    {
434       return JB_ERR_MEMORY;
435    }
436
437    if (enlist(rsp->headers, "Content-Type: " BUILTIN_IMAGE_MIMETYPE))
438    {
439       return JB_ERR_MEMORY;
440    }
441
442    rsp->is_static = 1;
443
444    return JB_ERR_OK;
445
446 }
447
448
449 /*********************************************************************
450  *
451  * Function    :  cgi_transparent_image
452  *
453  * Description :  CGI function that sends a 1x1 transparent image.
454  *
455  * Parameters  :
456  *          1  :  csp = Current client state (buffers, headers, etc...)
457  *          2  :  rsp = http_response data structure for output
458  *          3  :  parameters = map of cgi parameters
459  *
460  * CGI Parameters : None
461  *
462  * Returns     :  JB_ERR_OK on success
463  *                JB_ERR_MEMORY on out-of-memory error.  
464  *
465  *********************************************************************/
466 jb_err cgi_transparent_image(struct client_state *csp,
467                            struct http_response *rsp,
468                            const struct map *parameters)
469 {
470    rsp->body = bindup(image_blank_data, image_blank_length);
471    rsp->content_length = image_blank_length;
472
473    if (rsp->body == NULL)
474    {
475       return JB_ERR_MEMORY;
476    }
477
478    if (enlist(rsp->headers, "Content-Type: " BUILTIN_IMAGE_MIMETYPE))
479    {
480       return JB_ERR_MEMORY;
481    }
482
483    rsp->is_static = 1;
484
485    return JB_ERR_OK;
486
487 }
488
489
490 /*********************************************************************
491  *
492  * Function    :  cgi_show_version
493  *
494  * Description :  CGI function that returns a a web page describing the
495  *                file versions of IJB.
496  *
497  * Parameters  :
498  *          1  :  csp = Current client state (buffers, headers, etc...)
499  *          2  :  rsp = http_response data structure for output
500  *          3  :  parameters = map of cgi parameters
501  *
502  * CGI Parameters : none
503  *
504  * Returns     :  JB_ERR_OK on success
505  *                JB_ERR_MEMORY on out-of-memory error.  
506  *
507  *********************************************************************/
508 jb_err cgi_show_version(struct client_state *csp,
509                         struct http_response *rsp,
510                         const struct map *parameters)
511 {
512    struct map *exports;
513
514    assert(csp);
515    assert(rsp);
516    assert(parameters);
517
518    if (NULL == (exports = default_exports(csp, "show-version")))
519    {
520       return JB_ERR_MEMORY;
521    }
522
523    if (map(exports, "sourceversions", 1, show_rcs(), 0))
524    {
525       free_map(exports);
526       return JB_ERR_MEMORY;
527    }
528
529    return template_fill_for_cgi(csp, "show-version", exports, rsp);
530 }
531
532  
533 /*********************************************************************
534  *
535  * Function    :  cgi_show_status
536  *
537  * Description :  CGI function that returns a a web page describing the
538  *                current status of IJB.
539  *
540  * Parameters  :
541  *          1  :  csp = Current client state (buffers, headers, etc...)
542  *          2  :  rsp = http_response data structure for output
543  *          3  :  parameters = map of cgi parameters
544  *
545  * CGI Parameters :
546  *        file :  Which file to show.  Only first letter is checked,
547  *                valid values are:
548  *                - "p"ermissions (actions) file
549  *                - "r"egex
550  *                - "t"rust
551  *                Default is to show menu and other information.
552  *
553  * Returns     :  JB_ERR_OK on success
554  *                JB_ERR_MEMORY on out-of-memory error.  
555  *
556  *********************************************************************/
557 jb_err cgi_show_status(struct client_state *csp,
558                        struct http_response *rsp,
559                        const struct map *parameters)
560 {
561    char *s = NULL;
562    int i;
563
564    FILE * fp;
565    char buf[BUFFER_SIZE];
566    const char * filename = NULL;
567    char * file_description = NULL;
568 #ifdef FEATURE_STATISTICS
569    float perc_rej;   /* Percentage of http requests rejected */
570    int local_urls_read;
571    int local_urls_rejected;
572 #endif /* ndef FEATURE_STATISTICS */
573    jb_err err;
574
575    struct map *exports;
576
577    assert(csp);
578    assert(rsp);
579    assert(parameters);
580
581    if (NULL == (exports = default_exports(csp, "show-status")))
582    {
583       return JB_ERR_MEMORY;
584    }
585
586    switch (*(lookup(parameters, "file")))
587    {
588    case 'p':
589       if (csp->actions_list)
590       {
591          filename = csp->actions_list->filename;
592          file_description = "Actions List";
593       }
594       break;
595
596    case 'r':
597       if (csp->rlist)
598       {
599          filename = csp->rlist->filename;
600          file_description = "Regex Filter List";
601       }
602       break;
603
604 #ifdef FEATURE_TRUST
605    case 't':
606       if (csp->tlist)
607       {
608          filename = csp->tlist->filename;
609          file_description = "Trust List";
610       }
611       break;
612 #endif /* def FEATURE_TRUST */
613    }
614
615    if (NULL != filename)
616    {
617       if ( map(exports, "file-description", 1, file_description, 1)
618         || map(exports, "filepath", 1, html_encode(filename), 0) )
619       {
620          free_map(exports);
621          return JB_ERR_MEMORY;
622       }
623
624       if ((fp = fopen(filename, "r")) == NULL)
625       {
626          if (map(exports, "content", 1, "<h1>ERROR OPENING FILE!</h1>", 1))
627          {
628             free_map(exports);
629             return JB_ERR_MEMORY;
630          }
631       }
632       else
633       {
634          s = strdup("");
635          while ((s != NULL) && fgets(buf, sizeof(buf), fp))
636          {
637             string_join  (&s, html_encode(buf));
638             string_append(&s, "<br>");
639          }
640          fclose(fp);
641
642          if (map(exports, "contents", 1, s, 0))
643          {
644             free_map(exports);
645             return JB_ERR_MEMORY;
646          }
647       }
648
649       return template_fill_for_cgi(csp, "show-status-file", exports, rsp);
650    }
651
652    if (map(exports, "redirect-url", 1, html_encode(REDIRECT_URL), 0))
653    {
654       free_map(exports);
655       return JB_ERR_MEMORY;
656    }
657    
658    s = strdup("");
659    for (i = 0; (s != NULL) && (i < Argc); i++)
660    {
661       string_join  (&s, html_encode(Argv[i]));
662       string_append(&s, " ");
663    }
664    if (map(exports, "invocation", 1, s, 0))
665    {
666       free_map(exports);
667       return JB_ERR_MEMORY;
668    }
669
670    err = map(exports, "options", 1, csp->config->proxy_args, 1);
671    if (!err) err = show_defines(exports);
672
673 #ifdef FEATURE_STATISTICS
674    local_urls_read     = urls_read;
675    local_urls_rejected = urls_rejected;
676
677    /*
678     * Need to alter the stats not to include the fetch of this
679     * page.
680     *
681     * Can't do following thread safely! doh!
682     *
683     * urls_read--;
684     * urls_rejected--; * This will be incremented subsequently *
685     */
686
687    if (local_urls_read == 0)
688    {
689       if (!err) err = map_block_killer(exports, "have-stats");
690    }
691    else
692    {
693       if (!err) err = map_block_killer(exports, "have-no-stats");
694
695       perc_rej = (float)local_urls_rejected * 100.0F /
696             (float)local_urls_read;
697
698       sprintf(buf, "%d", local_urls_read);
699       if (!err) err = map(exports, "requests-received", 1, buf, 1);
700
701       sprintf(buf, "%d", local_urls_rejected);
702       if (!err) err = map(exports, "requests-blocked", 1, buf, 1);
703
704       sprintf(buf, "%6.2f", perc_rej);
705       if (!err) err = map(exports, "percent-blocked", 1, buf, 1);
706    }
707
708 #else /* ndef FEATURE_STATISTICS */
709    err = err || map_block_killer(exports, "statistics");
710 #endif /* ndef FEATURE_STATISTICS */
711
712    if (csp->actions_list)
713    {
714       if (!err) err = map(exports, "actions-filename", 1, html_encode(csp->actions_list->filename), 0);
715    }
716    else
717    {
718       if (!err) err = map(exports, "actions-filename", 1, "None specified", 1);
719    }
720
721    if (csp->rlist)
722    {
723       if (!err) err = map(exports, "re-filter-filename", 1, html_encode(csp->rlist->filename), 0);
724    }
725    else
726    {
727       if (!err) err = map(exports, "re-filter-filename", 1, "None specified", 1);
728    }
729
730 #ifdef FEATURE_TRUST
731    if (csp->tlist)
732    {
733       if (!err) err = map(exports, "trust-filename", 1, html_encode(csp->tlist->filename), 0);
734    }
735    else
736    {
737       if (!err) err = map(exports, "trust-filename", 1, "None specified", 1);
738    }
739 #else
740    if (!err) err = map_block_killer(exports, "trust-support");
741 #endif /* ndef FEATURE_TRUST */
742
743    if (err)
744    {
745       free_map(exports);
746       return JB_ERR_MEMORY;
747    }
748
749    return template_fill_for_cgi(csp, "show-status", exports, rsp);
750 }
751
752  
753 /*********************************************************************
754  *
755  * Function    :  cgi_show_url_info
756  *
757  * Description :  CGI function that determines and shows which actions
758  *                junkbuster will perform for a given url, and which
759  *                matches starting from the defaults have lead to that.
760  *
761  * Parameters  :
762  *          1  :  csp = Current client state (buffers, headers, etc...)
763  *          2  :  rsp = http_response data structure for output
764  *          3  :  parameters = map of cgi parameters
765  *
766  * CGI Parameters :
767  *            url : The url whose actions are to be determined.
768  *                  If url is unset, the url-given conditional will be
769  *                  set, so that all but the form can be suppressed in
770  *                  the template.
771  *
772  * Returns     :  JB_ERR_OK on success
773  *                JB_ERR_MEMORY on out-of-memory error.  
774  *
775  *********************************************************************/
776 jb_err cgi_show_url_info(struct client_state *csp,
777                          struct http_response *rsp,
778                          const struct map *parameters)
779 {
780    char *url_param;
781    struct map *exports;
782
783    assert(csp);
784    assert(rsp);
785    assert(parameters);
786
787    if (NULL == (exports = default_exports(csp, "show-url-info")))
788    {
789       return JB_ERR_MEMORY;
790    }
791
792    /*
793     * Get the url= parameter (if present) and remove any leading/trailing spaces.
794     */
795    url_param = strdup(lookup(parameters, "url"));
796    if (url_param == NULL)
797    {
798       free_map(exports);
799       return JB_ERR_MEMORY;
800    }
801    chomp(url_param);
802
803    /*
804     * Handle prefixes.  4 possibilities:
805     * 1) "http://" or "https://" prefix present and followed by URL - OK
806     * 2) Only the "http://" or "https://" part is present, no URL - change
807     *    to empty string so it will be detected later as "no URL".
808     * 3) Parameter specified but doesn't contain "http(s?)://" - add a
809     *    "http://" prefix.
810     * 4) Parameter not specified or is empty string - let this fall through
811     *    for now, next block of code will handle it.
812     */
813    if (0 == strncmp(url_param, "http://", 7))
814    {
815       if (url_param[7] == '\0')
816       {
817          /*
818           * Empty URL (just prefix).
819           * Make it totally empty so it's caught by the next if()
820           */
821          url_param[0] = '\0';
822       }
823    }
824    else if (0 == strncmp(url_param, "https://", 8))
825    {
826       if (url_param[8] == '\0')
827       {
828          /*
829           * Empty URL (just prefix).
830           * Make it totally empty so it's caught by the next if()
831           */
832          url_param[0] = '\0';
833       }
834    }
835    else if (url_param[0] != '\0')
836    {
837       /*
838        * Unknown prefix - assume http://
839        */
840       char * url_param_prefixed = malloc(7 + 1 + strlen(url_param));
841       if (NULL == url_param_prefixed)
842       {
843          free(url_param);
844          free_map(exports);
845          return JB_ERR_MEMORY;
846       }
847       strcpy(url_param_prefixed, "http://");
848       strcpy(url_param_prefixed + 7, url_param);
849       free(url_param);
850       url_param = url_param_prefixed;
851    }
852
853
854    if (url_param[0] == '\0')
855    {
856       /* URL paramater not specified, display query form only. */
857       free(url_param);
858       if (map_block_killer(exports, "url-given")
859         || map(exports, "url", 1, "", 1))
860       {
861          free_map(exports);
862          return JB_ERR_MEMORY;
863       }
864    }
865    else
866    {
867       /* Given a URL, so query it. */
868       jb_err err;
869       char *matches;
870       char *s;
871       int hits = 0;
872       struct file_list *fl;
873       struct url_actions *b;
874       struct http_request url_to_query[1];
875       struct current_action_spec action[1];
876       
877       if (map(exports, "url", 1, html_encode(url_param), 0))
878       {
879          free(url_param);
880          free_map(exports);
881          return JB_ERR_MEMORY;
882       }
883
884       init_current_action(action);
885
886       if (map(exports, "default", 1, html_encode_and_free_original(
887          current_action_to_text(action)), 0))
888       {
889          free_current_action(action);
890          free(url_param);
891          free_map(exports);
892          return JB_ERR_MEMORY;
893       }
894
895       if (((fl = csp->actions_list) == NULL) || ((b = fl->f) == NULL))
896       {
897          err = map(exports, "matches", 1, "none" , 1);
898          if (!err) err = map(exports, "final", 1, lookup(exports, "default"), 1);
899
900          free_current_action(action);
901          free(url_param);
902
903          if (err)
904          {
905             free_map(exports);
906             return JB_ERR_MEMORY;
907          }
908
909          return template_fill_for_cgi(csp, "show-url-info", exports, rsp);
910       }
911
912       err = parse_http_url(url_param, url_to_query, csp);
913
914       free(url_param);
915
916       if (err == JB_ERR_MEMORY)
917       {
918          free_current_action(action);
919          free_map(exports);
920          return JB_ERR_MEMORY;
921       }
922       else if (err)
923       {
924          /* Invalid URL */
925
926          err = map(exports, "matches", 1, "<b>[Invalid URL specified!]</b>" , 1);
927          if (!err) err = map(exports, "final", 1, lookup(exports, "default"), 1);
928
929          free_current_action(action);
930
931          if (err)
932          {
933             free_map(exports);
934             return JB_ERR_MEMORY;
935          }
936
937          return template_fill_for_cgi(csp, "show-url-info", exports, rsp);
938       }
939
940       /*
941        * We have a warning about SSL paths.  Hide it for insecure sites.
942        */
943       if (!url_to_query->ssl)
944       {
945          if (map_block_killer(exports, "https"))
946          {
947             free_current_action(action);
948             free_map(exports);
949             return JB_ERR_MEMORY;
950          }
951       }
952
953       matches = strdup("");
954
955       for (b = b->next; (b != NULL) && (matches != NULL); b = b->next)
956       {
957          if (url_match(b->url, url_to_query))
958          {
959             string_append(&matches, "<b>{");
960             string_join  (&matches, html_encode_and_free_original(
961                                     actions_to_text(b->action)));
962             string_append(&matches, " }</b><br>\n<code>");
963             string_join  (&matches, html_encode(b->url->spec));
964             string_append(&matches, "</code><br>\n<br>\n");
965
966             if (merge_current_action(action, b->action))
967             {
968                freez(matches);
969                free_http_request(url_to_query);
970                free_current_action(action);
971                free_map(exports);
972                return JB_ERR_MEMORY;
973             }
974             hits++;
975          }
976       }
977
978       free_http_request(url_to_query);
979
980       if (matches == NULL)
981       {
982          free_current_action(action);
983          free_map(exports);
984          return JB_ERR_MEMORY;
985       }
986
987       if (!hits)
988       {
989          free(matches);
990          matches = strdup("none");
991       }
992       if (map(exports, "matches", 1, matches , 0))
993       {
994          free_current_action(action);
995          free_map(exports);
996          return JB_ERR_MEMORY;
997       }
998
999       s = html_encode_and_free_original(current_action_to_text(action));
1000
1001       free_current_action(action);
1002
1003       if (map(exports, "final", 1, s, 0))
1004       {
1005          free_map(exports);
1006          return JB_ERR_MEMORY;
1007       }
1008    }
1009
1010    return template_fill_for_cgi(csp, "show-url-info", exports, rsp);
1011 }
1012
1013
1014 /*********************************************************************
1015  *
1016  * Function    :  cgi_robots_txt
1017  *
1018  * Description :  CGI function to return "/robots.txt".
1019  *
1020  * Parameters  :
1021  *          1  :  csp = Current client state (buffers, headers, etc...)
1022  *          2  :  rsp = http_response data structure for output
1023  *          3  :  parameters = map of cgi parameters
1024  *
1025  * CGI Parameters : None
1026  *
1027  * Returns     :  JB_ERR_OK on success
1028  *                JB_ERR_MEMORY on out-of-memory error.  
1029  *
1030  *********************************************************************/
1031 jb_err cgi_robots_txt(struct client_state *csp,
1032                       struct http_response *rsp,
1033                       const struct map *parameters)
1034 {
1035    char buf[100];
1036    jb_err err;
1037
1038    rsp->body = strdup(
1039       "# This is the Internet Junkbuster control interface.\n"
1040       "# It isn't very useful to index it, and you're likely to break stuff.\n"
1041       "# So go away!\n"
1042       "\n"
1043       "User-agent: *\n"
1044       "Disallow: /\n"
1045       "\n");
1046    if (rsp->body == NULL)
1047    {
1048       return JB_ERR_MEMORY;
1049    }
1050
1051    err = enlist_unique(rsp->headers, "Content-Type: text/plain", 13);
1052
1053    rsp->is_static = 1;
1054
1055    get_http_time(7 * 24 * 60 * 60, buf); /* 7 days into future */
1056    if (!err) err = enlist_unique_header(rsp->headers, "Expires", buf);
1057
1058    return (err ? JB_ERR_MEMORY : JB_ERR_OK);
1059 }
1060
1061
1062 /*********************************************************************
1063  *
1064  * Function    :  show_defines
1065  *
1066  * Description :  Add to a map the state od all conditional #defines
1067  *                used when building
1068  *
1069  * Parameters  :
1070  *          1  :  exports = map to extend
1071  *
1072  * Returns     :  JB_ERR_OK on success
1073  *                JB_ERR_MEMORY on out-of-memory error.  
1074  *
1075  *********************************************************************/
1076 static jb_err show_defines(struct map *exports)
1077 {
1078    jb_err err = JB_ERR_OK;
1079
1080 #ifdef FEATURE_ACL
1081    if (!err) err = map_conditional(exports, "FEATURE_ACL", 1);
1082 #else /* ifndef FEATURE_ACL */
1083    if (!err) err = map_conditional(exports, "FEATURE_ACL", 0);
1084 #endif /* ndef FEATURE_ACL */
1085
1086 #ifdef FEATURE_CGI_EDIT_ACTIONS
1087    if (!err) err = map_conditional(exports, "FEATURE_CGI_EDIT_ACTIONS", 1);
1088 #else /* ifndef FEATURE_COOKIE_JAR */
1089    if (!err) err = map_conditional(exports, "FEATURE_CGI_EDIT_ACTIONS", 0);
1090 #endif /* ndef FEATURE_COOKIE_JAR */
1091
1092 #ifdef FEATURE_COOKIE_JAR
1093    if (!err) err = map_conditional(exports, "FEATURE_COOKIE_JAR", 1);
1094 #else /* ifndef FEATURE_COOKIE_JAR */
1095    if (!err) err = map_conditional(exports, "FEATURE_COOKIE_JAR", 0);
1096 #endif /* ndef FEATURE_COOKIE_JAR */
1097
1098 #ifdef FEATURE_FAST_REDIRECTS
1099    if (!err) err = map_conditional(exports, "FEATURE_FAST_REDIRECTS", 1);
1100 #else /* ifndef FEATURE_FAST_REDIRECTS */
1101    if (!err) err = map_conditional(exports, "FEATURE_FAST_REDIRECTS", 0);
1102 #endif /* ndef FEATURE_FAST_REDIRECTS */
1103
1104 #ifdef FEATURE_FORCE_LOAD
1105    if (!err) err = map_conditional(exports, "FEATURE_FORCE_LOAD", 1);
1106 #else /* ifndef FEATURE_FORCE_LOAD */
1107    if (!err) err = map_conditional(exports, "FEATURE_FORCE_LOAD", 0);
1108 #endif /* ndef FEATURE_FORCE_LOAD */
1109
1110 #ifdef FEATURE_IMAGE_BLOCKING
1111    if (!err) err = map_conditional(exports, "FEATURE_IMAGE_BLOCKING", 1);
1112 #else /* ifndef FEATURE_IMAGE_BLOCKING */
1113    if (!err) err = map_conditional(exports, "FEATURE_IMAGE_BLOCKING", 0);
1114 #endif /* ndef FEATURE_IMAGE_BLOCKING */
1115
1116 #ifdef FEATURE_IMAGE_DETECT_MSIE
1117    if (!err) err = map_conditional(exports, "FEATURE_IMAGE_DETECT_MSIE", 1);
1118 #else /* ifndef FEATURE_IMAGE_DETECT_MSIE */
1119    if (!err) err = map_conditional(exports, "FEATURE_IMAGE_DETECT_MSIE", 0);
1120 #endif /* ndef FEATURE_IMAGE_DETECT_MSIE */
1121
1122 #ifdef FEATURE_KILL_POPUPS
1123    if (!err) err = map_conditional(exports, "FEATURE_KILL_POPUPS", 1);
1124 #else /* ifndef FEATURE_KILL_POPUPS */
1125    if (!err) err = map_conditional(exports, "FEATURE_KILL_POPUPS", 0);
1126 #endif /* ndef FEATURE_KILL_POPUPS */
1127
1128 #ifdef FEATURE_NO_GIFS
1129    if (!err) err = map_conditional(exports, "FEATURE_NO_GIFS", 1);
1130 #else /* ifndef FEATURE_NO_GIFS */
1131    if (!err) err = map_conditional(exports, "FEATURE_NO_GIFS", 0);
1132 #endif /* ndef FEATURE_NO_GIFS */
1133
1134 #ifdef FEATURE_PTHREAD
1135    if (!err) err = map_conditional(exports, "FEATURE_PTHREAD", 1);
1136 #else /* ifndef FEATURE_PTHREAD */
1137    if (!err) err = map_conditional(exports, "FEATURE_PTHREAD", 0);
1138 #endif /* ndef FEATURE_PTHREAD */
1139
1140 #ifdef FEATURE_STATISTICS
1141    if (!err) err = map_conditional(exports, "FEATURE_STATISTICS", 1);
1142 #else /* ifndef FEATURE_STATISTICS */
1143    if (!err) err = map_conditional(exports, "FEATURE_STATISTICS", 0);
1144 #endif /* ndef FEATURE_STATISTICS */
1145
1146 #ifdef FEATURE_TOGGLE
1147    if (!err) err = map_conditional(exports, "FEATURE_TOGGLE", 1);
1148 #else /* ifndef FEATURE_TOGGLE */
1149    if (!err) err = map_conditional(exports, "FEATURE_TOGGLE", 0);
1150 #endif /* ndef FEATURE_TOGGLE */
1151
1152 #ifdef FEATURE_TRUST
1153    if (!err) err = map_conditional(exports, "FEATURE_TRUST", 1);
1154 #else /* ifndef FEATURE_TRUST */
1155    if (!err) err = map_conditional(exports, "FEATURE_TRUST", 0);
1156 #endif /* ndef FEATURE_TRUST */
1157
1158 #ifdef REGEX_GNU
1159    if (!err) err = map_conditional(exports, "REGEX_GNU", 1);
1160 #else /* ifndef REGEX_GNU */
1161    if (!err) err = map_conditional(exports, "REGEX_GNU", 0);
1162 #endif /* def REGEX_GNU */
1163
1164 #ifdef REGEX_PCRE
1165    if (!err) err = map_conditional(exports, "REGEX_PCRE", 1);
1166 #else /* ifndef REGEX_PCRE */
1167    if (!err) err = map_conditional(exports, "REGEX_PCRE", 0);
1168 #endif /* def REGEX_PCRE */
1169
1170 #ifdef STATIC_PCRE
1171    if (!err) err = map_conditional(exports, "STATIC_PCRE", 1);
1172 #else /* ifndef STATIC_PCRE */
1173    if (!err) err = map_conditional(exports, "STATIC_PCRE", 0);
1174 #endif /* ndef STATIC_PCRE */
1175
1176 #ifdef STATIC_PCRS
1177    if (!err) err = map_conditional(exports, "STATIC_PCRS", 1);
1178 #else /* ifndef STATIC_PCRS */
1179    if (!err) err = map_conditional(exports, "STATIC_PCRS", 0);
1180 #endif /* ndef STATIC_PCRS */
1181
1182    if (!err) err = map(exports, "FORCE_PREFIX", 1, FORCE_PREFIX, 1);
1183
1184    return err;
1185 }
1186
1187
1188 /*********************************************************************
1189  *
1190  * Function    :  show_rcs
1191  *
1192  * Description :  Create a string with the rcs info for all sourcefiles
1193  *
1194  * Parameters  :  None
1195  *
1196  * Returns     :  A string, or NULL on out-of-memory.
1197  *
1198  *********************************************************************/
1199 static char *show_rcs(void)
1200 {
1201    char *result = strdup("");
1202    char buf[BUFFER_SIZE];
1203
1204    /* Instead of including *all* dot h's in the project (thus creating a
1205     * tremendous amount of dependencies), I will concede to declaring them
1206     * as extern's.  This forces the developer to add to this list, but oh well.
1207     */
1208
1209 #define SHOW_RCS(__x)              \
1210    {                               \
1211       extern const char __x[];     \
1212       sprintf(buf, "%s\n", __x);   \
1213       string_append(&result, buf); \
1214    }
1215
1216    /* In alphabetical order */
1217    SHOW_RCS(actions_h_rcs)
1218    SHOW_RCS(actions_rcs)
1219    SHOW_RCS(cgi_h_rcs)
1220    SHOW_RCS(cgi_rcs)
1221 #ifdef FEATURE_CGI_EDIT_ACTIONS
1222    SHOW_RCS(cgiedit_h_rcs)
1223    SHOW_RCS(cgiedit_rcs)
1224 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
1225    SHOW_RCS(cgisimple_h_rcs)
1226    SHOW_RCS(cgisimple_rcs)
1227 #ifdef __MINGW32__
1228    SHOW_RCS(cygwin_h_rcs)
1229 #endif
1230    SHOW_RCS(deanimate_h_rcs)
1231    SHOW_RCS(deanimate_rcs)
1232    SHOW_RCS(encode_h_rcs)
1233    SHOW_RCS(encode_rcs)
1234    SHOW_RCS(errlog_h_rcs)
1235    SHOW_RCS(errlog_rcs)
1236    SHOW_RCS(filters_h_rcs)
1237    SHOW_RCS(filters_rcs)
1238    SHOW_RCS(gateway_h_rcs)
1239    SHOW_RCS(gateway_rcs)
1240 #ifdef GNU_REGEX
1241    SHOW_RCS(gnu_regex_h_rcs)
1242    SHOW_RCS(gnu_regex_rcs)
1243 #endif /* def GNU_REGEX */
1244    SHOW_RCS(jbsockets_h_rcs)
1245    SHOW_RCS(jbsockets_rcs)
1246    SHOW_RCS(jcc_h_rcs)
1247    SHOW_RCS(jcc_rcs)
1248 #ifdef FEATURE_KILL_POPUPS
1249    SHOW_RCS(killpopup_h_rcs)
1250    SHOW_RCS(killpopup_rcs)
1251 #endif /* def FEATURE_KILL_POPUPS */
1252    SHOW_RCS(list_h_rcs)
1253    SHOW_RCS(list_rcs)
1254    SHOW_RCS(loadcfg_h_rcs)
1255    SHOW_RCS(loadcfg_rcs)
1256    SHOW_RCS(loaders_h_rcs)
1257    SHOW_RCS(loaders_rcs)
1258    SHOW_RCS(miscutil_h_rcs)
1259    SHOW_RCS(miscutil_rcs)
1260    SHOW_RCS(parsers_h_rcs)
1261    SHOW_RCS(parsers_rcs)
1262    SHOW_RCS(pcrs_rcs)
1263    SHOW_RCS(pcrs_h_rcs)
1264    SHOW_RCS(project_h_rcs)
1265    SHOW_RCS(ssplit_h_rcs)
1266    SHOW_RCS(ssplit_rcs)
1267    SHOW_RCS(urlmatch_h_rcs)
1268    SHOW_RCS(urlmatch_rcs)
1269 #ifdef _WIN32
1270 #ifndef _WIN_CONSOLE
1271    SHOW_RCS(w32log_h_rcs)
1272    SHOW_RCS(w32log_rcs)
1273    SHOW_RCS(w32res_h_rcs)
1274    SHOW_RCS(w32taskbar_h_rcs)
1275    SHOW_RCS(w32taskbar_rcs)
1276 #endif /* ndef _WIN_CONSOLE */
1277    SHOW_RCS(win32_h_rcs)
1278    SHOW_RCS(win32_rcs)
1279 #endif /* def _WIN32 */
1280
1281 #undef SHOW_RCS
1282
1283    return result;
1284
1285 }
1286
1287
1288 /*
1289   Local Variables:
1290   tab-width: 3
1291   end:
1292 */