/* 
** CDMA 2000 project, SMPP module
**
** File name: smpp_msg.c
** Written by Li Long at 2004-11-25
** CVS $Id: smpp_msg.c,v0.1 2004/11/25 17:03:14 lilong Exp $
**
*/

#include "./include/smpp.h"
#include "./include/smpp_ext.h"

//static BYTE	src_ref[MAX_SMPP_LINK];
//static BYTE	dst_ref[MAX_SMPP_LINK];

/* by simon at 23/9/26 */
BYTE smpp_msg_buf[MAX_SMPP_LINK][MAX_PACKET_SIZE];
extern int smpp_msg_buf_len[MAX_SMPP_LINK];

extern int sclc_receive(SCLC_MSG *pmsg, BYTE usertype);
extern int sclc_send(SCLC_MSG *pmsg);

static SMPP_OPTIONAL_PARAMETER	opt_param[SMPP_OPT_PARAM_NUM];

void smpp_msgInit()
{
	int i,t;

	t	= rand();
	for (i=0; i<MAX_SMPP_LINK; i++)
	{
		src_ref[i]	= t+i;
		dst_ref[i]	= 0;
	}

	memset(opt_param, 0, sizeof(SMPP_OPTIONAL_PARAMETER) * SMPP_OPT_PARAM_NUM);
}

void smpp_rvMsgOverTCP()
{
	struct sockaddr_in	remote_addr;
	int flag=1, len,cmd_len, i, retcode, newsock;
	char temp_buf[4096];
	//FILE	*fp;
	
	for (i=0; i<MAX_SMPP_LINK; i++)
	{
		// tcp link no != physical smpp link no.
		if (Mysock.server_sock[i] > 0) {
			//printf("Mysock.server_sock[%d]=%d.\n", i, Mysock.server_sock[i]);
			len = recv(Mysock.server_sock[i], smpp_msg, sizeof(smpp_msg), 0);
			if (len > 0) {
//				printf("TCP link receive setup SMPP link.\n");
				if ((retcode = smpp_decode_setup(SMPP_TCP, i, 0, (SMPP_GENERAL *)smpp_msg, len)) != -1) {
//					printf("[smpp] tcp link %d find smpp link %d\n", i, retcode);
				}
			}
			else if(len == 0 )
			{	
				close(Mysock.server_sock[i]);
				Mysock.server_sock[i] = 0;
			}
		}
		
		// i = physical smpp link.
		if (Mysock.Sockets[i] > 0)
		{
/*			len = recv(Mysock.Sockets[i], smpp_msg, sizeof(smpp_msg), 0);
			if (len > 0)
			{
				printf("[TCP received packets]linkNo = %d, len = %d\n", i, len);
				retcode = smpp_decode_msg(i, (SMPP_GENERAL *)smpp_msg, len);
			}*/
			if(smpp_msg_buf_len[i] < 4)	//recv command_length in smpp msg
			{
				len = recv(Mysock.Sockets[i], smpp_msg_buf[i]+smpp_msg_buf_len[i], 4-smpp_msg_buf_len[i],MSG_NOSIGNAL|MSG_DONTWAIT);
				if (len == -1 && errno != EAGAIN)
				{
					sprintf(temp_buf,"SMPP receive 4 BYTE from tcp socket error:%s",strerror(errno));
					smpp_send_error(temp_buf);
					continue;
				}
				else if(len >0)
				{
					smpp_msg_buf_len[i] += len;
				}
			}
			if(smpp_msg_buf_len[i] >= 4)	 //recv remain of smpp msg
			{
				cmd_len = bcdtou32(smpp_msg_buf[i],4);
				if ( cmd_len > MAX_PACKET_SIZE )
				{
					recv(Mysock.Sockets[i], temp_buf, 4096,MSG_NOSIGNAL|MSG_DONTWAIT);
					sprintf(temp_buf,"SMPP MSG CMD_LEN Error,Clear TCP Socket Buffer.");
					smpp_send_error(temp_buf);
					smpp_msg_buf_len[i] = 0;
					continue;
				}
				if (smpp_msg_buf_len[i]<cmd_len)
				{
					len = recv(Mysock.Sockets[i], smpp_msg_buf[i]+smpp_msg_buf_len[i], cmd_len-smpp_msg_buf_len[i] ,MSG_NOSIGNAL|MSG_DONTWAIT);									
					if(len >0)
					{
						smpp_msg_buf_len[i] += len;
						if(smpp_msg_buf_len[i] >= cmd_len)
						{			
							//printf("[TCP received packets]linkNo = %d, len = %d\n", i, cmd_len);
							retcode = smpp_decode_msg(i, (SMPP_GENERAL *)smpp_msg_buf[i], cmd_len);																
							smpp_msg_buf_len[i] = 0;
						}
					}
				}
			}
			/*else if (len > 0)
			{
				cmd_len = bcdtou32(smpp_msg,4);
				if ( cmd_len > sizeof(smpp_msg) )
				{
					recv(Mysock.Sockets[i], temp_buf, 4096,MSG_NOSIGNAL|MSG_DONTWAIT);
					sprintf(temp_buf,"SMPP MSG CMD_LEN Error,Clear TCP Socket Buffer.");
					smpp_send_error(temp_buf);
					fp = fopen("smpp_log","a");
					if (fp != NULL)
					{
						fprintf(fp,"%s\n",temp_buf);
						fclose(fp);
					}
					continue;
				}
				else
				{
					len = recv(Mysock.Sockets[i], smpp_msg+4, cmd_len-4 ,MSG_NOSIGNAL|MSG_DONTWAIT);
					if (len == -1)
					{
						sprintf(temp_buf,"SMPP receive cmd_len(%d)-4 BYTE from tcp socket error:%s",cmd_len,strerror(errno));
						smpp_send_error(temp_buf);
						fp = fopen("smpp_log","a");
						if (fp != NULL)
						{
							fprintf(fp,"%s\n",temp_buf);
							fclose(fp);
						}
						continue;						
					}
					else 
					{
						printf("[TCP received packets]linkNo = %d, len = %d\n", i, cmd_len);
						retcode = smpp_decode_msg(i, (SMPP_GENERAL *)smpp_msg, cmd_len);						
					}
				}
			}*/
		}		
	}

	len = sizeof(remote_addr);
	bzero((char *)&remote_addr, len);
	newsock	= accept(Mysock.DaemonSock, (struct sockaddr *)&remote_addr, (socklen_t *)&len);
	if (newsock == -1)	return;
	ioctl(newsock, FIONBIO, &flag);
	for (i=0; i<MAX_SMPP_LINK; i++)
	{
		if (Mysock.server_sock[i] > 0) {
			//printf("Mysock.server_sock[%d] = %d > 0, CONTINUE.\n", i, Mysock.server_sock[i]);
			continue;			
		}
		else {
			Mysock.server_sock[i] = newsock;
			Mysock.remote_ip[i] = remote_addr.sin_addr.s_addr;
//			printf("link %d accept %d.\n", i, newsock);
			return;
		}
	}
	close(newsock);
	return;
}

//void smpp_rvMsgOverSCCP(BYTE sccp_usertype)
//{
//	int 		i, linkNo;
//	SCLC_MSG	sclcMsg;
//
//	if (sclc_receive(&sclcMsg, sccp_usertype) != FALSE) {
//		/*
//		if (sccp_usertype == SMPP_PPS_USERTYPE)
//			printf("receive to PPS sclc message.\n");
//		else if (sccp_usertype == SMPP_SMSC_USERTYPE)
//			printf("receive to SMSC sclc message.\n");
//		*/	
//		for (i=0; i<MAX_SMPP_LINK; i++) {
//			if (smpp_param[i].link_enable == 0) continue;
//			if (smpp_param[i].link_type == SMPP_TCP) continue;
//			if (sclcMsg.msg[0] == src_ref[i]) {
//				//printf("link %d, received message dst_ref=%d, src_def=%d\n", i, sclcMsg.msg[0], src_ref[i]);
//				dst_ref[i]	= sclcMsg.msg[1];
//				smpp_decode_msg(i, (SMPP_GENERAL *)(sclcMsg.msg+2), sclcMsg.msglen-2);
//				return;
//			}
//		}
//
//		if ((linkNo = smpp_decode_setup(SMPP_UDP, 0, sclcMsg.msg[1], (SMPP_GENERAL *)(sclcMsg.msg+2), sclcMsg.msglen-2)) != -1) {
////			printf("[smpp] udp link find smpp link %d\n", linkNo);
//			return;
//		}
//		
//		//reroute the message 
//		if ((sclcMsg.msg[0]&0x80) == 0x80)
//			smpp_send_error("[smpp] the message has reroute once.\r\n");
//		else {
//			sclcMsg.sls	= 0x80;
//			sclcMsg.msg[0]	|= 0x80;
//			smpp_send_ascout("[smpp] REROUTE smpp message.\r\n");
//			sclc_send(&sclcMsg);
//		}
//	}
//}

void smpp_rvMsgOverSCCP(BYTE sccp_usertype)
{
	int 		i, linkNo;
	SCLC_MSG	sclcMsg;

	if (sclc_receive(&sclcMsg, sccp_usertype) != FALSE) {
		/*
		if (sccp_usertype == SMPP_PPS_USERTYPE)
			printf("receive to PPS sclc message.\n");
		else if (sccp_usertype == SMPP_SMSC_USERTYPE)
			printf("receive to SMSC sclc message.\n");
		*/	
		if(sclcMsg.msg[0]==0)			
		{
			if ((linkNo = smpp_decode_setup(SMPP_UDP, 0, sclcMsg.msg[1], (SMPP_GENERAL *)(sclcMsg.msg+2), sclcMsg.msglen-2)) != -1) {
	//			printf("[smpp] udp link find smpp link %d\n", linkNo);
				return;
			}						
		}
		else
		{
			for (i=0; i<MAX_SMPP_LINK; i++) {
				if ((smpp_param[i].link_enable & 0x01) == 0) continue;
				if (smpp_param[i].link_type == SMPP_TCP) continue;
				if (sclcMsg.msg[0] == src_ref[i]) {
					//printf("link %d, received message dst_ref=%d, src_def=%d\n", i, sclcMsg.msg[0], src_ref[i]);
					dst_ref[i]	= sclcMsg.msg[1];
					smpp_decode_msg(i, (SMPP_GENERAL *)(sclcMsg.msg+2), sclcMsg.msglen-2);
					return;
				}
			}			
			//reroute the message 
			if ((sclcMsg.msg[0]&0x80) == 0x80)
				smpp_send_error("[smpp] the message has reroute once.\r\n");
			else {
				sclcMsg.sls	= 0x80;
				sclcMsg.msg[0]	|= 0x80;
				smpp_send_ascout("[smpp] REROUTE smpp message.\r\n");
				sclc_send(&sclcMsg);
			}			
		}
	}
}

