[0001]
[0002]
[0003]
[0004]
[0005]
[0006]
[0007]
[0008]
[0009]
[0010]
[0011]
[0012]
[0013]
[0014]
[0015]
[0016]
[0017]
[0018]
[0019]
[0020]
[0021]
[0022]
[0023]
[0024]
[0025]
[0026]
[0027]
[0028]
[0029]
[0030]
[0031]
[0032]
[0033]
[0034]
[0035]
[0036]
[0037]
[0038]
[0039]
[0040]
[0041]
[0042]
[0043]
[0044]
[0045]
[0046]
[0047]
[0048]
[0049]
[0050]
[0051]
[0052]
[0053]
[0054]
[0055]
[0056]
[0057]
[0058]
[0059]
[0060]
[0061]
[0062]
[0063]
[0064]
[0065]
[0066]
[0067]
[0068]
[0069]
[0070]
[0071]
[0072]
[0073]
[0074]
[0075]
[0076]
[0077]
[0078]
[0079]
[0080]
[0081]
[0082]
[0083]
[0084]
[0085]
[0086]
[0087]
[0088]
[0089]
[0090]
[0091]
[0092]
[0093]
[0094]
[0095]
[0096]
[0097]
[0098]
[0099]
[0100]
[0101]
[0102]
[0103]
[0104]
[0105]
[0106]
[0107]
[0108]
[0109]
[0110]
[0111]
[0112]
[0113]
[0114]
[0115]
[0116]
[0117]
[0118]
[0119]
[0120]
[0121]
[0122]
[0123]
[0124]
[0125]
[0126]
[0127]
[0128]
[0129]
[0130]
[0131]
[0132]
[0133]
[0134]
[0135]
[0136]
[0137]
[0138]
[0139]
[0140]
[0141]
[0142]
[0143]
[0144]
[0145]
[0146]
[0147]
[0148]
[0149]
[0150]
[0151]
[0152]
[0153]
[0154]
[0155]
[0156]
[0157]
[0158]
[0159]
[0160]
[0161]
[0162]
[0163]
[0164]
[0165]
[0166]
[0167]
[0168]
[0169]
[0170]
[0171]
[0172]
[0173]
[0174]
[0175]
[0176]
[0177]
[0178]
[0179]
[0180]
[0181]
[0182]
[0183]
[0184]
[0185]
[0186]
[0187]
[0188]
[0189]
[0190]
[0191]
[0192]
[0193]
[0194]
[0195]
[0196]
[0197]
[0198]
[0199]
[0200]
[0201]
[0202]
[0203]
[0204]
[0205]
[0206]
[0207]
[0208]
[0209]
[0210]
[0211]
[0212]
[0213]
[0214]
[0215]
[0216]
[0217]
[0218]
[0219]
[0220]
[0221]
[0222]
[0223]
[0224]
[0225]
[0226]
[0227]
[0228]
[0229]
[0230]
[0231]
[0232]
[0233]
[0234]
[0235]
[0236]
[0237]
[0238]
[0239]
[0240]
[0241]
[0242]
[0243]
[0244]
[0245]
[0246]
[0247]
[0248]
[0249]
[0250]
[0251]
[0252]
[0253]
[0254]
[0255]
[0256]
[0257]
[0258]
[0259]
[0260]
[0261]
[0262]
[0263]
[0264]
[0265]
[0266]
[0267]
[0268]
[0269]
[0270]
[0271]
[0272]
[0273]
[0274]
[0275]
[0276]
[0277]
[0278]
[0279]
[0280]
[0281]
[0282]
[0283]
[0284]
[0285]
[0286]
[0287]
[0288]
[0289]
[0290]
[0291]
[0292]
[0293]
[0294]
[0295]
[0296]
[0297]
[0298]
[0299]
[0300]
[0301]
[0302]
[0303]
[0304]
[0305]
[0306]
[0307]
[0308]
[0309]
[0310]
[0311]
[0312]
[0313]
[0314]
[0315]
[0316]
[0317]
[0318]
[0319]
[0320]
[0321]
[0322]
[0323]
[0324]
[0325]
[0326]
[0327]
[0328]
[0329]
[0330]
[0331]
[0332]
[0333]
[0334]
[0335]
[0336]
[0337]
[0338]
[0339]
[0340]
[0341]
[0342]
[0343]
[0344]
[0345]
[0346]
[0347]
[0348]
[0349]
[0350]
[0351]
[0352]
[0353]
[0354]
[0355]
[0356]
[0357]
[0358]
[0359]
[0360]
/*
 * This program is intended to be run by a HTTP server script in order to
 * convert the CGILIB environment to CLI symbols.  An optional argument
 * is a prefix string for the created symbols (default="WWW_").
 *
 * The HTTP request information is obtained by getting the values of P1, P2, 
 * and P3 (method, path, protocol).  The script running this program should 
 * not modify these symbols.
 *
 * Additional execution options are specifing a bitmask as an integer value
 * in parameter P4:
 *   bit 0 - If set, inhibit sending of <DNETCGI>
 *
 * This program puts the link to the HTTP server into CGI mode and flags
 * the environment so that WWWEXEC will automatically send the CGI terminator
 * when the DCL script exits.  Note that in the CGI mode, the writes to
 * net_link must explicitly include the carriage control.  The first line
 * output must be either and content-type: header or a location: header
 * followed by a blank line (newline sequence).
 *
 * Usage:
 *    cgi_symbols prefix [form_prefix]
 *    cgi_symbols table [filename]		! filename must contain period
 *
 * If (and only if) you specify a form prefix as argument 2 on the command 
 * line, the program interprets the request contents as form input,creating a 
 * series of symbols for it. The symbols created will be (xxx is form_prefix):
 *
 *	xxxFIELDS		Comma-separated list of field names parsed
 *				from form input.  For every name in list
 *				a DCL symbol of form xxxFLD_name will be
 *				created.  Note that the form writer must
 *				garantee that the field names will result in
 *				valid DCL symbol names (e.g. no hyphens).
 *				This list is truncated to 255 characters.
 *
 *	xxxFLD_yyyy		Field value of field yyyy parsed from form
 *				input.  Value is truncated to 255 characters.
 *
 * If you specify a filename as argument 2 on the command line, the request
 * content data (possible none) is saved in a file by that name and argument
 * 1 is a logical name table to save the environment variables in rather than
 * creating DCL symbols.
 *
 * Examples:
 *	$ run cgi_symbols
 *
 *	$ mcr sys$disk:[]cgi_symbols http_ cgiform_
 *
 *      $ mcr sys$disk:[]cgi_symbols lnm$process form_content044.tmp
 *
 * Author: David Jones
 * Date:   26-SEP-1994
 * Revised: 25-OCT-1994		Add option to interpret form input into symbols.
 * Revised: 28-OCT-1994		Bug fixes.
 * Revised: 16-MAY-1995		Support multiple occureces of form values.
 *				If value appears more than once, concatenate
 *				values and separate by commas.
 * Revised: 8-SEP-1995		Fix bug in handling of plus signs in input
 *				fields.  To revert to old behaviour compile
 *				with KEEP_PLUSES macro symbol defined.
 * Revised: 14-NOV-1995		Bug fix, terminate namlist in add_symbol().
 * Revised: 21-MAR-1996		Add alternate (logical name) command syntax.
 * Revised: 15-NOV-1997		Add P4 hack.
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <descrip.h>
#include <libclidef.h>

#include "scriptlib.h"
#include "cgilib.h"
int cgi_show_env();
static void set_form_symbols ( char *prefix );

int main ( int argc, char **argv )
{
    int i, status, LIB$GET_SYMBOL(), table, length, virtual_argc, flags;
    char *virtual_argv[4], *base_prefix, *form_prefix;
    char param_name[4], param_value[256];
    $DESCRIPTOR(pname,"");
    $DESCRIPTOR(pvalue,"");
    /*
     * Check for invalid invocation
     */
    if ( argc > 3 ) {
	printf(
	   "Too many arguments, this program must be run from a DCL script\n");
	exit (20);
    }
    /*
     * Build dummy argument list from P1 through P3 to get the values WWWEXEC 
     * passed to the script.
     */
    virtual_argc = 4;
    virtual_argv[0] = argv[0];		/* for lack of anything better! */
    pname.dsc$w_length = 2;
    pname.dsc$a_pointer = param_name;
    pvalue.dsc$w_length = sizeof(param_value)-1;
    pvalue.dsc$a_pointer = param_value;

    for ( i = 1; i < virtual_argc; i++ ) {
	sprintf ( param_name, "P%d", i );
	length = 0;
	status = LIB$GET_SYMBOL ( &pname, &pvalue, &length );
	if ( (status&1) == 1 ) {
	    /*
	     * Allocate new buffer to hold value.
	     */
	    virtual_argv[i] = malloc ( length+1 );
	    param_value[length] = '\0';
	    strcpy ( virtual_argv[i], param_value );
	}
	else virtual_argv[i] = "";
    }
    /*
     * Retrieve flags for execution options from P4.
     */
    flags = 0;
    strcpy ( param_name, "P4" );
    status = LIB$GET_SYMBOL ( &pname, &pvalue, &length );
    if ( (status&1) == 1 ) {
	param_value[length] = '\0';
	if ( length > 0 ) flags = atoi ( param_value );
    }
    /*
     * Load CGI environment and convert to DCL
     */
    if ( (flags&1) ) {
        status = cgi_init_env ( virtual_argc, virtual_argv );
    } else {
        status = cgi_init ( virtual_argc, virtual_argv );
    }

    base_prefix = argc > 1 ? argv[1] : "";
    if ( !*base_prefix ) base_prefix = "WWW_";
    form_prefix = argc > 2 ? argv[2] : "";
    if ( strchr ( form_prefix, '.') ) {
	/*
	 * A period in form_prefix means it is an output filename.
	 * base_prefix becomes the table name.
	 */
	cgi_set_cli_env ( "", base_prefix );
	if ( *form_prefix ) {
	    /* Second argument is filename to receive post data */
	    FILE *pdata;
	    char *var, buffer[4096];
	    int seg, length, content_length;

    	    var = cgi_info ( "CONTENT_LENGTH" );
    	    content_length = var ? atoi(var) : 0;
	    if ( content_length <= 0 ) return 3;	/* no content. */

	    pdata = fopen ( argv[2], "w", "mbc=64" );
	    if ( !pdata ) {
		perror ( "Error creating content file\n" );
		return 0;
	    }

	    for ( ; content_length > 0; content_length -= seg ) {
		seg = (content_length > sizeof(buffer) ) ? sizeof(buffer) :
			content_length;
		length = cgi_read ( buffer, seg );
		fwrite ( buffer, length, 1, pdata );
		if ( length <= 0 ) break;
	    }
	    fclose ( pdata );
	}
    } else {
        cgi_set_dcl_env ( base_prefix );
        /*
         * Check if form input parse wanted.
         */
        if ( *form_prefix ) set_form_symbols ( form_prefix );
    }
    return 1;
}
/***************************************************************************/
/* Search comma-delimited list of names (namlist) for specified name
 * and add to end of list if not found.  If found, fetch value of DCL symbol
 * given by prefix+symname and return that to caller.
 *
 * Return values:
 *    0		Name too large to add to list,	vallen set to 0.
 *    1		Name appended to end of list, vallen set to 0.
 *    2		Name found, symbol value stored symval, length in vallen.
 */
