Listing 2: A CGI program that sends email

/* formtest.cgi.c */

char *Name = NULL;
char *Prod = NULL;
char *Rush = NULL;

/*------------------------------------------*
 * CGI program processes orders from the    *
 * Web form page.                           *
 *------------------------------------------*/

int main() {
  checkInputHdr();
  getNameValuePairs();
  if (sendReply() && Rush != NULL)
    sendMail();
  return 0;
}

/*------------------------------------------*
 * This step is just a formality, since the *
 * server will always get this stuff right. *
 * I guess someone might try to use this    *
 * program for something else (?) in which  *
 * case it will bomb.                       *
 *------------------------------------------*/

void checkInputHdr (void) {
  /* This function checks for a             *
   * REQUEST_METHOD of "post" and the       *
   * correct CONTENT_TYPE.                  */
}

/*------------------------------------------*
 * Read the NAME/VALUE pairs from the form  *
 * and put them into into a linked list for *
 * later.                                   *
 *------------------------------------------*/

void getNameValuePairs (void) {
    
  /* As suggested, this function gets       *
   * name/value pairs as global variables   *
   * and also saves them in a log file. The *
   * real program calls a few other         *
   * functions that I have also omitted     *
   * here.                                  */

}

/*------------------------------------------*
 * Send the top part of the reply page,     *
 * then check a few things and issue either *
 * a message or an acknowledgement, then    *
 * send the rest of the page.               *
 *------------------------------------------*/

int sendReply (void) {
  int ok = TRUE; /* error code */

  /* send top part of page */
  printf ("Content-type: text/html\n\n");
  printf ("<html> <head> <title>\n");
  printf ("CGI send mail test\n");
  printf ("</title> </head>\n");
  printf ("<body> <center>\n");

  /* do a simple validation */

  if (Name == NULL) {
    printf ("<h1> Name required </h1>");
    ok = FALSE;
  }

  /* send appropriate message */

  if (ok) {
    printf ("<h1> Thanks for \n");
    printf ("your order </h1>\n");
  } else {
    printf ("<h1> Resubmit form </h1>");
  }

  /* send the message trailer */

  printf ("</center>\n");
  printf ("</body>\n");
  printf ("</html>\n");

  return ok;
}

/*------------------------------------------*
 * Flush standard output, so user sees all  *
 * HTML. Create pipe then fork child to     *
 * exec sendmail. Parent writes to pipe as  *
 * stdout and child reads from pipe as      *
 * stdin.                                   *
 *------------------------------------------*/

void sendMail (void) {
  int pfd [2];
  if (fflush (stdout) == EOF)
    err ("Can't flush stdout");
  if (pipe (pfd) == -1)
    err ("Can't open pipe");
  switch (fork()) {
  case 0:
    child (pfd);
    break;
  default:
    parent (pfd);
    break;
  }
}

/*------------------------------------------*
 * Child process closes writing end of      *
 * pipe, closes stdin and dup's reading end *
 * of pipe, so it becomes child's stdin. It *
 * then closes reading end of pipe and      *
 * exec's sendmail, which ends up reading   *
 * from pipe (which by now is connected to  *
 * parent's stdout.                         *
 *------------------------------------------*/

void child (int *pfd) {
  if (close (pfd [1]) == -1)
    err ("Child can't close pfd [1]");
  if (close (0) == -1)
    err ("Child can't close stdin");
  if (dup (pfd [0]) != 0)
    err ("Child can't dup stdin");
  if (close (pfd [0]) == -1)
    err ("Child can't close pfd [0]");
  execl (MAIL, MAILTO, (char *)0);
  err ("exec failed");
}

/*------------------------------------------*
 * Parent closes reading end of pipe,       *
 * closes its stdout and dup's writing      *
 * end of the pipe, so it becomes stdout.   *
 * After closing the writing end of pipe it *
 * sends mail text to stdout.               *
 *------------------------------------------*/

void parent (int *pfd) {

  /* make the pipe into stdout */

  if (close (pfd [0]) == -1)
    err ("Parent can't close pfd [0]");
  if (close (1) == -1)
    err ("Parent can't close stdout");
  if (dup (pfd [1]) != 1)
    err ("Parent can't dup stdout");
  if (close (pfd [1]) == -1)
    err ("Parent can't close pfd [1]");

  /* send the message */

  printf ("To: Expediter\n");
  printf ("From: Web_Server\n");
  printf ("Subject: Rush Order\n");
  printf ("\n");
  printf ("Process the following "
          "order immediately:\n\n");
  printf ("Name: %s\n", Name);
  printf ("Product: %s\n", Prod);
  printf ("\n");
}
/* End of File */