/*************************************************
File name:	smeg_smpp.c
Author: 	JianHui Zheng
Version:	9:00:00
Date:  		2008-4-1
Description:This file include the functions to encode and send message in smpp
			to the SMSC with smpp link

			Functions from Smpp Module
			smpp_registerLink()
			smpp_attach_link()


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

#include <errno.h>
#include <ctype.h>
#include <iconv.h>
#include <math.h>

#define SMEG_SMPP_MAX_PORT 256
#define SMPP_PORT_IDLE 0
#define SMPP_PORT_BUSY 1

//BYTE DEBUG_buf[512];

static BYTE smpp_rx_link = 0;
static BYTE smpp_tx_link = 0;
static int license_count = 0;
int max_license_count = 0;
BYTE short_message_buf[4096];

typedef enum
{
	// server type
	SMEG_SMPP_CLIENT = 0,
	SMEG_SMPP_SERVER,
	// session type
	SMEG_SMPP_BIND_TX = 0,
	SMEG_SMPP_BIND_RX,
	SMEG_SMPP_BIND_TRX,
} SMEG_SMPP_PARAM;

#define CONCATENATED_SMS_BUFFER_SIZE 32
typedef struct CONCATENATED_SMS_T
{
	int ttl;	  // time to live
	int ref_id;	  // reference id
	BYTE max_num; // max sms
	BYTE cur_num; // current receieved sms
	BYTE content[MAX_CONCATENATED_SMS][MAX_SMPP_MSG_LENGTH];
} CONCATENATED_SMS;
CONCATENATED_SMS concat_buf[CONCATENATED_SMS_BUFFER_SIZE];
inline BYTE get_allowed_prefixes_flag(int i);
/*************************************************
Function:        // logMes
Description:     // Write the log into the file
Calls:           //
Called By:       //
Table Accessed:  //
Table Updated:   //
Input:           //
Output:          //
Return:          //
Others:          // For test
*************************************************/
char mes[8192];
void logMes(char *message)
{
	char command[8192];
	long l_time;
	struct tm *t;

	l_time = time(NULL);
	t = localtime(&l_time);
	if (strlen(message) > 8190)
		return;
	sprintf(command, "echo '%02d:%02d:%02d %s' >>../log/smeg_%d_%d.log", t->tm_hour, t->tm_min, t->tm_sec, message, t->tm_mon + 1, t->tm_mday);
	system(command);
}

int code_convert(char *from_charset, char *to_charset, char *inbuf, int inlen, char *outbuf, int outlen);
int check_code(char *subject_code, char *content_code);
int send_mail(SMTP_MSG *pSmtpMsg, int recipient_index);

/*************************************************
Function:        // add_concatenated_sms
Description:     // Connect the sm received from SMSC into a integrated email
Calls:           //
Called By:       // parse_sm
Table Accessed:  //
Table Updated:   //
Input:           // ref_id:the index of the whole sm
					max_num:the count of the split sm
					seq_id:the index of the split sm
					pContent:the data of the split sm
Output:          //
Return:          // 1:the connection is complete; 0-not finish
Others:          //
*************************************************/
int add_concatenated_sms(int ref_id, BYTE max_num, BYTE seq_id, BYTE *pContent)
{
	int i;
	int idle_one = -1;

	if (pContent == NULL)
		return 0;

	for (i = 0; i < CONCATENATED_SMS_BUFFER_SIZE; i++)
	{
		if (concat_buf[i].ref_id == ref_id)
		{
			strcpy((char *)concat_buf[i].content[seq_id - 1], (char *)pContent);
			concat_buf[i].cur_num++;
			smeg_print("Add concatenated sms: id:%d, ref_id:%d, max_msg:%d, current recieved:%d, Content:%s\n\n", i,
					   concat_buf[i].ref_id, concat_buf[i].max_num, concat_buf[i].cur_num, concat_buf[i].content[seq_id - 1]);
			if (concat_buf[i].cur_num >= concat_buf[i].max_num)
				return 1;
			else
				return 0;
		}
		else if (concat_buf[i].ttl == 0 && idle_one == -1)
			idle_one = i;
	}

	// first one
	if (idle_one != -1)
	{
		concat_buf[idle_one].ttl = 300; // 30s
		concat_buf[idle_one].ref_id = ref_id;
		concat_buf[idle_one].max_num = max_num;
		concat_buf[idle_one].cur_num = 1;
		strcpy((char *)concat_buf[idle_one].content[seq_id - 1], (char *)pContent);
		smeg_print("Add concatenated new sms: id:%d, ref_id:%d, max_msg:%d, current recieved:%d, Content:%s\n\n", idle_one,
				   concat_buf[idle_one].ref_id, concat_buf[idle_one].max_num,
				   concat_buf[idle_one].cur_num, concat_buf[idle_one].content[seq_id - 1]);
		return 0;
	}

	return 0;
}

/*************************************************
Function:        // get_concatenated_sms
Description:     // Return the whole data of the connected sm
Calls:           //
Called By:       // parse_sm
Table Accessed:  //
Table Updated:   //
Input:           // ref_id:the index of the connected sm
Output:          //
Return:          // The whole data
Others:          //
*************************************************/
BYTE *get_concatenated_sms(int ref_id)
{
	int i, j;

	for (i = 0; i < CONCATENATED_SMS_BUFFER_SIZE; i++)
	{
		if (concat_buf[i].ref_id == ref_id)
		{
			short_message_buf[0] = '\0';
			for (j = 0; j < concat_buf[i].max_num; j++)
			{
				strcat((char *)short_message_buf, (char *)concat_buf[i].content[j]);
			}
			memset(&concat_buf[i], 0, sizeof(CONCATENATED_SMS));
			return short_message_buf;
		}
	}
	return NULL;
}

/*************************************************
Function:        // update_concatenated_sms_buf
Description:     // Delete the whole sm data when its time to live exhaust
Calls:           //
Called By:       // smpp_main
Table Accessed:  //
Table Updated:   //
Input:           //
Output:          //
Return:          //
Others:          //
*************************************************/
void update_concatenated_sms_buf()
{
	int i = 0;

	for (; i < CONCATENATED_SMS_BUFFER_SIZE; i++)
	{
		if (concat_buf[i].ttl != 0)
			if (--concat_buf[i].ttl == 0)
				memset(&concat_buf[i], 0, sizeof(CONCATENATED_SMS));
	}
}

