/*********************************************************************
 *
 *  Application to Demo HTTP2 Server
 *  Support for HTTP2 module in Microchip TCP/IP Stack
 *	 -Implements the application 
 *	 -Reference: RFC 1002
 *
 *********************************************************************
 * FileName:        CustomHTTPApp.c
 * Dependencies:    TCP/IP stack
 * Processor:       PIC18, PIC24F, PIC24H, dsPIC30F, dsPIC33F, PIC32
 * Compiler:        Microchip C32 v1.05 or higher
 *					Microchip C30 v3.12 or higher
 *					Microchip C18 v3.30 or higher
 *					HI-TECH PICC-18 PRO 9.63PL2 or higher
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * Copyright (C) 2002-2009 Microchip Technology Inc.  All rights
 * reserved.
 *
 * Microchip licenses to you the right to use, modify, copy, and
 * distribute:
 * (i)  the Software when embedded on a Microchip microcontroller or
 *      digital signal controller product ("Device") which is
 *      integrated into Licensee's product; or
 * (ii) ONLY the Software driver source files ENC28J60.c, ENC28J60.h,
 *		ENCX24J600.c and ENCX24J600.h ported to a non-Microchip device
 *		used in conjunction with a Microchip ethernet controller for
 *		the sole purpose of interfacing with the ethernet controller.
 *
 * You should refer to the license agreement accompanying this
 * Software for additional information regarding your rights and
 * obligations.
 *
 * THE SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT
 * WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
 * LIMITATION, ANY WARRANTY OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * MICROCHIP BE LIABLE FOR ANY INCIDENTAL, SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF
 * PROCUREMENT OF SUBSTITUTE GOODS, TECHNOLOGY OR SERVICES, ANY CLAIMS
 * BY THIRD PARTIES (INCLUDING BUT NOT LIMITED TO ANY DEFENSE
 * THEREOF), ANY CLAIMS FOR INDEMNITY OR CONTRIBUTION, OR OTHER
 * SIMILAR COSTS, WHETHER ASSERTED ON THE BASIS OF CONTRACT, TORT
 * (INCLUDING NEGLIGENCE), BREACH OF WARRANTY, OR OTHERWISE.
 *
 *
 * Author               Date    Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Elliott Wood     	6/18/07	Original
 ********************************************************************/
#define __CUSTOMHTTPAPP_C

#include "TCPIPConfig.h"

#if defined(STACK_USE_HTTP2_SERVER)

#include "TCPIP Stack/TCPIP.h"
#include "MainDemo.h"		// Needed for SaveAppConfig() prototype

/****************************************************************************
  Section:
	Function Prototypes and Memory Globalizers
  ***************************************************************************/

#define SM_POST_INDEX_NAME				(0u)		// state machine names for post call back
#define SM_POST_INDEX_NAME_VALUE		(1u)		// a state machine is used just in case 
#define SM_POST_INDEX_GENDER			(2u)		// the data arrives in chunks
#define SM_POST_INDEX_GENDER_VALUE		(3u)
#define SM_POST_INDEX_HEIGHT			(4u)
#define SM_POST_INDEX_HEIGHT_VALUE		(5u)
#define SM_POST_INDEX_WEIGHT			(6u)
#define SM_POST_INDEX_WEIGHT_VALUE		(7u)
#define SM_POST_INDEX_EYECOLOR			(8u)
#define SM_POST_INDEX_EYECOLOR_VALUE	(9u)

#define PostIndexSize 50					// max allowable array size for each element of index.htm
BYTE bufName[PostIndexSize];				// location to store Name data read from webpage
BYTE bufGender[PostIndexSize];				// location to store Gender data read from webpage
BYTE bufHeight[PostIndexSize];				// location to store Height data read from webpage
BYTE bufWeight[PostIndexSize];				// location to store Weight data read from webpage
BYTE bufEye[PostIndexSize];					// location to store Eye Color data read from webpage

/****************************************************************************
  Section:
	Authorization Handlers
  ***************************************************************************/
  
/*****************************************************************************
  Function:
	BYTE HTTPNeedsAuth(BYTE* cFile)
	
  Internal:
  	See documentation in the TCP/IP Stack API or HTTP2.h for details.
  ***************************************************************************/
#if defined(HTTP_USE_AUTHENTICATION)
BYTE HTTPNeedsAuth(BYTE* cFile)
{
	// If the filename begins with the folder "protect", then require auth
	if(memcmppgm2ram(cFile, (ROM void*)"protect", 7) == 0)
		return 0x00;		// Authentication will be needed later

	// If the filename begins with the folder "snmp", then require auth
	if(memcmppgm2ram(cFile, (ROM void*)"snmp", 4) == 0)
		return 0x00;		// Authentication will be needed later

	#if defined(HTTP_MPFS_UPLOAD_REQUIRES_AUTH)
	if(memcmppgm2ram(cFile, (ROM void*)"mpfsupload", 10) == 0)
		return 0x00;
	#endif

	// You can match additional strings here to password protect other files.
	// You could switch this and exclude files from authentication.
	// You could also always return 0x00 to require auth for all files.
	// You can return different values (0x00 to 0x79) to track "realms" for below.

	return 0x80;			// No authentication required
}
#endif

