Link to home
Start Free TrialLog in
Avatar of szetoa
szetoa

asked on

Passing parameter to a C CGI.

Experts,

Is it possible to pass parameter to a C CGI from a form, like we used to do on a command line:

    pgm arg1 arg2 ...

Thanks in advance for your help.
Avatar of maneshr
maneshr

sure you can do that.

here is a sample code in C that will do exactly that....


/************************************************************************\
*                                                                        *
* CookMail                                                               *
* Version 2.13                                                           *
* (c) Copyright Heng Yuan 1996                                           *
* All Rights Reserved.                                                   *
*                                                                        *
* This program can be easily modified to handle forms other than email.  *
* To do so, search the string "WISH" to get to the right place.          *
* Do NOT distribute this program in any modified format.                 *
*                                                                        *
*                                                                        *
* Description:                                                           *
*      A Form Handling CGI script for Unix                               *
*                                                                        *
\************************************************************************/

#ifdef MS
#define DOS
#endif

#ifdef DOS
#include <windows.h>
#endif

#include <stdio.h>
#include "html.h"
#include "string.h"
#include "btree.h"
#include "mime.h"

/*----------------------------------------------------------------------*\
 *                                                                      *
 *   -- YOU MAY CONFIGURE THIS PART --                                  *
 *                                                                      *
\*----------------------------------------------------------------------*/

/* default mailer program */
#ifdef DOS
/* specific handling of BLAT */
static char MAILER[100] = "cookblat.exe";
/* TEMP is the directory where you store all the cookmail temp
   files.  The filenames will be owebm*.html.  Make sure that
   your server is configured with virtual directory /tmp pointed
   to here,
   In LITE version, virtual directory is not needed, but this
   directory is still required.
 */
char TEMP[200] = "TEMP=C:\\TEMP";
#else
static char MAILER[] = "/usr/lib/sendmail";
#endif

/* default forms */
static char FORMform[] = "\
From: ${EMAIL} (${NAME})\n\
Subject: ${SUBJECT}\n\
To: ${TO}\n\
\n\
${MESSAGE}\n\
${ETC}\n";

static char SHOWform[] = "\
<HTML>\n\
<HEAD>\n\
<TITLE>Thank You Note</TITLE>\n\
</HEAD>\n\
<BODY>\n\
<H1>Thank You Note</H1>\n\
Thank you for taking the time to fill out of this form.  Below is what you have submitted.\n\
<HR>\n\
<B>From</B>: ${EMAIL} (${NAME})<BR>\n\
<B>Subject</B>: ${SUBJECT}<BR>\n\
<B>To</B>: ${TO}\n\
<HR>\n\
<PRE>\n\
${MESSAGE}\n\
${ETC}\n\
</PRE>\n\
<HR>\n\
<A HREF=${HTTP_REFERER}><B>Go Back<B></A>\n\
</BODY>\n\
</HTML>\n";

static char CCFORMform[] = "\
From: ${TO} (${REPLYNAME})\n\
Subject: ${SUBJECT}\n\
To: ${EMAIL} (${NAME})\n\
\n\
Thank You For Your Information:\n\
===============================\n\
From: ${EMAIL} (${NAME})\n\
Subject: ${SUBJECT}\n\
To: ${TO}\n\
\n\
${MESSAGE}\n\
${ETC}\n\
===============================\n\
URL: ${HTTP_REFERER}\n";

static char EMPTYform [] = "\
<HTML>\n\
<HEAD>\n\
<TITLE>Data Error</TITLE>\n\
</HEAD>\n\
<BODY>\n\
<H1>Data Error</H1>\n\
Sorry, the following field must not be blank.\n\
<HR>\n\
<CODE>${EMPTYERROR}</CODE>\n\
<HR>\n\
Please go back and fill the form again.\n\
</BODY>\n\
</HTML>\n";

/* This part is for C programmer only */
/* this envhandle only work for those forms without FORM or SHOW field */
void envhandle (btree *env, FILE *f)
{
  char separator[] = "======================================================";
  fprintf (f, "\n%s\n%.*s\n%s\n", env->data, (int)strlen (env->data), separator, getnodedata (env));
/*
  Explaination :
  env->data is the name of the environmental variable which hold the non
    default field name
  \n is carriage return
  strlen (env->data) is the length of the ENV string
  separator is the line which separate the field name and field content
  getnodedata (env) is the content of the ENV field
  Example:
    FOOD=Extra Large Stuffed Pizza
  Where FOOD is the field name and Pizza is the content, the output result
  will be:
    FOOD
    ====
    Extra Large Stuffed Pizza
*/
}

