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