/*************************************************
Function:        // parse_sm
Description:     // Parse the data receive from SMSC
Calls:           // add_concatenated_sms
					get_concatenated_sms
					smtp_send_sm
					sm_decode
Called By:       // smpp_rx_DataRecv
Table Accessed:  //
Table Updated:   //
Input:           // udhi:the flag to devide sm
					coding:the coding method of the sm
					pFromAddr:the msisdn of the MT
					pSM:the data of the sm
					sm_len:the length of the message
Output:          //
Return:          //
Others:          //
*************************************************/
void parse_sm(int udhi, int coding, char *pFromAddr, char *pSM, int sm_len)
{
	int ret;
	BYTE udh_len;
	BYTE udh_iei;
	BYTE udh_ie_len;
	unsigned int ref_id;
	BYTE total_msg = 0;
	BYTE seq_id = 0;
	BYTE *pData = NULL;

	if (pSM == NULL)
		return;

	if (udhi == 1)
	{
		udh_len = *pSM++;
		udh_iei = *pSM++;
		udh_ie_len = *pSM++;
		if (udh_iei == 0x00)
			ref_id = *pSM++;
		else if (udh_iei == 0x08)
		{
			ref_id = *pSM++;
			ref_id = (ref_id << 8) | *pSM++;
		}
		else
			return;
		total_msg = *pSM++;
		seq_id = *pSM++;
		sm_len = sm_len - udh_len - 1;
		if (coding == 0x00 && udh_iei == 0x00)
		{		   // 7bit coding & 8bit reference
			pSM++; // skip padding byte
			sm_len--;
		}
		pData = (BYTE *)sm_decode(coding, pSM, sm_len);
		if (pData != NULL)
		{
			smeg_print("calling add_concatenated_sms(ref_id=%d, total_msg=%d, seq_id=%d, pData=%s)", ref_id, total_msg, seq_id, pData);
			ret = add_concatenated_sms(ref_id, total_msg, seq_id, pData);
			if (ret == 1)
			{
				pData = get_concatenated_sms(ref_id);
				if (pData != NULL)
					smtp_send_sm(pFromAddr, (char *)pData);
			}
		}
	}
	else
	{
		pData = (BYTE *)sm_decode(coding, pSM, sm_len);
		if (pData != NULL)
			smtp_send_sm(pFromAddr, (char *)pData);
	}
}

/*************************************************
Function:        // check_user
Description:     // Check the validation of the MT's msisdn
Calls:           // get_allowed_prefixes
Called By:       // smpp_send_email
Table Accessed:  //
Table Updated:   //
Input:           // recipient:the MT's msisdn
Output:          //
Return:          // 1:valid; 0:not valid
Others:          //
*************************************************/
int check_user(const char *recipient)
{
	int i, j;
	BYTE *pPrefix;

	// remove cc and ndc prefix, if existed
	i = 0;
	if (recipient[0] == '+')
		i++;
	if (!strncmp((char *)(recipient + i), (char *)get_cc(), strlen((char *)get_cc())))
		i += strlen((char *)get_cc());
	if (!strncmp((char *)(recipient + i), (char *)get_ndc(), strlen((char *)get_ndc())))
		i += strlen((char *)get_ndc());

	for (j = 1; j < SMEG_MAX_ALLOWED_PREFIX_ENTRY; j++)
	{
		if ((pPrefix = get_allowed_prefixes(j)) == NULL)
			continue;

		if (get_allowed_prefixes_flag(j) == 0)
			continue;

		if (pPrefix[0] != 0 && !strncmp((char *)(recipient + i), (char *)(pPrefix + 1), strlen((char *)(pPrefix + 1))))
			return 1;
	}

	smeg_print("User not in allowed list, discard message...\n");
	return 0;
}

/*************************************************
Function:        // smpp_send_email
Description:     // Send email to the email server
Calls:           // send_mail
					add_call_statistics
					email2sm; generating_cdr
					get_max_sms_per_email
Called By:       // smtp_rx_fsm
Table Accessed:  //
Table Updated:   //
Input:           // smtp_msg:the data of smtp; recipient_num:the recipient count;
Output:          //
Return:          //
Others:          //
*************************************************/
void smpp_send_email(SMTP_MSG *smtp_msg, int recipient_num)
{
	int i; // offset, sm_seq_id;
	// SMPP_MSG tmpMsg;

	if (!get_smpp_tx_link_state())
	{
		return;
	}

	for (i = 0; i < recipient_num; i++)
	{
		if (check_user(smtp_msg->recipient[i]))
		{
			send_mail(smtp_msg, i);

			/*
			offset = 0;
			sm_seq_id = 0;
			logMes("*************");
			logMes(smtp_msg->contents);
			logMes("*************");
			do{
				if(++sm_seq_id > get_max_sms_per_email())
					break;
				add_call_statistics(SMS_Outgoing_Attempt, 0);
				offset = email2sm(&tmpMsg, smtp_msg, offset, i);
				smpp_send(smpp_tx_link , &tmpMsg, 0);
				add_call_statistics(SMS_Outgoing_Successful, tmpMsg.pdu.deliver_sm.sm_length);
				license_count++;
				//generating_cdr();
			}while(offset > 0);
			*/
		}
	}
}