int smpp_encode_msg(int linkNo, SMPP_MSG *pMsg, int event_id)
{
	int			tLen=16, offset=0, len, actlen, i, num;
	char		debugBuf[1024];
	WORD		us_valueLen;
	DWORD		optionalParamFlag;
	SCLC_MSG	sclcMsg;
	PDU_SUBMIT_SM			*pSubmitSM;
	PDU_SUBMIT_SM_RESP		*pSubmitSMResp;
	PDU_SUBMIT_MULTI		*pSubmitMulti;
	PDU_SUBMIT_MULTI_RESP	*pSubmitMultiResp;
	PDU_DELIVER_SM			*pDeliverSM;
	PDU_DELIVER_SM_RESP		*pDeliverSMResp;
	PDU_DATA_SM				*pDataSM;
	PDU_DATA_SM_RESP		*pDataSMResp;
	PDU_QUERY_SM			*pQuerySM;
	PDU_QUERY_SM_RESP		*pQuerySMResp;
	PDU_CANCEL_SM			*pCancelSM;
	PDU_CANCEL_SM_RESP		*pCancelSMResp;
	PDU_REPLACE_SM			*pReplaceSM;
	PDU_REPLACE_SM_RESP		*pReplaceSMResp;
	PDU_OUTBIND				*pOutbind;
	PDU_BIND				*pBind;
	PDU_BIND_RESP			*pBindResp;
	PDU_UNBIND				*pUnbind;
	PDU_GENERIC_NACK		*pGenericNack;

	char	comm_str[32];
	DWORD	command_id;
	
	command_id		= ntohl(pMsg->pdu.bind_transmitter.head.command_id);
	#ifdef SMPP_DEBUG
	if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
	{	
//		if(command_id!=ENQUIRE_LINK && command_id!=ENQUIRE_LINK_RESP)
		{
			smpp_command_id_to_string(comm_str, ntohl(pMsg->pdu.bind_transmitter.head.command_id));
			sprintf(debugBuf, "\nSMPP==>    %s\tlink: %d\n", comm_str, linkNo);
			smpp_send_ascout(debugBuf);
		}
	}
	#endif

	if (smpp_param[linkNo].link_type == SMPP_UDP)
	{
		offset	= 2;
		tLen	= tLen + offset;
		smpp_msg[0]	= dst_ref[linkNo];
		smpp_msg[1]	= src_ref[linkNo];
	}
	switch (event_id)
	{
	case SubmitSM:
		/* mandatory parameter. */
		pSubmitSM	= (PDU_SUBMIT_SM *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pSubmitSM, 16);
		len		= strlen(pSubmitSM->service_type);
		memcpy(smpp_msg+tLen, pSubmitSM->service_type, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pSubmitSM->source_addr_ton;
		*(smpp_msg+tLen++)	= pSubmitSM->source_addr_npi;
		len		= strlen(pSubmitSM->source_addr);
		memcpy(smpp_msg+tLen, pSubmitSM->source_addr, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pSubmitSM->dest_addr_ton;
		*(smpp_msg+tLen++)	= pSubmitSM->dest_addr_npi;
		len		= strlen(pSubmitSM->destination_addr);
		memcpy(smpp_msg+tLen, pSubmitSM->destination_addr, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pSubmitSM->esm_class;
		*(smpp_msg+tLen++)	= pSubmitSM->protocol_id;
		*(smpp_msg+tLen++)	= pSubmitSM->priority_flag;
		len		= strlen(pSubmitSM->schedule_delivery_time);
		if (len > 0)	{ len = 16; }
		memcpy(smpp_msg+tLen, pSubmitSM->schedule_delivery_time, len+1);
		tLen	= tLen+len+1;
		len		= strlen(pSubmitSM->validity_period);
		if (len > 0)	{ len = 16; }
		memcpy(smpp_msg+tLen, pSubmitSM->validity_period, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pSubmitSM->registered_delivery;
		*(smpp_msg+tLen++)	= pSubmitSM->replace_if_present_flag;
		*(smpp_msg+tLen++)	= pSubmitSM->data_coding;
		*(smpp_msg+tLen++)	= pSubmitSM->sm_default_msg_id;
//		len		= strlen(pSubmitSM->short_message);
		len		= pSubmitSM->sm_length;
		*(smpp_msg+tLen++)	= len;
		if (len > 0)
		{
			memcpy(smpp_msg+tLen, pSubmitSM->short_message, len);
			tLen	= tLen+len;
		}
		/* optional paramter */
		optionalParamFlag	= pMsg->optional_param_flag1;
		#ifdef SMPP_PRINT_SCREEN
//		printf("param_flag in SUBMIT SM = 0x%08x\n", optionalParamFlag);
		#endif /* endif ifdef SMPP_PRINT_SCREEN */
		if ((optionalParamFlag&0x0001) == 0x0001)
		{
			smpp_addTLV(smpp_msg+tLen, USER_MESSAGE_REFERENCE, 
				(BYTE *)&(pSubmitSM->user_message_reference), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0002) == 0x0002)
		{
			smpp_addTLV(smpp_msg+tLen, SOURCE_PORT, 
				(BYTE *)&(pSubmitSM->source_port), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0004) == 0x0004)
		{
			smpp_addTLV(smpp_msg+tLen, SOURCE_ADDR_SUBUNIT, 
				(BYTE *)&(pSubmitSM->source_addr_subunit), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0080) == 0x0080)
		{
			smpp_addTLV(smpp_msg+tLen, DESTINATION_PORT, 
				(BYTE *)&(pSubmitSM->destination_port), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0010) == 0x0010)
		{
			smpp_addTLV(smpp_msg+tLen, DEST_ADDR_SUBUNIT, 
				(BYTE *)&(pSubmitSM->dest_addr_subunit), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0020) == 0x0020)
		{
			smpp_addTLV(smpp_msg+tLen, SAR_MSG_REF_NUM, 
				(BYTE *)&(pSubmitSM->sar_msg_ref_num), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0040) == 0x0040)
		{
			smpp_addTLV(smpp_msg+tLen, SAR_TOTAL_SEGMENTS, 
				(BYTE *)&(pSubmitSM->sar_total_segments), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0080) == 0x0080)
		{
			smpp_addTLV(smpp_msg+tLen, SAR_SEGMENT_SEQNUM, 
				(BYTE *)&(pSubmitSM->sar_segment_seqnum), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0100) == 0x0100)
		{
			smpp_addTLV(smpp_msg+tLen, MORE_MESSAGES_TO_SEND, 
				(BYTE *)&(pSubmitSM->more_messages_to_send), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0200) == 0x0200)
		{
			smpp_addTLV(smpp_msg+tLen, PAYLOAD_TYPE, 
				(BYTE *)&(pSubmitSM->payload_type), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0400) == 0x0400)
		{
			us_valueLen	= strlen(pSubmitSM->message_payload);
			smpp_addTLV(smpp_msg+tLen, MESSAGE_PAYLOAD, 
				(BYTE *)&(pSubmitSM->message_payload), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x0800) == 0x0800)
		{
			smpp_addTLV(smpp_msg+tLen, PRIVACY_INDICATOR, 
				(BYTE *)&(pSubmitSM->privacy_indicator), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x1000) == 0x1000)
		{
			us_valueLen	= strlen(pSubmitSM->callback_num);
			smpp_addTLV(smpp_msg+tLen, CALLBACK_NUM, 
				(BYTE *)&(pSubmitSM->callback_num), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x2000) == 0x2000)
		{
			smpp_addTLV(smpp_msg+tLen, CALLBACK_NUM_PRES_IND, 
				(BYTE *)&(pSubmitSM->callback_num_pres_ind), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x4000) == 0x4000)
		{
			us_valueLen	= strlen(pSubmitSM->callback_num_atag);
			smpp_addTLV(smpp_msg+tLen, CALLBACK_NUM_ATAG, 
				(BYTE *)&(pSubmitSM->callback_num_atag), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x8000) == 0x8000)
		{
			us_valueLen	= strlen(pSubmitSM->source_subaddress);
			smpp_addTLV(smpp_msg+tLen, SOURCE_SUBADDRESS, 
				(BYTE *)&(pSubmitSM->source_subaddress), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x00010000) == 0x00010000)
		{
			us_valueLen	= strlen(pSubmitSM->dest_subaddress);
			smpp_addTLV(smpp_msg+tLen, DEST_SUBADDRESS, 
				(BYTE *)&(pSubmitSM->dest_subaddress), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x00020000) == 0x00020000)
		{
			smpp_addTLV(smpp_msg+tLen, USER_RESPONSE_CODE, 
				(BYTE *)&(pSubmitSM->user_response_code), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x00040000) == 0x00040000)
		{
			smpp_addTLV(smpp_msg+tLen, DISPLAY_TIME, 
				(BYTE *)&(pSubmitSM->display_time), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x00080000) == 0x00080000)
		{
			smpp_addTLV(smpp_msg+tLen, SMS_SIGNAL, 
				(BYTE *)&(pSubmitSM->sms_signal), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x00100000) == 0x00100000)
		{
			smpp_addTLV(smpp_msg+tLen, MS_VALIDITY, 
				(BYTE *)&(pSubmitSM->ms_validity), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x00200000) == 0x00200000)
		{
			smpp_addTLV(smpp_msg+tLen, MS_MSG_WAIT_FACILITIES, 
				(BYTE *)&(pSubmitSM->ms_msg_wait_facilities), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x00400000) == 0x00400000)
		{
			smpp_addTLV(smpp_msg+tLen, NUMBER_OF_MESSAGES, 
				(BYTE *)&(pSubmitSM->number_of_messages), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x00800000) == 0x00800000)
		{
			smpp_addTLV(smpp_msg+tLen, ALERT_ON_MESSAGE_DELIVERY, 
				(BYTE *)&(pSubmitSM->alert_on_message_delivery), 1);
			tLen	= tLen+4;
		}
		if ((optionalParamFlag&0x01000000) == 0x01000000)
		{
			smpp_addTLV(smpp_msg+tLen, LANGUAGE_INDICATOR, 
				(BYTE *)&(pSubmitSM->language_indicator), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x02000000) == 0x02000000)
		{
			smpp_addTLV(smpp_msg+tLen, ITS_REPLY_TYPE, 
				(BYTE *)&(pSubmitSM->its_reply_type), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x04000000) == 0x04000000)
		{
			smpp_addTLV(smpp_msg+tLen, ITS_SESSION_INFO, 
				(BYTE *)pSubmitSM->its_session_info, 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x08000000) == 0x08000000)
		{
			smpp_addTLV(smpp_msg+tLen, USSD_SERVICE_OP, 
				(BYTE *)&(pSubmitSM->ussd_service_op), 1);
			tLen	= tLen+5;
		}
		/* all the other param_flag values reserved. */
		/* command_length */
		pSubmitSM->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pSubmitSM->head.command_length, 4);
		break;
	case SubmitSMResp:
		pSubmitSMResp	= (PDU_SUBMIT_SM_RESP *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pSubmitSMResp, 16);
		len	= strlen(pSubmitSMResp->message_id);
		memcpy(smpp_msg+tLen, pSubmitSMResp->message_id, len+1);
		tLen	= tLen+len+1;
		pSubmitSMResp->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pSubmitSMResp->head.command_length, 4);
		break;
	case SubmitMulti:
		pSubmitMulti	= (PDU_SUBMIT_MULTI *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pSubmitMulti, 16);
		/* mandatory parameters. */
		len		= strlen(pSubmitMulti->service_type);
		memcpy(smpp_msg+tLen, pSubmitMulti->service_type, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pSubmitMulti->source_addr_ton;
		*(smpp_msg+tLen++)	= pSubmitMulti->source_addr_npi;
		len		= strlen(pSubmitMulti->source_addr);
		memcpy(smpp_msg+tLen, pSubmitMulti->source_addr, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pSubmitMulti->number_of_dests;
		for (i=0; i<pSubmitMulti->number_of_dests; i++)
		{
			switch(pSubmitMulti->dest_address[i].dest_flag)
			{
			case 1:	//SME address
				*(smpp_msg+tLen++)	= pSubmitMulti->dest_address[i].dest_addr.sme_dest_address.dest_addr_ton;
				*(smpp_msg+tLen++)	= pSubmitMulti->dest_address[i].dest_addr.sme_dest_address.dest_addr_npi;
				len = strlen(pSubmitMulti->dest_address[i].dest_addr.sme_dest_address.destination_addr);
				memcpy(smpp_msg+tLen, 
					pSubmitMulti->dest_address[i].dest_addr.sme_dest_address.destination_addr, len+1);
				tLen	= tLen+len+1;
				break;
			case 2: //Distribution List Name
				len = strlen(pSubmitMulti->dest_address[i].dest_addr.dl_name.dl_name);
				memcpy(smpp_msg+tLen, 
					pSubmitMulti->dest_address[i].dest_addr.dl_name.dl_name, len+1);
				tLen	= tLen+len+1;
				break;
			default:
				break;
			}
		}
		*(smpp_msg+tLen++)	= pSubmitMulti->esm_class;
		*(smpp_msg+tLen++)	= pSubmitMulti->protocol_id;
		*(smpp_msg+tLen++)	= pSubmitMulti->priority_flag;
		len		= strlen(pSubmitMulti->schedule_delivery_time);
		if (len > 0)	{ len = 16; }
		memcpy(smpp_msg+tLen, pSubmitMulti->schedule_delivery_time, len+1);
		tLen	= tLen+len+1;
		len		= strlen(pSubmitMulti->validity_period);
		if (len > 0)	{ len = 16; }
		memcpy(smpp_msg+tLen, pSubmitMulti->validity_period, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pSubmitMulti->registered_delivery;
		*(smpp_msg+tLen++)	= pSubmitMulti->replace_if_present_flag;
		*(smpp_msg+tLen++)	= pSubmitMulti->data_coding;
		*(smpp_msg+tLen++)	= pSubmitMulti->sm_default_msg_id;
		*(smpp_msg+tLen++)	= pSubmitMulti->sm_length;
//		len		= strlen(pSubmitMulti->short_message);
		len		= pSubmitMulti->sm_length;
		memcpy(smpp_msg+tLen, pSubmitMulti->short_message, len+1);
		tLen	= tLen+len+1;
		/* optional parameters. */
		optionalParamFlag	= pMsg->optional_param_flag1;
		#ifdef SMPP_PRINT_SCREEN
//		printf("param_flag in SUBMIT MULTI = 0x%08x\n", optionalParamFlag);
		#endif /* endif ifdef SMPP_PRINT_SCREEN */
		if ((optionalParamFlag&0x0001) == 0x0001)
		{
			smpp_addTLV(smpp_msg+tLen, USER_MESSAGE_REFERENCE, 
				(BYTE *)&(pSubmitMulti->user_message_reference), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0002) == 0x0002)
		{
			smpp_addTLV(smpp_msg+tLen, SOURCE_PORT, 
				(BYTE *)&(pSubmitMulti->source_port), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0004) == 0x0004)
		{
			smpp_addTLV(smpp_msg+tLen, SOURCE_ADDR_SUBUNIT, 
				(BYTE *)&(pSubmitMulti->source_addr_subunit), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0080) == 0x0080)
		{
			smpp_addTLV(smpp_msg+tLen, DESTINATION_PORT, 
				(BYTE *)&(pSubmitMulti->destination_port), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0010) == 0x0010)
		{
			smpp_addTLV(smpp_msg+tLen, DEST_ADDR_SUBUNIT, 
				(BYTE *)&(pSubmitMulti->dest_addr_subunit), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0020) == 0x0020)
		{
			smpp_addTLV(smpp_msg+tLen, SAR_MSG_REF_NUM, 
				(BYTE *)&(pSubmitMulti->sar_msg_ref_num), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0040) == 0x0040)
		{
			smpp_addTLV(smpp_msg+tLen, SAR_TOTAL_SEGMENTS, 
				(BYTE *)&(pSubmitMulti->sar_total_segments), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0080) == 0x0080)
		{
			smpp_addTLV(smpp_msg+tLen, SAR_SEGMENT_SEQNUM, 
				(BYTE *)&(pSubmitMulti->sar_segment_seqnum), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0100) == 0x0100)
		{
			smpp_addTLV(smpp_msg+tLen, PAYLOAD_TYPE, 
				(BYTE *)&(pSubmitMulti->payload_type), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0200) == 0x0200)
		{
			us_valueLen	= strlen(pSubmitMulti->message_payload);
			smpp_addTLV(smpp_msg+tLen, MESSAGE_PAYLOAD, 
				(BYTE *)&(pSubmitMulti->message_payload), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x0400) == 0x0400)
		{
			smpp_addTLV(smpp_msg+tLen, PRIVACY_INDICATOR, 
				(BYTE *)&(pSubmitMulti->privacy_indicator), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0800) == 0x0800)
		{
			us_valueLen	= strlen(pSubmitMulti->callback_num);
			smpp_addTLV(smpp_msg+tLen, CALLBACK_NUM, 
				(BYTE *)&(pSubmitMulti->callback_num), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x1000) == 0x1000)
		{
			smpp_addTLV(smpp_msg+tLen, CALLBACK_NUM_PRES_IND, 
				(BYTE *)&(pSubmitMulti->callback_num_pres_ind), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x2000) == 0x2000)
		{
			us_valueLen	= strlen(pSubmitMulti->callback_num_atag);
			smpp_addTLV(smpp_msg+tLen, CALLBACK_NUM_ATAG, 
				(BYTE *)&(pSubmitMulti->callback_num_atag), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x4000) == 0x4000)
		{
			us_valueLen	= strlen(pSubmitMulti->source_subaddress);
			smpp_addTLV(smpp_msg+tLen, SOURCE_SUBADDRESS, 
				(BYTE *)&(pSubmitMulti->source_subaddress), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x8000) == 0x8000)
		{
			us_valueLen	= strlen(pSubmitMulti->dest_subaddress);
			smpp_addTLV(smpp_msg+tLen, DEST_SUBADDRESS, 
				(BYTE *)&(pSubmitMulti->dest_subaddress), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x00010000) == 0x00010000)
		{
			smpp_addTLV(smpp_msg+tLen, DISPLAY_TIME, 
				(BYTE *)&(pSubmitMulti->display_time), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x00020000) == 0x00020000)
		{
			smpp_addTLV(smpp_msg+tLen, SMS_SIGNAL, 
				(BYTE *)&(pSubmitMulti->sms_signal), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x00040000) == 0x00040000)
		{
			smpp_addTLV(smpp_msg+tLen, MS_VALIDITY, 
				(BYTE *)&(pSubmitMulti->ms_validity), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x00080000) == 0x00080000)
		{
			smpp_addTLV(smpp_msg+tLen, MS_MSG_WAIT_FACILITIES, 
				(BYTE *)&(pSubmitMulti->ms_msg_wait_facilities), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x00100000) == 0x00100000)
		{
			smpp_addTLV(smpp_msg+tLen, ALERT_ON_MESSAGE_DELIVERY, 
				(BYTE *)&(pSubmitMulti->alert_on_message_delivery), 1);
			tLen	= tLen+4;
		}
		if ((optionalParamFlag&0x00200000) == 0x00200000)
		{
			smpp_addTLV(smpp_msg+tLen, LANGUAGE_INDICATOR, 
				(BYTE *)&(pSubmitMulti->language_indicator), 1);
			tLen	= tLen+5;
		}
		/* all the other param_flag values reserved. */
		/* command_length */
		pSubmitMulti->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pSubmitMulti->head.command_length, 4);
		break;
	case SubmitMultiResp:
		pSubmitMultiResp	= (PDU_SUBMIT_MULTI_RESP *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pSubmitMultiResp, 16);
		/* body	*/
		len	= strlen(pSubmitMultiResp->message_id);
		memcpy(smpp_msg+tLen, pSubmitMultiResp->message_id, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pSubmitMultiResp->no_unsuccess;
		num	= pSubmitMultiResp->no_unsuccess;
		for (i=0; i<num; i++)
		{
			*(smpp_msg+tLen++)	= pSubmitMultiResp->unsuccess_sme[i].dest_addr_ton;
			*(smpp_msg+tLen++)	= pSubmitMultiResp->unsuccess_sme[i].dest_addr_npi;
			len	= strlen(pSubmitMultiResp->unsuccess_sme[i].destination_addr);
			memcpy(smpp_msg+tLen, pSubmitMultiResp->unsuccess_sme[i].destination_addr, len+1);
			tLen	= tLen+len+1;
			memcpy(smpp_msg+tLen, &(pSubmitMultiResp->unsuccess_sme[i].error_status_code), 4);
			tLen	= tLen+4;
		}
		/* command_length */
		pSubmitMultiResp->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pSubmitMultiResp->head.command_length, 4);
		break;
	case DeliverSM:
		pDeliverSM	= (PDU_DELIVER_SM *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pDeliverSM, 16);
		len		= strlen(pDeliverSM->service_type);
		memcpy(smpp_msg+tLen, pDeliverSM->service_type, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pDeliverSM->source_addr_ton;
		*(smpp_msg+tLen++)	= pDeliverSM->source_addr_npi;
		len		= strlen(pDeliverSM->source_addr);
		memcpy(smpp_msg+tLen, pDeliverSM->source_addr, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pDeliverSM->dest_addr_ton;
		*(smpp_msg+tLen++)	= pDeliverSM->dest_addr_npi;
		len		= strlen(pDeliverSM->destination_addr);
		memcpy(smpp_msg+tLen, pDeliverSM->destination_addr, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pDeliverSM->esm_class;
		*(smpp_msg+tLen++)	= pDeliverSM->protocol_id;
		*(smpp_msg+tLen++)	= pDeliverSM->priority_flag;
		*(smpp_msg+tLen++)	= pDeliverSM->schedule_delivery_time;
		*(smpp_msg+tLen++)	= pDeliverSM->validity_period;
		*(smpp_msg+tLen++)	= pDeliverSM->registered_delivery;
		*(smpp_msg+tLen++)	= pDeliverSM->replace_if_present_flag;
		*(smpp_msg+tLen++)	= pDeliverSM->data_coding;
		*(smpp_msg+tLen++)	= pDeliverSM->sm_default_msg_id;
//		len		= strlen(pDeliverSM->short_message);
		len		= pDeliverSM->sm_length;
		*(smpp_msg+tLen++)	= len;
		memcpy(smpp_msg+tLen, pDeliverSM->short_message, len);
		tLen	= tLen+len;
		/* optional parameters */
		optionalParamFlag	= pMsg->optional_param_flag1;
		#ifdef SMPP_PRINT_SCREEN
//		printf("param_flag in DELIVER SM = 0x%08x\n", optionalParamFlag);
		#endif /* endif ifdef SMPP_PRINT_SCREEN */
		if ((optionalParamFlag&0x0001) == 0x0001)
		{
			smpp_addTLV(smpp_msg+tLen, USER_MESSAGE_REFERENCE, 
				(BYTE *)&(pDeliverSM->user_message_reference), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0002) == 0x0002)
		{
			smpp_addTLV(smpp_msg+tLen, SOURCE_PORT, 
				(BYTE *)&(pDeliverSM->source_port), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0004) == 0x0004)
		{
			smpp_addTLV(smpp_msg+tLen, DESTINATION_PORT, 
				(BYTE *)&(pDeliverSM->destination_port), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0080) == 0x0080)
		{
			smpp_addTLV(smpp_msg+tLen, SAR_MSG_REF_NUM, 
				(BYTE *)&(pDeliverSM->sar_msg_ref_num), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0010) == 0x0010)
		{
			smpp_addTLV(smpp_msg+tLen, SAR_TOTAL_SEGMENTS, 
				(BYTE *)&(pDeliverSM->sar_total_segments), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0020) == 0x0020)
		{
			smpp_addTLV(smpp_msg+tLen, SAR_SEGMENT_SEQNUM, 
				(BYTE *)&(pDeliverSM->sar_segment_seqnum), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0040) == 0x0040)
		{
			smpp_addTLV(smpp_msg+tLen, USER_RESPONSE_CODE, 
				(BYTE *)&(pDeliverSM->user_response_code), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0080) == 0x0080)
		{
			smpp_addTLV(smpp_msg+tLen, PRIVACY_INDICATOR, 
				(BYTE *)&(pDeliverSM->privacy_indicator), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0100) == 0x0100)
		{
			smpp_addTLV(smpp_msg+tLen, PAYLOAD_TYPE, 
				(BYTE *)&(pDeliverSM->payload_type), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0200) == 0x0200)		{
			us_valueLen	= strlen(pDeliverSM->message_payload);
			smpp_addTLV(smpp_msg+tLen, MESSAGE_PAYLOAD, 
				(BYTE *)&(pDeliverSM->message_payload), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x0400) == 0x0400)
		{
			us_valueLen	= strlen(pDeliverSM->callback_num);
			smpp_addTLV(smpp_msg+tLen, CALLBACK_NUM, 
				(BYTE *)&(pDeliverSM->callback_num), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x0800) == 0x0800)
		{
			us_valueLen	= strlen(pDeliverSM->source_subaddress);
			smpp_addTLV(smpp_msg+tLen, SOURCE_SUBADDRESS, 
				(BYTE *)&(pDeliverSM->source_subaddress), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x1000) == 0x1000)
		{
			us_valueLen	= strlen(pDeliverSM->dest_subaddress);
			smpp_addTLV(smpp_msg+tLen, DEST_SUBADDRESS, 
				(BYTE *)&(pDeliverSM->dest_subaddress), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x2000) == 0x2000)
		{
			smpp_addTLV(smpp_msg+tLen, LANGUAGE_INDICATOR, 
				(BYTE *)&(pDeliverSM->language_indicator), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x4000) == 0x4000)
		{
			smpp_addTLV(smpp_msg+tLen, ITS_SESSION_INFO, 
				(BYTE *)pDeliverSM->its_session_info, 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x8000) == 0x8000)
		{
			us_valueLen	= strlen(pDeliverSM->network_error_code);
			smpp_addTLV(smpp_msg+tLen, NETWORK_ERROR_CODE, 
				(BYTE *)&(pDeliverSM->network_error_code), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x00010000) == 0x00010000)
		{
			smpp_addTLV(smpp_msg+tLen, MESSAGE_STATE, 
				(BYTE *)&(pDeliverSM->message_state), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x00020000) == 0x00020000)
		{
			us_valueLen	= strlen(pDeliverSM->receipted_message_id);
			smpp_addTLV(smpp_msg+tLen, RECEIPTED_MESSAGE_ID, 
				(BYTE *)&(pDeliverSM->receipted_message_id), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x00040000) == 0x00040000)
		{
			smpp_addTLV(smpp_msg+tLen, USSD_SERVICE_OP, 
				(BYTE *)&(pDeliverSM->ussd_service_op), 1);
			tLen	= tLen+5;
		}
		/* all the other param_flag values reserved. */
		/* command_length */
		pDeliverSM->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pDeliverSM->head.command_length, 4);
		break;
	case DeliverSMResp:
		pDeliverSMResp	= (PDU_DELIVER_SM_RESP *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pDeliverSMResp, 16);
		*(smpp_msg+tLen++)	= pDeliverSMResp->message_id;
		pDeliverSMResp->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pDeliverSMResp->head.command_length, 4);
		break;
	case DataSM:
		pDataSM	= (PDU_DATA_SM *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pDataSM, 16);
		/* mandatory parameter. */
		len		= strlen(pDataSM->service_type);
		memcpy(smpp_msg+tLen, pDataSM->service_type, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pDataSM->source_addr_ton;
		*(smpp_msg+tLen++)	= pDataSM->source_addr_npi;
		len		= strlen(pDataSM->source_addr);
		memcpy(smpp_msg+tLen, pDataSM->source_addr, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pDataSM->dest_addr_ton;
		*(smpp_msg+tLen++)	= pDataSM->dest_addr_npi;
		len		= strlen(pDataSM->destination_addr);
		memcpy(smpp_msg+tLen, pDataSM->destination_addr, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pDataSM->esm_class;
		*(smpp_msg+tLen++)	= pDataSM->registered_delivery;
		*(smpp_msg+tLen++)	= pDataSM->data_coding;
		/* Optional parameter */
		optionalParamFlag	= pMsg->optional_param_flag1;
		#ifdef SMPP_PRINT_SCREEN
//		printf("optional_param_flag1 in DATA SM = 0x%08x\n", optionalParamFlag);
		#endif /* endif ifdef SMPP_PRINT_SCREEN */
		if ((optionalParamFlag&0x0001) == 0x0001)
		{
			smpp_addTLV(smpp_msg+tLen, SOURCE_PORT, 
				(BYTE *)&(pDataSM->source_port), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0002) == 0x0002)
		{
			smpp_addTLV(smpp_msg+tLen, SOURCE_ADDR_SUBUNIT, 
				(BYTE *)&(pDataSM->source_addr_subunit), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0004) == 0x0004)
		{
			smpp_addTLV(smpp_msg+tLen, SOURCE_NETWORK_TYPE, 
				(BYTE *)&(pDataSM->source_network_type), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0080) == 0x0080)
		{
			smpp_addTLV(smpp_msg+tLen, SOURCE_BEARER_TYPE, 
				(BYTE *)&(pDataSM->source_bearer_type), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0010) == 0x0010)
		{
			smpp_addTLV(smpp_msg+tLen, SOURCE_TELEMATICS_ID, 
				(BYTE *)&(pDataSM->source_telematics_id), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0020) == 0x0020)
		{
			smpp_addTLV(smpp_msg+tLen, DESTINATION_PORT, 
				(BYTE *)&(pDataSM->destination_port), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0040) == 0x0040)
		{
			smpp_addTLV(smpp_msg+tLen, DEST_ADDR_SUBUNIT, 
				(BYTE *)&(pDataSM->dest_addr_subunit), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0080) == 0x0080)
		{
			smpp_addTLV(smpp_msg+tLen, DEST_NETWORK_TYPE, 
				(BYTE *)&(pDataSM->dest_network_type), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0100) == 0x0100)
		{
			smpp_addTLV(smpp_msg+tLen, DEST_BEARER_TYPE, 
				(BYTE *)&(pDataSM->dest_bearer_type), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0200) == 0x0200)
		{
			smpp_addTLV(smpp_msg+tLen, DEST_TELEMATICS_ID, 
				(BYTE *)&(pDataSM->dest_telematics_id), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0400) == 0x0400)
		{
			smpp_addTLV(smpp_msg+tLen, SAR_MSG_REF_NUM, 
				(BYTE *)&(pDataSM->sar_msg_ref_num), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x0800) == 0x0800)
		{
			smpp_addTLV(smpp_msg+tLen, SAR_TOTAL_SEGMENTS, 
				(BYTE *)&(pDataSM->sar_total_segments), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x1000) == 0x1000)
		{
			smpp_addTLV(smpp_msg+tLen, SAR_SEGMENT_SEQNUM, 
				(BYTE *)&(pDataSM->sar_segment_seqnum), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x2000) == 0x2000)
		{
			smpp_addTLV(smpp_msg+tLen, MORE_MESSAGES_TO_SEND, 
				(BYTE *)&(pDataSM->more_messages_to_send), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x4000) == 0x4000)
		{
			smpp_addTLV(smpp_msg+tLen, QOS_TIME_TO_LIVE, 
				(BYTE *)&(pDataSM->qos_time_to_live), 4);
			tLen	= tLen+8;
		}
		if ((optionalParamFlag&0x8000) == 0x8000)
		{
			smpp_addTLV(smpp_msg+tLen, PAYLOAD_TYPE, 
				(BYTE *)&(pDataSM->payload_type), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x00010000) == 0x00010000)
		{
			us_valueLen	= strlen(pDataSM->message_payload);
			smpp_addTLV(smpp_msg+tLen, MESSAGE_PAYLOAD, 
				(BYTE *)&(pDataSM->message_payload), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x00020000) == 0x00020000)
		{
			smpp_addTLV(smpp_msg+tLen, SET_DPF, 
				(BYTE *)&(pDataSM->set_dpf), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x00040000) == 0x00040000)
		{
			us_valueLen	= strlen(pDataSM->receipted_message_id);
			smpp_addTLV(smpp_msg+tLen, RECEIPTED_MESSAGE_ID, 
				(BYTE *)&(pDataSM->receipted_message_id), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x00080000) == 0x00080000)
		{
			smpp_addTLV(smpp_msg+tLen, MESSAGE_STATE, 
				(BYTE *)&(pDataSM->message_state), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x00100000) == 0x00100000)
		{
			smpp_addTLV(smpp_msg+tLen, NETWORK_ERROR_CODE, 
				(BYTE *)&(pDataSM->network_error_code), 3);
			tLen	= tLen+7;
		}
		if ((optionalParamFlag&0x00200000) == 0x00200000)
		{
			smpp_addTLV(smpp_msg+tLen, USER_MESSAGE_REFERENCE, 
				(BYTE *)&(pDataSM->user_message_reference), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x00400000) == 0x00400000)
		{
			smpp_addTLV(smpp_msg+tLen, PRIVACY_INDICATOR, 
				(BYTE *)&(pDataSM->privacy_indicator), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x00800000) == 0x00800000)
		{
			us_valueLen	= strlen(pDataSM->callback_num);
			smpp_addTLV(smpp_msg+tLen, CALLBACK_NUM, 
				(BYTE *)&(pDataSM->callback_num), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x01000000) == 0x01000000)
		{
			smpp_addTLV(smpp_msg+tLen, CALLBACK_NUM_PRES_IND, 
				(BYTE *)&(pDataSM->callback_num_pres_ind), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x02000000) == 0x02000000)
		{
			us_valueLen	= strlen(pDataSM->callback_num_atag);
			smpp_addTLV(smpp_msg+tLen, CALLBACK_NUM_ATAG, 
				(BYTE *)&(pDataSM->callback_num_atag), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x04000000) == 0x04000000)
		{
			us_valueLen	= strlen(pDataSM->source_subaddress);
			smpp_addTLV(smpp_msg+tLen, SOURCE_SUBADDRESS, 
				(BYTE *)&(pDataSM->source_subaddress), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x08000000) == 0x08000000)
		{
			us_valueLen	= strlen(pDataSM->dest_subaddress);
//			printf("dest subaddress len = %d\n", us_valueLen);
			smpp_addTLV(smpp_msg+tLen, DEST_SUBADDRESS, 
				(BYTE *)&(pDataSM->dest_subaddress), us_valueLen);
			tLen	= tLen+4+us_valueLen;
		}
		if ((optionalParamFlag&0x10000000) == 0x10000000)
		{
			smpp_addTLV(smpp_msg+tLen, USER_RESPONSE_CODE, 
				(BYTE *)&(pDataSM->user_response_code), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x20000000) == 0x20000000)
		{
			smpp_addTLV(smpp_msg+tLen, DISPLAY_TIME, 
				(BYTE *)&(pDataSM->display_time), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x40000000) == 0x40000000)
		{
			smpp_addTLV(smpp_msg+tLen, SMS_SIGNAL, 
				(BYTE *)&(pDataSM->sms_signal), 2);
			tLen	= tLen+6;
		}
		if ((optionalParamFlag&0x80000000) == 0x80000000)
		{
			smpp_addTLV(smpp_msg+tLen, MS_VALIDITY, 
				(BYTE *)&(pDataSM->ms_validity), 1);
			tLen	= tLen+5;
		}
		optionalParamFlag	= pMsg->optional_param_flag2;
		#ifdef SMPP_PRINT_SCREEN
//		printf("optional_param_flag2 in DATA SM = 0x%08x\n", optionalParamFlag);
		#endif /* endif ifdef SMPP_PRINT_SCREEN */
		if ((optionalParamFlag&0x0001) == 0x0001)
		{
			smpp_addTLV(smpp_msg+tLen, MS_MSG_WAIT_FACILITIES, 
				(BYTE *)&(pDataSM->ms_msg_wait_facilities), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0002) == 0x0002)
		{
			smpp_addTLV(smpp_msg+tLen, NUMBER_OF_MESSAGES, 
				(BYTE *)&(pDataSM->number_of_messages), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0004) == 0x0004)
		{
			smpp_addTLV(smpp_msg+tLen, ALERT_ON_MESSAGE_DELIVERY, 
				(BYTE *)&(pDataSM->alert_on_message_delivery), 1);
			tLen	= tLen+4;
		}
		if ((optionalParamFlag&0x0008) == 0x0008)
		{
			smpp_addTLV(smpp_msg+tLen, LANGUAGE_INDICATOR, 
				(BYTE *)&(pDataSM->language_indicator), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0010) == 0x0010)
		{
			smpp_addTLV(smpp_msg+tLen, ITS_REPLY_TYPE, 
				(BYTE *)&(pDataSM->its_reply_type), 1);
			tLen	= tLen+5;
		}
		if ((optionalParamFlag&0x0020) == 0x0020)
		{
			smpp_addTLV(smpp_msg+tLen, ITS_SESSION_INFO, 
				(BYTE *)pDataSM->its_session_info, 2);
			tLen	= tLen+6;
		}
		/* all the other param_flag values reserved. */
		/* command_length */
		pDataSM->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pDataSM->head.command_length, 4);
		break;
	case DataSMResp:
		pDataSMResp	= (PDU_DATA_SM_RESP *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pDataSMResp, 16);
		len	= strlen(pDataSMResp->message_id);
		memcpy(smpp_msg+tLen, pDataSMResp->message_id, len+1);
		tLen	= tLen+len+1;
		pDataSMResp->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pDataSMResp->head.command_length, 4);
		break;
	case QuerySM:
		pQuerySM	= (PDU_QUERY_SM *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pQuerySM, 16);
		/* mandatory parameter. */
		len		= strlen(pQuerySM->message_id);
		memcpy(smpp_msg+tLen, pQuerySM->message_id, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pQuerySM->source_addr_ton;
		*(smpp_msg+tLen++)	= pQuerySM->source_addr_npi;
		len		= strlen(pQuerySM->source_addr);
		memcpy(smpp_msg+tLen, pQuerySM->source_addr, len+1);
		tLen	= tLen+len+1;
		/* command_length */
		pQuerySM->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pQuerySM->head.command_length, 4);
		break;
	case QuerySMResp:
		pQuerySMResp	= (PDU_QUERY_SM_RESP *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pQuerySMResp, 16);
		/* mandatory parameter. */
		len		= strlen(pQuerySMResp->message_id);
		memcpy(smpp_msg+tLen, pQuerySMResp->message_id, len+1);
		tLen	= tLen+len+1;
		len		= strlen(pQuerySMResp->final_date);
		if (len > 0)	{ len = 16;}
		memcpy(smpp_msg+tLen, pQuerySMResp->final_date, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pQuerySMResp->message_state;
		*(smpp_msg+tLen++)	= pQuerySMResp->error_code;
		/* command_length */
		pQuerySMResp->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pQuerySMResp->head.command_length, 4);
		break;
	case CancelSM:
		pCancelSM	= (PDU_CANCEL_SM *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pCancelSM, 16);
		/* mandatory parameter. */
		len		= strlen(pCancelSM->service_type);
		memcpy(smpp_msg+tLen, pCancelSM->service_type, len+1);
		tLen	= tLen+len+1;
		len		= strlen(pCancelSM->message_id);
		memcpy(smpp_msg+tLen, pCancelSM->message_id, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pCancelSM->source_addr_ton;
		*(smpp_msg+tLen++)	= pCancelSM->source_addr_npi;
		len		= strlen(pCancelSM->source_addr);
		memcpy(smpp_msg+tLen, pCancelSM->source_addr, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pCancelSM->dest_addr_ton;
		*(smpp_msg+tLen++)	= pCancelSM->dest_addr_npi;
		len		= strlen(pCancelSM->destination_addr);
		memcpy(smpp_msg+tLen, pCancelSM->destination_addr, len+1);
		tLen	= tLen+len+1;
		/* command_length */
		pCancelSM->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pCancelSM->head.command_length, 4);
		break;
	case CancelSMResp:
		pCancelSMResp	= (PDU_CANCEL_SM_RESP *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pCancelSMResp, 16);
		pCancelSMResp->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pCancelSMResp->head.command_length, 4);
		break;
	case ReplaceSM:
		pReplaceSM	= (PDU_REPLACE_SM *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pReplaceSM, 16);
		/* mandatory parameter. */
		len		= strlen(pReplaceSM->message_id);
		memcpy(smpp_msg+tLen, pReplaceSM->message_id, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pReplaceSM->source_addr_ton;
		*(smpp_msg+tLen++)	= pReplaceSM->source_addr_npi;
		len		= strlen(pReplaceSM->source_addr);
		memcpy(smpp_msg+tLen, pReplaceSM->source_addr, len+1);
		tLen	= tLen+len+1;
		len		= strlen(pReplaceSM->schedule_delivery_time);
		memcpy(smpp_msg+tLen, pReplaceSM->schedule_delivery_time, len+1);
		tLen	= tLen+len+1;
		len		= strlen(pReplaceSM->validity_period);
		memcpy(smpp_msg+tLen, pReplaceSM->validity_period, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pReplaceSM->registered_delivery;
		*(smpp_msg+tLen++)	= pReplaceSM->sm_default_msg_id;
		*(smpp_msg+tLen++)	= pReplaceSM->sm_length;
//		len		= strlen(pReplaceSM->short_message);
		len		= pReplaceSM->sm_length;
		memcpy(smpp_msg+tLen, pReplaceSM->short_message, len+1);
		tLen	= tLen+len+1;
		/* command_length */
		pReplaceSM->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pReplaceSM->head.command_length, 4);
		break;
	case ReplaceSMResp:
		pReplaceSMResp	= (PDU_REPLACE_SM_RESP *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pReplaceSMResp, 16);
		pReplaceSMResp->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pReplaceSMResp->head.command_length, 4);
		break;
	case Outbind:
		pOutbind	= (PDU_OUTBIND *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pOutbind, 16);
		len	= strlen(pOutbind->system_id);
		memcpy(smpp_msg+tLen, pOutbind->system_id, len+1);
		tLen	= tLen+len+1;
		len	= strlen(pOutbind->password);
		memcpy(smpp_msg+tLen, pOutbind->password, len+1);
		tLen	= tLen+len+1;
		pOutbind->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pOutbind->head.command_length, 4);
		break;
	case BindTransmitter:
	case BindReceiver:
	case BindTransceiver:
		pBind	= (PDU_BIND *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pBind, 16);
		len	= strlen(pBind->system_id);
		memcpy(smpp_msg+tLen, pBind->system_id, len+1);
		tLen	= tLen+len+1;
		len	= strlen(pBind->password);
		memcpy(smpp_msg+tLen, pBind->password, len+1);
		tLen	= tLen+len+1;
		len	= strlen(pBind->system_type);
		memcpy(smpp_msg+tLen, pBind->system_type, len+1);
		tLen	= tLen+len+1;
		*(smpp_msg+tLen++)	= pBind->interface_version;
		*(smpp_msg+tLen++)	= pBind->addr_ton;
		*(smpp_msg+tLen++)	= pBind->addr_npi;
		len	= strlen(pBind->address_range);
		memcpy(smpp_msg+tLen, pBind->address_range, len+1);
		tLen	= tLen+len+1;
		pBind->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pBind->head.command_length, 4);
		break;
	case BindTransmitterResp:
	case BindReceiverResp:
	case BindTransceiverResp:
		pBindResp	= (PDU_BIND_RESP *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pBindResp, 16);

		len	= strlen(pBindResp->system_id);
		memcpy(smpp_msg+tLen, pBindResp->system_id, len+1);
		tLen	= tLen+len+1;
		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_send_ascout("[Mandatory Parameters]\n");
			sprintf(debugBuf, "system_id: %s\n", pBindResp->system_id);
			smpp_send_ascout(debugBuf);
		}
		#endif

		/* sc_interface_version */
		smpp_addTLV(smpp_msg+tLen, SC_INTERFACE_VERSION, 
			&pBindResp->sc_interface_version, 1);
		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_send_ascout("[Optional Parameters]\n");
			sprintf(debugBuf, "sc_interface_version: 0x%02X\n", pBindResp->sc_interface_version);
			smpp_send_ascout(debugBuf);
		}
		#endif

		tLen	= tLen + 5;
		pBindResp->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pBindResp->head.command_length, 4);
		break;
	case Unbind:
	case UnbindResp:
	case EnquireLink:
	case EnquireLinkResp:
		pUnbind	= (PDU_UNBIND *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pUnbind, 16);
		pUnbind->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pUnbind->head.command_length, 4);
		break;
	case UnknownCommandID:
		pGenericNack	= (PDU_GENERIC_NACK *)&pMsg->pdu;
		memcpy(smpp_msg+offset, pGenericNack, 16);
		pGenericNack->head.command_length	= htonl(tLen-offset);
		memcpy(smpp_msg+offset, &pGenericNack->head.command_length, 4);
		break;
	default:
		break;
	}
	
	#ifdef SMPP_DEBUG
	if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
	{
		smpp_send_ascout("ENCODE:\n");
		smpp_display_hex_msg((BYTE*) smpp_msg+offset, tLen);
	}
	#endif

	if (smpp_param[linkNo].link_type == 0)	//send message over SCCP
	{
//		printf("link %d send sccp message. dst_ref=%d, src_ref=%d\n", linkNo, smpp_msg[0], smpp_msg[1]);
		memset(&sclcMsg,0,sizeof(sclcMsg));
		smpp_setSccpAddr(linkNo, &sclcMsg.src_addr, &sclcMsg.dst_addr);
		sclcMsg.msglen	= tLen;
		memcpy(sclcMsg.msg, smpp_msg, tLen);
		sclcMsg.sls = smpp_system_no;
		//sclcMsg.sls += 1;
		//sclcMsg.sls &= 0x0f;
		
		sclc_send(&sclcMsg);
	}
	else if (smpp_param[linkNo].link_type == 1) //send message over TCP
	{
		if (Mysock.Sockets[linkNo] < 0)
		{
//			printf("[FAIL]socket %d number = %d\n", linkNo, Mysock.Sockets[linkNo]);
			return (-1);
		}
		if ((actlen = send(Mysock.Sockets[linkNo], smpp_msg, tLen, MSG_NOSIGNAL)) < 0)
		{
			smpp_state[linkNo] = SUSPEND;//ch
			sprintf(debugBuf, "link %d Socket Send Error: %s\n",linkNo,strerror(errno));
			smpp_send_error(debugBuf);
			return (-2);
		}
	}

	return tLen;
}