/*****************************************************************************
  Function:
	BYTE HTTPCheckAuth(BYTE* cUser, BYTE* cPass)
	
  Internal:
  	See documentation in the TCP/IP Stack API or HTTP2.h for details.
  ***************************************************************************/
#if defined(HTTP_USE_AUTHENTICATION)
BYTE HTTPCheckAuth(BYTE* cUser, BYTE* cPass)
{
	if(strcmppgm2ram((char *)cUser,(ROM char *)"admin") == 0
		&& strcmppgm2ram((char *)cPass, (ROM char *)"microchip") == 0)
		return 0x80;		// We accept this combination
	
	// You can add additional user/pass combos here.
	// If you return specific "realm" values above, you can base this 
	//   decision on what specific file or folder is being accessed.
	// You could return different values (0x80 to 0xff) to indicate 
	//   various users or groups, and base future processing decisions
	//   in HTTPExecuteGet/Post or HTTPPrint callbacks on this value.
	
	return 0x00;			// Provided user/pass is invalid
}
#endif

/****************************************************************************
  Section:
	GET Form Handlers
  ***************************************************************************/
  
/*****************************************************************************
  Function:
	HTTP_IO_RESULT HTTPExecuteGet(void)
	
  Internal:
  	See documentation in the TCP/IP Stack API or HTTP2.h for details.
  ***************************************************************************/
HTTP_IO_RESULT HTTPExecuteGet(void)
{
	BYTE *ptr;
	BYTE filename[20];
	
	// Load the file name
	// Make sure BYTE filename[] above is large enough for your longest name
	MPFSGetFilename(curHTTP.file, filename, 20);
	
	// If its the forms.htm page
	if(!memcmppgm2ram(filename, "forms.htm", 9))
	{
		// Seek out each of the four LED strings, and if it exists set the LED states
		ptr = HTTPGetROMArg(curHTTP.data, (ROM BYTE *)"led4");
		if(ptr)
			LED4_IO = (*ptr == '1');

		ptr = HTTPGetROMArg(curHTTP.data, (ROM BYTE *)"led3");
		if(ptr)
			LED3_IO = (*ptr == '1');

		ptr = HTTPGetROMArg(curHTTP.data, (ROM BYTE *)"led2");
		if(ptr)
			LED2_IO = (*ptr == '1');

		ptr = HTTPGetROMArg(curHTTP.data, (ROM BYTE *)"led1");
		if(ptr)
			LED1_IO = (*ptr == '1');
	}
	
	// If it's the LED updater file
	else if(!memcmppgm2ram(filename, "cookies.htm", 11))
	{
		// This is very simple.  The names and values we want are already in
		// the data array.  We just set the hasArgs value to indicate how many
		// name/value pairs we want stored as cookies.
		// To add the second cookie, just increment this value.
		// remember to also add a dynamic variable callback to control the printout.
		curHTTP.hasArgs = 0x01;
	}
		
	
	// If it's the LED updater file
	else if(!memcmppgm2ram(filename, "leds.cgi", 8))
	{
		// Determine which LED to toggle
		ptr = HTTPGetROMArg(curHTTP.data, (ROM BYTE *)"led");
		
		// Toggle the specified LED
		switch(*ptr) {
			case '1':
				LED1_IO ^= 1;
				break;
			case '2':
				LED2_IO ^= 1;
				break;
			case '3':
				LED3_IO ^= 1;
				break;
			case '4':
				LED4_IO ^= 1;
				break;
			case '5':
				LED5_IO ^= 1;
				break;
			case '6':
				LED6_IO ^= 1;
				break;
			case '7':
				LED7_IO ^= 1;
				break;
		}
		
	}
	
	return HTTP_IO_DONE;
}


/****************************************************************************
  Section:
	POST Form Handlers
  ***************************************************************************/
#if defined(HTTP_USE_POST)

/*****************************************************************************
  Function:
	HTTP_IO_RESULT HTTPExecutePost(void)
	
  Internal:
  	See documentation in the TCP/IP Stack API or HTTP2.h for details.
  ***************************************************************************/
