[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] [0361] [0362] [0363] [0364] [0365] [0366] [0367] [0368] [0369] [0370] [0371] [0372] [0373] [0374] [0375] [0376] [0377] [0378] [0379] [0380] [0381] [0382] [0383] [0384] [0385] [0386] [0387] [0388] [0389] [0390] [0391] [0392] [0393] [0394] [0395] [0396] [0397] [0398] [0399] [0400] [0401] [0402] [0403] [0404] [0405] [0406] [0407] [0408] [0409] [0410] [0411] [0412] [0413] [0414] [0415] [0416] [0417] [0418] [0419] [0420] [0421] [0422] [0423] [0424] [0425] [0426] [0427] [0428] [0429] [0430] [0431] [0432] [0433] [0434] [0435] [0436] [0437] [0438] [0439] [0440] [0441] [0442] [0443] [0444] [0445] [0446] [0447] [0448] [0449] [0450] [0451] [0452] [0453] [0454] [0455] [0456] [0457] [0458] [0459] [0460] [0461] [0462] [0463] [0464] [0465] [0466] [0467] [0468] [0469] [0470] [0471] [0472] [0473] [0474] [0475] [0476] [0477] [0478] [0479] [0480] [0481] [0482] [0483] [0484] [0485] [0486] [0487] [0488] [0489] [0490] [0491] [0492] [0493] [0494] [0495] [0496] [0497] [0498] [0499] [0500] [0501] [0502] [0503] [0504] [0505] [0506] [0507] [0508] [0509] [0510] [0511] [0512] [0513] [0514] [0515] [0516] [0517] [0518] [0519] [0520] [0521] [0522] [0523] [0524] [0525] [0526] [0527] [0528] [0529] [0530] [0531] [0532] [0533] [0534] [0535] [0536] [0537] [0538] [0539] [0540] [0541] [0542] [0543] [0544] [0545] [0546] [0547] [0548] [0549] [0550] [0551] [0552] [0553] [0554] [0555] [0556] [0557] [0558] [0559] [0560] [0561] [0562] [0563] [0564] [0565] [0566] [0567] [0568] [0569] [0570] [0571] [0572] [0573] [0574] [0575] [0576] [0577] [0578] [0579] [0580] [0581] [0582] [0583] [0584] [0585] [0586] [0587] [0588] [0589] [0590] [0591] [0592] [0593] [0594] [0595] [0596] [0597] [0598] [0599] [0600] [0601] [0602] [0603] [0604] [0605] [0606] [0607] [0608] [0609] [0610] [0611] [0612] [0613] [0614] [0615] [0616] [0617] [0618] [0619] [0620] [0621] [0622] [0623] [0624] [0625] [0626] [0627] [0628] [0629] [0630] [0631] [0632] [0633] [0634] [0635] [0636] [0637] [0638] [0639] [0640] [0641] [0642] [0643] [0644] [0645] [0646] [0647] [0648] [0649] [0650] [0651] [0652] [0653] [0654] [0655] [0656] [0657] [0658] [0659] [0660] [0661] [0662] [0663] [0664] [0665] [0666] [0667] [0668] [0669] [0670] [0671] [0672] [0673] [0674] [0675] [0676] [0677] [0678] [0679] [0680] [0681] [0682] [0683] [0684] [0685] [0686] [0687] [0688] [0689] [0690] [0691] [0692] [0693] [0694] [0695] [0696] [0697] [0698] [0699] [0700] [0701] [0702] [0703] [0704] [0705] [0706] [0707] [0708] [0709] [0710] [0711] [0712] [0713] [0714] [0715] [0716] [0717] [0718] [0719] [0720] [0721] [0722] [0723] [0724] [0725] [0726] [0727] [0728] [0729] [0730] [0731] [0732] [0733] [0734]
/* * Define support routines for porting CGI (Common Gateway Interface) * conforming programs to the DECthreads script environment. * * Routines: * int cgi_init ( int argc, char **argv ); * Initialize support routines. Command line arguments will * be retrieved. * * char *cgi_info ( char *name ); * This routine returns environment and request information * for the current request. If run in the CERN server * environment, this routine simply performs a get * * int cgi_write ( char *string, int length ); * Send output. * * int cgi_printf ( char *ctlstr, ... ); * * int cgi_read ( char *buffer, int bufsize ); * * int cgi_set_dcl_env ( char *prefix ); * int cgi_set_cli_env ( char *prefix, char *table_name ); * * FILE *cgi_content_file(); * * Author: David Jones * Revised: 2-JUN-1994 ! don't decode query_string (unless * ! module compiled with DECODE_QUERY * Revised: 27-JUN-1994 ! corrected cgi_read to use contentf. * Revised: 19-JUL-1994 ! Fixed bad parse of content_length. * Revised: 27-SEP-1994 ! added cgi_set_dcl_env() routine. * Revised: 18-OCT-1994 ! Switch to <DNETID2> to get host name. * Revised: 20-DEC-1994 ! Fixed bug in allocating scriptname * ! storage, wrong size being used. * Revised: 14-JAN-1995 ! Added missing REMOTE_PORT to env * ! table, fixed length allocation in * ! fetch value. * Revised: 26-APR-1995 ! Build path_info from requested * ! url when script_path null. * Revised: 16-MAY-1995 ! additional routines for special * ! interface for defering output. * Revised: 20-MAR-1996 ! add cgi_set_cli_env function * Revised: 22-MAR-1996 ! add content cache. * Revised: 27-AUG-1996 ! fix bug in cgi_write, (large writes). * Revised: 6-MAY-1997 ! handle case where script path * ! template used by server does not * ! end in "/" or "/*". * Revised: 24-JUN-1997 ! have cgi_set_cli_env create * ! multi-value logicals. * Revised: 14-OCT-1998 ! Fix bugs in multi-value logical * ! creation. */ #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <descrip.h> #include <lnmdef.h> #include <libclidef.h> #define strerror strerror_1 #include <string.h> #undef strerror char *strerror ( int errnum, ... ); #include <ctype.h> #include <errno.h> #include "cgilib.h" #include "scriptlib.h" /* * Define static structure to hold environment information expect by CGI * programs. */ struct envdef { char *name, *value; int state; }; #define ENV_LIMIT 200 #define NET_IO_SIZE 1000 #define CONTENT_CACHE_SIZE 4096 static int content_length=0, env_used = 19; /* * Content cache will hold request content in memory if possible. * Iff content_cache_length is negative, content is in file opened on contentf, * otherwise content_cache_pos holds next read position from cache array. */ static int content_cache_length, content_cache_pos = 0; static FILE *contentf; static char content_cache[CONTENT_CACHE_SIZE]; static struct envdef env[ENV_LIMIT] = { /* Request independent variables */ { "SERVER_SOFTWARE", "", 0 }, { "SERVER_NAME", "", 0 }, { "GATEWAY_INTERFACE", "CGI/1.0", 1 }, /* Request-specific variables */ { "SERVER_PROTOCOL", "", 0 }, { "SERVER_PORT", "", 0 }, { "REQUEST_METHOD", "", 0 }, { "PATH_INFO", "", 0 }, { "PATH_TRANSLATED", "", 0 }, { "SCRIPT_NAME", "", 0 }, { "SCRIPT_PATH", "", 0 }, { "QUERY_STRING","", 0 }, { "REMOTE_USER", "", 0 }, { "REMOTE_ADDR", "", 0 }, { "REMOTE_PORT", "", 0 }, { "REMOTE_HOST", "", 0 }, { "AUTH_TYPE", "", 0 }, { "REMOTE_IDENT", "", 0 }, { "CONTENT_TYPE", "", 0 }, { "CONTENT_LENGTH", "", 0 } }; static int env_index ( char *name ) { int i; for (i = 0; i < env_used; i++) if (0==strcmp ( name, env[i].name)) { return i; } return ENV_LIMIT; } /* Query server for tag and place result in environment array */ static int fetch_value ( char *name, char *tag, int *length, char **value ) { int status, ndx; char buffer[4096]; status = net_link_query ( tag, buffer, sizeof(buffer), length ); if ( (status&1) == 0 ) return status; if ( *length > 0 ) { ndx = env_index ( name ); if ( ndx >= ENV_LIMIT ) return 20; env[ndx].value = *value = malloc ( (*length) + 1 ); strncpy ( *value, buffer, *length ); env[ndx].value[*length] = '\0'; env[ndx].state = 1; } return status; } static int load_translation ( char *name, char *tag, char *arg ) { int status, ndx, length; char *value, buffer[4096]; status = net_link_write ( tag, strlen(tag) ); if ( (status&1) == 0 ) return status; status = net_link_query ( arg, buffer, sizeof(buffer), &length ); if ( (status&1) == 0 ) return status; if ( length > 0 ) { ndx = env_index ( name ); if ( ndx >= ENV_LIMIT ) return 20; env[ndx].value = value = malloc ( (length) + 1 ); strncpy ( value, buffer, length ); env[ndx].value[length] = '\0'; env[ndx].state = 1; } return status; } /***************************************************************************/ /* Return copy of content_file pointer. Must convert cached content. */ FILE *cgi_content_file() { if ( content_cache_length >= 0 ) { /* * We have been reading from internal cache, convert it to real file. */ contentf = fopen ( tmpnam(NULL), "w+", "fop=dlt", "mbc=64" ); if ( contentf ) { /* put cache contents into file and match current position. */ fwrite ( content_cache, content_cache_length, 1, contentf ); fseek ( contentf, content_cache_pos, 0 ); } content_cache_length = -1; /* cache no longer valid */ } return contentf; } /***************************************************************************/ /* Initialize CGI envrironment and place net_link in CGI mode. */ int cgi_init ( int argc, char **argv ) { int status; status = cgi_init_env ( argc, argv ); if ( status&1 ) status = cgi_begin_output(1); return status; } /***************************************************************************/ /* Send <DNETCGI> tag to server to place link into CGI mode. If rundown * flag true, exit handler will be setup to automatically terminate CGI * mode on image exit (sends </DNETCGI> tag). */ int cgi_begin_output ( int rundown_on_exit ) { int status; status = net_link_write ( "<DNETCGI>", 9 ); if ( rundown_on_exit ) net_link_set_rundown ( "</DNETCGI>" ); return status; } /***************************************************************************/ /* Initialize CGI environment array. Return value is VMS condition code. */ int cgi_init_env ( int argc, char **argv ) { int status, ndx, i, colon, length; char *label, *value, buffer[4096]; /* * Establish connection to server. */ content_cache_length = -1; content_cache_pos = 0; status = net_link_open(); if ( (status&1) == 0 ) return status; /* * Assume program invoked with arguments: method url protocol */ if ( (ndx = env_index ( "REQUEST_METHOD" )) < ENV_LIMIT ) { env[ndx].state = 1; if ( argc > 1 ) env[ndx].value = argv[1]; } if ( (ndx = env_index ( "SCRIPT_NAME" )) < ENV_LIMIT ) { if ( argc > 2 ) { /* Duplicate argv[2] string. */ env[ndx].value = malloc ( strlen(argv[2])+1 ); strcpy ( env[ndx].value, argv[2] ); env[ndx].state = 1; } } if ( (ndx = env_index ( "SERVER_PROTOCOL" )) < ENV_LIMIT ) { env[ndx].state = 1; if ( argc > 3 ) env[ndx].value = argv[3]; } /* * Ask server for its version and connection information. */ status = fetch_value ( "SERVER_SOFTWARE", "<DNETID2>", &length, &value ); if ( (status&1) == 1 ) value = strchr(value, ' '); else value = NULL; if ( value ) { *value++ = '\0'; ndx = env_index ( "SERVER_NAME" ); env[ndx].state = 1; env[ndx].value = value; value = strchr(value, ' '); } if ( value ) { *value++ = '\0'; ndx = env_index ( "SERVER_PORT" ); env[ndx].state = 1; env[ndx].value = value; value = strchr(value, ' '); } if ( value ) { *value++ = '\0'; ndx = env_index ( "REMOTE_PORT" ); env[ndx].state = 1; env[ndx].value = value; value = strchr(value, ' '); } if ( value ) { int addr; char *nextval; *value++ = '\0'; ndx = env_index ( "REMOTE_ADDR" ); nextval = strchr(value,' '); /* find end of string */ if ( nextval ) *nextval = '\0'; /* truncate it for atoi() */ addr = atoi ( value ); env[ndx].state = 1; env[ndx].value = malloc(16); sprintf ( env[ndx].value, "%d.%d.%d.%d", (addr&255), ((addr>>8)&255), ((addr>>16)&255), ((addr>>24)&255) ); value = nextval; } if ( value ) { *value++ = '\0'; ndx = env_index ( "REMOTE_USER" ); /* * Only set value if string is non-null. */ if ( *value != ' ' ) env[ndx].state = 1; env[ndx].value = value; value = strchr(value,' '); /* find end of string */ } if ( value ) { *value++ = '\0'; ndx = env_index ( "REMOTE_HOST" ); env[ndx].state = 1; env[ndx].value = value; value = strchr(value,' '); /* Find end of string */ if ( value ) *value = '\0'; /* Terminate it */ } else { /* Fallback remote host to REMOTE_ADDR */ int andx; andx = env_index ( "REMOTE_ADDR" ); if ( env[andx].state ) { ndx = env_index ( "REMOTE_HOST" ); env[ndx].state = 1; env[ndx].value = env[andx].value; } } /* * Ask for name of script being executed and derive path_info and * script name from that. */ status = fetch_value ( "SCRIPT_PATH", "<DNETPATH>", &length, &value ); if ( ((status&1) == 1) && (strncmp(argv[2], value, length )==0) ) { /* * add path_info entry. */ char *p; if ( (ndx = env_index ( "PATH_INFO" )) < ENV_LIMIT ) { if ( length > 0 ) { /* * path info follows script_name, (1st slash after script_path) */ env[ndx].state = 1; for ( p = &argv[2][length]; *p && (*p != '/'); p++ ); #ifndef NOHACK1 if ( *p == '/' && value[length-1] != '/' ) { /* Rewrite script_path, make new value and length */ int path_ndx; while ( p != &argv[2][length] ) length++; length++; path_ndx = env_index ( "SCRIPT_PATH" ); env[path_ndx].value = value = realloc ( value, length+1 ); strncpy ( value, argv[2], length ); value[length] = '\0'; /* script path didn't end in '/', take next slash. */ for ( p++; *p && (*p != '/'); p++ ); } #endif env[ndx].value = p; } else { /* * Get original URL to bypass server translation done on arg2 * Fixup path_info: strip search arg and unescape. */ int plen; fetch_value ( "PATH_INFO", "<DNETRQURL>", &plen, &p ); for ( plen = 0; p[plen]; plen++ ) if ( p[plen] == '?' ) { p[plen] = 0; break; } net_unescape_string ( p, &plen ); p[plen] = '\0'; } load_translation ( "PATH_TRANSLATED", "<DNETXLATE>", p ); } if ( (ndx = env_index ( "SCRIPT_NAME" )) < ENV_LIMIT ) { if ( strlen(env[ndx].value) > length ) { for ( p = &env[ndx].value[length]; *p && (*p != '/'); p++ ); *p = '\0'; /* Truncate script name */ } } } /* * Get query string and convert escaped characters. */ status = fetch_value ( "QUERY_STRING", "<DNETARG>", &length, &value ); if ( (status&1) == 0 ) return status; if ( length > 0 ) { length = length - 1; /* remove leading '?' */ for ( i = 0; i < length; i++ ) value[i] = value[i+1]; #ifdef DECODE_QUERY net_unescape_string ( value, &length ); #endif value[length] = '\0'; } /* * Get header lines from HTTP server and save in environment array. */ status = net_link_write ( "<DNETHDR>", 9 ); if ( (status&1) == 0 ) return status; content_length = 0; do { status = net_link_read ( buffer, sizeof(buffer), &length ); if ( (status &1) == 0 ) return status; /* Parse out header label */ for ( colon = 0; colon < length; colon++ ) if ( buffer[colon]==':' ) { value = malloc ( length+1 ); strncpy ( value, buffer, length ); value[length] = '\0'; /* * Construct label. Upcase characters and convert '-' to '_'. */ label = malloc ( colon + 6 ); strcpy ( label, "HTTP_" ); for ( i = 0; i < colon; i++ ) { label[i+5] = _toupper(buffer[i]); if ( label[i+5] == '-' ) label[i+5] = '_'; } label[colon+5] = '\0'; /* * Trim leading whitespace. */ for ( colon++; isspace(value[colon]); colon++ ); /* * Check for special header lines that go into pre-defined * variables. */ if ( 0 == strcmp(label,"HTTP_CONTENT_LENGTH") ) { ndx = env_index ( "CONTENT_LENGTH" ); content_length = atoi ( &value[colon] ); free ( label ); } else if ( 0 == strcmp ( label, "HTTP_CONTENT_TYPE") ) { ndx = env_index ( "CONTENT_TYPE" ); free ( label ); } else if ( (ndx=env_index(label)) < ENV_LIMIT ) { /* * Append string to existing. Allocate extra. */ int old_length; char *cat_value; old_length = strlen ( env[ndx].value ); cat_value = malloc ( old_length + length + 3 ); strcpy ( cat_value, env[ndx].value ); strcpy ( &cat_value[old_length], ", "); strcpy ( &cat_value[old_length+2], &value[colon] ); free ( env[ndx].value ); free ( value ); value = cat_value; colon = 0; } else { /* Make new */ ndx = env_used; if ( ndx < ENV_LIMIT ) { env_used = ndx + 1; env[ndx].name = label; } } if ( ndx < ENV_LIMIT ) { char *in, *out; env[ndx].state = 1; /* mark as valid */ env[ndx].value = value; /* Trim label from value buffer. */ if ( colon != 0) { in = &value[colon]; for ( out = value; *in; *out++ = *in++ ); *out = '\0'; } } break; } if ( (colon >= length) && (length > 0) ) { /* Continuation header line, handle later */ } } while ( length > 0 ); /* continue until null line read */ /* * If request includes data, read it into temporary file. */ if ( content_length > 0 ) { /* * Check for content-length limit. */ char *cl_limit; cl_limit = getenv("WWW_MAX_CGILIB_CONTENT"); if ( cl_limit ) { if ( content_length > atoi(cl_limit) ) content_length = 0; } if ( content_length < CONTENT_CACHE_SIZE ) { /* Make internal copy rather than creating file. */ content_cache_length = content_length; contentf = (FILE *) 0; } else { /* Content to big to go to cache, go directly to file. */ contentf = fopen ( tmpnam(NULL), "w+", "fop=dlt", "mbc=64" ); } if ( contentf || content_cache_length >= 0 ) { int remaining, k; char *content_type; /* * Request the file a chunk at a time. */ for ( remaining = content_length; remaining > 0; remaining = remaining - length ) { /* * Get server to read more data from client and sent it to us. */ status = net_link_write ( "<DNETINPUT>", 11 ); if ( (status&1) == 0 ) break; /* * Read the sent data and output to contents file. */ status = net_link_read ( buffer, sizeof(buffer), &length ); if ( (status&1) == 0 ) break; if ( length > 0 ) { if ( contentf ) { status = fwrite(buffer, length, 1, contentf); } else { if ( length+content_cache_pos > CONTENT_CACHE_SIZE ) length = CONTENT_CACHE_SIZE - content_cache_pos; memcpy ( &content_cache[content_cache_pos], buffer,length); content_cache_pos += length; } } if ( status == 0 ) { status = vaxc$errno; break; }/* error */ } if ( remaining > 0 ) { fprintf ( stderr, "Error getting request contents: %s\n(continuing)\n", strerror ( EVMSERR, status ) ); } /* * Reset for reads. */ if ( contentf ) fseek ( contentf, 0, 0 ); else content_cache_pos = 0; } else { fprintf(stderr,"Error opening request contents temp file:\n%s\n", strerror(errno,vaxc$errno) ); content_length = 0; } } return status; } /************************************************************************/ /* Do server callback to translate server path according to server's rule * file translation rules, optionally doing protection check as well. * An invalid or protected path will return a zero in the length argument * and a 1 status, errors communicating with the server will return a VMS * error condition code. */ int cgi_translate_path ( char *path, int check_protection, char *buffer, int bufsize, int *length ) { int status, tag_len; char *tag; *length = 0; if ( check_protection ) { tag = "<DNETXLATEV>"; tag_len = 12; } else { tag = "<DNETXLATE>", tag_len = 11; } /* * Send tag followed by path and read response. */ status = net_link_write ( tag, tag_len ); if ( (status&1) == 0 ) return status; status = net_link_query ( path, buffer, bufsize, length ); return status; } /************************************************************************/ /* Return CGI variable. In standard CGI this would just be a getenv call. * The lookup will ignore a "WWW_" prefix, if present, on the variable name * to ease porting of CERN VMS clients. */ char *cgi_info ( char *name ) { int ndx; if ( strncmp ( name, "WWW_", 4 ) == 0 ) name = &name[4]; ndx = env_index ( name ); #ifdef DEBUG printf("/cgilib/ info index for %s is %d\n", name, ndx ); #endif if ( ndx < env_used ) return env[ndx].value; return getenv ( name ); } /*****************************************************************************/ /* Write data to CGI result file. For CERN server this would go to * standard output. Return value is number of characters written or -1; */ int cgi_write ( char *buffer, int bufsize ) { int status, remaining, length, segment; /* * Network link can't handle arbitrary write lengths, break it up. */ for (remaining = bufsize; remaining > 0; remaining = remaining - length) { length = remaining > NET_IO_SIZE ? NET_IO_SIZE : remaining; status = net_link_write ( buffer, length ); if ( (status&1) == 0 ) return -1; /* error */ buffer += length; } return (bufsize - remaining); } /*****************************************************************************/ /* Read data from contents file. In unix CGI this would read from standard * input. Return value is number of character read or zero for eof. */ int cgi_read ( char *buffer, int bufsize ) { int status, length; if ( content_length <= 0 ) return 0; /* no data in request */ if ( content_cache_length < 0 ) { return fread ( buffer, 1, bufsize, contentf ); } else { int count; count = content_cache_length - content_cache_pos; if ( count > bufsize ) count = bufsize; if ( count <= 0 ) return -1; memcpy ( buffer, &content_cache[content_cache_pos], count ); content_cache_pos += count; return count; } } /************************************************************************/ /* Convert internal environment list to global DCL symbols with the * specified prefix. Number of symbols created is returned. The * rundown string in the exit handler is reset and a DCL symbol * WWWEXEC_RUNDOWN_STRING, is defined as well. Any content file data * will be lost when program exits (not available from DCL). */ int cgi_set_dcl_env ( char *prefix ) { return cgi_set_cli_env ( prefix, (char *) 0 ); } int cgi_set_cli_env ( char *prefix, char *log_table ) /* if null or zero length, use DCL symbols */ { int i, lnm, hits, status, prefix_len, length, table, LIB$SET_SYMBOL(); int LIB$SET_LOGICAL(); $DESCRIPTOR(symbol,""); $DESCRIPTOR(value,""); $DESCRIPTOR(parent,""); char symname[256], table_name[256]; /* * Define global symbol used by WWWEXEC to terminate connection properly. */ symbol.dsc$a_pointer = symname; strcpy ( symname, "WWWEXEC_RUNDOWN_STRING" ); symbol.dsc$w_length = strlen(symbol.dsc$a_pointer); value.dsc$a_pointer = "</DNETCGI>"; value.dsc$w_length = strlen(value.dsc$a_pointer); table = LIB$K_CLI_GLOBAL_SYM; status = LIB$SET_SYMBOL ( &symbol, &value, &table ); if ( (status&1) == 1 ) net_link_set_rundown ( "" ); /* eliminate rundown output */ else printf("Error in set_symbol: %d, len: %d\n", status, symbol.dsc$w_length ); /* * Determine output mode. */ if ( !log_table ) lnm = 0; else if ( *log_table == '\0' ) lnm = 0; else { /* * Set flag to cause logical name creation and upcase name. */ lnm = 1; for (i = 0; log_table[i]; i++) table_name[i] = toupper(log_table[i]); table_name[i] = '\0'; parent.dsc$w_length = i; parent.dsc$a_pointer = table_name; } /* * Define local symbols to be used by calling script. */ table = LIB$K_CLI_LOCAL_SYM; prefix_len = strlen ( prefix ); if ( prefix_len > 255 ) prefix_len = 255; strncpy ( symname, prefix, prefix_len ); for ( hits = i = 0; i < env_used; i++ ) if ( env[i].state ) { /* * Construct symbol name. */ length = strlen ( env[i].name ); if ( (prefix_len + length) > 255 ) length = 255 - prefix_len; symbol.dsc$w_length = prefix_len + length; strncpy ( &symname[prefix_len], env[i].name, length ); /* * Make descriptor for value. */ value.dsc$a_pointer = env[i].value; value.dsc$w_length = strlen ( env[i].value ); /* * upload symbol to environment, either logical name or CLI symbol. */ if ( lnm ) { struct item_list { short length, code; char *ptr; short *retlen; } *itm; itm = (struct item_list *) 0; /* 12-MAY-2000 MGD (short)! */ if ( (short)value.dsc$w_length <= 0 ) continue; else if ( value.dsc$w_length > 255 ) { /* * Construct item list to define multiple names. */ int k, count; count = (value.dsc$w_length+255)/255; itm = (struct item_list *) malloc ( sizeof(struct item_list) * (count+1) ); for ( k = 0; value.dsc$w_length > 0; k++ ) { itm[k].length = value.dsc$w_length; if ( itm[k].length > 255 ) itm[k].length = 255; itm[k].code = LNM$_STRING; itm[k].ptr = value.dsc$a_pointer; itm[k].retlen = (short *) 0; value.dsc$a_pointer += itm[k].length; value.dsc$w_length = value.dsc$w_length - itm[k].length; } itm[k].code = itm[k].length = 0; } status = LIB$SET_LOGICAL ( &symbol, &value, &parent, 0, itm ); if ( itm ) free ( itm ); } else { /* Truncate DCL symbol to 255 characters */ if ( value.dsc$w_length > 255 ) value.dsc$w_length = 255; status = LIB$SET_SYMBOL ( &symbol, &value, &table ); } } return hits; } /*****************************************************************************/ /* Dump environement array to specified output file. */ int cgi_show_env ( int (*user_printf)() ) { int i, hits; for ( hits = i = 0; i < env_used; i++ ) { user_printf("%s %s%s\n", env[i].name, env[i].state ? "= ": "*undefined* ", env[i].value); if ( env[i].state ) hits++; } return hits; } /**************************************************************************/ /* Provide formatted output to net_link, replacing printf calls to stdout. * Newline chars in format string are replaced with carriage-return/linefeed * pairs. */ int cgi_printf ( const char *fmt, ... ) { va_list alist; int state, out_len, status, j; char buffer[8192]; /* * Setup pointer to variable argument list. */ va_start ( alist, fmt ); status = vsprintf ( buffer, fmt, alist ); if ( status == EOF ) return status; va_end ( alist ); status = net_link_printf ( "%s", buffer ); return status; }