/*************************************************
File name:	smeg_smtp.c
Author: 	JianHui Zheng
Version:	9:00:00
Date:  		2008-4-1
Description:This file include the functions to communicate with the smtp server





History:
No.
Author:
Date:
Version:
Description:
*************************************************/
#include "include/smtp.h"
#include "include/smeg_pub.h"
#include "include/statistic_data.h"
#include "include/tcp_client.h"

/* by simon at 23/9/27 */
//extern BYTE DEBUG_buf[6000];

static struct tSmtpPort smtp_tx_port[SMTP_MAX_TX_PORT];
static struct tSmtpPort smtp_rx_port[SMTP_MAX_RX_PORT];
static int Smtp_Ser_Sockfd;
static int Execute[Exe_num];

static int socket_tx = 0;
static int socket_rx = 0; // 1-6

static fd_set Read_fd, Write_fd;
static int All_Socket_FD[Exe_num + LISTEN_NUMS];
// Move from smtp.h by simon, at 2024/06/11
static struct Smtp_wait_queue smtp_wait_queue;

char base64_alphabet[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
						  'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
						  'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a',
						  'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
						  'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
						  't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1',
						  '2', '3', '4', '5', '6', '7', '8', '9', '+',
						  '/'};

char base64_suffix_map[256] = {
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
	255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
	15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28,
	29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
	49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
	255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};

/*************************************************
Function:        // read_smtp_response
Description:     // Parse the smtp response
Calls:           // tcp_recv
Called By:       // smtp_rx_fsm; smtp_tx_fsm;
Table Accessed:  //
Table Updated:   //
Input:           // sockfd:socket id; recv_buf:the received data; recv_offset:the offset of the data
Output:          //
Return:          // 0 if whole response is received
					1 if <CRLF> is not seen
					-1 on error
Others:          //
*************************************************/
#define READ_ERROR (-1)
#define READ_PARTIAL 1
#define READ_COMPLETE 0
static int read_smtp_response(int sockfd, char *recv_buf, unsigned short *recv_offset)
{
	int retval;

	if (!FD_ISSET(sockfd, &Read_fd))
	{
		return READ_PARTIAL;
	}

	if ((*recv_offset) >= SMTP_RECV_BUF_SIZE)
		return READ_COMPLETE;

	retval = tcp_recv(sockfd, recv_buf + *recv_offset, SMTP_RECV_BUF_SIZE - *recv_offset);
	if (retval <= 0)
	{
		return READ_ERROR;
	}

	*recv_offset += retval;

	if ((*recv_offset) >= SMTP_RECV_BUF_SIZE)
		recv_buf[SMTP_RECV_BUF_SIZE - 1] = '\0';
	else
		recv_buf[*recv_offset] = '\0';

	if ((recv_buf[*recv_offset - 2] != '\r') || (recv_buf[*recv_offset - 1] != '\n'))
	{
		/* More to read as <CRLF> is not seen */
		return READ_PARTIAL;
	}
	return READ_COMPLETE;
}

/*************************************************
Function:        // send_smtp_command
Description:     // Send the smtp command to the mail server
Calls:           // tcp_send
Called By:       // smtp_tx_fsm; smtp_rx_fsm;
Table Accessed:  //
Table Updated:   //
Input:           // sockfd:socket id; send_buf:the send data
Output:          //
Return:          // Return 0 on success, -1 otherwise
Others:          //
*************************************************/
static int send_smtp_command(int sockfd, char *send_buf)
{
	int len;
	int retval;

	len = strlen(send_buf);

	retval = tcp_send(sockfd, send_buf, len);
	if (retval != len)
	{
		perror("send error");
		return -1;
	}
	return 0;
}

/*************************************************
Function:        // smtp_tx_port_reset
Description:     // Reset the smtp tx port
Calls:           // smtp_tx_port_release
Called By:       // smtp_tx_restart
Table Accessed:  //
Table Updated:   //
Input:           // pTxPort:the port which be reset
Output:          //
Return:          //
Others:          //
*************************************************/
void smtp_tx_port_reset(struct tSmtpPort *pTxPort)
{
	pTxPort->count++;
	if (pTxPort->count >= 4)
	{
		smtp_tx_port_release(pTxPort);
		return;
	}
	else if (smtp_wait_queue.start == ((smtp_wait_queue.end + 1) % wait_queue_num)) // 队列满的话
	{
		smtp_tx_port_release(pTxPort);
		return;
	}
	else if (pTxPort->time_out >= 40)
	{
		smtp_tx_port_release(pTxPort);
		return;
	} // 1-6

	pTxPort->port_state = SMTP_PORT_BUSY;
	pTxPort->curr_state = SMTP_TX_BEGIN;
	pTxPort->sockfd = 0;
	pTxPort->recv_offset = 0;
	pTxPort->time_out = 0; // 1-6
	pTxPort->recipient_index = 0;
}

/*************************************************
Function:        // smtp_tx_restart
Description:     // Restart the smtp rx port
Calls:           // tcp_disconnect; delete_socket_fd; add_call_statistics; smtp_tx_port_reset;
Called By:       // smtp_tx_fsm
Table Accessed:  //
Table Updated:   //
Input:           // pTxPort:the port which be restarted
Output:          //
Return:          //
Others:          //
*************************************************/
void smtp_tx_restart(struct tSmtpPort *pTxPort)
{
	tcp_disconnect(pTxPort->sockfd);
	delete_socket_fd(pTxPort->sockfd);
	add_call_statistics(Email_Outgoing_Failure, 0);
	smtp_tx_port_reset(pTxPort);
}

/*************************************************
Function:        // base64_encode
Description:     // Encode the data in base64
Calls:           //
Called By:       // smtp_tx_fsm
Table Accessed:  //
Table Updated:   //
Input:           // data:the input data
Output:          //
Return:          // the output data
Others:          //
*************************************************/
char *base64_encode(const char *data)
{
	char *ret, *retpos;
	static char out[MAX_EMAIL_LENGTH];
	int m, padnum = 0, retsize, dlen = strlen(data);

	if (dlen == 0)
		return NULL;

	/* Account the result buffer size and alloc the memory for it. */
	if ((dlen % 3) != 0)
		padnum = 3 - dlen % 3;
	retsize = (dlen + padnum) + ((dlen + padnum) * 1 / 3) + 1;
	if (retsize > MAX_EMAIL_LENGTH)
		return NULL;
	ret = out;
	retpos = ret;

	/* Starting to convert the originality characters to BASE64 chracaters.
	   Converting process keep to 4->6 principle. */
	for (m = 0; m < (dlen + padnum); m += 3)
	{
		/* When data is not suffice 24 bits then pad 0 and the empty place pad '='. */
		*(retpos) = base64_alphabet[cmove_bits(*data, 0, 2)];
		if (m == dlen + padnum - 3 && padnum != 0)
		{ /* Whether the last bits-group suffice 24 bits. */
			if (padnum == 1)
			{ /* 16bit need pad one '='. */
				*(retpos + 1) = base64_alphabet[cmove_bits(*data, 6, 2) + cmove_bits(*(data + 1), 0, 4)];
				*(retpos + 2) = base64_alphabet[cmove_bits(*(data + 1), 4, 2)];
				*(retpos + 3) = BASE64_PAD64;
			}
			else if (padnum == 2)
			{ /* 8bit need pad two'='. */
				*(retpos + 1) = base64_alphabet[cmove_bits(*data, 6, 2)];
				*(retpos + 2) = BASE64_PAD64;
				*(retpos + 3) = BASE64_PAD64;
			}
		}
		else
		{ /* 24bit normal. */
			*(retpos + 1) = base64_alphabet[cmove_bits(*data, 6, 2) + cmove_bits(*(data + 1), 0, 4)];
			*(retpos + 2) = base64_alphabet[cmove_bits(*(data + 1), 4, 2) + cmove_bits(*(data + 2), 0, 6)];
			*(retpos + 3) = base64_alphabet[*(data + 2) & 0x3f];
		}

		retpos += 4;
		data += 3;
	}

	ret[retsize - 1] = 0;

	return ret;
}

