/*****************************************************************************/
/*
                              CGIplusDemo.c

Simple program that can be used in both standard CGI and CGIplus environments.
The standard CGI section merely echoes the remote host name (lacking any
mechanism to list all variables ... apart perhaps from a SHOW SYMBOL WWW_*).
The CGIplus section uses two methods to access the CGI variables. One just
reads CGIPLUSIN checking each line for the required variable (and displaying
them as it goes). The other uses a more sophisticated function that processes
the CGIplus variables and the allows queries on variable names, etc. This
function is presented as a template in CGIplusSkel.c

Defining the logical name CGIPLUSDEMO$STRUCT causes this demo to use 'struct'
mode rather than 'record mode' for for passing the CGIplus variables.


VERSION HISTORY (update SOFTWAREVN as well!)
---------------
23-DEC-2003  MGD  v1.3.2, minor conditional mods to support IA64
30-NOV-2002  MGD  v1.3.1, bugfix; every second CGIplus request incorrectly
                          having the variables read by CgiPlusReader();
05-APR-2001  MGD  v1.3.0, demo/test CGIplus variable 'struct',
                          body via CGIPLUSIN
24-APR-1999  MGD  v1.2.0, use CGILIB.C
21-JUN-1998  MGD  v1.1.0, revision of CgiVar()
08-JUN-1997  MGD  v1.0.0, initial development
*/
/*****************************************************************************/

#define SOFTWAREVN "1.3.2"
#define SOFTWARENM "CGIPLUSDEMO"
#ifdef __ALPHA
#  define SOFTWAREID SOFTWARENM " AXP-" SOFTWAREVN
#endif
#ifdef __ia64
#  define SOFTWAREID SOFTWARENM " IA64-" SOFTWAREVN
#endif
#ifdef __VAX
#  define SOFTWAREID SOFTWARENM " VAX-" SOFTWAREVN
#endif

#ifndef __VAX
#   pragma nomember_alignment
#endif

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <time.h>

char  Utility [] = "CGIPLUSDEMO";

int  Debug,
     IsCgiPlus,
     UsageCounter,
     UseCgiPlusVarStruct;

char  *CgiPlusEofPtr;

char  FirstUsedDateTime [32],
      NowDateTime [32];

unsigned long  UnixTime;
struct tm  *UnixTmPtr;

/*****************************************************************************/
/*
Include the CGILIB.H/.C function code from the standard WASD location if
CGILIB_INCLUDE_H/_C has not been defined.  If it has been defined then the
value must be the #include location.
*/

/* indicate required functionality */
#define CGILIB_CGIVAR_SUPPORT  1
#define CGILIB_CGIPLUS_SUPPORT 1

#define CGILIB_DEBUG (Debug)

#include "/ht_root/src/misc/cgilib.h"
#include "/ht_root/src/misc/cgilib.c"

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

main ()

{
   /*********/
   /* begin */
   /*********/

   if (getenv ("CGIPLUSDEMO$DBUG")) Debug = 1;

   CgiLibEnvironmentSetDebug (Debug);

   UseCgiPlusVarStruct = (int)getenv("CGIPLUSDEMO$STRUCT");

   time (&UnixTime);
   UnixTmPtr = localtime (&UnixTime);
   if (!strftime (FirstUsedDateTime, sizeof(FirstUsedDateTime),
                  "%a, %d %b %Y %T", UnixTmPtr))
      strcpy (FirstUsedDateTime, "[error]");

   /* demonstrate the ease with which it may operate in both environments */
   IsCgiPlus = (CgiPlusEofPtr = getenv("CGIPLUSEOF"));

   do {

      time (&UnixTime);
      UnixTmPtr = localtime (&UnixTime);
      if (!strftime (NowDateTime, sizeof(NowDateTime),
                     "%a, %d %b %Y %T", UnixTmPtr))
         strcpy (NowDateTime, "[error]");

      if (IsCgiPlus)
         CgiPlusDemo ();
      else
         CgiStandardDemo ();

   } while (IsCgiPlus);

   exit (1);
}

/*****************************************************************************/
/*
Using standard CGI.  Get CGI variable data using getenv(), not using the
function CgiLibVar() illustrated below.
*/

CgiStandardDemo ()

{
   char  *cptr;

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

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

   fprintf (stdout,
"Content-Type: text/plain\n\
Expires: Thu, 01 Jan 1970 00:00:01 GMT\n\
\n\
Number of times used: %d (standard CGI)\n\
First used: %s\n\
Now: %s\n\
\n",
      ++UsageCounter, FirstUsedDateTime, NowDateTime);

   if (cptr = getenv("WWW_REMOTE_ADDR"))
      fprintf (stdout, "Remote-Addr: %s\n", cptr);
   else
      fprintf (stdout, "Remote-Addr: NOT FOUND!\n");
}