/*************************************************
Function:        // send_mail
Description:     // Send email to the email server(support unicode and UDH)
Calls:           // check_code
					code_convert
					byteswap
					add_call_statistics
					smpp_send
					get_max_sms_per_email
Called By:       // smpp_send_email
Table Accessed:  //
Table Updated:   //
Input:           // pSmtpMsg: the data of smtp message; recipient_index:the index of the recipient
Output:          //
Return:          //
Others:          // This function is added for unicode support
*************************************************/
int send_mail(SMTP_MSG *pSmtpMsg, int recipient_index)
{
	SMPP_MSG smppMsg;
	int check_res;
	char to_code_set[32];
	char *pch;
	char data[MAX_EMAIL_LENGTH];
	char code_subject_data[MAX_EMAIL_LENGTH];
	char code_content_data[MAX_EMAIL_LENGTH];
	char code_data[MAX_EMAIL_LENGTH];
	char *recipient = pSmtpMsg->recipient[recipient_index];
	char *subject = (char *)pSmtpMsg->subject;
	// char *content = (char*)pSmtpMsg->contents;
	int subject_len;
	int content_len;
	int i;

	int sm_count;
	int pos;
	int total_len;
	int maxLen;

	//----------fill the smpp object-------------
	memset(&smppMsg, 0, sizeof(SMPP_MSG));
	memset(data, 0, MAX_EMAIL_LENGTH);
	memset(code_data, 0, MAX_EMAIL_LENGTH);
	memset(code_subject_data, 0, MAX_EMAIL_LENGTH);
	memset(code_content_data, 0, MAX_EMAIL_LENGTH);

	smppMsg.message_type = 0x0B;
	smppMsg.optional_param_flag1 = 0x08000001;
	smppMsg.pdu.submit_sm.dest_addr_ton = 0x01;	  // IDD
	smppMsg.pdu.submit_sm.dest_addr_npi = 0x01;	  // E164
	smppMsg.pdu.submit_sm.source_addr_ton = 0x00; // Unknow
	smppMsg.pdu.submit_sm.source_addr_npi = 0x01; // E164
	strcpy((char *)smppMsg.pdu.submit_sm.service_type, "GSM");
	strcpy((char *)smppMsg.pdu.submit_sm.source_addr, (char *)get_service_number());
	if (*recipient == '+')
		recipient++;
	strcpy((char *)smppMsg.pdu.submit_sm.destination_addr, recipient);

	//--------check and justify the coding---------
	check_res = check_code(pSmtpMsg->subject_coding, pSmtpMsg->contents_coding);
	if (check_res == 0)
	{
		sprintf(to_code_set, "us-ascii");
		smppMsg.pdu.submit_sm.data_coding = 0x04;
	}
	else
	{
		sprintf(to_code_set, "UCS-2");
		smppMsg.pdu.submit_sm.data_coding = 0x08;
	}

	//----------------get the subject--------------
	if ((pch = strstr(subject, "\r\n")) != NULL)
		*pch = '\0';
	strcpy(data, pSmtpMsg->sender);
	strcat(data, " ");
	if (strlen(subject) > 0)
	{
		strcat(data, "(");
		strcat(data, subject);
		strcat(data, ")");
	}

	//----------------code the subject--------------
	{
		int ii;
		char tmpstr[32];

		logMes("-------------------------------------send_email--------------------------------------");
		memset(mes, 0, MAX_EMAIL_LENGTH);
		sprintf(mes, "pSmtpMsg->subject_coding=%s,to_code_set=%s,datalen=%d\n", pSmtpMsg->subject_coding, to_code_set, strlen(data));
		for (ii = 0; ii < (strlen(data) >= 1024 ? 1024 : subject_len); ii++)
		{
			sprintf(tmpstr, "%02x ", (unsigned char)data[ii]);
			strcat(mes, tmpstr);
		}
		logMes(mes);
	}

	subject_len = code_convert(pSmtpMsg->subject_coding, to_code_set, data, strlen(data), code_subject_data, MAX_EMAIL_LENGTH);
	if (subject_len == -1)
	{
		sprintf(mes, "convert error subject_len=%d\n", subject_len);
		logMes(mes);
		return 1;
	}
	{
		int ii;
		char tmpstr[32];

		memset(mes, 0, MAX_EMAIL_LENGTH);
		sprintf(mes, "coded subject_len=%d\n", subject_len);
		for (ii = 0; ii < (subject_len >= 1024 ? 1024 : subject_len); ii++)
		{
			sprintf(tmpstr, "%02x ", (unsigned char)code_subject_data[ii]);
			strcat(mes, tmpstr);
		}
		logMes(mes);
	}


	//---------------get the content-----------------
	strcpy((char *)data, (char *)pSmtpMsg->contents);
	{
		int ii;
		char tmpstr[32];

		memset(mes, 0, MAX_EMAIL_LENGTH);
		sprintf(mes, "pSmtpMsg->contents_coding=%s,to_code_set=%s,datalen=%d\n", pSmtpMsg->contents_coding, to_code_set, strlen(data));
		for (ii = 0; ii < (strlen(data) >= 1024 ? 1024 : subject_len) ; ii++)
		{
			sprintf(tmpstr, "%02x ", (unsigned char)data[ii]);
			strcat(mes, tmpstr);
		}
		logMes(mes);
	}
	//----------------code the content---------------
	content_len = code_convert(pSmtpMsg->contents_coding, to_code_set, data, strlen(data), code_content_data, MAX_EMAIL_LENGTH);
	if (content_len == -1) 
	{
		sprintf(mes, "convert error content_len=%d\n", content_len);
		logMes(mes);
		return 1;
	}
	{
		int ii;
		char tmpstr[32];

		memset(mes, 0, MAX_EMAIL_LENGTH);
		sprintf(mes, "coded content_len=%d\n", content_len);
		// for (ii = 0; ii < (content_len>64?64:content_len); ii++)
		// {
		// 	sprintf(tmpstr, "%02x ", (unsigned char)code_content_data[ii]);
		// 	strcat(mes, tmpstr);
		// }
		logMes(mes);
	}

	//-----------connect the subject and content-------------
	if (check_res == 1)
	{
		byteswap(code_subject_data, subject_len);
		byteswap(code_content_data, content_len);
	}
	for (i = 0; i < subject_len; i++)
	{
		code_data[i] = code_subject_data[i];
	}
	for (i = 0; i < content_len; i++)
	{
		code_data[i + subject_len] = code_content_data[i];
	}
	{
		int ii;
		char tmpstr[32];

		memset(mes, 0, MAX_EMAIL_LENGTH);
		sprintf(mes, "coded total message data len=%d\n", subject_len + content_len);
		// for (ii = 0; ii < subject_len + content_len; ii++)
		// {
		// 	sprintf(tmpstr, "%02x ", (unsigned char)code_data[ii]);
		// 	strcat(mes, tmpstr);
		// }
		logMes(mes);
	}
	//------------------divide the data----------------------
	// only need 1 short message
	if ((subject_len + content_len) <= MAX_SMPP_MSG_LENGTH)
	{
		smppMsg.pdu.submit_sm.sm_length = subject_len + content_len;
		memcpy(smppMsg.pdu.submit_sm.short_message, code_data, subject_len + content_len);
		add_call_statistics(SMS_Outgoing_Attempt, 0);
		smpp_send(smpp_tx_link, &smppMsg, 0);
		add_call_statistics(SMS_Outgoing_Successful, smppMsg.pdu.deliver_sm.sm_length);
		license_count++;
		// generating_cdr();
	}
	else
	{
		size_t temp = time(NULL);
		total_len = subject_len + content_len;
		sm_count = ceil((subject_len + content_len + 0.0) / MAX_SMPP_MSG_LENGTH);
		sm_count = ceil((subject_len + content_len + sm_count * 6 + 0.0) / MAX_SMPP_MSG_LENGTH);
		smppMsg.pdu.submit_sm.esm_class |= 0x40;
		maxLen = MAX_SMPP_MSG_LENGTH - 6;

		{
			sprintf(mes, "User data header(%dx6)=%d", sm_count, sm_count * 6);
			logMes(mes);
			sprintf(mes, "smppMsg.pdu.submit_sm.esm_class=%02x,max mail=%d,maxLen=%d", smppMsg.pdu.submit_sm.esm_class, get_max_sms_per_email(), maxLen);
			logMes(mes);
		}
		for (i = 0; i < sm_count; i++)
		{
			pos = 0;
			if (i >= get_max_sms_per_email())
				break;
			{
				sprintf(mes, "len=%d,position=%d,sm_count=%d", total_len, i + 1, sm_count);
				logMes(mes);
			}

			// User-Data-Header-Length
			smppMsg.pdu.submit_sm.short_message[pos++] = 0x05;
			// Information Element Identifier "A"
			smppMsg.pdu.submit_sm.short_message[pos++] = 0x00;
			// Length of Information Element "A"
			smppMsg.pdu.submit_sm.short_message[pos++] = 0x03;
			// Octet 1 Concatenated short message reference number
			smppMsg.pdu.submit_sm.short_message[pos++] = temp % 255 + 1;
			// Maximum number of short messages in the concatenated short message
			if (sm_count > get_max_sms_per_email())
				smppMsg.pdu.submit_sm.short_message[pos++] = get_max_sms_per_email();
			else
				smppMsg.pdu.submit_sm.short_message[pos++] = sm_count;
			// Sequence number of the current short message
			smppMsg.pdu.submit_sm.short_message[pos++] = i + 1;
			// short message data
			if (total_len >= maxLen)
			{
				smppMsg.pdu.submit_sm.sm_length = maxLen + pos;
				memcpy(smppMsg.pdu.submit_sm.short_message + pos, code_data + i * maxLen, maxLen);
			}
			else
			{
				smppMsg.pdu.submit_sm.sm_length = total_len + pos;
				memcpy(smppMsg.pdu.submit_sm.short_message + pos, code_data + i * maxLen, total_len);
			}
			{
				sprintf(mes, "message(%d),len=%d", i + 1, smppMsg.pdu.submit_sm.sm_length);
				logMes(mes);
			}
			add_call_statistics(SMS_Outgoing_Attempt, 0);
			smpp_send(smpp_tx_link, &smppMsg, 0);
			add_call_statistics(SMS_Outgoing_Successful, smppMsg.pdu.deliver_sm.sm_length);
			license_count++;
			// generating_cdr();
			total_len -= maxLen;
		}
		{
			logMes("---------------------------------------------------------------------------");
		}
	}
	return 0;
}

