/*******************************************************************
Guestbook app

	This serves up a webpage to sign a guestbook.  Usernames and
	messages are printer to the receipt printer.

 2002.02.10 (rb) works on the dev board, drops some letters :-(
******************************************************************/

#define MAX_UDP_SOCKET_BUFFERS 2

// Network Settings
#define DHCP_CLASS_ID "Rabbit-TCPIP:Z-World:DHCP-Test:1.0.0"
#define DHCP_NUM_SMTP 1		// Get an SMTP server if possible
#define USE_DHCP			// Main define to cause BOOTP or DHCP to be used.
#define DHCP_MINRETRY 5		// Min DHCP retry interval (secs).  If not defined, defaults to 60.
#define MY_IP_ADDRESS	"10.10.6.100"
#define MY_NETMASK		"255.255.255.0"
#define MY_GATEWAY		"10.10.6.1"
#define HTTP_PORT 80

// Web Server Settings
#define HTTP_MAXSERVERS 1
#define MAX_TCP_SOCKET_BUFFERS 1

// Library Setup
#memmap xmem
#use "dcrtcp.lib"
#use "http.lib"

/*******************************************************************
   Network Utility Functions
 ******************************************************************/
//print out useful network information
static void print_results(){
	auto long tz;
	printf("Network Parameters:\n");
	printf("  My IP Address = %08lX\n", my_ip_addr);
	printf("  Netmask = %08lX\n", sin_mask);
	if (_dhcphost != ~0UL) {
		if (_dhcpstate == DHCP_ST_PERMANENT) {
			printf("  Permanent lease\n");
		} else {
			printf("  Remaining lease = %ld (sec)\n", _dhcplife - SEC_TIMER);
			printf("  Renew lease in %ld (sec)\n", _dhcpt1 - SEC_TIMER);
		}
		printf("  DHCP server = %08lX\n", _dhcphost);
		printf("  Boot server = %08lX\n", _bootphost);
	}
	if (gethostname(NULL,0))
		printf("  Host name = %s\n", gethostname(NULL,0));
	if (getdomainname(NULL,0))
		printf("  Domain name = %s\n", getdomainname(NULL,0));
	if (dhcp_get_timezone(&tz))
		printf("  Timezone (fallback only) = %ldh\n", tz / 3600);
	else
		printf("  Timezone (DHCP server) = %ldh\n", tz / 3600);
	if (_last_nameserver)
		printf("  First DNS = %08lX\n", def_nameservers[0]);
	if (_smtpsrv)
		printf("  SMTP server = %08lX\n", _smtpsrv);
}
//grab a DCHP address
static int init_DHCP(){
	int status;
	_survivebootp = 1;// Set to 1 (default) or 0 to never use fallbacks
	_bootptimeout = 6;// Short timeout for testing
	printf("Starting network (max wait %d seconds)...\n", _bootptimeout);
	status = sock_init();
	switch (status) {
		case 1:
			printf("! Could not initialize packet driver.\n");
			return 0;
		case 2:
			printf("! Could not configure using DHCP.\n");
			break;	// continue with fallbacks
		case 3:
			printf("! Could not configure using DHCP; fallbacks disallowed.\n");
			return 0;
		default:
			break;
	}
	if (_dhcphost != ~0UL)
		printf("Lease obtained\n");
	else {
		printf("! Lease not obtained.  DHCP server may be down.\n");
		printf("! Using fallback parameters...\n");
		return 0;
	}
	print_results();
	return 1;
}

/*******************************************************************
   Webserver Setup
 ******************************************************************/
//the file types, default 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},
   { ".jpg", "image/jpeg", NULL}
};
//for cgi queries
#define MAX_FORMSIZE	512
typedef struct {
	char *name;
	char value[MAX_FORMSIZE];
} FORMType;
//the Form object for the CGI
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((sock_type *)&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 */
}

/*******************************************************************
   Webpage Setup
 ******************************************************************/