//return smpp link no. (-1) -- error
//link_type: 0-UDP, 1-TCP
int smpp_decode_setup(BYTE link_type, int tcp_linkNo, BYTE src_ref, SMPP_GENERAL *pData, int len) 
{
	int		i, linkNo;
	int		current_len, c_octet_string_len=0;
	struct in_addr	addr;

	BYTE	*pMsg;
	char	ton_str[32], npi_str[32], debugBuf[512];
	DWORD 	command_length, command_id, command_status, sequence_number;

	SMPP_MSG		smppMsg;
	PDU_BIND		*pBind;
	PDU_OUTBIND		*pOutbind;

	command_length	= ntohl(pData->head.command_length);
	command_id		= ntohl(pData->head.command_id);
	command_status	= ntohl(pData->head.command_status);
	sequence_number	= ntohl(pData->head.sequence_number);
	memset(&smppMsg,0,sizeof(smppMsg));
	switch (command_id)
	{
	case BIND_TRANSMITTER:
		pMsg	= pData->msg;
		pBind	= &smppMsg.pdu.bind_transmitter;

//		printf("receive bind_transmitter.\n");
		/* mandatory parameter */

		current_len	= 0;

		/* system id */
		c_octet_string_len	= 1;
		for (i=0; i<16; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->system_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		// find out link no
		linkNo = smpp_check_sysid_route(pBind->system_id, c_octet_string_len, SMPP_CLIENT, BIND_TX);
		if (linkNo == -1) 
		{
			sprintf(debugBuf, "[smpp BIND_TRANSMITTER]can't not find system id %s in smpp parameter table.\r\n", pBind->system_id);
			smpp_send_error(debugBuf);
			if (link_type == SMPP_TCP) 
			{
				close(Mysock.server_sock[tcp_linkNo]);
				Mysock.server_sock[tcp_linkNo] = -1;
			}
			return (-1);
		}		
		if (link_type == SMPP_TCP) 
		{
			if (smpp_param[linkNo].remote_ip != Mysock.remote_ip[tcp_linkNo])
			{
				addr.s_addr	= Mysock.remote_ip[tcp_linkNo];
				sprintf(debugBuf, "[Remote ip error]remote_ip is: %s\r\n", inet_ntoa(addr));					
				smpp_send_error(debugBuf);
				close(Mysock.server_sock[tcp_linkNo]);
				Mysock.server_sock[tcp_linkNo] = -1;				
			}
//		if(smpp_state[linkNo] != IDLE)
//			{	
//				close(Mysock.server_sock[tcp_linkNo]);
//				Mysock.server_sock[tcp_linkNo] = -1;
//				return (-1);
//			}
			if(Mysock.Sockets[linkNo] > 0)
				close(Mysock.Sockets[linkNo]);			
			Mysock.Sockets[linkNo] = Mysock.server_sock[tcp_linkNo];
			Mysock.server_sock[tcp_linkNo] = -1;			
		}
		else if (link_type == SMPP_UDP)	
			dst_ref[linkNo] = src_ref;
		smpp_link[linkNo].seq_num	= sequence_number;

		/* password */
		c_octet_string_len	= 1;
		for (i=0; i<9; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->password, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		/* system type */
		c_octet_string_len	= 1;
		for (i=0; i<13; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->system_type, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		/* interface version */
		pBind->interface_version	= *(pMsg+current_len);
		current_len	+= 1;

		/* addr_ton */
		pBind->addr_ton		= *(pMsg+current_len);
		current_len	+= 1;

		/* addr_npi */
		pBind->addr_npi		= *(pMsg+current_len);
		current_len	+= 1;

		/* address_range */
		c_octet_string_len	= 1;
		for (i=0; i<13; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->address_range, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		
		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup] link %d receive BIND_TRANSMITTER: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return (-1);
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup] link %d receive BIND_TRANSMITTER: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return (-1);
		}

		if (strcmp(pBind->system_id, smpp_param[linkNo].sys_id) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup] link %d receive BIND_TRANSMITTER: system_id = %s, sys_id in param=%s\n",
					linkNo,
					pBind->system_id, 
					smpp_param[linkNo].sys_id);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendBindResp(linkNo, BindTransmitterResp, ESME_RINVSYSID);
			return (-1);
		}

		if (strcmp(pBind->password, smpp_param[linkNo].password) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup]link %d receive BIND_TRANSMITTER: password = %s, password in param=%s\n",
					linkNo,
					pBind->password, 
					smpp_param[linkNo].password);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendBindResp(linkNo, BindTransmitterResp, ESME_RINVPASWD);
			return (-1);
		}

		if (strcmp(pBind->system_type, smpp_param[linkNo].system_type) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup]link %d receive BIND_TRANSMITTER: system_type = %s, system_type in param=%s\n",
					linkNo,
					pBind->system_type, 
					smpp_param[linkNo].system_type);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendBindResp(linkNo, BindTransmitterResp, ESME_RINVSYSTYP);
			return (-1);
		}

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_ton_to_string(ton_str, pBind->addr_ton);
			smpp_npi_to_string(npi_str, pBind->addr_npi);
			sprintf(debugBuf, "[Mandatory parameters]\nsystem_id:%s, password:%s, system_type:%s, interface_version:0x%x, addr_ton: 0x%x - %s, addr_npi: 0x%x - %s\n",
				pBind->system_id,
				pBind->password, 
				pBind->system_type,
				pBind->interface_version,
				pBind->addr_ton, ton_str, 
				pBind->addr_npi, npi_str
			);
			smpp_send_ascout(debugBuf);
		}
		#endif

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= BindTransmitter;
//		printf("link %d receive bind_transmitter.\n", linkNo);
		break;
	case BIND_TRANSCEIVER:
		pMsg	= pData->msg;
		pBind	= &smppMsg.pdu.bind_transmitter;
		
		/* mandatory parameter */

		current_len	= 0;

		/* system id */
		c_octet_string_len	= 1;
		for (i=0; i<16; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->system_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		// find out link no		
		linkNo = smpp_check_sysid_route(pBind->system_id, c_octet_string_len, SMPP_CLIENT, BIND_TRX);
		if (linkNo == -1) 
		{
			sprintf(debugBuf, "[smpp BIND_TRANSCEIVER]can't not find system id %s in smpp parameter table.\r\n", pBind->system_id);
			smpp_send_error(debugBuf);
			if (link_type == SMPP_TCP) 
			{
				close(Mysock.server_sock[tcp_linkNo]);
				Mysock.server_sock[tcp_linkNo] = -1;
			}
			return (-1);
		}
		if (link_type == SMPP_TCP) 
		{
			if (smpp_param[linkNo].remote_ip != Mysock.remote_ip[tcp_linkNo])
			{
				addr.s_addr	= Mysock.remote_ip[tcp_linkNo];
				sprintf(debugBuf, "[smpp BIND_TRANSCEIVER]Remote ip error,remote_ip is: %s\r\n", inet_ntoa(addr));					
				smpp_send_error(debugBuf);
				close(Mysock.server_sock[tcp_linkNo]);
				Mysock.server_sock[tcp_linkNo] = -1;				
			}						
//			if(smpp_state[linkNo] != IDLE)
//			{	
//				close(Mysock.server_sock[tcp_linkNo]);
//				Mysock.server_sock[tcp_linkNo] = -1;
//				return (-1);
//			}
			if(Mysock.Sockets[linkNo] > 0)
				close(Mysock.Sockets[linkNo]);			
			Mysock.Sockets[linkNo] = Mysock.server_sock[tcp_linkNo];
			Mysock.server_sock[tcp_linkNo] = -1;			
		}
		if (link_type == SMPP_UDP)	dst_ref[linkNo] = src_ref;
		smpp_link[linkNo].seq_num	= sequence_number;

		/* password */
		c_octet_string_len	= 1;
		for (i=0; i<9; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->password, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		/* system type */
		c_octet_string_len	= 1;
		for (i=0; i<13; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->system_type, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		/* interface version */
		pBind->interface_version	= *(pMsg+current_len);
		current_len	+= 1;

		/* addr_ton */
		pBind->addr_ton		= *(pMsg+current_len);
		current_len	+= 1;

		/* addr_npi */
		pBind->addr_npi		= *(pMsg+current_len);
		current_len	+= 1;

		/* address_range */
		c_octet_string_len	= 1;
		for (i=0; i<13; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->address_range, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		
		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup] link %d receive BIND_TRANSCEIVER: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return (-1);
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup] link %d receive BIND_TRANSCEIVER: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return (-1);
		}

		if (strcmp(pBind->system_id, smpp_param[linkNo].sys_id) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup] link %d receive BIND_TRANSCEIVER: system_id = %s, sys_id in param=%s\n",
					linkNo,
					pBind->system_id, 
					smpp_param[linkNo].sys_id);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendBindResp(linkNo, BindTransceiverResp, ESME_RINVSYSID);
			return (-1);
		}

		if (strcmp(pBind->password, smpp_param[linkNo].password) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup]link %d receive BIND_TRANSCEIVER: password = %s, password in param=%s\n",
					linkNo,
					pBind->password, 
					smpp_param[linkNo].password);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendBindResp(linkNo, BindTransceiverResp, ESME_RINVPASWD);
			return (-1);
		}

		if (strcmp(pBind->system_type, smpp_param[linkNo].system_type) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup]link %d receive BIND_TRANSCEIVER: system_type = %s, system_type in param=%s\n",
					linkNo,
					pBind->system_type, 
					smpp_param[linkNo].system_type);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendBindResp(linkNo, BindTransceiverResp, ESME_RINVSYSTYP);
			return (-1);
		}
	
		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_ton_to_string(ton_str, pBind->addr_ton);
			smpp_npi_to_string(npi_str, pBind->addr_npi);
			sprintf(debugBuf, "[Mandatory parameters]\nsystem_id:%s, password:%s, system_type:%s, interface_version:0x%x, addr_ton: 0x%x - %s, addr_npi: 0x%x - %s\n",
				pBind->system_id,
				pBind->password, 
				pBind->system_type,
				pBind->interface_version,
				pBind->addr_ton, ton_str, 
				pBind->addr_npi, npi_str
			);
			smpp_send_ascout(debugBuf);
		}
		#endif

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= BindTransceiver;
//		printf("link %d receive BIND_TRANCEIVER", linkNo);
		break;
	case OUTBIND:
		pMsg	= pData->msg;
		pOutbind	= &smppMsg.pdu.outbind;
		
		/* mandatory parameter */
		current_len	= 0;

		/* system id */
		c_octet_string_len	= 1;
		for (i=0; i<16; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pOutbind->system_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		// find out link no
		linkNo = smpp_check_sysid_route(pOutbind->system_id, c_octet_string_len, SMPP_SERVER, BIND_RX);
		if (linkNo == -1) 
		{
			addr.s_addr	= Mysock.remote_ip[tcp_linkNo];
			sprintf(debugBuf, "remote_ip: %s\r\n", inet_ntoa(addr));			
			smpp_send_error(debugBuf);
			sprintf(debugBuf, "[smpp OUTBIND]can't not find system id %s in smpp parameter table.\r\n", pOutbind->system_id);
			smpp_send_error(debugBuf);
			if (link_type == SMPP_TCP) 
			{
				close(Mysock.server_sock[tcp_linkNo]);
				Mysock.server_sock[tcp_linkNo] = -1;
			}
			return (-1);
		}
		if (link_type == SMPP_TCP) 
		{
			if (smpp_param[linkNo].remote_ip != Mysock.remote_ip[tcp_linkNo])
			{
				addr.s_addr	= Mysock.remote_ip[tcp_linkNo];
				sprintf(debugBuf, "[smpp OUTBIND]Remote ip error,remote_ip is: %s\r\n", inet_ntoa(addr));					
				smpp_send_error(debugBuf);
				close(Mysock.server_sock[tcp_linkNo]);
				Mysock.server_sock[tcp_linkNo] = -1;				
			}
//			if(smpp_state[linkNo] != IDLE)
//			{	
//				close(Mysock.server_sock[tcp_linkNo]);
//				Mysock.server_sock[tcp_linkNo] = -1;
//				return (-1);
//			}
			if(Mysock.Sockets[linkNo] > 0)
				close(Mysock.Sockets[linkNo]);			
			Mysock.Sockets[linkNo] = Mysock.server_sock[tcp_linkNo];
			Mysock.server_sock[tcp_linkNo] = -1;	
		}
		if (link_type == SMPP_UDP)	dst_ref[linkNo] = src_ref;
		smpp_link[linkNo].seq_num	= sequence_number;

		/* password */
		c_octet_string_len	= 1;
		for (i=0; i<9; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pOutbind->password, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup] link %d receive OUTBIND: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return (-1);
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup] link %d receive OUTBIND: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return (-1);
		}

		if (strcmp(pOutbind->system_id, smpp_param[linkNo].sys_id) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup] link %d receive OUTBIND: system_id = %s, sys_id in param=%s\n",
					linkNo,
					pOutbind->system_id, 
					smpp_param[linkNo].sys_id);
				smpp_send_error(debugBuf);
			}
			#endif
