#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "SmsSender.h"
#include <iterator>

#define DEFAULT_BUFFER_SIZE   9216 		
#define MaxSizeOfTRxBuffer		1024


string CSmsSender::RemoveBlankSpace(const char* pszData, size_t nLength)
{
    char * szTemp = NULL;
    string strReturn;
    const char * src;
    char * dest;


    szTemp = (char*) ::malloc(sizeof(char) * nLength +1);
    ::memset(szTemp, 0 , sizeof(char)*nLength +1);

    src = pszData;
    dest = szTemp;

    if( pszData == NULL )
    {
        strReturn.clear();
        return strReturn;
    }

    if( *src == '\0' )
    {
        strReturn = src;
        return strReturn;
    }
    // start with 2nd position
    src++;
    while ( src <= (pszData + nLength)  && *(src-1) != '\0' )
    {
        if( *(src-1) == ' ' && *(src) == ' ' )
        {  // 연속된 공백이 발견되면, 스킵한다.
            src++;
            continue;
        }
        *dest = *(src-1);
        src++;
        dest++;
    }
    // 종료표기
	dest++;
    *(dest) = '\0';

    strReturn = szTemp;
	if (szTemp != NULL)
	{
		free(szTemp);
		szTemp = NULL;
	}
    return strReturn;
}
char hexchars[] = "0123456789ABCDEF";
string CSmsSender::PostDataEncode(const char *pszCommand, size_t length)
{
	int i;
	char tmpBuffer[MaxSizeOfTRxBuffer];
	string strReturn;

	if( pszCommand == NULL )
	{
		strReturn.clear();
		return strReturn;
	}

	::memset(tmpBuffer, 0 , MaxSizeOfTRxBuffer);
	i = 0;
	while( *pszCommand != '\0' )
	{
		if( *pszCommand == ' ' )
		{ // ' ' => '+'
			tmpBuffer[i++] = '+';
			pszCommand++;
		}
		else if(*pszCommand == '%')
		{ // % => %%
			tmpBuffer[i++] = '%';
			tmpBuffer[i++] = '%';
			pszCommand++;
		}
		else if( (*pszCommand < '0' && *pszCommand != '-' && *pszCommand != '.' )
				|| (*pszCommand < 'A' && *pszCommand > '9' ) 
				|| (*pszCommand > 'Z' && *pszCommand < 'a' && *pszCommand != '_' ) 
				|| (*pszCommand > 'z' ) )
		{
			tmpBuffer[i++] = '%';
			tmpBuffer[i++] = hexchars[(unsigned char)*pszCommand >> 4];
			tmpBuffer[i++] = hexchars[(unsigned char)*pszCommand & 15];
			pszCommand++;
		}
		else
		{
			tmpBuffer[i++] = *pszCommand++;
		}
	}
	tmpBuffer[i] = '\0';

	strReturn = tmpBuffer;
	return strReturn;
}



	CSmsSender::CSmsSender(const std::string& szHost, const int nPort, const std::string& szPath)
: CBaseSocket( SOCKET_NOT_VALID), m_szHost(szHost), m_nPort(nPort), m_szPath(szPath)
{
	// 생성자
}

CSmsSender::~CSmsSender()
{
	// 소멸자에 BaseSocket의 명시적 Close 처리를 한다.
	Close();
}

bool CSmsSender::Init(void) 
{
	bool bRet = false;

	// 데이터 체크
	if( m_szHost.empty() || m_nPort < 0 || m_szPath.empty() )
	{
		LOG(LERR, "Invalid Parameter.");
		return false;
	}

	return true;
}