char userNameBuffer[512];
char msgBuffer[512];
int newMsg;
//the webpage files
#ximport "index.html"			index_html
//the cgi reply function
int submit(HttpState* state)
{
	auto int i;
	char fixedbuffer1[512];
	char fixedbuffer2[512];
	if(state->length) {
		/* buffer to write out */
		if(state->offset < state->length) {
			state->offset += sock_fastwrite((sock_type *)&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>Guestbook Signed</title></head><body><link rel=\"stylesheet\" type=\"text/css\" href=\"http://www.instituteofthefuture.org/misc/misc.css\"><center><table border=0 cellpadding=8 cellspacing=1 width=600>");
			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(fixedbuffer1,"%s  \0",FORMSpec[0].value);
				http_urldecode(userNameBuffer,fixedbuffer1, 512);
				sprintf(fixedbuffer1,"%s  \0",FORMSpec[1].value);
				http_urldecode(msgBuffer,fixedbuffer1, 512);
				sprintf(state->buffer, "<tr valign=\"top\"><td class=\"header\">Sign my Guestbook</td></tr><tr valign=\"center\" bgcolor=\"#FFFFFF\"><td class=\"body\"><br><p class=\"body\"><b>%s</b>, thank you for your message (%d bytes).</p><br>",
					userNameBuffer,strlen(FORMSpec[1].value));
				//newmessage = 1;
				state->length = strlen(state->buffer);
				state->substate++;
				newMsg = 1;
			} else {
			}
			break;

		case 4:	
			strcpy(state->buffer, "</td></tr><tr valign=\"top\"><td align=\"right\"><a href=\"http://www.instituteofthefuture.org/\"><img src=\"http://www.instituteofthefuture.org/images/logo-wide.gif\" border=0></a></td></tr></table></center></body></html>");
			state->length = strlen(state->buffer);
			state->substate++;
			break;

		default:
			state->substate = 0;
			return 1;
		}
	}
	return 0;
}
//the file system using these files...
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}
};


/*******************************************************************
   Recipt Printer Functions
 ******************************************************************/
#define N_STROBE PEB0R
#define DATA_PORT PADR 
#define DATA_PORT_SHADOW PADRShadow

static void init_ports() {
	//set PA0:PA7 as outputs (Data0:Data7), disable slave port
	WrPortI(SPCR, & SPCRShadow, 0x84);
	//set PE0 for output (~Strobe)
	WrPortI(PEDDR, & PEDDRShadow, 0x01 | PEDDRShadow);
	WrPortI(PEFR, & PEFRShadow, 0x00);
	//set PC1 (~Acknowledge) and PC3 (Busy) for input
	//WrPortI(PCFR, & PCFRShadow, ~((1<<3)|(1<<1)) & PCFRShadow);
}

static void print_char(char c){
	int i;
	//put the data on the lines
	WrPortI(DATA_PORT, & DATA_PORT_SHADOW, c);
	//toggle ~Strobe (delay must be > 5us)
	WrPortI(N_STROBE, NULL, 0x00);
	WrPortI(N_STROBE, NULL, 0xFF);
}

static void print_str(char* str){
	int i;
	for(i=0;i<strlen(str);i++){
		print_char(str[i]);
	}
}

/*******************************************************************
   Program Code
 ******************************************************************/
main() {
	//network variables
	char ipstr[20];

	init_ports();

	//network initialization
	if(!init_DHCP()) return 0;

	//web server setup
	FORMSpec[0].name = "user_name";
	FORMSpec[1].name = "user_msg";
	strcpy(ipstr," IP ");
	inet_ntoa(&(ipstr[4]),my_ip_addr);
	http_init();
	tcp_reserveport(80);
	newMsg = 0;

	print_str("Initializing... \n \n");

	//control loop just keeps the server alive and ticking...
	while(true){

		costate{
			http_handler();
		}

		costate{
			if(newMsg){
				printf("%s - (%d) %s\n", userNameBuffer,strlen(msgBuffer),msgBuffer);
				//dump it to the receipt printer...
				print_str(userNameBuffer);
				print_str(" \n");
				print_str(msgBuffer);
				print_str(" \n \n");
				newMsg = 0;
			}
		}

 	}

}