//			smpp_sendBindResp(linkNo, BindReceiverResp, ESME_RINVSYSID);
			return (-1);
		}

		if (strcmp(pOutbind->password, smpp_param[linkNo].password) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup]link %d receive OUTBIND: password = %s, password in param=%s\n",
					linkNo,
					pOutbind->password, 
					smpp_param[linkNo].password);
				smpp_send_error(debugBuf);
			}
			#endif
			return (-1);
		}

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= Outbind;
//		printf("link %d receive OUTBIND, inter_head=%d.\n", linkNo, inter_head[linkNo]);
		break;
	case BIND_RECEIVER:
		pMsg	= pData->msg;
		pBind	= &smppMsg.pdu.bind_receiver;

//		printf("receive bind_receiver.\n");
		/* mandatory parameter */

		current_len	= 0;

		/* system id */
		c_octet_string_len	= 1;
		for (i=0; i<16; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->system_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		// find out link no
		linkNo = smpp_check_sysid_route(pBind->system_id, c_octet_string_len, SMPP_CLIENT, BIND_RX);
		if (linkNo == -1) 
		{
			sprintf(debugBuf, "[smpp bind_receiver]can't not find system id %s in smpp parameter table.\r\n", pBind->system_id);
			smpp_send_error(debugBuf);
			if (link_type == SMPP_TCP) 
			{
				close(Mysock.server_sock[tcp_linkNo]);
				Mysock.server_sock[tcp_linkNo] = -1;
			}
			return (-1);
		}
		if (link_type == SMPP_TCP) 
		{
			if (smpp_param[linkNo].remote_ip != Mysock.remote_ip[tcp_linkNo])
			{
				addr.s_addr	= Mysock.remote_ip[tcp_linkNo];
				sprintf(debugBuf, "[smpp bind_receiver]Remote ip error,remote_ip is: %s\r\n", inet_ntoa(addr));					
				smpp_send_error(debugBuf);
				close(Mysock.server_sock[tcp_linkNo]);
				Mysock.server_sock[tcp_linkNo] = -1;				
			}			
			if(smpp_state[linkNo]!=IDLE && smpp_state[linkNo]!=WAITING)//send out bind wating state
			{	
				close(Mysock.server_sock[tcp_linkNo]);
				Mysock.server_sock[tcp_linkNo] = -1;
				return (-1);
			}
			if(Mysock.Sockets[linkNo] > 0)
				close(Mysock.Sockets[linkNo]);			
			Mysock.Sockets[linkNo] = Mysock.server_sock[tcp_linkNo];
			Mysock.server_sock[tcp_linkNo] = -1;
		}
		else if (link_type == SMPP_UDP)	
			dst_ref[linkNo] = src_ref;
		smpp_link[linkNo].seq_num	= sequence_number;

		/* password */
		c_octet_string_len	= 1;
		for (i=0; i<9; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->password, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		/* system type */
		c_octet_string_len	= 1;
		for (i=0; i<13; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->system_type, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		/* interface version */
		pBind->interface_version	= *(pMsg+current_len);
		current_len	+= 1;

		/* addr_ton */
		pBind->addr_ton		= *(pMsg+current_len);
		current_len	+= 1;

		/* addr_npi */
		pBind->addr_npi		= *(pMsg+current_len);
		current_len	+= 1;

		/* address_range */
		c_octet_string_len	= 1;
		for (i=0; i<13; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->address_range, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		
		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup] link %d receive bind_receiver: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return (-1);
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup] link %d receive bind_receiver: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return (-1);
		}

		if (strcmp(pBind->system_id, smpp_param[linkNo].sys_id) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup] link %d receive bind_receiver: system_id = %s, sys_id in param=%s\n",
					linkNo,
					pBind->system_id, 
					smpp_param[linkNo].sys_id);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendBindResp(linkNo, BindReceiverResp, ESME_RINVSYSID);
			return (-1);
		}

		if (strcmp(pBind->password, smpp_param[linkNo].password) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup]link %d receive bind_receiver: password = %s, password in param=%s\n",
					linkNo,
					pBind->password, 
					smpp_param[linkNo].password);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendBindResp(linkNo, BindReceiverResp, ESME_RINVPASWD);
			return (-1);
		}

		if (strcmp(pBind->system_type, smpp_param[linkNo].system_type) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_setup]link %d receive bind_receiver: system_type = %s, system_type in param=%s\n",
					linkNo,
					pBind->system_type, 
					smpp_param[linkNo].system_type);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendBindResp(linkNo, BindReceiverResp, ESME_RINVSYSTYP);
			return (-1);
		}

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_ton_to_string(ton_str, pBind->addr_ton);
			smpp_npi_to_string(npi_str, pBind->addr_npi);
			sprintf(debugBuf, "[Mandatory parameters]\nsystem_id:%s, password:%s, system_type:%s, interface_version:0x%x, addr_ton: 0x%x - %s, addr_npi: 0x%x - %s\n",
				pBind->system_id,
				pBind->password, 
				pBind->system_type,
				pBind->interface_version,
				pBind->addr_ton, ton_str, 
				pBind->addr_npi, npi_str
			);
			smpp_send_ascout(debugBuf);
		}
		#endif

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= BindReceiver;
//		printf("link %d receive bind_transmitter.\n", linkNo);
		break;		
	default:
		sprintf(debugBuf, "receive error command:%ld",command_id);
		smpp_send_error(debugBuf);
		if (link_type == SMPP_TCP) 
		{
			close(Mysock.server_sock[tcp_linkNo]);
			Mysock.server_sock[tcp_linkNo] = 0;
		}
		return (-1);
	}	
	return linkNo;
}

