Web server name should begin www.
[privoxy.git] / cgi.c
1 const char cgi_rcs[] = "$Id: cgi.c,v 1.56 2002/03/24 17:50:46 jongfoster Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/cgi.c,v $
5  *
6  * Purpose     :  Declares functions to intercept request, generate
7  *                html or gif answers, and to compose HTTP resonses.
8  *                This only contains the framework functions, the
9  *                actual handler functions are declared elsewhere.
10  *                
11  *                Functions declared include:
12  * 
13  *
14  * Copyright   :  Written by and Copyright (C) 2001 the SourceForge
15  *                Privoxy team. http://www.privoxy.org/
16  *
17  *                Based on the Internet Junkbuster originally written
18  *                by and Copyright (C) 1997 Anonymous Coders and 
19  *                Junkbusters Corporation.  http://www.junkbusters.com
20  *
21  *                This program is free software; you can redistribute it 
22  *                and/or modify it under the terms of the GNU General
23  *                Public License as published by the Free Software
24  *                Foundation; either version 2 of the License, or (at
25  *                your option) any later version.
26  *
27  *                This program is distributed in the hope that it will
28  *                be useful, but WITHOUT ANY WARRANTY; without even the
29  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
30  *                PARTICULAR PURPOSE.  See the GNU General Public
31  *                License for more details.
32  *
33  *                The GNU General Public License should be included with
34  *                this file.  If not, you can view it at
35  *                http://www.gnu.org/copyleft/gpl.html
36  *                or write to the Free Software Foundation, Inc., 59
37  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
38  *
39  * Revisions   :
40  *    $Log: cgi.c,v $
41  *    Revision 1.56  2002/03/24 17:50:46  jongfoster
42  *    Fixing compile error if actions file editor disabled
43  *
44  *    Revision 1.55  2002/03/24 16:55:06  oes
45  *    Making GIF checkerboard transparent
46  *
47  *    Revision 1.54  2002/03/24 16:18:15  jongfoster
48  *    Removing old logo
49  *
50  *    Revision 1.53  2002/03/24 16:06:00  oes
51  *    Correct transparency for checkerboard PNG. Thanks, Magnus!
52  *
53  *    Revision 1.52  2002/03/24 15:23:33  jongfoster
54  *    Name changes
55  *
56  *    Revision 1.51  2002/03/24 13:25:43  swa
57  *    name change related issues
58  *
59  *    Revision 1.50  2002/03/16 23:54:06  jongfoster
60  *    Adding graceful termination feature, to help look for memory leaks.
61  *    If you enable this (which, by design, has to be done by hand
62  *    editing config.h) and then go to http://i.j.b/die, then the program
63  *    will exit cleanly after the *next* request.  It should free all the
64  *    memory that was used.
65  *
66  *    Revision 1.49  2002/03/13 00:27:04  jongfoster
67  *    Killing warnings
68  *
69  *    Revision 1.48  2002/03/08 17:47:07  jongfoster
70  *    Adding comments
71  *
72  *    Revision 1.47  2002/03/08 16:41:33  oes
73  *    Added GIF images again
74  *
75  *    Revision 1.46  2002/03/07 03:48:38  oes
76  *     - Changed built-in images from GIF to PNG
77  *       (with regard to Unisys patent issue)
78  *     - Added a 4x4 pattern PNG which is less intrusive
79  *       than the logo but also clearly marks the deleted banners
80  *
81  *    Revision 1.45  2002/03/06 22:54:35  jongfoster
82  *    Automated function-comment nitpicking.
83  *
84  *    Revision 1.44  2002/03/05 22:43:45  david__schmidt
85  *    - Better error reporting on OS/2
86  *    - Fix double-slash comment (oops)
87  *
88  *    Revision 1.43  2002/03/05 21:33:45  david__schmidt
89  *    - Re-enable OS/2 building after new parms were added
90  *    - Fix false out of memory report when resolving CGI templates when no IP
91  *      address is available of failed attempt (a la no such domain)
92  *
93  *    Revision 1.42  2002/01/21 00:33:20  jongfoster
94  *    Replacing strsav() with the safer string_append() or string_join().
95  *    Adding map_block_keep() to save a few bytes in the edit-actions-list HTML.
96  *    Adding missing html_encode() to error message generators.
97  *    Adding edit-actions-section-swap and many "shortcuts" to the list of CGIs.
98  *
99  *    Revision 1.41  2002/01/17 20:56:22  jongfoster
100  *    Replacing hard references to the URL of the config interface
101  *    with #defines from project.h
102  *
103  *    Revision 1.40  2002/01/09 14:26:46  oes
104  *    Added support for thread-safe gmtime_r call.
105  *
106  *    Revision 1.39  2001/11/16 00:48:13  jongfoster
107  *    Fixing a compiler warning
108  *
109  *    Revision 1.38  2001/11/13 00:31:21  jongfoster
110  *    - Adding new CGIs for use by non-JavaScript browsers:
111  *        edit-actions-url-form
112  *        edit-actions-add-url-form
113  *        edit-actions-remove-url-form
114  *    - Fixing make_menu()'s HTML generation - it now quotes the href parameter.
115  *    - Fixing || bug.
116  *
117  *    Revision 1.37  2001/11/01 14:28:47  david__schmidt
118  *    Show enablement/disablement status in almost all templates.
119  *    There is a little trickiness here: apparent recursive resolution of
120  *    @if-enabled-then@ caused the toggle template to show status out-of-phase with
121  *    the actual enablement status.  So a similar construct,
122  *    @if-enabled-display-then@, is used to resolve the status display on non-'toggle'
123  *    templates.
124  *
125  *    Revision 1.36  2001/10/26 17:33:27  oes
126  *    marginal bugfix
127  *
128  *    Revision 1.35  2001/10/23 21:48:19  jongfoster
129  *    Cleaning up error handling in CGI functions - they now send back
130  *    a HTML error page and should never cause a FATAL error.  (Fixes one
131  *    potential source of "denial of service" attacks).
132  *
133  *    CGI actions file editor that works and is actually useful.
134  *
135  *    Ability to toggle JunkBuster remotely using a CGI call.
136  *
137  *    You can turn off both the above features in the main configuration
138  *    file, e.g. if you are running a multi-user proxy.
139  *
140  *    Revision 1.34  2001/10/18 22:22:09  david__schmidt
141  *    Only show "Local support" on templates conditionally:
142  *      - if either 'admin-address' or 'proxy-info-url' are uncommented in config
143  *      - if not, no Local support section appears
144  *
145  *    Revision 1.33  2001/10/14 22:28:41  jongfoster
146  *    Fixing stupid typo.
147  *
148  *    Revision 1.32  2001/10/14 22:20:18  jongfoster
149  *    - Changes to CGI dispatching method to match CGI names exactly,
150  *      rather than doing a prefix match.
151  *    - No longer need to count the length of the CGI handler names by hand.
152  *    - Adding new handler for 404 error when disptching a CGI, if none of
153  *      the handlers match.
154  *    - Adding new handlers for CGI actionsfile editor.
155  *
156  *    Revision 1.31  2001/10/10 10:56:39  oes
157  *    Failiure to load template now fatal. Before, the user got a hard-to-understand assertion failure from cgi.c
158  *
159  *    Revision 1.30  2001/10/02 15:30:57  oes
160  *    Introduced show-request cgi
161  *
162  *    Revision 1.29  2001/09/20 15:47:44  steudten
163  *
164  *    Fix BUG: Modify int size to size_t size in fill_template()
165  *     - removes big trouble on machines where sizeof(int) != sizeof(size_t).
166  *
167  *    Revision 1.28  2001/09/19 18:00:37  oes
168  *     - Deletef time() FIXME (Can't fail under Linux either, if
169  *       the argument is guaranteed to be in out address space,
170  *       which it is.)
171  *     - Fixed comments
172  *     - Pointer notation cosmetics
173  *     - Fixed a minor bug in template_fill(): Failiure of
174  *       pcrs_execute() now secure.
175  *
176  *    Revision 1.27  2001/09/16 17:08:54  jongfoster
177  *    Moving simple CGI functions from cgi.c to new file cgisimple.c
178  *
179  *    Revision 1.26  2001/09/16 15:47:37  jongfoster
180  *    First version of CGI-based edit interface.  This is very much a
181  *    work-in-progress, and you can't actually use it to edit anything
182  *    yet.  You must #define FEATURE_CGI_EDIT_ACTIONS for these changes
183  *    to have any effect.
184  *
185  *    Revision 1.25  2001/09/16 15:02:35  jongfoster
186  *    Adding i.j.b/robots.txt.
187  *    Inlining add_stats() since it's only ever called from one place.
188  *
189  *    Revision 1.24  2001/09/16 11:38:01  jongfoster
190  *    Splitting fill_template() into 2 functions:
191  *    template_load() loads the file
192  *    template_fill() performs the PCRS regexps.
193  *    This is because the CGI edit interface has a "table row"
194  *    template which is used many times in the page - this
195  *    change means it's only loaded from disk once.
196  *
197  *    Revision 1.23  2001/09/16 11:16:05  jongfoster
198  *    Better error handling in dispatch_cgi() and parse_cgi_parameters()
199  *
200  *    Revision 1.22  2001/09/16 11:00:10  jongfoster
201  *    New function alloc_http_response, for symmetry with free_http_response
202  *
203  *    Revision 1.21  2001/09/13 23:53:03  jongfoster
204  *    Support for both static and dynamically generated CGI pages.
205  *    Correctly setting Last-Modified: and Expires: HTTP headers.
206  *
207  *    Revision 1.20  2001/09/13 23:40:36  jongfoster
208  *    (Cosmetic only) Indentation correction
209  *
210  *    Revision 1.19  2001/09/13 23:31:25  jongfoster
211  *    Moving image data to cgi.c rather than cgi.h.
212  *
213  *    Revision 1.18  2001/08/05 16:06:20  jongfoster
214  *    Modifiying "struct map" so that there are now separate header and
215  *    "map_entry" structures.  This means that functions which modify a
216  *    map no longer need to return a pointer to the modified map.
217  *    Also, it no longer reverses the order of the entries (which may be
218  *    important with some advanced template substitutions).
219  *
220  *    Revision 1.17  2001/08/05 15:57:38  oes
221  *    Adapted finish_http_response to new list_to_text
222  *
223  *    Revision 1.16  2001/08/01 21:33:18  jongfoster
224  *    Changes to fill_template() that reduce memory usage without having
225  *    an impact on performance.  I also renamed some variables so as not
226  *    to clash with the C++ keywords "new" and "template".
227  *
228  *    Revision 1.15  2001/08/01 21:19:22  jongfoster
229  *    Moving file version information to a separate CGI page.
230  *
231  *    Revision 1.14  2001/08/01 00:19:03  jongfoster
232  *    New function: map_conditional() for an if-then-else syntax.
233  *    Changing to use new version of show_defines()
234  *
235  *    Revision 1.13  2001/07/30 22:08:36  jongfoster
236  *    Tidying up #defines:
237  *    - All feature #defines are now of the form FEATURE_xxx
238  *    - Permanently turned off WIN_GUI_EDIT
239  *    - Permanently turned on WEBDAV and SPLIT_PROXY_ARGS
240  *
241  *    Revision 1.12  2001/07/29 18:47:05  jongfoster
242  *    Adding missing #include "loadcfg.h"
243  *
244  *    Revision 1.11  2001/07/18 17:24:37  oes
245  *    Changed to conform to new pcrs interface
246  *
247  *    Revision 1.10  2001/07/13 13:53:13  oes
248  *    Removed all #ifdef PCRS and related code
249  *
250  *    Revision 1.9  2001/06/29 21:45:41  oes
251  *    Indentation, CRLF->LF, Tab-> Space
252  *
253  *    Revision 1.8  2001/06/29 13:21:46  oes
254  *    - Cosmetics: renamed and reordered functions, variables,
255  *      texts, improved comments  etc
256  *
257  *    - Removed ij_untrusted_url() The relevant
258  *      info is now part of the "untrusted" page,
259  *      which is generated by filters.c:trust_url()
260  *
261  *    - Generators of content now call finish_http_response()
262  *      themselves, making jcc.c:chat() a little less
263  *      cluttered
264  *
265  *    - Removed obsolete "Pragma: no-cache" from our headers
266  *
267  *    - http_responses now know their head length
268  *
269  *    - fill_template now uses the new interface to pcrs, so that
270  *       - long jobs (like whole files) no longer have to be assembled
271  *         in a fixed size buffer
272  *       - the new T (trivial) option is used, and the replacement may
273  *         contain Perl syntax backrefs without confusing pcrs
274  *
275  *    - Introduced default_exports() which generates a set of exports
276  *      common to all CGIs and other content generators
277  *
278  *    - Introduced convenience function map_block_killer()
279  *
280  *    - Introduced convenience function make_menu()
281  *
282  *    - Introduced CGI-like function error_response() which generates
283  *      the "No such domain" and "Connect failed" messages using the
284  *      CGI platform
285  *
286  *    - cgi_show_url_info:
287  *      - adapted to new CGI features
288  *      - form and answers now generated from same template
289  *      - http:// prefix in URL now OK
290  *
291  *    - cgi_show_status:
292  *      - adapted to new CGI features
293  *      - no longer uses csp->init_proxy_args
294  *
295  *    - cgi_default:
296  *      - moved menu generation to make_menu()
297  *
298  *    - add_stats now writes single export map entries instead
299  *      of a fixed string
300  *
301  *    - Moved redirect_url() to filters.c
302  *
303  *    - Fixed mem leak in free_http_response(), map_block_killer(),
304  *
305  *    - Removed logentry from cancelled commit
306  *
307  *    Revision 1.7  2001/06/09 10:51:58  jongfoster
308  *    Changing "show URL info" handler to new style.
309  *    Changing BUFSIZ ==> BUFFER_SIZE
310  *
311  *    Revision 1.6  2001/06/07 23:05:19  jongfoster
312  *    Removing code related to old forward and ACL files.
313  *
314  *    Revision 1.5  2001/06/05 19:59:16  jongfoster
315  *    Fixing multiline character string (a GCC-only "feature"), and snprintf (it's _snprintf under VC++).
316  *
317  *    Revision 1.4  2001/06/04 10:41:52  swa
318  *    show version string of cgi.h and cgi.c
319  *
320  *    Revision 1.3  2001/06/03 19:12:16  oes
321  *    introduced new cgi handling
322  *
323  *    No revisions before 1.3
324  *
325  **********************************************************************/
326 \f
327
328 #include "config.h"
329
330 #include <stdio.h>
331 #include <sys/types.h>
332 #include <stdlib.h>
333 #include <ctype.h>
334 #include <string.h>
335 #include <assert.h>
336
337 #ifdef _WIN32
338 #define snprintf _snprintf
339 #endif /* def _WIN32 */
340
341 #include "project.h"
342 #include "cgi.h"
343 #include "list.h"
344 #include "encode.h"
345 #include "ssplit.h"
346 #include "errlog.h"
347 #include "miscutil.h"
348 #include "cgisimple.h"
349 #ifdef FEATURE_CGI_EDIT_ACTIONS
350 #include "cgiedit.h"
351 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
352 #include "loadcfg.h"
353 /* loadcfg.h is for g_bToggleIJB only */
354
355 const char cgi_h_rcs[] = CGI_H_VERSION;
356
357 static const struct cgi_dispatcher cgi_dispatchers[] = {
358    { "",
359          cgi_default,
360          "Privoxy main page" },
361 #ifdef FEATURE_GRACEFUL_TERMINATION
362    { "die", 
363          cgi_die,  
364          "<b>Shut down</b> - <font color=red size='+1'>Do not deploy this build in a production environment, this is a one click Denial Of Service attack!!!</font>" }, 
365 #endif
366    { "show-status", 
367          cgi_show_status,  
368          "Show information about the current configuration" }, 
369    { "show-version", 
370          cgi_show_version,  
371          "Show the source code version numbers" }, 
372    { "show-request", 
373          cgi_show_request,  
374          "Show the client's request headers." }, 
375    { "show-url-info",
376          cgi_show_url_info, 
377          "Show which actions apply to a URL and why"  },
378 #ifdef FEATURE_CGI_EDIT_ACTIONS
379    { "toggle",
380          cgi_toggle, 
381          "Toggle Privoxy on or off" },
382    { "edit-actions",
383          cgi_edit_actions, 
384          "Edit the actions list" },
385
386    
387    { "eaa", /* Shortcut for edit-actions-add-url-form */
388          cgi_edit_actions_add_url_form, 
389          NULL },
390    { "eau", /* Shortcut for edit-actions-url-form */
391          cgi_edit_actions_url_form, 
392          NULL },
393    { "ear", /* Shortcut for edit-actions-remove-url-form */
394          cgi_edit_actions_remove_url_form, 
395          NULL },
396    { "eas", /* Shortcut for edit-actions-for-url */
397          cgi_edit_actions_for_url, 
398          NULL },
399    { "easa", /* Shortcut for edit-actions-section-add */
400          cgi_edit_actions_section_add, 
401          NULL },
402    { "easr", /* Shortcut for edit-actions-section-remove */
403          cgi_edit_actions_section_remove, 
404          NULL },
405    { "eass", /* Shortcut for edit-actions-section-swap */
406          cgi_edit_actions_section_swap, 
407          NULL },
408    { "edit-actions-for-url",
409          cgi_edit_actions_for_url, 
410          NULL /* Edit the actions for (a) specified URL(s) */ },
411    { "edit-actions-list",
412          cgi_edit_actions_list, 
413          NULL /* Edit the actions list */ },
414    { "edit-actions-submit",
415          cgi_edit_actions_submit, 
416          NULL /* Change the actions for (a) specified URL(s) */ },
417    { "edit-actions-url",
418          cgi_edit_actions_url, 
419          NULL /* Change a URL pattern in the actionsfile */ },
420    { "edit-actions-url-form",
421          cgi_edit_actions_url_form, 
422          NULL /* Form to change a URL pattern in the actionsfile */ },
423    { "edit-actions-add-url",
424          cgi_edit_actions_add_url, 
425          NULL /* Add a URL pattern to the actionsfile */ },
426    { "edit-actions-add-url-form",
427          cgi_edit_actions_add_url_form, 
428          NULL /* Form to add a URL pattern to the actionsfile */ },
429    { "edit-actions-remove-url",
430          cgi_edit_actions_remove_url, 
431          NULL /* Remove a URL pattern from the actionsfile */ },
432    { "edit-actions-remove-url-form",
433          cgi_edit_actions_remove_url_form, 
434          NULL /* Form to remove a URL pattern from the actionsfile */ },
435    { "edit-actions-section-add",
436          cgi_edit_actions_section_add, 
437          NULL /* Remove a section from the actionsfile */ },
438    { "edit-actions-section-remove",
439          cgi_edit_actions_section_remove, 
440          NULL /* Remove a section from the actionsfile */ },
441    { "edit-actions-section-swap",
442          cgi_edit_actions_section_swap, 
443          NULL /* Swap two sections in the actionsfile */ },
444 #endif /* def FEATURE_CGI_EDIT_ACTIONS */
445    { "robots.txt", 
446          cgi_robots_txt,  
447          NULL /* Sends a robots.txt file to tell robots to go away. */ }, 
448    { "send-banner",
449          cgi_send_banner, 
450          NULL /* Send a built-in image */ },
451    { "t",
452          cgi_transparent_image, 
453          NULL /* Send a transparent image (short name) */ },
454    { NULL, /* NULL Indicates end of list and default page */
455          cgi_error_404,
456          NULL /* Unknown CGI page */ }
457 };
458
459
460 /*
461  * Bulit-in images for ad replacement
462  *
463  * Hint: You can encode your own images like this:
464  * cat your-image | perl -e 'while (read STDIN, $c, 1) { printf("\\%.3o", unpack("C", $c)); }'
465  */
466
467 #ifdef FEATURE_NO_GIFS
468
469 /*
470  * Checkerboard pattern, as a PNG.
471  */
472 const char image_pattern_data[] =
473    "\211\120\116\107\015\012\032\012\000\000\000\015\111\110\104"
474    "\122\000\000\000\004\000\000\000\004\010\002\000\000\000\046"
475    "\223\011\051\000\000\000\006\142\113\107\104\000\310\000\310"
476    "\000\310\052\045\225\037\000\000\000\032\111\104\101\124\170"
477    "\332\143\070\161\342\304\377\377\377\041\044\003\234\165\342"
478    "\304\011\006\234\062\000\125\200\052\251\125\174\360\223\000"
479    "\000\000\000\111\105\116\104\256\102\140\202";
480
481 /*
482  * 1x1 transparant PNG.
483  */
484 const char image_blank_data[] =
485  "\211\120\116\107\015\012\032\012\000\000\000\015\111\110\104\122"
486  "\000\000\000\004\000\000\000\004\010\006\000\000\000\251\361\236"
487  "\176\000\000\000\007\164\111\115\105\007\322\003\013\020\073\070"
488  "\013\025\036\203\000\000\000\011\160\110\131\163\000\000\013\022"
489  "\000\000\013\022\001\322\335\176\374\000\000\000\004\147\101\115"
490  "\101\000\000\261\217\013\374\141\005\000\000\000\033\111\104\101"
491  "\124\170\332\143\070\161\342\304\207\377\377\377\347\302\150\006"
492  "\144\016\210\146\040\250\002\000\042\305\065\221\270\027\131\110"
493  "\000\000\000\000\111\105\116\104\256\102\140\202";
494 #else
495
496 /*
497  * Checkerboard pattern, as a GIF.
498  */
499 const char image_pattern_data[] =
500    "\107\111\106\070\071\141\004\000\004\000\200\000\000\310\310"
501    "\310\377\377\377\041\376\016\111\040\167\141\163\040\141\040"
502    "\142\141\156\156\145\162\000\041\371\004\001\012\000\001\000"
503    "\054\000\000\000\000\004\000\004\000\000\002\005\104\174\147"
504    "\270\005\000\073";
505
506 /*
507  * 1x1 transparant GIF.
508  */
509 const char image_blank_data[] =
510    "GIF89a\001\000\001\000\200\000\000\377\377\377\000\000"
511    "\000!\371\004\001\000\000\000\000,\000\000\000\000\001"
512    "\000\001\000\000\002\002D\001\000;";
513 #endif
514
515 const size_t image_pattern_length = sizeof(image_pattern_data) - 1;
516 const size_t image_blank_length   = sizeof(image_blank_data) - 1;
517
518
519 static struct http_response cgi_error_memory_response[1];
520
521 static struct http_response *dispatch_known_cgi(struct client_state * csp,
522                                                 const char * path);
523 static struct map *parse_cgi_parameters(char *argstring);
524
525
526 /*********************************************************************
527  * 
528  * Function    :  dispatch_cgi
529  *
530  * Description :  Checks if a request URL has either the magical
531  *                hostname CGI_SITE_1_HOST (usully http://i.j.b/) or
532  *                matches CGI_SITE_2_HOST CGI_SITE_2_PATH (usually
533  *                http://ijbswa.sourceforge.net/config). If so, it passes
534  *                the (rest of the) path onto dispatch_known_cgi, which
535  *                calls the relevant CGI handler function.
536  *
537  * Parameters  :
538  *          1  :  csp = Current client state (buffers, headers, etc...)
539  *
540  * Returns     :  http_response if match, NULL if nonmatch or handler fail
541  *
542  *********************************************************************/
543 struct http_response *dispatch_cgi(struct client_state *csp)
544 {
545    const char *host = csp->http->host;
546    const char *path = csp->http->path;
547
548    /*
549     * Should we intercept ?
550     */
551
552    /* Note: "example.com" and "example.com." are equivalent hostnames. */
553
554    /* Either the host matches CGI_SITE_1_HOST ..*/
555    if (   ( (0 == strcmpic(host, CGI_SITE_1_HOST))
556          || (0 == strcmpic(host, CGI_SITE_1_HOST ".")))
557        && (path[0] == '/') )
558    {
559       /* ..then the path will all be for us.  Remove leading '/' */
560       path++;
561    }
562    /* Or it's the host part CGI_SITE_2_HOST, and the path CGI_SITE_2_PATH */
563    else if ( ( (0 == strcmpic(host, CGI_SITE_2_HOST ))
564             || (0 == strcmpic(host, CGI_SITE_2_HOST ".")) )
565           && (0 == strncmpic(path, CGI_SITE_2_PATH, strlen(CGI_SITE_2_PATH))) )
566    {
567       /* take everything following CGI_SITE_2_PATH */
568       path += strlen(CGI_SITE_2_PATH);
569       if (*path == '/')
570       {
571          /* skip the forward slash after CGI_SITE_2_PATH */
572          path++;
573       }
574       else if (*path != '\0')
575       {
576          /*
577           * wierdness: URL is /configXXX, where XXX is some string
578           * Do *NOT* intercept.
579           */
580          return NULL;
581       }
582    }
583    else
584    {
585       /* Not a CGI */
586       return NULL;
587    }
588
589    /* 
590     * This is a CGI call.
591     */
592
593    return dispatch_known_cgi(csp, path);
594 }
595
596
597 /*********************************************************************
598  * 
599  * Function    :  dispatch_known_cgi
600  *
601  * Description :  Processes a CGI once dispatch_cgi has determined that
602  *                it matches one of the magic prefixes. Parses the path
603  *                as a cgi name plus query string, prepares a map that
604  *                maps CGI parameter names to their values, initializes
605  *                the http_response struct, and calls the relevant CGI
606  *                handler function.
607  *
608  * Parameters  :
609  *          1  :  csp = Current client state (buffers, headers, etc...)
610  *          2  :  path = Path of CGI, with the CGI prefix removed.
611  *                       Should not have a leading "/".
612  *
613  * Returns     :  http_response, or NULL on handler failure or out of
614  *                memory.
615  *
616  *********************************************************************/
617 static struct http_response *dispatch_known_cgi(struct client_state * csp,
618                                                 const char * path)
619 {
620    const struct cgi_dispatcher *d;
621    struct map *param_list;
622    struct http_response *rsp;
623    char *query_args_start;
624    char *path_copy;
625    jb_err err;
626
627    if (NULL == (path_copy = strdup(path)))
628    {
629       return cgi_error_memory();
630    }
631
632    query_args_start = path_copy;
633    while (*query_args_start && *query_args_start != '?')
634    {
635       query_args_start++;
636    }
637    if (*query_args_start == '?')
638    {
639       *query_args_start++ = '\0';
640    }
641
642    if (NULL == (param_list = parse_cgi_parameters(query_args_start)))
643    {
644       free(path_copy);
645       return cgi_error_memory();
646    }
647
648
649    /*
650     * At this point:
651     * path_copy        = CGI call name
652     * param_list       = CGI params, as map
653     */
654
655    /* Get mem for response or fail*/
656    if (NULL == (rsp = alloc_http_response()))
657    {
658       free(path_copy);
659       free_map(param_list);
660       return cgi_error_memory();
661    }
662
663    log_error(LOG_LEVEL_GPC, "%s%s cgi call", csp->http->hostport, csp->http->path);
664    log_error(LOG_LEVEL_CLF, "%s - - [%T] \"%s\" 200 3", 
665                             csp->ip_addr_str, csp->http->cmd); 
666
667    /* Find and start the right CGI function*/
668    d = cgi_dispatchers;
669    for (;;)
670    {
671       if ((d->name == NULL) || (strcmp(path_copy, d->name) == 0))
672       {
673          err = (d->handler)(csp, rsp, param_list);
674          free(path_copy);
675          free_map(param_list);
676          if (err == JB_ERR_CGI_PARAMS)
677          {
678             err = cgi_error_bad_param(csp, rsp);
679          }
680          if (!err)
681          {
682             /* It worked */
683             return finish_http_response(rsp);
684          }
685          else
686          {
687             /* Error in handler, probably out-of-memory */
688             free_http_response(rsp);
689             return cgi_error_memory();
690          }
691       }
692       d++;
693    }
694 }
695
696
697 /*********************************************************************
698  *
699  * Function    :  parse_cgi_parameters
700  *
701  * Description :  Parse a URL-encoded argument string into name/value
702  *                pairs and store them in a struct map list.
703  *
704  * Parameters  :
705  *          1  :  string = string to be parsed.  Will be trashed.
706  *
707  * Returns     :  pointer to param list, or NULL if out of memory.
708  *
709  *********************************************************************/
710 static struct map *parse_cgi_parameters(char *argstring)
711 {
712    char *p;
713    char *vector[BUFFER_SIZE];
714    int pairs, i;
715    struct map *cgi_params;
716
717    if (NULL == (cgi_params = new_map()))
718    {
719       return NULL;
720    }
721
722    pairs = ssplit(argstring, "&", vector, SZ(vector), 1, 1);
723
724    for (i = 0; i < pairs; i++)
725    {
726       if ((NULL != (p = strchr(vector[i], '='))) && (*(p+1) != '\0'))
727       {
728          *p = '\0';
729          if (map(cgi_params, url_decode(vector[i]), 0, url_decode(++p), 0))
730          {
731             free_map(cgi_params);
732             return NULL;
733          }
734       }
735    }
736
737    return cgi_params;
738
739 }
740
741
742 /*********************************************************************
743  *
744  * Function    :  error_response
745  *
746  * Description :  returns an http_response that explains the reason
747  *                why a request failed.
748  *
749  * Parameters  :
750  *          1  :  csp = Current client state (buffers, headers, etc...)
751  *          2  :  templatename = Which template should be used for the answer
752  *          3  :  sys_err = system error number
753  *
754  * Returns     :  A http_response.  If we run out of memory, this
755  *                will be cgi_error_memory().
756  *
757  *********************************************************************/
758 struct http_response *error_response(struct client_state *csp,
759                                      const char *templatename,
760                                      int sys_err)
761 {
762    jb_err err;
763    struct http_response *rsp;
764    struct map * exports = default_exports(csp, NULL);
765    if (exports == NULL)
766    {
767       return cgi_error_memory();
768    }
769
770    if (NULL == (rsp = alloc_http_response()))
771    {
772       free_map(exports);
773       return cgi_error_memory();
774    }
775
776    err = map(exports, "host", 1, html_encode(csp->http->host), 0);
777    if (!err) err = map(exports, "hostport", 1, html_encode(csp->http->hostport), 0);
778    if (!err) err = map(exports, "path", 1, html_encode(csp->http->path), 0);
779    if (!err) err = map(exports, "error", 1, html_encode_and_free_original(safe_strerror(sys_err)), 0);
780    if (!err)
781    {
782      err = map(exports, "host-ip", 1, html_encode(csp->http->host_ip_addr_str), 0);
783      if (err)
784      {
785        /* Some failures, like "404 no such domain", don't have an IP address. */
786        err = map(exports, "host-ip", 1, html_encode(csp->http->host), 0);
787      }
788    }
789
790
791    if (err)
792    {
793       free_map(exports);
794       free_http_response(rsp);
795       return cgi_error_memory();
796    }
797
798    if (!strcmp(templatename, "no-such-domain"))
799    {
800       rsp->status = strdup("404 No such domain");
801       if (rsp->status == NULL)
802       {
803          free_map(exports);
804          free_http_response(rsp);
805          return cgi_error_memory();
806       }
807    }
808    else if (!strcmp(templatename, "connect-failed"))
809    {
810       rsp->status = strdup("503 Connect failed");
811       if (rsp->status == NULL)
812       {
813          free_map(exports);
814          free_http_response(rsp);
815          return cgi_error_memory();
816       }
817    }
818
819    err = template_fill_for_cgi(csp, templatename, exports, rsp);
820    if (err)
821    {
822       free_http_response(rsp);
823       return cgi_error_memory();
824    }
825
826    return finish_http_response(rsp);
827 }
828
829
830 /*********************************************************************
831  *
832  * Function    :  cgi_init_error_messages
833  *
834  * Description :  Call at the start of the program to initialize
835  *                the error message used by cgi_error_memory().
836  *
837  * Parameters  :  N/A
838  *
839  * Returns     :  N/A
840  *
841  *********************************************************************/
842 void cgi_init_error_messages(void)
843 {
844    memset(cgi_error_memory_response, '\0', sizeof(*cgi_error_memory_response));
845    cgi_error_memory_response->head =
846       "HTTP/1.0 500 Internal Privoxy Error\r\n"
847       "Content-Type: text/html\r\n"
848       "\r\n";
849    cgi_error_memory_response->body =
850       "<html>\r\n"
851       "<head><title>500 Internal Privoxy Error</title></head>\r\n"
852       "<body>\r\n"
853       "<h1>500 Internal Privoxy Error</h1>\r\n"
854       "<p>Privoxy <b>ran out of memory</b> while processing your request.</p>\r\n"
855       "<p>Please contact your proxy administrator, or try again later</p>\r\n"
856       "</body>\r\n"
857       "</html>\r\n";
858
859    cgi_error_memory_response->head_length =
860       strlen(cgi_error_memory_response->head);
861    cgi_error_memory_response->content_length =
862       strlen(cgi_error_memory_response->body);
863 }
864
865
866 /*********************************************************************
867  *
868  * Function    :  cgi_error_memory
869  *
870  * Description :  Called if a CGI function runs out of memory.
871  *                Returns a statically-allocated error response.
872  *
873  * Parameters  :
874  *          1  :  csp = Current client state (buffers, headers, etc...)
875  *          2  :  rsp = http_response data structure for output
876  *          3  :  template_name = Name of template that could not
877  *                                be loaded.
878  *
879  * Returns     :  JB_ERR_OK on success
880  *                JB_ERR_MEMORY on out-of-memory error.  
881  *
882  *********************************************************************/
883 struct http_response *cgi_error_memory(void)
884 {
885    /* assert that it's been initialized. */
886    assert(cgi_error_memory_response->head);
887
888    return cgi_error_memory_response;
889 }
890
891
892 /*********************************************************************
893  *
894  * Function    :  cgi_error_no_template
895  *
896  * Description :  Almost-CGI function that is called if a templae
897  *                cannot be loaded.  Note this is not a true CGI,
898  *                it takes a template name rather than a map of 
899  *                parameters.
900  *
901  * Parameters  :
902  *          1  :  csp = Current client state (buffers, headers, etc...)
903  *          2  :  rsp = http_response data structure for output
904  *          3  :  template_name = Name of template that could not
905  *                                be loaded.
906  *
907  * Returns     :  JB_ERR_OK on success
908  *                JB_ERR_MEMORY on out-of-memory error.  
909  *
910  *********************************************************************/
911 jb_err cgi_error_no_template(struct client_state *csp,
912                              struct http_response *rsp,
913                              const char *template_name)
914 {
915    static const char status[] =
916       "500 Internal Privoxy Error";
917    static const char body_prefix[] =
918       "<html>\r\n"
919       "<head><title>500 Internal Privoxy Error</title></head>\r\n"
920       "<body>\r\n"
921       "<h1>500 Internal Privoxy Error</h1>\r\n"
922       "<p>Privoxy encountered an error while processing your request:</p>\r\n"
923       "<p><b>Could not load template file <code>";
924    static const char body_suffix[] =
925       "</code></b></p>\r\n"
926       "<p>Please contact your proxy administrator.</p>\r\n"
927       "<p>If you are the proxy administrator, please put the required file "
928       "in the <code><i>(confdir)</i>/templates</code> directory.  The "
929       "location of the <code><i>(confdir)</i></code> directory "
930       "is specified in the main Privoxy <code>config</code> "
931       "file.  (It's typically the Privoxy install directory"
932 #ifndef _WIN32
933       ", or <code>/etc/privoxy/</code>"
934 #endif /* ndef _WIN32 */
935       ").</p>\r\n"
936       "</body>\r\n"
937       "</html>\r\n";
938
939    assert(csp);
940    assert(rsp);
941    assert(template_name);
942
943    /* Reset rsp, if needed */
944    freez(rsp->status);
945    freez(rsp->head);
946    freez(rsp->body);
947    rsp->content_length = 0;
948    rsp->head_length = 0;
949    rsp->is_static = 0;
950
951    rsp->body = malloc(strlen(body_prefix) + strlen(template_name) + strlen(body_suffix) + 1);
952    if (rsp->body == NULL)
953    {
954       return JB_ERR_MEMORY;
955    }
956    strcpy(rsp->body, body_prefix);
957    strcat(rsp->body, template_name);
958    strcat(rsp->body, body_suffix);
959
960    rsp->status = strdup(status);
961    if (rsp->body == NULL)
962    {
963       return JB_ERR_MEMORY;
964    }
965
966    return JB_ERR_OK;
967 }
968
969
970 /*********************************************************************
971  *
972  * Function    :  cgi_error_bad_param
973  *
974  * Description :  CGI function that is called if the parameters
975  *                (query string) for a CGI were wrong.
976  *               
977  * Parameters  :
978  *          1  :  csp = Current client state (buffers, headers, etc...)
979  *          2  :  rsp = http_response data structure for output
980  *
981  * CGI Parameters : none
982  *
983  * Returns     :  JB_ERR_OK on success
984  *                JB_ERR_MEMORY on out-of-memory error.  
985  *
986  *********************************************************************/
987 jb_err cgi_error_bad_param(struct client_state *csp,
988                            struct http_response *rsp)
989 {
990    struct map *exports;
991
992    assert(csp);
993    assert(rsp);
994
995    if (NULL == (exports = default_exports(csp, NULL)))
996    {
997       return JB_ERR_MEMORY;
998    }
999
1000    return template_fill_for_cgi(csp, "cgi-error-bad-param", exports, rsp);
1001 }
1002
1003
1004 /*********************************************************************
1005  *
1006  * Function    :  get_http_time
1007  *
1008  * Description :  Get the time in a format suitable for use in a
1009  *                HTTP header - e.g.:
1010  *                "Sun, 06 Nov 1994 08:49:37 GMT"
1011  *
1012  * Parameters  :  
1013  *          1  :  time_offset = Time returned will be current time
1014  *                              plus this number of seconds.
1015  *          2  :  buf = Destination for result.  Must be long enough
1016  *                      to hold 29 characters plus a trailing zero.
1017  *
1018  * Returns     :  N/A
1019  *
1020  *********************************************************************/
1021 void get_http_time(int time_offset, char *buf)
1022 {
1023    static const char day_names[7][4] =
1024       { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
1025    static const char month_names[12][4] =
1026       { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1027         "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
1028
1029    struct tm *t;
1030    time_t current_time;
1031
1032    assert(buf);
1033
1034    time(&current_time); /* get current time */
1035
1036    current_time += time_offset;
1037
1038    /* get and save the gmt */
1039    {
1040 #ifdef HAVE_GMTIME_R
1041       struct tm dummy;
1042       t = gmtime_r(&current_time, &dummy);
1043 #else
1044       t = gmtime(&current_time);
1045 #endif
1046    }
1047
1048    /* Format: "Sun, 06 Nov 1994 08:49:37 GMT" */
1049    snprintf(buf, 30,
1050       "%s, %02d %s %4d %02d:%02d:%02d GMT",
1051       day_names[t->tm_wday],
1052       t->tm_mday,
1053       month_names[t->tm_mon],
1054       t->tm_year + 1900,
1055       t->tm_hour,
1056       t->tm_min,
1057       t->tm_sec
1058       );
1059
1060 }
1061
1062
1063 /*********************************************************************
1064  *
1065  * Function    :  finish_http_response
1066  *
1067  * Description :  Fill in the missing headers in an http response,
1068  *                and flatten the headers to an http head.
1069  *
1070  * Parameters  :
1071  *          1  :  rsp = pointer to http_response to be processed
1072  *
1073  * Returns     :  A http_response, usually the rsp parameter.
1074  *                On error, free()s rsp and returns cgi_error_memory()
1075  *
1076  *********************************************************************/
1077 struct http_response *finish_http_response(struct http_response *rsp)
1078 {
1079    char buf[BUFFER_SIZE];
1080    jb_err err;
1081
1082    /* Special case - do NOT change this statically allocated response,
1083     * which is ready for output anyway.
1084     */
1085    if (rsp == cgi_error_memory_response)
1086    {
1087       return rsp;
1088    }
1089
1090    /* 
1091     * Fill in the HTTP Status
1092     */
1093    sprintf(buf, "HTTP/1.0 %s", rsp->status ? rsp->status : "200 OK");
1094    err = enlist_first(rsp->headers, buf);
1095
1096    /* 
1097     * Set the Content-Length
1098     */
1099    if (rsp->content_length == 0)
1100    {
1101       rsp->content_length = rsp->body ? strlen(rsp->body) : 0;
1102    }
1103    if (!err)
1104    {
1105       sprintf(buf, "Content-Length: %d", rsp->content_length);
1106       err = enlist(rsp->headers, buf);
1107    }
1108
1109    /* 
1110     * Fill in the default headers:
1111     *
1112     * Content-Type: default to text/html if not already specified.
1113     * Date: set to current date/time.
1114     * Last-Modified: set to date/time the page was last changed.
1115     * Expires: set to date/time page next needs reloading.
1116     * Cache-Control: set to "no-cache" if applicable.
1117     * 
1118     * See http://www.w3.org/Protocols/rfc2068/rfc2068
1119     */
1120    if (!err) err = enlist_unique(rsp->headers, "Content-Type: text/html", 13);
1121
1122    if (rsp->is_static)
1123    {
1124       /*
1125        * Set Expires to about 10 min into the future so it'll get reloaded
1126        * occasionally, e.g. if Privoxy gets upgraded.
1127        */
1128
1129       if (!err)
1130       {
1131          get_http_time(0, buf);
1132          err = enlist_unique_header(rsp->headers, "Date", buf);
1133       }
1134
1135       /* Some date in the past. */
1136       if (!err) err = enlist_unique_header(rsp->headers, "Last-Modified", "Sat, 17 Jun 2000 12:00:00 GMT");
1137
1138       if (!err)
1139       {
1140          get_http_time(10 * 60, buf); /* 10 * 60sec = 10 minutes */
1141          err = enlist_unique_header(rsp->headers, "Expires", buf);
1142       }
1143    }
1144    else
1145    {
1146       /*
1147        * Compliant browsers should not cache this due to the "Cache-Control"
1148        * setting.  However, to be certain, we also set both "Last-Modified"
1149        * and "Expires" to the current time.
1150        */
1151       if (!err) err = enlist_unique_header(rsp->headers, "Cache-Control", "no-cache");
1152
1153       get_http_time(0, buf);
1154       if (!err) err = enlist_unique_header(rsp->headers, "Date", buf);
1155       if (!err) err = enlist_unique_header(rsp->headers, "Last-Modified", buf);
1156       if (!err) err = enlist_unique_header(rsp->headers, "Expires", buf);
1157    }
1158
1159
1160    /* 
1161     * Write the head
1162     */
1163    if (err || (NULL == (rsp->head = list_to_text(rsp->headers))))
1164    {
1165       free_http_response(rsp);
1166       return cgi_error_memory();
1167    }
1168    rsp->head_length = strlen(rsp->head);
1169
1170    return rsp;
1171
1172 }
1173
1174
1175 /*********************************************************************
1176  *
1177  * Function    :  alloc_http_response
1178  *
1179  * Description :  Allocates a new http_response structure.
1180  *
1181  * Parameters  :  N/A
1182  *
1183  * Returns     :  pointer to a new http_response, or NULL.
1184  *
1185  *********************************************************************/
1186 struct http_response *alloc_http_response(void)
1187 {
1188    return (struct http_response *) zalloc(sizeof(struct http_response));
1189
1190 }
1191
1192
1193 /*********************************************************************
1194  *
1195  * Function    :  free_http_response
1196  *
1197  * Description :  Free the memory occupied by an http_response
1198  *                and its depandant structures.
1199  *
1200  * Parameters  :
1201  *          1  :  rsp = pointer to http_response to be freed
1202  *
1203  * Returns     :  N/A
1204  *
1205  *********************************************************************/
1206 void free_http_response(struct http_response *rsp)
1207 {
1208    /*
1209     * Must special case cgi_error_memory_response, which is never freed.
1210     */
1211    if (rsp && (rsp != cgi_error_memory_response))
1212    {
1213       freez(rsp->status);
1214       freez(rsp->head);
1215       freez(rsp->body);
1216       destroy_list(rsp->headers);
1217       free(rsp);
1218    }
1219
1220 }
1221
1222
1223 /*********************************************************************
1224  *
1225  * Function    :  template_load
1226  *
1227  * Description :  CGI support function that loads a given HTML
1228  *                template from the confdir, ignoring comment
1229  *                lines. 
1230  *
1231  * Parameters  :
1232  *          1  :  csp = Current client state (buffers, headers, etc...)
1233  *          2  :  template_ptr = Destination for pointer to loaded
1234  *                               template text.
1235  *          3  :  template = name of the HTML template to be used
1236  *
1237  * Returns     :  JB_ERR_OK on success
1238  *                JB_ERR_MEMORY on out-of-memory error.  
1239  *                JB_ERR_FILE if the template file cannot be read
1240  *
1241  *********************************************************************/
1242 jb_err template_load(struct client_state *csp, char ** template_ptr, 
1243                      const char *templatename)
1244 {
1245    char *templates_dir_path;
1246    char *full_path;
1247    char *file_buffer;
1248    FILE *fp;
1249    char buf[BUFFER_SIZE];
1250
1251    assert(csp);
1252    assert(template_ptr);
1253    assert(templatename);
1254
1255    *template_ptr = NULL;
1256
1257    /*
1258     * Open template file or fail
1259     */
1260
1261    templates_dir_path = make_path(csp->config->confdir, "templates");
1262    if (templates_dir_path == NULL)
1263    {
1264       return JB_ERR_MEMORY;
1265    }
1266
1267    full_path = make_path(templates_dir_path, templatename);
1268    free(templates_dir_path);
1269    if (full_path == NULL)
1270    {
1271       return JB_ERR_MEMORY;
1272    }
1273
1274    file_buffer = strdup("");
1275    if (file_buffer == NULL)
1276    {
1277       free(full_path);
1278       return JB_ERR_MEMORY;
1279    }
1280
1281    if (NULL == (fp = fopen(full_path, "r")))
1282    {
1283       log_error(LOG_LEVEL_ERROR, "Cannot open template file %s: %E", full_path);
1284       free(full_path);
1285       free(file_buffer);
1286       return JB_ERR_FILE;
1287    }
1288    free(full_path);
1289
1290    /* 
1291     * Read the file, ignoring comments.
1292     *
1293     * FIXME: The comment handling could break with lines >BUFFER_SIZE long.
1294     *        This is unlikely in practise.
1295     */
1296    while (fgets(buf, BUFFER_SIZE, fp))
1297    {
1298       /* skip lines starting with '#' */
1299       if(*buf == '#')
1300       {
1301          continue;
1302       }
1303
1304       if (string_append(&file_buffer, buf))
1305       {
1306          fclose(fp);
1307          return JB_ERR_MEMORY;
1308       }
1309    }
1310    fclose(fp);
1311
1312    *template_ptr = file_buffer;
1313
1314    return JB_ERR_OK;
1315 }
1316
1317
1318 /*********************************************************************
1319  *
1320  * Function    :  template_fill
1321  *
1322  * Description :  CGI support function that fills in a pre-loaded
1323  *                HTML template by replacing @name@ with value using
1324  *                pcrs, for each item in the output map.
1325  *
1326  *                Note that a leading '$' charachter in the export map's
1327  *                values will be stripped and toggle on backreference
1328  *                interpretation.
1329  *
1330  * Parameters  :
1331  *          1  :  template_ptr = IN: Template to be filled out.
1332  *                                   Will be free()d.
1333  *                               OUT: Filled out template.
1334  *                                    Caller must free().
1335  *          2  :  exports = map with fill in symbol -> name pairs
1336  *
1337  * Returns     :  JB_ERR_OK on success
1338  *                JB_ERR_MEMORY on out-of-memory error
1339  *
1340  *********************************************************************/
1341 jb_err template_fill(char **template_ptr, const struct map *exports)
1342 {
1343    struct map_entry *m;
1344    pcrs_job *job;
1345    char buf[BUFFER_SIZE];
1346    char *tmp_out_buffer;
1347    char *file_buffer;
1348    size_t  size;
1349    int error;
1350    const char *flags;
1351
1352    assert(template_ptr);
1353    assert(*template_ptr);
1354    assert(exports);
1355
1356    file_buffer = *template_ptr;
1357    size = strlen(file_buffer) + 1;
1358
1359    /* 
1360     * Assemble pcrs joblist from exports map
1361     */
1362    for (m = exports->first; m != NULL; m = m->next)
1363    {
1364       if (*m->name == '$')
1365       {
1366          /*
1367           * First character of name is '$', so remove this flag
1368           * character and allow backreferences ($1 etc) in the
1369           * "replace with" text.
1370           */
1371          snprintf(buf, BUFFER_SIZE, "%s", m->name + 1);
1372          flags = "sigU";
1373       }
1374       else
1375       {
1376          /*
1377           * Treat the "replace with" text as a literal string - 
1378           * no quoting needed, no backreferences allowed.
1379           * ("Trivial" ['T'] flag).
1380           */
1381          flags = "sigTU";
1382
1383          /* Enclose name in @@ */
1384          snprintf(buf, BUFFER_SIZE, "@%s@", m->name);
1385       }
1386
1387
1388       log_error(LOG_LEVEL_CGI, "Substituting: s/%s/%s/%s", buf, m->value, flags);
1389
1390       /* Make and run job. */
1391       job = pcrs_compile(buf, m->value, flags,  &error);
1392       if (job == NULL) 
1393       {
1394          if (error == PCRS_ERR_NOMEM)
1395          {
1396             free(file_buffer);
1397             *template_ptr = NULL;
1398             return JB_ERR_MEMORY;
1399          }
1400          else
1401          {
1402             log_error(LOG_LEVEL_ERROR, "Error compiling template fill job %s: %d", m->name, error);
1403             /* Hope it wasn't important and silently ignore the invalid job */
1404          }
1405       }
1406       else
1407       {
1408          pcrs_execute(job, file_buffer, size, &tmp_out_buffer, &size);
1409          free(file_buffer);
1410          pcrs_free_job(job);
1411          if (NULL == tmp_out_buffer)
1412          {
1413             *template_ptr = NULL;
1414             return JB_ERR_MEMORY;
1415          }
1416          file_buffer = tmp_out_buffer;
1417       }
1418    }
1419
1420    /*
1421     * Return
1422     */
1423    *template_ptr = file_buffer;
1424    return JB_ERR_OK;
1425 }
1426
1427
1428 /*********************************************************************
1429  *
1430  * Function    :  template_fill_for_cgi
1431  *
1432  * Description :  CGI support function that loads a HTML template
1433  *                and fills it in.  Handles file-not-found errors
1434  *                by sending a HTML error message.  For convenience,
1435  *                this function also frees the passed "exports" map.
1436  *
1437  * Parameters  :
1438  *          1  :  csp = Client state
1439  *          2  :  templatename = name of the HTML template to be used
1440  *          3  :  exports = map with fill in symbol -> name pairs.
1441  *                          Will be freed by this function.
1442  *
1443  * Returns     :  JB_ERR_OK on success
1444  *                JB_ERR_MEMORY on out-of-memory error
1445  *
1446  *********************************************************************/
1447 jb_err template_fill_for_cgi(struct client_state *csp,
1448                              const char *templatename,
1449                              struct map *exports,
1450                              struct http_response *rsp)
1451 {
1452    jb_err err;
1453    
1454    assert(csp);
1455    assert(templatename);
1456    assert(exports);
1457    assert(rsp);
1458
1459    err = template_load(csp, &rsp->body, templatename);
1460    if (err == JB_ERR_FILE)
1461    {
1462       free_map(exports);
1463       return cgi_error_no_template(csp, rsp, templatename);
1464    }
1465    else if (err)
1466    {
1467       free_map(exports);
1468       return err; /* JB_ERR_MEMORY */
1469    }
1470    err = template_fill(&rsp->body, exports);
1471    free_map(exports);
1472    return err;
1473 }
1474
1475
1476 /*********************************************************************
1477  *
1478  * Function    :  default_exports
1479  *
1480  * Description :  returns a struct map list that contains exports
1481  *                which are common to all CGI functions.
1482  *
1483  * Parameters  :
1484  *          1  :  csp = Current client state (buffers, headers, etc...)
1485  *          2  :  caller = name of CGI who calls us and which should
1486  *                         be excluded from the generated menu. May be
1487  *                         NULL.
1488  * Returns     :  NULL if no memory, else a new map.  Caller frees.
1489  *
1490  *********************************************************************/
1491 struct map *default_exports(const struct client_state *csp, const char *caller)
1492 {
1493    char buf[20];
1494    jb_err err;
1495    struct map * exports;
1496    int local_help_exists = 0;
1497
1498    assert(csp);
1499
1500    exports = new_map();
1501    if (exports == NULL)
1502    {
1503       return NULL;
1504    }
1505
1506    err = map(exports, "version", 1, html_encode(VERSION), 0);
1507    if (!err) err = map(exports, "my-ip-address", 1, html_encode(csp->my_ip_addr_str ? csp->my_ip_addr_str : "unknown"), 0);
1508    if (!err) err = map(exports, "my-hostname",   1, html_encode(csp->my_hostname ? csp->my_hostname : "unknown"), 0);
1509    if (!err) err = map(exports, "homepage",      1, html_encode(HOME_PAGE_URL), 0);
1510    if (!err) err = map(exports, "default-cgi",   1, html_encode(CGI_PREFIX), 0);
1511    if (!err) err = map(exports, "menu",          1, make_menu(caller), 0);
1512    if (!err) err = map(exports, "code-status",   1, CODE_STATUS, 1);
1513    if (!err) err = map_conditional(exports, "enabled-display", g_bToggleIJB);
1514
1515    snprintf(buf, 20, "%d", csp->config->hport);
1516    if (!err) err = map(exports, "my-port", 1, buf, 1);
1517
1518    if(!strcmp(CODE_STATUS, "stable"))
1519    {
1520       if (!err) err = map_block_killer(exports, "unstable");
1521    }
1522
1523    if (csp->config->admin_address != NULL)
1524    {
1525       if (!err) err = map(exports, "admin-address", 1, html_encode(csp->config->admin_address), 0);
1526       local_help_exists = 1;
1527    }
1528    else
1529    {
1530       if (!err) err = map_block_killer(exports, "have-adminaddr-info");
1531    }
1532
1533    if (csp->config->proxy_info_url != NULL)
1534    {
1535       if (!err) err = map(exports, "proxy-info-url", 1, html_encode(csp->config->proxy_info_url), 0);
1536       local_help_exists = 1;
1537    }
1538    else
1539    {
1540       if (!err) err = map_block_killer(exports, "have-proxy-info");
1541    }
1542
1543    if (local_help_exists == 0)
1544    {
1545       if (!err) err = map_block_killer(exports, "have-help-info");
1546    }
1547
1548    if (err)
1549    {
1550       free_map(exports);
1551       return NULL;
1552    }
1553
1554    return exports;
1555 }
1556
1557
1558 /*********************************************************************
1559  *
1560  * Function    :  map_block_killer
1561  *
1562  * Description :  Convenience function.
1563  *                Adds a "killer" for the conditional HTML-template
1564  *                block <name>, i.e. a substitution of the regex
1565  *                "if-<name>-start.*if-<name>-end" to the given
1566  *                export list.
1567  *
1568  * Parameters  :  
1569  *          1  :  exports = map to extend
1570  *          2  :  name = name of conditional block
1571  *
1572  * Returns     :  JB_ERR_OK on success
1573  *                JB_ERR_MEMORY on out-of-memory error.  
1574  *
1575  *********************************************************************/
1576 jb_err map_block_killer(struct map *exports, const char *name)
1577 {
1578    char buf[1000]; /* Will do, since the names are hardwired */
1579
1580    assert(exports);
1581    assert(name);
1582    assert(strlen(name) < 490);
1583
1584    snprintf(buf, 1000, "if-%s-start.*if-%s-end", name, name);
1585    return map(exports, buf, 1, "", 1);
1586 }
1587
1588
1589 /*********************************************************************
1590  *
1591  * Function    :  map_block_keep
1592  *
1593  * Description :  Convenience function.  Removes the markers used
1594  *                by map-block-killer, to save a few bytes.
1595  *                i.e. removes "@if-<name>-start@" and "@if-<name>-end@"
1596  *
1597  * Parameters  :  
1598  *          1  :  exports = map to extend
1599  *          2  :  name = name of conditional block
1600  *
1601  * Returns     :  JB_ERR_OK on success
1602  *                JB_ERR_MEMORY on out-of-memory error.  
1603  *
1604  *********************************************************************/
1605 jb_err map_block_keep(struct map *exports, const char *name)
1606 {
1607    jb_err err;
1608    char buf[500]; /* Will do, since the names are hardwired */
1609
1610    assert(exports);
1611    assert(name);
1612    assert(strlen(name) < 490);
1613
1614    snprintf(buf, 500, "if-%s-start", name);
1615    err = map(exports, buf, 1, "", 1);
1616
1617    if (err)
1618    {
1619       return err;
1620    }
1621
1622    snprintf(buf, 500, "if-%s-end", name);
1623    return map(exports, buf, 1, "", 1);
1624 }
1625
1626
1627 /*********************************************************************
1628  *
1629  * Function    :  map_conditional
1630  *
1631  * Description :  Convenience function.
1632  *                Adds an "if-then-else" for the conditional HTML-template
1633  *                block <name>, i.e. a substitution of the form:
1634  *                @if-<name>-then@
1635  *                   True text
1636  *                @else-not-<name>@
1637  *                   False text
1638  *                @endif-<name>@
1639  *
1640  *                The control structure and one of the alternatives
1641  *                will be hidden.
1642  *
1643  * Parameters  :  
1644  *          1  :  exports = map to extend
1645  *          2  :  name = name of conditional block
1646  *          3  :  choose_first = nonzero for first, zero for second.
1647  *
1648  * Returns     :  JB_ERR_OK on success
1649  *                JB_ERR_MEMORY on out-of-memory error.  
1650  *
1651  *********************************************************************/
1652 jb_err map_conditional(struct map *exports, const char *name, int choose_first)
1653 {
1654    char buf[1000]; /* Will do, since the names are hardwired */
1655    jb_err err;
1656
1657    assert(exports);
1658    assert(name);
1659    assert(strlen(name) < 480);
1660
1661    snprintf(buf, 1000, (choose_first
1662       ? "else-not-%s@.*@endif-%s"
1663       : "if-%s-then@.*@else-not-%s"),
1664       name, name);
1665
1666    err = map(exports, buf, 1, "", 1);
1667    if (err)
1668    {
1669       return err;
1670    }
1671
1672    snprintf(buf, 1000, (choose_first ? "if-%s-then" : "endif-%s"), name);
1673    return map(exports, buf, 1, "", 1);
1674 }
1675
1676
1677 /*********************************************************************
1678  *
1679  * Function    :  make_menu
1680  *
1681  * Description :  Returns an HTML-formatted menu of the available 
1682  *                unhidden CGIs, excluding the one given in <self>.
1683  *
1684  * Parameters  :  self = name of CGI to leave out, can be NULL
1685  *
1686  * Returns     :  menu string, or NULL on out-of-memory error.
1687  *
1688  *********************************************************************/
1689 char *make_menu(const char *self)
1690 {
1691    const struct cgi_dispatcher *d;
1692    char *result = strdup("");
1693
1694    if (self == NULL)
1695    {
1696       self = "NO-SUCH-CGI!";
1697    }
1698
1699    /* List available unhidden CGI's and export as "other-cgis" */
1700    for (d = cgi_dispatchers; d->name; d++)
1701    {
1702       if (d->description && strcmp(d->name, self))
1703       {
1704          string_append(&result, "<li><a href=\"" CGI_PREFIX);
1705          string_append(&result, d->name);
1706          string_append(&result, "\">");
1707          string_append(&result, d->description);
1708          string_append(&result, "</a></li>\n");
1709       }
1710    }
1711
1712    return result;
1713 }
1714
1715
1716 /*********************************************************************
1717  *
1718  * Function    :  dump_map
1719  *
1720  * Description :  HTML-dump a map for debugging
1721  *
1722  * Parameters  :
1723  *          1  :  the_map = map to dump
1724  *
1725  * Returns     :  string with HTML
1726  *
1727  *********************************************************************/
1728 char *dump_map(const struct map *the_map)
1729 {
1730    struct map_entry *cur_entry;
1731    char *ret = strdup("");
1732
1733    string_append(&ret, "<table>\n");
1734
1735    for (cur_entry = the_map->first;
1736         (cur_entry != NULL) && (ret != NULL);
1737         cur_entry = cur_entry->next)
1738    {
1739       string_append(&ret, "<tr><td><b>");
1740       string_join  (&ret, html_encode(cur_entry->name));
1741       string_append(&ret, "</b></td><td>");
1742       string_join  (&ret, html_encode(cur_entry->value));
1743       string_append(&ret, "</td></tr>\n");
1744    }
1745
1746    string_append(&ret, "</table>\n");
1747    return ret;
1748 }
1749
1750
1751 /*
1752   Local Variables:
1753   tab-width: 3
1754   end:
1755 */