ftp.nice.ch/pub/next/unix/network/www/gform.1.1.NIHS.bs.gnutar.gz#/gform-1.1/gform.c

This is gform.c in view mode; [Download] [Up]

/***
 * gform - A generic HTML form decoder 
 *
 * 	It takes a HTML form file and scans
 *	this file for comments beginning with <!--gform ....>
 *	These are taken to be formatting info and delivery commands
 *	for gform.
 *
 *	See gform.txt for description and samples
 *
 *      Swinburne University of Technology and the author will not be 
 *	responsible for any damages or loss suffered or incurred by 
 *	any user or any other person arising in any way from the use
 *	of this software. No warranty of any kind, either express or
 *	implied is given. You may copy, modify and redistribute it.
 *
 *      Ver 1.1e harry@swin.edu.au 8-Nov-95 Swinburne University
 *
 *	Contibutions:
 *		jem@sunsite.unc.edu University of North Caroline   
 *
 *	See CHANGES for change history.
 ***/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <time.h>
#include <string.h>

#include "config.h"

#define bzero(s,n)	memset(s,0,n)
#include <stdlib.h>

#define LEN	4096
	
/* keywords for gform */ 
#define DELIVER		"DELIVER"	/* indicates delivery method */
#define MAIL		"MAIL"		/* a delivery method */
#define FFILE		"FILE"		/* a delivery method */
#define PRINT		"PRINT"		/* Send to printer */
#define SUBJECT		"SUBJECT"	/* Subject of mail mesg */
#define REPLY		"REPLY"		/* reply to form submission */
#define GFORM_TAG	"<!GFORM "	/* gform command line keyword */
#define GFORM_TAG2	"<!--GFORM "	/* gform command line keyword */

/* commandline parsing states */
#define NSTATE		0	/* NULL state */ 
#define TSTATE		1	/* text string with variables */

#define SKIP_WHITE(a) 	while (isspace(*a)) a++ 

struct entry {
    char *name;
    char *val;
    struct entry *next;
};

/* from cgi-bin/util.c */

char *fmakeword();
char *makeword();
void unescape_url();
void plustospace();
char *tildeexpand();

/* func prototypes */

char *decode_commands();
char *command();
void print_header();
char *strnupr();
void error();
char *insert_value();
char *do_escapes();
int send_to_file();
int isendtag();
char *get_html_filename();
char *get_cmd_val();

struct 	entry *entries, *head;
int 	state, linecount, printit=0;
char 	*outfile, *address, *subject, DEFSUBJECT[256], 
	*queue, *replyfile, *webhome, date[12], ttime[12];

