/*-------------------------------------------------------------------------
   HTTP Server function copy right information

   Copyright (C) 2006-2008. Tang, Li <tangli@palmmicro.com>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   This software is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-------------------------------------------------------------------------*/

#include "version.h"
#include "type.h"
#include "ar168.h"
#include "core.h"
#include "apps.h"
#include "tcpip.h"
#include "bank3.h"

#define MAX_SEND_LEN		384		// should be less than TCP_SND_MSS, the space left is because I don't know exactly how much will be written each time

// Http control block
#define HTTP_CB_TSIZE		2

// HTTP control block structure
struct http_cb 
{
	UCHAR iState;		// state of this HTTP control block
	TCP_HANDLE pTcb;	// TCP handle of this HTTP control block
	UCHAR iGetTask;		// GET task to be fullfilled
	UCHAR iPostTask;	// POST task to be fullfilled
	PCHAR pRecvBuf;		// buffer to store incomplete message from last received packet 
	UCHAR iRecvLen;		// length of the incomplete message

	USHORT sMsgAddr;	// Address of the web page
	USHORT sMsgLen;		// length of a web page
	USHORT sSendLen;	// length of data that has been sent

	ULONG lRecvLen;		// total length of data to receive
	USHORT sPostLen;	// Length of data posted
	UCHAR iUpdatePage;	// Page to be upgraded
	UCHAR iUpdateState;
	UCHAR iCurPage;
};
typedef struct http_cb * HTTP_HANDLE;

#define HTTP_CB_LENGTH		(sizeof(struct http_cb))

// HTTP control block state
#define HS_FREE				0
#define HS_INIT				1
#define HS_HEADER_BEGIN		2
#define HS_HEADER_END		3
#define HS_REQUEST_END		4
#define HS_SEND_BEGIN		5
#define HS_SEND_END			6

// HTTP task
#define HTTP_TASK_NONE					0
#define HTTP_TASK_GET_LOGIN				1
#define	HTTP_TASK_GET_SETTINGS			2
#define	HTTP_TASK_GET_PHONEBOOK			3
#define	HTTP_TASK_GET_PHONEBOOK_BODY	4
#define	HTTP_TASK_GET_PHONEBOOK_TAIL	5
#define	HTTP_TASK_GET_UPGRADE			6
#define	HTTP_TASK_GET_SUCCESS			7
#define	HTTP_TASK_GET_FAILURE			8
#define HTTP_TASK_GET_ABORT				9
#define	HTTP_TASK_GET_IMAGE				10
#define HTTP_TASK_GET_DIGITMAP			11
#define HTTP_TASK_GET_DIGITMAP_BODY		12
#define HTTP_TASK_GET_DIGITMAP_TAIL		14
#define HTTP_TASK_POST_LOGIN			15
#define HTTP_TASK_POST_SETTINGS			16
#define HTTP_TASK_POST_PHONEBOOK		17
#define HTTP_TASK_POST_DIGITMAP			18
#define HTTP_TASK_POST_UPGRADE			19
#define HTTP_TASK_UNKNOWN				255

// WEB PAGE index
#define HTTP_LOGIN_PAGE			0
#define HTTP_SETTINGS_PAGE		4
#define HTTP_PBHEAD_PAGE		8
#define HTTP_PBTAIL_PAGE		12
#define HTTP_UPGRADE_PAGE		16
#define HTTP_SUCCESS_PAGE		20
#define HTTP_FAILURE_PAGE		24
#define HTTP_ABORT_PAGE			28
#define HTTP_IMAGE_PAGE			32
#define HTTP_DMHEAD_PAGE		36
#define HTTP_DMTAIL_PAGE		40

// Content type
#define CTYPE_TEXT_HTML		0
#define CTYPE_IMAGE_JPEG	1

#define UPDATE_STATE_PART1_HEAD		0
#define UPDATE_STATE_PART1_BODY		1
#define UPDATE_STATE_PART2_HEAD		2
#define UPDATE_STATE_PART2_BODY		3
#define UPDATE_STATE_END			4

// local variables
struct http_cb _pHcbData[HTTP_CB_TSIZE];
HTTP_HANDLE _pCurHcb;
TCP_HANDLE _pCurTcb;
TCP_HANDLE _pHttpdTcb;
BOOLEAN _bNeedReboot;
#ifdef OEM_IP20
BOOLEAN Write ;
USHORT sIndexPhn;
#endif
UCHAR _iRebootTimer;

/****************************************************************************
**** HTTP common functions                                                 **
****************************************************************************/

// This data block may cross 0x8000 boundary
void http_read_page(USHORT sDstAddr, USHORT sSrcAddr, USHORT sLen)
{
	USHORT sTemp;
	UCHAR iPage;

	iPage = OptionsGetByte(OPT_SYSTEM_PAGE) + SYSTEM_HTTP_PAGE_OFFSET;

	sTemp = sSrcAddr + sLen;
	if (sSrcAddr < BANK_BASE && sTemp > BANK_BASE)
	{
		sTemp = BANK_BASE - sSrcAddr;
		ReadFlashData(sDstAddr, sSrcAddr, sTemp, iPage);
		ReadFlashData((USHORT)(sDstAddr + sTemp), BANK_BASE, (USHORT)(sLen - sTemp), iPage);
	}
	else
	{
		ReadFlashData(sDstAddr, sSrcAddr, sLen, iPage);
	}
}

/****************************************************************************
**** HTTP control block functions                                          **
****************************************************************************/
void http_cb_free(HTTP_HANDLE pHcb)
{
	if (pHcb->pRecvBuf)
	{
		free(pHcb->pRecvBuf);
	}
	memset((PCHAR)pHcb, 0, HTTP_CB_LENGTH);
	pHcb->iUpdatePage = SYSTEM_INVALID_PAGE;
}

HTTP_HANDLE http_cb_match(TCP_HANDLE pTcb)
{
	UCHAR i;
	HTTP_HANDLE pHcb;

	pHcb = _pHcbData;
	for (i = 0; i < HTTP_CB_TSIZE ; i ++)
	{
		if ((pHcb->iState != HS_FREE) && ((USHORT)pHcb->pTcb == (USHORT)pTcb))
		{
			return pHcb;
		}
		pHcb ++;
	}

	return NULL;
}