/*------------------------------------------------------------------------*\
 *                                                                        *
 *     -- END OF CONFIGURATION ** DO NOT MODIFY ANYTHING BELOW --         *
 *                                                                        *
\*------------------------------------------------------------------------*/

/* predefined field names for email */
static char FORM[] = "FORM";         /* email form file */
static char SHOW[] = "SHOW";         /* show form file */
static char EMPTY[] = "EMPTY";       /* empty form file */
static char NAME[] = "NAME";         /* name of sender */
static char EMAIL[] = "EMAIL";       /* email addr of sendor */
static char TO[] = "TO";             /* email address of recipient */
static char SUBJECT[] = "SUBJECT";   /* email subject */
static char MESSAGE[] = "MESSAGE";   /* email message */
static char MIME[] = "MIME";         /* mime encoding for email message */
static char CC[] = "CC";             /* carbon copy email to sender */
static char CCFORM[] = "CCFORM";     /* Cc email form */
static char REPLYNAME[] = "REPLYNAME"; /* for CCFORM, name for TO */

/* defined in html.c */
extern char EMPTYHANDLE[];
extern char EMPTYERROR[];
extern char MULTIPLE[];
extern char MULTIPLEMARK[];

/* predefined field name for returning info */
static char REDIRECT[] = "REDIRECT"; /* default prewritten html */

/* tmpfile name contain the translated form */
static char TMPFILE[256];

/* translate forms and return the file name contain the result */
int translate (const char *);

/* read a file into a buffer */
char *fileread (FILE *fin);

/* display the current cookmail version */
void showversion ()
{
#ifndef LITE
  puts ("CookMail Version 2.13.");
#else
  puts ("CookMail Lite Version 2.13.");
#endif
#ifdef MS
  puts ("This version display HTTP/1.0 200 OK before CGI headers.");
#endif
  puts ("\n\
(c) Copyright 1996, 1997, 1998 Heng Yuan\n\
\n\
Please visit the CookMail homepage at\n\
\thttp://ag.arizona.edu/~heng/cookmail/cookmail.html\n\
for the latest version and other information.");
}

/* read TMPFILE and display it on the web using HTML */
void showtmpfile ()
{
  #ifndef LITE
    #ifdef DOS
      sprintf (TMPFILE, "/tmp/%s", &TMPFILE[strlen (getenv ("TEMP")) + 1]);
      showhtml (TMPFILE);
    #else
      showhtml (TMPFILE);
    #endif
  #else
    FILE *fin = fopen (TMPFILE, "rb");
    char *buffer = fileread (fin);
    showoutput (HTML);
    if (buffer)
      {
      fputs (buffer, stdout);
      free (buffer);
      }
    else
      puts ("Error: out of memory");
    fclose (fin);
    remove (TMPFILE);
  #endif
}

