Update all patches to CVS version as of 2007-10-14.
[privoxy.git] / cgisimple.c
1 const char cgisimple_rcs[] = "$Id: cgisimple.c,v 1.57 2007/06/01 16:53:05 fabiankeil 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-2007 the SourceForge
13  *                Privoxy team. http://www.privoxy.org/
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.57  2007/06/01 16:53:05  fabiankeil
40  *    Adjust cgi_show_url_info() to show what forward-override{}
41  *    would do with the requested URL (instead of showing how the
42  *    request for the CGI page would be forwarded if it wasn't a
43  *    CGI request).
44  *
45  *    Revision 1.56  2007/05/21 10:50:35  fabiankeil
46  *    - Use strlcpy() instead of strcpy().
47  *    - Stop treating actions files special. Expect a complete file name
48  *      (with or without path) like it's done for the rest of the files.
49  *      Closes FR#588084.
50  *    - Don't rerun sed() in cgi_show_request().
51  *
52  *    Revision 1.55  2007/04/13 13:36:46  fabiankeil
53  *    Reference action files in CGI URLs by id instead
54  *    of using the first part of the file name.
55  *    Fixes BR 1694250 and BR 1590556.
56  *
57  *    Revision 1.54  2007/04/09 18:11:35  fabiankeil
58  *    Don't mistake VC++'s _snprintf() for a snprintf() replacement.
59  *
60  *    Revision 1.53  2007/04/08 13:21:04  fabiankeil
61  *    Reference action files in CGI URLs by id instead
62  *    of using the first part of the file name.
63  *    Fixes BR 1694250 and BR 1590556.
64  *
65  *    Revision 1.52  2007/02/13 15:10:26  fabiankeil
66  *    Apparently fopen()ing in "binary" mode doesn't require
67  *    #ifdefs, it's already done without them in cgiedit.c.
68  *
69  *    Revision 1.51  2007/02/10 16:55:22  fabiankeil
70  *    - Show forwarding settings on the show-url-info page
71  *    - Fix some HTML syntax errors.
72  *
73  *    Revision 1.50  2007/01/23 15:51:17  fabiankeil
74  *    Add favicon delivery functions.
75  *
76  *    Revision 1.49  2007/01/20 16:29:38  fabiankeil
77  *    Suppress edit buttons for action files if Privoxy has
78  *    no write access. Suggested by Roland in PR 1564026.
79  *
80  *    Revision 1.48  2007/01/20 15:31:31  fabiankeil
81  *    Display warning if show-url-info CGI page
82  *    is used while Privoxy is toggled off.
83  *
84  *    Revision 1.47  2007/01/12 15:07:10  fabiankeil
85  *    Use zalloc in cgi_send_user_manual.
86  *
87  *    Revision 1.46  2007/01/02 12:49:46  fabiankeil
88  *    Add FEATURE_ZLIB to the list of conditional
89  *    defines at the show-status page.
90  *
91  *    Revision 1.45  2006/12/28 18:16:41  fabiankeil
92  *    Fixed gcc43 compiler warnings, zero out cgi_send_user_manual's
93  *    body memory before using it, replaced sprintf calls with snprintf.
94  *
95  *    Revision 1.44  2006/12/22 14:19:27  fabiankeil
96  *    Removed checks whether or not AF_FILES have
97  *    data structures associated with them in cgi_show_status.
98  *    It doesn't matter as we're only interested in the file names.
99  *
100  *    For the action files the checks were always true,
101  *    but they prevented empty filter files from being
102  *    listed. Fixes parts of BR 1619208.
103  *
104  *    Revision 1.43  2006/12/17 17:57:56  fabiankeil
105  *    - Added FEATURE_GRACEFUL_TERMINATION to the
106  *      "conditional #defines" section
107  *    - Escaped ampersands in generated HTML.
108  *    - Renamed re-filter-filename to re-filter-filenames
109  *
110  *    Revision 1.42  2006/11/21 15:43:12  fabiankeil
111  *    Add special treatment for WIN32 to make sure
112  *    cgi_send_user_manual opens the files in binary mode.
113  *    Fixes BR 1600411 and unbreaks image delivery.
114  *
115  *    Remove outdated comment.
116  *
117  *    Revision 1.41  2006/10/09 19:18:28  roro
118  *    Redirect http://p.p/user-manual (without trailing slash) to
119  *    http://p.p/user-manual/ (with trailing slash), otherwise links will be broken.
120  *
121  *    Revision 1.40  2006/09/09 13:05:33  fabiankeil
122  *    Modified cgi_send_user_manual to serve binary
123  *    content without destroying it first. Should also be
124  *    faster now. Added ".jpg" check for Content-Type guessing.
125  *
126  *    Revision 1.39  2006/09/08 09:49:23  fabiankeil
127  *    Deliver documents in the user-manual directory
128  *    with "Content-Type text/css" if their filename
129  *    ends with ".css".
130  *
131  *    Revision 1.38  2006/09/06 18:45:03  fabiankeil
132  *    Incorporate modified version of Roland Rosenfeld's patch to
133  *    optionally access the user-manual via Privoxy. Closes patch 679075.
134  *
135  *    Formatting changed to Privoxy style, added call to
136  *    cgi_error_no_template if the requested file doesn't
137  *    exist and modified check whether or not Privoxy itself
138  *    should serve the manual. Should work cross-platform now.
139  *
140  *    Revision 1.37  2006/07/18 14:48:45  david__schmidt
141  *    Reorganizing the repository: swapping out what was HEAD (the old 3.1 branch)
142  *    with what was really the latest development (the v_3_0_branch branch)
143  *
144  *    Revision 1.35.2.7  2006/01/29 23:10:56  david__schmidt
145  *    Multiple filter file support
146  *
147  *    Revision 1.35.2.6  2005/07/04 03:13:43  david__schmidt
148  *    Undo some damaging memory leak patches
149  *
150  *    Revision 1.35.2.5  2005/05/07 21:50:55  david__schmidt
151  *    A few memory leaks plugged (mostly on error paths)
152  *
153  *    Revision 1.35.2.4  2005/04/04 02:21:24  david__schmidt
154  *    Another instance of:
155  *    Don't show "Edit" buttons #ifndef FEATURE_CGI_EDIT_ACTIONS
156  *    Thanks to Magnus Holmgren for the patch
157  *
158  *    Revision 1.35.2.3  2003/12/17 16:34:15  oes
159  *     - Prevent line wrap beween "View/Edit" link buttons on status page
160  *     - Some (mostly irrelevant) fixes for Out-of-mem-case handling
161  *
162  *    Revision 1.35.2.2  2003/04/03 13:48:28  oes
163  *    Don't show "Edit" buttons #ifndef FEATURE_CGI_EDIT_ACTIONS
164  *
165  *    Revision 1.35.2.1  2002/07/04 15:02:38  oes
166  *    Added ability to send redirects to send-banner CGI, so that it can completely mimic the image blocking action if called with type=auto
167  *
168  *    Revision 1.35.2.1  2002/07/01 17:32:04  morcego
169  *    Applying patch from Andreas as provided by Hal on the list.
170  *    Message-ID: <20020701121218.V1606@feenix.burgiss.net>
171  *
172  *    Revision 1.35  2002/05/12 21:44:44  jongfoster
173  *    Adding amiga.[ch] revision information, if on an amiga.
174  *
175  *    Revision 1.34  2002/04/30 12:06:12  oes
176  *    Deleted unused code from default_cgi
177  *
178  *    Revision 1.33  2002/04/30 11:14:52  oes
179  *    Made csp the first parameter in *action_to_html
180  *
181  *    Revision 1.32  2002/04/26 18:29:13  jongfoster
182  *    Fixing this Visual C++ warning:
183  *    cgisimple.c(775) : warning C4018: '<' : signed/unsigned mismatch
184  *
185  *    Revision 1.31  2002/04/26 12:54:36  oes
186  *     - Kill obsolete REDIRECT_URL code
187  *     - Error handling fixes
188  *     - Style sheet related HTML snipplet changes
189  *     - cgi_show_url_info:
190  *       - Matches now in table, actions on single lines,
191  *         linked to help
192  *       - standard.action suppressed
193  *       - Buttons to View and Edit AFs
194  *
195  *    Revision 1.30  2002/04/24 02:18:08  oes
196  *     - show-status is now the starting point for editing
197  *       the actions files, generate list of all AFs with buttons
198  *       for viewing and editing, new look for file list (Jon:
199  *       buttons now aligned ;-P ), view mode now supports multiple
200  *       AFs, name changes, no view links for unspecified files,
201  *       no edit link for standard.action.
202  *
203  *     - Jon's multiple AF patch: cgi_show_url_info now uses all
204  *       AFs and marks the output accordingly
205  *
206  *    Revision 1.29  2002/04/10 13:38:35  oes
207  *    load_template signature changed
208  *
209  *    Revision 1.28  2002/04/07 15:42:12  jongfoster
210  *    Fixing send-banner?type=auto when the image-blocker is
211  *    a redirect to send-banner
212  *
213  *    Revision 1.27  2002/04/05 15:50:48  oes
214  *    added send-stylesheet CGI
215  *
216  *    Revision 1.26  2002/04/04 00:36:36  gliptak
217  *    always use pcre for matching
218  *
219  *    Revision 1.25  2002/04/03 22:28:03  gliptak
220  *    Removed references to gnu_regex
221  *
222  *    Revision 1.24  2002/04/02 16:12:47  oes
223  *    Fix: moving misplaced lines into #ifdef FEATURE_FORCE
224  *
225  *    Revision 1.23  2002/03/26 22:29:54  swa
226  *    we have a new homepage!
227  *
228  *    Revision 1.22  2002/03/24 16:18:15  jongfoster
229  *    Removing old logo
230  *
231  *    Revision 1.21  2002/03/24 15:23:33  jongfoster
232  *    Name changes
233  *
234  *    Revision 1.20  2002/03/24 13:25:43  swa
235  *    name change related issues
236  *
237  *    Revision 1.19  2002/03/16 23:54:06  jongfoster
238  *    Adding graceful termination feature, to help look for memory leaks.
239  *    If you enable this (which, by design, has to be done by hand
240  *    editing config.h) and then go to http://i.j.b/die, then the program
241  *    will exit cleanly after the *next* request.  It should free all the
242  *    memory that was used.
243  *
244  *    Revision 1.18  2002/03/12 01:44:49  oes
245  *    Changed default for "blocked" image from jb logo to checkboard pattern
246  *
247  *    Revision 1.17  2002/03/08 16:43:18  oes
248  *    Added choice beween GIF and PNG built-in images
249  *
250  *    Revision 1.16  2002/03/07 03:48:38  oes
251  *     - Changed built-in images from GIF to PNG
252  *       (with regard to Unisys patent issue)
253  *     - Added a 4x4 pattern PNG which is less intrusive
254  *       than the logo but also clearly marks the deleted banners
255  *
256  *    Revision 1.15  2002/03/06 22:54:35  jongfoster
257  *    Automated function-comment nitpicking.
258  *
259  *    Revision 1.14  2002/03/02 04:14:50  david__schmidt
260  *    Clean up a little CRLF unpleasantness that suddenly appeared
261  *
262  *    Revision 1.13  2002/02/21 00:10:37  jongfoster
263  *    Adding send-banner?type=auto option
264  *
265  *    Revision 1.12  2002/01/23 01:03:32  jongfoster
266  *    Fixing gcc [CygWin] compiler warnings
267  *
268  *    Revision 1.11  2002/01/23 00:01:04  jongfoster
269  *    Adding cgi_transparent_gif() for http://i.j.b/t
270  *    Adding missing html_encode() to many CGI functions.
271  *    Adding urlmatch.[ch] to http://i.j.b/show-version
272  *
273  *    Revision 1.10  2002/01/17 21:10:37  jongfoster
274  *    Changes to cgi_show_url_info to use new matching code from urlmatch.c.
275  *    Also fixing a problem in the same function with improperly quoted URLs
276  *    in output HTML, and adding code to handle https:// URLs correctly.
277  *
278  *    Revision 1.9  2001/11/30 23:09:15  jongfoster
279  *    Now reports on FEATURE_CGI_EDIT_ACTIONS
280  *    Removing FEATURE_DENY_GZIP from template
281  *
282  *    Revision 1.8  2001/11/13 00:14:07  jongfoster
283  *    Fixing stupid bug now I've figured out what || means.
284  *    (It always returns 0 or 1, not one of it's paramaters.)
285  *
286  *    Revision 1.7  2001/10/23 21:48:19  jongfoster
287  *    Cleaning up error handling in CGI functions - they now send back
288  *    a HTML error page and should never cause a FATAL error.  (Fixes one
289  *    potential source of "denial of service" attacks).
290  *
291  *    CGI actions file editor that works and is actually useful.
292  *
293  *    Ability to toggle JunkBuster remotely using a CGI call.
294  *
295  *    You can turn off both the above features in the main configuration
296  *    file, e.g. if you are running a multi-user proxy.
297  *
298  *    Revision 1.6  2001/10/14 22:00:32  jongfoster
299  *    Adding support for a 404 error when an invalid CGI page is requested.
300  *
301  *    Revision 1.5  2001/10/07 15:30:41  oes
302  *    Removed FEATURE_DENY_GZIP
303  *
304  *    Revision 1.4  2001/10/02 15:31:12  oes
305  *    Introduced show-request cgi
306  *
307  *    Revision 1.3  2001/09/22 16:34:44  jongfoster
308  *    Removing unneeded #includes
309  *
310  *    Revision 1.2  2001/09/19 18:01:11  oes
311  *    Fixed comments; cosmetics
312  *
313  *    Revision 1.1  2001/09/16 17:08:54  jongfoster
314  *    Moving simple CGI functions from cgi.c to new file cgisimple.c
315  *
316  *
317  **********************************************************************/
318 \f
319
320 #include "config.h"
321
322 #include <stdio.h>
323 #include <sys/types.h>
324 #include <stdlib.h>
325 #include <ctype.h>
326 #include <string.h>
327 #include <assert.h>
328
329 #ifdef HAVE_ACCESS
330 #include <unistd.h>
331 #endif /* def HAVE_ACCESS */
332
333 #include "project.h"
334 #include "cgi.h"
335 #include "cgisimple.h"
336 #include "list.h"
337 #include "encode.h"
338 #include "jcc.h"
339 #include "filters.h"
340 #include "actions.h"
341 #include "miscutil.h"
342 #include "loadcfg.h"
343 #include "parsers.h"
344 #include "urlmatch.h"
345 #include "errlog.h"
346
347 const char cgisimple_h_rcs[] = CGISIMPLE_H_VERSION;
348
349
350 static char *show_rcs(void);
351 static jb_err show_defines(struct map *exports);
352
353 /*
354  * 16x16 ico blobs for favicon delivery functions.
355  */
356 const char default_favicon_data[] =
357    "\000\000\001\000\001\000\020\020\002\000\000\000\000\000\260"
358    "\000\000\000\026\000\000\000\050\000\000\000\020\000\000\000"
359    "\040\000\000\000\001\000\001\000\000\000\000\000\100\000\000"
360    "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000"
361    "\000\000\377\377\377\000\377\000\052\000\017\360\000\000\077"
362    "\374\000\000\161\376\000\000\161\376\000\000\361\377\000\000"
363    "\361\377\000\000\360\017\000\000\360\007\000\000\361\307\000"
364    "\000\361\307\000\000\361\307\000\000\360\007\000\000\160\036"
365    "\000\000\177\376\000\000\077\374\000\000\017\360\000\000\360"
366    "\017\000\000\300\003\000\000\200\001\000\000\200\001\000\000"
367    "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
368    "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
369    "\000\000\200\001\000\000\200\001\000\000\300\003\000\000\360"
370    "\017\000\000";
371 const char error_favicon_data[] =
372    "\000\000\001\000\001\000\020\020\002\000\000\000\000\000\260"
373    "\000\000\000\026\000\000\000\050\000\000\000\020\000\000\000"
374    "\040\000\000\000\001\000\001\000\000\000\000\000\100\000\000"
375    "\000\000\000\000\000\000\000\000\000\002\000\000\000\000\000"
376    "\000\000\377\377\377\000\000\000\377\000\017\360\000\000\077"
377    "\374\000\000\161\376\000\000\161\376\000\000\361\377\000\000"
378    "\361\377\000\000\360\017\000\000\360\007\000\000\361\307\000"
379    "\000\361\307\000\000\361\307\000\000\360\007\000\000\160\036"
380    "\000\000\177\376\000\000\077\374\000\000\017\360\000\000\360"
381    "\017\000\000\300\003\000\000\200\001\000\000\200\001\000\000"
382    "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
383    "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
384    "\000\000\200\001\000\000\200\001\000\000\300\003\000\000\360"
385    "\017\000\000";
386 const size_t default_favicon_length  = sizeof(default_favicon_data) - 1;
387 const size_t error_favicon_length  = sizeof(error_favicon_data) - 1;
388
389 /*********************************************************************
390  *
391  * Function    :  cgi_default
392  *
393  * Description :  CGI function that is called for the CGI_SITE_1_HOST
394  *                and CGI_SITE_2_HOST/CGI_SITE_2_PATH base URLs.
395  *                Boring - only exports the default exports.
396  *               
397  * Parameters  :
398  *          1  :  csp = Current client state (buffers, headers, etc...)
399  *          2  :  rsp = http_response data structure for output
400  *          3  :  parameters = map of cgi parameters
401  *
402  * CGI Parameters : none
403  *
404  * Returns     :  JB_ERR_OK on success
405  *                JB_ERR_MEMORY on out-of-memory
406  *
407  *********************************************************************/
408 jb_err cgi_default(struct client_state *csp,
409                    struct http_response *rsp,
410                    const struct map *parameters)
411 {
412    struct map *exports;
413
414    assert(csp);
415    assert(rsp);
416
417    if (NULL == (exports = default_exports(csp, "")))
418    {
419       return JB_ERR_MEMORY;
420    }
421
422    return template_fill_for_cgi(csp, "default", exports, rsp);
423 }
424
425
426 /*********************************************************************
427  *
428  * Function    :  cgi_error_404
429  *
430  * Description :  CGI function that is called if an unknown action was
431  *                given.
432  *               
433  * Parameters  :
434  *          1  :  csp = Current client state (buffers, headers, etc...)
435  *          2  :  rsp = http_response data structure for output
436  *          3  :  parameters = map of cgi parameters
437  *
438  * CGI Parameters : none
439  *
440  * Returns     :  JB_ERR_OK on success
441  *                JB_ERR_MEMORY on out-of-memory error.  
442  *
443  *********************************************************************/
444 jb_err cgi_error_404(struct client_state *csp,
445                      struct http_response *rsp,
446                      const struct map *parameters)
447 {
448    struct map *exports;
449
450    assert(csp);
451    assert(rsp);
452    assert(parameters);
453
454    if (NULL == (exports = default_exports(csp, NULL)))
455    {
456       return JB_ERR_MEMORY;
457    }
458
459    rsp->status = strdup("404 Privoxy configuration page not found");
460    if (rsp->status == NULL)
461    {
462       free_map(exports);
463       return JB_ERR_MEMORY;
464    }
465
466    return template_fill_for_cgi(csp, "cgi-error-404", exports, rsp);
467 }
468
469
470 #ifdef FEATURE_GRACEFUL_TERMINATION
471 /*********************************************************************
472  *
473  * Function    :  cgi_die
474  *
475  * Description :  CGI function to shut down Privoxy.
476  *                NOTE: Turning this on in a production build
477  *                would be a BAD idea.  An EXTREMELY BAD idea.
478  *                In short, don't do it.
479  *               
480  * Parameters  :
481  *          1  :  csp = Current client state (buffers, headers, etc...)
482  *          2  :  rsp = http_response data structure for output
483  *          3  :  parameters = map of cgi parameters
484  *
485  * CGI Parameters : none
486  *
487  * Returns     :  JB_ERR_OK on success
488  *                JB_ERR_MEMORY on out-of-memory error.  
489  *
490  *********************************************************************/
491 jb_err cgi_die (struct client_state *csp,
492                 struct http_response *rsp,
493                 const struct map *parameters)
494 {
495    assert(csp);
496    assert(rsp);
497    assert(parameters);
498
499    /* quit */
500    g_terminate = 1;
501
502    /*
503     * I don't really care what gets sent back to the browser.
504     * Take the easy option - "out of memory" page.
505     */
506
507    return JB_ERR_MEMORY;
508 }
509 #endif /* def FEATURE_GRACEFUL_TERMINATION */
510
511
512 /*********************************************************************
513  *
514  * Function    :  cgi_show_request
515  *
516  * Description :  Show the client's request and what sed() would have
517  *                made of it.
518  *               
519  * Parameters  :
520  *          1  :  csp = Current client state (buffers, headers, etc...)
521  *          2  :  rsp = http_response data structure for output
522  *          3  :  parameters = map of cgi parameters
523  *
524  * CGI Parameters : none
525  *
526  * Returns     :  JB_ERR_OK on success
527  *                JB_ERR_MEMORY on out-of-memory error.  
528  *
529  *********************************************************************/
530 jb_err cgi_show_request(struct client_state *csp,
531                         struct http_response *rsp,
532                         const struct map *parameters)
533 {
534    char *p;
535    struct map *exports;
536
537    assert(csp);
538    assert(rsp);
539    assert(parameters);
540
541    if (NULL == (exports = default_exports(csp, "show-request")))
542    {
543       return JB_ERR_MEMORY;
544    }
545    
546    /*
547     * Repair the damage done to the IOB by get_header()
548     */
549    for (p = csp->iob->buf; p < csp->iob->eod; p++)
550    {
551       if (*p == '\0') *p = '\n';
552    }
553
554    /*
555     * Export the original client's request and the one we would
556     * be sending to the server if this wasn't a CGI call
557     */
558
559    if (map(exports, "client-request", 1, html_encode(csp->iob->buf), 0))
560    {
561       free_map(exports);
562       return JB_ERR_MEMORY;
563    }
564
565    if (map(exports, "processed-request", 1, html_encode(list_to_text(csp->headers)), 0))
566    {
567       free_map(exports);
568       return JB_ERR_MEMORY;
569    }
570
571    return template_fill_for_cgi(csp, "show-request", exports, rsp);
572 }
573
574
575 /*********************************************************************
576  *
577  * Function    :  cgi_send_banner
578  *
579  * Description :  CGI function that returns a banner. 
580  *
581  * Parameters  :
582  *          1  :  csp = Current client state (buffers, headers, etc...)
583  *          2  :  rsp = http_response data structure for output
584  *          3  :  parameters = map of cgi parameters
585  *
586  * CGI Parameters :
587  *           type : Selects the type of banner between "trans", "logo",
588  *                  and "auto". Defaults to "logo" if absent or invalid.
589  *                  "auto" means to select as if we were image-blocking.
590  *                  (Only the first character really counts; b and t are
591  *                  equivalent).
592  *
593  * Returns     :  JB_ERR_OK on success
594  *                JB_ERR_MEMORY on out-of-memory error.  
595  *
596  *********************************************************************/
597 jb_err cgi_send_banner(struct client_state *csp,
598                        struct http_response *rsp,
599                        const struct map *parameters)
600 {
601    char imagetype = lookup(parameters, "type")[0];
602
603    /*
604     * If type is auto, then determine the right thing
605     * to do from the set-image-blocker action
606     */
607    if (imagetype == 'a') 
608    {
609       /*
610        * Default to pattern
611        */
612       imagetype = 'p';
613
614 #ifdef FEATURE_IMAGE_BLOCKING
615       if ((csp->action->flags & ACTION_IMAGE_BLOCKER) != 0)
616       {
617          static const char prefix1[] = CGI_PREFIX "send-banner?type=";
618          static const char prefix2[] = "http://" CGI_SITE_1_HOST "/send-banner?type=";
619          const char *p = csp->action->string[ACTION_STRING_IMAGE_BLOCKER];
620
621          if (p == NULL)
622          {
623             /* Use default - nothing to do here. */
624          }
625          else if (0 == strcmpic(p, "blank"))
626          {
627             imagetype = 'b';
628          }
629          else if (0 == strcmpic(p, "pattern"))
630          {
631             imagetype = 'p';
632          }
633
634          /*
635           * If the action is to call this CGI, determine
636           * the argument:
637           */
638          else if (0 == strncmpic(p, prefix1, sizeof(prefix1) - 1))
639          {
640             imagetype = p[sizeof(prefix1) - 1];
641          }
642          else if (0 == strncmpic(p, prefix2, sizeof(prefix2) - 1))
643          {
644             imagetype = p[sizeof(prefix2) - 1];
645          }
646
647          /*
648           * Everything else must (should) be a URL to
649           * redirect to.
650           */
651          else
652          {
653             imagetype = 'r';
654          }
655       }
656 #endif /* def FEATURE_IMAGE_BLOCKING */
657    }
658       
659    /*
660     * Now imagetype is either the non-auto type we were called with,
661     * or it was auto and has since been determined. In any case, we
662     * can proceed to actually answering the request by sending a redirect
663     * or an image as appropriate:
664     */
665    if (imagetype == 'r') 
666    {
667       rsp->status = strdup("302 Local Redirect from Privoxy");
668       if (rsp->status == NULL)
669       {
670          return JB_ERR_MEMORY;
671       }
672       if (enlist_unique_header(rsp->headers, "Location",
673                                csp->action->string[ACTION_STRING_IMAGE_BLOCKER]))
674       {
675          return JB_ERR_MEMORY;
676       }
677    }
678    else
679    {
680       if ((imagetype == 'b') || (imagetype == 't')) 
681       {
682          rsp->body = bindup(image_blank_data, image_blank_length);
683          rsp->content_length = image_blank_length;
684       }
685       else
686       {
687          rsp->body = bindup(image_pattern_data, image_pattern_length);
688          rsp->content_length = image_pattern_length;
689       }
690
691       if (rsp->body == NULL)
692       {
693          return JB_ERR_MEMORY;
694       }
695       if (enlist(rsp->headers, "Content-Type: " BUILTIN_IMAGE_MIMETYPE))
696       {
697          return JB_ERR_MEMORY;
698       }
699
700       rsp->is_static = 1;
701    }
702
703    return JB_ERR_OK;
704
705 }
706
707
708 /*********************************************************************
709  *
710  * Function    :  cgi_transparent_image
711  *
712  * Description :  CGI function that sends a 1x1 transparent image.
713  *
714  * Parameters  :
715  *          1  :  csp = Current client state (buffers, headers, etc...)
716  *          2  :  rsp = http_response data structure for output
717  *          3  :  parameters = map of cgi parameters
718  *
719  * CGI Parameters : None
720  *
721  * Returns     :  JB_ERR_OK on success
722  *                JB_ERR_MEMORY on out-of-memory error.  
723  *
724  *********************************************************************/
725 jb_err cgi_transparent_image(struct client_state *csp,
726                              struct http_response *rsp,
727                              const struct map *parameters)
728 {
729    rsp->body = bindup(image_blank_data, image_blank_length);
730    rsp->content_length = image_blank_length;
731
732    if (rsp->body == NULL)
733    {
734       return JB_ERR_MEMORY;
735    }
736
737    if (enlist(rsp->headers, "Content-Type: " BUILTIN_IMAGE_MIMETYPE))
738    {
739       return JB_ERR_MEMORY;
740    }
741
742    rsp->is_static = 1;
743
744    return JB_ERR_OK;
745
746 }
747
748
749 /*********************************************************************
750  *
751  * Function    :  cgi_send_default_favicon
752  *
753  * Description :  CGI function that sends the standard favicon.
754  *
755  * Parameters  :
756  *          1  :  csp = Current client state (buffers, headers, etc...)
757  *          2  :  rsp = http_response data structure for output
758  *          3  :  parameters = map of cgi parameters
759  *
760  * CGI Parameters : None
761  *
762  * Returns     :  JB_ERR_OK on success
763  *                JB_ERR_MEMORY on out-of-memory error.  
764  *
765  *********************************************************************/
766 jb_err cgi_send_default_favicon(struct client_state *csp,
767                                 struct http_response *rsp,
768                                 const struct map *parameters)
769 {
770    rsp->body = bindup(default_favicon_data, default_favicon_length);
771    rsp->content_length = default_favicon_length;
772
773    if (rsp->body == NULL)
774    {
775       return JB_ERR_MEMORY;
776    }
777
778    if (enlist(rsp->headers, "Content-Type: image/x-icon"))
779    {
780       return JB_ERR_MEMORY;
781    }
782
783    rsp->is_static = 1;
784
785    return JB_ERR_OK;
786
787 }
788
789
790 /*********************************************************************
791  *
792  * Function    :  cgi_send_error_favicon
793  *
794  * Description :  CGI function that sends the favicon for error pages.
795  *
796  * Parameters  :
797  *          1  :  csp = Current client state (buffers, headers, etc...)
798  *          2  :  rsp = http_response data structure for output
799  *          3  :  parameters = map of cgi parameters
800  *
801  * CGI Parameters : None
802  *
803  * Returns     :  JB_ERR_OK on success
804  *                JB_ERR_MEMORY on out-of-memory error.  
805  *
806  *********************************************************************/
807 jb_err cgi_send_error_favicon(struct client_state *csp,
808                               struct http_response *rsp,
809                               const struct map *parameters)
810 {
811    rsp->body = bindup(error_favicon_data, error_favicon_length);
812    rsp->content_length = error_favicon_length;
813
814    if (rsp->body == NULL)
815    {
816       return JB_ERR_MEMORY;
817    }
818
819    if (enlist(rsp->headers, "Content-Type: image/x-icon"))
820    {
821       return JB_ERR_MEMORY;
822    }
823
824    rsp->is_static = 1;
825
826    return JB_ERR_OK;
827
828 }
829
830
831 /*********************************************************************
832  *
833  * Function    :  cgi_send_stylesheet
834  *
835  * Description :  CGI function that sends a css stylesheet found
836  *                in the cgi-style.css template
837  *
838  * Parameters  :
839  *          1  :  csp = Current client state (buffers, headers, etc...)
840  *          2  :  rsp = http_response data structure for output
841  *          3  :  parameters = map of cgi parameters
842  *
843  * CGI Parameters : None
844  *
845  * Returns     :  JB_ERR_OK on success
846  *                JB_ERR_MEMORY on out-of-memory error.  
847  *
848  *********************************************************************/
849 jb_err cgi_send_stylesheet(struct client_state *csp,
850                            struct http_response *rsp,
851                            const struct map *parameters)
852 {
853    jb_err err;
854    
855    assert(csp);
856    assert(rsp);
857
858    err = template_load(csp, &rsp->body, "cgi-style.css", 0);
859
860    if (err == JB_ERR_FILE)
861    {
862       /*
863        * No way to tell user; send empty stylesheet
864        */
865       log_error(LOG_LEVEL_ERROR, "Could not find cgi-style.css template");
866    }
867    else if (err)
868    {
869       return err; /* JB_ERR_MEMORY */
870    }
871
872    if (enlist(rsp->headers, "Content-Type: text/css"))
873    {
874       return JB_ERR_MEMORY;
875    }
876
877    return JB_ERR_OK;
878
879 }
880 /*********************************************************************
881  *
882  * Function    :  cgi_send_user_manual
883  *
884  * Description :  CGI function that sends a file in the user
885  *                manual directory.
886  *
887  * Parameters  :
888  *          1  :  csp = Current client state (buffers, headers, etc...)
889  *          2  :  rsp = http_response data structure for output
890  *          3  :  parameters = map of cgi parameters
891  *
892  * CGI Parameters : file=name.html, the name of the HTML file
893  *                  (relative to user-manual from config)
894  *
895  * Returns     :  JB_ERR_OK on success
896  *                JB_ERR_MEMORY on out-of-memory error.  
897  *
898  *********************************************************************/
899 jb_err cgi_send_user_manual(struct client_state *csp,
900                             struct http_response *rsp,
901                             const struct map *parameters)
902 {
903    const char * filename;
904    char *full_path;
905    FILE *fp;
906    jb_err err = JB_ERR_OK;
907    size_t length;
908
909    assert(csp);
910    assert(rsp);
911    assert(parameters);
912
913    if (!parameters->first)
914    {
915       /* requested http://p.p/user-manual (without trailing slash) */
916       return cgi_redirect(rsp, CGI_PREFIX "user-manual/");
917    }
918
919    get_string_param(parameters, "file", &filename);
920    /* Check paramter for hack attempts */
921    if (filename && strchr(filename, '/'))
922    {
923       return JB_ERR_CGI_PARAMS;
924    }
925    if (filename && strstr(filename, ".."))
926    {
927       return JB_ERR_CGI_PARAMS;
928    }
929
930    full_path = make_path(csp->config->usermanual, filename ? filename : "index.html");
931    if (full_path == NULL)
932    {
933       return JB_ERR_MEMORY;
934    }
935
936    /* Open user-manual file */
937    if (NULL == (fp = fopen(full_path, "rb")))
938    {
939       log_error(LOG_LEVEL_ERROR, "Cannot open user-manual file %s: %E", full_path);
940       err = cgi_error_no_template(csp, rsp, full_path);
941       free(full_path);
942       return err;
943    }
944
945    /* Get file length */
946    fseek(fp, 0, SEEK_END);
947    length = (size_t)ftell(fp);
948    fseek(fp, 0, SEEK_SET);
949
950    /* Allocate memory and load the file directly into the body */
951    rsp->body = (char *)zalloc(length+1);
952    if (!rsp->body)
953    {
954       fclose(fp);
955       free(full_path);
956       return JB_ERR_MEMORY;
957    }
958    if (!fread(rsp->body, length, 1, fp))
959    {
960       /*
961        * May happen if the file size changes between fseek() and fread().
962        * If it does, we just log it and serve what we got.
963        */
964       log_error(LOG_LEVEL_ERROR, "Couldn't completely read user-manual file %s.", full_path);
965    }
966    fclose(fp);
967    free(full_path);
968
969    rsp->content_length = length;
970
971    /* Guess correct Content-Type based on the filename's ending */
972    if (filename)
973    {
974       length = strlen(filename);
975    }
976    else
977    {
978       length = 0;
979    } 
980    if((length>=4) && !strcmp(&filename[length-4], ".css"))
981    {
982       err = enlist(rsp->headers, "Content-Type: text/css");
983    }
984    else if((length>=4) && !strcmp(&filename[length-4], ".jpg"))
985    {
986       err = enlist(rsp->headers, "Content-Type: image/jpeg");
987    }
988    else
989    {
990       err = enlist(rsp->headers, "Content-Type: text/html");
991    }
992
993    return err;
994 }
995
996
997 /*********************************************************************
998  *
999  * Function    :  cgi_show_version
1000  *
1001  * Description :  CGI function that returns a a web page describing the
1002  *                file versions of Privoxy.
1003  *
1004  * Parameters  :
1005  *          1  :  csp = Current client state (buffers, headers, etc...)
1006  *          2  :  rsp = http_response data structure for output
1007  *          3  :  parameters = map of cgi parameters
1008  *
1009  * CGI Parameters : none
1010  *
1011  * Returns     :  JB_ERR_OK on success
1012  *                JB_ERR_MEMORY on out-of-memory error.  
1013  *
1014  *********************************************************************/
1015 jb_err cgi_show_version(struct client_state *csp,
1016                         struct http_response *rsp,
1017                         const struct map *parameters)
1018 {
1019    struct map *exports;
1020
1021    assert(csp);
1022    assert(rsp);
1023    assert(parameters);
1024
1025    if (NULL == (exports = default_exports(csp, "show-version")))
1026    {
1027       return JB_ERR_MEMORY;
1028    }
1029
1030    if (map(exports, "sourceversions", 1, show_rcs(), 0))
1031    {
1032       free_map(exports);
1033       return JB_ERR_MEMORY;
1034    }
1035
1036    return template_fill_for_cgi(csp, "show-version", exports, rsp);
1037 }
1038
1039  
1040 /*********************************************************************
1041  *
1042  * Function    :  cgi_show_status
1043  *
1044  * Description :  CGI function that returns a web page describing the
1045  *                current status of Privoxy.
1046  *
1047  * Parameters  :
1048  *          1  :  csp = Current client state (buffers, headers, etc...)
1049  *          2  :  rsp = http_response data structure for output
1050  *          3  :  parameters = map of cgi parameters
1051  *
1052  * CGI Parameters :
1053  *        file :  Which file to show.  Only first letter is checked,
1054  *                valid values are:
1055  *                - "p"ermissions (actions) file
1056  *                - "r"egex
1057  *                - "t"rust
1058  *                Default is to show menu and other information.
1059  *
1060  * Returns     :  JB_ERR_OK on success
1061  *                JB_ERR_MEMORY on out-of-memory error.  
1062  *
1063  *********************************************************************/
1064 jb_err cgi_show_status(struct client_state *csp,
1065                        struct http_response *rsp,
1066                        const struct map *parameters)
1067 {
1068    char *s = NULL;
1069    unsigned i;
1070    int j;
1071
1072    FILE * fp;
1073    char buf[BUFFER_SIZE];
1074    const char * filename = NULL;
1075    char * file_description = NULL;
1076 #ifdef FEATURE_STATISTICS
1077    float perc_rej;   /* Percentage of http requests rejected */
1078    int local_urls_read;
1079    int local_urls_rejected;
1080 #endif /* ndef FEATURE_STATISTICS */
1081    jb_err err = JB_ERR_OK;
1082
1083    struct map *exports;
1084
1085    assert(csp);
1086    assert(rsp);
1087    assert(parameters);
1088
1089    if (NULL == (exports = default_exports(csp, "show-status")))
1090    {
1091       return JB_ERR_MEMORY;
1092    }
1093
1094    switch (*(lookup(parameters, "file")))
1095    {
1096    case 'a':
1097       if (!get_number_param(csp, parameters, "index", &i) && i < MAX_AF_FILES && csp->actions_list[i])
1098       {
1099          filename = csp->actions_list[i]->filename;
1100          file_description = "Actions File";
1101       }
1102       break;
1103
1104    case 'f':
1105       if (!get_number_param(csp, parameters, "index", &i) && i < MAX_AF_FILES && csp->rlist[i])
1106       {
1107          filename = csp->rlist[i]->filename;
1108          file_description = "Filter File";
1109       }
1110       break;
1111
1112 #ifdef FEATURE_TRUST
1113    case 't':
1114       if (csp->tlist)
1115       {
1116          filename = csp->tlist->filename;
1117          file_description = "Trust File";
1118       }
1119       break;
1120 #endif /* def FEATURE_TRUST */
1121    }
1122
1123    if (NULL != filename)
1124    {
1125       if ( map(exports, "file-description", 1, file_description, 1)
1126         || map(exports, "filepath", 1, html_encode(filename), 0) )
1127       {
1128          free_map(exports);
1129          return JB_ERR_MEMORY;
1130       }
1131
1132       if ((fp = fopen(filename, "r")) == NULL)
1133       {
1134          if (map(exports, "content", 1, "<h1>ERROR OPENING FILE!</h1>", 1))
1135          {
1136             free_map(exports);
1137             return JB_ERR_MEMORY;
1138          }
1139       }
1140       else
1141       {
1142          s = strdup("");
1143          while ((s != NULL) && fgets(buf, sizeof(buf), fp))
1144          {
1145             string_join  (&s, html_encode(buf));
1146          }
1147          fclose(fp);
1148
1149          if (map(exports, "contents", 1, s, 0))
1150          {
1151             free_map(exports);
1152             return JB_ERR_MEMORY;
1153          }
1154       }
1155
1156       return template_fill_for_cgi(csp, "show-status-file", exports, rsp);
1157    }
1158
1159    s = strdup("");
1160    for (j = 0; (s != NULL) && (j < Argc); j++)
1161    {
1162       if (!err) err = string_join  (&s, html_encode(Argv[j]));
1163       if (!err) err = string_append(&s, " ");
1164    }
1165    if (!err) err = map(exports, "invocation", 1, s, 0);
1166
1167    if (!err) err = map(exports, "options", 1, csp->config->proxy_args, 1);
1168    if (!err) err = show_defines(exports);
1169
1170    if (err) 
1171    {
1172       free_map(exports);
1173       return JB_ERR_MEMORY;
1174    }
1175
1176 #ifdef FEATURE_STATISTICS
1177    local_urls_read     = urls_read;
1178    local_urls_rejected = urls_rejected;
1179
1180    /*
1181     * Need to alter the stats not to include the fetch of this
1182     * page.
1183     *
1184     * Can't do following thread safely! doh!
1185     *
1186     * urls_read--;
1187     * urls_rejected--; * This will be incremented subsequently *
1188     */
1189
1190    if (local_urls_read == 0)
1191    {
1192       if (!err) err = map_block_killer(exports, "have-stats");
1193    }
1194    else
1195    {
1196       if (!err) err = map_block_killer(exports, "have-no-stats");
1197
1198       perc_rej = (float)local_urls_rejected * 100.0F /
1199             (float)local_urls_read;
1200
1201       snprintf(buf, sizeof(buf), "%d", local_urls_read);
1202       if (!err) err = map(exports, "requests-received", 1, buf, 1);
1203
1204       snprintf(buf, sizeof(buf), "%d", local_urls_rejected);
1205       if (!err) err = map(exports, "requests-blocked", 1, buf, 1);
1206
1207       snprintf(buf, sizeof(buf), "%6.2f", perc_rej);
1208       if (!err) err = map(exports, "percent-blocked", 1, buf, 1);
1209    }
1210
1211 #else /* ndef FEATURE_STATISTICS */
1212    err = err || map_block_killer(exports, "statistics");
1213 #endif /* ndef FEATURE_STATISTICS */
1214    
1215    /* 
1216     * List all action files in use, together with view and edit links,
1217     * except for standard.action, which should only be viewable. (Not
1218     * enforced in the editor itself)
1219     * FIXME: Shouldn't include hardwired HTML here, use line template instead!
1220     */
1221    s = strdup("");
1222    for (i = 0; i < MAX_AF_FILES; i++)
1223    {
1224       if (csp->actions_list[i] != NULL)
1225       {
1226          if (!err) err = string_append(&s, "<tr><td>");
1227          if (!err) err = string_join(&s, html_encode(csp->actions_list[i]->filename));
1228          snprintf(buf, sizeof(buf),
1229             "</td><td class=\"buttons\"><a href=\"/show-status?file=actions&amp;index=%d\">View</a>", i);
1230          if (!err) err = string_append(&s, buf);
1231
1232 #ifdef FEATURE_CGI_EDIT_ACTIONS
1233          if (NULL == strstr(csp->actions_list[i]->filename, "standard.action") && NULL != csp->config->actions_file_short[i])
1234          {
1235 #ifdef HAVE_ACCESS
1236             if (access(csp->config->actions_file[i], W_OK) == 0)
1237             {
1238 #endif /* def HAVE_ACCESS */
1239                snprintf(buf, sizeof(buf), "&nbsp;&nbsp;<a href=\"/edit-actions-list?f=%d\">Edit</a>", i);
1240                if (!err) err = string_append(&s, buf);
1241 #ifdef HAVE_ACCESS
1242             }
1243             else
1244             {
1245                if (!err) err = string_append(&s, "&nbsp;&nbsp;<strong>No write access.</strong>");
1246             }
1247 #endif /* def HAVE_ACCESS */
1248          }
1249 #endif
1250
1251          if (!err) err = string_append(&s, "</td></tr>\n");
1252       }
1253    }
1254    if (*s != '\0')   
1255    {
1256       if (!err) err = map(exports, "actions-filenames", 1, s, 0);
1257    }
1258    else
1259    {
1260       if (!err) err = map(exports, "actions-filenames", 1, "<tr><td>None specified</td></tr>", 1);
1261    }
1262
1263    /* 
1264     * List all re_filterfiles in use, together with view options.
1265     * FIXME: Shouldn't include hardwired HTML here, use line template instead!
1266     */
1267    s = strdup("");
1268    for (i = 0; i < MAX_AF_FILES; i++)
1269    {
1270       if (csp->rlist[i] != NULL)
1271       {
1272          if (!err) err = string_append(&s, "<tr><td>");
1273          if (!err) err = string_join(&s, html_encode(csp->rlist[i]->filename));
1274          snprintf(buf, 100,
1275             "</td><td class=\"buttons\"><a href=\"/show-status?file=filter&amp;index=%d\">View</a>", i);
1276          if (!err) err = string_append(&s, buf);
1277          if (!err) err = string_append(&s, "</td></tr>\n");
1278       }
1279    }
1280    if (*s != '\0')   
1281    {
1282       if (!err) err = map(exports, "re-filter-filenames", 1, s, 0);
1283    }
1284    else
1285    {
1286       if (!err) err = map(exports, "re-filter-filenames", 1, "<tr><td>None specified</td></tr>", 1);
1287       if (!err) err = map_block_killer(exports, "have-filterfile");
1288    }
1289
1290 #ifdef FEATURE_TRUST
1291    if (csp->tlist)
1292    {
1293       if (!err) err = map(exports, "trust-filename", 1, html_encode(csp->tlist->filename), 0);
1294    }
1295    else
1296    {
1297       if (!err) err = map(exports, "trust-filename", 1, "None specified", 1);
1298       if (!err) err = map_block_killer(exports, "have-trustfile");
1299    }
1300 #else
1301    if (!err) err = map_block_killer(exports, "trust-support");
1302 #endif /* ndef FEATURE_TRUST */
1303
1304    if (err)
1305    {
1306       free_map(exports);
1307       return JB_ERR_MEMORY;
1308    }
1309
1310    return template_fill_for_cgi(csp, "show-status", exports, rsp);
1311 }
1312
1313  
1314 /*********************************************************************
1315  *
1316  * Function    :  cgi_show_url_info
1317  *
1318  * Description :  CGI function that determines and shows which actions
1319  *                Privoxy will perform for a given url, and which
1320  *                matches starting from the defaults have lead to that.
1321  *
1322  * Parameters  :
1323  *          1  :  csp = Current client state (buffers, headers, etc...)
1324  *          2  :  rsp = http_response data structure for output
1325  *          3  :  parameters = map of cgi parameters
1326  *
1327  * CGI Parameters :
1328  *            url : The url whose actions are to be determined.
1329  *                  If url is unset, the url-given conditional will be
1330  *                  set, so that all but the form can be suppressed in
1331  *                  the template.
1332  *
1333  * Returns     :  JB_ERR_OK on success
1334  *                JB_ERR_MEMORY on out-of-memory error.  
1335  *
1336  *********************************************************************/
1337 jb_err cgi_show_url_info(struct client_state *csp,
1338                          struct http_response *rsp,
1339                          const struct map *parameters)
1340 {
1341    char *url_param;
1342    struct map *exports;
1343    char buf[150];
1344
1345    assert(csp);
1346    assert(rsp);
1347    assert(parameters);
1348
1349    if (NULL == (exports = default_exports(csp, "show-url-info")))
1350    {
1351       return JB_ERR_MEMORY;
1352    }
1353
1354    /*
1355     * Get the url= parameter (if present) and remove any leading/trailing spaces.
1356     */
1357    url_param = strdup(lookup(parameters, "url"));
1358    if (url_param == NULL)
1359    {
1360       free_map(exports);
1361       return JB_ERR_MEMORY;
1362    }
1363    chomp(url_param);
1364
1365    /*
1366     * Handle prefixes.  4 possibilities:
1367     * 1) "http://" or "https://" prefix present and followed by URL - OK
1368     * 2) Only the "http://" or "https://" part is present, no URL - change
1369     *    to empty string so it will be detected later as "no URL".
1370     * 3) Parameter specified but doesn't contain "http(s?)://" - add a
1371     *    "http://" prefix.
1372     * 4) Parameter not specified or is empty string - let this fall through
1373     *    for now, next block of code will handle it.
1374     */
1375    if (0 == strncmp(url_param, "http://", 7))
1376    {
1377       if (url_param[7] == '\0')
1378       {
1379          /*
1380           * Empty URL (just prefix).
1381           * Make it totally empty so it's caught by the next if()
1382           */
1383          url_param[0] = '\0';
1384       }
1385    }
1386    else if (0 == strncmp(url_param, "https://", 8))
1387    {
1388       if (url_param[8] == '\0')
1389       {
1390          /*
1391           * Empty URL (just prefix).
1392           * Make it totally empty so it's caught by the next if()
1393           */
1394          url_param[0] = '\0';
1395       }
1396    }
1397    else if (url_param[0] != '\0')
1398    {
1399       /*
1400        * Unknown prefix - assume http://
1401        */
1402       const size_t url_param_prefixed_size = 7 + 1 + strlen(url_param);
1403       char * url_param_prefixed = malloc(url_param_prefixed_size);
1404       if (NULL == url_param_prefixed)
1405       {
1406          free(url_param);
1407          free_map(exports);
1408          return JB_ERR_MEMORY;
1409       }
1410       strlcpy(url_param_prefixed, "http://", url_param_prefixed_size);
1411       strlcat(url_param_prefixed, url_param, url_param_prefixed_size);
1412       free(url_param);
1413       url_param = url_param_prefixed;
1414    }
1415
1416    /*
1417     * Hide "toggle off" warning if Privoxy is toggled on.
1418     */
1419    if (
1420 #ifdef FEATURE_TOGGLE
1421        (global_toggle_state == 1) &&
1422 #endif /* def FEATURE_TOGGLE */
1423        map_block_killer(exports, "privoxy-is-toggled-off")
1424       )
1425    {
1426       free_map(exports);
1427       return JB_ERR_MEMORY;
1428    }
1429
1430    if (url_param[0] == '\0')
1431    {
1432       /* URL paramater not specified, display query form only. */
1433       free(url_param);
1434       if (map_block_killer(exports, "url-given")
1435         || map(exports, "url", 1, "", 1))
1436       {
1437          free_map(exports);
1438          return JB_ERR_MEMORY;
1439       }
1440    }
1441    else
1442    {
1443       /* Given a URL, so query it. */
1444       jb_err err;
1445       char *matches;
1446       char *s;
1447       int hits = 0;
1448       struct file_list *fl;
1449       struct url_actions *b;
1450       struct http_request url_to_query[1];
1451       struct current_action_spec action[1];
1452       int i;
1453       
1454       if (map(exports, "url", 1, html_encode(url_param), 0))
1455       {
1456          free(url_param);
1457          free_map(exports);
1458          return JB_ERR_MEMORY;
1459       }
1460
1461       init_current_action(action);
1462
1463       if (map(exports, "default", 1, current_action_to_html(csp, action), 0))
1464       {
1465          free_current_action(action);
1466          free(url_param);
1467          free_map(exports);
1468          return JB_ERR_MEMORY;
1469       }
1470
1471       err = parse_http_url(url_param, url_to_query, csp);
1472
1473       free(url_param);
1474
1475       if (err == JB_ERR_MEMORY)
1476       {
1477          free_http_request(url_to_query);
1478          free_current_action(action);
1479          free_map(exports);
1480          return JB_ERR_MEMORY;
1481       }
1482       else if (err)
1483       {
1484          /* Invalid URL */
1485
1486          err = map(exports, "matches", 1, "<b>[Invalid URL specified!]</b>" , 1);
1487          if (!err) err = map(exports, "final", 1, lookup(exports, "default"), 1);
1488          if (!err) err = map_block_killer(exports, "valid-url");
1489
1490          free_current_action(action);
1491          free_http_request(url_to_query);
1492
1493          if (err)
1494          {
1495             free_map(exports);
1496             return JB_ERR_MEMORY;
1497          }
1498
1499          return template_fill_for_cgi(csp, "show-url-info", exports, rsp);
1500       }
1501
1502       /*
1503        * We have a warning about SSL paths.  Hide it for unencrypted sites.
1504        */
1505       if (!url_to_query->ssl)
1506       {
1507          if (map_block_killer(exports, "https"))
1508          {
1509             free_current_action(action);
1510             free_map(exports);
1511             free_http_request(url_to_query);
1512             return JB_ERR_MEMORY;
1513          }
1514       }
1515
1516       matches = strdup("<table summary=\"\" class=\"transparent\">");
1517
1518       for (i = 0; i < MAX_AF_FILES; i++)
1519       {
1520          if (NULL == csp->config->actions_file_short[i]
1521              || !strcmp(csp->config->actions_file_short[i], "standard.action")) continue;
1522
1523          b = NULL;
1524          hits = 1;
1525          if ((fl = csp->actions_list[i]) != NULL)
1526          {
1527             if ((b = fl->f) != NULL)
1528             {
1529                /* FIXME: Hardcoded HTML! */
1530                string_append(&matches, "<tr><th>In file: ");
1531                string_join  (&matches, html_encode(csp->config->actions_file_short[i]));
1532                snprintf(buf, sizeof(buf), " <a class=\"cmd\" href=\"/show-status?file=actions&amp;index=%d\">", i);
1533                string_append(&matches, buf);
1534                string_append(&matches, "View</a>");
1535 #ifdef FEATURE_CGI_EDIT_ACTIONS
1536                snprintf(buf, sizeof(buf), " <a class=\"cmd\" href=\"/edit-actions-list?f=%d\">", i);
1537                string_append(&matches, buf);
1538                string_append(&matches, "Edit</a>");
1539 #endif
1540                string_append(&matches, "</th></tr>\n");
1541
1542                hits = 0;
1543                b = b->next;
1544             }
1545          }
1546
1547          for (; (b != NULL) && (matches != NULL); b = b->next)
1548          {
1549             if (url_match(b->url, url_to_query))
1550             {
1551                string_append(&matches, "<tr><td>{");
1552                string_join  (&matches, actions_to_html(csp, b->action));
1553                string_append(&matches, " }<br>\n<code>");
1554                string_join  (&matches, html_encode(b->url->spec));
1555                string_append(&matches, "</code></td></tr>\n");
1556
1557                if (merge_current_action(action, b->action))
1558                {
1559                   freez(matches);
1560                   free_http_request(url_to_query);
1561                   free_current_action(action);
1562                   free_map(exports);
1563                   return JB_ERR_MEMORY;
1564                }
1565                hits++;
1566             }
1567          }
1568
1569          if (!hits)
1570          {
1571             string_append(&matches, "<tr><td>(no matches in this file)</td></tr>\n");
1572          }
1573       }
1574       string_append(&matches, "</table>\n");
1575
1576       /*
1577        * XXX: Kludge to make sure the "Forward settings" section
1578        * shows what forward-override{} would do with the requested URL.
1579        * No one really cares how the CGI request would be forwarded
1580        * if it wasn't intercepted as CGI request in the first place.
1581        *
1582        * From here on the action bitmask will no longer reflect
1583        * the real url (http://config.privoxy.org/show-url-info?url=.*),
1584        * but luckily it's no longer required later on anyway.
1585        */
1586       free_current_action(csp->action);
1587       url_actions(url_to_query, csp);
1588
1589       /*
1590        * Fill in forwarding settings.
1591        *
1592        * The possibilities are:
1593        *  - no forwarding
1594        *  - http forwarding only
1595        *  - socks4(a) forwarding only
1596        *  - socks4(a) and http forwarding.
1597        *
1598        * XXX: Parts of this code could be reused for the
1599        * "forwarding-failed" template which currently doesn't
1600        * display the proxy port and an eventual second forwarder.
1601        */
1602       {
1603          const struct forward_spec * fwd = forward_url(url_to_query, csp);
1604
1605          if ((fwd->gateway_host == NULL) && (fwd->forward_host == NULL))
1606          {
1607             if (!err) err = map_block_killer(exports, "socks-forwarder");
1608             if (!err) err = map_block_killer(exports, "http-forwarder");
1609          }
1610          else
1611          {
1612             char port[10]; /* We save proxy ports as int but need a string here */
1613
1614             if (!err) err = map_block_killer(exports, "no-forwarder");
1615
1616             if (fwd->gateway_host != NULL)
1617             {
1618                if (!err) err = map(exports, "socks-type", 1, (fwd->type == SOCKS_4) ?
1619                                   "socks4" : "socks4a", 1);
1620                if (!err) err = map(exports, "gateway-host", 1, fwd->gateway_host, 1);
1621                snprintf(port, sizeof(port), "%d", fwd->gateway_port);
1622                if (!err) err = map(exports, "gateway-port", 1, port, 1);
1623             }
1624             else
1625             {
1626                if (!err) err = map_block_killer(exports, "socks-forwarder");
1627             }
1628
1629             if (fwd->forward_host != NULL)
1630             {
1631                if (!err) err = map(exports, "forward-host", 1, fwd->forward_host, 1);
1632                snprintf(port, sizeof(port), "%d", fwd->forward_port);
1633                if (!err) err = map(exports, "forward-port", 1, port, 1);
1634             }
1635             else
1636             {
1637                if (!err) err = map_block_killer(exports, "http-forwarder");
1638             }
1639          }
1640       }
1641
1642       free_http_request(url_to_query);
1643
1644       if (err || matches == NULL)
1645       {
1646          free_current_action(action);
1647          free_map(exports);
1648          return JB_ERR_MEMORY;
1649       }
1650
1651       if (map(exports, "matches", 1, matches , 0))
1652       {
1653          free_current_action(action);
1654          free_map(exports);
1655          return JB_ERR_MEMORY;
1656       }
1657
1658       s = current_action_to_html(csp, action);
1659
1660       free_current_action(action);
1661
1662       if (map(exports, "final", 1, s, 0))
1663       {
1664          free_map(exports);
1665          return JB_ERR_MEMORY;
1666       }
1667    }
1668
1669    return template_fill_for_cgi(csp, "show-url-info", exports, rsp);
1670 }
1671
1672
1673 /*********************************************************************
1674  *
1675  * Function    :  cgi_robots_txt
1676  *
1677  * Description :  CGI function to return "/robots.txt".
1678  *
1679  * Parameters  :
1680  *          1  :  csp = Current client state (buffers, headers, etc...)
1681  *          2  :  rsp = http_response data structure for output
1682  *          3  :  parameters = map of cgi parameters
1683  *
1684  * CGI Parameters : None
1685  *
1686  * Returns     :  JB_ERR_OK on success
1687  *                JB_ERR_MEMORY on out-of-memory error.  
1688  *
1689  *********************************************************************/
1690 jb_err cgi_robots_txt(struct client_state *csp,
1691                       struct http_response *rsp,
1692                       const struct map *parameters)
1693 {
1694    char buf[100];
1695    jb_err err;
1696
1697    rsp->body = strdup(
1698       "# This is the Privoxy control interface.\n"
1699       "# It isn't very useful to index it, and you're likely to break stuff.\n"
1700       "# So go away!\n"
1701       "\n"
1702       "User-agent: *\n"
1703       "Disallow: /\n"
1704       "\n");
1705    if (rsp->body == NULL)
1706    {
1707       return JB_ERR_MEMORY;
1708    }
1709
1710    err = enlist_unique(rsp->headers, "Content-Type: text/plain", 13);
1711
1712    rsp->is_static = 1;
1713
1714    get_http_time(7 * 24 * 60 * 60, buf); /* 7 days into future */
1715    if (!err) err = enlist_unique_header(rsp->headers, "Expires", buf);
1716
1717    return (err ? JB_ERR_MEMORY : JB_ERR_OK);
1718 }
1719
1720
1721 /*********************************************************************
1722  *
1723  * Function    :  show_defines
1724  *
1725  * Description :  Add to a map the state od all conditional #defines
1726  *                used when building
1727  *
1728  * Parameters  :
1729  *          1  :  exports = map to extend
1730  *
1731  * Returns     :  JB_ERR_OK on success
1732  *                JB_ERR_MEMORY on out-of-memory error.  
1733  *
1734  *********************************************************************/
1735 static jb_err show_defines(struct map *exports)
1736 {
1737    jb_err err = JB_ERR_OK;
1738
1739 #ifdef FEATURE_ACL
1740    if (!err) err = map_conditional(exports, "FEATURE_ACL", 1);
1741 #else /* ifndef FEATURE_ACL */
1742    if (!err) err = map_conditional(exports, "FEATURE_ACL", 0);
1743 #endif /* ndef FEATURE_ACL */
1744
1745 #ifdef FEATURE_CGI_EDIT_ACTIONS
1746    if (!err) err = map_conditional(exports, "FEATURE_CGI_EDIT_ACTIONS", 1);
1747 #else /* ifndef FEATURE_COOKIE_JAR */
1748    if (!err) err = map_conditional(exports, "FEATURE_CGI_EDIT_ACTIONS", 0);
1749 #endif /* ndef FEATURE_COOKIE_JAR */
1750
1751 #ifdef FEATURE_COOKIE_JAR
1752    if (!err) err = map_conditional(exports, "FEATURE_COOKIE_JAR", 1);
1753 #else /* ifndef FEATURE_COOKIE_JAR */
1754    if (!err) err = map_conditional(exports, "FEATURE_COOKIE_JAR", 0);
1755 #endif /* ndef FEATURE_COOKIE_JAR */
1756
1757 #ifdef FEATURE_FAST_REDIRECTS
1758    if (!err) err = map_conditional(exports, "FEATURE_FAST_REDIRECTS", 1);
1759 #else /* ifndef FEATURE_FAST_REDIRECTS */
1760    if (!err) err = map_conditional(exports, "FEATURE_FAST_REDIRECTS", 0);
1761 #endif /* ndef FEATURE_FAST_REDIRECTS */
1762
1763 #ifdef FEATURE_FORCE_LOAD
1764    if (!err) err = map_conditional(exports, "FEATURE_FORCE_LOAD", 1);
1765    if (!err) err = map(exports, "FORCE_PREFIX", 1, FORCE_PREFIX, 1);
1766 #else /* ifndef FEATURE_FORCE_LOAD */
1767    if (!err) err = map_conditional(exports, "FEATURE_FORCE_LOAD", 0);
1768    if (!err) err = map(exports, "FORCE_PREFIX", 1, "(none - disabled)", 1);
1769 #endif /* ndef FEATURE_FORCE_LOAD */
1770
1771 #ifdef FEATURE_GRACEFUL_TERMINATION
1772    if (!err) err = map_conditional(exports, "FEATURE_GRACEFUL_TERMINATION", 1);
1773 #else /* ifndef FEATURE_GRACEFUL_TERMINATION */
1774    if (!err) err = map_conditional(exports, "FEATURE_GRACEFUL_TERMINATION", 0);
1775 #endif /* ndef FEATURE_GRACEFUL_TERMINATION */
1776
1777 #ifdef FEATURE_IMAGE_BLOCKING
1778    if (!err) err = map_conditional(exports, "FEATURE_IMAGE_BLOCKING", 1);
1779 #else /* ifndef FEATURE_IMAGE_BLOCKING */
1780    if (!err) err = map_conditional(exports, "FEATURE_IMAGE_BLOCKING", 0);
1781 #endif /* ndef FEATURE_IMAGE_BLOCKING */
1782
1783 #ifdef FEATURE_IMAGE_DETECT_MSIE
1784    if (!err) err = map_conditional(exports, "FEATURE_IMAGE_DETECT_MSIE", 1);
1785 #else /* ifndef FEATURE_IMAGE_DETECT_MSIE */
1786    if (!err) err = map_conditional(exports, "FEATURE_IMAGE_DETECT_MSIE", 0);
1787 #endif /* ndef FEATURE_IMAGE_DETECT_MSIE */
1788
1789 #ifdef FEATURE_KILL_POPUPS
1790    if (!err) err = map_conditional(exports, "FEATURE_KILL_POPUPS", 1);
1791 #else /* ifndef FEATURE_KILL_POPUPS */
1792    if (!err) err = map_conditional(exports, "FEATURE_KILL_POPUPS", 0);
1793 #endif /* ndef FEATURE_KILL_POPUPS */
1794
1795 #ifdef FEATURE_NO_GIFS
1796    if (!err) err = map_conditional(exports, "FEATURE_NO_GIFS", 1);
1797 #else /* ifndef FEATURE_NO_GIFS */
1798    if (!err) err = map_conditional(exports, "FEATURE_NO_GIFS", 0);
1799 #endif /* ndef FEATURE_NO_GIFS */
1800
1801 #ifdef FEATURE_PTHREAD
1802    if (!err) err = map_conditional(exports, "FEATURE_PTHREAD", 1);
1803 #else /* ifndef FEATURE_PTHREAD */
1804    if (!err) err = map_conditional(exports, "FEATURE_PTHREAD", 0);
1805 #endif /* ndef FEATURE_PTHREAD */
1806
1807 #ifdef FEATURE_STATISTICS
1808    if (!err) err = map_conditional(exports, "FEATURE_STATISTICS", 1);
1809 #else /* ifndef FEATURE_STATISTICS */
1810    if (!err) err = map_conditional(exports, "FEATURE_STATISTICS", 0);
1811 #endif /* ndef FEATURE_STATISTICS */
1812
1813 #ifdef FEATURE_TOGGLE
1814    if (!err) err = map_conditional(exports, "FEATURE_TOGGLE", 1);
1815 #else /* ifndef FEATURE_TOGGLE */
1816    if (!err) err = map_conditional(exports, "FEATURE_TOGGLE", 0);
1817 #endif /* ndef FEATURE_TOGGLE */
1818
1819 #ifdef FEATURE_TRUST
1820    if (!err) err = map_conditional(exports, "FEATURE_TRUST", 1);
1821 #else /* ifndef FEATURE_TRUST */
1822    if (!err) err = map_conditional(exports, "FEATURE_TRUST", 0);
1823 #endif /* ndef FEATURE_TRUST */
1824
1825 #ifdef FEATURE_ZLIB
1826    if (!err) err = map_conditional(exports, "FEATURE_ZLIB", 1);
1827 #else /* ifndef FEATURE_ZLIB */
1828    if (!err) err = map_conditional(exports, "FEATURE_ZLIB", 0);
1829 #endif /* ndef FEATURE_ZLIB */
1830
1831 #ifdef STATIC_PCRE
1832    if (!err) err = map_conditional(exports, "STATIC_PCRE", 1);
1833 #else /* ifndef STATIC_PCRE */
1834    if (!err) err = map_conditional(exports, "STATIC_PCRE", 0);
1835 #endif /* ndef STATIC_PCRE */
1836
1837 #ifdef STATIC_PCRS
1838    if (!err) err = map_conditional(exports, "STATIC_PCRS", 1);
1839 #else /* ifndef STATIC_PCRS */
1840    if (!err) err = map_conditional(exports, "STATIC_PCRS", 0);
1841 #endif /* ndef STATIC_PCRS */
1842
1843    return err;
1844 }
1845
1846
1847 /*********************************************************************
1848  *
1849  * Function    :  show_rcs
1850  *
1851  * Description :  Create a string with the rcs info for all sourcefiles
1852  *
1853  * Parameters  :  None
1854  *
1855  * Returns     :  A string, or NULL on out-of-memory.
1856  *
1857  *********************************************************************/
1858 static char *show_rcs(void)
1859 {
1860    char *result = strdup("");
1861    char buf[BUFFER_SIZE];
1862
1863    /* Instead of including *all* dot h's in the project (thus creating a
1864     * tremendous amount of dependencies), I will concede to declaring them
1865     * as extern's.  This forces the developer to add to this list, but oh well.
1866     */
1867
1868 #define SHOW_RCS(__x)              \
1869    {                               \
1870       extern const char __x[];     \
1871       snprintf(buf, sizeof(buf), " %s\n", __x);   \
1872       string_append(&result, buf); \
1873    }
1874
1875    /* In alphabetical order */
1876    SHOW_RCS(actions_h_rcs)
1877    SHOW_RCS(actions_rcs)
1878 #ifdef AMIGA
1879    SHOW_RCS(amiga_h_rcs)
1880    SHOW_RCS(amiga_rcs)
1881 #endif /* def AMIGA */
1882    SHOW_RCS(cgi_h_rcs)
1883    SHOW_RCS(cgi_rcs)
1884 #ifdef FEATURE_CGI_EDIT_ACTIONS
1885    SHOW_RCS(cgiedit_h_rcs)
1886    SHOW_RCS(cgiedit_rcs)
1887 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
1888    SHOW_RCS(cgisimple_h_rcs)
1889    SHOW_RCS(cgisimple_rcs)
1890 #ifdef __MINGW32__
1891    SHOW_RCS(cygwin_h_rcs)
1892 #endif
1893    SHOW_RCS(deanimate_h_rcs)
1894    SHOW_RCS(deanimate_rcs)
1895    SHOW_RCS(encode_h_rcs)
1896    SHOW_RCS(encode_rcs)
1897    SHOW_RCS(errlog_h_rcs)
1898    SHOW_RCS(errlog_rcs)
1899    SHOW_RCS(filters_h_rcs)
1900    SHOW_RCS(filters_rcs)
1901    SHOW_RCS(gateway_h_rcs)
1902    SHOW_RCS(gateway_rcs)
1903    SHOW_RCS(jbsockets_h_rcs)
1904    SHOW_RCS(jbsockets_rcs)
1905    SHOW_RCS(jcc_h_rcs)
1906    SHOW_RCS(jcc_rcs)
1907 #ifdef FEATURE_KILL_POPUPS
1908    SHOW_RCS(killpopup_h_rcs)
1909    SHOW_RCS(killpopup_rcs)
1910 #endif /* def FEATURE_KILL_POPUPS */
1911    SHOW_RCS(list_h_rcs)
1912    SHOW_RCS(list_rcs)
1913    SHOW_RCS(loadcfg_h_rcs)
1914    SHOW_RCS(loadcfg_rcs)
1915    SHOW_RCS(loaders_h_rcs)
1916    SHOW_RCS(loaders_rcs)
1917    SHOW_RCS(miscutil_h_rcs)
1918    SHOW_RCS(miscutil_rcs)
1919    SHOW_RCS(parsers_h_rcs)
1920    SHOW_RCS(parsers_rcs)
1921    SHOW_RCS(pcrs_rcs)
1922    SHOW_RCS(pcrs_h_rcs)
1923    SHOW_RCS(project_h_rcs)
1924    SHOW_RCS(ssplit_h_rcs)
1925    SHOW_RCS(ssplit_rcs)
1926    SHOW_RCS(urlmatch_h_rcs)
1927    SHOW_RCS(urlmatch_rcs)
1928 #ifdef _WIN32
1929 #ifndef _WIN_CONSOLE
1930    SHOW_RCS(w32log_h_rcs)
1931    SHOW_RCS(w32log_rcs)
1932    SHOW_RCS(w32res_h_rcs)
1933    SHOW_RCS(w32taskbar_h_rcs)
1934    SHOW_RCS(w32taskbar_rcs)
1935 #endif /* ndef _WIN_CONSOLE */
1936    SHOW_RCS(win32_h_rcs)
1937    SHOW_RCS(win32_rcs)
1938 #endif /* def _WIN32 */
1939
1940 #undef SHOW_RCS
1941
1942    return result;
1943
1944 }
1945
1946
1947 /*
1948   Local Variables:
1949   tab-width: 3
1950   end:
1951 */