int smpp_decode_msg(int linkNo, SMPP_GENERAL *pData, int len)
{
	DWORD		command_length, command_id, command_status, sequence_number;
	char		debugBuf[1024];
	int			i, j, current_len, c_octet_string_len=0;
	SMPP_MSG	smppMsg;
	PDU_BIND	*pBind;
	PDU_BIND_RESP			*pBindResp;
	PDU_OUTBIND				*pOutbind;
	PDU_SUBMIT_SM			*pSubmitSM;
	PDU_SUBMIT_SM_RESP		*pSubmitSMResp;
	PDU_SUBMIT_MULTI		*pSubmitMulti;
	PDU_SUBMIT_MULTI_RESP	*pSubmitMultiResp;
	PDU_DELIVER_SM			*pDeliverSM;
	PDU_DELIVER_SM_RESP		*pDeliverSMResp;
	PDU_DATA_SM				*pDataSM;
	PDU_DATA_SM_RESP		*pDataSMResp;
	PDU_QUERY_SM			*pQuerySM;
	PDU_QUERY_SM_RESP		*pQuerySMResp;
	PDU_CANCEL_SM			*pCancelSM;
	PDU_CANCEL_SM_RESP		*pCancelSMResp;
	PDU_REPLACE_SM			*pReplaceSM;
	PDU_REPLACE_SM_RESP		*pReplaceSMResp;
	PDU_ALERT_NOTIFICATION	*pAlertNotification;
	BYTE	*pMsg;
	char	comm_str[32], status_str[128], ton_str[32], npi_str[32];
	BYTE	opt_num;

	command_length	= ntohl(pData->head.command_length);
	command_id		= ntohl(pData->head.command_id);
	command_status	= ntohl(pData->head.command_status);
	sequence_number	= ntohl(pData->head.sequence_number);
	memset(&smppMsg,0,sizeof(smppMsg));
	#ifdef SMPP_DEBUG
	if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
	{
//		if(command_id!=ENQUIRE_LINK && command_id!=ENQUIRE_LINK_RESP)
		{	
			smpp_command_id_to_string(comm_str, command_id);
			sprintf(debugBuf, "\n==>SMPP    %s\tlink: %d\n", comm_str, linkNo);
			smpp_send_ascout(debugBuf);
			smpp_display_hex_msg((BYTE*) pData, len);
			smpp_command_status_to_string(status_str, command_status);
			sprintf(debugBuf, "DECODE:\n[Header]\ncommand_length=0x%lx(hex), command_id=0x%lx(hex), command_status=0x%lx(%s), sequence_number=%ld(dec)\n", 
				command_length, 
				command_id, 
				command_status, status_str, 
				sequence_number);
			smpp_send_ascout(debugBuf);
	//		printf("%s\n",debugBuf);
		}
	}
	#endif

	switch (command_id)
	{
	case BIND_TRANSMITTER:
		break;
	case BIND_TRANSMITTER_RESP:
		pMsg		= pData->msg;
		pBindResp	= &smppMsg.pdu.bind_transmitter_resp;
		smpp_link[linkNo].seq_num	= sequence_number;

		/* mandatory parameter */

		current_len	= 0;

		/* system id */
		c_octet_string_len	= 1;
		for (i=0; i<16; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBindResp->system_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			sprintf(debugBuf, "[Mandatory Parameters]\nsystem_id: %s\n",
				pBindResp->system_id);
			smpp_send_ascout(debugBuf);
		}
		#endif 

		/* Optional parameter */
		if (current_len < command_length - 16)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				smpp_send_ascout("[Optional parameters]\n");
			}
			#endif 

			memset(opt_param, 0, sizeof(SMPP_OPTIONAL_PARAMETER) * SMPP_OPT_PARAM_NUM);
			opt_num	= smpp_decode_optional_parameter(opt_param, pMsg+current_len, command_length - current_len - 16);
			for (i=0; i<opt_num; i++)
			{
				switch (opt_param[i].tag)
				{
				case SC_INTERFACE_VERSION:
					memcpy(&pBindResp->sc_interface_version, &opt_param[i].value, opt_param[i].len);
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sc_interface_version: 0x%02X\n", pBindResp->sc_interface_version);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				default:
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, 
							"Optional parameter not allowed in BIND_TRANSMITTER_RESP. tag=0x%02X",
							opt_param[i].tag);
						smpp_send_error(debugBuf);
					}
					#endif
					return 0;
				}
			}
		}

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= BindTransmitterResp;
		break;
	case BIND_RECEIVER:
		pMsg	= pData->msg;
		pBind	= &smppMsg.pdu.bind_transmitter;
		smpp_link[linkNo].seq_num	= sequence_number;

		/* mandatory parameter */

		current_len	= 0;

		/* system id */
		c_octet_string_len	= 1;
		for (i=0; i<16; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->system_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		/* password */
		c_octet_string_len	= 1;
		for (i=0; i<9; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->password, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		/* system type */
		c_octet_string_len	= 1;
		for (i=0; i<13; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->system_type, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		/* interface version */
		pBind->interface_version	= *(pMsg+current_len);
		current_len	+= 1;

		/* addr_ton */
		pBind->addr_ton		= *(pMsg+current_len);
		current_len	+= 1;

		/* addr_npi */
		pBind->addr_npi		= *(pMsg+current_len);
		current_len	+= 1;

		/* address_range */
		c_octet_string_len	= 1;
		for (i=0; i<13; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBind->address_range, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		
		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive BIND_RECEIVER: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive BIND_RECEIVER: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}

		if (strcmp(pBind->system_id, smpp_param[linkNo].sys_id) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive BIND_RECEIVER: system_id = %s, sys_id in param=%s\n",
					linkNo,
					pBind->system_id, 
					smpp_param[linkNo].sys_id);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendBindResp(linkNo, BindReceiverResp, ESME_RINVSYSID);
			return 0;
		}

		if (strcmp(pBind->password, smpp_param[linkNo].password) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg]link %d receive BIND_RECEIVER: password = %s, password in param=%s\n",
					linkNo,
					pBind->password, 
					smpp_param[linkNo].password);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendBindResp(linkNo, BindReceiverResp, ESME_RINVPASWD);
			return 0;
		}

		if (strcmp(pBind->system_type, smpp_param[linkNo].system_type) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg]link %d receive BIND_RECEIVER: system_type = %s, system_type in param=%s\n",
					linkNo,
					pBind->system_type, 
					smpp_param[linkNo].system_type);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendBindResp(linkNo, BindReceiverResp, ESME_RINVSYSTYP);
			return 0;
		}

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_ton_to_string(ton_str, pBind->addr_ton);
			smpp_npi_to_string(npi_str, pBind->addr_npi);
			sprintf(debugBuf, "[Mandatory parameters]\nsystem_id:%s, password:%s, system_type:%s, interface_version:0x%x, addr_ton: 0x%x - %s, addr_npi: 0x%x - %s\n",
				pBind->system_id,
				pBind->password, 
				pBind->system_type,
				pBind->interface_version,
				pBind->addr_ton, ton_str, 
				pBind->addr_npi, npi_str
			);
			smpp_send_ascout(debugBuf);
		}
		#endif

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= BindReceiver;
//		printf("[smpp] link %d receiver BindReceiver. inter_head=%d\n", linkNo, inter_head[linkNo]);
		break;
	case BIND_RECEIVER_RESP:
		pMsg		= pData->msg;
		pBindResp	= &smppMsg.pdu.bind_receiver_resp;
		smpp_link[linkNo].seq_num	= sequence_number;

		/* mandatory parameter */

		current_len	= 0;

		/* system id */
		c_octet_string_len	= 1;
		for (i=0; i<16; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBindResp->system_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			sprintf(debugBuf, "[Mandatory Parameters]\nsystem_id: %s\n",
				pBindResp->system_id);
			smpp_send_ascout(debugBuf);
		}
		#endif 

		/* Optional parameter */
		if (current_len < command_length - 16)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				smpp_send_ascout("[Optional parameters]\n");
			}
			#endif 

			memset(opt_param, 0, sizeof(SMPP_OPTIONAL_PARAMETER) * SMPP_OPT_PARAM_NUM);
			opt_num	= smpp_decode_optional_parameter(opt_param, pMsg+current_len, command_length - current_len - 16);
			for (i=0; i<opt_num; i++)
			{
				switch (opt_param[i].tag)
				{
				case SC_INTERFACE_VERSION:
					memcpy(&pBindResp->sc_interface_version, &opt_param[i].value, opt_param[i].len);
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sc_interface_version: 0x%02X\n", pBindResp->sc_interface_version);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				default:
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, 
							"Optional parameter not allowed in BIND_RECEIVER_RESP. tag=0x%02X",
							opt_param[i].tag);
						smpp_send_error(debugBuf);
					}
					#endif
					return 0;
				}
			}
		}

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= BindReceiverResp;
		break;
	case BIND_TRANSCEIVER:
		break;
	case BIND_TRANSCEIVER_RESP:
		pMsg		= pData->msg;
		pBindResp	= &smppMsg.pdu.bind_receiver_resp;
		smpp_link[linkNo].seq_num	= sequence_number;

		/* mandatory parameter */

		current_len	= 0;

		/* system id */
		c_octet_string_len	= 1;
		for (i=0; i<16; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pBindResp->system_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			sprintf(debugBuf, "[Mandatory Parameters]\nsystem_id: %s\n",
				pBindResp->system_id);
			smpp_send_ascout(debugBuf);
		}
		#endif 

		/* Optional parameter */
		if (current_len < command_length - 16)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				smpp_send_ascout("[Optional parameters]\n");
			}
			#endif 

			memset(opt_param, 0, sizeof(SMPP_OPTIONAL_PARAMETER) * SMPP_OPT_PARAM_NUM);
			opt_num	= smpp_decode_optional_parameter(opt_param, pMsg+current_len, command_length - current_len - 16);
			for (i=0; i<opt_num; i++)
			{
				switch (opt_param[i].tag)
				{
				case SC_INTERFACE_VERSION:
					memcpy(&pBindResp->sc_interface_version, &opt_param[i].value, opt_param[i].len);
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sc_interface_version: 0x%02X\n", pBindResp->sc_interface_version);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				default:
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, 
							"Optional parameter not allowed in BIND_TRANSCEIVER_RESP. tag=0x%02X",
							opt_param[i].tag);
						smpp_send_error(debugBuf);
					}
					#endif
					return 0;
				}
			}
		}

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= BindTransceiverResp;
		break;
	case ENQUIRE_LINK:
		if (16 != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive ENQUIRE_LINK: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (16 != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive ENQUIRE_LINK: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		smpp_link[linkNo].seq_num	= sequence_number;
		interEvent[linkNo][inter_head[linkNo]]	= EnquireLink;
		break;
	case ENQUIRE_LINK_RESP:
		if (16 != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive ENQUIRE_LINK_RESP: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (16 != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive ENQUIRE_LINK_RESP: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= EnquireLinkResp;
		break;
	case SUBMIT_SM:
//		printf("\33[32mlink %d receive SUBMIT_SM.\33[0m\n", linkNo);
		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= SubmitSM;
		smpp_link[linkNo].seq_num	= sequence_number;
		/* fill with SMPP_MSG data structure. */
		pMsg			= pData->msg;
		pSubmitSM	= &smppMsg.pdu.submit_sm;
		smppMsg.message_type	= 0x0B;
		/* head */
		memcpy(&pSubmitSM->head, &pData->head, 16);
		/* mandatory parameter */
		current_len	= 0;
		c_octet_string_len	= 1;
		for (i=0; i<6; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pSubmitSM->service_type, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pSubmitSM->source_addr_ton	= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitSM->source_addr_npi	= *(pMsg+current_len);
		current_len	+= 1;	
		c_octet_string_len	= 1;
		for (i=0; i<21; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pSubmitSM->source_addr, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pSubmitSM->dest_addr_ton		= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitSM->dest_addr_npi		= *(pMsg+current_len);
		current_len	+= 1;
		c_octet_string_len	= 1;
		for (i=0; i<21; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pSubmitSM->destination_addr, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pSubmitSM->esm_class			= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitSM->protocol_id		= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitSM->priority_flag		= *(pMsg+current_len);
		current_len	+= 1;
		c_octet_string_len	= 1;
		for (i=0; i<17; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pSubmitSM->schedule_delivery_time, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		c_octet_string_len	= 1;
		for (i=0; i<17; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pSubmitSM->validity_period, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pSubmitSM->registered_delivery		= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitSM->replace_if_present_flag	= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitSM->data_coding				= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitSM->sm_default_msg_id		= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitSM->sm_length				= *(pMsg+current_len);
		current_len	+= 1;
		memcpy(pSubmitSM->short_message, pMsg+current_len, pSubmitSM->sm_length);
		current_len	+= pSubmitSM->sm_length;
		pSubmitSM->short_message[pSubmitSM->sm_length] = 0;

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_send_ascout("[Mandatory parameters]\n");
			smpp_ton_to_string(ton_str, pSubmitSM->source_addr_ton);
			smpp_npi_to_string(npi_str, pSubmitSM->source_addr_npi);
			sprintf(debugBuf, "service_type: %s,\tsource_addr_ton: 0x%x - %s,\tsource_addr_npi: 0x%x - %s,\tsource_addr: %s\t",
				pSubmitSM->service_type,
				pSubmitSM->source_addr_ton, ton_str,
				pSubmitSM->source_addr_npi, npi_str,
				pSubmitSM->source_addr);
			smpp_send_ascout(debugBuf);
			smpp_ton_to_string(ton_str, pSubmitSM->dest_addr_ton);
			smpp_npi_to_string(npi_str, pSubmitSM->dest_addr_npi);
			sprintf(debugBuf, "dest_addr_ton: 0x%x - %s,\tdest_addr_npi: 0x%x - %s,\tdestination_addr: %s\t",
				pSubmitSM->dest_addr_ton, ton_str,
				pSubmitSM->dest_addr_npi, npi_str,
				pSubmitSM->destination_addr);
			smpp_send_ascout(debugBuf);
			sprintf(debugBuf, "esm_class: 0x%x,\tprotocol_id: 0x%x,\tpriority_flag: 0x%x,\tschedule_delivery_time: %s,\tvalidity_period: %s,\tregistered_delivery: 0x%x\t",
				pSubmitSM->esm_class,
				pSubmitSM->protocol_id,
				pSubmitSM->priority_flag,
				pSubmitSM->schedule_delivery_time,
				pSubmitSM->validity_period,
				pSubmitSM->registered_delivery);
			smpp_send_ascout(debugBuf);
			sprintf(debugBuf, "replace_if_present_flag: 0x%x,\tdata_coding: 0x%x,\tsm_default_msg_id: 0x%x,\tsm_length: 0x%x,\tshort_message: %s\n",
				pSubmitSM->replace_if_present_flag,
				pSubmitSM->data_coding,
				pSubmitSM->sm_default_msg_id,
				pSubmitSM->sm_length,
				pSubmitSM->short_message);
			smpp_send_ascout(debugBuf);
		}
		#endif

		/* optional parameter */
		if (current_len < command_length - 16)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				smpp_send_ascout("[Optional parameters]\n");
			}
			#endif 

			memset(opt_param, 0, sizeof(SMPP_OPTIONAL_PARAMETER) * SMPP_OPT_PARAM_NUM);
			opt_num	= smpp_decode_optional_parameter(opt_param, pMsg+current_len, command_length - current_len - 16);
			for (i=0; i<opt_num; i++)
			{
				switch (opt_param[i].tag)
				{
				case USER_MESSAGE_REFERENCE:
					memcpy(&pSubmitSM->user_message_reference, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "user_message_reference: 0x%04X\n", pSubmitSM->user_message_reference);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SOURCE_PORT:
					memcpy(&pSubmitSM->source_port, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "source_port: 0x%04X\n", pSubmitSM->source_port);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SOURCE_ADDR_SUBUNIT:
					memcpy(&pSubmitSM->source_addr_subunit, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "source_addr_subunit: 0x%02X\n", pSubmitSM->source_addr_subunit);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DESTINATION_PORT:
					memcpy(&pSubmitSM->destination_port, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "destination_port: 0x%04X\n", pSubmitSM->destination_port);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DEST_ADDR_SUBUNIT:
					memcpy(&pSubmitSM->dest_addr_subunit, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "dest_addr_subunit: 0x%02X\n", pSubmitSM->dest_addr_subunit);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SAR_MSG_REF_NUM:
					memcpy(&pSubmitSM->sar_msg_ref_num, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sar_msg_ref_num: 0x%04X\n", pSubmitSM->sar_msg_ref_num);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SAR_TOTAL_SEGMENTS:
					memcpy(&pSubmitSM->sar_total_segments, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sar_total_segments: 0x%02X\n", pSubmitSM->sar_total_segments);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SAR_SEGMENT_SEQNUM:
					memcpy(&pSubmitSM->sar_segment_seqnum, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sar_segment_seqnum: 0x%02X\n", pSubmitSM->sar_segment_seqnum);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case MORE_MESSAGES_TO_SEND:
					memcpy(&pSubmitSM->more_messages_to_send, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "more_messages_to_send: 0x%02X\n", pSubmitSM->more_messages_to_send);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case PAYLOAD_TYPE:
					memcpy(&pSubmitSM->payload_type, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "payload_type: 0x%02X\n", pSubmitSM->payload_type);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case MESSAGE_PAYLOAD:
					memcpy(pSubmitSM->message_payload, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "message_payload: %s\n", pSubmitSM->message_payload);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case PRIVACY_INDICATOR:
					memcpy(&pSubmitSM->privacy_indicator, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "privacy_indicator: 0x%02X\n", pSubmitSM->privacy_indicator);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case CALLBACK_NUM:
					memcpy(pSubmitSM->callback_num, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "callback_num: %s\n", pSubmitSM->callback_num);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case CALLBACK_NUM_PRES_IND:
					memcpy(&pSubmitSM->callback_num_pres_ind, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "callback_num_pres_ind: 0x%02X\n", pSubmitSM->callback_num_pres_ind);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case CALLBACK_NUM_ATAG:
					memcpy(pSubmitSM->callback_num_atag, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "callback_num_atag: %s\n", pSubmitSM->callback_num_atag);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SOURCE_SUBADDRESS:
					memcpy(pSubmitSM->source_subaddress, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "source_subaddress: %s\n", pSubmitSM->source_subaddress);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DEST_SUBADDRESS:
					memcpy(pSubmitSM->dest_subaddress, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "dest_subaddress: %s\n", pSubmitSM->dest_subaddress);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case USER_RESPONSE_CODE:
					memcpy(&pSubmitSM->user_response_code, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "user_response_code: 0x%02X\n", pSubmitSM->user_response_code);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DISPLAY_TIME:
					memcpy(&pSubmitSM->display_time, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "display_time: 0x%02X\n", pSubmitSM->display_time);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SMS_SIGNAL:
					memcpy(&pSubmitSM->sms_signal, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sms_signal: 0x%04X\n", pSubmitSM->sms_signal);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case MS_VALIDITY:
					memcpy(&pSubmitSM->ms_validity, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "ms_validity: 0x%02X\n", pSubmitSM->ms_validity);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case MS_MSG_WAIT_FACILITIES:
					memcpy(&pSubmitSM->ms_msg_wait_facilities, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "ms_msg_wait_facilities: 0x%02X\n", pSubmitSM->ms_msg_wait_facilities);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case NUMBER_OF_MESSAGES:
					memcpy(&pSubmitSM->number_of_messages, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "number_of_messages: 0x%02X\n", pSubmitSM->number_of_messages);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case ALERT_ON_MESSAGE_DELIVERY:
					current_len = current_len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "alert_on_message_delivery: 0x%02X\n", pSubmitSM->alert_on_message_delivery);
						smpp_send_ascout(debugBuf);
					}                                                       
					#endif 
					break;
				case LANGUAGE_INDICATOR:
					memcpy(&pSubmitSM->language_indicator, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "language_indicator: 0x%02X\n", pSubmitSM->language_indicator);
						smpp_send_ascout(debugBuf);
					}                                                       
					#endif 
					break;
				case ITS_REPLY_TYPE:
					memcpy(&pSubmitSM->its_reply_type, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "its_reply_type: 0x%02X\n", pSubmitSM->its_reply_type);
						smpp_send_ascout(debugBuf);
					}                                                       
					#endif 
					break;
				case ITS_SESSION_INFO:
					memcpy(pSubmitSM->its_session_info, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "its_session_info: 0x%02X%02X\n", 
							pSubmitSM->its_session_info[0], pSubmitSM->its_session_info[1]);
						smpp_send_ascout(debugBuf);
					}                                                       
					#endif 
					break;
				case USSD_SERVICE_OP:
					memcpy(&pSubmitSM->ussd_service_op, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "ussd_service_op: 0x%04X\n", pSubmitSM->ussd_service_op);
						smpp_send_ascout(debugBuf);
					}                                                       
					#endif 
					break;
				case DEST_NETWORK_TYPE:
					memcpy(&pSubmitSM->dest_network_type, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "dest_network_type: 0x%04X\n", pSubmitSM->dest_network_type);
						smpp_send_ascout(debugBuf);
					}                                                       
					#endif 
					break;
				default:
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, 
							"Optional parameter not allowed in SUBMIT_SM. tag=0x%04X",
							opt_param[i].tag);
						smpp_send_error(debugBuf);
					}
					#endif
					return 0;
				}
			}
		}

		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive SUBMIT_SM: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive SUBMIT_SM: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}
		if(callBackFunc[linkNo].data_proc!= NULL)
		callBackFunc[linkNo].data_proc(linkNo, (SMPP_MSG *)&smppMsg, sizeof(PDU_SUBMIT_SM));
		break;
	case SUBMIT_SM_RESP:
		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= SubmitSMResp;
		
		pMsg			= pData->msg;
		pSubmitSMResp	= &smppMsg.pdu.submit_sm_resp;
		smppMsg.message_type = 0x0C;

		memcpy(&pSubmitSMResp->head, &pData->head, 16);

		current_len	= 0;
		c_octet_string_len	= 1;
		for (i=0; i<65; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pSubmitSMResp->message_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			sprintf(debugBuf, "[Mandatory Parameters]\nmessage_id: %s\n",
				pSubmitSMResp->message_id);
			smpp_send_ascout(debugBuf);
		}
		#endif 

		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive SUBMIT_SM_RESP: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive SUBMIT_SM_RESP: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}
		if(callBackFunc[linkNo].data_proc!= NULL)
		callBackFunc[linkNo].data_proc(linkNo, (SMPP_MSG *)&smppMsg, sizeof(PDU_SUBMIT_SM_RESP));
		break;
	case SUBMIT_MULTI:
		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= SubmitMulti;
		smpp_link[linkNo].seq_num	= sequence_number;
		
		pMsg			= pData->msg;
		pSubmitMulti	= &smppMsg.pdu.submit_multi;
		smppMsg.message_type	= 0x0D;
		
		memcpy(&pSubmitMulti->head, &pData->head, 16);
		
		/* mandatory parameter */
		current_len	= 0;
		c_octet_string_len	= 1;
		for (i=0; i<6; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pSubmitMulti->service_type, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pSubmitMulti->source_addr_ton		= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitMulti->source_addr_npi		= *(pMsg+current_len);
		current_len	+= 1;
		c_octet_string_len	= 1;
		for (i=0; i<21; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pSubmitMulti->source_addr, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pSubmitMulti->number_of_dests		= *(pMsg+current_len);
		current_len	+= 1;
		for (i=0; i<pSubmitMulti->number_of_dests; i++)
		{
			switch(*(pMsg+current_len))
			{
			case 1:	//SME address
				pSubmitMulti->dest_address[i].dest_flag		= *(pMsg+current_len);
				current_len	+= 1;
				pSubmitMulti->dest_address[i].dest_addr.sme_dest_address.dest_addr_ton	= *(pMsg+current_len);
				current_len	+= 1;
				pSubmitMulti->dest_address[i].dest_addr.sme_dest_address.dest_addr_npi	= *(pMsg+current_len);
				current_len	+= 1;
				c_octet_string_len	= 1;
				for (j=0; j<21; j++)
				{
					if (*(pMsg+current_len+j) != 0)	c_octet_string_len++;
					else	break;
				}
				memcpy(pSubmitMulti->dest_address[i].dest_addr.sme_dest_address.destination_addr, 
					pMsg+current_len, c_octet_string_len);
				current_len	+= c_octet_string_len;
				break;
			case 2:	//Distribution List Name
				pSubmitMulti->dest_address[i].dest_flag		= *(pMsg+current_len);
				current_len	+= 1;
				c_octet_string_len	= 1;
				for (j=0; j<21; j++)
				{
					if (*(pMsg+current_len+j) != 0)	c_octet_string_len++;
					else	break;
				}
				memcpy(pSubmitMulti->dest_address[i].dest_addr.dl_name.dl_name, 
					pMsg+current_len, c_octet_string_len);
				current_len	+= c_octet_string_len;
				break;
			default:
				break;
			}
		}
		pSubmitMulti->esm_class				= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitMulti->protocol_id			= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitMulti->priority_flag			= *(pMsg+current_len);
		current_len	+= 1;
		c_octet_string_len	= 1;
		for (i=0; i<17; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pSubmitMulti->schedule_delivery_time, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		c_octet_string_len	= 1;
		for (i=0; i<17; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pSubmitMulti->validity_period, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pSubmitMulti->registered_delivery	= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitMulti->replace_if_present_flag= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitMulti->data_coding			= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitMulti->sm_default_msg_id		= *(pMsg+current_len);
		current_len	+= 1;
		pSubmitMulti->sm_length				= *(pMsg+current_len);
		current_len	+= 1;
		memcpy(pSubmitMulti->short_message, pMsg+current_len, pSubmitMulti->sm_length);
		pSubmitMulti->short_message[pSubmitMulti->sm_length] = 0;
		current_len	+= pSubmitMulti->sm_length;

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_send_ascout("[Mandatory parameters]\n");
			smpp_ton_to_string(ton_str, pSubmitMulti->source_addr_ton);
			smpp_npi_to_string(npi_str, pSubmitMulti->source_addr_npi);
			sprintf(debugBuf, "service_type: %s,\tsource_addr_ton: 0x%x - %s,\tsource_addr_npi: 0x%x - %s,\tsource_addr: %s\t",
				pSubmitMulti->service_type,
				pSubmitMulti->source_addr_ton, ton_str,
				pSubmitMulti->source_addr_npi, npi_str,
				pSubmitMulti->source_addr);
			smpp_send_ascout(debugBuf);
			sprintf(debugBuf, "number_of_dests: %d,\t",
				pSubmitMulti->number_of_dests);
			smpp_send_ascout(debugBuf);
			for (i=0; i<pSubmitMulti->number_of_dests; i++)
			{
				if (0 == pSubmitMulti->number_of_dests)	break;
				if (pSubmitMulti->dest_address[i].dest_flag == 1)
				{
					sprintf(debugBuf, "destination address %d flag: 0x01 - %s",
						i, "SME address");
					smpp_send_ascout(debugBuf);
					smpp_ton_to_string(ton_str, pSubmitMulti->dest_address[i].dest_addr.sme_dest_address.dest_addr_ton);
					smpp_npi_to_string(npi_str, pSubmitMulti->dest_address[i].dest_addr.sme_dest_address.dest_addr_npi);
					sprintf(debugBuf, "ton: 0x%02X - %s,\tnpi: 0x%02X - %s,\tdestination_addr: %s,\t",
						pSubmitMulti->dest_address[i].dest_addr.sme_dest_address.dest_addr_ton, ton_str,
						pSubmitMulti->dest_address[i].dest_addr.sme_dest_address.dest_addr_npi, npi_str,
						pSubmitMulti->dest_address[i].dest_addr.sme_dest_address.destination_addr);
					smpp_send_ascout(debugBuf);
				}else if (pSubmitMulti->dest_address[i].dest_flag == 2)
				{
					sprintf(debugBuf, "destination address %d flag: 0x02 - %s,\tdl_name: %s,\t",
						i, "Distribution List Name",
						pSubmitMulti->dest_address[i].dest_addr.dl_name.dl_name);
					smpp_send_ascout(debugBuf);
				}
			}
			sprintf(debugBuf, "esm_class: 0x%x,\tprotocol_id: 0x%x,\tpriority_flag: 0x%x,\tschedule_delivery_time: %s,\tvalidity_period: %s,\tregistered_delivery: 0x%x\t",
				pSubmitMulti->esm_class,
				pSubmitMulti->protocol_id,
				pSubmitMulti->priority_flag,
				pSubmitMulti->schedule_delivery_time,
				pSubmitMulti->validity_period,
				pSubmitMulti->registered_delivery);
			smpp_send_ascout(debugBuf);
			sprintf(debugBuf, "replace_if_present_flag: 0x%x,\tdata_coding: 0x%x,\tsm_default_msg_id: 0x%x,\tsm_length: 0x%x,\tshort_message: %s\n",
				pSubmitMulti->replace_if_present_flag,
				pSubmitMulti->data_coding,
				pSubmitMulti->sm_default_msg_id,
				pSubmitMulti->sm_length,
				pSubmitMulti->short_message);
			smpp_send_ascout(debugBuf);
		}
		#endif

		/* optional parameter */
		if (current_len < command_length - 16)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				smpp_send_ascout("[Optional parameters]\n");
			}
			#endif 

			memset(opt_param, 0, sizeof(SMPP_OPTIONAL_PARAMETER) * SMPP_OPT_PARAM_NUM);
			opt_num	= smpp_decode_optional_parameter(opt_param, pMsg+current_len, command_length - current_len - 16);
			for (i=0; i<opt_num; i++)
			{
				switch (opt_param[i].tag)
				{
				case USER_MESSAGE_REFERENCE:
					memcpy(&pSubmitMulti->user_message_reference, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "user_message_reference: 0x%04X\n", pSubmitMulti->user_message_reference);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SOURCE_PORT:
					memcpy(&pSubmitMulti->source_port, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "source_port: 0x%04X\n", pSubmitMulti->source_port);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SOURCE_ADDR_SUBUNIT:
					memcpy(&pSubmitMulti->source_addr_subunit, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "source_addr_subunit: 0x%02X\n", pSubmitMulti->source_addr_subunit);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DESTINATION_PORT:
					memcpy(&pSubmitMulti->destination_port, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "destination_port: 0x%04X\n", pSubmitMulti->destination_port);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DEST_ADDR_SUBUNIT:
					memcpy(&pSubmitMulti->dest_addr_subunit, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "dest_addr_subunit: 0x%02X\n", pSubmitMulti->dest_addr_subunit);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SAR_MSG_REF_NUM:
					memcpy(&pSubmitMulti->sar_msg_ref_num, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sar_msg_ref_num: 0x%04X\n", pSubmitMulti->sar_msg_ref_num);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SAR_TOTAL_SEGMENTS:
					memcpy(&pSubmitMulti->sar_total_segments, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sar_total_segments: 0x%02X\n", pSubmitMulti->sar_total_segments);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SAR_SEGMENT_SEQNUM:
					memcpy(&pSubmitMulti->sar_segment_seqnum, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sar_segment_seqnum: 0x%02X\n", pSubmitMulti->sar_segment_seqnum);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case PAYLOAD_TYPE:
					memcpy(&pSubmitMulti->payload_type, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "payload_type: 0x%02X\n", pSubmitMulti->payload_type);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case MESSAGE_PAYLOAD:
					memcpy(pSubmitMulti->message_payload, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "message_payload: %s\n", pSubmitMulti->message_payload);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case PRIVACY_INDICATOR:
					memcpy(&pSubmitMulti->privacy_indicator, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "privacy_indicator: 0x%02X\n", pSubmitMulti->privacy_indicator);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case CALLBACK_NUM:
					memcpy(pSubmitMulti->callback_num, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "callback_num: %s\n", pSubmitMulti->callback_num);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case CALLBACK_NUM_PRES_IND:
					memcpy(&pSubmitMulti->callback_num_pres_ind, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "callback_num_pres_ind: 0x%02X\n", pSubmitMulti->callback_num_pres_ind);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case CALLBACK_NUM_ATAG:
					memcpy(pSubmitMulti->callback_num_atag, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "callback_num_atag: %s\n", pSubmitMulti->callback_num_atag);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SOURCE_SUBADDRESS:
					memcpy(pSubmitMulti->source_subaddress, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "source_subaddress: %s\n", pSubmitMulti->source_subaddress);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DEST_SUBADDRESS:
					memcpy(pSubmitMulti->dest_subaddress, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "dest_subaddress: %s\n", pSubmitMulti->dest_subaddress);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DISPLAY_TIME:
					memcpy(&pSubmitMulti->display_time, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "display_time: 0x%02X\n", pSubmitMulti->display_time);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SMS_SIGNAL:
					memcpy(&pSubmitMulti->sms_signal, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sms_signal: 0x%04X\n", pSubmitMulti->sms_signal);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case MS_VALIDITY:
					memcpy(&pSubmitMulti->ms_validity, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "ms_validity: 0x%02X\n", pSubmitMulti->ms_validity);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case MS_MSG_WAIT_FACILITIES:
					memcpy(&pSubmitMulti->ms_msg_wait_facilities, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "ms_msg_wait_facilities: 0x%02X\n", pSubmitMulti->ms_msg_wait_facilities);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case ALERT_ON_MESSAGE_DELIVERY:
					current_len = current_len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "alert_on_message_delivery: 0x%02X\n", pSubmitMulti->alert_on_message_delivery);
						smpp_send_ascout(debugBuf);
					}                                                       
					#endif 
					break;
				case LANGUAGE_INDICATOR:
					memcpy(&pSubmitMulti->language_indicator, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "language_indicator: 0x%02X\n", pSubmitMulti->language_indicator);
						smpp_send_ascout(debugBuf);
					}                                                       
					#endif 
					break;
				case DEST_NETWORK_TYPE:
					memcpy(&pSubmitMulti->dest_network_type, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "dest_network_type: 0x%04X\n", pSubmitMulti->dest_network_type);
						smpp_send_ascout(debugBuf);
					}                                                       
					#endif 
					break;
				default:
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, 
							"Optional parameter not allowed in SUBMIT_MULTI. tag=0x%04X",
							opt_param[i].tag);
						smpp_send_error(debugBuf);
					}
					#endif
					smpp_sendResponse(linkNo, SUBMIT_SM_RESP, ESME_ROPTPARNOTALLWD, sequence_number);
					return 0;
				}
			}
		}

		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive SUBMIT_MULTI: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive SUBMIT_MULTI: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}
		if(callBackFunc[linkNo].data_proc!= NULL)
		callBackFunc[linkNo].data_proc(linkNo, (SMPP_MSG *)&smppMsg, sizeof(PDU_SUBMIT_MULTI));
		break;
	case SUBMIT_MULTI_RESP:
		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= SubmitMultiResp;
		
		pMsg			= pData->msg;
		pSubmitMultiResp	= &smppMsg.pdu.submit_multi_resp;
		smppMsg.message_type	= 0x0E;

		memcpy(&(pSubmitMultiResp->head), &pData->head, 16);

		current_len	= 0;
		c_octet_string_len	= 1;
		for (i=0; i<65; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pSubmitMultiResp->message_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pSubmitMultiResp->no_unsuccess	= *(pMsg+current_len);
		current_len	+= 1;
		for (i=0; i<pSubmitMultiResp->no_unsuccess; i++)
		{
			pSubmitMultiResp->unsuccess_sme[i].dest_addr_ton	= *(pMsg+current_len);
			current_len	+= 1;
			pSubmitMultiResp->unsuccess_sme[i].dest_addr_npi	= *(pMsg+current_len);
			current_len	+= 1;
			c_octet_string_len	= 1;
			for (i=0; i<21; i++)
			{
				if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
				else	break;
			}
			memcpy(pSubmitMultiResp->unsuccess_sme[i].destination_addr, pMsg+current_len, c_octet_string_len);
			current_len	+= c_octet_string_len;
			memcpy(&pSubmitMultiResp->unsuccess_sme[i].error_status_code, pMsg+current_len, 4);
		}

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_send_ascout("[Mandatory parameters]\n");
			sprintf(debugBuf, "message_id: %s\nno_unsuccess: %d\n",
				pSubmitMultiResp->message_id,
				pSubmitMultiResp->no_unsuccess);
			for (i=0; i<pSubmitMultiResp->no_unsuccess; i++)
			{
				if (pSubmitMultiResp->no_unsuccess == 0)	break;
				smpp_ton_to_string(ton_str, pSubmitMultiResp->unsuccess_sme[i].dest_addr_ton);
				smpp_npi_to_string(npi_str, pSubmitMultiResp->unsuccess_sme[i].dest_addr_npi);
				smpp_command_status_to_string(status_str, pSubmitMultiResp->unsuccess_sme[i].error_status_code);
				sprintf(debugBuf, "[unsuccess dest %d] ton: 0x%x - %s, npi: 0x%x - %s, destination_addr: %s, error_status_code: %ld - %s\n",
					i,
					pSubmitMultiResp->unsuccess_sme[i].dest_addr_ton, ton_str,
					pSubmitMultiResp->unsuccess_sme[i].dest_addr_npi, npi_str,
					pSubmitMultiResp->unsuccess_sme[i].destination_addr,
					pSubmitMultiResp->unsuccess_sme[i].error_status_code, status_str);
			}
		}
		#endif
		if(callBackFunc[linkNo].data_proc!= NULL)
		callBackFunc[linkNo].data_proc(linkNo, (SMPP_MSG *)&smppMsg, sizeof(PDU_SUBMIT_MULTI_RESP));
		break;
	case DELIVER_SM:
		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= DeliverSM;
		smpp_link[linkNo].seq_num	= sequence_number;
		
		pMsg			= pData->msg;
		pDeliverSM	= &smppMsg.pdu.deliver_sm;
		smppMsg.message_type	= 0x0F;
		
		memcpy(&pDeliverSM->head, &pData->head, 16);

		/* mandatory parameter */
		current_len	= 0;
		c_octet_string_len	= 1;
		for (i=0; i<6; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pDeliverSM->service_type, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pDeliverSM->source_addr_ton			= *(pMsg+current_len);
		current_len	+= 1;
		pDeliverSM->source_addr_npi			= *(pMsg+current_len);
		current_len	+= 1;
		c_octet_string_len	= 1;
		for (i=0; i<21; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pDeliverSM->source_addr, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pDeliverSM->dest_addr_ton			= *(pMsg+current_len);
		current_len	+= 1;
		pDeliverSM->dest_addr_npi			= *(pMsg+current_len);
		current_len	+= 1;
		c_octet_string_len	= 1;
		for (i=0; i<21; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pDeliverSM->destination_addr, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pDeliverSM->esm_class				= *(pMsg+current_len);
		current_len	+= 1;
		pDeliverSM->protocol_id				= *(pMsg+current_len);
		current_len	+= 1;
		pDeliverSM->priority_flag			= *(pMsg+current_len);
		current_len	+= 1;
		pDeliverSM->schedule_delivery_time	= *(pMsg+current_len);
		current_len	+= 1;
		pDeliverSM->validity_period			= *(pMsg+current_len);
		current_len	+= 1;
		pDeliverSM->registered_delivery		= *(pMsg+current_len);
		current_len	+= 1;
		pDeliverSM->replace_if_present_flag	= *(pMsg+current_len);
		current_len	+= 1;
		pDeliverSM->data_coding				= *(pMsg+current_len);
		current_len	+= 1;
		pDeliverSM->sm_default_msg_id		= *(pMsg+current_len);
		current_len	+= 1;
		pDeliverSM->sm_length				= *(pMsg+current_len);
		current_len	+= 1;
		memcpy(pDeliverSM->short_message, pMsg+current_len, pDeliverSM->sm_length);
		current_len	+= pDeliverSM->sm_length;

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_send_ascout("[Mandatory parameters]\n");
			smpp_ton_to_string(ton_str, pDeliverSM->source_addr_ton);
			smpp_npi_to_string(npi_str, pDeliverSM->source_addr_npi);
			sprintf(debugBuf, "service_type: %s,\tsource_addr_ton: 0x%x - %s,\tsource_addr_npi: 0x%x - %s,\tsource_addr: %s\t",
				pDeliverSM->service_type,
				pDeliverSM->source_addr_ton, ton_str,
				pDeliverSM->source_addr_npi, npi_str,
				pDeliverSM->source_addr);
			smpp_send_ascout(debugBuf);
			smpp_ton_to_string(ton_str, pDeliverSM->dest_addr_ton);
			smpp_npi_to_string(npi_str, pDeliverSM->dest_addr_npi);
			sprintf(debugBuf, "dest_addr_ton: 0x%x - %s,\tdest_addr_npi: 0x%x - %s,\tdestination_addr: %s\t",
				pDeliverSM->dest_addr_ton, ton_str,
				pDeliverSM->dest_addr_npi, npi_str,
				pDeliverSM->destination_addr);
			smpp_send_ascout(debugBuf);
			sprintf(debugBuf, "esm_class: 0x%x,\tprotocol_id: 0x%x,\tpriority_flag: 0x%x,\tschedule_delivery_time: 0x%02X,\tvalidity_period: 0x%02X,\tregistered_delivery: 0x%x\t",
				pDeliverSM->esm_class,
				pDeliverSM->protocol_id,
				pDeliverSM->priority_flag,
				pDeliverSM->schedule_delivery_time,
				pDeliverSM->validity_period,
				pDeliverSM->registered_delivery);
			smpp_send_ascout(debugBuf);
			sprintf(debugBuf, "replace_if_present_flag: 0x%x,\tdata_coding: 0x%x,\tsm_default_msg_id: 0x%x,\tsm_length: 0x%x,\tshort_message: %s\n",
				pDeliverSM->replace_if_present_flag,
				pDeliverSM->data_coding,
				pDeliverSM->sm_default_msg_id,
				pDeliverSM->sm_length,
				pDeliverSM->short_message);
			smpp_send_ascout(debugBuf);
		}
		#endif

		/* optional parameter */
		if (current_len < command_length - 16)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				smpp_send_ascout("[Optional parameters]\n");
			}
			#endif 

			memset(opt_param, 0, sizeof(SMPP_OPTIONAL_PARAMETER) * SMPP_OPT_PARAM_NUM);
			opt_num	= smpp_decode_optional_parameter(opt_param, pMsg+current_len, command_length - current_len - 16);
			for (i=0; i<opt_num; i++)
			{
				switch (opt_param[i].tag)
				{
				case USER_MESSAGE_REFERENCE:
					memcpy(&pDeliverSM->user_message_reference, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "user_message_reference: 0x%04X\n", pDeliverSM->user_message_reference);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SOURCE_PORT:
					memcpy(&pDeliverSM->source_port, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "source_port: 0x%04X\n", pDeliverSM->source_port);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DESTINATION_PORT:
					memcpy(&pDeliverSM->destination_port, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "destination_port: 0x%04X\n", pDeliverSM->destination_port);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SAR_MSG_REF_NUM:
					memcpy(&pDeliverSM->sar_msg_ref_num, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sar_msg_ref_num: 0x%04X\n", pDeliverSM->sar_msg_ref_num);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SAR_TOTAL_SEGMENTS:
					memcpy(&pDeliverSM->sar_total_segments, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sar_total_segments: 0x%02X\n", pDeliverSM->sar_total_segments);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SAR_SEGMENT_SEQNUM:
					memcpy(&pDeliverSM->sar_segment_seqnum, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sar_segment_seqnum: 0x%02X\n", pDeliverSM->sar_segment_seqnum);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case USER_RESPONSE_CODE:
					memcpy(&pDeliverSM->user_response_code, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "user_response_code: 0x%02X\n", pDeliverSM->user_response_code);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case PRIVACY_INDICATOR:
					memcpy(&pDeliverSM->privacy_indicator, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "privacy_indicator: 0x%02X\n", pDeliverSM->privacy_indicator);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case PAYLOAD_TYPE:
					memcpy(&pDeliverSM->payload_type, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "payload_type: 0x%02X\n", pDeliverSM->payload_type);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case MESSAGE_PAYLOAD:
					memcpy(pDeliverSM->message_payload, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "message_payload: %s\n", pDeliverSM->message_payload);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case CALLBACK_NUM:
					memcpy(pDeliverSM->callback_num, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "callback_num: %s\n", pDeliverSM->callback_num);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SOURCE_SUBADDRESS:
					memcpy(pDeliverSM->source_subaddress, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "source_subaddress: %s\n", pDeliverSM->source_subaddress);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DEST_SUBADDRESS:
					memcpy(pDeliverSM->dest_subaddress, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "dest_subaddress: %s\n", pDeliverSM->dest_subaddress);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case LANGUAGE_INDICATOR:
					memcpy(&pDeliverSM->language_indicator, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "language_indicator: 0x%02X\n", pDeliverSM->language_indicator);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case ITS_SESSION_INFO:
					memcpy(pDeliverSM->its_session_info, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "its_session_info: 0x%02X%02X\n", 
						pDeliverSM->its_session_info[0], pDeliverSM->its_session_info[1]);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case NETWORK_ERROR_CODE:
					memcpy(&pDeliverSM->network_error_code, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "network_error_code: 0x%02X%02X%02X\n", 
							pDeliverSM->network_error_code[0], 
							pDeliverSM->network_error_code[1], 
							pDeliverSM->network_error_code[2]);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case MESSAGE_STATE:
					memcpy(&pDeliverSM->message_state, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "message_state: 0x%02X\n", pDeliverSM->message_state);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case RECEIPTED_MESSAGE_ID:
					memcpy(&pDeliverSM->receipted_message_id, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "receipted_message_id: %s\n", pDeliverSM->receipted_message_id);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case USSD_SERVICE_OP:
					memcpy(&pDeliverSM->ussd_service_op, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "ussd_service_op: 0x%04X\n", pDeliverSM->ussd_service_op);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				default:
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, 
							"Optional parameter not allowed in DELIVER_SM. tag=0x%04X",
							opt_param[i].tag);
						smpp_send_error(debugBuf);
					}
					#endif
					smpp_sendResponse(linkNo, DATA_SM_RESP, ESME_ROPTPARNOTALLWD, sequence_number);
					return 0;
				}
			}
		}

		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive DELIVER_SM: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive DELIVER_SM: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}
		if(callBackFunc[linkNo].data_proc!= NULL)
		callBackFunc[linkNo].data_proc(linkNo, &smppMsg, sizeof(PDU_DELIVER_SM));
		break;
	case DELIVER_SM_RESP:
		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= DeliverSMResp;
		/* fill with SMPP_MSG data structure. */
		pMsg				= pData->msg;
		pDeliverSMResp	= &smppMsg.pdu.deliver_sm_resp;
		smppMsg.message_type	= 0x10;

		memcpy(&pDeliverSMResp->head, &pData->head, 16);

		current_len	= 0;
		c_octet_string_len	= 1;
		//lw modify here 06/10/08 decode code byte sequence error
    pDeliverSMResp->head.command_length	= ntohl(pData->head.command_length);
	  pDeliverSMResp->head.command_id		= ntohl(pData->head.command_id);
	  pDeliverSMResp->head.command_status	= ntohl(pData->head.command_status);
	  pDeliverSMResp->head.sequence_number	= ntohl(pData->head.sequence_number);