int main ()
{
  int i;
  /* obviously we are not running under appropriet conditions */
  if (REQUEST_METHOD == NULL)
    {
      showversion ();
      return 0;
    }

  /* hmm, we are called not as form handler,
     we must be used as to display HTTP_REFERER */
  if (strcasecmp (REQUEST_METHOD, "GET") == 0 &&
      (QUERY_STRING == NULL ||
       strlen (QUERY_STRING) == 0))
    {
      char *h;
      showoutput (HTML);
      h = HTTP_REFERER;
      if (h != NULL)
      putsf ("<INPUT TYPE=HIDDEN NAME=HTTP_REFERER VALUE=%s>", h);
      return 0;
    }

  #ifdef DOS
    putenv (TEMP);
  #endif

  i = getmethod ();      /* read all fields */
  switch (i)
    {                    /* handle returned message */
      case 0:
        break;
      case 1:            /* Forced EMPTYERROR */
      if (translate (EMPTY) == 0)
        showtmpfile ();
      return 0;
      default:         /* death value */
      showoutput (PLAIN);
      putsf ("Error: internal unknown error id %d, possibily out of memory", i);
      return -1;
    }

  i = strlen (getformdata ("TO"));
  if (i == 0)          /* no address */
    {
      showoutput (PLAIN);
      puts ("Error: no recipient address");
      return -1;
    }

  if (strspn (getformdata ("TO"), "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@.0123456789,-_ \t") < i)    /* invalid address */
    {
      showoutput (PLAIN);
      puts ("Error: invalid characters in email address");
      return -1;
    }

  i = strlen (getformdata ("EMAIL"));
  if (i)
    {
      if (strspn (getformdata ("EMAIL"), "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@.0123456789,-_ \t") < i)    /* invalid address */
      {
        showoutput (PLAIN);
        puts ("Error: invalid characters in email address");
        return -1;
      }
    }

  /* translate email form */
  /* "WISH"
     change here if you wish to use commands other than sendmail to
     store form data.
     please do not distribute the modified form of this program.
   */
  if (translate (FORM) == 0)
    {
/*    char *COMMAND = (char *)malloc (sizeof (MAILER) + strlen (getformdata (TO)) + strlen (TMPFILE) + 2); */
      char *COMMAND = (char *)malloc (sizeof (MAILER) + strlen (getformdata (TO)) + strlen (TMPFILE) + 10);
      if (COMMAND)
      {
#ifdef DOS
        sprintf (COMMAND, "%s %s -t %s -q",
               MAILER,
               TMPFILE,
               getformdata (TO));
#else
        sprintf (COMMAND, "%s %s<%s",
               MAILER,
               getformdata (TO),
               TMPFILE);
#endif
        system (COMMAND);
        remove (TMPFILE);
        free (COMMAND);
      }
      else
      {
        showoutput (PLAIN);
        puts ("Error: unable to send email");
        return -1;
      }
    }
  else                              /* error */
    return -1;

  /* do the carbon copy form */
  if (strcasecmp (getformdata (CC), "on") == 0 &&
      !isemptyenv (getformdata (EMAIL)))
    {
      if (translate (CCFORM) == 0)
      {
/*        char *COMMAND = (char *)malloc (sizeof (MAILER) + strlen (getformdata (TO)) + strlen (TMPFILE) + 2); */
        char *COMMAND = (char *)malloc (sizeof (MAILER) + strlen (getformdata (TO)) + strlen (TMPFILE) + 10);
        if (COMMAND)
          {
#ifdef DOS
            sprintf (COMMAND, "%s %s -t %s -q",
                   MAILER,
                   TMPFILE,
                   getformdata (EMAIL));
#else
            sprintf (COMMAND, "%s %s<%s",
                   MAILER,
                   getformdata (EMAIL),
                   TMPFILE);
#endif
            system (COMMAND);
            remove (TMPFILE);
            free (COMMAND);
          }
      }
    }

  /* translate show form */
  if (strlen (getformdata (REDIRECT)) > 0)
    showhtml (getformdata (REDIRECT));
  else
    {
      if (translate (SHOW) == 0)
      showtmpfile ();

      /* assume tmp files are cleaned periodically.  You can do this
       by using cron/at jobs.  If you are hate to use cron/at jobs,
       use REDIRECT instead.
        "WARNING"
       someone can really fill up the tmp space very quickly if he
       wishs to do so.
       because the source of this program is available to public,
       hackers can always find some bugs :(  There is no good
       solution to this problem.  If you experenced such problem,
       remove this program immediately from your server */
      else
      showoutput (HTML);   /* display nothing */
    }
  return 0;
}

