
/* echoer.c */
/* Andrew Davison (ad@ratree.psu.ac.th) */
/* December 1996 */
/* Modified January 2000 */

/* Echo the name=value pairs posted from the form:
      http://fivedots.coe.psu.ac.th/~ad/eform.html

   Compiled code placed in:
      ~ad/cgi-bin which is really
      /usr/lib/cgi-bin/ad/
*/
/* Some of the HTML utilities were written by Rob McCool */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BKGROUND "http://fivedots.coe.psu.ac.th/~ad/chalk.jpg"
#define MAX_ENTRIES 5   /* max number of input fields */
#define MAXLEN 300      /* max length of a string */
#define NOVAL "$$no-value$$"    /* when no value is found */

typedef struct {       /* for form nameString=valueString pairs */
    char *name;
    char *val;
} entry;


/* Standard Form Functions */
void start_reply(char *title);
void cgi_errs();
int build_entries(entry entries[]);
char *find_value(entry entries[], int etnum, char *name);

/* Debugging Utilities */
int input_entries(entry entries[]);
void show_entries(entry entries[], int etnum);

/* CGI utilities written by Rob McCool */
char *makeword(char *line, char stop);
char *fmakeword(FILE *f, char stop, int *len);
void unescape_url(char *url);
char x2c(char *what);
void plustospace(char *str);


int main()
{
  entry entries[MAX_ENTRIES];
  int etnum = 0;

  start_reply("Query Result");

  cgi_errs();
  etnum = build_entries(entries);
/*
  etnum = input_entries(entries); 
*/
  show_entries(entries, etnum);

  return 0;
}



/* Standard Form Functions */

void start_reply(char *title)
/* Output the HTML header, including the title and H1 container */
{
  printf("Content-type: text/html\n\n");
  printf("<html><head><title>%s</title></head>\n", title);
  printf("<body background=\"%s\">", BKGROUND);
  printf("<H1 align=center>%s</H1>\n", title);
  fflush(NULL);   /* force output to occur now */
}


void cgi_errs()
/* Check for errors in the REQUEST_METHOD and CONTENT_TYPE
   environment variables.
*/
{
  if(strcmp(getenv("REQUEST_METHOD"),"POST")) {
    printf("<P>This script should be referenced with a METHOD of POST.\n");
    printf("If you don't understand this, read ");
    printf("<A HREF=\"http://www.ncsa.uiuc.edu/SDG/Software/Mosaic/Docs/fill-out-forms/overview.html\">forms overview</A>.</P>\n");
    printf("</body></html>\n");
    exit(1);
  }
  if(strcmp(getenv("CONTENT_TYPE"), "application/x-www-form-urlencoded")) {
    printf("<P>This script can only be used to decode form results.</P>\n");
    printf("</body></html>\n");
    exit(1);
  }
}


int build_entries(entry entries[])
/* Fill in the entries array with nameString=valueString 
   pairs from the form. 
*/
{
  int len, i;

  len = atoi(getenv("CONTENT_LENGTH"));
  for(i=0; len && (!feof(stdin)) && (i < MAX_ENTRIES); i++) {
    entries[i].val = fmakeword(stdin,'&',&len);
    plustospace(entries[i].val);
    unescape_url(entries[i].val);
    entries[i].name = makeword(entries[i].val,'=');
  }
  return i;  
}


char *find_value(entry entries[], int etnum, char *name)
/* Search through the entries array for a name string 
   which matches name and return its associated value 
   string. Otherwise return NOVAL.
*/
{
  int i;
  char *value;

  for(i=0; i < etnum; i++)
    if (strcmp(entries[i].name, name) == 0) {
      value = (char *)malloc(sizeof(char)*(strlen(entries[i].val)+1));
      strcpy(value, entries[i].val);
      break;
    }
  if ((i == etnum) || (value[0] == '\0')) {
    value = (char *)malloc(sizeof(char)*(strlen(NOVAL)+1));
    strcpy(value, NOVAL);
  }
  return value;
}



/* Debugging Utilities */

int input_entries(entry entries[])
/* Fill in the entries array with nameString=valueString pairs 
   entered by the user at the keyboard.
   Each pair should be entered in the format:
      nameString=valueString
   Terminate the input with <ctrl>d
*/
{
  int num = 0, namelen, linelen;
  char line[MAXLEN];

  printf("\nEnter name=value pairs:\n\n");

  while (fgets(line, MAXLEN, stdin) && (num < MAX_ENTRIES)) {
    linelen = strlen(line);
    namelen = strcspn(line, "=");
    entries[num].name =
      (char *)malloc(sizeof(char)*(namelen+1));
    strncpy(entries[num].name, line, namelen);
    entries[num].name[namelen] = '\0';
    entries[num].val =
      (char *)malloc(sizeof(char)*(linelen-namelen));
    strcpy(entries[num].val, &line[namelen+1]);
    num++;
  }
  return num;
}


void show_entries(entry entries[], int etnum)
/* Output the nameString=valueString pairs as an HTML 
   unnumbered list */
{
  int x;

  printf("<P>You submitted these nameString=valueString pairs:</P>\n");
  printf("<ul>\n");
  for(x=0; x < etnum; x++)
    printf("<li><code>%s = %s</code>\n", entries[x].name, entries[x].val);
  printf("</ul>\n");
  printf("</body></html>\n");
}



/* CGI Utilities by Rob McCool; 
   comments by Andrew Davison */

char *makeword(char *line, char stop) 
/* Builds a word by extracting characters from line up to the
   stopping character in stop (or until line is exhausted).
*/
{
  int x = 0, y = 0;
  char *word = (char *) malloc(sizeof(char) * (strlen(line) + 1));

  for(x=0; ((line[x]) && (line[x] != stop)); x++)
     word[x] = line[x];
  word[x] = '\0';
  if(line[x]) 
    ++x;
  while((line[y++] = line[x++]));
  return word;
}


char *fmakeword(FILE *f, char stop, int *len) 
/* Similar to makeword(): builds a word by extracting characters 
   from the file f up to the stopping character in stop (or
   until f is exhausted). The function is also supplied with
   the length of the string (len) left unread in f.
*/
{
  int wsize = 102400, ll = 0;
  char *word = (char *) malloc(sizeof(char) * (wsize + 1));

  while(1) {
    word[ll] = (char)fgetc(f);
    if(ll == wsize) {
       word[ll+1] = '\0';
       wsize += 102400;
       word = (char *)realloc(word,sizeof(char)*(wsize+1));
    }
    --(*len);
    if((word[ll] == stop) || (feof(f)) || (!(*len))) {
       if(word[ll] != stop) ll++;
       word[ll] = '\0';
       return word;
    }
    ++ll;
  }
}


void unescape_url(char *url) 
/* Convert the hexadecimal characters in url into ASCII.
   They are detected by starting with a '%'.
*/
{
  register int x, y;

  for(x=0,y=0; url[y]; ++x,++y) {
    if((url[x] = url[y]) == '%') {
      url[x] = x2c(&url[y+1]);
      y+=2;
    }
  }
  url[x] = '\0';
}


char x2c(char *what) 
/* Convert the hexadecimal (consisting of two characters) into
   a single ASCII character.
*/
{
  register char digit;

  digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
  digit *= 16;
  digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
  return(digit);
}


void plustospace(char *str) 
/* Replace '+'s by spaces in str */
{
  register int x;

  for(x=0; str[x]; x++) 
    if(str[x] == '+') str[x] = ' ';
}