//		for (i=0; i<65; i++)
//		{
//			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
//			else	break;
//		}
//	comment patch 20
		memcpy(&pDeliverSMResp->message_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive DELIVER_SM_RESP: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive DELIVER_SM_RESP: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}
		if(callBackFunc[linkNo].data_proc!= NULL)
		callBackFunc[linkNo].data_proc(linkNo, (SMPP_MSG *)&smppMsg, sizeof(PDU_DELIVER_SM_RESP));
		break;
	case DATA_SM:
		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= DataSM;
		smpp_link[linkNo].seq_num	= sequence_number;
		
		pMsg	= pData->msg;
		pDataSM	= &smppMsg.pdu.data_sm;
		smppMsg.message_type	= 0x11;
		
		memcpy(&pDataSM->head, &pData->head, 16);

		/* mandatory parameter */
		current_len	= 0;
		c_octet_string_len	= 1;
		for (i=0; i<6; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pDataSM->service_type, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pDataSM->source_addr_ton		= *(pMsg+current_len);
		current_len	+= 1;
		pDataSM->source_addr_npi		= *(pMsg+current_len);
		current_len	+= 1;
		c_octet_string_len	= 1;
		for (i=0; i<65; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pDataSM->source_addr, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pDataSM->dest_addr_ton			= *(pMsg+current_len);
		current_len	+= 1;
		pDataSM->dest_addr_npi			= *(pMsg+current_len);
		current_len	+= 1;
		c_octet_string_len	= 1;
		for (i=0; i<65; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pDataSM->destination_addr, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pDataSM->esm_class				= *(pMsg+current_len);
		current_len	+= 1;
		pDataSM->registered_delivery	= *(pMsg+current_len);
		current_len	+= 1;
		pDataSM->data_coding			= *(pMsg+current_len);
		current_len	+= 1;

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_send_ascout("[Mandatory parameters]\n");
			smpp_ton_to_string(ton_str, pDataSM->source_addr_ton);
			smpp_npi_to_string(npi_str, pDataSM->source_addr_npi);
			sprintf(debugBuf, "service_type: %s,\tsource_addr_ton: 0x%x - %s,\tsource_addr_npi: 0x%x - %s,\tsource_addr: %s\t",
				pDataSM->service_type,
				pDataSM->source_addr_ton, ton_str,
				pDataSM->source_addr_npi, npi_str,
				pDataSM->source_addr);
			smpp_send_ascout(debugBuf);
			smpp_ton_to_string(ton_str, pDataSM->dest_addr_ton);
			smpp_npi_to_string(npi_str, pDataSM->dest_addr_npi);
			sprintf(debugBuf, "dest_addr_ton: 0x%x - %s,\tdest_addr_npi: 0x%x - %s,\tdestination_addr: %s\t",
				pDataSM->dest_addr_ton, ton_str,
				pDataSM->dest_addr_npi, npi_str,
				pDataSM->destination_addr);
			smpp_send_ascout(debugBuf);
			sprintf(debugBuf, "esm_class: 0x%x,\tregistered_delivery: 0x%x\tdata_coding: 0x%x, current_len=%d\n",
				pDataSM->esm_class,
				pDataSM->registered_delivery,
				pDataSM->data_coding, 
				current_len);
			smpp_send_ascout(debugBuf);
		}
		#endif

		/* optional parameter */
		
		if (current_len < command_length - 16)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				smpp_send_ascout("[Optional parameters]\n");
			}
			#endif 

			memset(opt_param, 0, sizeof(SMPP_OPTIONAL_PARAMETER) * SMPP_OPT_PARAM_NUM);
			opt_num	= smpp_decode_optional_parameter(opt_param, pMsg+current_len, command_length - current_len - 16);
			for (i=0; i<opt_num; i++)
			{
				switch (opt_param[i].tag)
				{
				case SOURCE_PORT:
					memcpy(&pDataSM->source_port, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "source_port: 0x%04X\n", pDataSM->source_port);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SOURCE_ADDR_SUBUNIT:
					memcpy(&pDataSM->source_addr_subunit, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "source_addr_subunit: 0x%02X\n", pDataSM->source_addr_subunit);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SOURCE_NETWORK_TYPE:
					memcpy(&pDataSM->source_network_type, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "source_network_type: 0x%02X\n", pDataSM->source_network_type);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SOURCE_BEARER_TYPE:
					memcpy(&pDataSM->source_bearer_type, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "source_bearer_type: 0x%02X\n", pDataSM->source_bearer_type);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SOURCE_TELEMATICS_ID:
					memcpy(&pDataSM->source_telematics_id, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "source_telematics_id: 0x%04X\n", pDataSM->source_telematics_id);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DESTINATION_PORT:
					memcpy(&pDataSM->destination_port, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "destination_port: 0x%04X\n", pDataSM->destination_port);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DEST_ADDR_SUBUNIT:
					memcpy(&pDataSM->dest_addr_subunit, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "dest_addr_subunit: 0x%02X\n", pDataSM->dest_addr_subunit);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DEST_NETWORK_TYPE:
					memcpy(&pDataSM->dest_network_type, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "dest_network_type: 0x%02X\n", pDataSM->dest_network_type);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DEST_BEARER_TYPE:
					memcpy(&pDataSM->dest_bearer_type, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "dest_bearer_type: 0x%02X\n", pDataSM->dest_bearer_type);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DEST_TELEMATICS_ID:
					memcpy(&pDataSM->dest_telematics_id, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "dest_telematics_id: 0x%02X\n", pDataSM->dest_telematics_id);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SAR_MSG_REF_NUM:
					memcpy(&pDataSM->sar_msg_ref_num, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sar_msg_ref_num: 0x%04X\n", pDataSM->sar_msg_ref_num);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SAR_TOTAL_SEGMENTS:
					memcpy(&pDataSM->sar_total_segments, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sar_total_segments: 0x%02X\n", pDataSM->sar_total_segments);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SAR_SEGMENT_SEQNUM:
					memcpy(&pDataSM->sar_segment_seqnum, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sar_segment_seqnum: 0x%02X\n", pDataSM->sar_segment_seqnum);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case MORE_MESSAGES_TO_SEND:
					memcpy(&pDataSM->more_messages_to_send, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "more_messages_to_send: 0x%02X\n", pDataSM->more_messages_to_send);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case QOS_TIME_TO_LIVE:
					memcpy(&pDataSM->qos_time_to_live, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "qos_time_to_live: 0x%lx\n", pDataSM->qos_time_to_live);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case PAYLOAD_TYPE:
					memcpy(&pDataSM->payload_type, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "payload_type: 0x%02X\n", pDataSM->payload_type);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case MESSAGE_PAYLOAD:
					memcpy(pDataSM->message_payload, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "message_payload: %s\n", pDataSM->message_payload);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SET_DPF:
					memcpy(&pDataSM->set_dpf, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "set_dpf: 0x%02X\n", pDataSM->set_dpf);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case RECEIPTED_MESSAGE_ID:
					memcpy(pDataSM->receipted_message_id, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "receipted_message_id: %s\n", pDataSM->receipted_message_id);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case MESSAGE_STATE:
					memcpy(&pDataSM->message_state, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "message_state: 0x%02X\n", pDataSM->message_state);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case NETWORK_ERROR_CODE:
					memcpy(pDataSM->network_error_code, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "network_error_code: 0x%02X%02X%02X\n", 
							pDataSM->network_error_code[0], 
							pDataSM->network_error_code[1],
							pDataSM->network_error_code[2]);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case USER_MESSAGE_REFERENCE:
					memcpy(&pDataSM->user_message_reference, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "user_message_reference: 0x%02X\n", pDataSM->user_message_reference);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case PRIVACY_INDICATOR:
					memcpy(&pDataSM->privacy_indicator, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "privacy_indicator: 0x%02X\n", pDataSM->privacy_indicator);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case CALLBACK_NUM:
					memcpy(pDataSM->callback_num, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "callback_num: %s\n", pDataSM->callback_num);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case CALLBACK_NUM_PRES_IND:
					memcpy(&pDataSM->callback_num_pres_ind, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "callback_num_pres_ind: 0x%02X\n", pDataSM->callback_num_pres_ind);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case CALLBACK_NUM_ATAG:
					memcpy(&pDataSM->callback_num_atag, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "callback_num_atag: %s\n", pDataSM->callback_num_atag);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SOURCE_SUBADDRESS:
					memcpy(pDataSM->source_subaddress, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "source_subaddress: %s\n", pDataSM->source_subaddress);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DEST_SUBADDRESS:
					memcpy(pDataSM->dest_subaddress, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "dest_subaddress: %s\n", pDataSM->dest_subaddress);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case USER_RESPONSE_CODE:
					memcpy(&pDataSM->user_response_code, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "user_response_code: 0x%02X\n", pDataSM->user_response_code);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case DISPLAY_TIME:
					memcpy(&pDataSM->display_time, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "display_time: 0x%02X\n", pDataSM->display_time);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case SMS_SIGNAL:
					memcpy(&pDataSM->sms_signal, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "sms_signal: 0x%04X\n", pDataSM->sms_signal);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case MS_VALIDITY:
					memcpy(&pDataSM->ms_validity, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "ms_validity: 0x%02X\n", pDataSM->ms_validity);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case MS_MSG_WAIT_FACILITIES:
					memcpy(&pDataSM->ms_msg_wait_facilities, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "ms_msg_wait_facilities: 0x%02X\n", pDataSM->ms_msg_wait_facilities);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case NUMBER_OF_MESSAGES:
					memcpy(&pDataSM->number_of_messages, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "number_of_messages: 0x%02X\n", pDataSM->number_of_messages);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case LANGUAGE_INDICATOR:
					memcpy(&pDataSM->language_indicator, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "language_indicator: 0x%02X\n", pDataSM->language_indicator);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case ALERT_ON_MESSAGE_DELIVERY:
					current_len = current_len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "alert_on_message_delivery: 0x%02X\n", pDataSM->alert_on_message_delivery);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case ITS_REPLY_TYPE:
					memcpy(&pDataSM->its_reply_type, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "its_reply_type: 0x%02X\n", pDataSM->its_reply_type);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				case ITS_SESSION_INFO:
					memcpy(pDataSM->its_session_info, &opt_param[i].value, opt_param[i].len);
					current_len = current_len + opt_param[i].len + 4;
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "its_session_info: 0x%02X%02X\n", 
							pDataSM->its_session_info[0], pDataSM->its_session_info[1]);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				default:
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, 
							"Optional parameter not allowed in DATA_SM. tag=0x%04X",
							opt_param[i].tag);
						smpp_send_error(debugBuf);
					}
					#endif
					smpp_sendResponse(linkNo, DATA_SM_RESP, ESME_ROPTPARNOTALLWD, sequence_number);
					return 0;
				}
			}
		}

		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive DATA_SM: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive DATA_SM: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}
		if(callBackFunc[linkNo].data_proc!= NULL)		
		callBackFunc[linkNo].data_proc(linkNo, (SMPP_MSG *)&smppMsg, sizeof(PDU_DATA_SM));
		break;
	case DATA_SM_RESP:
		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= DataSMResp;
		
		pMsg			= pData->msg;
		pDataSMResp	= &smppMsg.pdu.data_sm_resp;
		smppMsg.message_type	= 0x12;

		memcpy(&pDataSMResp->head, &pData->head, 16);
		
		current_len	= 0;
		c_octet_string_len	= 1;
		for (i=0; i<65; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pDataSMResp->message_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		
		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive DATA_SM_RESP: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive DATA_SM_RESP: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}
		if(callBackFunc[linkNo].data_proc!= NULL)
		callBackFunc[linkNo].data_proc(linkNo, (SMPP_MSG *)&smppMsg, sizeof(PDU_DATA_SM_RESP));
		break;
	case QUERY_SM:
		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= QuerySM;
		smpp_link[linkNo].seq_num	= sequence_number;
		
		pMsg			= pData->msg;
		pQuerySM		= &smppMsg.pdu.query_sm;
		smppMsg.message_type	= 0x13;
		
		memcpy(&pQuerySM->head, &pData->head, 16);

		/* mandatory parameter */
		current_len	= 0;
		c_octet_string_len	= 1;
		for (i=0; i<65; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pQuerySM->message_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pQuerySM->source_addr_ton	= *(pMsg+current_len);
		current_len	+= 1;
		pQuerySM->source_addr_npi	= *(pMsg+current_len);
		current_len	+= 1;
		c_octet_string_len	= 1;
		for (i=0; i<21; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pQuerySM->source_addr, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_send_ascout("[Mandatory parameters]\n");
			smpp_ton_to_string(ton_str, pQuerySM->source_addr_ton);
			smpp_npi_to_string(npi_str, pQuerySM->source_addr_npi);
			sprintf(debugBuf, "message_id: %s,\tsource_addr_ton: 0x%x - %s,\tsource_addr_npi: 0x%x - %s,\tsource_addr: %s\t",
				pQuerySM->message_id,
				pQuerySM->source_addr_ton, ton_str,
				pQuerySM->source_addr_npi, npi_str,
				pQuerySM->source_addr);
			smpp_send_ascout(debugBuf);
		}
		#endif

		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive QUERY_SM: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive QUERY_SM: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}
		if(callBackFunc[linkNo].data_proc!= NULL)
		callBackFunc[linkNo].data_proc(linkNo, (SMPP_MSG *)&smppMsg, sizeof(PDU_QUERY_SM));
		break;
	case QUERY_SM_RESP:
		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= QuerySMResp;
		
		pMsg			= pData->msg;
		pQuerySMResp	= &smppMsg.pdu.query_sm_resp;
		smppMsg.message_type			= 0x14;

		memcpy(&pQuerySMResp->head, &pData->head, 16);
		
		current_len	= 0;
		c_octet_string_len	= 1;
		for (i=0; i<65; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pQuerySMResp->message_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		c_octet_string_len	= 1;
		for (i=0; i<17; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pQuerySMResp->final_date, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pQuerySMResp->message_state	= *(pMsg+current_len);
		current_len	+= 1;
		pQuerySMResp->error_code		= *(pMsg+current_len);
		current_len	+= 1;

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_send_ascout("[Mandatory parameters]\n");
			sprintf(debugBuf, "message_id: %s,\tfinal_date: %s,\tmessage_state: 0x%x,\terror_code: 0x%02X\t",
				pQuerySMResp->message_id,
				pQuerySMResp->final_date,
				pQuerySMResp->message_state,
				pQuerySMResp->error_code);
			smpp_send_ascout(debugBuf);
		}
		#endif

		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive QUERY_SM_RESP: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive QUERY_SM_RESP: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}
		if(callBackFunc[linkNo].data_proc!= NULL)
		callBackFunc[linkNo].data_proc(linkNo, (SMPP_MSG *)&smppMsg, sizeof(PDU_QUERY_SM_RESP));
		break;
	case CANCEL_SM:
		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= CancelSM;
		smpp_link[linkNo].seq_num	= sequence_number;
		
		pMsg			= pData->msg;
		pCancelSM	= &smppMsg.pdu.cancel_sm;
		smppMsg.message_type	= 0x15;
		
		memcpy(&(pCancelSM->head), &pData->head, 16);
		
		/* mandatory parameter */
		current_len	= 0;
		c_octet_string_len	= 1;
		for (i=0; i<6; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pCancelSM->service_type, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		c_octet_string_len	= 1;
		for (i=0; i<65; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pCancelSM->message_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pCancelSM->source_addr_ton	= *(pMsg+current_len);
		current_len	+= 1;
		pCancelSM->source_addr_npi	= *(pMsg+current_len);
		current_len	+= 1;
		c_octet_string_len	= 1;
		for (i=0; i<21; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pCancelSM->source_addr, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pCancelSM->dest_addr_ton	= *(pMsg+current_len);
		current_len	+= 1;
		pCancelSM->dest_addr_npi	= *(pMsg+current_len);
		current_len	+= 1;
		c_octet_string_len	= 1;
		for (i=0; i<21; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pCancelSM->destination_addr, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		
		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_send_ascout("[Mandatory parameters]\n");
			smpp_ton_to_string(ton_str, pCancelSM->source_addr_ton);
			smpp_npi_to_string(npi_str, pCancelSM->source_addr_npi);
			sprintf(debugBuf, "service_type: %s,\tmessage_id: %s,\tsource_addr_ton: 0x%x - %s,\tsource_addr_npi: 0x%x - %s,\tsource_addr: %s\t",
				pCancelSM->service_type,
				pCancelSM->message_id,
				pCancelSM->source_addr_ton, ton_str,
				pCancelSM->source_addr_npi, npi_str,
				pCancelSM->source_addr);
			smpp_send_ascout(debugBuf);
			smpp_ton_to_string(ton_str, pCancelSM->dest_addr_ton);
			smpp_npi_to_string(npi_str, pCancelSM->dest_addr_npi);
			sprintf(debugBuf, "dest_addr_ton: 0x%x - %s,\tdest_addr_npi: 0x%x - %s,\tdestination_addr: %s\t",
				pCancelSM->dest_addr_ton, ton_str,
				pCancelSM->dest_addr_npi, npi_str,
				pCancelSM->destination_addr);
			smpp_send_ascout(debugBuf);
		}
		#endif

		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive CANCEL_SM: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive CANCEL_SM: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}
		if(callBackFunc[linkNo].data_proc!= NULL)
		callBackFunc[linkNo].data_proc(linkNo, (SMPP_MSG *)&smppMsg, sizeof(PDU_CANCEL_SM));
		break;
	case CANCEL_SM_RESP:
		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= CancelSMResp;
		/* fill with SMPP_MSG data structure. */
		pCancelSMResp	= &smppMsg.pdu.cancel_sm_resp;
		smppMsg.message_type	= 0x16;
		
		memcpy(&pCancelSMResp->head, &pData->head, 16);

		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive CANCEL_SM_RESP: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive CANCEL_SM_RESP: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}
		if(callBackFunc[linkNo].data_proc!= NULL)
		callBackFunc[linkNo].data_proc(linkNo, (SMPP_MSG *)&smppMsg, sizeof(PDU_CANCEL_SM_RESP));
		break;
	case REPLACE_SM:
		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= ReplaceSM;
		smpp_link[linkNo].seq_num	= sequence_number;
		
		pMsg			= pData->msg;
		pReplaceSM	= &smppMsg.pdu.replace_sm;
		smppMsg.message_type	= 0x17;
		
		memcpy(&pReplaceSM->head, &pData->head, 16);
		
		current_len	= 0;
		c_octet_string_len	= 1;
		for (i=0; i<6; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pReplaceSM->message_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pReplaceSM->source_addr_ton		= *(pMsg+current_len);
		current_len	+= 1;
		pReplaceSM->source_addr_npi		= *(pMsg+current_len);
		current_len	+= 1;
		c_octet_string_len	= 1;
		for (i=0; i<21; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pReplaceSM->source_addr, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		c_octet_string_len	= 1;
		for (i=0; i<17; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pReplaceSM->schedule_delivery_time, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		c_octet_string_len	= 1;
		for (i=0; i<17; i++)
		{
			if (*(pMsg+current_len+i) != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pReplaceSM->validity_period, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		pReplaceSM->registered_delivery	= *(pMsg+current_len);
		current_len	+= 1;
		pReplaceSM->sm_default_msg_id	= *(pMsg+current_len);
		current_len	+= 1;
		pReplaceSM->sm_length			= *(pMsg+current_len);
		current_len	+= 1;
		memcpy(pReplaceSM->short_message, pMsg+current_len, pReplaceSM->sm_length);
		current_len	+= pReplaceSM->sm_length;

		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_send_ascout("[Mandatory parameters]\n");
			smpp_ton_to_string(ton_str, pReplaceSM->source_addr_ton);
			smpp_npi_to_string(npi_str, pReplaceSM->source_addr_npi);
			sprintf(debugBuf, "message_id: %s,\tsource_addr_ton: 0x%x - %s,\tsource_addr_npi: 0x%x - %s,\tsource_addr: %s\t",
				pReplaceSM->message_id,
				pReplaceSM->source_addr_ton, ton_str,
				pReplaceSM->source_addr_npi, npi_str,
				pReplaceSM->source_addr);
			smpp_send_ascout(debugBuf);
			sprintf(debugBuf, "schedule_delivery_time: %s,\tvalidity_period: %s,\tregistered_delivery: 0x%02X,\tsm_default_msg_id: 0x%02X, sm_length: 02%02X, short_message: %s\n",
				pReplaceSM->schedule_delivery_time,
				pReplaceSM->validity_period,
				pReplaceSM->registered_delivery,
				pReplaceSM->sm_default_msg_id,
				pReplaceSM->sm_length,
				pReplaceSM->short_message);
			smpp_send_ascout(debugBuf);
		}
		#endif

		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive REPLACE_SM: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive REPLACE_SM: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}
		if(callBackFunc[linkNo].data_proc!= NULL)
			callBackFunc[linkNo].data_proc(linkNo, (SMPP_MSG *)&smppMsg, sizeof(PDU_REPLACE_SM));
		break;
	case REPLACE_SM_RESP:
		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= ReplaceSMResp;
		/* fill with SMPP_MSG data structure. */
		pReplaceSMResp	= &smppMsg.pdu.replace_sm_resp;
		smppMsg.message_type	= 0x18;
		memcpy(&pReplaceSMResp->head, &pData->head, 16);
		if(callBackFunc[linkNo].data_proc!= NULL)
			callBackFunc[linkNo].data_proc(linkNo, (SMPP_MSG *)&smppMsg, sizeof(PDU_REPLACE_SM_RESP));
		break;
	case UNBIND:
		if (16 != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive UNBIND: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (16 != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive UNBIND: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= Unbind;
		smpp_link[linkNo].seq_num	= sequence_number;
		break;
	case UNBIND_RESP:
		if (16 != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive UNBIND_RESP: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (16 != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive UNBIND_RESP: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= UnbindResp;
		break;
	case GENERIC_NAK:
		if (16 != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive GENERIC_NAK: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (16 != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive GENERIC_NAK: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= GenericNak;
		smpp_link[linkNo].seq_num	= sequence_number;
		break;
	case OUTBIND:
		pMsg	= pData->msg;
		pOutbind	= &smppMsg.pdu.outbind;
		smpp_link[linkNo].seq_num	= sequence_number;

		/* mandatory parameter */

		current_len	= 0;

		/* system id */
		c_octet_string_len	= 1;
		for (i=0; i<16; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pOutbind->system_id, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		/* password */
		c_octet_string_len	= 1;
		for (i=0; i<9; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pOutbind->password, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;

		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive OUTBIND: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive OUTBIND: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}

		if (strcmp(pOutbind->system_id, smpp_param[linkNo].sys_id) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive OUTBIND: system_id = %s, sys_id in param=%s\n",
					linkNo,
					pOutbind->system_id, 
					smpp_param[linkNo].sys_id);
				smpp_send_error(debugBuf);
			}
			#endif
//			smpp_sendBindResp(linkNo, BindReceiverResp, ESME_RINVSYSID);
			return 0;
		}

		if (strcmp(pOutbind->password, smpp_param[linkNo].password) != 0)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg]link %d receive OUTBIND: password = %s, password in param=%s\n",
					linkNo,
					pOutbind->password, 
					smpp_param[linkNo].password);
				smpp_send_error(debugBuf);
			}
			#endif
//			smpp_sendBindResp(linkNo, BindReceiverResp, ESME_RINVPASWD);
			return 0;
		}

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= Outbind;
		break;
	case ALERT_NOTIFICATION:
		pMsg	= pData->msg;
		pAlertNotification	= &smppMsg.pdu.alert_notification;
		smpp_link[linkNo].seq_num	= sequence_number;

		/* mandatory parameter */

		current_len	= 0;

		/* addr_ton */
		pAlertNotification->source_addr_ton		= *(pMsg+current_len);
		current_len	+= 1;

		/* addr_npi */
		pAlertNotification->source_addr_npi		= *(pMsg+current_len);
		current_len	+= 1;

		/* source_addr */
		c_octet_string_len	= 1;
		for (i=0; i<65; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pAlertNotification->source_addr, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		
		/* esme_addr_ton */
		pAlertNotification->esme_addr_ton		= *(pMsg+current_len);
		current_len	+= 1;

		/* esme_addr_npi */
		pAlertNotification->esme_addr_npi		= *(pMsg+current_len);
		current_len	+= 1;

		/* esme_addr */
		c_octet_string_len	= 1;
		for (i=0; i<65; i++)
		{
			if (pMsg[current_len+i] != 0)	c_octet_string_len++;
			else	break;
		}
		memcpy(pAlertNotification->esme_addr, pMsg+current_len, c_octet_string_len);
		current_len	+= c_octet_string_len;
		
		#ifdef SMPP_DEBUG
		if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
		{
			smpp_ton_to_string(ton_str, pAlertNotification->source_addr_ton);
			smpp_npi_to_string(npi_str, pAlertNotification->source_addr_npi);
			sprintf(debugBuf, "[Mandatory parameters]\nsource_addr_ton: 0x%x - %s, source_addr_npi: 0x%x - %s, source_addr: %s",
				pAlertNotification->source_addr_ton, ton_str, 
				pAlertNotification->source_addr_npi, npi_str, 
				pAlertNotification->source_addr
				);
			smpp_send_ascout(debugBuf);
			smpp_ton_to_string(ton_str, pAlertNotification->esme_addr_ton);
			smpp_npi_to_string(npi_str, pAlertNotification->esme_addr_npi);
			sprintf(debugBuf, "esme_addr_ton: 0x%x - %s, esme_addr_npi: 0x%x - %s, esme_addr: %s\n",
				pAlertNotification->esme_addr_ton, ton_str, 
				pAlertNotification->esme_addr_npi, npi_str, 
				pAlertNotification->esme_addr);
			smpp_send_ascout(debugBuf);
		}
		#endif

		/* Optional parameter */
		if (current_len < command_length - 16)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				smpp_send_ascout("[Optional parameters]\n");
			}
			#endif 

			memset(opt_param, 0, sizeof(SMPP_OPTIONAL_PARAMETER) * SMPP_OPT_PARAM_NUM);
			opt_num	= smpp_decode_optional_parameter(opt_param, pMsg+current_len, command_length - current_len - 16);
			for (i=0; i<opt_num; i++)
			{
				switch (opt_param[i].tag)
				{
				case MS_AVAILABILITY_STATUS:
					memcpy(&pAlertNotification->ms_availability_status, &opt_param[i].value, opt_param[i].len);
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, "ms_availability_status: 0x%02X\n", pAlertNotification->ms_availability_status);
						smpp_send_ascout(debugBuf);
					}
					#endif 
					break;
				default:
					#ifdef SMPP_DEBUG
					if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
					{
						sprintf(debugBuf, 
							"Optional parameter not allowed in ALERT_NOTIFICATION. tag=0x%02X",
							opt_param[i].tag);
						smpp_send_error(debugBuf);
					}
					#endif
					return 0;
				}
			}
		}

		current_len += 16;
		if (current_len != command_length)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive ALERT_NOTIFICATION: decode length = %d, command length=%ld\n",
					linkNo,
					current_len, 
					command_length);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVCMDLEN, 0);
			return 0;
		}
		else if (current_len != len)
		{
			#ifdef SMPP_DEBUG
			if ((smppDebug.debug_switch == 1) || (smppDebug.link_switch[linkNo] == 1))
			{
				sprintf(debugBuf, "[smpp_decode_msg] link %d receive ALERT_NOTIFICATION: decode length = %d, message length=%d\n",
					linkNo,
					current_len, 
					len);
				smpp_send_error(debugBuf);
			}
			#endif
			smpp_sendGenericNack(linkNo, ESME_RINVMSGLEN, 0);
			return 0;
		}

		inter_head[linkNo]	= (inter_head[linkNo]+1)&0x7;
		interEvent[linkNo][inter_head[linkNo]]	= AlertNotification;
		break;	
	default:
		smpp_sendGenericNack(linkNo, ESME_RINVCMDID, sequence_number);
		break;
	}

	#ifdef SMPP_PRINT_SCREEN