main(argc, argv)
int argc;
char *argv[];
{
     int len,i, line[LEN];
     char s[256], *word, *buf, *tmp, *tmp2, *fname;
     FILE *f1;

     setdate(date, ttime);

     if (strcmp(getenv("REQUEST_METHOD"),"POST")!=0) 
	error("This program should be referenced with the method=POST\n",0);
     if (strcmp(getenv("CONTENT_TYPE"),
		"application/x-www-form-urlencoded")!=0)
	error("This program can only be used to decode forms\n",0);

      
     len = atoi(getenv("CONTENT_LENGTH"));

     entries = NULL; replyfile=NULL; 
     outfile = NULL; subject=NULL; address=NULL;

/* Get document root directory */

	if ((webhome = getenv("DOCUMENT_ROOT"))==NULL) 
#if defined(WEBHOME)
		webhome=WEBHOME;
#endif
	if (webhome==NULL)
		error("Failed to get DOCUMENT_ROOT directory. Define WEBHOME in the config.h file",0);

/* Grab all the variable names and data from the form */
 
     for(i=0;len && (!feof(stdin));i++) {
        
	if (entries) { 
	    entries->next = (struct entry *) malloc(sizeof(struct entry));
	    entries=entries->next;
	} else { 
	    entries = (struct entry *) malloc(sizeof(struct entry));
	    head = entries;
	}

/* stick all the fields of the HTML Form into the entries struct */

        entries->val = fmakeword(stdin,'&',&len);
        plustospace(entries->val);
        unescape_url(entries->val);
        word = (char *) makeword(entries->val, '=');
        entries->name = strnupr(word, strlen(word));

	entries->next=NULL;

     }

/* We now have all the data from the form, now decode the 
   'GFORM' commands from the HTML form file */

     fname = get_html_filename();

     buf = decode_commands(fname);

     sprintf(DEFSUBJECT,"Form [%s] submission" ,fname);

/* Now deliver the results */

     if (outfile)	/* Results to a file */ 
		send_to_file(outfile,buf);
     if (address) 	/* or results thru the mail */
		send_email(address,subject,buf);
     if (printit)	/* straight to a printer */
		send_to_printer(queue, buf);

     if (replyfile) {	/* The HTML file to reply with */

#ifdef USERDIR
		for (tmp2=replyfile; *replyfile=='/'; replyfile++);
		if (*replyfile == '~')  
			tmp2=tildeexpand(replyfile); 
		else {
#endif
			tmp2 = (char *) malloc(strlen(webhome)+strlen(replyfile)+1);
			if (*replyfile=='/') replyfile++;
			sprintf(tmp2,"%s/%s",webhome,replyfile);
#ifdef USERDIR
		}
#endif	
		if ((f1 = fopen(tmp2,"r"))==NULL) {
			sprintf(s,"Opening Replyfile: %s not found",replyfile);
			error(s,0);
		} else {
		        print_header();
			while (fread(line,1,LEN,f1)!=0)
				fprintf(stdout,"%s",line);
		}
	        fclose(f1);		
	} else {	/* A default thank you reply */
		print_header();
		printf("<BODY>");
		printf("<TITLE>Thank you</TITLE>");
		printf("<H3>Thank you</H3>");
		printf("</BODY>");
        }

     return(0);
}
/***
 * decode_commands
 *	Read the HTML form file and look for commands 
 *	Replace variables, translate escaped chars
 *	and return the results
 *
 ***/