/*************************************************
Function:        // base64_decode
Description:     // Decode the data in base64
Calls:           //
Called By:       // parse_field
Table Accessed:  //
Table Updated:   //
Input:           // bdata:the input data
Output:          //
Return:          // the output data
Others:          //
*************************************************/
char *base64_decode(const char *bdata)
{

	char *ret = NULL, *retpos;
	static char out[MAX_EMAIL_LENGTH];
	int m, padnum = 0, retsize, bdlen = strlen(bdata);
	memset(out, 0, sizeof(out));

	if (bdlen == 0)
		return NULL;
	if (bdlen % 4 != 0)
		return NULL;

	/* Whether the data have invalid base-64 characters? */
	for (m = 0; m < bdlen; ++m)
	{
		if ((bdata[m] != BASE64_PAD64) && (base64_suffix_map[(int)bdata[m]] == -1))
			goto LEND;
	}

	/* Account the output size. */
	if (bdata[bdlen - 1] == '=')
		padnum = 1;
	if (bdata[bdlen - 1] == '=' && bdata[bdlen - 2] == '=')
		padnum = 2;
	retsize = (bdlen - 4) - (bdlen - 4) / 4 + (3 - padnum) + 1;
	ret = out;
	if (retsize > MAX_EMAIL_LENGTH)
		return NULL;
	retpos = ret;

	/* Begging to decode. */
	for (m = 0; m < bdlen; m += 4)
	{
		*retpos = cmove_bits(base64_suffix_map[(int)*bdata], 2, 0) + cmove_bits(base64_suffix_map[(int)*(bdata + 1)], 0, 4);
		if (m == bdlen - 4 && padnum != 0)
		{					 /* Only deal with last four bits. */
			if (padnum == 1) /* Have one pad characters, only two availability characters. */
				*(retpos + 1) = cmove_bits(base64_suffix_map[(int)*(bdata + 1)], 4, 0) + cmove_bits(base64_suffix_map[(int)*(bdata + 2)], 0, 2);
			/*
			Have two pad characters, only two availability characters.
			if(padnum == 2) {
			}
			*/
			retpos += 3 - padnum;
		}
		else
		{
			*(retpos + 1) = cmove_bits(base64_suffix_map[(int)*(bdata + 1)], 4, 0) + cmove_bits(base64_suffix_map[(int)*(bdata + 2)], 0, 2);
			*(retpos + 2) = cmove_bits(base64_suffix_map[(int)*(bdata + 2)], 6, 0) + base64_suffix_map[(int)*(bdata + 3)];
			retpos += 3;
		}
		bdata += 4;
	}

	ret[retsize - 1] = 0;

LEND:
	return ret;
}

