/*********************************************************************
 *
 *  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-2010 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"

#include "FreeRTOS.h"
#include "queue.h"
#include "lcd.h"
#include "TCPIP Stack/StackTsk.h"

#if defined(STACK_USE_HTTP2_SERVER)

#include "TCPIP Stack/TCPIP.h"
#include "prvTaskTCPIP.h"		// Needed for SaveAppConfig() prototype
#include "node.h"
#include "TCPIP Stack/DstarRoomServer.h"

AD_PARAM AdParam;

void MACWriteArray(BYTE address, BYTE *val, WORD wLen);
BOOL MACReadArray(BYTE address, BYTE *buffer, WORD length);
WORD CalcIPChecksum(BYTE *AppConfig, WORD length);

/****************************************************************************
  Section:
	Function Prototypes and Memory Globalizers
  ***************************************************************************/
#if defined(HTTP_USE_POST)
	#if defined(STACK_USE_HTTP_MD5_DEMO)
		#if !defined(STACK_USE_MD5)
			#error The HTTP_MD5_DEMO requires STACK_USE_MD5
		#endif
		static HTTP_IO_RESULT HTTPPostMD5(void);
	#endif
	#if defined(STACK_USE_HTTP_APP_RECONFIG)
		static HTTP_IO_RESULT HTTPPostConfig(void);
		static HTTP_IO_RESULT HTTPAd1Config(void);
		static HTTP_IO_RESULT HTTPAd2Config(void);
		static HTTP_IO_RESULT HTTPAd3Config(void);
		static HTTP_IO_RESULT HTTPUserPassword(void);
		#if defined(STACK_USE_SNMP_SERVER)
		static HTTP_IO_RESULT HTTPPostSNMPCommunity(void);
		#endif
	#endif
	#if defined(STACK_USE_HTTP_EMAIL_DEMO) || defined(STACK_USE_SMTP_CLIENT)
		#if !defined(STACK_USE_SMTP_CLIENT)
			#error The HTTP_EMAIL_DEMO requires STACK_USE_SMTP_CLIENT
		#endif
		static HTTP_IO_RESULT HTTPPostEmail(void);
	#endif
#endif


// Sticky status message variable.
// This is used to indicated whether or not the previous POST operation was 
// successful.  The application uses these to store status messages when a 
// POST operation redirects.  This lets the application provide status messages
// after a redirect, when connection instance data has already been lost.
static BOOL lastSuccess = FALSE;

// Stick status message variable.  See lastSuccess for details.
static BOOL lastFailure = FALSE;

/****************************************************************************
  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 *)AppConfig.UserID) == 0
		&& strcmppgm2ram((char *)cPass, (ROM char *)AppConfig.PASSWORD) == 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 filename[20];
	
	// Load the file name
	// Make sure BYTE filename[] above is large enough for your longest name
	MPFSGetFilename(curHTTP.file, filename, 20);
	
	
	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[32];
	
	// Load the file name
	// Make sure BYTE filename[] above is large enough for your longest name
	MPFSGetFilename(curHTTP.file, filename, sizeof(filename));
	
	if(!memcmppgm2ram(filename, "protect/config.htm", 18))
		return HTTPPostConfig();
	if(!memcmppgm2ram(filename, "protect/user.htm", 16))
		return HTTPUserPassword();
	if(!memcmppgm2ram(filename, "nodeadapter/config.htm", 22))
		return HTTPAd1Config();
	if(!memcmppgm2ram(filename, "nodeadapter/config2.htm", 23))
		return HTTPAd2Config();
	if(!memcmppgm2ram(filename, "nodeadapter/config3.htm", 23))
		return HTTPAd3Config();


	return HTTP_IO_DONE;
}


/*****************************************************************************
  Function:
	static HTTP_IO_RESULT HTTPPostConfig(void)

  Summary:
	Processes the configuration form on config/index.htm

  Description:
	Accepts configuration parameters from the form, saves them to a
	temporary location in RAM, then eventually saves the data to EEPROM or
	external Flash.
	
	When complete, this function redirects to config/reboot.htm, which will
	display information on reconnecting to the board.

	This function creates a shadow copy of the AppConfig structure in 
	RAM and then overwrites incoming data there as it arrives.  For each 
	name/value pair, the name is first read to curHTTP.data[0:5].  Next, the 
	value is read to newAppConfig.  Once all data has been read, the new
	AppConfig is saved back to EEPROM and the browser is redirected to 
	reboot.htm.  That file includes an AJAX call to reboot.cgi, which 
	performs the actual reboot of the machine.
	
	If an IP address cannot be parsed, too much data is POSTed, or any other 
	parsing error occurs, the browser reloads config.htm and displays an error 
	message at the top.

  Precondition:
	None

  Parameters:
	None

  Return Values:
  	HTTP_IO_DONE - all parameters have been processed
  	HTTP_IO_NEED_DATA - data needed by this function has not yet arrived
  ***************************************************************************/
