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