BOOLEAN http_cb_busy()
{
	UCHAR i;
	HTTP_HANDLE pHcb;

	pHcb = _pHcbData;
	for (i = 0; i < HTTP_CB_TSIZE ; i ++)
	{
		if (pHcb->iPostTask >= HTTP_TASK_POST_SETTINGS && pHcb->iPostTask <= HTTP_TASK_POST_UPGRADE)
		{
			return TRUE;
		}
		pHcb ++;
	}

	return FALSE;
}

/****************************************************************************
**** Send functions                                                        **
****************************************************************************/
void HttpSendError()
{
	TcpWriteStr(_pCurTcb, "HTTP/1.1 403 Forbidden\r\nConnection: close\r\n\r\n");
}

void HttpSendOK(USHORT sLen, UCHAR iType)
{
	UCHAR pStr[16];

	// fill header
	TcpWriteStr(_pCurTcb, "HTTP/1.1 200 OK\r\nContent-Length: ");
	itoa(sLen, pStr, 10);
	TcpWriteStr(_pCurTcb, pStr);
	TcpWriteStr(_pCurTcb, "\r\n");
	if (iType == CTYPE_IMAGE_JPEG)
	{
		TcpWriteStr(_pCurTcb, "Cache-Control: max-age=86400\r\n");
		TcpWriteStr(_pCurTcb, "Content-Type: image/jpeg");
	}
	else
	{
		TcpWriteStr(_pCurTcb, "Content-Type: text/html");
	}
	TcpWriteStr(_pCurTcb, "\r\nConnection: close\r\n\r\n");
}


/* each item is 4 bytes, first 2 bytes is address, next 2 bytes is length */
void http_prepare_send()
{
	USHORT sLen;
	UCHAR iType, iIndex, iTask;
	UCHAR pHead[64];

	http_read_page((USHORT)pHead, 0, 64);
	iType = CTYPE_TEXT_HTML;
	iTask = _pCurHcb->iGetTask;
	switch (iTask)
	{
	case HTTP_TASK_GET_LOGIN:
		iIndex = HTTP_LOGIN_PAGE;
		break;

	case HTTP_TASK_GET_SETTINGS:
		iIndex = HTTP_SETTINGS_PAGE;
		break;

	case HTTP_TASK_GET_PHONEBOOK:
		iIndex = HTTP_PBHEAD_PAGE;
		break;

	case HTTP_TASK_GET_DIGITMAP:
		iIndex = HTTP_DMHEAD_PAGE;
		break;

	case HTTP_TASK_GET_UPGRADE:
		iIndex = HTTP_UPGRADE_PAGE;
		break;
		
	case HTTP_TASK_GET_SUCCESS:
#ifdef OEM_IP20
		iIndex = HTTP_LOGIN_PAGE;
#else
		iIndex = HTTP_SUCCESS_PAGE;
#endif
		break;

	case HTTP_TASK_GET_FAILURE:
		iIndex = HTTP_FAILURE_PAGE;
		break;

	case HTTP_TASK_GET_ABORT:
#ifdef OEM_IP20
		iIndex = HTTP_UPGRADE_PAGE;
#else
		iIndex = HTTP_ABORT_PAGE;
#endif
		break;

	case HTTP_TASK_GET_IMAGE:
		iIndex = HTTP_IMAGE_PAGE;
		iType = CTYPE_IMAGE_JPEG;
		break;

	default:
		return;
	}
		
	_pCurHcb->sMsgAddr = PCHAR2USHORT((PCHAR)(pHead + iIndex));
	_pCurHcb->sMsgLen = PCHAR2USHORT((PCHAR)(pHead + iIndex + 2));
	_pCurHcb->sSendLen = 0;
	sLen = _pCurHcb->sMsgLen;
	if (iTask == HTTP_TASK_GET_PHONEBOOK)
	{
		sLen += PCHAR2USHORT((PCHAR)(pHead + HTTP_PBTAIL_PAGE + 2));
		sLen += TaskHttpEvent(HTTP_GET_PB_LEN, 0);
	}
	else if (iTask == HTTP_TASK_GET_DIGITMAP)
	{
		sLen += PCHAR2USHORT((PCHAR)(pHead + HTTP_DMTAIL_PAGE + 2));
		sLen += TaskHttpEvent(HTTP_GET_DM_LEN, 0);
	}
#ifdef OEM_IP20
	else if (iTask == HTTP_TASK_GET_SETTINGS || iTask == HTTP_TASK_GET_SUCCESS)
	{
		sLen += TaskHttpEvent(HTTP_GET_SETTINGS_LEN, 0);
	}
#else
	else if (iTask == HTTP_TASK_GET_SETTINGS)
	{
		sLen += TaskHttpEvent(HTTP_GET_SETTINGS_LEN, 0);
	}
#endif
	HttpSendOK(sLen, iType);
}

USHORT http_send_settings(PCHAR pMsg, USHORT sMsgLen)
{
	PCHAR pLeft;
	PCHAR pRight;
	PCHAR pLast;
	USHORT sLen, sIndex;
	PCHAR pInput;

	pLast = pMsg;
	sIndex = 0;
	pInput = (PCHAR)(pMsg + MAX_SEND_LEN + MAX_SEND_LEN);
	while(sIndex < sMsgLen)
	{
		pLeft = strchr(pLast, '<');
		if (pLeft)
		{
			sLen = (USHORT)pLeft - (USHORT)pLast;
			if (sLen)
			{
				TcpWriteData(_pCurTcb, pLast, sLen);
				sIndex += sLen;
			}

			pRight = strchr(pLeft, '>');
			if (pRight)
			{
				sLen = (USHORT)pRight - (USHORT)pLeft + 1;
				memcpy(pInput, pLeft, sLen);
				pInput[sLen] = 0;
				TaskHttpEvent(HTTP_UPDATE_SETTINGS, (USHORT)pInput);
				TcpWriteStr(_pCurTcb, pInput);
				sIndex += sLen;
				pLast = pRight;
				pLast ++;
			}
			else
			{
				break;
			}
		}
		else
		{
			sLen = sMsgLen - ((USHORT)pLast - (USHORT)pMsg);
			if (sLen)
			{
				TcpWriteData(_pCurTcb, pLast, sLen);
				sIndex += sLen;
			}
			break;
		}
	}

	return sIndex;
}

