/*************************************************************************\
* "$RCSfile: CSmtp.cpp,v $"                                               *
***************************************************************************
* Information by CVS or VSS:                                              *
*     Last check in on: $Date: 2010/06/16 10:23:13 $                      *
*     by                $Author: schluckebier $
*     Revision        : $Revision: 1.6 $                                 *
\*************************************************************************/
/*! \file CSmtp.cpp
*	\brief Implementation of Simple Mail Transfer Protocol Class
**************************************************************************/

#include <string.h>
#include "VIC_PS.h"
#include "GBit.h"
#include "CSmtp.hpp"
#include <sem.h>

//! Enable debug output
#define DEBUG_SMTP 0

CSmtp *CSmtp::m_pThis = NULL;	//!< The one and only CSmtp instance
SEM_Handle CSmtp::m_SendSem = NULL;

/*************************************************************************/
CSmtp::CSmtp()
/*************************************************************************/
/*! @brief Constructor
**************************************************************************/
{
	char serialNumber[32];

	memset(&m_Socket_SMTP_Addr, 0, sizeof(struct sockaddr_in) );
	m_MailAddress[0] = '\0';
	m_Recepient[0] = '\0';
	m_StatusEmailLevel = 0;
	if (VIB_GetSerialNumber(serialNumber) < 0)
		strcpy(m_Subject, "Status - error reading serial number");
	else
		sprintf(m_Subject, "Status of \"%s\"", serialNumber);

	m_Text = NULL;
	m_bSendTaskActive = false;
	if (m_SendSem == NULL)
	{
		m_SendSem = SEM_create(0, 0);
		SEM_reset(m_SendSem, 0);
	}
}

/*************************************************************************/
CSmtp::~CSmtp()
/*************************************************************************/
/*! @brief Destructor.
**************************************************************************/
{
	while (m_bSendTaskActive)
		TSK_sleep(100);

	if (m_Text != NULL)
		free(m_Text);
}

/*************************************************************************/
CSmtp *CSmtp::CreateInstance()
/*************************************************************************/
/*! @brief Creates CSmtp instance.
	@return Pointer to CSmtp instance
**************************************************************************/
{
	if (m_pThis == NULL)
		m_pThis = new CSmtp();
	return m_pThis;
}

/*************************************************************************/
void CSmtp::DisposeInstance()
/*************************************************************************/
/*! @brief Disposes CSmtp instance.
**************************************************************************/
{
	if (m_pThis)
		delete m_pThis;
	m_pThis = NULL;
}

/*************************************************************************/
int CSmtp::Send(const char *pText, int Level)
/*************************************************************************/
/*! @brief Function sends an email \p pText.
	@param pText Content of the email
	@param Level Send level
	@return Error code
**************************************************************************/
{
	if (m_StatusEmailLevel < Level)
		return -1;

	if (pText == NULL || pText[0] == '\0')
		return -1;

	if (m_bSendTaskActive)
		SEM_pend(m_SendSem, 30000);
	else
		SEM_reset(m_SendSem, 0);

	if (m_Text != NULL)
		free(m_Text);
	m_Text = (char *)malloc(strlen(pText) + 1);
	if (m_Text == NULL)
		return -2;
	strcpy(m_Text, pText);

	struct TSK_Attrs ta;
	ta.priority  = TSK_getpri(TSK_self());
	ta.stack     = 0;
	ta.stacksize = 2048;
	ta.stackseg  = SDRAM1;
	ta.environ   = 0;
	ta.exitflag  = 0;
	ta.initstackflag = 1;
	ta.name      = "TaskSendMail";
	SEM_reset(m_SendSem, 0);
	TSK_create((Fxn)TaskSendMail, &ta);
	SEM_pend(m_SendSem, SYS_FOREVER);
	SEM_reset(m_SendSem, 0);

	return 0;
}