/*************************************************
Function:        // email2sm
Description:     // Change the smtp message to smpp message
Calls:           // get_service_number; code_convert; byteswap;
Called By:       // smpp_send_email
Table Accessed:  //
Table Updated:   //
Input:           // pMsg:the smpp message;
					pSmtpMsg:the smtp message;
					offset:the data index;
					recipient_index:the index of the recipient
Output:          //
Return:          // the data index
Others:          //
*************************************************/
int data_len;
char data_buf[MAX_EMAIL_LENGTH];
int email2sm(SMPP_MSG *pMsg, SMTP_MSG *pSmtpMsg, int offset, int recipient_index)
{
	int len;
	int sender_subject_len = 0;
	int contents_len = 0;
	char tmpBuf[256];
	char *sender = pSmtpMsg->sender;
	char *recipient = pSmtpMsg->recipient[recipient_index];
	char *subject = (char *)pSmtpMsg->subject;
	char *contents = (char *)pSmtpMsg->contents;
	PDU_SUBMIT_SM *submit_sm = &pMsg->pdu.submit_sm;

	int check_res = -1;
	char to_code_set[32];

	memset(pMsg, 0, sizeof(SMPP_MSG));
	{
		logMes("----------------------------------email2sm-------------------------------------");
		sprintf(mes, "before pSmtpMsg->subject_coding=%s\n", pSmtpMsg->subject_coding);
		logMes(mes);
		sprintf(mes, "before pSmtpMsg->contents_coding=%s\n", pSmtpMsg->contents_coding);
		logMes(mes);
	}
	check_res = check_code(pSmtpMsg->subject_coding, pSmtpMsg->contents_coding);

	pMsg->message_type = 0x0B;
	pMsg->optional_param_flag1 = 0x08000001;
	if (check_res == 0)
	{
		sprintf(to_code_set, "us-ascii");
		submit_sm->data_coding = 0x04;
	}
	else
	{
		sprintf(to_code_set, "UCS-2");
		submit_sm->data_coding = 0x08;
	}

	submit_sm->dest_addr_ton = 0x01;   // IDD
	submit_sm->dest_addr_npi = 0x01;   // E164
	submit_sm->source_addr_ton = 0x00; // Unknow
	submit_sm->source_addr_npi = 0x01; // E164
	strcpy((char *)submit_sm->service_type, "GSM");
	strcpy((char *)submit_sm->source_addr, (char *)get_service_number());
	if (*recipient == '+')
		recipient++;
	strcpy((char *)submit_sm->destination_addr, recipient);

	if (offset == 0)
	{
		// from&subject
		char *pch;
		if ((pch = strstr(subject, "\r\n")) != NULL)
			*pch = '\0';

		strcpy(tmpBuf, sender);
		strcat(tmpBuf, " ");
		if (strlen(subject) > 0)
		{
			strcat(tmpBuf, "(");
			strcat(tmpBuf, subject);
			strcat(tmpBuf, ")");
		}
		// pSmtpMsg->contents_coding
		{
			int ii;
			char strtmp[32];
			sprintf(mes, "after pSmtpMsg->subject_coding=%s\n", pSmtpMsg->subject_coding);
			logMes(mes);
			sprintf(mes, "after pSmtpMsg->contents_coding=%s\n", pSmtpMsg->contents_coding);
			logMes(mes);
			sprintf(mes, "before subject,size=%d\n", strlen(tmpBuf));
			logMes(mes);

			mes[0] = '\0';
			for (ii = 0; ii < strlen(tmpBuf); ii++)
			{
				sprintf(strtmp, "%02x ", tmpBuf[ii]);
				strcat(mes, strtmp);
			}
			logMes(mes);
		}
		sender_subject_len = code_convert(pSmtpMsg->subject_coding, to_code_set, tmpBuf, strlen(tmpBuf), data_buf, MAX_EMAIL_LENGTH);
		{
			int ii;
			char strtmp[32];
			sprintf(mes, "coded subject,size=%d\n", sender_subject_len);
			logMes(mes);

			mes[0] = '\0';
			for (ii = 0; ii < sender_subject_len; ii++)
			{
				sprintf(strtmp, "%02x ", data_buf[ii]);
				strcat(mes, strtmp);
			}
			logMes(mes);
		}
		// pSmtpMsg->contents_coding
		{
			int ii;
			char strtmp[32];
			sprintf(mes, "before content,size=%d\n", strlen(contents));
			logMes(mes);

			mes[0] = '\0';
			for (ii = 0; ii < strlen(contents); ii++)
			{
				sprintf(strtmp, "%02x ", (unsigned char)contents[ii]);
				strcat(mes, strtmp);
			}
			logMes(mes);
		}
		contents_len = code_convert(pSmtpMsg->contents_coding, to_code_set, contents, strlen(contents), data_buf + sender_subject_len, MAX_EMAIL_LENGTH);

		/*
				sender_subject_len = unicode_conv(pSmtpMsg->subject_coding,
											"UCS-2",
											tmpBuf,
											data_buf,
											strlen(tmpBuf),
											MAX_EMAIL_LENGTH);

				//content
				contents_len = unicode_conv(pSmtpMsg->contents_coding,
											"UCS-2",
											contents,
											data_buf+sender_subject_len,
											strlen(contents),
											MAX_EMAIL_LENGTH);
		*/
		if (check_res == 1)
			byteswap(data_buf, sender_subject_len + contents_len);

		// strcpy(data_buf, tmpBuf);
		// strcat(data_buf, contents);
		// data_len = strlen(data_buf);
		data_len = sender_subject_len + contents_len;
	}

	if (offset == 0)
	{
		if (data_len > MAX_SMPP_MSG_LENGTH)
			len = MAX_SMPP_MSG_LENGTH;
		else
			len = data_len;

		memcpy(submit_sm->short_message, data_buf, len);
		offset = len;
	}
	else
	{
		if ((len = data_len - offset) > MAX_SMPP_MSG_LENGTH)
			len = MAX_SMPP_MSG_LENGTH;

		memcpy(submit_sm->short_message, data_buf + offset, len);
		offset += len;
	}
	submit_sm->sm_length = len;
	smeg_print("destination_addr():%s\n", submit_sm->destination_addr);
	smeg_print("short_message():%s\n", submit_sm->short_message);

	{
		int ii;
		char strtmp[32];

		sprintf(mes, "coded short_message,size=%d\n", submit_sm->sm_length);
		logMes(mes);

		mes[0] = '\0';
		for (ii = 0; ii < submit_sm->sm_length; ii++)
		{
			sprintf(strtmp, "%02x ", (unsigned char)submit_sm->short_message[ii]);
			strcat(mes, strtmp);
		}
		logMes(mes);
		logMes("----------------------------------------------------------------------------------\n");
	}

	if (offset < data_len)
		return offset;
	else
		return 0;
}