/* actural translation routin, shell script would have done this easier */
int translate (const char *form)
{
  FILE *fin, *fout;
  char *tmp, *tmp2, *tmp3;
  char *buffer;
  btree *usedtree = NULL;

  /* get form data */
  tmp = getformdata (form);
  if (tmp != NULL && strlen (tmp) > 0)      /* user has specified a form */
    {
      fin = fopen (tmp, "rb");  /* file not found :( */
      if (fin == NULL)
      {
        showoutput (PLAIN);
        putsf ("Error: unable to find %s formating file: %s\n", form, tmp);
        return -1;
      }
      buffer = fileread (fin);
      fclose (fin);
      if (buffer == NULL)
      {
        showoutput (PLAIN);
        putsf ("Error: empty %s formating file: %s\n", form, tmp);
        return -1;
      }
    }
  else
    {
      if (form == FORM)
      buffer = FORMform;
      else if (form == SHOW)
      buffer = SHOWform;
      else if (form == CCFORM)
      buffer = CCFORMform;
      else /* form == EMPTY */
      buffer = EMPTYform;
    }

  /* all the tmpfiles has a name of owebmXXXXXXX.html */
  /* "WARNING"
     you may have to create a link to /tmp directory in your
     httpd document root,
       ln -s /tmp tmp
     To prevent this directory from visible to the outside world,
     create an empty default HTML file in that directory, such as
     .html index.html index.htm default.htm or default.html
     If your system has a periodical program that removes aged
     files, you may have to create another program that touches
     this file regularly.  For instance,
       /bin/touch .html
  */
#ifdef DOS
  tmp = tempnam (getenv ("TEMP"), "owebm");
#else
  tmp = (char *)tempnam ("/tmp", "owebm");
#endif
  sprintf (TMPFILE, "%s.html", tmp);

  free (tmp);
  fout = fopen (TMPFILE, "wb+");
  if (fout == NULL)
    {
      showoutput (PLAIN);
      puts ("Error: unable to create temp file");
      return -1;
    }

  /* now start translating */

  tmp = buffer;        /* this pointer indicate position of last var */
  tmp2 = tmp;          /* this pointer indicate strchr result */
  tmp3 = tmp;          /* this pointer indicate position of last $ */

  if (usedtree == NULL)
    usedtree = addtree (NULL, strdup (http_referer), NULL, NULL);
  addtree (usedtree, strdup (TO), NULL, NULL);
  addtree (usedtree, strdup (NAME), NULL, NULL);
  addtree (usedtree, strdup (EMAIL), NULL, NULL);
  addtree (usedtree, strdup (SUBJECT), NULL, NULL);
  addtree (usedtree, strdup (MESSAGE), NULL, NULL);
  addtree (usedtree, strdup (EMPTYHANDLE), NULL, NULL);
  addtree (usedtree, strdup (MULTIPLE), NULL, NULL);
  addtree (usedtree, strdup (MULTIPLEMARK), NULL, NULL);
  addtree (usedtree, strdup (REDIRECT), NULL, NULL);
  addtree (usedtree, strdup (FORM), NULL, NULL);
  addtree (usedtree, strdup (SHOW), NULL, NULL);
  addtree (usedtree, strdup (EMPTY), NULL, NULL);
  addtree (usedtree, strdup (EMPTYERROR), NULL, NULL);
  addtree (usedtree, strdup (MIME), NULL, NULL);
  addtree (usedtree, strdup (CC), NULL, NULL);
  addtree (usedtree, strdup (CCFORM), NULL, NULL);
  addtree (usedtree, strdup (REPLYNAME), NULL, NULL);

  do
    {
      /* use ${var} pair to identify variable */
      tmp2 = strchr (tmp3, '$');
      if (tmp2 == NULL)
      fputs (tmp, fout); /* nothing found */
      else if (*(char *)(tmp2 + 1) != '{')
      tmp3 = tmp2 + 1;   /* false alarm */
      else
      {
        *tmp2 = '\0';
        fputs (tmp, fout);
        tmp = tmp2;
        tmp3 = tmp2 + 2;
        tmp2 = strchr (tmp3, '}');
        if (tmp2 == NULL) /* another false alarm? */
          {
            *tmp = '{';
            fputs (tmp, fout);
          }
        else
          {
            *tmp2 = '\0';
            if (strcmp (tmp3, "ETC") != 0)
            {
              tmp = getformdata (tmp3);
              /* add env to used list */
              addtree (usedtree, strdup (tmp3), NULL, NULL);
              if (tmp)  /* found the variable */
                fputs (tmp, fout);
            }
            else                               /* found ${ETC} */
            {
              if (linearstart)
                {
                  btree *temp = linearstart;
                  while (temp)
                  {
                    if (intree (usedtree, temp->data) != 0)
                      envhandle (temp, fout);
                    temp = temp->linearnext;
                  }
                }
            }
            tmp = tmp2 + 1;
            tmp3 = tmp;
          }
      }
    }
  while (tmp2 != NULL);

  if (buffer != FORMform && buffer != SHOWform && buffer != EMPTYform &&
      buffer != CCFORMform)
    free (buffer);
  trashtree (usedtree);

  /* end translating */

  /* mime processing */
  if ((form == FORM || form == CCFORM) &&
      strcasecmp (getformdata (MIME), "on") == 0)
    {
      char *ptr;
      buffer = fileread (fout);
      if (buffer)
      {
        ptr = mime_encode (buffer, strlen (buffer));
        if (ptr)
          {
            fseek (fout, 0, SEEK_SET);
            fputs (ptr, fout);
            free (ptr);
          }
        free (buffer);
      }
    }

  fclose (fout);

  return 0;
}

char *fileread (FILE *fin)
{
  char *buffer;
  int length;

  fseek (fin, 0, SEEK_END);
  length = ftell (fin);
  fseek (fin, 0, SEEK_SET);

  buffer = (char *)malloc (length + 1);
  buffer[length] = '\0';

  if (!buffer)
    return NULL;

  fread (buffer, 1, length, fin);
  return buffer;
}

ASKER CERTIFIED SOLUTION
Avatar of chensu
chensu
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of szetoa

ASKER

Let me digest them and will get back to you later.  Thanks.
Avatar of szetoa

ASKER

Thanks chensu and maneshr.