/*************************************************
Function:        // smtp_tx_fsm
Description:     // The timer function of tx smtp
Calls:           // read_smtp_response
					send_smtp_command
					add_call_statistics
					tcp_disconnect
					set_smtp_link_state
					add_socket_tx
					add_socket_fd
Called By:       // smtp_main
Table Accessed:  //
Table Updated:   //
Input:           // pTxPort:the port to operate
Output:          //
Return:          //
Others:          //
*************************************************/
void smtp_tx_fsm(struct tSmtpPort *pTxPort)
{
	int ret = 0;
	switch (pTxPort->curr_state)
	{
	case SMTP_TX_BEGIN:
	{
		add_call_statistics(Email_Outgoing_Attempt, 0);
		if ((ret = tcp_tx_connect(&pTxPort->sockfd, (char *)get_mailserver_ip(), SMTP, 1)) < 0)
		{
			if (ret == CONNECT_FAIL)
			{
				tcp_disconnect(pTxPort->sockfd);
				pTxPort->sockfd = 0;
				set_smtp_link_state(0);
			}
			return;
		}
		add_socket_fd(pTxPort->sockfd);
		set_smtp_link_state(1);
		add_socket_tx();
		pTxPort->curr_state = SMTP_TX_CONNECTING;
	}
	break;
	case SMTP_TX_CONNECTING:
	{
		ret = read_smtp_response(pTxPort->sockfd, (char *)pTxPort->recv_buf, &pTxPort->recv_offset);
		switch (ret)
		{
		case READ_ERROR:
			smtp_tx_restart(pTxPort);
			break;
		case READ_PARTIAL:
			break;
		case READ_COMPLETE:
		{
			if (strncasecmp((char *)pTxPort->recv_buf, SERVICE_READY, strlen(SERVICE_READY)))
			{
				// server not ready
				smtp_tx_restart(pTxPort);
				smeg_print("smtp_tx_connecting: READ_COMPLETE: %s\n", pTxPort->recv_buf);
				return;
			}
			pTxPort->recv_offset = 0;
			pTxPort->curr_state = SMTP_TX_SEND_HELO;
		}
		break;
		default:
			break;
		}
	}
	break;
	case SMTP_TX_SEND_HELO:
	{
		sprintf((char *)pTxPort->send_buf, "HELO %s\r\n", get_localdomain());
		ret = send_smtp_command(pTxPort->sockfd, (char *)pTxPort->send_buf);
		if (ret < 0)
		{
			smeg_print("smtp_tx_connecting: ret < 0: %d\n", pTxPort->curr_state);
			smeg_print("ret = send_smtp_command\n");
			smtp_tx_restart(pTxPort);
			break;
		}
		pTxPort->curr_state = SMTP_TX_WAIT_FOR_HELO_RESP;
	}
	break;
	case SMTP_TX_WAIT_FOR_HELO_RESP:
	{
		ret = read_smtp_response(pTxPort->sockfd, (char *)pTxPort->recv_buf, &pTxPort->recv_offset);
		switch (ret)
		{
		case READ_ERROR:
			smeg_print("smtp_tx_wait_for_helo_resp READ_ERROR: curr_state: %d\n", pTxPort->curr_state);
			smtp_tx_restart(pTxPort); // 12-26-11
			break;
		case READ_PARTIAL:
			break;
		case READ_COMPLETE:
		{
			if (strncasecmp((char *)pTxPort->recv_buf, MAIL_ACTION_OK, strlen(MAIL_ACTION_OK)))
			{
				smeg_print("smtp_tx_wait_for_helo_resp: %s\n", pTxPort->recv_buf);
				smtp_tx_restart(pTxPort);
				return;
			}
			pTxPort->recv_offset = 0;
			if (get_smtp_auth_flag())
				pTxPort->curr_state = SMTP_TX_SEND_AUTH_LOGIN;
			else
				pTxPort->curr_state = SMTP_TX_SEND_MAIL_FROM;
		}
		break;
		}
	}
	break;
	case SMTP_TX_SEND_AUTH_LOGIN:
	{
		sprintf((char *)pTxPort->send_buf, "AUTH LOGIN\r\n");
		smeg_print("Send: %s\n", pTxPort->send_buf);
		ret = send_smtp_command(pTxPort->sockfd, (char *)pTxPort->send_buf);
		if (ret < 0)
		{
			smeg_print("SMTP_TX_ALARM: curr_state: %d\n", pTxPort->curr_state);
			smtp_tx_restart(pTxPort);
		}
		else
		{
			smeg_print("Recv: %s\n", pTxPort->recv_buf);
			pTxPort->recv_offset = 0;
			pTxPort->curr_state = SMTP_TX_WAIT_FOR_AUTH_LOGIN_RESP;
		}
	}
	break;
	case SMTP_TX_WAIT_FOR_AUTH_LOGIN_RESP:
	{
		ret = read_smtp_response(pTxPort->sockfd, (char *)pTxPort->recv_buf, &pTxPort->recv_offset);
		switch (ret)
		{
		case READ_ERROR:
			smeg_print("smtp_tx_wait_for_AUTH_LOGIN_resp READ_ERROR: curr_state: %d\n", pTxPort->curr_state);
			smtp_tx_restart(pTxPort);
			break;
		case READ_PARTIAL:
			break;
		case READ_COMPLETE:
			if (strncmp((char *)pTxPort->recv_buf, "334", 3))
			{
				smeg_print("smtp_tx_wait_for_AUTH_LOGIN_resp: %s\n", pTxPort->recv_buf);
				smtp_tx_restart(pTxPort);
				return;
			}
			smeg_print("Recv: %s\n", pTxPort->recv_buf);
			pTxPort->recv_offset = 0;
			pTxPort->curr_state = SMTP_TX_SEND_USERNAME;
			break;
		}
	}
	break;
	case SMTP_TX_SEND_USERNAME:
	{
		char *p = base64_encode((char *)get_smtp_auth_user());
		if (p == NULL)
		{
			tcp_disconnect(pTxPort->sockfd);
			smtp_tx_port_release(pTxPort);
			return;
		}
		sprintf((char *)pTxPort->send_buf, "%s\r\n", p);
		smeg_print("Send: %s\n", pTxPort->send_buf);
		ret = send_smtp_command(pTxPort->sockfd, (char *)pTxPort->send_buf);
		if (ret < 0)
		{
			smeg_print("SMTP_TX_ALARM: curr_state: %d\n", pTxPort->curr_state);
			smtp_tx_restart(pTxPort); // 12-26-11
			return;
		}
		pTxPort->curr_state = SMTP_TX_WAIT_FOR_USER_NAME_RESP;
	}
	break;
	case SMTP_TX_WAIT_FOR_USER_NAME_RESP:
	{
		ret = read_smtp_response(pTxPort->sockfd, (char *)pTxPort->recv_buf, &pTxPort->recv_offset);
		switch (ret)
		{
		case READ_ERROR:
			smeg_print("smtp_tx_wait_for_user_name_resp READ_ERROR: curr_state: %d\n", pTxPort->curr_state);
			smtp_tx_restart(pTxPort); // 12-26-11
			break;
		case READ_PARTIAL:
			break;
		case READ_COMPLETE:
			if (strncmp((char *)pTxPort->recv_buf, "334", 3))
			{
				smeg_print("smtp_tx_wait_for_user_name_resp: %s\n", pTxPort->recv_buf);
				smtp_tx_restart(pTxPort); // 12-26-11
				return;
			}
			smeg_print("Recv: %s\n", pTxPort->recv_buf);
			pTxPort->recv_offset = 0;
			pTxPort->curr_state = SMTP_TX_SEND_PASSWD;
			break;
		}
	}
	break;
	case SMTP_TX_SEND_PASSWD:
	{
		char *p = base64_encode((char *)get_smtp_auth_passwd());
		if (p == NULL)
		{
			tcp_disconnect(pTxPort->sockfd);
			smtp_tx_port_release(pTxPort);
			return;
		}
		sprintf((char *)pTxPort->send_buf, "%s\r\n", p);
		smeg_print("Send: %s\n", pTxPort->send_buf);
		ret = send_smtp_command(pTxPort->sockfd, (char *)pTxPort->send_buf);
		if (ret < 0)
		{
			smeg_print("SMTP_TX_ALARM: curr_state: %d\n", pTxPort->curr_state);
			smtp_tx_restart(pTxPort);
			return;
		}
		pTxPort->curr_state = SMTP_TX_WAIT_FOR_PASSWORD_RESP;
	}
	break;
	case SMTP_TX_WAIT_FOR_PASSWORD_RESP:
	{
		ret = read_smtp_response(pTxPort->sockfd, (char *)pTxPort->recv_buf, &pTxPort->recv_offset);
		switch (ret)
		{
		case READ_ERROR:
			smeg_print("smtp_tx_wait_for_password_resp READ_ERROR: curr_state: %d\n", pTxPort->curr_state);
			smtp_tx_restart(pTxPort);
			break;
		case READ_PARTIAL:
			break;
		case READ_COMPLETE:
			if (strncmp((char *)pTxPort->recv_buf, "235", 3))
			{
				smeg_print("smtp_tx_wait_for_password_resp: %s\n", pTxPort->recv_buf);
				smtp_tx_restart(pTxPort);
				return;
			}
			pTxPort->recv_offset = 0;
			smeg_print("Recv: %s\n", pTxPort->recv_buf);
			pTxPort->curr_state = SMTP_TX_SEND_MAIL_FROM;
			break;
		}
	}
	break;
	case SMTP_TX_SEND_MAIL_FROM:
	{
		sprintf((char *)pTxPort->send_buf, "MAIL FROM: %s\r\n", pTxPort->smtp_msg.sender);
		smeg_print("Send: %s\n", pTxPort->send_buf);
		ret = send_smtp_command(pTxPort->sockfd, (char *)pTxPort->send_buf);
		if (ret < 0)
		{
			smeg_print("SMTP_TX_ALARM: curr_state: %d\n", pTxPort->curr_state);
			smtp_tx_restart(pTxPort);
			return;
		}
		pTxPort->curr_state = SMTP_TX_WAIT_FOR_MAIL_RESP;
	}
	break;
	case SMTP_TX_WAIT_FOR_MAIL_RESP:
	{
		ret = read_smtp_response(pTxPort->sockfd, (char *)pTxPort->recv_buf, &pTxPort->recv_offset);
		switch (ret)
		{
		case READ_ERROR:
			smeg_print("smtp_tx_wait_for_mail_resp READ_ERROR: %s\n", pTxPort->recv_buf);
			smtp_tx_restart(pTxPort);
			break;
		case READ_PARTIAL:
			break;
		case READ_COMPLETE:
			smeg_print("Recv: %s\n", pTxPort->recv_buf);
			if (strncasecmp((char *)pTxPort->recv_buf, MAIL_ACTION_OK, 3))
			{
				smeg_print("smtp_tx_wait_for_mail_resp: %s\n", pTxPort->recv_buf);
				smtp_tx_restart(pTxPort);
				return;
			}
			pTxPort->recv_offset = 0;
			pTxPort->curr_state = SMTP_TX_SEND_RCPT;
			break;
		}
	}
	break;
	case SMTP_TX_SEND_RCPT:
	{
		sprintf((char *)pTxPort->send_buf, "RCPT TO: %s\r\n", pTxPort->smtp_msg.recipient[pTxPort->recipient_index++]);
		ret = send_smtp_command(pTxPort->sockfd, (char *)pTxPort->send_buf);
		if (ret < 0)
		{
			smeg_print("SMTP_TX_ALARM: curr_state: %d\n", pTxPort->curr_state);
			smtp_tx_restart(pTxPort);
			return;
		}
		smeg_print("Send: %s\n", pTxPort->send_buf);
		pTxPort->curr_state = SMTP_TX_WAIT_FOR_RCPT_RESP;
	}
	break;
	case SMTP_TX_WAIT_FOR_RCPT_RESP:
	{
		ret = read_smtp_response(pTxPort->sockfd, (char *)pTxPort->recv_buf, &pTxPort->recv_offset);
		switch (ret)
		{
		case READ_ERROR:
			smeg_print("smtp_tx_wait_for_rcpt_resp READ_ERROR : %s\n", pTxPort->recv_buf);
			smtp_tx_restart(pTxPort); // 12-26-11
			break;
		case READ_PARTIAL:
			break;
		case READ_COMPLETE:
			smeg_print("Recv: %s\n", pTxPort->recv_buf);
			if (strncasecmp((char *)pTxPort->recv_buf, MAIL_ACTION_OK, 3))
			{
				smeg_print("strncmp(pTxPort->recv_buf, %s\n", pTxPort->recv_buf);
				smeg_print("SMTP_TX_ALARM: curr_state: %d\n", pTxPort->curr_state);
				smtp_tx_restart(pTxPort); // 12-26-11
				return;
			}
			pTxPort->recv_offset = 0;
			if (pTxPort->recipient_index < pTxPort->smtp_msg.recipientNum)
				pTxPort->curr_state = SMTP_TX_SEND_RCPT;
			else
				pTxPort->curr_state = SMTP_TX_SEND_DATA;
			break;
		}
	}
	break;
	case SMTP_TX_SEND_DATA:
	{
		strcpy((char *)pTxPort->send_buf, "DATA\r\n");
		ret = send_smtp_command(pTxPort->sockfd, (char *)pTxPort->send_buf);
		if (ret < 0)
		{
			smeg_print("SMTP_TX_ALARM: curr_state: %d\n", pTxPort->curr_state);
			smtp_tx_restart(pTxPort);
			return;
		}
		smeg_print("Send: QUIT\n");
		pTxPort->curr_state = SMTP_TX_WAIT_FOR_DATA_RESP;
	}
	break;
	case SMTP_TX_WAIT_FOR_DATA_RESP:
	{
		ret = read_smtp_response(pTxPort->sockfd, (char *)pTxPort->recv_buf, &pTxPort->recv_offset);
		switch (ret)
		{
		case READ_ERROR:
			smeg_print("SMTP_TX_ALARM READ_ERROR: curr_state: %d\n", pTxPort->curr_state);
			smtp_tx_restart(pTxPort); // 12-26-11
			break;
		case READ_PARTIAL:
			break;
		case READ_COMPLETE:
			smeg_print("Recv: %s\n", pTxPort->recv_buf);
			if (strncasecmp((char *)pTxPort->recv_buf, START_MAIL_INPUT, 3))
			{
				smeg_print("strncmp(pTxPort->recv_buf, START_MAIL_INPUT, 3, %s\n", pTxPort->recv_buf);
				smeg_print("SMTP_TX_ALARM: curr_state: %d\n", pTxPort->curr_state);
				smtp_tx_restart(pTxPort); // 12-26-11
				return;
			}
			pTxPort->recv_offset = 0;
			pTxPort->curr_state = SMTP_TX_SEND_CONTENT;
			break;
		}
	}
	break;
	case SMTP_TX_SEND_CONTENT:
	{
		sprintf((char *)pTxPort->send_buf, "%s\r\n\r\n.\r\n", pTxPort->smtp_msg.contents);
		ret = send_smtp_command(pTxPort->sockfd, (char *)pTxPort->send_buf);
		if (ret < 0)
		{
			smeg_print("SMTP_TX_ALARM: curr_state: %d\n", pTxPort->curr_state);
			smtp_tx_restart(pTxPort);
			return;
		}
		smeg_print("Send: QUIT\n");
		pTxPort->curr_state = SMTP_TX_WAIT_FOR_CONTENT_RESP;
	}
	break;
	case SMTP_TX_WAIT_FOR_CONTENT_RESP:
	{
		ret = read_smtp_response(pTxPort->sockfd, (char *)pTxPort->recv_buf, &pTxPort->recv_offset);
		switch (ret)
		{
		case READ_ERROR:
			smeg_print("READ_ERROR, %s\n", pTxPort->recv_buf);
			smeg_print("SMTP_TX_ALARM: curr_state: %d\n", pTxPort->curr_state);
			smtp_tx_restart(pTxPort);
			return;
		case READ_PARTIAL:
			return;
		case READ_COMPLETE:
			smeg_print("Recv: %s\n", pTxPort->recv_buf);
			if (strncasecmp((char *)pTxPort->recv_buf, MAIL_ACTION_OK, 3))
			{
				smeg_print("strncmp(pTxPort->recv_buf, MAIL_ACTION_OK, 3\n,%s", pTxPort->recv_buf);
				smeg_print("SMTP_TX_ALARM: curr_state: %d\n", pTxPort->curr_state);
				smtp_tx_restart(pTxPort); // 12-26-11
				return;
			}
			pTxPort->recv_offset = 0;
			pTxPort->curr_state = SMTP_TX_SEND_QUIT;
			break;
		}
	}
	break;
	case SMTP_TX_SEND_QUIT:
	{
		strcpy((char *)pTxPort->send_buf, "QUIT\r\n");
		ret = send_smtp_command(pTxPort->sockfd, (char *)pTxPort->send_buf);
		if (ret < 0)
		{
			smeg_print("SMTP_TX_ALARM: curr_state: %d\n", pTxPort->curr_state);
			smtp_tx_restart(pTxPort);
			return;
		}
		smeg_print("Send: QUIT\n");
		pTxPort->curr_state = SMTP_TX_END;
	}
	break;
	case SMTP_TX_END:
	{
		ret = read_smtp_response(pTxPort->sockfd, (char *)pTxPort->recv_buf, &pTxPort->recv_offset);
		switch (ret)
		{
		case READ_ERROR:
			smtp_tx_restart(pTxPort);
			break;
		case READ_PARTIAL:
			break;
		case READ_COMPLETE:
			if (strncmp((char *)pTxPort->recv_buf, "221", 3))
			{
				smtp_tx_restart(pTxPort);
				return;
			}
			smeg_print("Recv: %s\n", pTxPort->recv_buf);
			add_call_statistics(Email_Outgoing_Successful, strlen((char *)pTxPort->smtp_msg.contents));
			tcp_disconnect(pTxPort->sockfd);
			smtp_tx_port_release(pTxPort);
			break;
		}
	}
	break;
	default:
		smeg_print("unknown curr_state:%d\n", pTxPort->curr_state);
		smtp_tx_restart(pTxPort);
		break;
	}
	return;
}