#if defined(STACK_USE_HTTP_APP_RECONFIG)
static HTTP_IO_RESULT HTTPPostConfig(void)
{
	APP_CONFIG newAppConfig;
	BYTE *ptr;
	WORD	i, k;

	// Check to see if the browser is attempting to submit more data than we 
	// can parse at once.  This function needs to receive all updated 
	// parameters and validate them all before committing them to memory so that
	// orphaned configuration parameters do not get written (for example, if a 
	// static IP address is given, but the subnet mask fails parsing, we 
	// should not use the static IP address).  Everything needs to be processed 
	// in a single transaction.  If this is impossible, fail and notify the user.
	// As a web devloper, if you add parameters to AppConfig and run into this 
	// problem, you could fix this by to splitting your update web page into two 
	// seperate web pages (causing two transactional writes).  Alternatively, 
	// you could fix it by storing a static shadow copy of AppConfig someplace 
	// in memory and using it instead of newAppConfig.  Lastly, you could 
	// increase the TCP RX FIFO size for the HTTP server.  This will allow more 
	// data to be POSTed by the web browser before hitting this limit.
	if(curHTTP.byteCount > TCPIsGetReady(sktHTTP) + TCPGetRxFIFOFree(sktHTTP))
		goto ConfigFailure;
	
	// Ensure that all data is waiting to be parsed.  If not, keep waiting for 
	// all of it to arrive.
	if(TCPIsGetReady(sktHTTP) < curHTTP.byteCount)
		return HTTP_IO_NEED_DATA;
	
	
	// Use current config in non-volatile memory as defaults
	
	MACReadArray(0x00, (BYTE *)&newAppConfig, sizeof(newAppConfig));

	// Start out assuming that DHCP is disabled.  This is necessary since the 
	// browser doesn't submit this field if it is unchecked (meaning zero).  
	// However, if it is checked, this will be overridden since it will be 
	// submitted.
	newAppConfig.Flags.bIsDHCPEnabled = 0;
	newAppConfig.Flags.RepeaterAcc = 0;


	// Read all browser POST data
	while(curHTTP.byteCount)
	{
		// Read a form field name
		if(HTTPReadPostName(curHTTP.data, 6) != HTTP_READ_OK)
			goto ConfigFailure;
			
		// Read a form field value
		if(HTTPReadPostValue(curHTTP.data + 6, sizeof(curHTTP.data)-6-2) != HTTP_READ_OK)
			goto ConfigFailure;
			
		// Parse the value that was read
		if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"ip"))
		{// Read new static IP Address
			if(!StringToIPAddress(curHTTP.data+6, &newAppConfig.MyIPAddr))
				goto ConfigFailure;
				
			newAppConfig.DefaultIPAddr.Val = newAppConfig.MyIPAddr.Val;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"gw"))
		{// Read new gateway address
			if(!StringToIPAddress(curHTTP.data+6, &newAppConfig.MyGateway))
				goto ConfigFailure;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"sub"))
		{// Read new static subnet
			if(!StringToIPAddress(curHTTP.data+6, &newAppConfig.MyMask))
				goto ConfigFailure;

			newAppConfig.DefaultMask.Val = newAppConfig.MyMask.Val;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"dns1"))
		{// Read new primary DNS server
			if(!StringToIPAddress(curHTTP.data+6, &newAppConfig.PrimaryDNSServer))
				goto ConfigFailure;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"dns2"))
		{// Read new secondary DNS server
			if(!StringToIPAddress(curHTTP.data+6, &newAppConfig.SecondaryDNSServer))
				goto ConfigFailure;
		}
