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