/*************************************************
Function:        // smtp_tx_port_assign
Description:     // Assign a new tx port to send mail
Calls:           //
Called By:       // smtp_send_sm
Table Accessed:  //
Table Updated:   //
Input:           // smtp_msg:the smtp message
Output:          //
Return:          //
Others:          //
*************************************************/
int smtp_tx_port_assign(SMTP_MSG *smtp_msg)
{
	static int start_pos = 0;
	int i = start_pos;
	int end_pos = start_pos - 1;
	if (end_pos < 0)
	{
		end_pos = SMTP_MAX_TX_PORT - 1;
	}

	while (i != end_pos)
	{
		if (smtp_tx_port[i].port_state == SMTP_PORT_IDLE)
		{

			smtp_tx_port[i].port_state = SMTP_PORT_BUSY;
			smtp_tx_port[i].curr_state = SMTP_TX_BEGIN;
			smtp_tx_port[i].recipient_index = 0;

			insert_smtp_wait_queue(i);

			memcpy(&smtp_tx_port[i].smtp_msg, smtp_msg, sizeof(SMTP_MSG));

			start_pos = i + 1;
			if (start_pos >= SMTP_MAX_TX_PORT)
				start_pos = 0;
			return 0;
		}
		if (++i >= SMTP_MAX_TX_PORT)
			i = 0;
	}
	return -1;
}

/*************************************************
Function:        // smtp_tx_port_release
Description:     // Release the smtp tx port
Calls:           // delt_socket_tx
Called By:       // smtp_tx_port_reset
Table Accessed:  //
Table Updated:   //
Input:           // p:the port to release
Output:          //
Return:          //
Others:          //
*************************************************/
void smtp_tx_port_release(struct tSmtpPort *p)
{
	if (p->port_state == SMTP_PORT_IDLE)
		return;
	delete_socket_fd(p->sockfd);
	delt_socket_tx(); // 1-6
	// memset(p, 0, sizeof(*p)); //1-6
	//----
	p->sockfd = 0;
	p->curr_state = 0;
	p->port_state = 0;
	// char send_buf[MAX_SMS_LENGTH + MAX_SMTP_SUBJECT_LENGTH + SMTP_ADDR_LENGTH*5]; //256+50+40*5 =506
	// char recv_buf[SMTP_SEND_BUF_SIZE]; //100
	// SMTP_MSG smtp_msg;  //746
	memset(p->smtp_msg.recipient, 0, sizeof(p->smtp_msg.recipient));
	p->recv_offset = 0;
	p->count = 0;
	p->time_out = 0;
	// short int curr_state_finished[13];

	//----
	p->curr_state = -1;
	return;
}

/*************************************************
Function:        // insert_smtp_wait_queue
Description:     // Insert the port to wait queue to send email
Calls:           //
Called By:       // smtp_tx_port_assign
Table Accessed:  //
Table Updated:   //
Input:           // port_num:the no of the port
Output:          //
Return:          //
Others:          //
*************************************************/
void insert_smtp_wait_queue(int port_num)
{
	printf("smtp_wait_queue.start=%d, end=%d, port_num=%d\n", smtp_wait_queue.start, smtp_wait_queue.end, port_num);
	int i;
	if (smtp_wait_queue.start == smtp_wait_queue.end) // 空的话
	{
		for (i = 0; i < Exe_num; i++)
			if (Execute[i] == -1)
			{
				Execute[i] = port_num;
				return;
			}
	}
	smtp_wait_queue.wait_queue[smtp_wait_queue.end] = port_num;
	smtp_wait_queue.end = (smtp_wait_queue.end + 1) % wait_queue_num;
}

/*************************************************
Function:        // smtp_insert_Execute
Description:     //
Calls:           //
Called By:       //
Table Accessed:  //
Table Updated:   //
Input:           //
Output:          //
Return:          //
Others:          // no use
*************************************************/
void smtp_insert_Execute(int *pexec)
{
	if (smtp_wait_queue.start == smtp_wait_queue.end) // 空的话
		return;
	*pexec = smtp_wait_queue.wait_queue[smtp_wait_queue.start];
	smtp_wait_queue.start = (smtp_wait_queue.start + 1) % wait_queue_num;
}

/*************************************************
Function:        // smtp_rx_port_assign
Description:     // Assign a new rx port
Calls:           //
Called By:       // smtp_main
Table Accessed:  //
Table Updated:   //
Input:           // temp_fd:the socket id; smtp_rx_port:the new port
Output:          //
Return:          //
Others:          //
*************************************************/
int smtp_rx_port_assign(int temp_fd, struct tSmtpPort *smtp_rx_port)
{
	static int start_pos = 0; // start position
	int i = start_pos;
	int end_pos = start_pos - 1;
	if (end_pos < 0)
	{
		end_pos = SMTP_MAX_RX_PORT - 1;
	}

	while (i != end_pos)
	{
		if (smtp_rx_port[i].port_state == SMTP_PORT_IDLE)
		{

			smtp_rx_port[i].port_state = SMTP_PORT_BUSY;
			smtp_rx_port[i].sockfd = temp_fd;
			smtp_rx_port[i].curr_state = SMTP_RX_BEGIN;

			start_pos = i + 1; // set next time start position
			if (start_pos >= SMTP_MAX_RX_PORT)
				start_pos = 0;
			return 0;
		}
		if (++i >= SMTP_MAX_RX_PORT)
			i = 0; // restart from beginning
	}
	return -1;
}

/*************************************************
Function:        // smtp_rx_port_release
Description:     // Release the rx port
Calls:           // delete_socket_fd
Called By:       // smtp_main
Table Accessed:  //
Table Updated:   //
Input:           // p:the port to release
Output:          //
Return:          //
Others:          //
*************************************************/
void smtp_rx_port_release(struct tSmtpPort *p)
{
	if (p->port_state == SMTP_PORT_IDLE)
		return;
	delete_socket_fd(p->sockfd);
	delt_socket_rx();
	p->port_state = 0;
	p->curr_state = 0;
	memset(p->smtp_msg.recipient, 0, sizeof(p->smtp_msg.recipient));
	p->recv_offset = 0;
	p->recipient_index = 0;
	p->count = 0;
	p->time_out = 0;
	p->sockfd = 0;
	p->encode_mode = 0;

	return;
}

/*************************************************
Function:        // smtp_rx_failed
Description:     // Disconnect the port when fail
Calls:           // tcp_disconnect; smtp_rx_port_release;
Called By:       //
Table Accessed:  //
Table Updated:   //
Input:           //
Output:          //
Return:          //
Others:          //
*************************************************/
void smtp_rx_failed(void *data)
{
	struct tSmtpPort *pSmtpRxPort = (struct tSmtpPort *)data;

	tcp_disconnect(pSmtpRxPort->sockfd);
	smtp_rx_port_release(pSmtpRxPort);
}