//		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"mac"))
//		{
//			// Read new MAC address
//			WORD w;
//			BYTE i;
//
//			ptr = curHTTP.data+6;
//
//			for(i = 0; i < 12u; i++)
//			{// Read the MAC address
//				
//				// Skip non-hex bytes
//				while( *ptr != 0x00u && !(*ptr >= '0' && *ptr <= '9') && !(*ptr >= 'A' && *ptr <= 'F') && !(*ptr >= 'a' && *ptr <= 'f') )
//					ptr++;
//
//				// MAC string is over, so zeroize the rest
//				if(*ptr == 0x00u)
//				{
//					for(; i < 12u; i++)
//						curHTTP.data[i] = '0';
//					break;
//				}
//				
//				// Save the MAC byte
//				curHTTP.data[i] = *ptr++;
//			}
//			
//			// Read MAC Address, one byte at a time
//			for(i = 0; i < 6u; i++)
//			{
//				((BYTE*)&w)[1] = curHTTP.data[i*2];
//				((BYTE*)&w)[0] = curHTTP.data[i*2+1];
//				newAppConfig.MyMACAddr.v[i] = hexatob(*((WORD_VAL*)&w));
//			}
//		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"logh"))
		{// Read new ;og server name (host name)
			i = strlen ((void*)curHTTP.data+6);
			memcpy (newAppConfig.LogServerName,(void*)curHTTP.data+6 ,i);
			newAppConfig.LogServerName[i] = 0x00;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"dhcp"))
		{
			if(curHTTP.data[6] == '1')
				newAppConfig.Flags.bIsDHCPEnabled = 1;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"oprt"))
		{
			newAppConfig.DefaultOutPort = atoi((char *)curHTTP.data+6);
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"iprt"))
		{
			newAppConfig.DefaultInPort = atoi((char *)curHTTP.data+6);
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"RmNm"))
		{// Read new Room Name
			ptr = curHTTP.data+6;
			i = strlen ((void*)curHTTP.data+6);
			if (i < 8)
			{
				ptr += i; 
				for (k = i ; k < 8 ; k++)
				{
					*ptr = ' ';
					ptr++;
				}
			}
			memcpy (newAppConfig.DefaultRoomName, (void*)curHTTP.data+6, 8);				
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"zone"))
		{
			newAppConfig.TmZone = atoi((void *)curHTTP.data+6);
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"zneM"))
		{
			i = atoi((void *)curHTTP.data+6);
			if (i >= 60) i = 0;
			newAppConfig.TmZoneMinutes = i;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"ntp"))
		{
			i = strlen ((void*)curHTTP.data+6);
			memcpy (newAppConfig.NTPserver,(void*)curHTTP.data+6 ,i);
			newAppConfig.NTPserver[i] = 0x00;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"rept"))
		{
			if(curHTTP.data[6] == '1')
				newAppConfig.Flags.RepeaterAcc = 1;
		}
	}

	// All parsing complete!  Save new settings and force a reboot
	//	SaveAppConfig(&newAppConfig);
	newAppConfig.CheckSum = CalcIPChecksum((BYTE*)&newAppConfig, sizeof(newAppConfig)-2);
	MACWriteArray(0x00, (BYTE *)&newAppConfig, sizeof(newAppConfig));

	
	// Set the board to reboot and display reconnecting information
	strcpypgm2ram((char*)curHTTP.data, "/protect/reboot.htm?");
//	memcpy((void*)(curHTTP.data+20), " New IP address", 16);
//	curHTTP.data[20+16] = 0x00;	// Force null termination
//	for(i = 20; i < 20u+16u; i++)
//	{
//		if(curHTTP.data[i] == ' ')
//			curHTTP.data[i] = 0x00;
//	}		
	curHTTP.httpStatus = HTTP_REDIRECT;	
	
	return HTTP_IO_DONE;


ConfigFailure:
	lastFailure = TRUE;
	strcpypgm2ram((char*)curHTTP.data, "/protect/config.htm");
	curHTTP.httpStatus = HTTP_REDIRECT;		

	return HTTP_IO_DONE;
}

