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