/*************************************************
Function:        // smpp_tx_register_link
Description:     // Register the tx smpp link
Calls:           // smpp_registerLink; smpp_attach_link; set_smpp_tx_link_state
Called By:       // smpp_init
Table Accessed:  //
Table Updated:   //
Input:           //
Output:          //
Return:          //
Others:          //
*************************************************/
extern BYTE smpp_registerLink(BYTE server_type, BYTE session_type, char *service_number_ptr, BYTE message_mode);
void smpp_tx_register_link()
{
	BYTE ret;

	smeg_debug_log("init smpp tx link");
	ret = smpp_registerLink(SMEG_SMPP_CLIENT, SMEG_SMPP_BIND_TX, get_service_number(), 0);
	set_smpp_tx_link_state(0);
	if ((ret & 0x80) == 0x80)
	{
		smpp_tx_link = ret & 0x7f;
		smeg_print("\nsmpp_registerLink:%d\n", smpp_tx_link);

		smpp_attach_link(smpp_tx_link, smpp_tx_DataRecv, smpp_tx_LinkStateChange);
		return;
	}

	return;
}

/*************************************************
Function:        // smpp_tx_LinkStateChange
Description:     // The callback function when the state of link change
Calls:           // set_smpp_tx_link_state
Called By:       // smpp_tx_register_link
Table Accessed:  //
Table Updated:   //
Input:           // linkNo:the no of the link; linkstate:the state of the link
Output:          //
Return:          //
Others:          //
*************************************************/
int smpp_tx_LinkStateChange(BYTE linkNo, BYTE linkstate)
{
	smeg_print("smpp_tx link %d state change to %d\n", linkNo, linkstate);
	if (linkstate == 0)
	{
		set_smpp_tx_link_state(0);
		smeg_debug_log("smpp tx link state change to disnormal");
	}
	else
	{
		set_smpp_tx_link_state(1);
		smeg_debug_log("smpp tx link state change to normal");
	}

	return linkNo;
}

/*************************************************
Function:        // smpp_tx_DataRecv
Description:     // The callback function when receive data from SMSC
Calls:           // smpp_send
Called By:       // smpp_tx_register_link
Table Accessed:  //
Table Updated:   //
Input:           // linkNo:the no of the link; pMsg:the smpp message; dataLen:the length of the data
Output:          //
Return:          //
Others:          //
*************************************************/
int smpp_tx_DataRecv(BYTE linkNo, SMPP_MSG *pMsg, WORD dataLen)
{
	int sequence_number = 100;
	char short_message[256];
	SMPP_MSG smpp_msg;

	memset(&smpp_msg, 0, sizeof(SMPP_MSG));

	switch (pMsg->message_type)
	{

	case 0x0C: /* SUBMIT SM RESP */
		break;
	case 0x0B: /* SUBMIT SM */
		strcpy(short_message, sm_decode(pMsg->pdu.submit_sm.data_coding, (char *)pMsg->pdu.submit_sm.short_message, pMsg->pdu.submit_sm.sm_length));
		smpp_msg.message_type = 0x0c;
		smpp_msg.pdu.submit_sm_resp.head.command_status = htonl(ESME_ROK);
		smpp_msg.pdu.submit_sm_resp.head.sequence_number = pMsg->pdu.submit_sm.head.sequence_number;
		smpp_msg.pdu.submit_sm_resp.head.command_length = 16 + strlen((char *)smpp_msg.pdu.submit_sm_resp.message_id);
		strcpy((char *)smpp_msg.pdu.submit_sm_resp.message_id, "0");
		smpp_send(linkNo, &smpp_msg, dataLen);
		break;
		//-------------------------------------------
	case 0x10: /* deliver_sm_resp*/
		break;
	case 0x0F: /* deliver_sm*/
		strcpy(short_message, sm_decode(pMsg->pdu.deliver_sm.data_coding, (char *)pMsg->pdu.deliver_sm.short_message, pMsg->pdu.deliver_sm.sm_length));
		smpp_msg.message_type = 0x10;
		smpp_msg.pdu.deliver_sm_resp.head.command_status = htonl(ESME_ROK);
		smpp_msg.pdu.deliver_sm_resp.head.sequence_number = pMsg->pdu.deliver_sm.head.sequence_number;
		smpp_msg.pdu.deliver_sm_resp.message_id = '0';
		smpp_msg.pdu.deliver_sm_resp.head.command_length = 17;
		smpp_send(linkNo, &smpp_msg, dataLen);
		break;
	default:
		smeg_debug_log("[ERROR]link %d no such message type!(=%02x)\n", linkNo, pMsg->message_type);
		break;
	}
	return sequence_number;
}