#ifdef OEM_IP20
void http_send_webpage()
{
	PCHAR pMsg;
	USHORT sWebPage;
	USHORT sLeftLen, sMsgLen;
	BOOLEAN bEnd;
	UCHAR pHead[64];
	

	pMsg = Adapter_pIpBuf;
	if (_pCurHcb->iGetTask == HTTP_TASK_GET_PHONEBOOK_BODY)
	{
		pMsg[0] = _pCurHcb->sSendLen;
		TaskHttpEvent(HTTP_UPDATE_PB, (USHORT)pMsg);
		TcpWriteStr(_pCurTcb, pMsg);
		_pCurHcb->sSendLen ++;
		if (_pCurHcb->sSendLen >= 128)		//PHN
		{
			http_read_page((USHORT)pHead, 0, 64);
			_pCurHcb->iGetTask = HTTP_TASK_GET_PHONEBOOK_TAIL;
			_pCurHcb->sMsgAddr = PCHAR2USHORT((PCHAR)(pHead + HTTP_PBTAIL_PAGE));
			_pCurHcb->sMsgLen = PCHAR2USHORT((PCHAR)(pHead + HTTP_PBTAIL_PAGE + 2));
			//_pCurHcb->sMsgAddr = PCHAR2USHORT((PCHAR)(pHead + HTTP_PBHEAD_PAGE));
			//_pCurHcb->sMsgLen = PCHAR2USHORT((PCHAR)(pHead + HTTP_PBHEAD_PAGE + 2));
			_pCurHcb->sSendLen = 0;
		}
	}
	
	else if (_pCurHcb->iGetTask == HTTP_TASK_GET_DIGITMAP_BODY)
	{
		
		
				
		if(_pCurHcb->sSendLen == 0){
		pMsg[0] = 7;
		}
		else if(_pCurHcb->sSendLen == 1){
			
			pMsg[0] = 119;
		}
		else if(_pCurHcb->sSendLen == 2){
			
			pMsg[0] = 8;
		}
		else if(_pCurHcb->sSendLen == 3){
			
			pMsg[0] = 0;
		}
		else if(_pCurHcb->sSendLen == 4){
			
			pMsg[0] = 9;
		}
		else if(_pCurHcb->sSendLen == 5){
			
			pMsg[0] = 1;
		}
		else if(_pCurHcb->sSendLen == 6){
			
			pMsg[0] = 10;
		}
		else if(_pCurHcb->sSendLen == 7){
			
			pMsg[0] = 2;
		}
		else if(_pCurHcb->sSendLen == 8){
			
			pMsg[0] = 11;
		}
		else if(_pCurHcb->sSendLen == 9){
			
			pMsg[0] = 3;
		}
		else if(_pCurHcb->sSendLen == 10){
			
			pMsg[0] = 12;
		}
		else if(_pCurHcb->sSendLen == 11){
			
			pMsg[0] = 4;
		}
		else if(_pCurHcb->sSendLen == 12){
			
			pMsg[0] = 13;
		}
		else if(_pCurHcb->sSendLen == 13){
			
			pMsg[0] = 5;
		}
		else if(_pCurHcb->sSendLen == 14){
			
			pMsg[0] = 14;
		}
		else if(_pCurHcb->sSendLen == 15){
			pMsg[0] = 6;			
		}
		
		//pMsg[0] = _pCurHcb->sSendLen;				
		TaskHttpEvent(HTTP_UPDATE_DM, (USHORT)pMsg);
		TcpWriteStr(_pCurTcb, pMsg);
		//UdpDebugVal(_pCurHcb->sSendLen , 10) ;		
		_pCurHcb->sSendLen ++;
				
		if (_pCurHcb->sSendLen >= 16)	//PHN
		{
			http_read_page((USHORT)pHead, 0, 64);
			_pCurHcb->iGetTask = HTTP_TASK_GET_DIGITMAP_TAIL;	//Change
			_pCurHcb->sMsgAddr = PCHAR2USHORT((PCHAR)(pHead + HTTP_DMTAIL_PAGE));
			_pCurHcb->sMsgLen = PCHAR2USHORT((PCHAR)(pHead + HTTP_DMTAIL_PAGE + 2));
			_pCurHcb->sSendLen = 0;
		}
	}
	else
	{
		bEnd = FALSE;
		sLeftLen = _pCurHcb->sMsgLen - _pCurHcb->sSendLen;
		sWebPage = _pCurHcb->sMsgAddr + _pCurHcb->sSendLen;
		// fill body
		if (sLeftLen > MAX_SEND_LEN)
		{
			sMsgLen = MAX_SEND_LEN;
		}
		else
		{
			sMsgLen = sLeftLen;
			bEnd = TRUE;
		}

		http_read_page((USHORT)pMsg, sWebPage, sMsgLen);

		if (_pCurHcb->iGetTask == HTTP_TASK_GET_SETTINGS || _pCurHcb->iGetTask == HTTP_TASK_GET_SUCCESS)
		{
			pMsg[sMsgLen] = 0;
			_pCurHcb->sSendLen += http_send_settings(pMsg, sMsgLen);
		}
		else
		{
			TcpWriteData(_pCurTcb, pMsg, sMsgLen);
			_pCurHcb->sSendLen += sMsgLen;
		}
		if (bEnd)
		{
			if (_pCurHcb->iGetTask == HTTP_TASK_GET_PHONEBOOK)
			{
				_pCurHcb->iGetTask = HTTP_TASK_GET_PHONEBOOK_BODY;
				_pCurHcb->sSendLen = 0;
			}
			
			else if (_pCurHcb->iGetTask == HTTP_TASK_GET_DIGITMAP)
			{
				_pCurHcb->iGetTask = HTTP_TASK_GET_DIGITMAP_BODY;
				_pCurHcb->sSendLen = 0;
			}
			else
			{
				_pCurHcb->iState = HS_SEND_END;
			}
		}
	}
}
#else