static HTTP_IO_RESULT HTTPAd1Config(void)
{
	BYTE	sMode, sMode2, sInvert;
	if(curHTTP.byteCount > TCPIsGetReady(sktHTTP) + TCPGetRxFIFOFree(sktHTTP))
		goto Ad1ConfigFailure;
	
	// Ensure that all data is waiting to be parsed.  If not, keep waiting for 
	// all of it to arrive.
	if(TCPIsGetReady(sktHTTP) < curHTTP.byteCount)
		return HTTP_IO_NEED_DATA;
	
	
	sMode = 0x00;
	sMode2 = 0x00;
	sInvert = 0x00;
	
	// Read all browser POST data
	while(curHTTP.byteCount)
	{
		// Read a form field name
		if(HTTPReadPostName(curHTTP.data, 6) != HTTP_READ_OK)
			goto Ad1ConfigFailure;
			
		// Read a form field value
		if(HTTPReadPostValue(curHTTP.data + 6, sizeof(curHTTP.data)-6-2) != HTTP_READ_OK)
			goto Ad1ConfigFailure;
			
		// Parse the value that was read
		if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"crc"))
		{
				sMode |= 0x02;
		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"cos"))
		{
				sMode |= 0x04;
		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"last"))
		{
				sMode |= 0x08;
		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"h_f"))
		{
				sMode |= 0x80;
		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"hdrg"))
		{
				sMode2 |= 0x01;
		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"hdrt"))
		{
				sMode2 |= 0x02;
		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"txhr"))
		{
				sMode2 |= 0x04;
		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"rxpl"))
		{
				sInvert |= 0x80;
		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"rxpo"))
		{
				sInvert |= 0x02;
		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"txpo"))
		{
				sInvert |= 0x01;
		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"dely"))
		{
			AdParam.DelayTime = atoi((void *)curHTTP.data+6) /10 ;
		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"tout"))
		{
			AdParam.TimeOut = atoi((void *)curHTTP.data+6) / 10;
		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"keep"))
		{
			AdParam.KeepAlive = atoi((void *)curHTTP.data+6) / 10;
		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"jitt"))
		{
			AdParam.JitterSize = atoi((void *)curHTTP.data+6);
		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"sn"))
		{
			AdParam.SN_Squelch = atoi((void *)curHTTP.data+6);
		}
	}

	AdParam.Mode = sMode;
	AdParam.Mode2 = sMode2;
	AdParam.Invert = sInvert;
	AdParam.UpdateFlag = 0x02;
	strcpypgm2ram((char*)curHTTP.data, "/nodeadapter/config.htm?");
	curHTTP.httpStatus = HTTP_REDIRECT;	
	
	return HTTP_IO_DONE;


Ad1ConfigFailure:
	lastFailure = TRUE;
	strcpypgm2ram((char*)curHTTP.data, "/nodeadapter/config.htm");
	curHTTP.httpStatus = HTTP_REDIRECT;		

	return HTTP_IO_DONE;
}

static HTTP_IO_RESULT HTTPAd2Config(void)
{
	static	WORD	i, len;

	if(curHTTP.byteCount > TCPIsGetReady(sktHTTP) + TCPGetRxFIFOFree(sktHTTP))
		goto Ad2ConfigFailure;
	
	// Ensure that all data is waiting to be parsed.  If not, keep waiting for 
	// all of it to arrive.
	if(TCPIsGetReady(sktHTTP) < curHTTP.byteCount)
		return HTTP_IO_NEED_DATA;
	

	// Read all browser POST data
	while(curHTTP.byteCount)
	{
		// Read a form field name
		if(HTTPReadPostName(curHTTP.data, 6) != HTTP_READ_OK)
			goto Ad2ConfigFailure;
			
		// Read a form field value
		if(HTTPReadPostValue(curHTTP.data + 6, sizeof(curHTTP.data)-6-2) != HTTP_READ_OK)
			goto Ad2ConfigFailure;
			
		// Parse the value that was read
		if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"beac"))
		{
			len = strlen((void*)curHTTP.data+6);
			if (len > 20) len = 20;
			memcpy (AdParam.BeaconMessage,(void*)curHTTP.data+6 ,len);
			if (len < 20)
			{
				for (i = len ; i < 20 ; i++)
				{
					AdParam.BeaconMessage[i] = 0x20;
				}
			}

		} else if (!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"intv"))
		{
				AdParam.BeaconInterval = atoi((void *)curHTTP.data+6) / 10;
		}
	}

	AdParam.UpdateFlag = 0x02;
	strcpypgm2ram((char*)curHTTP.data, "/nodeadapter/config2.htm?");
	curHTTP.httpStatus = HTTP_REDIRECT;	
	
	return HTTP_IO_DONE;


Ad2ConfigFailure:
	lastFailure = TRUE;
	strcpypgm2ram((char*)curHTTP.data, "/nodeadapter/config2.htm");
	curHTTP.httpStatus = HTTP_REDIRECT;		

	return HTTP_IO_DONE;
}

