/*===========================================================================
 *
 * File:	CGIQuery.CPP
 * Author:	Dave Humphrey (uesp@m0use.net)
 * Created On:	Friday, March 30, 2001
 *
 * Implements the CHTMLQuery class for handling GET and POST form outputs.
 *
 *=========================================================================*/

	/* Include Files */
#include "cgiquery.h"


/*===========================================================================
 *
 * Begin Local Variable Definitions
 *
 *=========================================================================*/
  DEFINE_FILE();
/*===========================================================================
 *		End of Local Variable Definitions
 *=========================================================================*/

 
/*===========================================================================
 *
 * Class CHTMLQuery Constructor
 *
 *=========================================================================*/
CHTMLQuery::CHTMLQuery () {
  //DEFINE_FUNCTION("CHTMLQuery::CHTMLQuery()");
  pQueryBuffer = NULL;
  QueryLength = 0;
 }
/*===========================================================================
 *		End of Class CHTMLQuery Constructor
 *=========================================================================*/


/*===========================================================================
 *
 * Class CHTMLQuery Method - void Destroy (void)
 *
 * Class pseudo-destructor
 *
 *=========================================================================*/
void CHTMLQuery::Destroy (void) {
  //DEFINE_FUNCTION("CHTMLQuery::Destroy()");
  DestroyPointer(pQueryBuffer);
  QueryLength = 0;
 }
/*===========================================================================
 *		End of Class Method CHTMLQuery::Destroy()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CHTMLQuery Method - boolean ParseQuery (PPARSEQUERYCALLBACK CallBackFunc)
 *
 * Parses the query from a POST/GET form output into individual variable
 * value pairs.  The query is assumed to be in the form
 *
 *	"Var1=Value1&Var2=Value2&Var3=Value3"
 *
 * For each variable/value pair, the passed callback function is called
 * with the pointers to the var/value.  The callback function must be a valid,
 * non-NULL function.  On any error, FALSE is returned.  The query must have 
 * previously been read.
 *
 *=========================================================================*/
boolean CHTMLQuery::ParseQuery (PPARSEQUERYCALLBACK CallBackFunc) {
  DEFINE_FUNCTION("CHTMLQuery::ParseQuery()");
  char*   pPairStart; 
  char*   pParsePair;
  char*   pVariable;
  char*   pValue;
  boolean Result;

	/* Ensure a valid callback function */
  ASSERT(CallBackFunc != NULL);
  pPairStart = pQueryBuffer;
  
	/* Parse the entire query string */
  while (pPairStart != NULL) {

		/* Find the end of the next var/value pair */
    pParsePair = strchr(pPairStart, '&');

    if (pParsePair != NULL) {
      *pParsePair = NULL_CHAR;
      pParsePair++;
     }

		/* Find the variable/value pair, if any */
    SeperateVarValue(&pVariable, &pValue, pPairStart, '=', NULL_CHAR);
    
		/* Call the user's callback function */
    Result = CallBackFunc(pVariable, pValue);
    if (!Result) return (FALSE);

		/* Move onto start of next var/value pair, if any */
    pPairStart = pParsePair;
   }

  return (TRUE);
 }
/*===========================================================================
 *		End of Class Method CHTMLQuery::ParseQuery()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CHTMLQuery Method - boolean ReadGETQuery (void)
 *
 * Read a GET form query, returning FALSE on any error.  A GET query stores
 * the string in the QUERY_STRING environment variable.
 *
 *=========================================================================*/
boolean CHTMLQuery::ReadGETQuery (void) {
  DEFINE_FUNCTION("CHTMLQuery::ReadGETQuery()");
  char* pQueryString;

	/* Look for a GET query variable */
  pQueryString = getenv(HTTP_QUERYSTRING_ENV);
  if (pQueryString == NULL) return (FALSE);
    
	/* Save the query to the query buffer */
  QueryLength = strlen(pQueryString);
  ReplaceString(&pQueryBuffer, pQueryString);
  return(TRUE);
 }