/*************************************************
Function:        // decode8byte7bitdata
Description:     // Decode the 8 bit to 7bit format
Calls:           //
Called By:       // decode7bitdata
Table Accessed:  //
Table Updated:   //
Input:           // in_buffer:the input data; out_buffer:the output data; len_of_data:the length of the input data
Output:          //
Return:          //
Others:          //
*************************************************/
void decode8byte7bitdata(char *in_buffer, char *out_buffer, int len_of_data)
{
	int i;
	for (i = 0; i < len_of_data; i++)
	{
		switch (i)
		{
		case 0:
			out_buffer[0] = in_buffer[0] & 0x7f;
			break;
		case 1:
			out_buffer[1] = ((in_buffer[1] & 0x3f) << 1) | ((in_buffer[0] >> 7) & 0x01);
			break;
		case 2:
			out_buffer[2] = ((in_buffer[2] & 0x1f) << 2) | ((in_buffer[1] >> 6) & 0x03);
			break;
		case 3:
			out_buffer[3] = ((in_buffer[3] & 0x0f) << 3) | ((in_buffer[2] >> 5) & 0x07);
			break;
		case 4:
			out_buffer[4] = ((in_buffer[4] & 0x07) << 4) | ((in_buffer[3] >> 4) & 0x0f);
			break;
		case 5:
			out_buffer[5] = ((in_buffer[5] & 0x03) << 5) | ((in_buffer[4] >> 3) & 0x1f);
			break;
		case 6:
			out_buffer[6] = ((in_buffer[6] & 0x01) << 6) | ((in_buffer[5] >> 2) & 0x3f);
			if (in_buffer[6] >> 1)
			{
				out_buffer[7] = (in_buffer[6] >> 1) & 0x7f;
			}
			break;
		default:
			break;
		}
	}
}

/*************************************************
Function:        // decode7bitdata
Description:     // Decode the 8 bit to 7bit format
Calls:           // decode8byte7bitdata
Called By:       // sm_decode
Table Accessed:  //
Table Updated:   //
Input:           // in_buffer:the input data; out_buffer:the output data; len_of_data:the length of the input data
Output:          //
Return:          //
Others:          //
*************************************************/
void decode7bitdata(char *in_buffer, char *out_buffer, int len_of_data)
{
	int i;
	int in_buffer_len = (len_of_data / 7) * 8 + len_of_data % 7;
	memset(out_buffer, 0, in_buffer_len);
	for (i = 0; i < (len_of_data + 7); i += 7)
	{
		decode8byte7bitdata(in_buffer + i, out_buffer + (i / 7) * 8, (len_of_data - i >= 7 ? 7 : len_of_data - i));
	}
	out_buffer[in_buffer_len + 1] = '\0';
}

/*************************************************
Function:        // from_default_alphabet
Description:     // Change some specil character to default
Calls:           //
Called By:       // sm_decode
Table Accessed:  //
Table Updated:   //
Input:           // in_buffer:the input data; in_buffer_len:the length of the input data
Output:          //
Return:          //
Others:          //
*************************************************/
void from_default_alphabet(char *in_buffer, int in_buffer_len)
{
	int i;

	for (i = 0; i < in_buffer_len; i++)
	{
		switch (in_buffer[i])
		{
		case 0x02:
			in_buffer[i] = '$';
			break;
		case 0x00:
			in_buffer[i] = '@';
			break;
		case 0x11:
			in_buffer[i] = '_';
			break;
		case 0x2F:
			in_buffer[i] = '/';
			break;
		default:
			break;
		}
	}
}

/*************************************************
Function:        // byteswap
Description:     // Swap the high byte and low byte
Calls:           //
Called By:       // sm_decode; send_mail; email2sm
Table Accessed:  //
Table Updated:   //
Input:           // input:the input data; input_len:the length of the input data
Output:          //
Return:          //
Others:          //
*************************************************/
void byteswap(char *input, int input_len)
{
	char temp;
	int i;

	for (i = 0; i < input_len; i += 2)
	{
		temp = input[i];
		input[i] = input[i + 1];
		input[i + 1] = temp;
	}
}

/*************************************************
Function:        // unicode_conv
Description:     // Convert the code data
Calls:           // iconv_open; iconv;
Called By:       // send_mail
Table Accessed:  //
Table Updated:   //
Input:           //
Output:          //
Return:          //
Others:          // This function have error
*************************************************/
int unicode_conv(const char *fromcode, const char *tocode, char *in_buffer, char *out_buffer, int insize, int outsize)
{
	size_t retval = 0;
	char *out_buffer_ptr = out_buffer;
	char *in_buffer_ptr = in_buffer;
	size_t out_byte = outsize; /* -2 because it ended with NUL,NUL */
	size_t in_byte = insize;
	iconv_t conv_d;

	conv_d = iconv_open(tocode, fromcode);
	if (conv_d == (iconv_t)-1)
	{
		return (-1);
	}
	retval = iconv(conv_d, NULL, NULL, NULL, NULL);
	if (retval == (size_t)-1)
		perror("1:unicode_conv()");

	retval = iconv(conv_d, &in_buffer_ptr, &in_byte, &out_buffer_ptr, &out_byte);

	if (retval == (size_t)-1)
	{
		smeg_print("ERROR ....\n");
		smeg_print("in_byte=%d,out_byte=%d\n", in_byte, out_byte);
		perror("unicode_conv()");
		return (-1);
	}

	{
		char *out_buffer_ptr = out_buffer;
		size_t out_byte = outsize;
		retval = iconv(conv_d, NULL, NULL, &out_buffer_ptr, &out_byte);
		if (retval == (size_t)-1)
		{
			smeg_print("ERROR .....\n");
		}
	}

	iconv_close(conv_d);
	return (outsize - out_byte);
}