static HTTP_IO_RESULT HTTPAd3Config(void)
{
	static	BYTE	sFlag, aFlag, sRepMode2;

	sFlag = 0x00;
	AdParam.Mode2 &= 0xfb;

	aFlag = AdParam.AltFlags[0];
	aFlag &= 0x07;

	sRepMode2 = AdParam.AltFlags[1];
	sRepMode2 = 0xfe;

	if(curHTTP.byteCount > TCPIsGetReady(sktHTTP) + TCPGetRxFIFOFree(sktHTTP))
		goto Ad3ConfigFailure;
	
	// Ensure that all data is waiting to be parsed.  If not, keep waiting for 
	// all of it to arrive.
	if(TCPIsGetReady(sktHTTP) < curHTTP.byteCount)
		return HTTP_IO_NEED_DATA;
	

	// Read all browser POST data
	while(curHTTP.byteCount)
	{
		// Read a form field name
		if(HTTPReadPostName(curHTTP.data, 6) != HTTP_READ_OK)
			goto Ad3ConfigFailure;
			
		// Read a form field value
		if(HTTPReadPostValue(curHTTP.data + 6, sizeof(curHTTP.data)-6-2) != HTTP_READ_OK)
			goto Ad3ConfigFailure;
			
		// Parse the value that was read
		if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"myc"))
		{
			memcpy (AdParam.AltMyCall,(void*)curHTTP.data+6 ,8);
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"myc2"))
		{
			memcpy (AdParam.AltMyCall2,(void*)curHTTP.data+6 ,4);
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"rpt1"))
		{
			memcpy (AdParam.AltRPT1Call,(void*)curHTTP.data+6 ,8);
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"rpt2"))
		{
			memcpy (AdParam.AltRPT2Call,(void*)curHTTP.data+6 ,8);
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"yrc"))
		{
			memcpy (AdParam.AltYourCall,(void*)curHTTP.data+6 ,8);
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"flg0"))
		{
				 sFlag |= 0x01;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"flg1"))
		{
				 sFlag |= 0x02;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"flg2"))
		{
				 sFlag |= 0x04;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"flg3"))
		{
				 sFlag |= 0x08;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"flg4"))
		{
				 sFlag |= 0x10;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"flg5"))
		{
				 sFlag |= 0x20;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"flg6"))
		{
				 sFlag |= 0x40;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"flg7"))
		{
				 sFlag |= 0x80;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"aflg"))
		{
				 sRepMode2 |= 0x01;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"txhr"))
		{
				  AdParam.Mode2 |= 0x04;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"amyc"))
		{
				  aFlag |= 0x08;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"amy2"))
		{
				  aFlag |= 0x10;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"ayrc"))
		{
				  aFlag |= 0x20;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"art1"))
		{
				  aFlag |= 0x40;
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"art2"))
		{
				  aFlag |= 0x80;
		}
	}

	AdParam.AltFlags[2] = sFlag;
	AdParam.AltFlags[0] = aFlag;
	AdParam.AltFlags[1] = sRepMode2; 

	AdParam.UpdateFlag = 0x02;
	strcpypgm2ram((char*)curHTTP.data, "/nodeadapter/config3.htm?");
	curHTTP.httpStatus = HTTP_REDIRECT;	
	
	return HTTP_IO_DONE;


Ad3ConfigFailure:
	lastFailure = TRUE;
	strcpypgm2ram((char*)curHTTP.data, "/nodeadapter/config3.htm");
	curHTTP.httpStatus = HTTP_REDIRECT;		

	return HTTP_IO_DONE;
}



static HTTP_IO_RESULT HTTPUserPassword(void)
{
	if(curHTTP.byteCount > TCPIsGetReady(sktHTTP) + TCPGetRxFIFOFree(sktHTTP))
		goto UserFailure;
	
	// Ensure that all data is waiting to be parsed.  If not, keep waiting for 
	// all of it to arrive.
	if(TCPIsGetReady(sktHTTP) < curHTTP.byteCount)
		return HTTP_IO_NEED_DATA;
	
	
	// Read all browser POST data
	while(curHTTP.byteCount)
	{
		// Read a form field name
		if(HTTPReadPostName(curHTTP.data, 6) != HTTP_READ_OK)
			goto UserFailure;
			
		// Read a form field value
		if(HTTPReadPostValue(curHTTP.data + 6, sizeof(curHTTP.data)-6-2) != HTTP_READ_OK)
			goto UserFailure;
			
		// Parse the value that was read
		if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"user"))
		{
			memcpy ((char *)&AppConfig.UserID, curHTTP.data + 6, 16);
		}
		else if(!strcmppgm2ram((char*)curHTTP.data, (ROM char*)"pwd"))
		{
			memcpy ((char *)&AppConfig.PASSWORD, curHTTP.data + 6, 16);
		}
	}

	// All parsing complete!  Save new settings and force a reboot
	//	SaveAppConfig(&newAppConfig);
	AppConfig.CheckSum = CalcIPChecksum((BYTE*)&AppConfig, sizeof(AppConfig)-2);
	MACWriteArray(0x00, (BYTE *)&AppConfig, sizeof(AppConfig));

	// Set the board to reboot and display reconnecting information
	strcpypgm2ram((char*)curHTTP.data, "/protect/user.htm?");
	curHTTP.httpStatus = HTTP_REDIRECT;	
	
	return HTTP_IO_DONE;


