/*****************************************************************************/
/*
                             CgiLib_example.c

Simple example showing the essential elements of using the CGILIB routines.

Demonstrates:  *  initializing the environment
               *  alternate processing according to the environment
               *  getting CGI variables
               *  generating responses
               *  processing POSTed requests

Remember, the behaviours of these scripts are WATCHable.

The $COUNT and $SLEEP logical names were added to allow testing of server
behaviour where a CGIplus script, programmed to exit elegantly after processing
a given number of requests, revealed a timing issue that, depending on the
run-down speed of the script, could result in an HTTP 502 status rather than
transparent reactivation as described in the April 1998 note in the
[SRC.HTTPD]DCL.C module.  This script used from the CGILIB_EXAMPLE.HTML
document was a convenient tool to test the server fix using both GET and POST
requests.


LOGICAL NAMES
-------------
CGILIB_EXAMPLE$COUNT  an integer for exit() after this many CGIplus requests
CGILIB_EXAMPLE$DBUG   turns on all "if (Debug)" statements
CGILIB_EXAMPLE$SLEEP  an integer to sleep this many seconds before exiting


BUILD DETAILS
-------------
$ @BUILD_ONE BUILD CGILIB_EXAMPLE
$ @BUILD_ONE LINK CGILIB_EXAMPLE


COPYRIGHT
---------
Copyright (C) 1999-2022 Mark G.Daniel

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.


VERSION HISTORY
---------------
15-OCT-2005  MGD  v1.2.1, CGILIB_EXAMPLE$COUNT and CGILIB_EXAMPLE$SLEEP
28-OCT-2000  MGD  v1.2.0, use CGILIB object module
12-APR-2000  MGD  v1.1.1, minor changes for CGILIB 1.4 (Apache)
24-SEP-1999  MGD  v1.0.0, initial development
*/

/*****************************************************************************/

/* standard C header files */
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* application related header file */
#include "cgilib.h"

/* global storage */

int  CgiPlusCount,
     CgiPlusSleep,
     CgiPlusUsage,
     Debug,
     IsCgiPlus;

char  *CgiContentTypePtr,
      *CgiQueryStringPtr,
      *CgiRequestMethodPtr;

/*****************************************************************************/
/*
*/

main (int argc, char* argv[])
       
{
   char  *cptr;

   /*********/
   /* begin */
   /*********/

   if (Debug = (getenv ("CGILIB_EXAMPLE$DBUG") != NULL))
   {
      CgiLibEnvironmentSetDebug (Debug);
      fprintf (stdout, "Content-Type: text/plain\r\n\r\n");
   }

   if (cptr = getenv ("CGILIB_EXAMPLE$COUNT"))
   {
      CgiPlusCount = atoi(cptr);
      if (cptr = getenv ("CGILIB_EXAMPLE$SLEEP"))
         CgiPlusSleep = atoi(cptr);
      else
         CgiPlusSleep = 1;
   }

   CgiLibEnvironmentInit (argc, argv, 0);

   IsCgiPlus = CgiLibEnvironmentIsCgiPlus ();

   if (IsCgiPlus)
   {
      for (;;)
      {
         /* block waiting for the next request */
         CgiLibVar ("");
         ProcessRequest ();
         CgiLibCgiPlusEOF ();
         if (CgiPlusCount)
         {
            CgiPlusCount--;
            if (!CgiPlusCount)
            {
               if (CgiPlusSleep) sleep (CgiPlusSleep);
               exit (1);
            }
         }
      }
   }
   else
      ProcessRequest ();
}

/*****************************************************************************/
/*
*/

ProcessRequest ()
       