/*************************************************
Function:        // unicode_conv
Description:     // Convert the code data
Calls:           // iconv_open; iconv;
Called By:       // send_mail
Table Accessed:  //
Table Updated:   //
Input:           // from_charset:the source code method
					to_charset:the destination code method
					inbuf:the data will be changed coding
					inlen:the length of the input data
					outbuf:the data have been changed coding
					outlen:the max length of the output data
Output:          //
Return:          // the length of the output data
Others:          //
*************************************************/
int code_convert(char *from_charset, char *to_charset, char *inbuf, int inlen, char *outbuf, int outlen)
{
	iconv_t cd;
	char **pin = &inbuf;
	char **pout = &outbuf;
	int len = outlen;
	size_t in_len = inlen, out_len = outlen;
	//in_len = inlen;
	cd = iconv_open(to_charset, from_charset);
	if (cd == 0)
		return -1;
	memset(outbuf, 0, outlen);
	if (iconv(cd, pin, (size_t *)&in_len, pout, (size_t *)&out_len) == -1)
	{
		sprintf(mes, "convert error, inbuf:%s, in_len=%d\n", inbuf, (int)in_len);
		logMes(mes);
		return -1;
	}
	iconv_close(cd);

	return len - (int)out_len;
}

/*************************************************
Function:        // check_code
Description:     // Justify the coding method
Calls:           //
Called By:       // send_mail
Table Accessed:  //
Table Updated:   //
Input:           // subject_code:the coding method of the subject
					content_code:the coding method of the content
Output:          //
Return:          //
Others:          //
*************************************************/
int check_code(char *subject_code, char *content_code)
{
	// check the subject coding
	if (strncasecmp(subject_code, "gb2312", 6) == 0)
	{
		sprintf(subject_code, "gb2312");
	}
	else if (strncasecmp(subject_code, "gbk", 3) == 0)
	{
		sprintf(subject_code, "GBK");
	}
	else if (strncasecmp(subject_code, "us-ascii", 8) == 0)
	{
		sprintf(subject_code, "us-ascii");
	}
	else if (strncasecmp(subject_code, "utf-8", 5) == 0)
	{
		sprintf(subject_code, "utf-8");
	}
	else
	{
		{
			sprintf(mes, "subject other coding=%s", subject_code);
			logMes(mes);
		}
		sprintf(subject_code, "utf-8");
	}

	// check the content coding
	if (strncasecmp(content_code, "gb2312", 6) == 0)
	{
		sprintf(content_code, "gb2312");
	}
	else if (strncasecmp(content_code, "gbk", 3) == 0)
	{
		sprintf(content_code, "GBK");
	}
	else if (strncasecmp(content_code, "us-ascii", 8) == 0)
	{
		sprintf(content_code, "us-ascii");
	}
	else if (strncasecmp(content_code, "utf-8", 5) == 0)
	{
		sprintf(content_code, "utf-8");
	}
	else
	{
		{
			sprintf(mes, "content other coding=%s", content_code);
			logMes(mes);
		}
		sprintf(content_code, "utf-8");
	}

	if (strcmp(subject_code, "us-ascii") == 0 && strcmp(content_code, "us-ascii") == 0)
	{
		return 0;
	}
	else
	{
		return 1;
	}
}

/*************************************************
Function:        // sm_decode
Description:     // Decode the data of sm
Calls:           // decode7bitdata; from_default_alphabet; byteswap; unicode_conv
Called By:       // parse_sm
Table Accessed:  //
Table Updated:   //
Input:           // data_coding:the coding method; short_message:the data; sm_length:the length of the data
Output:          //
Return:          // the coded data
Others:          //
*************************************************/
char *sm_decode(int data_coding, char *short_message, int sm_length)
{
	static char conv_message[256];
	char temp_buffer[512];
	char *in_buffer = short_message;
	int no_of_bytes = sm_length;

	switch (data_coding)
	{
	case 0:
		decode7bitdata(in_buffer, conv_message, no_of_bytes);
		from_default_alphabet(conv_message, no_of_bytes);
		smeg_print("short_message:%s\n", conv_message);
		break;
	case 4:
		smeg_print("short_message:%s\n", short_message);
		strcpy(conv_message, short_message);
		break;
	case 8:
		memcpy(temp_buffer, in_buffer, no_of_bytes);
		temp_buffer[no_of_bytes] = 0x0;
		temp_buffer[no_of_bytes + 1] = 0x0;
		temp_buffer[no_of_bytes + 2] = 0x0;
		temp_buffer[no_of_bytes + 3] = 0x0;
		byteswap(temp_buffer, no_of_bytes);
		unicode_conv("UCS-2", "UTF-8", temp_buffer, conv_message, no_of_bytes + 4, sizeof(conv_message));
		smeg_print("short_message:%s\n", conv_message);
		break;
	}

	return conv_message;
}