//	printf("link %d interEvent[%d] = %d, exterEvent[%d] = %d\n", 
//		linkNo, 
//		inter_head[linkNo], 
//		interEvent[linkNo][inter_head[linkNo]],
//		exter_head[linkNo], 
//		exterEvent[linkNo][inter_head[linkNo]]);
	#endif //end ifdef SMPP_PRINT_SCREEN

	return 1;
}

void smpp_sendBind(int linkNo, int event_id)
{
	SMPP_MSG smppMsg;
	PDU_BIND	*pBind;

	switch (event_id)
	{
	case BindTransmitter:
		pBind	= &smppMsg.pdu.bind_transmitter;
		pBind->head.command_id		= htonl(BIND_TRANSMITTER);
		pBind->head.command_status	= 0;
		pBind->head.sequence_number	= htonl(smpp_getSequenceNumber(linkNo));

		memcpy(pBind->system_id, smpp_param[linkNo].sys_id, 16);
		memcpy(pBind->password, smpp_param[linkNo].password, 9);
		memcpy(pBind->system_type, smpp_param[linkNo].system_type, 13);
		pBind->interface_version	= 0x34;
		pBind->addr_ton	= 0x1;
		pBind->addr_npi	= 0x1;
		memcpy(pBind->address_range,"888",sizeof(pBind->address_range));
//		printf("[smpp]link %d send bind transmitter.\n", linkNo);
		break;
	case BindReceiver:
		pBind	= &smppMsg.pdu.bind_receiver;
		pBind->head.command_id		= htonl(BIND_RECEIVER);
		pBind->head.command_status	= 0;
		pBind->head.sequence_number	= htonl(smpp_getSequenceNumber(linkNo));

		memcpy(pBind->system_id, smpp_param[linkNo].sys_id, 16);
		memcpy(pBind->password, smpp_param[linkNo].password, 9);
		memcpy(pBind->system_type, smpp_param[linkNo].system_type, 13);
		pBind->interface_version	= 0x34;
		pBind->addr_ton	= 0x1;
		pBind->addr_npi	= 0x1;
		memcpy(pBind->address_range,"888",sizeof(pBind->address_range));
//		printf("[smpp]link %d send bind receiver.\n", linkNo);
		break;
	case BindTransceiver:
		pBind	= &smppMsg.pdu.bind_transceiver;
		pBind->head.command_id		= htonl(BIND_TRANSCEIVER);
		pBind->head.command_status	= 0;
		pBind->head.sequence_number	= htonl(smpp_getSequenceNumber(linkNo));

		memcpy(pBind->system_id, smpp_param[linkNo].sys_id, 16);
		memcpy(pBind->password, smpp_param[linkNo].password, 9);
		memcpy(pBind->system_type, smpp_param[linkNo].system_type, 13);
		pBind->interface_version	= 0x34;
		pBind->addr_ton	= 0x1;
		pBind->addr_npi	= 0x1;
		memcpy(pBind->address_range,"888",sizeof(pBind->address_range));
//		printf("[smpp]link %d send bind transceiver.\n", linkNo);
		break;
	default:
		return;
	}
	smpp_encode_msg(linkNo, &smppMsg, event_id);
}