UserFailure:
	lastFailure = TRUE;
	strcpypgm2ram((char*)curHTTP.data, "/protect/user.htm");
	curHTTP.httpStatus = HTTP_REDIRECT;		

	return HTTP_IO_DONE;
}


#endif	// #if defined(STACK_USE_HTTP_APP_RECONFIG)

#endif //(use_post)


void HTTPPrint_hellomsg(void)
{
	BYTE *ptr;
	
	ptr = HTTPGetROMArg(curHTTP.data, (ROM BYTE*)"name");
	
	// We omit checking for space because this is the only data being written
	if(ptr != NULL)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"Hello, ");
		TCPPutString(sktHTTP, ptr);
	}

	return;
}

void HTTPPrintIP(IP_ADDR ip)
{
	static	BYTE digits[4];
	static	BYTE i;
	
	for(i = 0; i < 4u; i++)
	{
		if(i)
			TCPPut(sktHTTP, '.');
		uitoa(ip.v[i], digits);
		TCPPutString(sktHTTP, digits);
	}
}


void HTTPPrint_config_dhcpchecked(void)
{
	if(AppConfig.Flags.bIsDHCPEnabled)
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	return;
}

void HTTPPrint_config_ip(void)
{
	HTTPPrintIP(AppConfig.MyIPAddr);
	return;
}

void HTTPPrint_config_gw(void)
{
	HTTPPrintIP(AppConfig.MyGateway);
	return;
}

void HTTPPrint_config_subnet(void)
{
	HTTPPrintIP(AppConfig.MyMask);
	return;
}

void HTTPPrint_config_dns1(void)
{
	HTTPPrintIP(AppConfig.PrimaryDNSServer);
	return;
}

void HTTPPrint_config_dns2(void)
{
	HTTPPrintIP(AppConfig.SecondaryDNSServer);
	return;
}

void HTTPPrint_config_mac(void)
{
	BYTE i;
	extern	MAC_ADDR	MyMACAddr;              // Application MAC address

	
	if(TCPIsPutReady(sktHTTP) < 18u)
	{//need 17 bytes to write a MAC
		curHTTP.callbackPos = 0x01;
		return;
	}	
	
	// Write each byte
	for(i = 0; i < 6u; i++)
	{
		if(i)
			TCPPut(sktHTTP, ':');
		TCPPut(sktHTTP, btohexa_high(MyMACAddr.v[i]));
		TCPPut(sktHTTP, btohexa_low(MyMACAddr.v[i]));
	}
	
	// Indicate that we're done
	curHTTP.callbackPos = 0x00;
	return;
}

void HTTPPrint_reboot(void)
{
	// This is not so much a print function, but causes the board to reboot
	// when the configuration is changed.  If called via an AJAX call, this
	// will gracefully reset the board and bring it back online immediately
	Reset();
}

void HTTPPrint_rebootaddr(void)
{// This is the expected address of the board upon rebooting

	HTTPPrintIP(AppConfig.MyIPAddr);
}



void HTTPPrint_status_ok(void)
{
	if(lastSuccess)
		TCPPutROMString(sktHTTP, (ROM BYTE*)"block");
	else
		TCPPutROMString(sktHTTP, (ROM BYTE*)"none");
	lastSuccess = FALSE;
}

void HTTPPrint_status_fail(void)
{
	if(lastFailure)
		TCPPutROMString(sktHTTP, (ROM BYTE*)"block");
	else
		TCPPutROMString(sktHTTP, (ROM BYTE*)"none");
	lastFailure = FALSE;
}

#endif

void HTTPPrint_server_ip_address(void)
{
		HTTPPrintIP(AppConfig.MyIPAddr);
}

void HTTPPrint_out_port(void)
{
	BYTE digits[10];
	
		uitoa(AppConfig.DefaultOutPort, digits);
		TCPPutString(sktHTTP, digits);
}