bool CSmsSender::SendToWebServ(const string& pszHost, const string& pszTime, const string& pszMsg)
{
	string szHost;
	string szTime;
	string szMsg;
	char szSndBuffer[DEFAULT_BUFFER_SIZE];
	char szRcvBuffer[DEFAULT_BUFFER_SIZE];
	bool bRet = false;
	int nRet = 0;


	if( pszHost.empty() || pszMsg.empty() || pszTime.empty() )
	{
		LOG(LERR, "Invalid Parameter.");
		Close();
		return false;
	}

	// Connect
	bRet = Connect(m_szHost, m_nPort);
	if( bRet == false )
	{
		LOG(LERR, "Socket Connect Error.[%s:%d]", m_szHost.c_str(), m_nPort);
		return false;
	}
	if( IsValidSocket() == false )
	{
		LOG(LERR, "Invalid Socket.");
		Close();
		return false;
	}

	::bzero(szSndBuffer, DEFAULT_BUFFER_SIZE);
	::bzero(szRcvBuffer, DEFAULT_BUFFER_SIZE);

	szHost = PostDataEncode(pszHost.c_str(), pszHost.size());
	szTime = PostDataEncode(pszTime.c_str(), pszTime.size());
	szMsg =  RemoveBlankSpace(pszMsg.c_str(), pszMsg.size());
	LOG(LDBG, "SMSMsg = [%s]", szMsg.c_str());
	szMsg =  PostDataEncode(szMsg.c_str(), szMsg.size());


	// CHG 2019-09-16 huibong HTTP 관련 줄바꿈문자 LF->CR+LF 변경 (#32794)
	// - CVE-2016-8743 이슈에 따라 Apache 2.2.32 버전부터 HTTP header 상에서
	// - 줄바꿈문자가 CR+LF 가 아닌 경우 HTTP 400 응답 발생
	// - 이를 해결하기 위해 기존 줄바꿈 문자 \n -> \r\n 으로 변경처리한다.
	::snprintf(szSndBuffer, DEFAULT_BUFFER_SIZE, "GET %s?host=%s&time=%s&msg=%s HTTP/1.0\r\n"\
			"Content-Type: text/plain\r\n"\
			"User-Agent: Arcmond\r\n"\
			"Host: %s\r\n"\
			"Connection: close\r\n"\
			"Cache-Control: no-cache\r\n\r\n"
			,m_szPath.c_str(), szHost.c_str(), szTime.c_str(), szMsg.c_str() ,m_szHost.c_str());

	//DEBUG_LOG("%s", szSndBuffer);
	//요청 전송 시작
	nRet = WriteN(&szSndBuffer, ::strlen(szSndBuffer)+1); 
	// MAX_SEND_RETRY_COUNT 회수만큼 재시도 후 실패처리된다.
	if( nRet == 0 )
	{
		LOG(LERR, "write socket closed.");
		Close();
		return false;
	}
	else if( nRet == -1 )
	{
		LOG(LERR, "write socket error.(%s)",strerror(errno));
		Close();
		return false;
	}

	// 응답 결과 받기.
	nRet = ReadNTimeout(szRcvBuffer, DEFAULT_BUFFER_SIZE);
	if( nRet == 0 )
	{
		// Remain이 0일 경우가 모두 받은 상황인데, 그것을 알 수 없다면,
		// Ret==0일 때가 다 준 상황으로 판단해야 하지 않을까? 그렇다면 에러가 아니다.
		LOG(LDBG, "read socket closed.");
	}
	else if( nRet == -1 )
	{ // 단순 소켓 에러.
		LOG(LERR, "read socket error.(%s)",strerror(errno));
		Close();
		return false;
	}
	else if( nRet == -2 )
	{ // 타임아웃.
		LOG(LERR, "read socket timed out.");
		Close();
		return false;
	}
	// 정상 결과는 아래와 같은 형태이다.
	//----------------------------------------------------------------
	// HTTP/1.1 200 OK
	// Date: Thu, 10 Jun 2010 03:59:23 GMT
	// Server: Apache/2.0.55 (Unix) DAV/2 PHP/5.2.1
	// X-Powered-By: PHP/5.2.1
	// Content-Length: 87
	// Connection: close
	// Content-Type: text/html; charset=EUC-KR
	//
	// [RAID:qcrts4.ktsh.co.kr]::2010-07-09 12:59:19:Controller#1: SW API Interface API Log In
	//----------------------------------------------------------------
	
	// 첫번째 라인만 출력하기 위해서 \n을 \0으로 바꾸고 출력한다.
	char* pEnd = strchr(szRcvBuffer, '\n'); 
	*pEnd = '\0';

	LOG(LINF, "Result:%s", szRcvBuffer);

	// Close()는 return값이 없음.
	Close();
	return true;
}