void smpp_sendBindResp(int linkNo, int event_id, DWORD command_status)
{
	SMPP_MSG	smppMsg;

	switch (event_id)
	{
	case BindTransmitterResp:
		smppMsg.pdu.bind_transmitter_resp.head.command_id		= htonl(BIND_TRANSMITTER_RESP);
		smppMsg.pdu.bind_transmitter_resp.head.command_status	= htonl(command_status);
		smppMsg.pdu.bind_transmitter_resp.head.sequence_number	= htonl(smpp_link[linkNo].seq_num);
		memcpy(smppMsg.pdu.bind_transmitter_resp.system_id, smpp_param[linkNo].sys_id, 16);
		smppMsg.pdu.bind_transmitter_resp.sc_interface_version	= SMPP_VERSION;
//		printf("link %d send BindTransmitterResp.\n", linkNo);
		break;
	case BindReceiverResp:
		smppMsg.pdu.bind_receiver_resp.head.command_id			= htonl(BIND_RECEIVER_RESP);
		smppMsg.pdu.bind_receiver_resp.head.command_status		= htonl(command_status);
		smppMsg.pdu.bind_receiver_resp.head.sequence_number		= htonl(smpp_link[linkNo].seq_num);
		memcpy(smppMsg.pdu.bind_receiver_resp.system_id, smpp_param[linkNo].sys_id, 16);
		smppMsg.pdu.bind_transmitter_resp.sc_interface_version	= SMPP_VERSION;
//		printf("link %d send BindReceiverResp.\n", linkNo);
		break;
	case BindTransceiverResp:
		smppMsg.pdu.bind_transceiver_resp.head.command_id		= htonl(BIND_TRANSCEIVER_RESP);
		smppMsg.pdu.bind_transceiver_resp.head.command_status	= htonl(command_status);
		smppMsg.pdu.bind_transceiver_resp.head.sequence_number	= htonl(smpp_link[linkNo].seq_num);
		memcpy(smppMsg.pdu.bind_transceiver_resp.system_id, smpp_param[linkNo].sys_id, 16);
		smppMsg.pdu.bind_transmitter_resp.sc_interface_version	= SMPP_VERSION;
//		printf("link %d send BindTransceiverResp.\n", linkNo);
		break;
	default:
//		printf("[ERROR]send bind resp. no such command id.(=%d)\n", event_id);
		break;
	}
	smpp_encode_msg(linkNo, &smppMsg, event_id);
}

void smpp_sendUnbind(int linkNo)
{
	SMPP_MSG smppMsg;

	smppMsg.pdu.unbind.head.command_length	= htonl(sizeof(PDU_UNBIND));
	smppMsg.pdu.unbind.head.command_id		= htonl(UNBIND);
	smppMsg.pdu.unbind.head.command_status	= 0;
	smppMsg.pdu.unbind.head.sequence_number	= htonl(smpp_getSequenceNumber(linkNo));

	smpp_encode_msg(linkNo, &smppMsg, Unbind);
}

void smpp_sendUnbindResp(int linkNo)
{
	SMPP_MSG smppMsg;

	smppMsg.pdu.unbind_resp.head.command_length		= htonl(sizeof(PDU_UNBIND_RESP));
	smppMsg.pdu.unbind_resp.head.command_id			= htonl(UNBIND_RESP);
	smppMsg.pdu.unbind_resp.head.command_status		= 0;
	smppMsg.pdu.unbind_resp.head.sequence_number	= htonl(smpp_link[linkNo].seq_num);

	smpp_encode_msg(linkNo, &smppMsg, UnbindResp);
}

void smpp_sendEnquireLink(int linkNo)
{
	SMPP_MSG smppMsg;

	smppMsg.pdu.enquire_link.head.command_length	= htonl(sizeof(PDU_ENQUIRE_LINK));
	smppMsg.pdu.enquire_link.head.command_id		= htonl(ENQUIRE_LINK);
	smppMsg.pdu.enquire_link.head.command_status	= 0;
	smppMsg.pdu.enquire_link.head.sequence_number	= htonl(smpp_getSequenceNumber(linkNo));
//	printf("link %d send enquire link.\n", linkNo);
	smpp_encode_msg(linkNo, &smppMsg, EnquireLink);
}

void smpp_sendEnquireLinkResp(int linkNo)
{
	SMPP_MSG smppMsg;

	smppMsg.pdu.enquire_link_resp.head.command_length	= htonl(sizeof(PDU_ENQUIRE_LINK_RESP));
	smppMsg.pdu.enquire_link_resp.head.command_id		= htonl(ENQUIRE_LINK_RESP);
	smppMsg.pdu.enquire_link_resp.head.command_status	= htonl(ESME_ROK);
	smppMsg.pdu.enquire_link_resp.head.sequence_number	= htonl(smpp_link[linkNo].seq_num);
	//printf("link %d send enquire link resp.\n", linkNo);
	smpp_encode_msg(linkNo, &smppMsg, EnquireLinkResp);
}

void smpp_sendOutbind(int linkNo)
{
	SMPP_MSG smppMsg;

	smppMsg.pdu.outbind.head.command_length		= htonl(sizeof(PDU_OUTBIND));
	smppMsg.pdu.outbind.head.command_id			= htonl(OUTBIND);
	smppMsg.pdu.outbind.head.command_status		= 0;
	smppMsg.pdu.outbind.head.sequence_number	= htonl(smpp_getSequenceNumber(linkNo));

	strcpy(smppMsg.pdu.outbind.system_id,smpp_param[linkNo].sys_id);
	memcpy(smppMsg.pdu.outbind.password,smpp_param[linkNo].password,sizeof(smppMsg.pdu.outbind.password));
	
	//printf("link %d send OUTBIND.\n", linkNo);
	smpp_encode_msg(linkNo, &smppMsg, Outbind);
}

void smpp_sendGenericNack(int linkNo, DWORD command_status, DWORD sequence_number)
{
	SMPP_MSG smppMsg;

	smppMsg.pdu.generic_nack.head.command_length	= htonl(sizeof(PDU_GENERIC_NACK));
	smppMsg.pdu.generic_nack.head.command_id		= htonl(GENERIC_NAK);
	smppMsg.pdu.generic_nack.head.command_status	= htonl(command_status);
	smppMsg.pdu.generic_nack.head.sequence_number	= htonl(sequence_number);

	smpp_encode_msg(linkNo, &smppMsg, UnknownCommandID);
}

void smpp_sendResponse(int linkNo, DWORD command_id, DWORD command_status, DWORD sequence_number)
{
	SMPP_MSG smppMsg;
	
	switch (command_id)
	{
	case SUBMIT_SM_RESP:
		smppMsg.pdu.submit_sm_resp.head.command_length	= htonl(16);
		smppMsg.pdu.submit_sm_resp.head.command_id		= htonl(SUBMIT_SM_RESP);
		smppMsg.pdu.submit_sm_resp.head.command_status	= htonl(command_status);
		smppMsg.pdu.submit_sm_resp.head.sequence_number	= htonl(sequence_number);

		smpp_encode_msg(linkNo, &smppMsg, SubmitSMResp);
		break;
	case DELIVER_SM_RESP:
		smppMsg.pdu.deliver_sm_resp.head.command_length	= htonl(16);
		smppMsg.pdu.deliver_sm_resp.head.command_id		= htonl(DELIVER_SM_RESP);
		smppMsg.pdu.deliver_sm_resp.head.command_status	= htonl(command_status);
		smppMsg.pdu.deliver_sm_resp.head.sequence_number= htonl(sequence_number);

		smpp_encode_msg(linkNo, &smppMsg, DeliverSMResp);
		break;
	case DATA_SM_RESP:
		smppMsg.pdu.data_sm_resp.head.command_length	= htonl(16);
		smppMsg.pdu.data_sm_resp.head.command_id		= htonl(DATA_SM_RESP);
		smppMsg.pdu.data_sm_resp.head.command_status	= htonl(command_status);
		smppMsg.pdu.data_sm_resp.head.sequence_number	= htonl(sequence_number);

		smpp_encode_msg(linkNo, &smppMsg, DataSMResp);
		break;
	default:
		break;
	}
}