char *decode_commands(fname)
char *fname;
{

     FILE *f1;
     int BRACKET=0,j,escape, vl, variable, endvar=0;
     char line[LEN], *commandline,*start, *end, *trace,
	  *word,
	  msg[64], tmp[256],
	  *buf,		/* The buf of formatted output */ 
	  *vp,
	  *p,
	  ch;

     if ((f1 = fopen(fname,"r")) == NULL) {
#ifdef USERDIR
	   sprintf(tmp,"File not found: %s",fname); 
#else
	   sprintf(tmp,"File not found: %s<BR>('~' expansion not enabled)",fname); 
#endif

	   error(tmp,0);

     }

     linecount=0; 
     buf = (char *) malloc(1); 
     *buf=0;

     bzero(line, LEN);

     while (fgets(line,LEN, f1) !=NULL) {
	linecount++;
	state=NSTATE;

	if (!(commandline = command(line))) continue;

/* fixup any escaped chars */

	commandline = do_escapes(commandline);

	SKIP_WHITE(commandline);

/* A formatting command line */

	if ((state==NSTATE) && (*commandline == '"')) { 
	    state = TSTATE;
	    start = commandline+1;
	    trace=start; end=NULL;

	    variable=0; escape=0;
		
		for (;*trace && !end;trace++) {
		if (*trace=='"') { 
			end = trace;
			*trace=0;
			if (variable) {
				variable=0; start=trace;	
				buf = insert_value(buf,vp,vl);
			} else {
			    buf = (char *) realloc(buf, strlen(buf)+
				(trace-start)+1);
			    strncat(buf, start , (trace-start));
			}
			state=NSTATE;
			if (BRACKET)
				error("Missing bracket",linecount);

		} else if (variable && *trace == ')') { 
			BRACKET--;	 
			endvar=1;	
			vl--;
		} else if (variable) {
			if ((isspace(*trace) || end || endvar) && !BRACKET) {
				variable=0; start=trace;	
				buf = insert_value(buf,vp,vl);
				endvar=0;
			} else
			 	vl++;
		} else if (*trace=='$') { 
			variable=1; vl=0;
			vp = trace+1;
			if (*vp == '(') {
				vp++;
				BRACKET++;
			}
			buf = (char *) realloc(buf, strlen(buf) + 
			      (trace-start)+1);
			strncat(buf, start , (trace-start));
			start = vp;
		}

	     }
	 } 		/* end of formatting command lines */
	 else 		/* now check command keywords */
	      if (state==NSTATE) { 
		if (strcmp(strnupr(commandline,strlen(DELIVER)),
			    DELIVER)==0) {
			commandline=commandline+strlen(DELIVER);

			SKIP_WHITE(commandline);

			if (*commandline != '=') 
				error("Missing '='",linecount);
			commandline++;

			SKIP_WHITE(commandline);

/* Handle the FILE delivery command */

			if (strcmp(strnupr(commandline,strlen(FFILE)),FFILE)==0) {
				commandline=commandline+strlen(FFILE);

				SKIP_WHITE(commandline);

				if (*commandline !='"')
					error("\" Expected ",linecount);
				else 
				    outfile=get_cmd_val(commandline);
				state=NSTATE;

/* Handle the PRINT delivery command */

			} else if (strcmp(strnupr(commandline,strlen(PRINT)),PRINT)==0) {
				commandline=commandline+strlen(PRINT);

				SKIP_WHITE(commandline);

				if (isendtag(commandline))
					queue=0;
				else if (*commandline !='"')
					error("\" Expected ",linecount);
				else
				   queue = get_cmd_val(commandline);
				printit=1;
				state=NSTATE;

/* Handle the MAIL delivery command */

			} else if (strcmp(strnupr(commandline, strlen(MAIL)),MAIL)==0) {
				commandline=commandline+strlen(MAIL);

				SKIP_WHITE(commandline);
			        
				if (*commandline!='"')
					error("\" Expected ",linecount);
				else {
				   address=get_cmd_val(commandline);
				   commandline+=strlen(commandline)+1;
				}
				SKIP_WHITE(commandline);

				if (strcmp(strnupr(commandline,strlen(SUBJECT)),SUBJECT)==0) {
				     commandline=commandline+strlen(SUBJECT);
				     SKIP_WHITE(commandline);

				     if (*commandline!='=')
				     	     error("= Expected",linecount);
				     commandline++;	

				     SKIP_WHITE(commandline);

				     if (*commandline!='"')
					     error("\" Expected ",linecount);
				     else 
					     subject=get_cmd_val(commandline);
				} else 
				    subject=DEFSUBJECT;	
				state=NSTATE;
			} else {
				sprintf(msg,"Expected %s, %s or %s\n",
					FFILE, PRINT, MAIL);
				error(msg, linecount);	
			}
/* Handle REPLY command */

			} else if (strcmp(strnupr(commandline,strlen(REPLY)), REPLY)==0) {
				commandline=commandline+strlen(REPLY);

		       		 SKIP_WHITE(commandline);
		
				if (*commandline != '=') 
					error("Missing '='",linecount);
				commandline++;

		       		 SKIP_WHITE(commandline);
			
				if (*commandline != '"') 
					error("\" Expected ",linecount);
				else 
					replyfile=get_cmd_val(commandline);
				state=NSTATE;
			} else
				error("Commandline syntax, check \"",linecount);
	     	}
		if (state==TSTATE)
			error("Missing \"",linecount);

	        bzero(line, LEN);
	} /* end of lines */
	fclose(f1);

/* Handle Escaped '$' and '"' that have been turned into
   char 1 and 2 with do_escapes(). Handled last as not to interfere
   with the parsing of commandline
*/ 
	for (j=0;j<strlen(buf);j++)
		if (*(buf+j)==1)
			*(buf+j) = '$';
		else if (*(buf+j)==2)
			*(buf+j) = '"';
	return(buf);	    
}
/** 
 * insert_value
 * 	replace a variable with its value
 *
 **/
