A working Windows CGI Program
/*---------------------------------------------
WINCGI.CPP
(C) 1994 PHD Computer Consultants Ltd
27 October 1994: Chris Cant
---------------------------------------------*/
#include <windows.h>
#include <fcntl.h>
#include <io.h>
#include <sys\types.h>
#include <sys\stat.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <ctype.h>
/////////////////////////////////////////////////////////////////////////////
typedef char __huge *HPSTR;
/////////////////////////////////////////////////////////////////////////////
void LogError( char*, LPSTR);
void HandleComments( int);
void HandleOrder( int);
void HandleUnrecognised( int);
void EnumerateKeys( char* INIfile, int hOF);
/////////////////////////////////////////////////////////////////////////////
int DoTinyMessageLoop( HANDLE, HANDLE, int);
/////////////////////////////////////////////////////////////////////////////
const short MAXARG = 10;
char* argv[MAXARG];
int argc = 0;
char* pszCmdLine = NULL;
int GetArgs( LPSTR lpszCmdLine)
{
int len = _fstrlen( lpszCmdLine);
char* pszCmdLine = new char[len+1];
_fstrcpy( pszCmdLine, lpszCmdLine);
argc = 1;
argv[0] = NULL;
char* pCmdLine = pszCmdLine;
while( *pCmdLine!='\0')
{
char ch;
if( argc==MAXARG) break;
argv[argc++] = pCmdLine;
do ch=*++pCmdLine;
while( ch!=' ' && ch!='\0');
if( ch=='\0') break;
*pCmdLine++ = '\0';
do ch=*pCmdLine++;
while( ch==' ' && ch!='\0');
pCmdLine--;
}
return argc;
}
/////////////////////////////////////////////////////////////////////////////
// WinMain called with parameters <cgi-data-file> <content-file> <output-file>
<url-args>
static char* FormComments = "/Comments";
static char* FormOrder = "/Order";
int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)
{
/////////////////////////////////////////////////////////////////////////
// Get arguments
GetArgs( lpszCmdLine);
if( argc<4 || argc>5)
{
LogError( "Server calling with wrong number of parameters", lpszCmdLine);
return DoTinyMessageLoop( hInstance, hPrevInstance, nCmdShow);
}
/////////////////////////////////////////////////////////////////////////
// Open output file
char OutputFile[80];
strncpy( OutputFile, argv[3], 79);
OutputFile[79] = '\0';
int hOutputFile = _open( OutputFile, _O_TEXT|_O_WRONLY|_O_CREAT|_O_TRUNC, _S_IREAD|_S_IWRITE);
if( hOutputFile==-1)
{
LogError( "Could create output file", lpszCmdLine);
return DoTinyMessageLoop( hInstance, hPrevInstance, nCmdShow);
}
/////////////////////////////////////////////////////////////////////////
// Get logical path: see what to do
char Buf[80];
GetPrivateProfileString( "CGI", "Logical path", "", Buf, sizeof( Buf), argv[1]);
if( strnicmp( Buf, FormComments, strlen( FormComments))==0)
HandleComments( hOutputFile);
else if( strnicmp( Buf, FormOrder, strlen( FormOrder))==0)
HandleOrder( hOutputFile);
else
HandleUnrecognised( hOutputFile);
/////////////////////////////////////////////////////////////////////////
return DoTinyMessageLoop( hInstance, hPrevInstance, nCmdShow);
}
/////////////////////////////////////////////////////////////////////////////
// DoTinyMessageLoop: Necessary to allow httpd to sync with us
HANDLE hInst;
long FAR PASCAL _export WndProc (HWND, UINT, UINT, LONG);
int DoTinyMessageLoop( HANDLE hInstance, HANDLE hPrevInstance, int nCmdShow)
{
hInst = hInstance;
static char szAppName[] = "wincgi";
if (!hPrevInstance)
{
WNDCLASS wndclass;
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = GetStockObject (WHITE_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
RegisterClass (&wndclass);
}
HWND hwnd = CreateWindow (szAppName, szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL);
// ShowWindow (hwnd, nCmdShow);
// UpdateWindow (hwnd);
MSG msg;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return msg.wParam;
}
/////////////////////////////////////////////////////////////////////////////
#define ID_TIMER 1
long FAR PASCAL _export WndProc (HWND hwnd, UINT message, UINT wParam, LONG lParam)
{
static UINT timer = 0;
switch (message)
{
case WM_CREATE:
// Set timer for 50ms
SetTimer( hwnd, ID_TIMER, 50, (TIMERPROC)NULL);
return 0;
case WM_TIMER:
// Timer gone off: die
KillTimer( hwnd, ID_TIMER);
PostMessage( hwnd, WM_CLOSE, NULL, NULL);
return 0;
case WM_DESTROY:
PostQuitMessage (0);
return 0;
}
return DefWindowProc (hwnd, message, wParam, lParam);
}
/////////////////////////////////////////////////////////////////////////////
// LogError: Log an error message, together with given command line
void LogError( char* ErrorMsg, LPSTR lpszCmdLine)
{
// PlaySound( "C:\\WINDOWS\\DING.WAV");
int hLogFile = _open( "FAXBACK.LOG", _O_WRONLY|_O_TEXT|_O_APPEND|_O_CREAT, _S_IREAD|_S_IWRITE);
if( hLogFile==-1) return;
char HeaderBuf[50];
time_t now;
time( &now);
wsprintf( HeaderBuf, "--- WINCGI error on %s", (LPSTR)ctime( &now));
_write( hLogFile, HeaderBuf, strlen( HeaderBuf));
int len = strlen( ErrorMsg) + _fstrlen( lpszCmdLine);
char* MsgBuf = new char[strlen( ErrorMsg)+_fstrlen( lpszCmdLine)+50];
wsprintf( MsgBuf, "Error: %s\nCommand line: %s\n\n", (LPSTR)ErrorMsg, lpszCmdLine);
_write( hLogFile, MsgBuf, strlen( MsgBuf));
_close( hLogFile);
delete MsgBuf;
}
/////////////////////////////////////////////////////////////////////////////
// DecodeValue: Decode a huge value string: + to space, %XX to char code
void DecodeValue( HPSTR hpValue, long& length)
{
HPSTR hpDest = hpValue;
HPSTR hpSrc = hpValue;
for (long srcCountUp=0; srcCountUp<length; srcCountUp++)
{
char ch = *hpSrc++;
if( ch=='+')
{
*hpDest++ = ' ';
continue;
}
if( ch=='%')
{
ch = *hpSrc++;
char ch1 = toupper(ch);
ch = *hpSrc++;
char ch2 = toupper(ch);
if( isxdigit( ch1) && isxdigit( ch2))
{
int dig1 = (ch1<='9') ? ch1-'0' : ch1-'A'+10;
int dig2 = (ch2<='9') ? ch2-'0' : ch2-'A'+10;
*hpDest++ = (dig1<<4)+dig2;
length -= 2;
continue;
}
hpSrc -= 3;
ch = *hpSrc++;
}
*hpDest++ = ch;
}
}
/////////////////////////////////////////////////////////////////////////////
// ReadBuf: Read a file into a huge buffer, 256 bytes at a time
const short ReadBlockSize = 256;
void ReadBuf( int hF, HPSTR hpValue, long len)
{
long txd = 0L;
char block[ReadBlockSize];
while( txd<len)
{
int totx = ReadBlockSize;
if( txd+(long)totx > len)
totx = (int)(len-txd);
_read( hF, block, totx);
_fstrncpy( hpValue+txd, block, totx);
txd += totx;
}
}
/////////////////////////////////////////////////////////////////////////////
// GetFormValue: Get a value for a key, from one of the CGI data file sections.
// Return a huge pointer.
HPSTR GetFormValue( char* INIfile, char* ContFile, char* KeyName, long& count)
{
char INIline[300];
// Is key in LITERAL section?
count = GetPrivateProfileString( "Form Literal", KeyName, "\x1A", INIline, 300, INIfile);
if( *INIline!='\x1A')
{
// Copy INI string into value string
short len = strlen( INIline);
HPSTR hpValue = new __huge char[len+1];
_fstrncpy( hpValue, INIline, len+1);
return hpValue;
}
// Is key in EXTERNAL section?
GetPrivateProfileString( "Form External", KeyName, "\x1A", INIline, 300, INIfile);
if( *INIline!='\x1A')
{
char* pLen = strchr( INIline, ' ');
if( pLen)
{
*pLen++ = '\0';
int hExt = _open( INIline, _O_RDONLY|_O_BINARY);
if( hExt!=-1)
{
// Read external file into value string
unsigned int len = atoi( pLen);
HPSTR hpValue = new __huge char[len+1];
ReadBuf( hExt, hpValue, len);
hpValue[len] = '\0';
_close( hExt);
count = len;
return hpValue;
}
}
}
// Is key in HUGE section?
GetPrivateProfileString( "Form Huge", KeyName, "\x1A", INIline, 300, INIfile);
if( *INIline!='\x1A')
{
char *pLen = strchr( INIline, ' ');
if( pLen)
{
// Open raw content file
*pLen++ = '\0';
long offset = atol( INIline);
long len = atol( pLen);
int hExt = _open( ContFile, _O_RDONLY|_O_BINARY);
if( hExt!=-1)
{
// Read content file part into value string
_lseek( hExt, offset, SEEK_SET);
HPSTR hpValue = new __huge char[len+1];
ReadBuf( hExt, hpValue, len);
hpValue[len] = '\0';
_close( hExt);
// Decode from raw form
DecodeValue( hpValue, len);
count = len;
return hpValue;
}
}
}
count = 0;
return NULL;
}
/////////////////////////////////////////////////////////////////////////////
// TidyMultiLine: Tidy a TEXTAREA multi-line string so that \r chars removed.
void TidyMultiLine( HPSTR hpValue, long& length)
{
char __huge *hpDest = hpValue;
char __huge *hpSrc = hpValue;
long skipped = 0L;
for(long srcIndex=0; srcIndex<length; srcIndex++)
{
char ch = *hpSrc++;
if( ch=='\r')
skipped++;
else
*hpDest++ = ch;
}
length -= skipped;
}
/////////////////////////////////////////////////////////////////////////////
// HandleComments: Just act as if ignored for just now
void HandleComments( int hOF)
{
HandleUnrecognised( hOF);
}
/////////////////////////////////////////////////////////////////////////////
// HandleOrder: Check order details, build reply output and store order
void StoreOrder( HPSTR, HPSTR, HPSTR, HPSTR, HPSTR, HPSTR);
void HandleOrder( int hOF)
{
char* pCF = "Content-type: text/html\n\n<HTML><HEAD>";
int CFlen = strlen( pCF);
_write( hOF, pCF, CFlen);
pCF = "<TITLE>WINCGI Order</TITLE></HEAD>\n<BODY><H1>WINCGI Order</H1><P>\n";
CFlen = strlen( pCF);
_write( hOF, pCF, CFlen);
long ProdLen, NameLen, FaxLen, CardLen, ContactLen, AddrLen;
HPSTR ProductCode = GetFormValue( argv[1], argv[2], "ProductCode", ProdLen);
HPSTR Name = GetFormValue( argv[1], argv[2], "Name", NameLen);
HPSTR Fax = GetFormValue( argv[1], argv[2], "Fax", FaxLen);
HPSTR Card = GetFormValue( argv[1], argv[2], "Card", CardLen);
HPSTR Contact = GetFormValue( argv[1], argv[2], "Contact", ContactLen);
HPSTR Address = GetFormValue( argv[1], argv[2], "Address", AddrLen);
if( NameLen==0L || CardLen==0L || AddrLen==0L)
{
pCF = "<H2>Sorry, you must enter a name, a card number and an address</H2>\n";
CFlen = strlen( pCF);
_write( hOF, pCF, CFlen);
}
else
{
TidyMultiLine( Address, AddrLen);
Address[AddrLen] = '\0';
StoreOrder( ProductCode, Name, Fax, Card, Contact, Address);
char* Msg = new char[ProdLen+NameLen+CardLen+ContactLen+AddrLen+50];
wsprintf( Msg, "<H2>Thanks for your order <B>%s</B></H2>\n", Name);
CFlen = strlen( Msg);
_write( hOF, Msg, CFlen);
wsprintf( Msg, "You have ordered %s<P>\n", ProductCode);
CFlen = strlen( Msg);
_write( hOF, Msg, CFlen);
if( ContactLen>0L)
{
wsprintf( Msg, "Your contact phone/email is <I>%s</I><P>\n", Contact);
CFlen = strlen( Msg);
_write( hOF, Msg, CFlen);
}
wsprintf( Msg, "<HR>\n<H2>Billing Details</H2>\nName: \
<B>%s</B><P>\nCard: <B>%s</B><P>\nAddress: <B>%s</B><P>\n", Name, Card, Address);
CFlen = strlen( Msg);
_write( hOF, Msg, CFlen);
if( FaxLen>0)
{
wsprintf( Msg, "<HR><H2>Sending confirmation fax to <I>%s</I>.</H2>\n", Fax);
CFlen = strlen( Msg);
_write( hOF, Msg, CFlen);
}
delete Msg;
}
pCF = "<HR><A HREF=/phd//>Return to order menu</A>\n</BODY></HTML>\n";
CFlen = strlen( pCF);
_write( hOF, pCF, CFlen);
_close( hOF);
if( ProductCode) delete ProductCode;
if( Name) delete Name;
if( Fax) delete Fax;
if( Card) delete Card;
if( Contact) delete Contact;
if( Address) delete Address;
}
/////////////////////////////////////////////////////////////////////////////
// StoreOrder: Store away the received order
void StoreOrder( HPSTR ProductCode, HPSTR Name, HPSTR Fax, HPSTR Card, HPSTR Contact, HPSTR Address)
{
// Store in a file somewhere
}
/////////////////////////////////////////////////////////////////////////////
// HandleUnrecognised: Handle an unrecognised form request:
// Echo the keys as HTML to user
void HandleUnrecognised( int hOF)
{
char* pCF = "Content-type: text/html\n\n<HTML><HEAD><TITLE>Unrecognised \
request</TITLE></HEAD>\n<BODY><H1>Unrecognised request</H1><P>\n";
int CFlen = strlen( pCF);
_write( hOF, pCF, CFlen);
EnumerateKeys( argv[1], hOF);
pCF = "<HR><A HREF=/phd/>Return to main menu</A>\n</BODY></HTML>\n";
CFlen = strlen( pCF);
_write( hOF, pCF, CFlen);
_close( hOF);
}
/////////////////////////////////////////////////////////////////////////////
// EnumerateKeys: List the Query String and Logical Path , together
// all the keys from each Form section as HTML
enum LOCATION { LITERAL, EXTERNAL, HUGE, };
void EnumerateFormKeys( char* INIfile, int hOF, LOCATION);
void EnumerateKeys( char* INIfile, int hOF)
{
/////////////////////////////////////////////////////////////////////////
char* pCF = "Query String=";
int CFlen = strlen( pCF);
_write( hOF, pCF, CFlen);
char Query[80];
GetPrivateProfileString( "CGI", "Query String", "", Query, sizeof( Query), INIfile);
CFlen = strlen( Query);
_write( hOF, Query, CFlen);
pCF = "<P>\nLogical path=";
CFlen = strlen( pCF);
_write( hOF, pCF, CFlen);
GetPrivateProfileString( "CGI", "Logical path", "", Query, sizeof( Query), INIfile);
CFlen = strlen( Query);
_write( hOF, Query, CFlen);
pCF = "<P><P>\n";
CFlen = strlen( pCF);
_write( hOF, pCF, CFlen);
/////////////////////////////////////////////////////////////////////////
EnumerateFormKeys( INIfile, hOF, LITERAL);
EnumerateFormKeys( INIfile, hOF, EXTERNAL);
EnumerateFormKeys( INIfile, hOF, HUGE);
}
/////////////////////////////////////////////////////////////////////////////
// EnumerateKeys: Enumerate the keys in a form section as HTML
void EnumerateFormKeys( char* INIfile, int hOF, LOCATION location)
{
// Allocate a buffer for the entries
HLOCAL hBuf = LocalAlloc(LMEM_MOVEABLE, 1024);
char* pszBuf = (char*)LocalLock( hBuf);
// Retrieve all the entries in the one of the three sections
char* SectionName;
char* pHeader;
switch( location)
{
case LITERAL:
SectionName = "Form Literal";
pHeader = "<H2>LITERAL</H2>\n";
GetPrivateProfileString( SectionName, NULL, "", pszBuf, 1024, INIfile);
break;
case EXTERNAL:
SectionName = "Form External";
pHeader = "<H2>EXTERNAL</H2>\n";
GetPrivateProfileString( SectionName, NULL, "", pszBuf, 1024, INIfile);
break;
case HUGE:
SectionName = "Form Huge";
pHeader = "<H2>HUGE</H2>\n";
GetPrivateProfileString( SectionName, NULL, "", pszBuf, 1024, INIfile);
}
_write( hOF, pHeader, strlen( pHeader));
// Retrieve the string for each entry, until
// reaching the double null character.
for (char* pszKey = pszBuf; *pszKey != '\0'; pszKey += strlen(pszKey) + 1)
{
// Retrieve the value for each entry in the buffer
char szVal[80];
GetPrivateProfileString( SectionName, pszKey, "not found", szVal, sizeof(szVal), INIfile);
// Write each key=value string as HTML
char szMsg[80];
if( strlen( pszKey)+strlen(szVal) < 70)
{
wsprintf( szMsg, "%s = %s<P>\n", (LPSTR)pszKey, (LPSTR)szVal);
_write( hOF, szMsg, strlen( szMsg));
}
else
{
_write( hOF, pszKey, strlen( pszKey));
_write( hOF, "<P>\n", 4);
}
// For external keys, write the external value string as HTML
if( location==EXTERNAL)
{
char *pLen = strchr( szVal, ' ');
if( pLen)
{
*pLen++ = '\0';
int hExt = _open( szVal, _O_RDONLY|_O_BINARY);
if( hExt!=-1)
{
unsigned int len = atoi( pLen);
char* pBuf = new char[len+1];
_read( hExt, pBuf, len);
_close( hExt);
_write( hOF, pBuf, len);
_write( hOF, "<P>\n", 4);
delete pBuf;
}
}
}
}
LocalUnlock( hBuf);
LocalFree( hBuf);
}
/////////////////////////////////////////////////////////////////////////////
Return to Web Forms