/*************************************************
Function:        // smtp_rx_fsm
Description:     // The timer of rx smtp,to receive the email sent of email server
Calls:           // add_call_statistics
					smtp_rx_failed
					send_smtp_command
					read_smtp_response
					parse_field
Called By:       // smtp_main
Table Accessed:  //
Table Updated:   //
Input:           // pSmtpRxPort:the port to operate
Output:          //
Return:          //
Others:          //
*************************************************/
void smtp_rx_fsm(struct tSmtpPort *pSmtpRxPort)
{
	int retval;
	switch (pSmtpRxPort->curr_state)
	{
	case SMTP_RX_BEGIN:
	{
		add_call_statistics(Email_Incoming_Attempt, 0);
		sprintf((char *)pSmtpRxPort->send_buf, "%s\r\n", "220 LGC UltraWave SMS-Email Gateway Ready");
		retval = send_smtp_command(pSmtpRxPort->sockfd, (char *)pSmtpRxPort->send_buf);
		if (retval < 0)
		{
			smtp_rx_failed(pSmtpRxPort);
			return;
		}
		smeg_print("\nSend: %s\n", pSmtpRxPort->send_buf);
		pSmtpRxPort->curr_state = SMTP_RX_WAIT_HELO;
	}
	break;
	case SMTP_RX_WAIT_HELO:
	{
		retval = read_smtp_response(pSmtpRxPort->sockfd, (char *)pSmtpRxPort->recv_buf, &pSmtpRxPort->recv_offset);
		switch (retval)
		{
		case READ_ERROR:
			smtp_rx_failed(pSmtpRxPort);
			break;
		case READ_PARTIAL:
			break;
		case READ_COMPLETE:
			if (strncasecmp((char *)pSmtpRxPort->recv_buf, HELO_CMD, 4) && strncasecmp((char *)pSmtpRxPort->recv_buf, EHLO_CMD, 4))
			{
				smtp_rx_failed(pSmtpRxPort);
				return;
			}
			smeg_print("Recv: %s\n", pSmtpRxPort->recv_buf);
			pSmtpRxPort->recv_offset = 0;
			pSmtpRxPort->curr_state = SMTP_RX_SEND_HELO_RESP;
			break;
		}
	}
	break;
	case SMTP_RX_SEND_HELO_RESP:
	{
		sprintf((char *)pSmtpRxPort->send_buf, "%s\r\n", "250 Gateway service is Ready");
		retval = send_smtp_command(pSmtpRxPort->sockfd, (char *)pSmtpRxPort->send_buf);
		if (retval < 0)
		{
			smtp_rx_failed(pSmtpRxPort);
			return;
		}
		smeg_print("Send: %s\n", pSmtpRxPort->send_buf);
		pSmtpRxPort->curr_state = SMTP_RX_WAIT_MAIL;
	}
	break;
	case SMTP_RX_WAIT_MAIL:
	{
		retval = read_smtp_response(pSmtpRxPort->sockfd, (char *)pSmtpRxPort->recv_buf, &pSmtpRxPort->recv_offset);
		switch (retval)
		{
		case READ_ERROR:
			smtp_rx_failed(pSmtpRxPort);
			break;
		case READ_PARTIAL:
			break;
		case READ_COMPLETE:
			if (strncasecmp((char *)pSmtpRxPort->recv_buf, MAIL_CMD, 9))
			{
				smtp_rx_failed(pSmtpRxPort);
				return;
			}
			smeg_print("Recv: %s\n", pSmtpRxPort->recv_buf);
			pSmtpRxPort->recv_offset = 0;
			pSmtpRxPort->curr_state = SMTP_RX_SEND_MAIL_RESP;
			break;
		}
	}
	break;
	case SMTP_RX_SEND_MAIL_RESP:
	{
		sprintf((char *)pSmtpRxPort->send_buf, "%s\r\n", "250 OK");
		retval = send_smtp_command(pSmtpRxPort->sockfd, (char *)pSmtpRxPort->send_buf);
		if (retval < 0)
		{
			smtp_rx_failed(pSmtpRxPort);
			return;
		}
		smeg_print("Send: %s\n", pSmtpRxPort->send_buf);
		pSmtpRxPort->curr_state = SMTP_RX_WAIT_RCPT_DATA;
	}
	break;
	case SMTP_RX_WAIT_RCPT_DATA:
	{
		retval = read_smtp_response(pSmtpRxPort->sockfd, (char *)pSmtpRxPort->recv_buf, &pSmtpRxPort->recv_offset);
		switch (retval)
		{
		case READ_ERROR:
			smtp_rx_failed(pSmtpRxPort);
			break;
		case READ_PARTIAL:
			break;
		case READ_COMPLETE:
			if (strncasecmp((char *)pSmtpRxPort->recv_buf, DATA_CMD, 4))
			{
				if (strncasecmp((char *)pSmtpRxPort->recv_buf, RCPT_CMD, 7) == 0)
				{
					smeg_print("read rcpt:%s\n", pSmtpRxPort->recv_buf);
					*strchr((char *)pSmtpRxPort->recv_buf, '@') = '\0'; // remove @ and domain
					strcpy(pSmtpRxPort->smtp_msg.recipient[pSmtpRxPort->recipient_index], strchr((char *)pSmtpRxPort->recv_buf, '<') + 1);
					pSmtpRxPort->recipient_index++;
					pSmtpRxPort->recv_offset = 0;
					pSmtpRxPort->curr_state = SMTP_RX_SEND_RCPT_RESP;
					return;
				}
				else
					smtp_rx_failed(pSmtpRxPort);
				return;
			}
			smeg_print("Recv: %s\n", pSmtpRxPort->recv_buf);
			pSmtpRxPort->recv_offset = 0;
			pSmtpRxPort->curr_state = SMTP_RX_SEND_DATA_RESP;
			break;
		}
	}
	break;
	case SMTP_RX_SEND_RCPT_RESP:
	{
		sprintf((char *)pSmtpRxPort->send_buf, "%s\r\n", "250 OK");
		retval = send_smtp_command(pSmtpRxPort->sockfd, (char *)pSmtpRxPort->send_buf);
		if (retval < 0)
		{
			smtp_rx_failed(pSmtpRxPort);
			return;
		}
		smeg_print("Send: %s\n", pSmtpRxPort->send_buf);
		pSmtpRxPort->curr_state = SMTP_RX_WAIT_RCPT_DATA;
	}
	break;
	case SMTP_RX_SEND_DATA_RESP:
	{
		sprintf((char *)pSmtpRxPort->send_buf, "%s\r\n", "354 Start mail input;end with <CRLF>.<CRLF>");
		retval = send_smtp_command(pSmtpRxPort->sockfd, (char *)pSmtpRxPort->send_buf);
		if (retval < 0)
		{
			smtp_rx_failed(pSmtpRxPort);
			return;
		}
		smeg_print("Send: %s\n", pSmtpRxPort->send_buf);
		pSmtpRxPort->curr_state = SMTP_RX_WAIT_CONTENT;
		pSmtpRxPort->overflow = 0;
	}
	break;
	case SMTP_RX_WAIT_CONTENT:
	{
		retval = read_smtp_response(pSmtpRxPort->sockfd, (char *)pSmtpRxPort->recv_buf, &pSmtpRxPort->recv_offset);
		switch (retval)
		{
		case READ_ERROR:
			smtp_rx_failed(pSmtpRxPort);
			break;
		case READ_PARTIAL:
			break;
		case READ_COMPLETE:
			if (parse_field(pSmtpRxPort, (char *)pSmtpRxPort->recv_buf) == PARSE_ERROR)
			{
				smeg_print("Parsing email content failed\n");
				pSmtpRxPort->smtp_msg.parsed_flag = 0;
				//							smtp_rx_failed(pSmtpRxPort);
				//							return;
			}
			else
				pSmtpRxPort->smtp_msg.parsed_flag = 1;

			//						smeg_print("Recv: %s\n",pSmtpRxPort->recv_buf);
			if (pSmtpRxPort->recv_offset >= SMTP_RECV_BUF_SIZE)
			{
				// too many data
				pSmtpRxPort->overflow = 1;
			}
			pSmtpRxPort->recv_offset = 0;
			pSmtpRxPort->curr_state = SMTP_RX_SEND_CONTENT_RESP;
			break;
		}
	}
	break;
	case SMTP_RX_SEND_CONTENT_RESP:
	{
		if (pSmtpRxPort->overflow == 1)
		{
			pSmtpRxPort->curr_state = SMTP_RX_QUIT_RESP;
			sprintf((char *)pSmtpRxPort->send_buf, "%s\r\n", "552 Too much mail data");
		}
		else
		{
			pSmtpRxPort->curr_state = SMTP_RX_WAIT_QUIT;
			sprintf((char *)pSmtpRxPort->send_buf, "%s\r\n", "250 OK");
		}
		retval = send_smtp_command(pSmtpRxPort->sockfd, (char *)pSmtpRxPort->send_buf);
		if (retval < 0)
		{
			smtp_rx_failed(pSmtpRxPort);
			return;
		}
		smeg_print("Send: %s\n", pSmtpRxPort->send_buf);
	}
	break;
	case SMTP_RX_WAIT_QUIT:
	{
		retval = read_smtp_response(pSmtpRxPort->sockfd, (char *)pSmtpRxPort->recv_buf, &pSmtpRxPort->recv_offset);
		switch (retval)
		{
		case READ_ERROR:
			smtp_rx_failed(pSmtpRxPort);
			break;
		case READ_PARTIAL:
			break;
		case READ_COMPLETE:
			if (strncasecmp((char *)pSmtpRxPort->recv_buf, QUIT_CMD, 4))
			{
				smtp_rx_failed(pSmtpRxPort);
				return;
			}
			smeg_print("Recv: %s\n", pSmtpRxPort->recv_buf);
			pSmtpRxPort->recv_offset = 0;
			pSmtpRxPort->curr_state = SMTP_RX_QUIT_RESP;
			break;
		}
	}
	break;
	case SMTP_RX_QUIT_RESP:
	{
		sprintf((char *)pSmtpRxPort->send_buf, "%s\r\n", "221 Gateway closing transmission channel");
		retval = send_smtp_command(pSmtpRxPort->sockfd, (char *)pSmtpRxPort->send_buf);
		if (retval < 0)
		{
			smtp_rx_failed(pSmtpRxPort); // 12-26-10
			return;
		}
		smeg_print("Send: %s\n", pSmtpRxPort->send_buf);
		if (pSmtpRxPort->recipient_index > 0 && pSmtpRxPort->smtp_msg.parsed_flag != 0)
			smpp_send_email(&pSmtpRxPort->smtp_msg, pSmtpRxPort->recipient_index);
		tcp_disconnect(pSmtpRxPort->sockfd);
		smtp_rx_port_release(pSmtpRxPort);
		add_call_statistics(Email_Incoming_Successful, strlen((char *)pSmtpRxPort->smtp_msg.contents));
	};
	break;
	default:
		smeg_print("unknown curr_state:%d\n", pSmtpRxPort->curr_state);
		smtp_rx_port_release(pSmtpRxPort);
		break;
	}
}