void HTTPPrint_in_port(void)
{
	BYTE digits[10];
	
		uitoa(AppConfig.DefaultInPort, digits);
		TCPPutString(sktHTTP, digits);
}

void HTTPPrint_log_port(void)
{
	BYTE digits[10];
	
		uitoa(AppConfig.DefaultLogPort, digits);
		TCPPutString(sktHTTP, digits);
}


void HTTPPrint_TimeZone(void)
{
	char digits[10];
	
		sprintf (digits,"%+2d",AppConfig.TmZone);
		TCPPutString(sktHTTP, (BYTE *)digits);
}

void HTTPPrint_TimeZoneMinutes(void)
{
	char digits[10];
	
		sprintf (digits,"%2u",AppConfig.TmZoneMinutes);
		TCPPutString(sktHTTP, (BYTE *)digits);
}

void HTTPPrint_CurTime(void)
{
	static	BYTE temp[9];
	static	rtccDate dt;
	static	rtccTime tm;

		RtccGetTimeDate (&tm, &dt); 

		temp[0] = (tm.hour >> 4) + 0x30;
		temp[1] = (tm.hour & 0x0f) + 0x30;
		temp[2] = ':';
		temp[3] = (tm.min >> 4) + 0x30;
		temp[4] = (tm.min & 0x0f) + 0x30;
		temp[5] = ':';
		temp[6] = (tm.sec >> 4) + 0x30;
		temp[7] = (tm.sec & 0x0f) + 0x30;
		temp[8] = 0x00;
	
		TCPPutString(sktHTTP, (BYTE *)temp);
}

void HTTPPrint_CurDate(void)
{
	static	BYTE temp[11];
	static	rtccDate dt;
	static	rtccTime tm;

		RtccGetTimeDate (&tm, &dt); 
		temp[0] = '2';
		temp[1] = '0';
		temp[2] = (dt.year>> 4) + 0x30;
		temp[3] = (dt.year & 0x0f) + 0x30;
		temp[4] = '/';
		temp[5] = (dt.mon>> 4) + 0x30;
		temp[6] = (dt.mon & 0x0f) + 0x30;
		temp[7] = '/';
		temp[8] = (dt.mday>> 4) + 0x30;
		temp[9] = (dt.mday & 0x0f) + 0x30;
		temp[10] = 0x00;

	
		TCPPutString(sktHTTP, (BYTE *)temp);
}

void HTTPPrint_RoomName(void)
{
	static	BYTE temp[9];
	
		memcpy (temp, AppConfig.DefaultRoomName, 8);
		temp[8] = 0x00;
		TCPPutString(sktHTTP, (BYTE *)temp);
}


void HTTPPrint_NtpName(void)
{
		TCPPutROMString(sktHTTP, AppConfig.NTPserver);
}

void HTTPPrint_LogName(void)
{
		TCPPutROMString(sktHTTP, AppConfig.LogServerName);
}

void HTTPPrint_delay_time(void)
{
	char	temp[10];
	
	sprintf (temp, "%u0", AdParam.DelayTime);
	TCPPutString(sktHTTP, (BYTE *)temp);
}


void HTTPPrint_time_out()
{
	char	temp[10];
	
	sprintf (temp, "%u0", AdParam.TimeOut);
	TCPPutString(sktHTTP, (BYTE *)temp);
}

void HTTPPrint_keep_alive()
{
	char	temp[10];
	
	sprintf (temp, "%u0", AdParam.KeepAlive);
	TCPPutString(sktHTTP, (BYTE *)temp);
}

void HTTPPrint_jittter_size()
{
	char	temp[10];
	
	sprintf (temp, "%u", AdParam.JitterSize);
	TCPPutString(sktHTTP, (BYTE *)temp);
}

void HTTPPrint_RX_AutoPolarity()
{
	if (AdParam.Invert & 0x80)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}
void HTTPPrint_RX_Polarity()
{
	if (AdParam.Invert & 0x02)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_TX_Polarity()
{
	if (AdParam.Invert & 0x01)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}}

