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