/*************************************************************************/
void CSmtp::TaskSendMail()
/*************************************************************************/
/*! @brief Send mail task.
	@return Error code
**************************************************************************/
{
//	int Result;
	int Bytes;
	char *pBuffer;
	char *pC;
	SOCKET s = INVALID_SOCKET;
	struct timeval Timeout;
	time_t tTime;
	struct tm *sTime;
	char Day[7][4] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
	char Month[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};

	m_pThis->m_bSendTaskActive = true;
	SEM_post(m_SendSem);
	fdOpenSession(TSK_self());

	pBuffer = (char *)malloc(strlen(m_pThis->m_Text) + 2048);
	if (pBuffer == NULL)
	{
//		Result = -1;
		goto leave;
	}

	VIB_time(&tTime);
	sTime = localtime(&tTime);

	s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (s == INVALID_SOCKET)
	{
		printf("\nFailed socket create socket (%d)\n", socketerror());
//		Result = -1;
		goto leave;
	}

	if (connect(s, (struct sockaddr *)&m_pThis->m_Socket_SMTP_Addr, sizeof(m_pThis->m_Socket_SMTP_Addr)) < 0)
	{
		printf("\nFailed connect (%d)\n", socketerror());
//		Result = -1;
		goto leave;
	}

	// 10s timeout
	Timeout.tv_sec  = 10;
	Timeout.tv_usec = 0;
	setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &Timeout, sizeof(Timeout));
	Timeout.tv_sec  = 2;
	Timeout.tv_usec = 0;
	setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &Timeout, sizeof(Timeout));

	Bytes = recv(s, pBuffer, 256, 0);
	if (Bytes > 0)
	{
		pBuffer[Bytes] = 0;
#if DEBUG_SMTP
		printf("%s\n", pBuffer);
#endif
	}

	strcpy(pBuffer, "HELO strampe.de\r\n");
	if (m_pThis->SendData(s, pBuffer) < 0)
		goto leave;

	sprintf(pBuffer, "MAIL FROM:<%s>\r\n", m_pThis->m_MailAddress);
	if (m_pThis->SendData(s, pBuffer) < 0)
		goto leave;

	sprintf(pBuffer, "RCPT TO:<%s>\r\n", m_pThis->m_Recepient);
	if (m_pThis->SendData(s, pBuffer) < 0)
		goto leave;

	strcpy(pBuffer, "DATA\r\n");
	if (m_pThis->SendData(s, pBuffer) < 0)
		goto leave;

	sprintf(pBuffer, "From: <%s>\r\n", m_pThis->m_MailAddress);
	pC = pBuffer + strlen(pBuffer);
	sprintf(pC, "To: <%s>\r\n", m_pThis->m_Recepient);
	pC = pBuffer + strlen(pBuffer);
	sprintf(pC, "Subject: %s\r\n", m_pThis->m_Subject);
	pC = pBuffer + strlen(pBuffer);
	sprintf(pC, "Date: %s, %d %s %d\r\n", Day[sTime->tm_wday],
				sTime->tm_mday, Month[sTime->tm_mon],
				sTime->tm_year + 1900);
	pC = pBuffer + strlen(pBuffer);
	sprintf(pC, "%02d:%02d:%02d\r\n\r\n", sTime->tm_hour,
				sTime->tm_min, sTime->tm_sec);
	pC = pBuffer + strlen(pBuffer);
	sprintf(pC, "%s\r\n.\r\n", m_pThis->m_Text);
	if (m_pThis->SendData(s, pBuffer) < 0)
		goto leave;

	strcpy(pBuffer, "QUIT\r\n");
	if (m_pThis->SendData(s, pBuffer) < 0)
		goto leave;

	while (recv(s, pBuffer, 256, 0) != 0) ;

leave:
	if (s != INVALID_SOCKET)
		socketclose(s);
	fdCloseSession(TSK_self());
	m_pThis->m_bSendTaskActive = false;
	if (pBuffer)
		free(pBuffer);
	SEM_post(m_SendSem);
}

/*************************************************************************/
int CSmtp::SendData(SOCKET s, char *pBuffer)
/*************************************************************************/
/*! @brief Sends part of mail data.
**************************************************************************/
{
	int Result, Bytes;

#if DEBUG_SMTP
	printf("%s", pBuffer);
#endif
	Result = send(s, pBuffer, (int)strlen(pBuffer), 0);
	if (Result < 0)
	{
		printf("\nSend() error (%d)\n", socketerror());
		return -1;
	}

	Bytes = recv(s, pBuffer, 256, 0);
	if (Bytes>0)
	{
		pBuffer[Bytes] = '\0';
#if DEBUG_SMTP
		printf(">>>>%s\n", pBuffer);
#endif
	}
	return 0;
}

/*************************************************************************/
void CSmtp::SetMailServer(const char *pAddress, int Port)
/*************************************************************************/
/*! @brief Function sets the necessary mail server information
	@param pAddress Server address as string
	@param Port Port
**************************************************************************/
{
	while (m_bSendTaskActive)
		TSK_sleep(100);
	memset(&m_Socket_SMTP_Addr, 0, sizeof(struct sockaddr_in));
	m_Socket_SMTP_Addr.sin_family      = AF_INET;
	m_Socket_SMTP_Addr.sin_len         = sizeof(m_Socket_SMTP_Addr);
	m_Socket_SMTP_Addr.sin_addr.s_addr = inet_addr(pAddress);
	m_Socket_SMTP_Addr.sin_port        = htons(Port);
}

/*************************************************************************/
void CSmtp::SetMailAddress(const char *pMailAddress)
/*************************************************************************/
/*! @brief Function sets email address of sender.
	@param pMailAddress Mail address of sender
**************************************************************************/
{
	while (m_bSendTaskActive)
		TSK_sleep(100);
	VIB_SStrCpy(m_MailAddress, pMailAddress, 128);
}

/*************************************************************************/
void CSmtp::SetRecepientAddress(const char *pMailAddress)
/*************************************************************************/
/*! @brief Function sets email address of receiver.
	@param pMailAddress Mail address of receiver
**************************************************************************/
{
	while (m_bSendTaskActive)
		TSK_sleep(100);
	VIB_SStrCpy(m_Recepient, pMailAddress, 128);
}

/*************************************************************************/
