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