/*************************************************
Function:        // parse_field
Description:     // Parse the email content and subject
Calls:           // base64_decode; Qp_decode;
Called By:       // smtp_rx_fsm
Table Accessed:  //
Table Updated:   //
Input:           // pSmtpRxPort:the port; pt:the received data
Output:          //
Return:          // PARSE_ERROR; PARSE_SUCCESS;
Others:          //
*************************************************/
char contents_temp[MAX_EMAIL_LENGTH * 2];
int parse_field(struct tSmtpPort *pSmtpRxPort, char *pt)
{
	int i = 0;
	char *pStart, *pEnd;

	char *pFrom, *pSubject, *pContents, *pContentsEnd, *pBoundary;
	char *Pt_contents_origin_code; //, *Pt_boundary;
	int contents_temp_len = 0;

	char subject_temp[100];
	// 	char boundary[100];
	char encode;

	char *pB = NULL, *pC = NULL, *pD = NULL;

	//--From---------------
	if ((pFrom = strstr(pt, "From: ")) != NULL)
		pFrom += strlen("From: ");
	else
		return PARSE_ERROR;

	if (strncmp(pFrom, "=?", 2) == 0)
	{
		char *pTmp = pFrom;
		pFrom += 2;
		pFrom = strstr(pFrom, "?=");
		if ((pFrom != NULL) && (pFrom < strstr(pTmp, "\r\n")))
			pFrom += 2;
		else
			return PARSE_ERROR;
	}

	while (*pFrom != '\r')
		pSmtpRxPort->smtp_msg.sender[i++] = *pFrom++;

	if (i >= SMTP_ADDR_LENGTH)
		pSmtpRxPort->smtp_msg.sender[SMTP_ADDR_LENGTH - 1] = '\0';
	else
		pSmtpRxPort->smtp_msg.sender[i] = '\0';

	//---Subject-----------
	i = 0;
	if ((pSubject = strstr(pt, "Subject: ")) != NULL)
	{
		pSubject += strlen("Subject: ");
		while (*pSubject != '\r')
		{
			subject_temp[i++] = *pSubject++;

			if (i == MAX_SMTP_SUBJECT_LENGTH - 1)
				break;
		}
		subject_temp[i] = '\0';
		strcpy(pSmtpRxPort->smtp_msg.subject_coding, "us-ascii");
		pStart = subject_temp; // maybe Subject like: =?gb2312?B?TUlNRdCt0unLtcP308q8/g==?=
		if (strncmp(pStart, "=?", 2) == 0 && strncmp(pStart + strlen(pStart) - 2, "?=", 2) == 0)
		{
			subject_temp[strlen(pStart) - 2] = '\0';
			pStart = pStart + 2;
			pEnd = strstr(pStart, "?");
			strncpy(pSmtpRxPort->smtp_msg.subject_coding, pStart, pEnd - pStart);
			encode = *(pEnd + 1);
			strcpy(subject_temp, pEnd + 3);
			if (encode == 'B' || encode == 'b')
			{
				char *p = base64_decode(subject_temp);
				if (p == NULL)
					return PARSE_ERROR;
				strncpy((char *)pSmtpRxPort->smtp_msg.subject, p, MAX_SMTP_SUBJECT_LENGTH);
				pSmtpRxPort->smtp_msg.subject[MAX_SMTP_SUBJECT_LENGTH - 1] = '\0';
			}
			if (encode == 'Q' || encode == 'q')
				if (!Qp_decode((char *)pSmtpRxPort->smtp_msg.subject, subject_temp, strlen(subject_temp)))
					return PARSE_ERROR;
		}
		else
			strcpy((char *)pSmtpRxPort->smtp_msg.subject, subject_temp);
	}
	else
	{
		pSubject = pFrom;
		subject_temp[0] = '\0';
	}

	if (strstr(pt, "MIME-Version: 1.0") != NULL || strstr(pt, "Mime-Version: 1.0") != NULL)
	{
		// MIME format
		// find content start/end point
		pContents = pt;
		pContentsEnd = pt + strlen(pt);
		if ((pBoundary = strstr(pt, "boundary=")) != NULL)
		{
			char *pTemp;
			pBoundary += strlen("boundary=");
			if (*pBoundary == '"')
			{
				pBoundary++;
			}
			pTemp = pBoundary + 15; // just compare the first 15 chars
			//			while(*pTemp != '"' && *pTemp != '\r')
			//				pTemp++;
			*pTemp = '\0';
			pContents = pTemp + 1;
			pContentsEnd = strstr(pContents, "Content-Type: text/plain");
			if (pContentsEnd == NULL)
			{
				smeg_print("SYSTEM: No text content in this mail.\n");
				pSmtpRxPort->smtp_msg.contents[0] = '\0';
				return PARSE_SUCCESS;
			}
			pContentsEnd = strstr(pContentsEnd, pBoundary);
			if (pContentsEnd == NULL)
				pContentsEnd = pContents + strlen(pContents);
			else
				pContentsEnd--;
		}

		*pContentsEnd = '\0';
		if ((pContents = strstr(pContents, "Content-Type: text/plain")) != NULL)
		{
			Pt_contents_origin_code = strstr(pContents, "charset=");
			if (Pt_contents_origin_code == NULL)
				strcpy(pSmtpRxPort->smtp_msg.contents_coding, "us-ascii");
			else
			{
				Pt_contents_origin_code += strlen("charset=");

				if (*Pt_contents_origin_code == '"')
					Pt_contents_origin_code++;

				for (i = 0; *Pt_contents_origin_code != '\r'; i++)
				{
					if (*Pt_contents_origin_code == '"')
						Pt_contents_origin_code++;

					pSmtpRxPort->smtp_msg.contents_coding[i] = *Pt_contents_origin_code;
					Pt_contents_origin_code++;

					if (i >= 16) // for protection
						break;
				}
				pSmtpRxPort->smtp_msg.contents_coding[i] = '\0';
			}

			smeg_print("contents_coding: %s\n", pSmtpRxPort->smtp_msg.contents_coding);

			if ((pStart = strstr(pContents, "Content-Transfer-Encoding: base64")) != NULL)
			{
				pSmtpRxPort->encode_mode = 1;
			}
			else if ((pStart = strstr(pContents, "Content-Transfer-Encoding: quoted-printable")) != NULL)
			{
				pSmtpRxPort->encode_mode = 2;
			}
			else
			{
				pStart = pContents;
				pSmtpRxPort->encode_mode = 3;
			}

			pStart = strstr(pStart, "\r\n\r\n");
			if (pStart == NULL)
			{
				smeg_print("SYSTEM: Unable to decode this mail.\n");
				return PARSE_ERROR;
			}
			pStart += 4;

			pEnd = pContentsEnd;
			contents_temp_len = pEnd - pStart;
			if (contents_temp_len > MAX_EMAIL_LENGTH * 2 - 1)
				contents_temp_len = MAX_EMAIL_LENGTH * 2 - 1;
			memcpy(contents_temp, pStart, contents_temp_len);
			contents_temp[contents_temp_len] = '\0'; // 1-6
		}
		else
		{
			smeg_print("SYSTEM: No text content in this mail.\n");
			pSmtpRxPort->smtp_msg.contents[0] = '\0';
			return PARSE_SUCCESS;
		}
	}
	else
	{
		// RFC 822/2822 format
		pSmtpRxPort->encode_mode = 3;
		pStart = strstr(pt, "\r\n\r\n");
		if (pStart == NULL)
		{
			smeg_print("SYSTEM: No text content in this mail.\n");
			pSmtpRxPort->smtp_msg.contents[0] = '\0';
			return PARSE_SUCCESS;
		}
		pStart += 4;

		pEnd = strstr(pStart, "\r\n.");
		if (pEnd == NULL)
		{
			pEnd = pStart;
			while (*pEnd != '\0')
				pEnd++;
		}
		else
		{
			pEnd += 2;
		}
		contents_temp_len = pEnd - pStart;
		if (contents_temp_len > MAX_EMAIL_LENGTH * 2 - 1)
			contents_temp_len = MAX_EMAIL_LENGTH * 2 - 1;
		memcpy(contents_temp, pStart, contents_temp_len);
		contents_temp[contents_temp_len] = '\0'; // 1-6
	}

	smeg_print("contents_temp: %s\n", contents_temp);
	pSmtpRxPort->smtp_msg.contents[0] = '\0';
	if (pSmtpRxPort->encode_mode == 1)
	{
		pC = contents_temp;
		while (1)
		{
			pB = pC;
			pC = strchr(pC, '\r');
			if (pC == NULL)
				break;
			*(pC) = '\0';
			if (*pB == '\0')
				break;
			pD = base64_decode(pB);
			if (pD == NULL)
				return PARSE_ERROR;
			strcat((char *)pSmtpRxPort->smtp_msg.contents, pD);
			pC += 2;
		}
	}
	else if (pSmtpRxPort->encode_mode == 2)
	{
		char tmpBuf[MAX_EMAIL_LENGTH * 2];
		tmpBuf[0] = '\0';
		pC = contents_temp;
		while (1)
		{
			pB = pC;
			pC = strchr(pC, '\r');
			if (pC == NULL)
				break;

			*(pC) = '\0';
			strcat(tmpBuf, pB);
			pC += 2;
		}
		if (!Qp_decode((char *)pSmtpRxPort->smtp_msg.contents, tmpBuf, strlen((char *)tmpBuf)))
			return PARSE_ERROR;
	}
	else
	{
		pC = contents_temp;
		while (1)
		{
			pB = pC;
			pC = strchr(pC, '\r');
			if (pC == NULL)
				break;

			*(pC) = '\0';
			strcat((char *)pSmtpRxPort->smtp_msg.contents, pB);
			pC += 2;
		}
	}

	smeg_print("From: %s\nTo: ", pSmtpRxPort->smtp_msg.sender);
	for (i = 0; pSmtpRxPort->smtp_msg.recipient[i][0] != 0; i++)
		smeg_print("%s,", pSmtpRxPort->smtp_msg.recipient[i]);
	smeg_print("\nSubject: %s\n", pSmtpRxPort->smtp_msg.subject);
	smeg_print("Contents: %s\n", pSmtpRxPort->smtp_msg.contents);

	return PARSE_SUCCESS;
}