void http_send_webpage()
{
	PCHAR pMsg;
	USHORT sWebPage;
	USHORT sLeftLen, sMsgLen;
	BOOLEAN bEnd;
	UCHAR pHead[64];

	pMsg = Adapter_pIpBuf;
	if (_pCurHcb->iGetTask == HTTP_TASK_GET_PHONEBOOK_BODY)
	{
		pMsg[0] = _pCurHcb->sSendLen;
		TaskHttpEvent(HTTP_UPDATE_PB, (USHORT)pMsg);
		TcpWriteStr(_pCurTcb, pMsg);
		_pCurHcb->sSendLen ++;
		if (_pCurHcb->sSendLen >= PHONEBOOK_ENTRY_NUM)
		{
			http_read_page((USHORT)pHead, 0, 64);
			_pCurHcb->iGetTask = HTTP_TASK_GET_PHONEBOOK_TAIL;
			_pCurHcb->sMsgAddr = PCHAR2USHORT((PCHAR)(pHead + HTTP_PBTAIL_PAGE));
			_pCurHcb->sMsgLen = PCHAR2USHORT((PCHAR)(pHead + HTTP_PBTAIL_PAGE + 2));
			_pCurHcb->sSendLen = 0;
		}
	}
	else if (_pCurHcb->iGetTask == HTTP_TASK_GET_DIGITMAP_BODY)
	{
		pMsg[0] = _pCurHcb->sSendLen;
		TaskHttpEvent(HTTP_UPDATE_DM, (USHORT)pMsg);
		TcpWriteStr(_pCurTcb, pMsg);
		_pCurHcb->sSendLen +=2;
		if (_pCurHcb->sSendLen >= DIGITMAP_ENTRY_NUM)
		{
			http_read_page((USHORT)pHead, 0, 64);
			_pCurHcb->iGetTask = HTTP_TASK_GET_DIGITMAP_TAIL;
			_pCurHcb->sMsgAddr = PCHAR2USHORT((PCHAR)(pHead + HTTP_DMTAIL_PAGE));
			_pCurHcb->sMsgLen = PCHAR2USHORT((PCHAR)(pHead + HTTP_DMTAIL_PAGE + 2));
			_pCurHcb->sSendLen = 0;
		}
	}
	else
	{
		bEnd = FALSE;
		sLeftLen = _pCurHcb->sMsgLen - _pCurHcb->sSendLen;
		sWebPage = _pCurHcb->sMsgAddr + _pCurHcb->sSendLen;
		// fill body
		if (sLeftLen > MAX_SEND_LEN)
		{
			sMsgLen = MAX_SEND_LEN;
		}
		else
		{
			sMsgLen = sLeftLen;
			bEnd = TRUE;
		}

		http_read_page((USHORT)pMsg, sWebPage, sMsgLen);

		if (_pCurHcb->iGetTask == HTTP_TASK_GET_SETTINGS)
		{
			pMsg[sMsgLen] = 0;
			_pCurHcb->sSendLen += http_send_settings(pMsg, sMsgLen);
		}
		else
		{
			TcpWriteData(_pCurTcb, pMsg, sMsgLen);
			_pCurHcb->sSendLen += sMsgLen;
		}
		if (bEnd)
		{
			if (_pCurHcb->iGetTask == HTTP_TASK_GET_PHONEBOOK)
			{
				_pCurHcb->iGetTask = HTTP_TASK_GET_PHONEBOOK_BODY;
				_pCurHcb->sSendLen = 0;
			}
			else if (_pCurHcb->iGetTask == HTTP_TASK_GET_DIGITMAP)
			{
				_pCurHcb->iGetTask = HTTP_TASK_GET_DIGITMAP_BODY;
				_pCurHcb->sSendLen = 0;
			}
			else
			{
				_pCurHcb->iState = HS_SEND_END;
			}
		}
	}
}

#endif
/****************************************************************************
**** Receive functions                                                        **
****************************************************************************/
void http_write_flash()
{
	TaskSystemHandler(SYS_MODIFY_PAGE, SYSTEM_SETTINGS_PAGE);
	FlashWritePage(SYSTEM_SETTINGS_PAGE);
}

void http_handle_login_data(PCHAR pBuf)
{
	PCHAR pCur;
	UCHAR pAdmin[MAX_DNS_LEN];
	UCHAR iGetTask;

	pCur = pBuf;
	if (!memcmp_str(pCur, "auth="))
	{
		pCur += 5;
		OptionsGetString(pAdmin, OPT_ADMIN_PIN, MAX_ADMIN_PIN_LEN);
		if (strcmp(pCur, pAdmin))
		{
			_pCurHcb->iGetTask = HTTP_TASK_GET_FAILURE;
		}
	}
#ifdef OEM_INNOMEDIA
	else if (!memcmp_str(pCur, "login_user="))
	{
		pCur += 11;
		OptionsGetString(pAdmin, OPT_ADMIN_USER, MAX_ADMIN_USER_LEN);
		if (strcmp(pCur, pAdmin))
		{
			_pCurHcb->iGetTask = HTTP_TASK_GET_FAILURE;
		}
	}
#endif
	else if (!memcmp_str(pCur, "nextpage="))
	{
		pCur += 9;
		iGetTask = HTTP_TASK_GET_LOGIN;
		if (!strcmp(pCur, "settings"))
		{
			iGetTask = HTTP_TASK_GET_SETTINGS;
		}
		else if (!strcmp(pCur, "phonebook"))
		{
			iGetTask = HTTP_TASK_GET_PHONEBOOK;
#ifdef OEM_IP20
			Write = FALSE;
#endif
		}
		else if (!strcmp(pCur, "digitmap"))
		{
			iGetTask = HTTP_TASK_GET_DIGITMAP;
		}
		else if (!strcmp(pCur, "upgrade"))
		{
			iGetTask = HTTP_TASK_GET_UPGRADE;
		}
		_pCurHcb->iGetTask = iGetTask;
	}
}