/*****************************************************************************/
/*
Alternate between the two methods of obtaining CGI variables in the CGIplus
environment.  First, using the function CgiLibVar(), which allows specific
variable names to be queried.  Second, using a simple read of <stdin>,
checking for the variable names required.
*/

CgiPlusDemo ()

{
   static int  WasCgiPlusVarStruct = 0;

   char  *cptr;

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

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

   if (UseCgiPlusVarStruct)
   {
      /* wait for the next request */
      CgiLibVar ("");

   fprintf (stdout,
"Content-Type: text/plain\n\
Expires: Thu, 01 Jan 1970 00:00:01 GMT\n\
\n\
Number of times used: %d (CGIplus)\n\
First used: %s\n\
Now: %s\n\
Using: CgiLibVar() in %s mode\n\
\n",
      ++UsageCounter, FirstUsedDateTime, NowDateTime,
      WasCgiPlusVarStruct ? "STRUCT" : "RECORD");

      /* list all CGIplus variables names and values one-by-one */
      while (cptr = CgiLibVar ("*"))
      {
         if (!strncmp (cptr, "WWW_REMOTE_HOST=", 16))
            fprintf (stdout, "Remote-Host: %s\n", cptr+16);
         else
            fprintf (stdout, "|%s|\n", cptr);
      }

      /* query on the supplied variable name */
      fprintf (stdout, "\n");
      if (*(cptr = CgiLibVar ("WWW_REMOTE_ADDR")))
         fprintf (stdout, "Remote-Addr: %s\n", cptr);
      else
         fprintf (stdout, "Remote-Addr: NOT FOUND!\n");

      /* illustrate variable query when not found */
      if (*(cptr = CgiLibVar ("WWW_BOGUS_VARIABLE")))
         fprintf (stdout, "Bogus-Variable: %s\n", cptr);
      else
         fprintf (stdout, "Bogus-Variable: NOT FOUND!\n");

      if (UseCgiPlusVarStruct)
      {
         if (!WasCgiPlusVarStruct) CgiLibCgiPlusSetVarStruct ();
         WasCgiPlusVarStruct = 1;
      }
      else
      if (WasCgiPlusVarStruct)
      {
         CgiLibCgiPlusSetVarRecord ();
         WasCgiPlusVarStruct = 0;
      }
   }
   else
   {
      /* process the variables using a simple read loop */
      CgiPlusReader ();
   }

   /* record-oriented <stdout>, no need to flush, write end-of-output line */
   fprintf (stdout, "%s\n", CgiPlusEofPtr);
}

/*****************************************************************************/
/*
CGIplus variable access method 1 (simple).

Use a simple loop to read lines from standard input.  Detect specific CGI
variables by checking the leading section of these lines for the required
variable name.  The value may then be extracted from the remaining section.
*/

CgiPlusReader ()

{
#  define CGIPLUS_LINE_SIZE 1024

   int  LineCount = 0;
   char  *cptr;
   char  Line [CGIPLUS_LINE_SIZE];
   FILE  *CgiPlusIn;

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

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

   if (!(CgiPlusIn = fopen (getenv("CGIPLUSIN"), "r")))
      exit (vaxc$errno);

   /* wait for request, discard initial record */
   if (!(fgets (Line, sizeof(Line), CgiPlusIn))) exit (vaxc$errno);

   fprintf (stdout,
"Content-Type: text/plain\n\
\n\
Number of times used: %d (CGIplus)\n\
First used: %s\n\
Now: %s\n\
Using: CgiPlusReader()\n\
\n",
      ++UsageCounter, FirstUsedDateTime, NowDateTime);

   for (;;)
   {
      if ((fgets (Line, sizeof(Line), CgiPlusIn))) exit (vaxc$errno);
      /* first empty line signals the end of CGIplus variables */
      if (Line[0] == '\n') break;
      /* remove the trailing newline */
      for (cptr = Line; *cptr && *cptr != '\n'; cptr++);
      *cptr = '\0';

      /* select only the variable(s) we are interested in */
      if (!strncmp (Line, "WWW_REMOTE_HOST=", 16))
         fprintf (stdout, "Remote-Host: %s\n", Line+16);
      else
         fprintf (stdout, "|%s|\n", Line);
   }

   fclose (CgiPlusIn);
}

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