/*************************************************
Function:        // Qp_decode
Description:     // The email decode function
Calls:           //
Called By:       //
Table Accessed:  //
Table Updated:   //
Input:           // dst:the output data; src:the input data; len:the length of the input data
Output:          //
Return:          //
Others:          //
*************************************************/
int Qp_decode(char *dst, const char *src, int len) // 解码函数
{
	int i = 0;
	char tmp = 0;
	char ch1, ch2;

	if (len > 8192)
	{
		return 0;
	}

	while (i < len)
	{
		if (src[i] == '=' && i < len - 2) // 是编码字节
		{
			ch1 = src[i + 1];
			ch2 = src[i + 2];
			if ((src[i + 1] == '\r') || (src[i + 1] == '\n'))
			{
				i++;
				continue;
			}
			tmp = ((ch1 > '9') ? (ch1 - 'A' + 10) : (ch1 - '0')) * 16 + ((ch2 > '9') ? (ch2 - 'A' + 10) : (ch2 - '0'));
			*dst = tmp;
			dst++;
			i += 3;
		}
		else // 非编码字节
		{
			*dst = src[i];
			dst++;
			i++;
		}
	} // 输出加个结束符
	*dst = '\0';

	return 1;
}

/*************************************************
Function:        // delete_characters
Description:     //
Calls:           //
Called By:       //
Table Accessed:  //
Table Updated:   //
Input:           //
Output:          //
Return:          //
Others:          // no use
*************************************************/
char *delete_characters(const char *incoming, const char *characters, int flag)
{
	const char *pt1, *pt2;
	static char out[20 * 254];
	int len1;

	// memset(out, 0, sizeof(out));           //1-6
	pt1 = incoming;
	len1 = strlen(characters);
	while (strncmp(pt1, characters, len1) == 0) // 清除最开始的 characters
		pt1 = pt1 + len1;
	while ((pt2 = strstr(pt1, characters)) != NULL && *pt1 != '\0')
	{
		strncat(out, pt1, pt2 - pt1);
		if (flag)
			strcat(out, " "); // incoming为全英文
		pt1 = pt2 + len1;
	}

	if (*pt1 != '\0')
		strncat(out, pt1, strlen(incoming) - (pt1 - incoming));
	while (out[strlen(out) - 1] == ' ')
		out[strlen(out) - 1] = '\0';

	return out;
}

/*************************************************
Function:        // smtp_init
Description:     // The initial function of smtp file
Calls:           // tcp_socket; tcp_bind; tcp_listen;
					set_smtp_link_state
Called By:       //
Table Accessed:  //
Table Updated:   //
Input:           //
Output:          //
Return:          //
Others:          //
*************************************************/
void smtp_init()
{
	int i;
	struct sockaddr_in server_addr;
	memset(smtp_rx_port, 0, sizeof(struct tSmtpPort) * SMTP_MAX_RX_PORT);
	bzero(&server_addr, sizeof(struct sockaddr_in));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	server_addr.sin_port = htons(25);

	//----Smtp_Ser--
	tcp_socket(&Smtp_Ser_Sockfd);
	tcp_bind(Smtp_Ser_Sockfd, (struct sockaddr *)(&server_addr), sizeof(struct sockaddr));
	tcp_listen(Smtp_Ser_Sockfd, LISTEN_NUMS);
	//----smtp_tx_port-------------------
	memset(smtp_tx_port, 0, sizeof(struct tSmtpPort) * SMTP_MAX_TX_PORT);

	for (i = 0; i < Exe_num; i++)
		Execute[i] = -1;

	memset(&smtp_wait_queue, -1, sizeof(struct Smtp_wait_queue));
	smtp_wait_queue.start = 0;
	smtp_wait_queue.end = 0;
	for (i = 0; i < (Exe_num + LISTEN_NUMS); i++)
		All_Socket_FD[i] = -1;

	set_smtp_link_state(1);
	set_smtp_link_state(1);

	return;
}

/*************************************************
Function:        // smtp_main
Description:     // The timer function of the smtp file
Calls:           // tcp_accept
					add_socket_fd
					add_socket_rx
					set_smtp_link_state
					smtp_rx_failed
					smtp_rx_fsm
					smtp_tx_restart
					smtp_tx_fsm
Called By:       //
Table Accessed:  //
Table Updated:   //
Input:           //
Output:          //
Return:          //
Others:          //
*************************************************/
void smtp_main()
{
	int sin_size;
	int temp_fd = -2;
	int count;
	struct sockaddr_in client_addr;

	sin_size = sizeof(struct sockaddr_in);

	if (get_smpp_tx_link_state() > 0)
	{
		temp_fd = tcp_accept(Smtp_Ser_Sockfd, (struct sockaddr *)(&client_addr), &sin_size);
		if (temp_fd > -1)
		{
			smtp_rx_port_assign(temp_fd, smtp_rx_port);
			add_socket_fd(temp_fd);
			smeg_print("temp_fd: %d\n", temp_fd);
			add_socket_rx();
			set_smtp_link_state(1);
			printf("client connect\n");
		}
	}

	check_write_read();
	for (count = 0; count < SMTP_MAX_RX_PORT; count++)
	{
		if (smtp_rx_port[count].port_state != SMTP_PORT_IDLE)
		{
			smtp_rx_port[count].time_out++;
			if (smtp_rx_port[count].time_out >= 600)
			{
				smtp_rx_failed(&smtp_rx_port[count]); // 1-8
				continue;
			}
			smtp_rx_fsm(&smtp_rx_port[count]);
			smeg_print("smtp_rx_port:%d, port_state:%d, curr_state:%d\n", count, smtp_rx_port[count].port_state, smtp_rx_port[count].curr_state);
		}
	}

	//	check_write_read();
	for (count = 0; count < SMTP_MAX_TX_PORT; count++)
	{
		if (smtp_tx_port[count].port_state != SMTP_PORT_IDLE)
		{
			smtp_tx_port[count].time_out++;
			if (smtp_tx_port[count].time_out >= 600) // 10s for each trying
			{
				smtp_tx_restart(&smtp_tx_port[count]);
				continue;
			}
			smtp_tx_fsm(&smtp_tx_port[count]);
			smeg_print("smtp_tx_port:%d, port_state:%d, curr_state:%d\n", count, smtp_tx_port[count].port_state, smtp_tx_port[count].curr_state);
		}
	}
}