static int add_symbol ( char *prefix, char *symname, char *namlist, 
	int *nl_len, char *symval, int *vallen )
{
    int i,j,k, status, prefix_len, LIB$GET_SYMBOL(), table;
    /*
     * Search list from back.
     */
    *vallen = 0;
    for ( i = *nl_len-1; i >= 0; --i ) {
	if ( (i == 0) || namlist[i] == ',' ) {
	    /*
	     * namlist[i] or namlist[i+1] is start of name.
	     */
	    j = (i==0) ? i : i+1;
	    for ( k = 0; symname[k] != '='; k++ ) {
		if ( symname[k] != namlist[j] ) break;
		j++;
	    }
	    if ( (symname[k]=='=') && (namlist[j] == ',' || namlist[j] == '\0') ) {
		/* 
		 * found match, retrieve DCL symbol
		 */
		$DESCRIPTOR(symbol,"");
		$DESCRIPTOR(value,"");
		char prefixed_sym[256];
		/* Build symbol name from prefix */
		prefix_len = strlen(prefix);
 		symbol.dsc$w_length = k + prefix_len;
		if ( symbol.dsc$w_length > 255 ) symbol.dsc$w_length = 255;
		strncpy ( prefixed_sym, prefix, symbol.dsc$w_length );
		strncpy ( &prefixed_sym[prefix_len], symname,	
			symbol.dsc$w_length - prefix_len);
		symbol.dsc$a_pointer = prefixed_sym;

		/*
		 * Make descriptor for result and fetch.
		 */
		value.dsc$w_length = 255;
		value.dsc$a_pointer = symval;

		status = LIB$GET_SYMBOL ( &symbol, &value, vallen, &table );
		if ( (status&1) == 0 ) *vallen = 0;
		return 2;
	    }
	}
    }
    /*
     * No match, append name to namlist.
     */
    i = *nl_len;
    if ( i > 0 && i < 255 ) namlist[i++] = ',';
    for ( j = 0; symname[j] && symname[j] != '='; j++ ) if ( i < 255 ) {
	namlist[i++] = symname[j];
    } else return 0;
    namlist[i] = '\0';

    *nl_len = i;
    return 1;
}
/***************************************************************************/
/* Generate list of symbols for FORM input.
 */
