home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Add-Ons / WebSTAR / PPSendPartial CGI / Source / LRequest.cp < prev    next >
Encoding:
Text File  |  1997-02-26  |  9.0 KB  |  337 lines  |  [TEXT/CWIE]

  1. /***
  2.     File:        LRequest.cp
  3.  
  4.  
  5.     Contains:    A Single Request thread class
  6.  
  7.  
  8.     Written by:    Ken Wieschhoff
  9.  
  10.  
  11.     Copyright:    ©1996 Siren Enterprises, All Rights Reserved.
  12.  
  13.  
  14.     Change History (most recent first):
  15.  
  16.  
  17.  
  18.        <1>     9/5/96  kw     Original
  19.  
  20. ***/
  21.  
  22.  
  23. #include "LMainCGI.h"
  24. #include "LRequest.h"
  25. #include <string.h>
  26. #include <UMemoryMgr.h>
  27.  
  28. extern    AEIdleUPP    LMainCGI::sIdleUPP;
  29. extern    long        LCGIStatusThread::sTotalConnections;
  30. extern    Boolean        LCGIStatusThread::sNeedsUpdate;
  31.  
  32. #define    kMaxRows        20
  33. #define kBufferSize        2048
  34. #define kAEClassCGI        'WWWΩ'
  35. #define kAESendPartial    'SPar'
  36. #define kCGIPartialData    '----'
  37. #define kMoreData        true
  38. #define kSendNow        true
  39.  
  40.  
  41. // ---------------------------------------------------------------------------
  42. //        • Constructor
  43. // ---------------------------------------------------------------------------
  44. LRequest::LRequest(AEAddressDesc WebStar, long connectionID, Handle formData)
  45.     : LThread( false )
  46. {
  47.     // Save the WebStar return address
  48.     mWebSTAR = WebStar;
  49.  
  50.     // Same with the connection ID
  51.     mConnectionID = connectionID;
  52.     
  53.     // Make a new handle stream to buffer replies.
  54.     mData = new LHandleStream;
  55.     
  56.     // Make a local copy of the form data so the sender may delete
  57.     // their copy.
  58.     mFormData = formData;
  59.     HandToHand( &mFormData);
  60.  
  61.     // Increment the total amount of connections received.
  62.     LCGIStatusThread::sTotalConnections++;
  63.  
  64.     // Indicate to the main thread the window needs updating.
  65.     LCGIStatusThread::sNeedsUpdate = true;
  66. }
  67.  
  68. // ---------------------------------------------------------------------------
  69. //        • Destructor
  70. // ---------------------------------------------------------------------------
  71. LRequest::~LRequest()
  72. {
  73.     // dispose of the WebSTAR descriptor
  74.     AEDisposeDesc ( &mWebSTAR );
  75.  
  76.     // Delete the Handle Stream
  77.     delete mData;
  78.     
  79.     // Chuck the form data
  80.     ::DisposeHandle( mFormData);
  81.     
  82.     // Indicate to the main thread the window needs updating.
  83.     LCGIStatusThread::sNeedsUpdate = true;
  84. }
  85.  
  86.  
  87. // ---------------------------------------------------------------------------
  88. //        • Run
  89. // ---------------------------------------------------------------------------
  90. void*
  91. LRequest::Run()
  92. {
  93.  
  94.     LStr255 HTTPHeader("\"HTTP/1.0\" 200\r\n\r\n");
  95.     LStr255 HTMLPageTitle( "<HEAD><TITLE>Send Partial Test Page</TITLE></HEAD>");
  96.     LStr255 HTMLPageStart( "<H2>SendPartial Results</H2>");
  97.     LStr255 HTMLTableStart( "<P><TABLE BORDER>");
  98.     LStr255 HTMLRowStart( "<TR>");
  99.     LStr255 HTMLRowEnd( "</TR>");
  100.     LStr255 HTMLTableCell( "<TD align=left><P>??Item??</TD>");
  101.     LStr255 HTMLTableEnd( "</TABLE></TD></TR></TABLE></P>");
  102.     
  103.     long    numberOfRows = 5, numberOfColumns = 6;
  104.     long    index, jndex;
  105.     LStr255    itsCell, itemTemplate("??Item??");
  106.     LStr255    cellData;
  107.     Uint8    start;
  108.     
  109.     // Yield to the main thread to let the AppleEvent complete and send the "<SEND_PARTIAL>"
  110.     // string to WebSTAR.
  111.     LThread::Yield();
  112.         
  113.     Try_ {
  114.  
  115.         // Send the header
  116.         ThrowIfOSErr_( SendData( &HTTPHeader[1], HTTPHeader.Length(), kMoreData, kSendNow));
  117.     
  118.         // Send the page title
  119.         ThrowIfOSErr_( SendData( &HTMLPageTitle[1], HTMLPageTitle.Length(), kMoreData, !kSendNow));
  120.     
  121.         // Send the page start
  122.         ThrowIfOSErr_( SendData( &HTMLPageStart[1], HTMLPageStart.Length(), kMoreData, !kSendNow));
  123.     
  124.         // Send the table start
  125.         ThrowIfOSErr_( SendData( &HTMLTableStart[1], HTMLTableStart.Length(), kMoreData, !kSendNow));
  126.         LThread::Yield();
  127.  
  128.         ParseData( &numberOfRows, &numberOfColumns);
  129.         
  130.         for ( index = 0; index <= numberOfRows; index++) {
  131.             
  132.             // Send the row start
  133.             ThrowIfOSErr_( SendData( &HTMLRowStart[1], HTMLRowStart.Length(), kMoreData, !kSendNow));
  134.  
  135.             for ( jndex = 0; jndex <= numberOfColumns; jndex++) {
  136.                 // populate each cell like a spreadsheet
  137.                 FormatCell( index, jndex, cellData);
  138.  
  139.                 // Initialize the cell to the template
  140.                 itsCell = HTMLTableCell;
  141.                 
  142.                 // Replace the template with the returned cell data.
  143.                 start = itsCell.Find(&itemTemplate[1],itemTemplate.Length(),0);
  144.                 itsCell.Remove(start, itemTemplate.Length());
  145.                 itsCell.Insert(&cellData[1], cellData[0], start);
  146.                 
  147.                 // Send the cell
  148.                 ThrowIfOSErr_( SendData( &itsCell[1], itsCell.Length(), kMoreData, !kSendNow));
  149.             }
  150.             // Send the row end
  151.             ThrowIfOSErr_( SendData( &HTMLRowEnd[1], HTMLRowEnd.Length(), kMoreData, !kSendNow));
  152.             LThread::Yield();
  153.         }
  154.         // Send the table end
  155.         ThrowIfOSErr_( SendData( &HTMLTableEnd[1], HTMLTableEnd.Length(), !kMoreData, kSendNow));
  156.  
  157.     } Catch_ (inErr) {
  158.         // Ignore any errors.  
  159.     } EndCatch_;
  160.     
  161.     // Make the window redraw
  162.     LCGIStatusThread::sNeedsUpdate = true;
  163.  
  164.     DeleteThread();
  165.     return nil;
  166. }
  167.  
  168. // ---------------------------------------------------------------------------
  169. //        • SendData
  170. // ---------------------------------------------------------------------------
  171. OSErr
  172. LRequest::SendData( unsigned char *data, Size itsLength, Boolean more, Boolean sendNow) {
  173.  
  174.     OSErr            itsErr = noErr;
  175.     long            byteCount = itsLength;
  176.     long            amountSent = 0;
  177.  
  178.     // If this will fill the buffer, send it and "empty" the buffer.
  179.     if (( GetHandleSize(mData->GetDataHandle()) + itsLength) > kBufferSize)
  180.         itsErr = ReturnDataToClient( more);
  181.  
  182.     if ( itsErr == noErr) {
  183.         // Put the data into the stream
  184.         mData->PutBytes( data, byteCount);
  185.         
  186.         // Make sure it all went.  If not, send what fit in the buffer and
  187.         // repack the buffer.
  188.         amountSent = byteCount;
  189.         while ((itsErr == noErr) && ( amountSent < itsLength) ) {
  190.             itsErr = ReturnDataToClient( true);
  191.  
  192.             byteCount = itsLength - amountSent;
  193.             mData->PutBytes( &data[amountSent+1], byteCount);
  194.             amountSent += byteCount;
  195.         }
  196.         
  197.         // No more data or "send immediately".  Flush the buffer.
  198.         if (( itsErr == noErr) && (!more || sendNow))
  199.             itsErr = ReturnDataToClient( more);
  200.         
  201.     }
  202.     
  203.     return ( itsErr);
  204. }
  205.  
  206. // ---------------------------------------------------------------------------
  207. //        • ReturnDataToClient
  208. // ---------------------------------------------------------------------------
  209. OSErr
  210. LRequest::ReturnDataToClient( Boolean more) {
  211.  
  212.     AEAddressDesc    theAddress;
  213.     AppleEvent        ourEvent, ourReply;
  214.     OSErr            itsErr = noErr;
  215.     short            AEerr = noErr;
  216.     long            actualSize;
  217.     DescType        returnedType;
  218.     Handle            itsData = mData->GetDataHandle();
  219.     StHandleLocker    itsLocked( itsData);
  220.  
  221.     Try_ {
  222.         // Duplicate the address
  223.         ThrowIfOSErr_( AEDuplicateDesc( &mWebSTAR, &theAddress));
  224.  
  225.         // Create the Event
  226.         ThrowIfOSErr_( AECreateAppleEvent(kAEClassCGI,kAESendPartial, &theAddress,
  227.                 kAutoGenerateReturnID, kAnyTransactionID, &ourEvent));
  228.  
  229.         // Add our data
  230.         ThrowIfOSErr_( AEPutParamPtr( &ourEvent, kCGIPartialData, typeChar, 
  231.                 *itsData, GetHandleSize( itsData)));
  232.         
  233.         // Add the connection ID
  234.         ThrowIfOSErr_( AEPutParamPtr( &ourEvent, 'Kcid', typeLongInteger, 
  235.                 &mConnectionID, sizeof(mConnectionID)));
  236.         
  237.         // Add the "more data" flag.
  238.         ThrowIfOSErr_( AEPutParamPtr( &ourEvent, 'Kmor', typeBoolean, &more, 
  239.                     sizeof(more)));
  240.         
  241.         // Send the event. If the client has gone away this should return an error
  242.         itsErr = AESend( &ourEvent, &ourReply, kAEWaitReply + kAENeverInteract, 
  243.                     kAENormalPriority, kAEDefaultTimeout, nil, nil);
  244.  
  245.  
  246.         // extract the error reply */
  247.         if ( itsErr == noErr) {
  248.             AEerr  = noErr;
  249.             itsErr = AEGetParamPtr ( &ourReply, keyErrorNumber, typeSMInt, &returnedType, &AEerr,
  250.                         sizeof(AEerr), &actualSize );
  251.  
  252.             if (itsErr == errAEDescNotFound)
  253.                 itsErr = noErr;
  254.         }
  255.  
  256.  
  257.     } Catch_ (inErr) {
  258.         // Ignore any errors.  
  259.     } EndCatch_;
  260.  
  261.     // Reset the buffer to 0.
  262.     mData->SetLength( 0);
  263.     mData->SetMarker( 0, streamFrom_Start);
  264.  
  265.     AEDisposeDesc ( &theAddress );
  266.     AEDisposeDesc ( &ourEvent );
  267.     AEDisposeDesc ( &ourReply );
  268.  
  269.     if ( AEerr != noErr)
  270.         itsErr = AEerr;
  271.         
  272.     return itsErr;
  273.         
  274. }
  275.  
  276. // ---------------------------------------------------------------------------
  277. //        • FormatCell
  278. // ---------------------------------------------------------------------------
  279. void
  280. LRequest::FormatCell( long row, long column, LStr255 &cellData) {
  281.  
  282.     Uchar columnCharacter;
  283.  
  284.     // Set the cell descriptor empty
  285.     cellData = "\p";
  286.     
  287.     // Add the row number
  288.     if ( row > 0)
  289.         cellData = cellData + (LStr255)row;
  290.  
  291.     // Add the column as a character
  292.     if ( column > 0) {
  293.         columnCharacter = 'A' + column - 1;
  294.         cellData = cellData + (LStr255)columnCharacter;
  295.     }
  296.  
  297. }
  298.  
  299. // ---------------------------------------------------------------------------
  300. //        • ParseData
  301. // ---------------------------------------------------------------------------
  302. void
  303. LRequest::ParseData( long *row, long *column) {
  304.  
  305.     LStr255        itsData(mFormData), itsValue;
  306.     UInt8        start, end;
  307.     char        *rowsTag = "Rows=";
  308.     char        *columnsTag = "Columns=";
  309.     char        itsColumn;
  310.     
  311.     // Find the start of rows tag
  312.     start = itsData.Find(rowsTag,strlen(rowsTag),0);
  313.     
  314.     // If found...
  315.     if ( start) {
  316.         start += strlen(rowsTag);
  317.         // Grab the substring from after the tag to the '&' delimiter
  318.         end = itsData.Find("&",1,start);
  319.         itsValue = itsData(start,end - start);
  320.         // Convert to a long
  321.         *row = itsValue;
  322.     }
  323.  
  324.     // Find the columns tag.  This is capital letter.
  325.     start = itsData.Find(columnsTag, strlen(columnsTag), 0);
  326.     
  327.     if ( start) {
  328.         start += strlen(columnsTag);
  329.         end = itsData.Find("&",1,start);
  330.         // Grab the substring from after the tag to the '&' delimiter
  331.         itsValue = itsData(start,end - start);
  332.         // Convert to a decimal value.
  333.         itsColumn = itsValue[1];
  334.         *column = itsColumn - 'A' + 1;
  335.     }
  336. }
  337.