char *insert_value(buf, vp, vl)
char *buf, *vp;
int vl;
{

	char *word, msg[64], *envvar;
	int hit=0;

	word = strnupr(vp,vl);
	entries=head;
	while (entries) {
		if (strcmp(word,entries->name)==0) {
			
		    buf = (char *) realloc(buf,strlen(buf) + strlen(entries->val)+4);	/* 3 is to allow for ", " when multiple results */


	            if (hit) 
			strcat(buf,", ");

		    strcat(buf,entries->val);
		    hit++;
		}
		entries=entries->next;
	}

/* if variable is not found in the list of variables, try environement
   variables */

	if (!hit) 
		if (strcmp(word, "DATE")==0) {
		    buf = (char *) realloc(buf,strlen(buf) +
				 strlen(date)+1);	
		    strcat(buf, date);
		} else if (strcmp(word,"TIME")==0) {
		    buf = (char *) realloc(buf,strlen(buf) +
				 strlen(ttime)+1);	
		    strcat(buf, ttime);
		} else if ((envvar = getenv(word))!=NULL) {
		    buf = (char *) realloc(buf,strlen(buf) +
				 strlen(envvar)+1);	
	            strcat(buf, envvar);
		} else {	/* Nothing found */
			buf = (char *) realloc(buf, strlen(buf) + 5);
			strcat(buf,"null");
		}

	return(buf);
}

/***
 * do_escapes 
 *	Replaces all escaped chars with actual char its escaped.
 *
 ***/


char* strdup(s)
{
  unsigned long len;
  char* copy = NULL;
  
  if (s == NULL)		/* saftey check to postpone stupid errors */
    return(NULL);
    
  len = strlen(s);		/* length of string - terminator */
  copy = (char*)malloc((size_t)(sizeof(char)*(len + 1)));
  strncpy(copy,s,len + 1);
  return(copy);
}


char *do_escapes(line)
char *line;
{

	char *p, *tmp, *top;

	p = strdup(line);

	if ((tmp = (char *) malloc(2 * strlen(line)))==NULL)
		return(NULL);

	top = tmp;	
	while (*p) {
		if (*p=='\\') {
			p++;
			switch (*p) {
			  case 'n' : *p = 10; break;
			  case 't' : *p = 8; break;
			  case 'r' : *p = 13; break;
			  case 'f' : *p = 12; break;
			  case '$' : *p = 1; break;   /* special case */
			  case '"' : *p = 2; break;   /* special case */
			}
		}
		*(tmp++) = *(p++);
	}	
	return(top);
}

/***
 * command
 *	Looks for a 'gform' commandline.
 *	Returns the uppercase commandline (less the leading command tag
 *	or NULL if it is not a commandline.
 *	For backword compatibility, the old GFORM_TAG is still supported
 *	but not really correct.
 *
 ***/
char *command(line)
char *line;
{

	char *commandline, *word, *word2;

	word = strnupr(line,strlen(GFORM_TAG));
	word2 = strnupr(line,strlen(GFORM_TAG2));

	if (strncmp(GFORM_TAG, word,strlen(GFORM_TAG))==0) {
		commandline=line+strlen(GFORM_TAG);
		return(commandline);
	} else if (strncmp(GFORM_TAG2, word2,strlen(GFORM_TAG2))==0) {
		commandline=line+strlen(GFORM_TAG2);
		return(commandline);
	} else
	   return(NULL);
}

/***
 * send_to_file
 *	Send buffer to a file
 *
 ***/
int send_to_file(fname, buf)
char *fname, *buf;
{
	FILE *f;

	if ((f = fopen(fname,"a")) == NULL)
		return(0);

	fprintf(f,"%s",buf);

	fclose(f);
	return(1);
}

