Files
WrenchBoradWeb/wrenchboard/src/core/cgi.cc
T
2020-07-31 04:58:02 -04:00

1947 lines
39 KiB
C++

#include <sqlext.h>
#include <netdb.h>
#include <utime.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include "smtp.h"
#include <string.h>
#include "cgi.h"
#include <regex.h>
#include "safestring.h"
#include "cfg.h"
#include "clog.h"
#include "util.h"
#include "timer.h"
extern char SENDMAIL[];
int GetParam(char * params, char _name[], char value[], int valuelen, char ** end /*= NULL*/)
// *end is the first character after the end of the value
{
// logfmt( FLOG_MAX, "::GetParam( params='%s', name='%s', sz=%d )", params, _name, valuelen );
char *c, *cbeg, *cend, *vc;
unsigned int ch, len;
char name[50];
value[0] = 0;
snprintf( name, sizeof(name), "%s=", _name );
// logfmt( FLOG_MAX, "name=%s, params=%s", name, params );
if ( strncasecmp( name, params, strlen(name) ) == 0 )
{
cbeg = params + strlen( name );
cend = params + strcspn( params, "&;" );
// logfmt( FLOG_MAX, "cbeg=%s, len=%d", cbeg, cend-cbeg );
}
else
{
snprintf( name, sizeof(name), "&%s=", _name );
c = strcasestr( params, name );
if (!c )
{
snprintf( name, sizeof(name), " %s=", _name );
c = strcasestr( params, name );
}
if (!c )
{
snprintf( name, sizeof(name), "\n%s=", _name );
c = strcasestr( params, name );
}
if (!c)
return 0;
cbeg = c + strlen( name );
c++;
cend = c + strcspn( c, "&;" );
//logfmt( FLOG_MAX, "" );
}
// Ready to deal with '%' and '+' -- urldecode
c = cbeg; vc = value;
char save = *cend;
*cend = 0;
urldecode( cbeg, value, valuelen );
*cend = save;
// Strip trailing spaces
//logfmt( FLOG_MAX, "" );
while ( strlen(value)>0 && value[ strlen(value)-1 ] == ' ' )
value[ strlen(value)-1 ] = 0;
if (end)
*end = cend;
return 1;
}
bool initcgilib(int log = 0)
{
return true;
}
char * strlower( const char * str, char * res )
{
int len = strlen(str);
for ( int i=0; i<=len; i++ )
{
res[i] = tolower( str[i] );
}
return res;
}
/* Class definitions */
C_CGI_Form::C_CGI_Form( char * _dir, char * _template_file, char * _global_template/*=NULL*/, int _argc/*=0*/, char **_argv/* = NULL*/ )
{
//logfmt( FLOG_MAX, "C_CGI_Form constructor" );
sequence = SEQ_NONE;
dir = strdup( _dir );
if (_global_template)
global_template = strdup(_global_template);
else
global_template = NULL;
if ( getenv("SCRIPT_NAME") )
{
argc = _argc; argv = _argv;
char pars[16096]; pars[sizeof(pars)-1] = 0;
if ( !fgets( pars, sizeof(pars), stdin ) )
{
method = METHOD_GET;
char * qs = getenv("QUERY_STRING");
if ( qs && (strlen(qs)>0) )
params = strdup( qs );
else
{
params = strdup( "" );
// LOG( "No parameters", LOG_FATAL );
}
}
else // method POST
{
method = METHOD_POST;
//log.logfmt( FLOG_MAX, "strlen(pars)=%d, pars=%s", strlen(pars), pars );
params = strdup(pars);
if (!params)
{
logfmt( FLOG_MAX, "strdup failed" );
params = strdup("");
}
}
// log.logfmt( FLOG_MAX, pars );
// Uncomment below is you want to see what is being passed from the browser
// if ( params[0] ) //LOG( params, LOG_COMMAND );
// log.logfmt( FLOG_MAX, "%s", params );
}
else
{
method = METHOD_NONE;
params = strdup( "" );
}
template_file = strdup(_template_file);
nlists = 0;
#ifdef WITH_LANGUAGE
language[0] = 0;
char tmp_lang[10];
GetParam( "lang", tmp_lang, sizeof(tmp_lang) );
if ( reg_match( tmp_lang, "[[:alpha:]_-]+" ) )
{
logfmt( FLOG_MAX, "Language given as a parameter: %s", tmp_lang );
char expires[50] = "", domain[50] = "chiefsoft.com";
// determine the domain name
char * server_name = getenv( "SERVER_NAME" );
if ( server_name )
{
strsafecpy( domain, server_name, sizeof(domain) );
tolower( domain );
if ( strncasecmp( domain, "www.", 4 )==0 )
memmove( domain, &domain[4], strlen(domain)-4+1 );
}
else
logfmt( logWARNING, "Environment variable SERVER_NAME not found" );
int cookie_duration = 365*24*60; // default is now 24 hours x 365 = 1 year
time_t now = time( NULL ); now += cookie_duration*60; // cookie_duration is in minutes
strftime( expires, sizeof(expires), "; expires=%a, %d-%b-%Y %X GMT", gmtime( &now ) );
logfmt( FLOG_MAX, "DEBUG" );
send_header( "Set-Cookie: lang=%s; path=/; domain=%s%s", tmp_lang, domain, expires );
logfmt( FLOG_MAX, "DEBUG" );
logfmt( FLOG_MAX, "Set-Cookie: lang=%s; path=/; domain=%s%s", tmp_lang, domain, expires );
logfmt( FLOG_MAX, "DEBUG" );
strsafecpy( language, tmp_lang, sizeof( language ) );
logfmt( FLOG_MAX, "DEBUG" );
}
else
{
char * cookie = getenv( "HTTP_COOKIE" );
if ( cookie )
{
::GetParam( cookie, "lang", tmp_lang, sizeof( tmp_lang ) );
if ( reg_match( tmp_lang, "[[:alpha:]_-]+" ) )
{
logfmt( FLOG_MAX, "Language found in a cookie: %s", tmp_lang );
strsafecpy( language, tmp_lang, sizeof( language ) );
}
}
}
#endif
};
C_CGI_Form::~C_CGI_Form()
{
for ( int i=0; i<nlists; i++ )
if ( lists[i] ) delete lists[i]; // maybe zero out lists[i].form?
free( dir );
free( template_file );
free( params );
if ( global_template ) free( global_template );
}
void CatFile( char * fname, FILE * fout )
{
FILE * f = fopen( fname, "r" );
if (!f)
{
logfmt( logWARNING, "Couldn't open included file '%s'", fname );
return;
}
char buf[1024];
int read;
do {
read = fread( buf, 1, sizeof(buf), f );
fwrite( buf, 1, read, fout );
} while ( read==sizeof(buf) );
fclose( f );
}
char * C_CGI_Form::FormFile( char * fname )
{
logfmt( FLOG_MAX, "CGI Parsing: %s", fname );
char * result = NULL;
struct stat stats;
if ( stat(fname, &stats)==-1 )
{
logfmt( FLOG_MAX, "stat() error: %s, '%s'", strerror(errno), fname );
// delete filename;
// return 0;
return strdup("Template read error");
}
FILE * f = fopen( fname, "r" );
// delete filename;
if (!f)
{
logfmt( logERROR, "Could not read template '%s'", fname );
return strdup("Template read error");
}
char * buf = (char *)malloc(stats.st_size+1);
if (!buf)
{
fclose( f );
logfmt( logERROR, "Could not allocate %d bytes form template '%s'", stats.st_size+1, fname );
return 0;
}
fread( buf, 1, stats.st_size, f );
fclose( f );
buf[stats.st_size] = 0;
// Find out if this template has a parent and insert it into parent as necessary
char ret[100], *start = buf;
if ( reg_match( buf, "^([[:alnum:][:punct:]-]+\\[[[:alnum:]_]+\\]).*", ret, sizeof(ret) ) )
{
logfmt( FLOG_MAX, "TODO: Parent template: %s", ret );
start += strlen(ret);
char pfname[100], varname[50], pfname_full[200];
reg_match( ret, "^([[:alnum:][:punct:]-]+)\\[[[:alnum:]_]+\\]$", pfname, sizeof(pfname) );
reg_match( ret, "^[[:alnum:][:punct:]-]+\\[([[:alnum:]_]+)\\]$", varname, sizeof(varname) );
logfmt( FLOG_MAX, "file=%s, name=%s", pfname, varname );
LetStr( varname, start );
free(buf);
snprintf( pfname_full, sizeof(pfname_full), TMPL_PREFIX"/tmpl/%s", pfname );
logfmt( FLOG_MAX, "Loading Template '%s'", pfname_full );
buf = FormFile( pfname_full );
return buf;
}
logfmt( FLOG_MAX, "Template '%s' loaded: %d bytes", fname, stats.st_size );
// Last step: parse and substutute
result = RFormBuffer( start );
free( buf );
logfmt( FLOG_MAX, "Returning from FormFile()" );
return result;
}
int regall( const char * regex, const char * string, size_t nmatch, regmatch_t pmatch[] )
{
regex_t compiled;
int r;
r = regcomp( &compiled, regex, REG_EXTENDED );
if ( r ) return r;
r = regexec( &compiled, string, nmatch, pmatch, 0 );
regfree( &compiled );
return r;
}
void C_CGI_Form::GetNextVariable( TList * &cur, char * &c1, char * &c, char * listname, int listi )
{
c = strstr( c1, "{{" );
if (!c)
{
cur = Add( cur, c1, strlen(c1) ); // end
return;
}
// LOG( "BP", LOG_MAX );
cur = Add( cur, c1, c-c1 );
c += 2;
// LOG( "BP", LOG_MAX );
// Check for recursive variables, i.e., {{text{{var2}}}}
// Find the corresponding right bracket '}}'
char *c2;
int level = 1, maxlevel = 1;
char * b1 = c, *b2;
for ( c2=b1; c2<c+strlen(c); c2++ )
{
// logfmt(FLOG_MAX, "*c2=%c", *c2 );
if ( *c2=='{' && *(c2+1)=='{' )
{
level++; c2++;
if ( level>maxlevel )
maxlevel = level;
}
else
if ( *c2=='}' && *(c2+1)=='}' )
{
level--; c2++;
// logfmt(FLOG_MAX, "level=%d", level );
}
if (!level) break;
}
// LOG( "BP", LOG_MAX );
if ( c2==c1+strlen(c1) ) // no closing }}
{
cur = Add( cur, c, strlen(c) ); // end
c = 0;
return;
}
// LOG( "BP", LOG_MAX );
c2--; *c2 = 0; c2+=2;
// logfmt( FLOG_MAX, "Looking at '%s'", c );
if ( maxlevel>1 ) // recursive call needed
{
// char *newbuf = new char[ c2-b1 ];
// memcpy( newbuf, b1, c2-b1-1 );
// newbuf[ c2-b1-1 ] = 0;
// LOG( "Recursive call", LOG_MAX );
c = RFormBuffer( c, listname, listi );
// delete newbuf;
}
c1 = c2;
}
char * C_CGI_Form::RFormBuffer( char * buf, char * listname /*= NULL*/, int listi /*= 0*/ )
{
// parse and substutute
char * c = buf, *c1=buf;
TList *top = new TList, *cur = top;
// LOG( "BP", LOG_MAX );
do {
c = strstr( c1, "{{" );
// logfmt( FLOG_MAX, c );
if (!c)
{
cur = Add( cur, c1, strlen(c1) ); // end
break;
}
// LOG( "BP", LOG_MAX );
cur = Add( cur, c1, c-c1 );
c += 2;
// LOG( "BP", LOG_MAX );
// Check for recursive variables, i.e., {{text{{var2}}}}
// Find the corresponding right bracket '}}'
char *c2;
int level = 1, maxlevel = 1;
char * b1 = c, *b2;
for ( c2=b1; c2<c+strlen(c); c2++ )
{
// logfmt(FLOG_MAX, "*c2=%c", *c2 );
if ( *c2=='{' && *(c2+1)=='{' )
{
level++; c2++;
if ( level>maxlevel )
maxlevel = level;
}
else
if ( *c2=='}' && *(c2+1)=='}' )
{
level--; c2++;
// logfmt(FLOG_MAX, "level=%d", level );
}
if (!level) break;
}
// LOG( "BP", LOG_MAX );
if ( c2==c1+strlen(c1) ) // no closing }}
{
cur = Add( cur, c, strlen(c) ); // end
break;
}
// logfmt( FLOG_MAX, "BP, *c2=%s, c=%s", c2, c );
c2--; *c2 = 0; c2+=2;
// logfmt( FLOG_MAX, "Looking at '%s'", c );
if ( maxlevel>1 ) // recursive call needed
{
// char *newbuf = new char[ c2-b1 ];
// memcpy( newbuf, b1, c2-b1-1 );
// newbuf[ c2-b1-1 ] = 0;
// LOG( "Recursive call", LOG_MAX );
c = RFormBuffer( c, listname, listi );
// delete newbuf;
}
// resolve result which should have no recursive variables
// LOG( "BP", LOG_MAX );
c1 = c2;
// char var[20000];
if (c[0]) // non-empty variable
{
// Let's see if a special command is given
if ( c[0] == '#' )
{
regmatch_t match[2*10];
regex_t compiled;
if ( !regall( "^#include file=\"([[:alnum:][:punct:] ]+)\"$", c, 2, match ) )
{
char fname[50];
int len = match[1].rm_eo-match[1].rm_so;
if ( len>=sizeof(fname) )
len = sizeof(fname)-1; // to be safe
strncpy( fname, &c[ match[1].rm_so ], len );
fname[ len ] = 0;
logfmt( FLOG_MAX, "Including file '%s'", fname );
char filename[100];
snprintf( filename, sizeof(filename), TMPL_PREFIX"/%s", fname );
char * tt = FormFile( filename );
cur = Add( cur, tt, strlen(tt) );
delete tt;
}
else
if ( !regall( "^#field_([[:alpha:]]+)[[:space:]]*\\([[:space:]]*([[:alnum:]_]+)[[:space:]]*,[[:space:]]*\"(.*)\"[[:space:]]*,[[:space:]]*([[:digit:]]+)[[:space:]]*,[[:space:]]*([[:digit:]]+)[[:space:]]*\\)[[:space:];]*$", c, 6, match ) )
{
char name[50], description[200], size[10], maxlen[10], type[20];
strnsafecpy( type, c+match[1].rm_so, match[1].rm_eo-match[1].rm_so, sizeof(type) );
strnsafecpy( name, c+match[2].rm_so, match[2].rm_eo-match[2].rm_so, sizeof(name) );
strnsafecpy( description, c+match[3].rm_so, match[3].rm_eo-match[3].rm_so, sizeof(description) );
strnsafecpy( size, c+match[4].rm_so, match[4].rm_eo-match[4].rm_so, sizeof(size) );
strnsafecpy( maxlen, c+match[5].rm_so, match[5].rm_eo-match[5].rm_so, sizeof(maxlen) );
LetStr( "__func_type", type );
LetStr( "__func_name", name );
LetStr( "__func_description", description );
LetStr( "__func_size", size );
LetStr( "__func_maxlen", maxlen );
logfmt( FLOG_MAX, "field_%s( %s, %s, %s, %s )", type, name, description, size, maxlen );
char filename[100];
snprintf( filename, sizeof(filename), TMPL_PREFIX"/%s", "field_text.func" );
char * tt = FormFile( filename );
cur = Add( cur, tt, strlen(tt) );
delete tt;
}
if ( regcomp( &compiled, "^#global file=\"([[:alnum:][:punct:] ]+)\"$", REG_EXTENDED ) != 0 )
{
logfmt( logWARNING, "regcomp returned non-0, ignoring command" );
}
else
{
size_t r = regexec( &compiled, c, 2, match, 0 );
if (r)
;
// { logfmt( logWARNING, "Command detected, but no match" ); }
else
{
char fname[50];
int len = match[1].rm_eo-match[1].rm_so;
if ( len>=sizeof(fname) )
len = sizeof(fname)-1; // to be safe
strncpy( fname, &c[ match[1].rm_so ], len );
fname[ len ] = 0;
GlobalTemplate( fname );
ParseGlobalTemplate();
}
}
regfree( &compiled );
}
else
// if (false)
if ( c[0]=='\\' ) // talking lists now
{
//logfmt( FLOG_MAX, "talking lists now" );
char listname[50];
// strsafecpy( listname, c+1, sizeof(listname) );
int len = strcspn( c+1, " }" );
strnsafecpy( listname, c+1, len, sizeof(listname) );
// Locate the list in the form object
int j;
for (j=0; j<nlists; j++)
if ( strcasecmp( lists[j]->listname, listname )==0 ) break;
if (j==nlists)
{
// logfmt( logWARNING, "List '%s' not found in form object", listname );
// continue;
}
else
logfmt( FLOG_MAX, "Processing list %s[%d]", listname, lists[j]->n );
// logfmt( FLOG_MAX, "c -> '%s'", c );
bool only_if_present = *(c+1+len) != 0;
// logfmt( FLOG_MAX, "only_if_present = '%d'", only_if_present );
c += strlen(c)+2; // set c to after {{\list 1}} // ???? = c2
// crash ^^^
// c1++;
char temp[100], temp1[100];
snprintf( temp, sizeof(temp), "{{/%s}}", listname );
char * listend = strcasestr( c, temp ); // c1
if (!listend)
{
logfmt( logWARNING, "End of list '%s' not found", temp );
continue;
// fprintf(fout, c1); // end
// break;
}
*listend = 0;
c1 = listend + strlen(temp); // point to after the list closing command
// is there an 'else' section ?? {{//list}}
snprintf( temp, sizeof(temp), "{{//%s}}", listname );
char * celse = strcasestr( c1, temp );
// 06-16-2002
snprintf( temp1, sizeof(temp1), "{{\\%s", listname );
char * cnextinst = strcasestr( c1, temp1 );
if ( cnextinst && (cnextinst<celse) ) // 'else' section belongs to the next occurence of the list
celse = NULL;
// end 06-16-2002
if ( only_if_present && j<nlists && !lists[j]->n )
{
if (!celse) continue;
*celse = 0;
char * tt = RFormBuffer( c1 );
cur = Add( cur, tt, strlen(tt) );
delete tt;
c1 = celse + strlen(temp);
continue;
}
if (celse) c1 = celse + strlen(temp);
// if there is no such list drop it
if ( j==nlists )
{
logfmt( FLOG_MAX, "List '%s' not found in form object. Skipping...", listname );
continue;
}
// now parse
char * c2;
// Skip all child lists before {{...}}
c2 = strstr( c, "{{\\" );
char * c3 = strstr( c, "{{...}}" );
if ( c2 && c3 && c2<c3 )
{
c2 += 3;
char skiplist[30];
int n = strcspn( c2, " }" );
if (n<sizeof(skiplist))
{
strncpy( skiplist, c2, n );
skiplist[n] = 0;
logfmt( FLOG_MAX, "Childlist '%s'. Skip.", skiplist );
char temp[40];
snprintf( temp, sizeof(temp), "{{/%s}}", skiplist );
// logfmt( FLOG_MAX, "Looking for '%s'", temp );
c2 = strcasestr( c2, temp );
if (c2)
c2 += n+5;
// logfmt( FLOG_MAX, "Continuing at '%s'", c2 );
}
}
else
c2 = c;
if (!c2)
c2 = c;
c2 = strstr( c2, "{{...}}" );
if (!c2) // no elements, list used as a block
{
logfmt( FLOG_MAX, "List '%s' does not contain any {{...}} -> used as a block", listname );
char * tt = RFormBuffer( c );
cur = Add( cur, tt, strlen(tt) );
delete tt;
continue;
}
*c2 = 0;
char * tt = RFormBuffer( c );
cur = Add( cur, tt, strlen(tt) );
delete tt;
c = c2+7;
c2 = strstr( c, "{{/...}}" );
if (!c2) // no element close directive
{
logfmt( logWARNING, "Element close directive for '%s' not found", listname );
char * tt = RFormBuffer( c );
cur = Add( cur, tt, strlen(tt) );
delete tt;
continue; // this is correct
}
*c2 = 0;
//logfmt( FLOG_MAX, "Processing list '%s' 5", listname );
//logfmt( FLOG_MAX, "Calling FormBuffer() for '%s'", c );
for ( int i=0; i< lists[j]->n; i++ )
{
char * ctemp = strdup( c );
if (ctemp)
{
char * tt = RFormBuffer( ctemp, listname, i );
cur = Add( cur, tt, strlen(tt) );
delete tt;
free( ctemp );
}
}
tt = RFormBuffer( c2+8 );
cur = Add( cur, tt, strlen(tt) );
delete tt;
continue;
}
else
{
char * c5;
if (!listname)
{
// logfmt( FLOG_MAX, "Getting variable '%s'", c);
// GetVariable( c, var, sizeof(var) );
// cur = Add( cur, var, strlen(var) );
c5 = GetVariable( c );
if (c5)
{ // 11-03-2002 Parse variable contents recursively
char * temp = strdup( c5 ); // to prevent damage to the buffer
char * c = RFormBuffer( temp );
free( temp ); // 11-03-2002 This stuff rocks da house
cur = Add( cur, c, strlen(c) );
delete c;
}
}
else
{
char buf[100];
snprintf( buf, sizeof(buf), "__list_%s_%d_%s",
listname, listi, c );
// logfmt( FLOG_MAX, "Fetching variable '%s'", buf );
c5 = GetVariable( buf );
if (!c5)
c5 = GetVariable( c );
if (c5)
cur = Add( cur, c5, strlen(c5) );
}
if ( *c1=='/' && *(c1+1)=='\\' && *(c1+2)=='{' )
{
c1 += 2;
GetNextVariable( cur, c1, c, listname, listi );
if (!c5)
{
if ( c5 = GetVariable( c ) )
cur = Add( cur, c5, strlen(c5) );
}
}
}
}
// c1 += 2;
} while ( 1 );
// LOG( "BP3", LOG_MAX );
// PrintList( top );
ULONG len=0; cur = top;
while (cur->text)
{
len += strlen(cur->text);
cur = cur->next;
}
// logfmt( FLOG_MAX, "Allocating %lu bytes", len+1 );
char * ret = new char[len+1];
if (!ret) logfmt( logWARNING, "Not enough memory allocating %lu bytes", len );
cur = top; ULONG pos=0;
TList * prev;
while ( cur && cur->text)
{
// logfmt( FLOG_MAX, "Copying %d chars at %d..", strlen( cur->text ), pos );
memcpy( &ret[pos], cur->text, strlen( cur->text ) );
pos += strlen( cur->text );
delete cur->text;
prev = cur;
cur = cur->next;
delete prev;
}
// LOG( "BP5", LOG_MAX );
ret[pos] = 0;
// Fold();
return ret;
}
char * C_CGI_Form::FormBuffer( char * buf )
{
char * ret;
char * c = strdup( buf );
ret = RFormBuffer( c );
free( c );
return ret;
}
void C_CGI_Form::ParseGlobalTemplate( char * fname /*= NULL*/ )
{
char * global_template = fname?fname:this->global_template;
logfmt( FLOG_MAX, "ParseGlobalTemplate( \"%s\" )", global_template );
struct stat stats;
if ( stat(global_template, &stats)==-1 )
{
logfmt( FLOG_MAX, "stat() error: %s, '%s'", strerror(errno), global_template );
return;
}
char * buf = (char *)malloc(stats.st_size+1);
if (!buf)
{
logfmt( logERROR, "Could not allocate %d bytes for global template %s", stats.st_size+1, global_template );
return;
}
FILE * f = fopen( global_template, "r" );
if (!f)
{
logfmt( logERROR, "Could not read global template '%s'", global_template );
return;
}
fread( buf, 1, stats.st_size, f );
buf[stats.st_size] = 0;
fclose( f );
int i;
char s1[30], s2[30], *c1, *c2;
for (i=1; 1; i++ )
{
snprintf( s1, sizeof(s1), "<!--section%d-->", i );
snprintf( s2, sizeof(s2), "<!--/section%d-->", i );
c1 = strstr(buf, s1);
c2 = strstr(buf, s2);
if (!c1 || !c2) break;
c1 += strlen(s1);
snprintf( s2, sizeof(s2), "section%d", i );
char * buf = new char[c2-c1+1];
memcpy( buf, c1, c2-c1 );
buf[c2-c1] = 0;
char * temp = RFormBuffer( buf );
delete buf;
LetStr( s2, temp );
free( temp );
// LetStr( s2, c1, c2-c1 );
// logfmt( FLOG_MAX, "%s=%s", s2, GetVariable(s2) );
}
logfmt( FLOG_MAX, "%d sections found", i-1 );
free( buf );
}
bool C_CGI_Form::ParseNewTemplate( char * fname /*= NULL*/ )
// returns false if this seems to be wrong format template
{
char * global_template = fname?fname:this->global_template;
logfmt( FLOG_MAX, "ParseNewTemplate( \"%s\" )", global_template );
struct stat stats;
if ( stat(global_template, &stats)==-1 )
{
// delete filename;
logfmt( FLOG_MAX, "stat() error: %s, '%s'", strerror(errno), global_template );
return true;
}
char * buf = (char *)malloc(stats.st_size+1);
if (!buf)
{
// delete filename;
logfmt( logERROR, "Could not allocate %d bytes for global template %s", stats.st_size+1, global_template );
return true;
}
FILE * f = fopen( global_template, "r" );
// delete filename;
if (!f)
{
logfmt( logERROR, "Could not read global template '%s'", global_template );
return true;
}
fread( buf, 1, stats.st_size, f );
buf[stats.st_size] = 0;
fclose( f );
logfmt( FLOG_MAX, "New template loaded '%s', size=%d bytes", global_template, stats.st_size );
int i;
char name[50], *c1, *c2;
c1 = buf;
if ( c1[0]!='[' )
{
c1 = strstr( c1, "\n[" );
if (c1) c1++;
}
bool result = true;
if ( !c1 )
result = false;
while (c1)
{
c1++;
c2 = strchr( c1, ']' );
strnsafecpy( name, c1, c2-c1, sizeof(name) );
c2++;
c1 = c2+strspn( c2, " \t\r\n" ); // ignore initial spaces
if ( *c1=='[' ) // blank variable
{
LetStr( name, "" );
continue;
}
c2 = strstr( c1, "\n[" );
if (c2)
{
*c2 = 0;
c2++;
}
char * c = (c2?c2:(buf+stats.st_size)) -1;
while ( c>=c1 && strchr( " \t\r\n", *c ) )
{
*c = 0; c--;
}
LetStr( name, c1 = RFormBuffer(c1) );
free( c1 );
// logfmt( FLOG_MAX, "FOUND: %s, len = '%d'", name, strlen(GetVariable(name)) );
c1 = c2;
}
free( buf );
return result;
}
bool C_CGI_Form::Form( FILE * fout )
{
fprintf( fout, "Content-Type: text/html; charset=UTF-8\n\n");
if (global_template) ParseGlobalTemplate();
CTimer timer;
char * c = FormFile( template_file );
logfmt( logINFO, "FormFile() took %.3f sec", timer.elapsed()/1e6 );
logfmt( logINFO, "strlen(c)=%d", strlen(c) );
int r;
if ( r = ferror( fout ) ) logfmt( logWARNING, "ferror() returned %d: %s", r, strerror(r) );
fprintf( fout, "%s", c );
logfmt( FLOG_MAX, "DEBUG" );
if ( r = ferror( fout ) ) logfmt( logWARNING, "ferror() returned %d: %s", r, strerror(r) );
fflush( fout );
logfmt( FLOG_MAX, "DEBUG" );
delete c;
logfmt( logINFO, "fprintf()/fflush() took %.3f sec", timer.elapsed()/1e6 );
return true;
}
bool C_CGI_Form::Form( FILE * fout, char * template_file )
{
char * c = FormFile( template_file );
fprintf( fout, c ); fflush( fout );
delete c;
return true;
}
int C_CGI_Form::GetParam( char name[], char *value, int valuelen, char ** end /*= NULL*/, char * start /*= NULL*/ )
{
// logfmt( FLOG_MAX, "C_CGI_Form::GetParam( name='%s', sz=%d )", name, valuelen );
// printf("C_CGI_Form() on params=%s \n", params);
int result;
char * qs;
if (start)
result = ::GetParam( start, name, value, valuelen, end );
else
{
qs = getenv("QUERY_STRING");
//logfmt( FLOG_MAX, "qs='%s'", qs );
if ( !qs || !(result = ::GetParam( qs, name, value, valuelen, end ) ) )
result = ::GetParam( params, name, value, valuelen, end );
}
// if ( !value[0] )
// logfmt( FLOG_MAX, "GetParam returns '%s'='%s', qs='%s'", name, value, qs );
return result;
}
int C_CGI_Form::GetParamMul( char name[], TList ** list )
{
char value[100];
int r, i=0;
char * qs = params;
logfmt( FLOG_MAX, "params=%s", qs );
// getenv("QUERY_STRING"); if (!qs) qs = params;
char *start = qs, * end;
TList *top=NULL, *cur=NULL, *tmp;
do {
r = GetParam( name, value, sizeof(value), &end, start );
logfmt( FLOG_MAX, "%s[%d]=%s", name, i, value );
start = end;
if (r)
{
tmp = new TList;
tmp->text = strdup( value );
tmp->next = NULL;
if (cur)
{
cur->next = tmp;
cur = cur->next;
}
else
top = cur = tmp;
i++;
}
} while (r);
if (list) *list = top;
return i;
}
int C_CGI_Form::GetCommand( char * commands[], int n )
{
char cmd[30];
cmd[0] = 0;
/* LOG( argv[1], LOG_MAX );
if (argc>1)
{
::GetParam( argv[1], "action", cmd, sizeof(cmd) );
if (cmd[0])
logfmt( FLOG_MAX, "Command given as a parameter: %s", cmd);
}*/
/*
char * qs = getenv("QUERY_STRING");
if (qs)
{
::GetParam( qs, "action", cmd, sizeof(cmd) );
if (cmd[0])
logfmt( FLOG_MAX, "Command given as a parameter: %s", cmd);
}
if ( !cmd[0] )*/
GetParam( "action", cmd, sizeof(cmd) );
if ( !cmd[0] )
{
char * c;
c = strcasestr( params, ".x=" );
if (!c)
return -1;
char * c1 = strchr( c, '&' );
if (!c1) return -1;
c1++;
c = strchr( c1, '.' );
if (!c) return -1;
if (c-c1 < sizeof(cmd) )
strncpy( cmd, c1, c-c1 );
else
return -1;
cmd[c-c1] = 0;
}
//logfmt( FLOG_MAX, "command=%s", cmd); // LOG
int i;
for ( i=0; i<n; i++ )
{
if ( strcasecmp(cmd, commands[i])==0 )
break;
}
if (i==n)
return -1;
return i;
}
int C_CGI_Form::GetScreen( char * screens[], int n, const char * scrs /*= NULL*/ )
{
char cmd[30];
if ( !scrs )
{
char * qs = getenv("QUERY_STRING");
if (qs)
{
::GetParam( qs, "screen", cmd, sizeof(cmd) );
if (cmd[0])
logfmt( FLOG_MAX, "Screen given as a parameter: %s", cmd);
}
if (!cmd[0])
GetParam( "screen", cmd, sizeof(cmd) );
if ( !cmd[0] )
return -1;
}
else
strsafecpy( cmd, scrs, sizeof(scrs) );
int i;
for ( i=0; i<n; i++ )
{
if ( strcasecmp(cmd, screens[i])==0 )
break;
}
if (i==n)
return -1;
return i;
}
void C_CGI_Form::Flag( char * var, char * explanation /*= NULL*/ )
{
char buf[500], s[500];
snprintf( buf, sizeof(buf), "c%s", var );
LetStr( buf, GetVariable("syntax") );
snprintf( buf, sizeof(buf), "err_%s", var );
if ( CGI_FLAG_CLEAR==explanation )
LetStr( buf, "" );
else
LetStrf( buf, "<a href='#' onClick=\"alert('%1$s');return false;\" TABINDEX=-1><img src='/image/gif/point.gif' align=middle border=0 width=10 height=15 alt='%1$s'></a>", explanation?explanation:"Invalid input" );
logfmt( FLOG_MAX, "Flagged %s", buf );
}
void C_CGI_Form::Flag( CGI_Variable * var )
{
if ( var && var->pattern )
Flag( var->name, var->pattern->explanation );
}
void C_CGI_Form::MatchVariable( CGI_Variable * var, bool optional /*= false*/, bool flag_if_mismatch /*= true*/ )
{
char s[500];
char buf[500];
regex_t compiled;
char smatch[500], fc;
unsigned int i;
int n = 0;
ULONG * t = (ULONG*)var->target;
double amount;
// typedef *ULONG PULONG;
// (ULONG *) t[100];
// t = var->target;
if ( var->type != CGI_CHECKBOXLIST && var->type != CGI_CHECKBOXLIST_ARRAY)
{
GetParam( var->name, s, sizeof( s ) );
var->match = true; // Let's not raise hell
strsafecpy( smatch, s, sizeof(smatch) ); // in case it doesn't get filled in
if ( optional && smatch[0]==0 /*&& var->type==CGI_STRING*/ )
var->match = true;
else
{
if ( var->pattern ) // Matching requested?
{
regmatch_t match[2];
if ( regcomp( &compiled, var->pattern->mask, REG_EXTENDED ) != 0 )
{
logfmt( logWARNING, "regcomp returned non-0, assuming a match" );
}
else
{
size_t r = regexec( &compiled, s, 2, match, 0 );
if ( r==0 ) // match
{
int len = match[1].rm_eo-match[1].rm_so;
if ( len>=sizeof(smatch) )
len = sizeof(smatch)-1; // to be safe
strncpy( smatch, &s[ match[1].rm_so ], len );
smatch[ len ] = 0;
}
else
var->match = false;
regfree( &compiled );
}
}
// Too short or too long?
if ( ( var->minlen>=0 && strlen( smatch )<var->minlen ) ||
( var->maxlen>=0 && strlen( smatch )>var->maxlen )
)
var->match = false;
}
LetStr( var->name, smatch );
}
else
var->match = true;
if ( ( var->type==CGI_RADIO || var->type==CGI_RADIO_INT || var->type==CGI_RADIO_INT2 ) && smatch[0]==0 )
var->match = false;
// If match => store it
bool *_bool = (bool*)var->target;
if ( var->match )
{
switch ( var->type )
{
case CGI_STRING:
strsafecpy( (char *)var->target, smatch, var->size );
break;
case CGI_RADIO:
for ( i=0; i<var->nradio; i++ )
if ( strcasecmp( var->radio[i], smatch ) == 0 )
break;
if ( i == var->nradio )
var->match = 0;
else
{
*(unsigned char*)var->target = i;
snprintf( buf, sizeof(buf), "%schecked", smatch );
LetStr( buf, "checked" );
}
break;
case CGI_RADIO_INT:
snprintf( buf, sizeof(buf), "%c%s", var->name[0], smatch );
LetStr( buf, "checked" );
char * endptr;
*(short*)var->target = (short)strtol( smatch, &endptr, 10 );
var->match = smatch[0]!=0 && *endptr==0;
break;
case CGI_RADIO_INT2:
snprintf( buf, sizeof(buf), "%.2s%s", var->name, smatch );
LetStr( buf, "checked" );
*(short*)var->target = (short)strtol( smatch, &endptr, 10 );
var->match = smatch[0]!=0 && *endptr==0;
break;
case CGI_SELECT:
logfmt( FLOG_MAX, "CGI_SELECT" );
memset( var->target, 0, var->size );
*(unsigned short*)var->target = atol( smatch );
if ( var->radio )
fc = (char)*(*(var->radio+0)+0);
else
fc = var->name[0];
snprintf( buf, sizeof(buf), "%c%s", fc, smatch );
LetStr( buf, "selected" );
break;
case CGI_SELECT_LOOKUP:
memset( var->target, 0, var->size );
strsafecpy( (char *)var->target, smatch, var->size );
if ( var->radio )
fc = (char)*(*(var->radio+0)+0);
else
fc = var->name[0];
snprintf( buf, sizeof(buf), "%c%s", fc, smatch );
LetStr( buf, "selected" );
break;
case CGI_CHECKBOX:
// target is a boolean
*_bool = 0==strcasecmp( smatch, "on" );
if ( *_bool )
{
snprintf( buf, sizeof(buf), "%schecked", var->name );
LetStr( buf, "checked" );
}
break;
case CGI_CHECKBOXLIST:
// target is a ULONG 32-bit?
*(ULONG*)var->target = 0;
for (i=0; i<var->maxlen && i<sizeof(ULONG)*8; i++)
{
snprintf( s, sizeof(s), "%s%d", (char*)var->radio[0], i+1 );
GetParam( s, buf, sizeof(buf) );
logfmt( FLOG_MAX, "CHECKBOX_LIST '%s' %s=%s", var->name, s, buf );
if (buf[0])
{
// logfmt( FLOG_MAX, "CGI_CHECKBOXLIST: %d=%s, target=%lu", i+1, buf,
// *(ULONG*)var->target );
*(ULONG*)var->target |= (1<<i);
logfmt( FLOG_MAX, "CGI_CHECKBOXLIST: %d=%s, target=%lu", i+1, buf,
*(ULONG*)var->target );
LetStr( s, "checked" );
}
}
break;
case CGI_CHECKBOXLIST_ARRAY:
// target is a ULONG 32-bit?
// *(ULONG*)var->target = 0;
for (i=0; i<var->maxlen; i++) //&& i<sizeof(ULONG)*8
{
snprintf( s, sizeof(s), "%s%d", (char *)var->radio[0], i );
GetParam( s, buf, sizeof(buf) );
if (buf[0])
{
t[n] = atol( buf ); n++;
// logfmt( FLOG_MAX, "CGI_CHECKBOXLIST: %d=%s, target=%lu", i+1, buf,
// *(ULONG*)var->target );
// *(ULONG*)var->target |= (1<<i);
// logfmt( FLOG_MAX, "CGI_CHECKBOXLIST: %d=%s, target=%lu", i+1, buf,
// *(ULONG*)var->target );
LetStr( s, "checked" );
}
}
t[n] = 0;
if ( n<var->minlen ) // minimum required number of checked boxes
var->match = false;
break;
case CGI_SELECT_MUL:
TList *list, *cur;
GetParamMul( var->name, &list );
//PrintList( list );
cur = list;
for (i=0; cur; i++)
{
if ( var->radio )
if ( *(char*)var->radio==cur->text[0] )
{
t[n] = atol( &cur->text[1] ); n++;
}
else
{
cur = cur->next;
continue;
}
else
{
t[n] = atol( cur->text ); n++;
}
LetStr( cur->text, "selected" );
cur = cur->next;
}
t[n] = 0;
if ( n<var->minlen ) // minimum required number of checked boxes
var->match = false;
cur = list;
DestroyList( list );
break;
case CGI_LONG:
// target is a 32-bit long
*(long*)var->target = strtol( smatch, &endptr, 10 );
var->match = smatch[0]!=0 && *endptr==0;
break;
case CGI_FLOAT:
*(float*)var->target = strtod( smatch, &endptr );
var->match = smatch[0]!=0 && *endptr==0;
break;
case CGI_AMOUNT:
amount = strtod( smatch, &endptr );
var->match = smatch[0]!=0 && *endptr==0;;
*(unsigned long*)var->target = (ULONG)(amount*100.0+0.5);
break;
default: ; // do not let this happen, ok?
} // switch
}
// else
if ( !var->match )
{
if ( var->pattern /*&& !optional*/ && flag_if_mismatch )
{
Flag( var );
}
// PrintVars();
}
if ( optional && !var->match )
{
logfmt( FLOG_MAX, "Resetting '%s'", var->name );
memset( var->target, 0xFF, var->size );
if ( var->type== CGI_SELECT )
logfmt( FLOG_MAX, "%s, smatch=%s", var->name, smatch );
// Clear the flag if blank
if ( !smatch[0] )
Flag( var->name, CGI_FLAG_CLEAR );
}
if ( optional && var->type!=CGI_STRING )
var->match = true;
// logfmt( FLOG_MAX, "MatchVariable(): %s=%s, match=%s", var->name, smatch, var->match?"true":"false" );
}
void C_CGI_Form::SetVariable( CGI_Variable * var )
{
char buf[100], s[100];
int i;
switch ( var->type )
{
case CGI_STRING:
LetStr( var->name, (char*)var->target );
break;
case CGI_RADIO:
snprintf( buf, sizeof(buf), "%schecked", var->radio[ *(unsigned char *)var->target ] );
LetStr( buf, "checked" );
break;
case CGI_RADIO_INT:
snprintf( buf, sizeof(buf), "%c%d", var->name[0], *(short *)var->target );
LetStr( buf, "checked" );
break;
case CGI_RADIO_INT2:
snprintf( buf, sizeof(buf), "%.2s%d", var->name, *(short*)var->target );
LetStr( buf, "checked" );
break;
case CGI_SELECT:
snprintf( buf, sizeof(buf), "%c%d", var->name[0], *(unsigned short*)var->target );
LetStr( buf, "selected" );
break;
case CGI_SELECT_LOOKUP:
snprintf( buf, sizeof(buf), "%c%s",
var->radio ? (char)*(*(var->radio+0)+0) : var->name[0],
(char *)var->target );
LetStr( buf, "selected" );
break;
case CGI_CHECKBOX:
// target is a boolean
if (var->target)
{
snprintf( buf, sizeof(buf), "%schecked", var->name );
LetStr( buf, "checked" );
}
break;
case CGI_CHECKBOXLIST:
// target is a ULONG 32-bit?
for (i=0; i<var->maxlen && i<sizeof(ULONG)*8; i++)
{
if (*(ULONG*)var->target & 1<<i)
{
snprintf( s, sizeof(s), "%s%d", (char *)var->radio[0], i+1 );
LetStr( s, "checked" );
}
}
break;
case CGI_LONG:
// target is a 32-bit long
snprintf( s, sizeof(s), "%lu", *(ULONG*)var->target );
LetStr( var->name, s );
break;
case CGI_FLOAT:
LetStrf( var->name, "%.2f", *(float*)var->target );
break;
case CGI_AMOUNT:
// target is a 32-bit long
snprintf( s, sizeof(s), "%.2f", (*(ULONG*)var->target)/100.0 );
LetStr( var->name, s );
break;
default: ; // do not let this happen, ok?
}// switch
}
void C_CGI_Form::Email( char * fname, char * from/*=NULL*/ )
{
char name[100], headers[100];
snprintf( name, sizeof(name), EMAIL_PREFIX"/%s", fname );
char * c = FormFile( name );
logfmt( FLOG_MAX, "Template parsed: %s", name );
// logfmt( FLOG_MAX, "body=%s", c );
// Strip 8-bit content
int len = strlen( c );
for ( int i=0; i<len; i++ )
c[i] &= 0x7F;
// snprintf( headers, sizeof(headers), "X-EmailID: %s\n", fname );
// --
bool test = false;
SMTP2(CfgReadChar("mailsend.server"),
(from != NULL && strlen(from)>5) ? from : CfgReadChar( "mailsend.from" ), // From: "support@chiefsoft.com"
GetVariable("email"),
c,
CfgReadChar( "mailsend.domain" ),
CfgReadChar( "mailsend.user" ),
CfgReadChar( "mailsend.pass" ),
CfgReadChar( "mailsend.name" ));
free(c);
}
CGIList::CGIList( C_CGI_Form * _form, char * name )
// Instantiates a CGI_List object
// _form points to the parent form object
// name - name of the list as used in template
{
// logfmt( FLOG_MAX, "CGIList::CGIList()" );
form = _form; n = 0; listname = strdup(name);
if (!listname)
logfmt( FLOG_MAX, "Out of memory" );
listn = form->nlists;
form->lists[ listn ] = this;
form->nlists++;
// logfmt( FLOG_MAX, "/CGIList::CGIList(), form->lists[%d]='%s'", form->nlists-1, listname );
};
void CGIList::LetStrf( char * var, const char * format, ... )
{
char buf[100];
snprintf( buf, sizeof(buf), "__list_%s_%d_%s", listname, n, var );
va_list ap;
va_start( ap, format );
form->vLetStrf( buf, format, ap );
va_end( ap );
}
void CGIList::LetStr( char * var, char * value )
{
char buf[100];
snprintf( buf, sizeof(buf), "__list_%s_%d_%s", listname, n, var );
form->LetStr( buf, value );
}
void CGIList::LetStr( char * var, const char * format, ... )
{
char buf[100];
snprintf( buf, sizeof(buf), "__list_%s_%d_%s", listname, n, var );
char tmp[1000];
va_list ap;
va_start( ap, format );
vsnprintf( tmp, sizeof(tmp), format, ap );
va_end( ap );
form->LetStr( buf, tmp );
}
void CGIList::LetInt16( char * var, const int value )
{
char buf[100];
snprintf( buf, sizeof(buf), "__list_%s_%d_%s", listname, n, var );
form->LetInt16( buf, value );
// logfmt( FLOG_MAX, "Setting %s=%d", buf, value );
}
char * CGIList::GetVariable( char * var, char * result, int size )
{
char buf[100];
snprintf( buf, sizeof(buf), "__list_%s_%d_%s", listname, n, var );
return form->GetVariable( buf, result, size );
}
void CInputError::Log()
{
L_Variables * v;
v = this->var_top;
if ( !v ) return;
while ( v )
{
logfmt( FLOG_MAX, "%d: %s = %s", v->opts, v->name, v->value );
v = v->next;
}
}
void CInputError::Add( bool text, const char * var, const char * explanation, ... )
{
char *tmp;
int size;
va_list ap;
va_start( ap, explanation );
size = vsnprintf( NULL, 0, explanation, ap ) + 1;
tmp = (char*)malloc( size );
vsnprintf( tmp, size, explanation, ap );
va_end( ap );
L_Variables * v;
v = FindVariable( var, true );
if (v->value)
free( v->value );
v->value = strdup( tmp );
v->opts = text;
free( tmp );
}
char *CInputError::Get( const char * var, bool *text )
{
L_Variables * v;
v = FindVariable( var );
if ( !v )
return NULL;
else
{
*text = v->opts;
return v->value;
}
}
void C_CGI_Form::ClearVariable( CGI_Variable var )
{
char tmp[200];
LetStr( var.name, "" );
snprintf( tmp, sizeof(tmp), "err_%s", var.name );
LetStr( tmp, "" );
}