static void set_form_symbols ( char *prefix )
{
    char *var, *fdata;
    int status, table, i, j, k, vallen;
    int content_length, slist_len, length, prefix_len, LIB$SET_SYMBOL();
    $DESCRIPTOR(symbol,"");
    $DESCRIPTOR(value,"");
    char sym_list[256], symname[256], symval[256];
    /*
     * Initialize
     */
    strcpy ( symname, prefix );
    strcat ( symname, "FLD_" );
    prefix_len = strlen ( symname );
    table = LIB$K_CLI_LOCAL_SYM;
    symbol.dsc$a_pointer = symname;
    slist_len = 0;
    /*
     * See if any content present first checking for POST data and using
     * query string as fallback.
     */
    var = cgi_info ( "CONTENT_LENGTH" );
    content_length = var ? atoi(var) : 0;
    
    if ( content_length > 0 ) {
	/*
	 * Allocate buffer and read entire form data into it, forcing final &.
	 */
	fdata = malloc ( content_length+1 );
	if ( !fdata ) return;
	
	length = cgi_read ( fdata, content_length );
    } else {
	var = cgi_info ( "QUERY_STRING" );
	if ( var ) {
	    length = strlen ( var );
	    fdata = malloc ( length + 1 );
	    if ( !fdata ) return;
	    strcpy ( fdata, var );
	} else length = 0;
    }
    if ( length > 0 ) {
	int start, finish, flen;
	/*
	 * Parse the data.
	 */
	if ( fdata[length-1] != '&' ) fdata[length++] = '&';
	start = 0;
	finish = 0;
	for ( i = 0; i < length; i++ ) if ( !fdata[i] || (fdata[i] == '&') ) {
	    /*
	     * Value parsed.  Unescape characters and look for first '='
	     * to delimit field name from value.
	     */
	    flen = i - start;
#ifndef KEEP_PLUSES
	    for ( j = start; j < i; j++ ) 
		if ( fdata[j] == '+' ) fdata[j] = ' ';
#endif
	    net_unescape_string ( &fdata[start], &flen );
	    finish = start + flen;
	    for ( j = start; j < finish; j++ ) if ( fdata[j] == '=' ) {
		/*
		 * Append name to field list or retrieve current DCL symbol
		 * value if already defined once.
		 */
		symname[prefix_len] = '\0';
		k = add_symbol ( symname, &fdata[start], sym_list, &slist_len,
			symval, &vallen );
		/*
		 * Make DCL symbol.  Construct symbol name from prefix
		 * and portion before =, value is portion after.
		 */
 		symbol.dsc$w_length = j - start + prefix_len;
		if ( symbol.dsc$w_length > 255 ) symbol.dsc$w_length = 255;
		strncpy ( &symname[prefix_len], &fdata[start],	
			symbol.dsc$w_length );

		if ( j < finish ) if ( (vallen + finish-j) < 254 ) {
		    /* Append new value to string */
		    if ( vallen > 0 ) symval[vallen++] = ',';
		    strncpy(&symval[vallen], &fdata[j+1], finish-j-1 );
		    vallen += (finish-j-1);
		}
		value.dsc$w_length = vallen;
		value.dsc$a_pointer = symval;

		status = LIB$SET_SYMBOL ( &symbol, &value, &table );
		if ( (status&1) == 0 ) fprintf(stderr,
			"Error defining CGI form symbol: %d\n", status );
		break;
	    } else {
		/* make field name upcase */
		fdata[j] = _toupper(fdata[j]);
		if ( fdata[j] == '-' ) fdata[j] = '_';
	    }
	    start = i+1;
	}
    }
    /*
     * Set final symbol, which is list of fields.
     */
    prefix_len = strlen ( prefix );
    strcpy ( &symname[prefix_len], "FIELDS" );
    symbol.dsc$w_length = strlen ( symname );
    value.dsc$w_length = slist_len;
    value.dsc$a_pointer = sym_list;
    status = LIB$SET_SYMBOL ( &symbol, &value, &table );
}