void http_handle_settings_data(PCHAR pBuf)
{
	if (!memcmp_str(pBuf, "update="))
	{
		http_write_flash();
		// End of settings list
		_pCurHcb->iGetTask = HTTP_TASK_GET_SUCCESS;
		_pCurHcb->iUpdatePage = SYSTEM_SETTINGS_PAGE;
	}
#ifdef OEM_IP20
	else if (!memcmp_str(pBuf, "reset="))
	{	
		_pCurHcb->iGetTask = HTTP_TASK_GET_SUCCESS;
		_pCurHcb->iUpdatePage = SYSTEM_SETTINGS_PAGE;
	}
#endif
	else
	{
		TaskHttpEvent(HTTP_WRITE_SETTINGS, (USHORT)pBuf);
	}

}
// n001 name
// p001 number
void http_handle_pb_data(PCHAR pBuf)
{
#ifdef OEM_IP20
	sIndexPhn = atoi((PCHAR)(pBuf + 1), 10) - 1;	
#endif

	
	if (!memcmp_str(pBuf, "write="))
	{
#ifdef OEM_IP20
		Write = TRUE;
#else
		http_write_flash();
		// End of phonebook list
		_pCurHcb->iGetTask = HTTP_TASK_GET_SUCCESS;
		_pCurHcb->iUpdatePage = SYSTEM_SETTINGS_PAGE;
#endif		
	}
#ifdef OEM_IP20
	else if(!memcmp_str(pBuf, "reset="))
	{
		_pCurHcb->iGetTask = HTTP_TASK_GET_SUCCESS;
		_pCurHcb->iUpdatePage = SYSTEM_SETTINGS_PAGE;
	}
#endif
	else
	{
		if (pBuf[0] == 'n' || pBuf[0] == 'p')
		{
			TaskHttpEvent(HTTP_WRITE_PB, (USHORT)pBuf);
		}
	}
#ifdef OEM_IP20
		if (Write == 1 && sIndexPhn > 126)
		{
		http_write_flash();
		_pCurHcb->iGetTask = HTTP_TASK_GET_SUCCESS;
		_pCurHcb->iUpdatePage = SYSTEM_SETTINGS_PAGE;
		}
#endif

}

// m001 digtmap
void http_handle_dm_data(PCHAR pBuf)
{
	if (!memcmp_str(pBuf, "write="))
	{
		http_write_flash();
		// End of phonebook list
		_pCurHcb->iGetTask = HTTP_TASK_GET_SUCCESS;
		_pCurHcb->iUpdatePage = SYSTEM_SETTINGS_PAGE;
	}
#ifdef OEM_IP20
	else if (!memcmp_str(pBuf, "reset="))
	{
		_pCurHcb->iGetTask = HTTP_TASK_GET_SUCCESS;
		_pCurHcb->iUpdatePage = SYSTEM_SETTINGS_PAGE;
	}
#endif
		
	else
	{
#ifdef OEM_IP20
		if (pBuf[0] == 'n' || pBuf[0] == 'p')
		{
			TaskHttpEvent(HTTP_WRITE_PB, (USHORT)pBuf);
		}
#else
		if (pBuf[0] == 'm')
		{
			TaskHttpEvent(HTTP_WRITE_DM, (USHORT)pBuf);
		}
#endif		
	}
}

void http_handle_postdata(UCHAR iRecvLen, PCHAR pBuf)
{
	UCHAR i, iChar, iLen;
	UCHAR pTemp[3];

	if (!iRecvLen)	return;

	iLen = 0;
	pTemp[2] = 0;
	for (i = 0; i < iRecvLen; i ++)
	{
		iChar = pBuf[i];
		if (iChar == '+')
		{
			iChar = ' ';
		}
		else if (iChar == '%')
		{
			memcpy(pTemp, (PCHAR)(pBuf+i+1), 2);
			iChar = (UCHAR)atoi(pTemp, 16);
			i += 2;
		}
		pBuf[iLen] = iChar;
		iLen ++;
	}
	pBuf[iLen] = 0;

	switch (_pCurHcb->iPostTask)
	{
	case HTTP_TASK_POST_LOGIN:
		http_handle_login_data(pBuf);
		break;

	case HTTP_TASK_POST_SETTINGS:
		http_handle_settings_data(pBuf);
		break;

	case HTTP_TASK_POST_PHONEBOOK:
		http_handle_pb_data(pBuf);
		break;

	case HTTP_TASK_POST_DIGITMAP:
		http_handle_dm_data(pBuf);
		break;
	}
}

void http_handle_firstline(PCHAR pBuf)
{
	PCHAR pCur;
	PCHAR pTemp;
	UCHAR iGetTask, iPostTask;

	pCur = pBuf;
	_pCurHcb->iState = HS_HEADER_BEGIN;
	iGetTask = HTTP_TASK_UNKNOWN;
	iPostTask = HTTP_TASK_UNKNOWN;

	// Format of this message is "Method SP URL SP HTTP/version CRLF"
	if (!memcmp_str(pCur, "GET "))
	{
		pCur += 4;
		pTemp = strchr(pCur, ' ');
		if (pTemp)	*pTemp = 0;
		if (!strcmp(pCur, "/"))
		{
			iGetTask = HTTP_TASK_GET_LOGIN;
		}
		else if (!strcmp(pCur, "/image.jpg"))
		{
			iGetTask = HTTP_TASK_GET_IMAGE;
		}
	}
	else if (!memcmp_str(pCur, "POST "))
	{
		pCur += 5;
		pTemp = strchr(pCur, ' ');
		if (pTemp)		*pTemp = 0;		
		if (!strcmp(pCur, "/login"))
		{
			// retrieve login password
			iPostTask = HTTP_TASK_POST_LOGIN;
		}
		else if (!strcmp(pCur, "/settings"))
		{
			// retrieve settings
			iPostTask = HTTP_TASK_POST_SETTINGS;
		}
		else if (!strcmp(pCur, "/phonebook"))
		{
			// retrieve phone book
			iPostTask = HTTP_TASK_POST_PHONEBOOK;
		}
		else if (!strcmp(pCur, "/digitmap"))
		{
			// retrieve digit map
			iPostTask = HTTP_TASK_POST_DIGITMAP;
		}
		else if (!strcmp(pCur, "/upgrade"))
		{
			iPostTask = HTTP_TASK_POST_UPGRADE;
		}
	}

	_pCurHcb->iGetTask = iGetTask;
	_pCurHcb->iPostTask = iPostTask;
}

