/*******************************************************************************
        post.c
        Z-World, 2000

        This program accepts and parses POST style form submission, to
        get information from the user.
*******************************************************************************/

/***********************************
 * Configuration                   *
 * -------------                   *
 * All fields in this section must *
 * be altered to match your local  *
 * network settings.               *
 ***********************************/

/*
 * You must change the following values to whatever
 * your local IP address and netmask are. Contact your
 * network administrator for these numbers.
 */
#define MY_IP_ADDRESS   "10.10.6.100"
#define MY_NETMASK      "255.255.255.0"

/*
 * Web server configuration
 */

/*
 * Only one server is needed for a reserved port
 */
#define HTTP_MAXSERVERS 1
#define MAX_TCP_SOCKET_BUFFERS 1

/*
 * Our web server as seen from the clients.
 * This should be the address that the clients (netscape/IE)
 * use to access your server. Usually, this is your IP address.
 * If you are behind a firewall, though, it might be a port on
 * the proxy, that will be forwarded to the Rabbit board. The
 * commented out line is an example of such a situation.
 */
#define REDIRECTHOST		MY_IP_ADDRESS
//#define REDIRECTHOST	"proxy.domain.com:1111"

/********************************
 * End of configuration section *
 ********************************/

#define REDIRECTTO      "http://" REDIRECTHOST "/index.shtml"

#memmap xmem
#use "dcrtcp.lib"
#use "http.lib"

#ximport "samples/tcpip/http/pages/form.html"      index_html

/* the default for / must be first */
const HttpType http_types[] =
{
   { ".shtml", "text/html", shtml_handler}, // ssi
   { ".html", "text/html", NULL},           // html
   { ".cgi", "", NULL},                     // cgi
   { ".gif", "image/gif", NULL}
};

#define MAX_FORMSIZE	64
typedef struct {
	char *name;
	char value[MAX_FORMSIZE];
} FORMType;
FORMType FORMSpec[2];

/*
 * Parse one token 'foo=bar', matching 'foo' to the name field in
 * the struct, and storing 'bar' into the value
 */
void parse_token(HttpState* state)
{
	auto int i, len;

	for(i=0; i<HTTP_MAXBUFFER; i++) {
		if(state->buffer[i] == '=')
			state->buffer[i] = '\0';
	}
	state->p = state->buffer + strlen(state->buffer) + 1;
	
	for(i=0; i<(sizeof(FORMSpec)/sizeof(FORMType)); i++) {
		if(!strcmp(FORMSpec[i].name,state->buffer)) {
			len = (strlen(state->p)>MAX_FORMSIZE) ? MAX_FORMSIZE - 1: strlen(state->p);
			strncpy(FORMSpec[i].value,state->p,1+len);
			FORMSpec[i].value[MAX_FORMSIZE - 1] = '\0';
		}
	}
}

/*
 * parse the url-encoded POST data into the FORMSpec struct
 * (ie: parse 'foo=bar&baz=qux' into the struct
 */
int parse_post(HttpState* state)
{
	auto int retval;

	while(1) {
		retval = sock_fastread(&state->s, state->p, 1);
		if(0 == retval) {
			*state->p = '\0';
			parse_token(state);
			
			return 1;
		}

		/* should this only be '&'? (allow the eoln as valid text?) */
		if((*state->p == '&') || (*state->p == '\r') || (*state->p == '\n')) {
			/* found one token */
			*state->p = '\0';
			parse_token(state);
			
			state->p = state->buffer;
		} else {
			state->p++;
		}
			
		if((state->p - state->buffer) > HTTP_MAXBUFFER) {
			/* input too long */
			return 1;
		}
	}

	return 0; /* end of data - loop again to give it time to write more */
}

/*
 * Sample submit.cgi function
 */
int submit(HttpState* state)
{
	auto int i;
	
	if(state->length) {
		/* buffer to write out */
		if(state->offset < state->length) {
			state->offset += sock_fastwrite(&state->s,
					state->buffer + (int)state->offset,
					(int)state->length - (int)state->offset);
		} else {
			state->offset = 0;
			state->length = 0;
		}
	} else {
		switch(state->substate) {
		case 0:
			strcpy(state->buffer, "HTTP/1.0 200 OK\r\n\r\n");
			state->length = strlen(state->buffer);
			state->offset = 0;
			state->substate++;
			break;

		case 1:
			strcpy(state->buffer, "<html><head><title>Results</title></head><body>\r\n");
			state->length = strlen(state->buffer);
			state->substate++;
			break;
			
		case 2:
			/* init the FORMSpec data */
			FORMSpec[0].value[0] = '\0';
			FORMSpec[1].value[0] = '\0';

			state->p = state->buffer;
			state->substate++;
			break;

		case 3:
			/* parse the POST information */
			if(parse_post(state)) {
				sprintf(state->buffer, "<p>Username: %s<p>\r\n<p>Email: %s<p>\r\n",
					FORMSpec[0].value, FORMSpec[1].value);
				state->length = strlen(state->buffer);						
				state->substate++;
			} else {
			}
			break;

		case 4:
			strcpy(state->buffer, "<p>Go <a href=\"/\">home</a></body></html>\r\n");
			state->length = strlen(state->buffer);
			state->substate++;
			break;

		default:
			state->substate = 0;
			return 1;
		}
	}

	return 0;
}

const HttpSpec http_flashspec[] = 
{
   { HTTPSPEC_FILE, 	"/",		index_html,    NULL, 0, NULL, NULL},
   { HTTPSPEC_FILE, 	"/index.html",	index_html,    NULL, 0, NULL, NULL},
   { HTTPSPEC_FUNCTION,	"/submit.cgi",		 0,  submit, 0, NULL, NULL}
};

main()
{
	/* init FORM searchable names - must init ALL FORMSpec structs! */
	FORMSpec[0].name = "user_name";
	FORMSpec[1].name = "user_email";
	
	sock_init();
	http_init();
	tcp_reserveport(80);
		
	while (1) {
		http_handler();
	}
}

#nodebug