/*************************************************
Function:        // smpp_rx_DataRecv
Description:     // The callback function when smpp rx receive data
Calls:           // parse_sm
					add_call_statistics
Called By:       // smpp_rx_register_link
Table Accessed:  //
Table Updated:   //
Input:           // linkNo:the no of the link; pMsg:the received data; dataLen:the length of data
Output:          //
Return:          //
Others:          //
*************************************************/
int smpp_rx_DataRecv(BYTE linkNo, SMPP_MSG *pMsg, WORD dataLen)
{
	int udhi = 0;
	BYTE *pSM = NULL, *pFromAddr = NULL;
	BYTE sm_len = 0;
	BYTE coding = 0;
	int sequence_number = 100;
	SMPP_MSG smpp_msg;
	memset(&smpp_msg, 0, sizeof(SMPP_MSG));

	switch (pMsg->message_type)
	{
	case 0x0C: /* SUBMIT SM RESP */
		smeg_print("Recv: Link %d received SUBMIT SM RESP.\n", linkNo);
		break;
	case 0x0B: /* SUBMIT SM */
		smeg_print("Recv: Link %d received submit_sm:%s \n", linkNo, pMsg->pdu.submit_sm.short_message);
		smeg_print("data_coding_scheme:%d\n", pMsg->pdu.submit_sm.data_coding);

		pSM = pMsg->pdu.submit_sm.short_message;
		sm_len = pMsg->pdu.submit_sm.sm_length;
		pFromAddr = pMsg->pdu.submit_sm.source_addr;
		coding = pMsg->pdu.submit_sm.data_coding;
		if (pMsg->pdu.submit_sm.esm_class & 0x40)
			udhi = 1;

		smpp_msg.message_type = 0x0c;
		smpp_msg.pdu.submit_sm_resp.head.command_status = htonl(ESME_ROK);
		smpp_msg.pdu.submit_sm_resp.head.sequence_number = pMsg->pdu.submit_sm.head.sequence_number;
		strcpy((char *)smpp_msg.pdu.submit_sm_resp.message_id, "0");
		smpp_msg.pdu.submit_sm_resp.head.command_length = 16 + strlen((char *)smpp_msg.pdu.submit_sm_resp.message_id);
		smpp_send(linkNo, &smpp_msg, dataLen);
		break;
	case 0x10: /* deliver_sm_resp*/
		smeg_print("Link %d received deliver_sm_resp.\n", linkNo);
		break;
	case 0x0F: /* deliver_sm*/
		smeg_print("Link %d received deliver_sm:%s \n", linkNo, pMsg->pdu.deliver_sm.short_message);
		smeg_print("data_coding_scheme:%d\n", pMsg->pdu.deliver_sm.data_coding);

		pSM = pMsg->pdu.deliver_sm.short_message;
		sm_len = pMsg->pdu.deliver_sm.sm_length;
		pFromAddr = pMsg->pdu.deliver_sm.source_addr;
		coding = pMsg->pdu.deliver_sm.data_coding;
		if (pMsg->pdu.deliver_sm.esm_class & 0x40)
			udhi = 1;

		smpp_msg.message_type = 0x10;
		smpp_msg.pdu.deliver_sm_resp.head.command_status = htonl(ESME_ROK);
		smpp_msg.pdu.deliver_sm_resp.head.sequence_number = pMsg->pdu.deliver_sm.head.sequence_number;
		smpp_msg.pdu.deliver_sm_resp.message_id = '0';
		smpp_msg.pdu.deliver_sm_resp.head.command_length = 17;
		smpp_send(linkNo, &smpp_msg, dataLen);
		break;

	default:
		smeg_print("Message_type=%d---Link %d received DELIVER SM. op:%s \n", pMsg->message_type, linkNo, pMsg->pdu.deliver_sm.short_message);
		break;
	}

	parse_sm(udhi, coding, (char *)pFromAddr, (char *)pSM, sm_len);
	add_call_statistics(SMS_Incoming_Attempt, 0);
	add_call_statistics(SMS_Incoming_Successful, pMsg->pdu.submit_sm.sm_length);
	license_count++;
	return sequence_number;
}

/*************************************************
Function:        // smpp_rx_register_link
Description:     // Register the rx link
Calls:           // smpp_registerLink; smpp_attach_link; set_smpp_rx_link_state
Called By:       // smpp_init
Table Accessed:  //
Table Updated:   //
Input:           //
Output:          //
Return:          //
Others:          //
*************************************************/
void smpp_rx_register_link()
{
	BYTE ret;
	ret = smpp_registerLink(SMEG_SMPP_CLIENT, SMEG_SMPP_BIND_RX, get_service_number(), 0);
	set_smpp_rx_link_state(0);
	if ((ret & 0x80) == 0x80)
	{
		smpp_rx_link = ret & 0x7f;
		smeg_print("\nGet smpp rx link is:%d\n", smpp_rx_link);

		smpp_attach_link(smpp_rx_link, smpp_rx_DataRecv, smpp_rx_LinkStateChange);
	}
	smeg_debug_log("init smpp rx link");

	return;
}

/*************************************************
Function:        // smpp_rx_LinkStateChange
Description:     // The callback function when rx link state change
Calls:           // set_smpp_rx_link_state
Called By:       // smpp_rx_register_link
Table Accessed:  //
Table Updated:   //
Input:           // linkNo:the no of the link; linkstate:the state of the link
Output:          //
Return:          //
Others:          //
*************************************************/
int smpp_rx_LinkStateChange(BYTE linkNo, BYTE linkstate)
{
	smeg_print("smpp_rx link %d state change to %d\n", linkNo, linkstate);

	if (linkstate == 0)
	{
		set_smpp_rx_link_state(0); // 1-8
		smeg_debug_log("smpp rx link state change to disnormal");
	}
	else
	{
		set_smpp_rx_link_state(1);
		smeg_debug_log("smpp rx link state change to normal");
	}
	return linkNo;
}

/*************************************************
Function:        // smpp_init
Description:     // The initial function of the smpp file
Calls:           // smpp_tx_register_link; smpp_rx_register_link;
Called By:       // smeg_init
Table Accessed:  //
Table Updated:   //
Input:           //
Output:          //
Return:          //
Others:          //
*************************************************/
void smpp_init()
{
	smpp_tx_register_link();
	smpp_rx_register_link();
}

/*************************************************
Function:        // smpp_main
Description:     // The timer function of the smpp file
Calls:           // get_license
					smpp_closeTCPConnection
					set_smpp_rx_link_state
					smpp_tx_register_link
					smpp_rx_register_link
Called By:       // semg_main
Table Accessed:  //
Table Updated:   //
Input:           //
Output:          //
Return:          //
Others:          //
*************************************************/
void smpp_main()
{
	static int time_count = 0;
	static int smpp_timeout = 600;

	update_concatenated_sms_buf();

	if (time_count++ >= 36000)
	{ // 1 hour
		if (license_count > max_license_count)
			max_license_count = license_count;
		license_count = 0;
	}

	if (license_count > get_license())
	{
		if (get_smpp_rx_link_state() != 0)
		{
			smpp_closeTCPConnection(smpp_rx_link);
			set_smpp_rx_link_state(0);
		}
		else if (get_smpp_tx_link_state() != 0)
		{
			smpp_closeTCPConnection(smpp_tx_link);
			set_smpp_tx_link_state(0);
		}
	}
	else
	{
		if (smpp_timeout-- <= 0)
		{
			smpp_timeout = 600;
			if (get_smpp_rx_link_state() == 0)
			{
				smpp_rx_register_link();
			}
			if (get_smpp_tx_link_state() == 0)
			{
				smpp_tx_register_link();
			}
		}
	}
}