/***
 * print_header
 *	Prints the required header for http stuff 
 *
 ***/	
void print_header()
{

	printf("Content-type: text/html\n\n");

	return;
}
/***
 * strnupr
 *	takes a character string and converts 'len' into
 *	uppercase. It then returns a pointer to the uppercase
 *	chars.
 ***/
char *strnupr(line, len)
char *line;
int len;
{
	int i;
	char *newline;

	newline = (char *) malloc(len + 1);

	for (i=0;i<len;i++)
		*(newline+i) = toupper(line[i]);		
	*(newline+len) = '\0';
	
	return(newline);
}

/***
 * isendtag(cgar *p)
 *	Returns 1 if p is pointing to an end-of-comment tag
 *
 ***/
int isendtag(p)
char *p;
{
	char *q = p;

	if (q) {
		if (*q=='-' && q+1 && *(q+1)=='-' && q+2) {
			q+=2;
			SKIP_WHITE(q);	
		}
		if (*q=='>')
			return(1);
	}
	return(0);
}

/***
 * get_html_filename()
 *	Returns the filename of the FORM that called us.
 *
 ***/
char *get_html_filename()
{
	static char http[]="HTTP://";
	char *tmp, *path, *p, *uref, *referer = getenv("HTTP_REFERER");
	char s[256];
	struct stat fstat;

	if (referer==NULL) {	
		referer=getenv("QUERY_STRING");
		if (referer==NULL)
			error("Could not get environment", 0);
	}

	p = referer;
        if (strlen(referer)>6) {
		uref = strnupr(referer,7);
		if (strncmp(http,uref,7)==0) {
			p = referer+7;	
			while (p && *p!='/') p++; /* skip host */
			p++;
		} 
	}

	for (tmp=p; *p=='/'; p++);
#ifdef USERDIR

	if (*p=='~') {
		tmp=tildeexpand(p);
		if (!tmp) {
			sprintf(s,"Unable to expand: %s",p);	
			error(s,0);
		} else if (stat(tmp,&fstat)) {
			sprintf(s,"File not Found: %s",tmp);
			error(s,0);
		}
		return(tmp);
	} else {
#endif
		path = (char *) malloc(strlen(webhome)+ 
			(tmp==NULL ? 0: strlen(tmp)) + 2);
		sprintf(path, "%s/%s",webhome, tmp);
		return(path);
#ifdef USERDIR
	}
#endif
}

/*** 
 * get_cmd_val(string)
 *	Returns a string between quotes , less the quotes
 *
 ***/
char *get_cmd_val(s)
char *s;
{
	char *p;

	p = s+1;
	while (*p && *p!='"') p++; 
	if (!*p)
		error("\" Expected ",linecount);
	*p=0;

	return(s+1);
}
/***
 * setdate()
 *
 *	Sets 2 variables to the current date and time 
 *
 ***/

setdate(date, ttime)
char *date, *ttime;
{

	time_t t;	
	struct tm *ttm;
	static char *months[]={"Jan", "Feb", "Mar", "Apr", "May", "Jun",
			"Jul", "Aug","Sep","Oct","Nov","Dec" };

	t=time(0);
	ttm = localtime(&t);

	sprintf(ttime, "%.2d:%.2d:%.2d",ttm->tm_hour, ttm->tm_min,ttm->tm_sec);
	sprintf(date,"%2d-%s-%2d",ttm->tm_mday, months[ttm->tm_mon],ttm->tm_year);

}

/***
 * error
 *	Prints a simple error message back to the user 
 *
 ***/
void error(msg, linecount)
char *msg;
int linecount;
{
	print_header();

	if (linecount)
	    printf("<P>gform: Error (line %d) %s<P>\n",linecount,msg);
	else
	    printf("<P>gform: Error %s<P>\n",msg);

	exit(1);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.