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