/*===========================================================================
 *		End of Class Method CHTMLQuery::ReadGETQuery()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CHTMLQuery Method - boolean ReadPOSTQuery (void);
 *
 * Reads a POST form query, returning FALSE on any error. A POST query is
 * found by examining the environment variables CONTENT_LENGTH and 
 * CONTENT_TYPE for the correct values.
 *
 *=========================================================================*/
boolean CHTMLQuery::ReadPOSTQuery (void) {
  DEFINE_FUNCTION("CHTMLQuery::ReadPOSTQuery()");
  char*  pContentType;
  char*  pContentLength;
  size_t InputBytes;
  int    ContentSize;

	/* Get the enivronment variables and ensure they are valid */
  pContentType = getenv(HTTP_CONTENTTYPE_ENV);
  pContentLength = getenv(HTTP_CONTENTLENGTH_ENV);
  if (pContentType == NULL || pContentLength == NULL) return (FALSE);

	/* Check the content length for a valid size */
  ContentSize = atoi(pContentLength);
  if (ContentSize < 0) return (FALSE);
  QueryLength = (size_t) ContentSize;

	/* Check the content type for a correct value */
  if (stricmp(pContentType, HTTP_POST_CONTENTTYPE_VALUE) != 0) return (FALSE);

	/* Attempt to allocate and read the query input buffer */
  ReplaceString(&pQueryBuffer, QueryLength);
  InputBytes = fread(pQueryBuffer, sizeof(char), QueryLength, stdin);

	/* Ensure the input was successful */
  if (InputBytes != QueryLength) return (FALSE);
  return (TRUE); 
 }
/*===========================================================================
 *		End of Class Method CHTMLQuery::ReadPOSTQuery()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CHTMLQuery Method - boolean ReadQuery (void)
 *
 * Reads a POST or GET form query, depending on which is available.
 * Returns FALSE on any error or if no query is available.
 *
 *=========================================================================*/
boolean CHTMLQuery::ReadQuery (void) {
  //DEFINE_FUNCTION("CHTMLQuery::ReadQuery()");
  boolean Result;

	/* Check for a POST then a GET query */
  Result = ReadPOSTQuery();
  if (!Result) Result = ReadGETQuery();

	/* Convert form output to regular ASCII text */
  if (Result) UnWebQuery();
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CHTMLQuery::ReadQuery()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CHTMLQuery Method - boolean ReadQuery (Function)
 *
 * Reads a POST or GET form query, depending on which is available, and 
 * then parses the form output using the given parse function. Returns
 * FALSE on any error or if no query is available.
 *
 *=========================================================================*/
boolean CHTMLQuery::ReadQuery (PPARSEQUERYCALLBACK Function) {
  DEFINE_FUNCTION("CHTMLQuery::ReadQuery(PPARSEQUERYCALLBACK)");
  boolean Result;

	/* Ensure valid input */
  ASSERT(Function != NULL);

	/* Read, then parse, the form query */
  Result = ReadQuery();
  if (Result) Result = ParseQuery(Function);
  
  return (Result);
 }
/*===========================================================================
 *		End of Class Method CHTMLQuery::ReadQuery()
 *=========================================================================*/


/*===========================================================================
 *
 * Class CHTMLQuery Method - boolean UnWebQuery (void);
 *
 * Converts the webified form output to regular characters.  Some special
 * characters output from a form are converted to the form "%XX" where XX
 * is the hexidecimal ASCII code for the character.  This function converts
 * all these codes to their equivalent characters.  In addition, any '+' 
 * character is converted to a space. Returns FALSE if there was any
 * error converting the string.
 *
 *=========================================================================*/
boolean CHTMLQuery::UnWebQuery (void) {
  //DEFINE_FUNCTION("CHTMLQuery::UnWebQuery()");

  	/* Ensure a valid query buffer */
  if (pQueryBuffer == NULL) return(TRUE);
  return cgiUnWebFormOutput(pQueryBuffer);
 }
/*===========================================================================
 *		End of Class Method CHTMLQuery::UnWebQuery()
 *=========================================================================*/