void http_get_info(PCHAR pBuf)
{
	UCHAR iLen;
	PCHAR pCur;
	UCHAR pHeader[24];

	iLen = 0;
	pCur = pBuf;
	while (*pCur && *pCur != ' ' && *pCur != ':')
	{
		pHeader[iLen] = *pCur;
		iLen ++;
		pCur ++;
		if (iLen >= 24)
		{
			return;
		}
	}
	pHeader[iLen] = 0;

	while (*pCur == ' ' || *pCur == ':')
	{
		pCur ++;
	}
//	to_lower(pHeader, iLen);

	if (!strcmp_lowercase(pHeader, "content-length"))
	{
		_pCurHcb->lRecvLen = atol(pCur, 10);
	}
}

void http_handle_header(PCHAR pBuf, UCHAR iLen)
{
//	PCHAR pTemp;

	pBuf[iLen] = 0;

	if (_pCurHcb->iState == HS_INIT)
	{
		http_handle_firstline(pBuf);
	}
	else if (_pCurHcb->iState == HS_HEADER_BEGIN)
	{
		if (iLen)
		{
			http_get_info(pBuf);
		}
		else 
		{
			if (_pCurHcb->lRecvLen)
			{
				_pCurHcb->iState = HS_HEADER_END;
			}
			else
			{
				_pCurHcb->iState = HS_REQUEST_END;
			}
			if (_pCurHcb->iPostTask == HTTP_TASK_POST_SETTINGS || _pCurHcb->iPostTask == HTTP_TASK_POST_PHONEBOOK || _pCurHcb->iPostTask == HTTP_TASK_POST_DIGITMAP)
			{
				ReadFlashPage(SYSTEM_SETTINGS_PAGE);
			}
		}
	}
}

void http_handle_upgrade_header(PCHAR pBuf, UCHAR iLen)
{
	UCHAR iVal, iPage;

	switch (_pCurHcb->iUpdateState)
	{
	case UPDATE_STATE_PART1_HEAD:
		if (!iLen)
		{
			UdpDebugString("Part1 Body");
			_pCurHcb->iUpdateState = UPDATE_STATE_PART1_BODY;
		}
		break;

	case UPDATE_STATE_PART1_BODY:
		iVal = (UCHAR)atoi(pBuf, 10);
		BufSeek(0);
		if (iVal == 0)	
		{
			if (OptionsGetByte(OPT_SYSTEM_PAGE) == SYSTEM_1ST_PAGE)
			{
				iPage = SYSTEM_2ND_PAGE;
			}
			else
			{
				iPage = SYSTEM_1ST_PAGE;
			}
		}
		else if (iVal == 1)
		{
			ReadFlashPage(SYSTEM_SETTINGS_PAGE);
			iPage = SYSTEM_SETTINGS_PAGE;
			_pCurHcb->sSendLen = SETTINGS_FILE_SIZE;
		}
		else if (iVal == 2)
		{
			// phonebook
			ReadFlashPage(SYSTEM_SETTINGS_PAGE);
			iPage = SYSTEM_SETTINGS_PAGE;
			_pCurHcb->sSendLen = PHONEBOOK_FILE_SIZE;
			BufSeek(OPT_PHONE_BOOK);
		}
		else if (iVal == 3)
		{
			iPage = SYSTEM_RINGTONE_PAGE;
		}
		else if (iVal == 4)
		{
			iPage = SYSTEM_HOLDMUSIC_PAGE;
		}
		else
		{
			iPage = SYSTEM_INVALID_PAGE;
			UdpDebugString("Invalid page number");
		}
		_pCurHcb->iUpdatePage = iPage;
		_pCurHcb->iCurPage = iPage;
		_pCurHcb->iUpdateState = UPDATE_STATE_PART2_HEAD;
		break;

	case UPDATE_STATE_PART2_HEAD:
		if (!iLen)
		{
			UdpDebugString("Part2 Body");
			_pCurHcb->iUpdateState = UPDATE_STATE_PART2_BODY;
			_pCurHcb->sPostLen = 0;
		}
		break;
	}
}

void http_handle_upgrade_body(USHORT sLen, PCHAR pBuf)
{
	USHORT sLeftLen, sLen2;
	UCHAR iPageNum;

	if (_pCurHcb->iUpdatePage == SYSTEM_INVALID_PAGE)		return;

	if (_pCurHcb->iUpdatePage == SYSTEM_SETTINGS_PAGE)
	{
		sLeftLen = _pCurHcb->sSendLen - _pCurHcb->sPostLen;
	}
	else
	{
		sLeftLen = FILE_FULL_PAGE_SIZE - _pCurHcb->sPostLen;
	}

	if (sLen < sLeftLen || !sLeftLen)
	{
		BufWrite(pBuf, sLen);
		BufForward(sLen);
		_pCurHcb->sPostLen += sLen; 
	}
	else
	{
		BufWrite(pBuf, sLeftLen);
		BufForward(sLeftLen);
		_pCurHcb->sPostLen = 0;
		if (_pCurHcb->iUpdatePage == SYSTEM_SETTINGS_PAGE)
		{
			http_write_flash();
			_pCurHcb->iUpdateState = UPDATE_STATE_END;
			return;
		}
		else
		{
			if (_pCurHcb->iUpdatePage == SYSTEM_RINGTONE_PAGE)
			{
				iPageNum = SYSTEM_RINGTONE_PAGE_NUM;
			}
			else if (_pCurHcb->iUpdatePage == SYSTEM_HOLDMUSIC_PAGE)
			{
				iPageNum = SYSTEM_HOLDMUSIC_PAGE_NUM;
			}
			else
			{
				iPageNum = SYSTEM_PROGRAM_PAGE_NUM;
			}
			TaskUIHandler(UI_UPDATE_PROGRESS, (USHORT)_pCurHcb->iCurPage);
			if (FlashWritePage(_pCurHcb->iCurPage))
			{
				_pCurHcb->iUpdatePage = SYSTEM_INVALID_PAGE;
				_pCurHcb->iUpdateState = UPDATE_STATE_END;
				return;
			}
			_pCurHcb->iCurPage ++;
			if ((_pCurHcb->iCurPage - _pCurHcb->iUpdatePage) >= iPageNum)
			{
				if (_pCurHcb->iUpdatePage == SYSTEM_1ST_PAGE || _pCurHcb->iUpdatePage == SYSTEM_2ND_PAGE)
				{
					TaskSystemHandler(SYS_UPDATE_FLAG, _pCurHcb->iCurPage);
				}
				_pCurHcb->iUpdateState = UPDATE_STATE_END;
				return;
			}
			else
			{
				sLen2 = (USHORT)(sLen - sLeftLen);
				BufSeek(0);
				BufWrite((PCHAR)(pBuf + sLeftLen), sLen2);
				BufForward(sLen2);
				_pCurHcb->sPostLen = sLen2;
			}
		}
	}
}