{
   int  Context;
   char  *GatewaySymbolsPtr,
         *VariablePtr;

   /*********/
   /* begin */
   /*********/

   if (Debug) fprintf (stdout, "ProcessRequest()\n");

   CgiRequestMethodPtr = CgiLibVar ("WWW_REQUEST_METHOD");

   if (CgiLibEnvironmentIsWasd())
   {
      /* need this to be record-oriented for the DCL output records */
      CgiLibEnvironmentRecordOut ();
   }

   /* generate an HTTP header, plain-text content-type */
   CgiLibResponseHeader (200, "text/plain");

   fprintf (stdout, "Current environment is \"%s\" (%s)\n\n",
      CgiLibEnvironmentName(), CGILIB_SOFTWAREID);

   if (CgiLibEnvironmentIsCgiPlus())
      fprintf (stdout, "Usage count is %d.\n\n", ++CgiPlusUsage);

   if (CgiLibEnvironmentIsWasd() ||
       CgiLibEnvironmentIsApache())
   {
      fprintf (stdout,
"These are the CGI variables contained in the subprocess' DCL symbols:\n\n");

      /* with standard CGI the variables are all in DCL symbols */
      system ("SHOW SYMBOL WWW_*");
   }

   if (!strcmp (CgiRequestMethodPtr, "POST"))
      ProcessPost ();
   else
   if (CgiLibEnvironmentIsCgiPlus() ||
       CgiLibEnvironmentIsOsu())
   {
      fprintf (stdout,
"These are the CGI variables created from the %s:\n\n",
         CgiLibEnvironmentIsCgiPlus() ? "CGIPLUSIN stream" :
                                        "OSU dialog phase");

      while ((VariablePtr = CgiLibVarNull ("*")) != NULL)
         fprintf (stdout, "  %s\n", VariablePtr);
   }

   CgiQueryStringPtr = CgiLibVar ("WWW_QUERY_STRING");
   if (strchr (CgiQueryStringPtr, '=') != NULL)
   {
      fprintf (stdout,
"\nHere are the form elements of QUERY_STRING via CgiLibFormEncodedParse():\n\n");

      Context = 0;
      while ((VariablePtr =
              CgiLibFormEncodedParse (CgiQueryStringPtr, &Context)) != NULL)
         fprintf (stdout, "  %s\n", VariablePtr);
   }

   if (CgiLibEnvironmentIsWasd())
   {
      if (GatewaySymbolsPtr = CgiLibVar ("WWW_GATEWAY_SYMBOLS"))
      {
         fprintf (stdout,
"\nHere are the CGI variables via WWW_GATEWAY_SYMBOLS and CgiLibVar(\"*\"):\n\n");

         CgiLibVar (NULL);
         while ((VariablePtr = CgiLibVar ("*")) != NULL)
            fprintf (stdout, "  %s\n", VariablePtr);
      }
   }
}

/*****************************************************************************/
/*
*/

ProcessPost ()
       
{
   int  Context,
        PostBufferCount;
   char  *VariablePtr,
         *PostBufferPtr;

   /*********/
   /* begin */
   /*********/

   if (Debug) fprintf (stdout, "ProcessPost()\n");

   /* read the POSTed request body */
   CgiLibReadRequestBody (&PostBufferPtr, &PostBufferCount);
   if (PostBufferPtr == NULL ||
       PostBufferCount == 0)
   {
      CgiLibResponseError (__FILE__, __LINE__, 0, "No body in the POST!");
      return;
   }

   CgiContentTypePtr = CgiLibVar ("WWW_CONTENT_TYPE");

   if (!strcmp (CgiContentTypePtr, "application/x-www-form-urlencoded"))
   {
      /* is URL form encoded, turn that into pseudo CGI variables */
      CgiLibFormRequestBody (PostBufferPtr, PostBufferCount);

      fprintf (stdout,
"Request was via a POSTed form.\n\n\
Here are the form elements converted to pseudo CGI variables:\n\n");

      if (CgiLibEnvironmentIsCgiPlus())
         fprintf (stdout,
"(via CGIplus, so you'll also see the CGI environment variables)\n");
      else
      if (CgiLibEnvironmentIsOsu())
         fprintf (stdout,
"(via OSU, so you'll also see the CGI environment variables)\n\n");

      while ((VariablePtr = CgiLibVarNull ("*")) != NULL)
         fprintf (stdout, "  %s\n", VariablePtr);

      fprintf (stdout,
"\nHere are the form elements via CgiLibFormEncodedParse():\n\n");

      Context = 0;
      while ((VariablePtr =
              CgiLibFormEncodedParse (PostBufferPtr, &Context)) != NULL)
         fprintf (stdout, "  %s\n", VariablePtr);

      free (PostBufferPtr);
   }
   else
   {
      /* we'll just assume it's a body of displayable text */
      CgiLibResponseHeader (200, "text/plain");
      fputs (PostBufferPtr, stdout);
      free (PostBufferPtr);
   }
}

/*****************************************************************************/

