home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / ie4 / ieak4.cab / signup.cpp < prev    next >
C/C++ Source or Header  |  1998-02-09  |  13KB  |  486 lines

  1. /******************************************************************************\
  2.  *
  3.  *    Copyright (C) 1996 Microsoft Corporation
  4.  *    All rights reserved.
  5.  *
  6.  ******************************************************************************
  7.  *
  8.  *    Program: Signup.cpp
  9.  *
  10.  *    Purpose: Little CGI applet to handle ISP signup forms
  11.  *
  12. \******************************************************************************/
  13.  
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <ctype.h>
  18. #include <time.h>        // time f/n's
  19. #include "windows.h"    // Get/WriteProfile()
  20. #include "cgiutil.h"
  21. #include "random.h"
  22.  
  23. /******************************************************************************\
  24.  *
  25.  *    Main code starts here...
  26.  *
  27. \******************************************************************************/
  28.  
  29. /* Function */ int __cdecl main ( int argc, char *argv[] )
  30.  
  31. {
  32.     // fwd refs
  33.     int FormtoDB() ;
  34.     void ProcessCurrent() ;
  35.     void ProcessNext() ;
  36.  
  37.     // Turn buffering off for stdin/stdout
  38.     setvbuf ( stdin, NULL, _IONBF, 0 ) ;
  39.     setvbuf ( stdout, NULL, _IONBF, 0 ) ;
  40.  
  41.     ParseCGI() ;
  42.     if ( !FormtoDB() )    // validate and save form vars
  43.     {
  44.         ProcessCurrent() ;    // repump the current doc out
  45.     }
  46.     else
  47.     {
  48.         ProcessNext() ;    // pump the next doc out
  49.     }
  50.     return 0 ;        // done!
  51. }
  52.  
  53. /******************************************************************************\
  54.  *
  55.  *    ISP Customization Section
  56.  *
  57.  *    The code in the following section needs to be customized by the ISP for
  58.  *    their specific database keywords and database handlers. Please see the
  59.  *    IAK documentation for more information on implementing these.
  60.  *
  61. \******************************************************************************/
  62.  
  63. static char Session[25]={0} ;    // global session handle string
  64. static char Session1[25]={0} ;    // global session handle string
  65.  
  66. // Data name definitions
  67. static char *DataName[] =
  68. {
  69.     "fname", "lname", "addr1", "addr2", "city", "state", "zip",
  70.     "areac", "exch", "last4", "homebiz",
  71.     "ccard", "cardnum", "cardexp", "cardname",
  72.     "username", "passw", "passconf",
  73.     NULL
  74. } ;
  75.  
  76. static char *PairName[2][4] =
  77. {
  78.     { "homebiz", "home", "business", NULL },
  79.     { NULL, NULL, NULL, NULL }
  80. } ;
  81.  
  82. /* Function */ UINT BeginTransaction()
  83. {
  84.     // get new session handle and increment for next time
  85.     UINT hSession = GetPrivateProfileInt ( "ISS", "NextHandle", 0, "ISS.INI" ) ;
  86.     sprintf ( Session, "%d", random(hSession) ) ;    // increment for next time
  87.     WritePrivateProfileString ( "ISS", "NextHandle", Session, "ISS.INI" ) ;
  88.     sprintf ( Session, "%d", hSession ) ;    // use current for this session
  89.  
  90.     // log start time of this session
  91.     time_t now ;
  92.     time ( &now ) ;
  93.     struct tm *nowtime = gmtime ( &now ) ;
  94.     WritePrivateProfileString ( Session, "StartTime", asctime ( nowtime ), "ISS.INI" ) ;
  95.  
  96.     // set in-progress status
  97.     WritePrivateProfileString ( Session, "Status", "InProgress", "ISS.INI" ) ;
  98.  
  99.  
  100.     // set in-progress status
  101.     WritePrivateProfileString ( Session, "Status", "InProgress", "ISS.INI" ) ;
  102.  
  103.     return ( hSession ) ;
  104. }
  105.  
  106. /* Function */ void AcceptTransaction()
  107. {
  108.     WritePrivateProfileString ( Session, "Status", "Accepted", "ISS.INI" ) ;
  109. }
  110.  
  111. /* Function */ void CancelTransaction()
  112. {
  113.     WritePrivateProfileString ( Session, "Status", "Canceled", "ISS.INI" ) ;
  114. }
  115.  
  116. /* Function */ int DBStore ( char *did, char *val )
  117. {
  118.     WritePrivateProfileString ( Session, did, val, "ISS.INI" ) ;
  119.     return ( 1 ) ;    // return 0 if data validation failed
  120. }
  121.  
  122. /* Function */ int DBFetch ( char *did, char *val, int len )
  123. {
  124.     GetPrivateProfileString ( Session, did, "", val, len, "ISS.INI" ) ;
  125.     return ( 1 ) ;
  126. }
  127.  
  128. /******************************************************************************\
  129.  *
  130.  *    Function to fetch the next HTML template for processing
  131.  *
  132. \******************************************************************************/
  133.  
  134. /* Function */ void ProcessNext()
  135.  
  136. {
  137.     char e[MAX_PATH] ;    // just a little temp array
  138.     int  bHTML = 1 ;
  139.     void ProcessDoc ( char *fna, int bHTML ) ;    // fwd ref
  140.  
  141.     // fetch template for next doc
  142.     char t[80] ;
  143.     if ( FetchVar ( "Prev", e )    )
  144.     {
  145.         FetchVar ( "PBPrev", t ) ;
  146.     }
  147.     else if ( FetchVar ( "Next", e ) )
  148.     {
  149.         FetchVar ( "PBNext", t ) ;
  150.     }
  151.     else if ( FetchVar ( "Accept", e ) )
  152.     {
  153.         FetchVar ( "PBAccept", t ) ;
  154. //        strcpy ( t, "acc2.ins" );
  155.         bHTML = 0 ;
  156.         AcceptTransaction() ;
  157.     }
  158.     else if ( FetchVar ( "Cancel", e ) )
  159.     {
  160.         FetchVar ( "PBCancel", t ) ;
  161.         bHTML = 0 ;
  162.         CancelTransaction() ;
  163.     }
  164.     else
  165.     {
  166. //(dec) 3-May-96
  167. //        strcpy ( t, "Default.htm" ) ;
  168.         FetchVar ( "PBNext", t ) ;
  169.     }
  170.     ProcessDoc ( t, bHTML ) ;
  171. }
  172.  
  173. /******************************************************************************\
  174.  *
  175.  *    Function to resend current HTML doc, probably due to a data validation
  176.  *    failure.
  177.  *
  178. \******************************************************************************/
  179.  
  180. /* Function */ void ProcessCurrent()
  181.  
  182. {
  183.     void ProcessDoc ( char *fna, int bHTML ) ;    // fwd ref
  184.  
  185.     char t[80] ;
  186.     if ( FetchVar ( "ThisDoc", t ) )    // fetch template for current doc again
  187.     {
  188.         ProcessDoc ( t, 1 ) ;    // send this doc again
  189.     }
  190.     else    // can't get current doc, we must continue to next one
  191.     {
  192.         ProcessNext() ;
  193.     }
  194. }
  195.  
  196. /******************************************************************************\
  197.  *
  198.  *    Function to process an HTML template and pump it back to client
  199.  *
  200. \******************************************************************************/
  201.  
  202. /* Function */ void ProcessDoc ( char *fna, int bHTML )
  203.  
  204. {
  205.     // open template file
  206.     char Template[MAX_PATH] ;
  207.     strcpy ( Template, "template\\" ) ;//this line is all that I changes !!!
  208.     strcat ( Template, fna ) ;
  209.     FILE *fip = fopen ( Template, "r" ) ;
  210.     if ( fip == NULL )
  211.     {
  212.         strcpy ( Template, "scripts\\templates\\" ) ;
  213.         strcat ( Template, fna ) ;
  214.         if ( ( fip = fopen ( Template, "r" ) ) == NULL )
  215.         {
  216.             return ;
  217.         }
  218.     }
  219.  
  220.     // dispatch based on doc type
  221.     if ( bHTML )
  222.     {
  223.         void DBtoForm ( FILE *fip, FILE *fop ) ;    // fwd ref
  224.  
  225.         // tell the client we're sending html
  226.         printf ( "Content-type: text/html\n\n" ) ;
  227.  
  228.         // now process the template
  229.         DBtoForm ( fip, stdout ) ;
  230.         fclose ( fip ) ;
  231.     }
  232.     else    // it's an INS file
  233.     {
  234.         // This is a demo mode version of the INS file transmission.
  235.         // In this demo, we're just tranmitting a previously built INS file,
  236.         // one for Accept, or another for Cancel.
  237.  
  238.         // create the session-specific INS file
  239.         char OutputINS[MAX_PATH] ;
  240.         // get new session1 handle and increment for next time
  241.     if (Session1[0]==0){
  242.     UINT hSession1 = GetPrivateProfileInt ( "ISS", "NextHandle1", 0, "ISS.INI" ) ;
  243.     sprintf ( Session1, "%d", hSession1+1 ) ;    // increment for next time
  244.     WritePrivateProfileString ( "ISS", "NextHandle1", Session1, "ISS.INI" ) ;
  245.     sprintf ( Session1, "%d", hSession1 ) ;    // use current for this session
  246.     };
  247.  
  248. // >>>>> Note! <<<<<
  249.         // This path is unique to Microsoft IIS - set this for your HTTP server
  250.         sprintf ( OutputINS, "..\\wwwroot\\insfiles\\%s%s", Session1, fna ) ; 
  251. // >>>>> Note! <<<<<
  252.         FILE *fop = fopen ( OutputINS, "w" ) ;
  253.         if ( fop == NULL )
  254.         {
  255.             return ;
  256.         }
  257.  
  258.         // This is where the INS template would be interpreted and the
  259.         // ISP-specific stuff inserted. For demo purposes, we're just pumping
  260.         // the INS template file out as-is.
  261.         int num ;
  262.         char buf[1024] ;
  263.         for ( num = fread ( buf, sizeof(char), sizeof(buf), fip ) ;
  264.               num > 0 ;
  265.               num = fread ( buf, sizeof(char), sizeof(buf), fip ) )
  266.         {
  267.             fwrite ( buf, sizeof(char), num, fop ) ;
  268.         }
  269.         fclose ( fip ) ;
  270.         fclose ( fop ) ;
  271.  
  272.  
  273.         // Now the Session-specific INS file has been created in the insfiles
  274.         // subdirectory. We are just redirecting the client to fetch this file. 
  275.  
  276.         // Get the base reference for this server's HTML docs
  277.         // If we've specified our own, then use it.
  278.         // Otherwise, parse it from the environment variable.
  279.         char Server[40] ;
  280.         if ( !FetchVar ( "HTTP_REFERER", Server ) )
  281.         {
  282.             char *p = getenv ( "HTTP_REFERER" ) ;
  283.             if ( p == NULL ) return ;
  284.  
  285.             // The problem here is that all we want is our server's base name,
  286.             // not the referring document, so I'm parsing off (in a pathetically
  287.             // crude manner) the server name.
  288.             char *p1 = p ;
  289.             for ( int i = 0 ; i < 3 ; i++ )
  290.             {
  291.                 char *p2 = strchr ( p1, '/' ) ;
  292.                 p1 = p2 ; ;
  293.                 *p1++ ;
  294.             }
  295.             *p1 = '\0' ;
  296.             strcpy ( Server, p ) ;
  297.         }
  298.  
  299.         // simply redirect the client to the INS file
  300.         printf ( "Status: 301 Redirection\n" ) ;
  301.         printf ( "Location: %s/insfiles/%s%s\n\n", Server, Session1, fna ) ;
  302.     }
  303.  
  304. }
  305.  
  306.  
  307. /******************************************************************************\
  308.  *
  309.  *    Function to fetch the variables from a form and put into database
  310.  *
  311. \******************************************************************************/
  312.  
  313. /* Function */ int FormtoDB()
  314.  
  315. {
  316.     // if we didn't receive a session handle, we need to create one
  317.     int ret = FetchVar ( "SessionHandle", Session ) ;
  318.     if ( ret ) ret = *Session != '$' ;
  319.     if ( !ret )
  320.     {
  321.         BeginTransaction() ;
  322.     }
  323.  
  324.     for ( int i = 0 ; DataName[i] ; i++ )
  325.     {
  326.         char name[80] ;
  327.         if ( FetchVar ( DataName[i], name ) )
  328.         {
  329.             if ( !DBStore ( DataName[i], name ) )
  330.             {
  331.                 return ( 0 ) ;    // data validation failed
  332.             }
  333.         }
  334.     }
  335.     return ( 1 ) ;    // data validation(s) succeeded
  336. }
  337.  
  338. /******************************************************************************\
  339.  *
  340.  *    Function to interpret and HTML template
  341.  *
  342. \******************************************************************************/
  343.  
  344. /* Function */ void DBtoForm ( FILE *fip, FILE *fop )
  345.  
  346. {
  347.     char    buf[4096] ;
  348.     // fwd refs
  349.     int ReplaceChk ( char *buf, char *str[], FILE *fop ) ;
  350.     int ReplaceVal ( char *buf, char *str, FILE *fop ) ;
  351.  
  352.     // read file into buffer and process a line at a time
  353.     for ( fgets ( buf, 4096, fip ) ;
  354.           ! feof ( fip ) ;
  355.           fgets ( buf, 4096, fip ) )
  356.     {
  357.         // scan for tokens
  358.         for ( int i = 0 ; i < (int)strlen(buf) ; i++ )
  359.         {
  360.             if ( buf[i] == '$' ) // if token found, parse and replace
  361.             {
  362.                 int j ;
  363.                 // 1) Special case for session handle processing
  364.                 if ( memcmp ( &buf[i+1], "SessionHandle", strlen("SessionHandle") ) == 0 )
  365.                 {
  366.                     fprintf ( fop, "%s", Session ) ;
  367.                     i += strlen ( "$SessionHandle" ) - 1 ;
  368.                     continue ;
  369.                 }
  370.  
  371.                 // 2) Special case for cancel page - need to substitute PrevPage
  372.                 //    with where we came from...
  373.                 if ( memcmp ( &buf[i+1], "PrevPage", strlen("PrevPage") ) == 0 )
  374.                 {
  375.                     char PrevPage[40] ;
  376.                     FetchVar ( "ThisPage", PrevPage ) ;
  377.                     fprintf ( fop, "%s", PrevPage ) ;
  378.                     i += strlen ( "$PrevPage" ) - 1 ;
  379.                     continue ;
  380.                 }
  381.  
  382.                 // 3) Special case for data-value pair names
  383.                 for ( j = 0 ; PairName[j][0] ; j++ )
  384.                 {
  385.                     int k = ReplaceChk ( &buf[i+1], &PairName[j][0], fop ) ;
  386.                     if ( k != 0 ) 
  387.                     {
  388.                         i += k ;
  389.                         break ;
  390.                     }
  391.                 }
  392.  
  393.                 // 4) Finally, check data-name list
  394.                 for ( j = 0 ; DataName[j] ; j++ )
  395.                 {
  396.                     int k = ReplaceVal ( &buf[i+1], DataName[j], fop ) ;
  397.                     if ( k != 0 ) 
  398.                     {
  399.                         i += k ;
  400.                         break ;
  401.                     }
  402.                 }
  403.  
  404.                 // 5) If no valid token found in list, just copy input to output
  405.                 if ( !DataName[j] )
  406.                 {
  407.                     fputc ( (int)buf[i], fop ) ;
  408.                 }
  409.             }
  410.  
  411.             else // not a token, just copy the character to the output file
  412.             {
  413.                 fputc ( (int)buf[i], fop ) ;
  414.             }
  415.         }    // for ( strlen(buf )
  416.     }    // while ( !feof() )
  417. }
  418.  
  419. /******************************************************************************\
  420.  *
  421.  *    Functions to replace token strings in the input stream with data in the
  422.  *    output stream.
  423.  *
  424. \******************************************************************************/
  425.  
  426. /*
  427.  *    Handles data-value pair name data (radio buttons)
  428.  *    Returns 0 (zero) if the string was not found
  429.  *    Returns the number of characters to skip if it was found
  430.  */
  431.  
  432. /* Function */ int ReplaceChk ( char *buf, char *str[], FILE *fop )
  433.  
  434. {
  435.     char val[80] ;
  436.  
  437.     // if input buffer doesn't match the token in str[0], we're done
  438.     if ( memcmp ( buf, str[0], strlen(str[0]) ) != 0 )
  439.         return ( 0 ) ;
  440.  
  441.     // verify that the input buffer has an '=' delimiter for the control name
  442.     char *p = &buf[strlen(str[0])] ;
  443.     if ( *p != '=' )
  444.     {
  445.         return ( 0 ) ;
  446.     }
  447.     // group-name=control-name is correct syntax
  448.  
  449.     // fetch the value of this data item
  450.     DBFetch ( str[0], val, sizeof(val) ) ;
  451.  
  452.     // scan the control names in str[1...] to find data name match
  453.     int i = 1 ;
  454.     for ( *p++ ; str[i] ; i++ )
  455.     {
  456.         if ( memcmp ( p, str[i], strlen(str[i]) ) == 0 )
  457.         {
  458.             if ( strcmp ( str[i], val ) == 0 )
  459.             {
  460.                 fprintf ( fop, "checked" ) ;
  461.             }
  462.             // in either case, we skip over the entire token
  463.             return ( strlen(str[0]) + 1 + strlen(str[i]) + 1 ) ;
  464.         }
  465.     }
  466.     return ( 0 ) ;
  467. }
  468.  
  469. /*
  470.  *    Function to replace a token string in the output stream with data value
  471.  *    Returns 0 (zero) if the string was not found
  472.  *    Returns the number of characters to skip if it was found
  473.  */
  474. /* Function */ int ReplaceVal ( char *buf, char *str, FILE *fop )
  475.  
  476. {
  477.     char    val[80] ;
  478.  
  479.     if ( memcmp ( buf, str, strlen(str) ) != 0 )
  480.         return ( 0 ) ;
  481.  
  482.     DBFetch ( str, val, sizeof(val) ) ;
  483.     fprintf ( fop, "%s", val ) ;
  484.     return ( strlen(str) ) ;
  485. }
  486.