void http_save_recv(UCHAR iVal)
{
	if (_pCurHcb->iRecvLen < HTTP_MAX_RECV_LEN-1)
	{
		_pCurHcb->pRecvBuf[_pCurHcb->iRecvLen] = iVal;
		_pCurHcb->iRecvLen ++;
	}
}

void http_handle_content(USHORT sLen, PCHAR pBuf)
{
	ULONG lContentLen;
	UCHAR iVal, iNextVal, iTask;
	BOOLEAN bBrokenLine;

	lContentLen = _pCurHcb->lRecvLen;
	iTask = _pCurHcb->iPostTask;

	if (iTask == HTTP_TASK_POST_LOGIN || iTask == HTTP_TASK_POST_SETTINGS || iTask == HTTP_TASK_POST_PHONEBOOK || iTask == HTTP_TASK_POST_DIGITMAP)
	{
		while (lContentLen && sLen)
		{
			iVal = *pBuf;
			if (iVal == '&')
			{
				http_handle_postdata(_pCurHcb->iRecvLen, _pCurHcb->pRecvBuf);
				_pCurHcb->iRecvLen = 0;
			}
			else
			{
				http_save_recv(iVal);
			}
			lContentLen --;
			sLen --;
			pBuf ++;		
		}
		if (!lContentLen)
		{
			if (_pCurHcb->iRecvLen)
			{
				http_handle_postdata(_pCurHcb->iRecvLen, _pCurHcb->pRecvBuf);
				_pCurHcb->iRecvLen = 0;
			}
			_pCurHcb->iState = HS_REQUEST_END;
		}

		_pCurHcb->lRecvLen = lContentLen;
		return;
	}

	if (iTask == HTTP_TASK_POST_UPGRADE)
	{
		while (lContentLen && sLen)
		{
			if (_pCurHcb->iUpdateState < UPDATE_STATE_PART2_BODY)
			{
				bBrokenLine = FALSE;
				if (_pCurHcb->iRecvLen && _pCurHcb->pRecvBuf[_pCurHcb->iRecvLen-1] == 0x0d)
				{
					bBrokenLine = TRUE;
					_pCurHcb->iRecvLen --;
				}
				iVal = *pBuf;
				pBuf ++;
				sLen --;
				lContentLen --;
				if (iVal == 0x0d)
				{
					if (sLen)
					{
						iNextVal = *pBuf;
						pBuf ++;
						sLen --;
						lContentLen --;
						if (iNextVal == 0x0a)
						{
							http_handle_upgrade_header(_pCurHcb->pRecvBuf, _pCurHcb->iRecvLen);
							_pCurHcb->iRecvLen = 0;
						}
						else
						{
							http_save_recv(iVal);
							http_save_recv(iNextVal);
						}
						continue;
					}
				}
				else if (iVal == 0x0a)
				{
					if (bBrokenLine)
					{
						http_handle_upgrade_header(_pCurHcb->pRecvBuf, _pCurHcb->iRecvLen);
						_pCurHcb->iRecvLen = 0;
						bBrokenLine = FALSE;
						continue;
					}
				}
				http_save_recv(iVal);
			}
			else
			{
				if (_pCurHcb->iUpdateState == UPDATE_STATE_PART2_BODY)
				{
					http_handle_upgrade_body(sLen, pBuf);
				}
				break;
			}
		}
	}

	if (lContentLen > (ULONG)sLen)
	{
		lContentLen -= (ULONG)sLen;
	}
	else
	{
		UdpDebugString("upgrade data end");
		lContentLen = 0;
		_pCurHcb->iState = HS_REQUEST_END;
		if (_pCurHcb->iUpdatePage == SYSTEM_INVALID_PAGE || _pCurHcb->iUpdateState != UPDATE_STATE_END)
		{
			_pCurHcb->iGetTask = HTTP_TASK_GET_ABORT;
		}
		else
		{
			_pCurHcb->iGetTask = HTTP_TASK_GET_SUCCESS;
		}
	}

End:
	_pCurHcb->lRecvLen = lContentLen;
}