/*************************************************
Function:        // smtp_send_sm
Description:     // When receive a sm,change it to smtp format and send it to the smtp server
Calls:           // sm2email; smtp_tx_port_assign;
Called By:       // parse_sm
Table Accessed:  //
Table Updated:   //
Input:           // source_addr:the msisdn of the MT; short_message:the content of the sm
Output:          //
Return:          //
Others:          //
*************************************************/
void smtp_send_sm(const char *source_addr, char *short_message)
{
	SMTP_MSG smtp_msg;

	if (!check_user(source_addr))
		return;

	memset(&smtp_msg, 0, sizeof(SMTP_MSG));

	strcpy(smtp_msg.sender, "<");
	strcat(smtp_msg.sender, source_addr);
	strcat(smtp_msg.sender, "@");
	strcat(smtp_msg.sender, (char *)get_emaildomain());
	strcat(smtp_msg.sender, ">");

	if (sm2email(&smtp_msg, short_message) == PARSE_ERROR)
		return;

	smtp_tx_port_assign(&smtp_msg);
}

/*************************************************
Function:        // sm2email
Description:     // To change the sm format to the email format
Calls:           //
Called By:       // smtp_send_sm
Table Accessed:  //
Table Updated:   //
Input:           // smtp_msg:the smtp message; sm_contents:the content of the sm
Output:          //
Return:          //
Others:          //
*************************************************/
int sm2email(SMTP_MSG *smtp_msg, char *sm_contents)
{
	char tempcontents[8192];
	char *pAddr, *pDestAddr, *pSubject, *pContent;
	char *pMsg = sm_contents;
	;
	char *pAt, *pSemicolon, *pTmpCh;
	int addrLen = 0;
	int i = 0;

	if (smtp_msg == NULL || sm_contents == NULL || strlen(sm_contents) > MAX_EMAIL_LENGTH)
		return PARSE_ERROR;

	while (*pMsg < 0x21) // eat control ASCCII char
		pMsg++;

	if (*pMsg == '"')
	{ // eat sender's name
		pMsg++;
		while (*pMsg != '"')
			pMsg++;
		pMsg++;
	}

	while (*pMsg == ' ') // eat blank
		pMsg++;

	pDestAddr = pMsg;
	if ((pTmpCh = strchr(pMsg, ' ')) != NULL)
	{
		*pTmpCh = '\0';
		pSubject = pTmpCh + 1;
		if (pSubject[0] == '#' && pSubject[1] == '#' && strchr(pSubject + 2, '#') != NULL)
		{
			// has subject marked by ## and #
			pSubject += 2; // skip ##
			pTmpCh = strchr(pSubject, '#');
			*pTmpCh = '\0';
			pContent = pTmpCh + 1; // skip '#'
		}
		else if (pSubject[0] == '(' && strchr(pSubject, ')') != NULL)
		{
			// has subject marked by ( and )
			pSubject += 1; // skip (
			pTmpCh = strchr(pSubject, ')');
			*pTmpCh = '\0';
			pContent = pTmpCh + 1; // skip ')'
		}
		else
		{
			// no subject
			pContent = pSubject;
			pSubject = NULL;
		}
	}

	// parse receiptor address
	pAddr = pDestAddr;
	smtp_msg->recipientNum = 0;
	while (pAddr != NULL)
	{
		i = 0;

		if ((pSemicolon = strchr(pAddr, ',')) != NULL)
			*(pSemicolon++) = '\0';

		if ((pAt = strchr(pAddr, '@')) == NULL && (pAt = strchr(pAddr, '*')) == NULL)
			goto NEXT_ADDR; // format wrong

		if (*pAt == '*')
			*pAt = '@'; // replace '*' with '@'

		addrLen = strlen(pAddr);
		if (addrLen > SMTP_ADDR_LENGTH)
			goto NEXT_ADDR; // address to long, ignore

		smtp_msg->recipient[smtp_msg->recipientNum][i++] = '<';
		strncpy(smtp_msg->recipient[smtp_msg->recipientNum] + i, pAddr, addrLen);
		i += addrLen;
		smtp_msg->recipient[smtp_msg->recipientNum][i++] = '>';
		smtp_msg->recipient[smtp_msg->recipientNum][i++] = '\0';

		if (++smtp_msg->recipientNum > MAX_RECEIPTOR_PER_MSG)
			break;

	NEXT_ADDR:
		pAddr = pSemicolon; // point to next one
	}

	if (smtp_msg->recipientNum == 0)
		return PARSE_ERROR;

	strcpy(tempcontents, "From: ");
	strcat(tempcontents, smtp_msg->sender);
	strcat(tempcontents, "\r\nTo: ");
	for (i = 0; i < smtp_msg->recipientNum; i++)
	{
		if (i != 0)
			strcat(tempcontents, ",");
		strcat(tempcontents, smtp_msg->recipient[i]);
	}

	if (pSubject != NULL && strlen(pSubject) != 0)
	{
		char *p;
		strcpy((char *)smtp_msg->subject, pSubject);
		strcat(tempcontents, "\r\nSubject: =?UTF-8?B?");
		p = base64_encode(pSubject);
		if (p == NULL)
			return PARSE_ERROR;
		strcat(tempcontents, p);
		strcat(tempcontents, "?=");
	}
	strcat(tempcontents, "\r\nMIME-Version: 1.0\r\nContent-Type: text/plain; charset=\"");
	strcat(tempcontents, "UTF-8\"\r\nContent-Transfer-Encoding: base64\r\n\r\n");
	if (pContent != NULL && pContent[0] != '\0')
	{
		char *p = base64_encode(pContent);
		if (p == NULL)
			return PARSE_ERROR;
		strcat(tempcontents, p);
	}
	strcpy((char *)smtp_msg->contents, tempcontents);

	smeg_print("Recipient:");
	for (i = 0; i < smtp_msg->recipientNum; i++)
		smeg_print("%s,", smtp_msg->recipient[i]);
	smeg_print("\nSubject:%s\n", smtp_msg->subject);
	smeg_print("Contents:\n%s\n", smtp_msg->contents);

	return PARSE_SUCCESS;
}

/*************************************************
Function:        // save_smtp_tx_msg
Description:     //
Calls:           //
Called By:       //
Table Accessed:  //
Table Updated:   //
Input:           //
Output:          //
Return:          //
Others:          // no use
*************************************************/
void save_smtp_tx_msg()
{
	int count;
	for (count = 0; count < SMTP_MAX_TX_PORT; count++)
		if (smtp_tx_port[count].port_state == SMTP_PORT_BUSY)
			smtp_tx_port[count].curr_state = SMTP_TX_BEGIN;
}

/*************************************************
Function:        // add_socket_fd
Description:     // Insert the socket id into the queue
Calls:           //
Called By:       // smtp_tx_fsm
Table Accessed:  //
Table Updated:   //
Input:           // fd:the socket id
Output:          //
Return:          //
Others:          //
*************************************************/
void add_socket_fd(int fd)
{
	int i;
	for (i = 0; i < (Exe_num + LISTEN_NUMS); i++)
	{
		if (All_Socket_FD[i] == -1)
		{
			All_Socket_FD[i] = fd;
			return;
		}
	}
}

/*************************************************
Function:        // delete_socket_fd
Description:     // Delete the socket id in the queue
Calls:           //
Called By:       // smtp_tx_restart; smtp_tx_port_release;
Table Accessed:  //
Table Updated:   //
Input:           // fd:socket id
Output:          //
Return:          //
Others:          //
*************************************************/
void delete_socket_fd(int fd)
{
	int i;
	for (i = 0; i < (Exe_num + LISTEN_NUMS); i++)
	{
		if (All_Socket_FD[i] == fd)
		{
			All_Socket_FD[i] = -1;
			return;
		}
	}
}

/*************************************************
Function:        // check_write_read
Description:     // Check the state of the socket
Calls:           //
Called By:       //
Table Accessed:  //
Table Updated:   //
Input:           //
Output:          //
Return:          //
Others:          //
*************************************************/
int check_write_read()
{
	int i;
	int MaxFd = 0;
	struct timeval timeout = {0, 10};
	FD_ZERO(&Write_fd);
	FD_ZERO(&Read_fd);
	for (i = 0; i < (Exe_num + LISTEN_NUMS); i++)
	{
		if (All_Socket_FD[i] == -1)
			continue;

		FD_SET(All_Socket_FD[i], &Write_fd);
		FD_SET(All_Socket_FD[i], &Read_fd);
		if (All_Socket_FD[i] > MaxFd)
			MaxFd = All_Socket_FD[i];
	}
	return select(MaxFd + 1, &Read_fd, &Write_fd, NULL, &timeout);
}

void add_socket_tx()
{
	++socket_tx;
}
void add_socket_rx()
{
	++socket_rx;
}
void delt_socket_tx()
{
	--socket_tx;
}
void delt_socket_rx()
{
	--socket_rx;
} // 1-6