HTTP_IO_RESULT HTTPExecutePost(void)
{
	// Resolve which function to use and pass along
	BYTE filename[20];
	
	// Load the file name
	// Make sure BYTE filename[] above is large enough for your longest name
	MPFSGetFilename(curHTTP.file, filename, sizeof(filename));
	
	if(!strcmppgm2ram((char*)filename, "index.htm"))
	{
		while(curHTTP.byteCount)
		{
			switch(curHTTP.smPost)
			{
				// Find the name
				case SM_POST_INDEX_NAME:									// One common HTTPReadPostName is used to read
				case SM_POST_INDEX_GENDER:									// field names, we are not saving this data.
				case SM_POST_INDEX_HEIGHT:									// its read to curHTTP.data for processing
				case SM_POST_INDEX_WEIGHT:									
				case SM_POST_INDEX_EYECOLOR:								
						
					if(HTTPReadPostName(curHTTP.data, HTTP_MAX_DATA_LEN) == HTTP_READ_INCOMPLETE)
						return HTTP_IO_NEED_DATA;							// return if more data is needed
										
					if(strcmppgm2ram((char*)curHTTP.data, "name")==0)				// if form field name is "name"
					{
						 curHTTP.smPost = SM_POST_INDEX_NAME_VALUE; 		// set smPost to read to bufName
						 break;												// break, let state machine dictate next case
					}
					else if (strcmppgm2ram((char*)curHTTP.data, "gender")==0)		// if form field name is "gender"
					{
						 curHTTP.smPost = SM_POST_INDEX_GENDER_VALUE; 		// set smPost to read to bufGender
						 break;												// break, let state machine dictate next case
					}
					else if (strcmppgm2ram((char*)curHTTP.data, "height")==0)		// if form field name is "height"
					{
							 curHTTP.smPost = SM_POST_INDEX_HEIGHT_VALUE;	// set smPost to read to bufHeight
							 break;											// break, let state machine dictate next case
					}
					else if (strcmppgm2ram((char*)curHTTP.data, "weight")==0)		// if form field name is "weight"
					{
						 curHTTP.smPost = SM_POST_INDEX_WEIGHT_VALUE; 		// set smPost to read to bufWeight
						 break;												// break, let state machine dictate next case
					}
					else if (strcmppgm2ram((char*)curHTTP.data, "eye")==0)			// if form field name is "eye"
					{
						 curHTTP.smPost = SM_POST_INDEX_EYECOLOR_VALUE; 	// set smPost to read to bufEye
						 break;												// break, let state machine dictate next case
					}
					else
					{
						return HTTP_IO_DONE;								// valid name token for call back not found
																			// end callback
					}
							case SM_POST_INDEX_NAME_VALUE:								// read value of name field to bufName
					if(HTTPReadPostValue(bufName, PostIndexSize) == HTTP_READ_INCOMPLETE)
						return HTTP_IO_NEED_DATA;							// if read is incomplete return
					curHTTP.smPost = SM_POST_INDEX_GENDER;					// adjust state machine state
					break;
				
				case SM_POST_INDEX_GENDER_VALUE:							// read value of gender field to bufGender
					if(HTTPReadPostValue(bufGender, PostIndexSize) == HTTP_READ_INCOMPLETE)
						return HTTP_IO_NEED_DATA;							// if read is incomplete return
					curHTTP.smPost = SM_POST_INDEX_HEIGHT;					// adjust state machine state
					break;
				
				case SM_POST_INDEX_HEIGHT_VALUE:							// read value of height field to bufHeight
					if(HTTPReadPostValue(bufHeight, PostIndexSize) == HTTP_READ_INCOMPLETE)
						return HTTP_IO_NEED_DATA;							// if read is incomplete return
					curHTTP.smPost = SM_POST_INDEX_WEIGHT;					// adjust state machine state
					break;
				
				case SM_POST_INDEX_WEIGHT_VALUE:							// read value of weight field to bufWeight
					if(HTTPReadPostValue(bufWeight, PostIndexSize) == HTTP_READ_INCOMPLETE)
						return HTTP_IO_NEED_DATA;							// if read is incomplete return
					curHTTP.smPost = SM_POST_INDEX_EYECOLOR;				// adjust state machine state
					break;
				
				case SM_POST_INDEX_EYECOLOR_VALUE:							// read value of "eye" color field to bufEye
					if(HTTPReadPostValue(bufEye, PostIndexSize) == HTTP_READ_INCOMPLETE)
						return HTTP_IO_NEED_DATA;							// if read is incomplete return
					curHTTP.smPost = SM_POST_INDEX_NAME;					// adjust state machine state
					break;
				default:													// if we end up in an invalid state
					return HTTP_IO_DONE;									// return HTTP_IO_DONE
			
			}	// end state machine case statement
		}  // end of while(currHTTP.byteCount)
		strcpypgm2ram((char*)curHTTP.data, (ROM void*)"/index.htm");		// execute redirect to prevent resubmission of data
		curHTTP.httpStatus = HTTP_REDIRECT;
		return HTTP_IO_DONE;
	} // end of index post
    return HTTP_IO_DONE;
}

#endif //(use_post)


/****************************************************************************
  Section:
	Dynamic Variable Callback Functions
  ***************************************************************************/


#endif