void http_run_data(USHORT sLen, PCHAR pBuf)
{
	UCHAR iVal, iNextVal;
	BOOLEAN bBrokenLine;
	
	if (!_pCurHcb->pRecvBuf)	return;

	while (sLen)
	{
		if (_pCurHcb->iState < HS_HEADER_END)
		{
			bBrokenLine = FALSE;
			if (_pCurHcb->iRecvLen && _pCurHcb->pRecvBuf[_pCurHcb->iRecvLen-1] == 0x0d)
			{
				bBrokenLine = TRUE;
				_pCurHcb->iRecvLen --;
			}

			iVal = *pBuf;
			pBuf ++;
			sLen --;
			if (iVal == 0x0d)
			{
				if (sLen)
				{
					iNextVal = *pBuf;
					pBuf ++;
					sLen --;
					if (iNextVal == 0x0a)
					{
						http_handle_header(_pCurHcb->pRecvBuf, _pCurHcb->iRecvLen);
						_pCurHcb->iRecvLen = 0;
					}
					else
					{
						http_save_recv(iVal);
						http_save_recv(iNextVal);
					}
					continue;
				}
			}
			else if (iVal == 0x0a)
			{
				if (bBrokenLine)
				{
					http_handle_header(_pCurHcb->pRecvBuf, _pCurHcb->iRecvLen);
					_pCurHcb->iRecvLen = 0;
					bBrokenLine = FALSE;
					continue;
				}
			}
			http_save_recv(iVal);
		}
		else 
		{
			if (_pCurHcb->iState == HS_HEADER_END)
			{
				http_handle_content(sLen, pBuf);
			}
			break;
		}
	}
}

HTTP_HANDLE http_alloc()
{
	UCHAR i;
	HTTP_HANDLE pHcb;

	pHcb = _pHcbData;
	for (i = 0; i < HTTP_CB_TSIZE; i ++, pHcb ++)
	{
		if (pHcb->iState == HS_FREE)
		{
			pHcb->pRecvBuf = (PCHAR)malloc(HTTP_MAX_RECV_LEN + 1);
			if (pHcb->pRecvBuf)
			{
				return pHcb;
			}
			else
			{
				UdpDebugString("No more space for HTTP");
				heap_debug();
				return NULL;
			}
		}
	}
	UdpDebugString("No HTTP control block");
	return NULL;
}

void HttpdInit()
{
	UCHAR i;
	HTTP_HANDLE pHcb;

	pHcb = _pHcbData;
	for (i = 0; i < HTTP_CB_TSIZE; i ++)
	{
		memset((PCHAR)pHcb, 0, HTTP_CB_LENGTH);
		pHcb->iUpdatePage = SYSTEM_INVALID_PAGE;
		pHcb ++;
	}
	
	_pHttpdTcb = TcpListen(HTTP_SERVER_PORT, HTTP_BANK_OFFSET, (USHORT)HttpdRun);
	_bNeedReboot = FALSE;
	_iRebootTimer = 0;
}

void HttpdRun(TCP_HANDLE h, USHORT sLen, PCHAR pBuf)
{
	UCHAR iEvent;

	iEvent = TcpGetEvent(h);
	if (iEvent & TCP_EVENT_ACCEPT)
	{
		UdpDebugString("Http accept");
		if ((Sys_iCurMode != SYS_MODE_STANDBY && Sys_iCurMode != SYS_MODE_HTTPD) || http_cb_busy())
		{
			UdpDebugString("HTTP blocked");
			TcpFree(h);
		}
		else
		{
			_pCurHcb = http_alloc();
			if (!_pCurHcb)
			{
				TcpFree(h);
			}
			else
			{
				TaskUIHandler(UI_CHANGE_MODE, SYS_MODE_HTTPD);
				_pCurHcb->iState = HS_INIT;
				_pCurHcb->pTcb = h;
				TcpSetTimeout(h, HTTP_ACTIVE_TIMEOUT);
				TcpClearEvent(h);
				TcpStartSend(h);
			}
		}
		return;
	}

	_pCurHcb = http_cb_match(h);
	if (!_pCurHcb)
	{
		UdpDebugString("unkown Httpd handle");
		TcpFree(h);
		return;
	}
	if (iEvent & (TCP_EVENT_RESET|TCP_EVENT_ABORT|TCP_EVENT_USERTO|TCP_EVENT_RETRYTO))
	{
		UdpDebugString("Http reset/abort/timeout");
		if (iEvent & TCP_EVENT_ABORT)
		{
			TcpStartSend(h);
		}
		TcpFree(h);
		// should wait for some time before re-init this socket?
		if (_pCurHcb->iUpdatePage != SYSTEM_INVALID_PAGE)
		{
			_bNeedReboot = TRUE;
			_iRebootTimer = 0;
		}
		else
		{
			TaskUIHandler(UI_CHANGE_MODE, SYS_MODE_STANDBY);
		}
		http_cb_free(_pCurHcb);
		return;
	}

	_pCurTcb = h;
	if (iEvent & TCP_EVENT_CONNECT)
	{
		UdpDebugString("Http connect");
	}
	if (iEvent & TCP_EVENT_DATA)
	{
//		UdpDebugString("Http data");
		http_run_data(sLen, pBuf);
	}
	if (iEvent & TCP_EVENT_CLOSE)
	{
		UdpDebugString("Http close");
		if (_pCurHcb->iState < HS_REQUEST_END)
		{
			_pCurHcb->iState = HS_REQUEST_END;
		}
		TcpClose(_pCurTcb);
	}

	TcpClearEvent(_pCurTcb);

	while (TcpCanWrite(_pCurTcb, MAX_SEND_LEN))
	{
		if (_pCurHcb->iState == HS_REQUEST_END)
		{
			if (_pCurHcb->iGetTask == HTTP_TASK_UNKNOWN)
			{
				HttpSendError();
				TcpClose(_pCurTcb);
				_pCurHcb->iState = HS_INIT;
				break;
			}
			else
			{
				http_prepare_send();
				_pCurHcb->iState = HS_SEND_BEGIN;
			}
		}
		else if (_pCurHcb->iState == HS_SEND_BEGIN)
		{
			http_send_webpage();
			if (_pCurHcb->iState == HS_SEND_END)
			{
				TcpClose(_pCurTcb);
				_pCurHcb->iState = HS_INIT;
				break;
			}
		}
		else
		{
			break;
		}
	}

	TcpStartSend(_pCurTcb);
}

void HttpdTimer()
{
	if (_bNeedReboot)
	{
		_iRebootTimer ++;
		if (_iRebootTimer > HTTP_REBOOT_TIMEOUT)
		{
			UdpDebugString("rebooting ...");
			FlashReboot();
		}
	}
}

void HttpInit()
{
	HttpdInit();
	HttpcInit();
}

/*
void HttpTimer()
{
	HttpdTimer();
	HttpcTimer();
}
*/