void HTTPPrint_COS_Check()
{
	if (AdParam.Mode & 0x04)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_SN_Squelch()
{
	char	temp[10];
	
	sprintf (temp, "%u", AdParam.SN_Squelch);
	TCPPutString(sktHTTP, (BYTE *)temp);
}

void HTTPPrint_CRC_Check()
{
	if (AdParam.Mode & 0x02)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_LastFrame()
{
	if (AdParam.Mode & 0x08)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_HeaderGen()
{
	if (AdParam.Mode2 & 0x01)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_HeaderGenType()
{
	if (AdParam.Mode2 & 0x02)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_HeaderRep()
{
	if (AdParam.Mode2 & 0x04)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_HalfFull()
{
	if (AdParam.Mode & 0x80)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_user_id(void)
{
		TCPPutROMString(sktHTTP, AppConfig.UserID);
}

void HTTPPrint_user_pass(void)
{
		TCPPutROMString(sktHTTP, AppConfig.PASSWORD);
}

void HTTPPrint_user_passC(void)
{
		TCPPutROMString(sktHTTP, AppConfig.PASSWORD);
}

void HTTPPrint_BeaconM(void)
{
	static	BYTE msg[21];
	
		memcpy (msg , AdParam.BeaconMessage, 20);
		msg[20] = 0x00;
		TCPPutROMString(sktHTTP, msg);

}

void HTTPPrint_BeaconIntv(void)
{
	BYTE digits[10];

		uitoa(AdParam.BeaconInterval * 10, digits);
		TCPPutROMString(sktHTTP, digits);
}

void HTTPPrint_alt_mycall(void)
{
	static	BYTE msg[9];
	
		memcpy (msg , AdParam.AltMyCall, 8);
		msg[8] = 0x00;
		TCPPutROMString(sktHTTP, msg);

}

void HTTPPrint_alt_mycall2(void)
{
	static	BYTE msg[5];
	
		memcpy (msg , AdParam.AltMyCall2, 4);
		msg[4] = 0x00;
		TCPPutROMString(sktHTTP, msg);

}

void HTTPPrint_alt_yourcall(void)
{
	static	BYTE msg[9];
	
		memcpy (msg , AdParam.AltYourCall, 8);
		msg[8] = 0x00;
		TCPPutROMString(sktHTTP, msg);

}

void HTTPPrint_alt_rpt1call(void)
{
	static	BYTE msg[9];
	
		memcpy (msg , AdParam.AltRPT1Call, 8);
		msg[8] = 0x00;
		TCPPutROMString(sktHTTP, msg);

}

void HTTPPrint_alt_rpt2call(void)
{
	static	BYTE msg[9];
	
		memcpy (msg , AdParam.AltRPT2Call, 8);
		msg[8] = 0x00;
		TCPPutROMString(sktHTTP, msg);

}

void HTTPPrint_flag0()
{
	if (AdParam.AltFlags[2] & 0x01)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_flag1()
{
	if (AdParam.AltFlags[2] & 0x02)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_flag2()
{
	if (AdParam.AltFlags[2] & 0x04)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_flag3()
{
	if (AdParam.AltFlags[2] & 0x08)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_flag4()
{
	if (AdParam.AltFlags[2] & 0x10)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_flag5()
{
	if (AdParam.AltFlags[2] & 0x20)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_flag6()
{
	if (AdParam.AltFlags[2] & 0x40)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_flag7()
{
	if (AdParam.AltFlags[2] & 0x80)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_Aflag()
{
	if (AdParam.AltFlags[1] & 0x01)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_a_mycall()
{
	if (AdParam.AltFlags[0] & 0x08)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_a_mycall2()
{
	if (AdParam.AltFlags[0] & 0x10)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_a_yourcall()
{
	if (AdParam.AltFlags[0] & 0x20)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_a_rpt1call()
{
	if (AdParam.AltFlags[0] & 0x40)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_a_rpt2call()
{
	if (AdParam.AltFlags[0] & 0x80)
	{
		TCPPutROMString(sktHTTP, (ROM BYTE*)"checked");
	} else {
		TCPPutROMString(sktHTTP, (ROM BYTE*)"unchecked");
	}
}

void HTTPPrint_NdTable()
{
	extern	struct	connected_table *first_pnt;
	static	struct	connected_table *pnt;
	static	BYTE	temp[10];

	pnt = first_pnt->f_chain;
	if (!pnt) return;

	TCPPutROMString(sktHTTP, (ROM BYTE*)"<table>");
	while (pnt)
	{ 
		TCPPutROMString(sktHTTP, (ROM BYTE*)"<tr><td>");
		memcpy (temp, pnt->callsign, 8);
		temp[8] = 0x00;
		TCPPutROMString(sktHTTP, temp);
		TCPPutROMString(sktHTTP, (ROM BYTE*)"</td></tr>");
		pnt = pnt->f_chain;
	}
	TCPPutROMString(sktHTTP, (ROM BYTE*)"</table>");

}

