Click here to Skip to main content
15,888,610 members
Articles / Desktop Programming / MFC

An SMPPLIB with COM Support

Rate me:
Please Sign up or sign in to vote.
4.94/5 (25 votes)
27 Oct 20039 min read 332K   5.5K   87  
It is an SMPP implementation of v3.3 and v3.4 ( partial support). You can use it to connect to SMSC and send/receive SMS.
// EsmeTransceiverCom.cpp : Implementation of CEsmeTransceiverCom

#include "stdafx.h"
#include "EsmeTransceiverCom.h"


// CEsmeTransceiverCom

STDMETHODIMP CEsmeTransceiverCom::bind(BSTR sysid, BSTR passwd, BSTR systype, ISmppAddressCom* iaddr, VARIANT_BOOL* pret)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	// TODO: Add your implementation code here
	USES_CONVERSION;

	LPSTR sid, pwd, stype;

	sid = OLE2A(sysid);
	pwd = OLE2A(passwd);
	stype = OLE2A(systype);

	SHORT npi;
	SHORT ton;
	BSTR addr;

	iaddr->get_NPI(&npi);
	iaddr->get_TON(&ton);
	iaddr->get_Address(&addr);

	LPSTR paddr = OLE2A(addr);
	CSmppAddress srange(ton, npi, paddr);

	SysFreeString(addr);

	//setting finished, going to bind to SMSC

	EnterCriticalSection(&m_cs);				//enter m_cs

	ResetEvent(m_response_event);
	CEsmeTransceiver::bind(sid, pwd, stype, srange);

	HANDLE hwait[] = {m_response_event, m_hDisconnectEvent, m_hKillEvent};

	DWORD ret = WaitForMultipleObjects(3, hwait, FALSE, 30000);

	if (ret == WAIT_OBJECT_0)
	{
		if (m_last_error)
			*pret = VARIANT_FALSE;
		else
			*pret = VARIANT_TRUE;
	}
	else
		*pret = VARIANT_FALSE;

	ResetEvent(m_response_event);

	LeaveCriticalSection(&m_cs);				//leave m_cs

	return S_OK;
}

STDMETHODIMP CEsmeTransceiverCom::unbind(VARIANT_BOOL* pret)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	// TODO: Add your implementation code here

	EnterCriticalSection(&m_cs);				//enter m_cs

	ResetEvent(m_response_event);
	CEsmeTransceiver::unbind();

	HANDLE hwait[] = {m_response_event, m_hDisconnectEvent, m_hKillEvent};

	DWORD ret = WaitForMultipleObjects(3, hwait, FALSE, 30000);

	if (ret == WAIT_OBJECT_0)
	{
		if (m_last_error)
			*pret = VARIANT_FALSE;
		else
			*pret = VARIANT_TRUE;
	}
	else
		*pret = VARIANT_FALSE;

	ResetEvent(m_response_event);

	LeaveCriticalSection(&m_cs);				//leave m_cs

	return S_OK;
}

STDMETHODIMP CEsmeTransceiverCom::enquireLink(VARIANT_BOOL* pret)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	// TODO: Add your implementation code here

	EnterCriticalSection(&m_cs);				//enter m_cs

	ResetEvent(m_response_event);
	CEsmeTransceiver::enquireLink();

	HANDLE hwait[] = {m_response_event, m_hDisconnectEvent, m_hKillEvent};

	DWORD ret = WaitForMultipleObjects(3, hwait, FALSE, 30000);

	if (ret == WAIT_OBJECT_0)
	{
		if (m_last_error)
			*pret = VARIANT_FALSE;
		else
			*pret = VARIANT_TRUE;
	}
	else
		*pret = VARIANT_FALSE;

	ResetEvent(m_response_event);

	LeaveCriticalSection(&m_cs);				//leave m_cs

	return S_OK;
}

STDMETHODIMP CEsmeTransceiverCom::init(BSTR svrip, LONG port)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	// TODO: Add your implementation code here

	USES_CONVERSION;

	LPSTR sip = OLE2A(svrip);

	CEsmeTransceiver::init(sip, port);

	return S_OK;
}

STDMETHODIMP CEsmeTransceiverCom::close(void)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	// TODO: Add your implementation code here
	CEsmeTransceiver::close();

	return S_OK;
}

STDMETHODIMP CEsmeTransceiverCom::get_Connected(VARIANT_BOOL* pVal)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	// TODO: Add your implementation code here

	if (CEsmeTransceiver::isConnected())
	{
		*pVal = VARIANT_TRUE;
	}
	else
	{
		*pVal = VARIANT_FALSE;
	}

	return S_OK;
}

STDMETHODIMP CEsmeTransceiverCom::submitMessage(ISubmitSMCom* isubmit, BSTR* pMsgid, VARIANT_BOOL* pret)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());

	// TODO: Add your implementation code here
	CSubmitSM sm;

	USES_CONVERSION;

	BSTR svrtype;
	isubmit->get_ServiceType(&svrtype);
	LPSTR stype = OLE2A(svrtype);

	sm.setServiceType(stype);

	SHORT dc, esm, repif, priflag, proid, defmsg, regdel;
	
	isubmit->get_dataCoding(&dc);
	isubmit->get_esmClass(&esm);
	isubmit->get_replaceIfPresent(&repif);
	isubmit->get_priorityFlag(&priflag);
	isubmit->get_protocolID(&proid);
	isubmit->get_smDefaultMsgId(&defmsg);
	isubmit->get_registeredDelivery(&regdel);

	sm.setDataCoding(dc);
	sm.setEsmClass(esm);
	sm.setReplaceIfPresent(repif);
	sm.setPriorityFlag(priflag);
	sm.setProtocolId(proid);
	sm.setSmDefaultMsgId(defmsg);
	sm.setRegisteredDelivery(regdel);

	SHORT ton, npi;
	BSTR addr;

	ISmppAddressCom *iaddr;

	//getting source
	isubmit->get_Source(&iaddr);
	iaddr->get_TON(&ton);
	iaddr->get_NPI(&npi);
	iaddr->get_Address(&addr);
	iaddr->Release();

	LPSTR paddr = OLE2A(addr);
	SysFreeString(addr);

	CSmppAddress src(ton, npi, paddr);

	//getting destination
	isubmit->get_Destination(&iaddr);
	iaddr->get_TON(&ton);
	iaddr->get_NPI(&npi);
	iaddr->get_Address(&addr);
	iaddr->Release();

	paddr = OLE2A(addr);
	SysFreeString(addr);

	CSmppAddress dst(ton, npi, paddr);

	//assing source and destination
	sm.setSource(src);
	sm.setDestination(dst);

	ISmppDateCom *idate;
	BSTR strdate;

	//getting ScheduledDelivery
	isubmit->get_scheduledDelivery(&idate);
	idate->toString(&strdate);
	LPSTR sdt = OLE2A(strdate);
	idate->Release();

	CSmppDate schdel;
	schdel.setDate(sdt);

	//getting ValidityPeriod
	isubmit->get_validityPeriod(&idate);
	idate->toString(&strdate);
	sdt = OLE2A(strdate);
	idate->Release();

	CSmppDate valprd;
	valprd.setDate(sdt);

	//assign scheduledDelivery and validityPeriod to sm
	sm.setScheduledDelivery(schdel);
	sm.setValidityPeriod(valprd);

	VARIANT var;
	isubmit->getMessage(&var);
	SAFEARRAY *psa = var.parray;
	BYTE *padata;

	int nsize = psa->rgsabound->cElements;
	SafeArrayAccessData(psa, (void **) &padata);
	sm.setMessage(padata, nsize);
	SafeArrayUnaccessData(psa);


	//
	//okay, we've setting up the SubmitSM, send it
	//

	EnterCriticalSection(&m_cs);				//enter m_cs

	ResetEvent(m_response_event);
	CEsmeTransceiver::submitMessage(sm);

	HANDLE hwait[] = {m_response_event, m_hDisconnectEvent, m_hKillEvent};

	DWORD ret = WaitForMultipleObjects(3, hwait, FALSE, 30000);

	if (ret == WAIT_OBJECT_0)
	{
		if (m_last_error)
			*pret = VARIANT_FALSE;
		else
		{
			*pret = VARIANT_TRUE;
			*pMsgid = m_last_msg_id.AllocSysString();
		}
	}
	else
		*pret = VARIANT_FALSE;

	ResetEvent(m_response_event);

	LeaveCriticalSection(&m_cs);				//leave m_cs

	return S_OK;
}

//registered callback to handle SMPP packets sent from SMSC
//(must be static class method or global procedure)
void __stdcall CEsmeTransceiverCom::processPacketProc(CPacketBase *pak, LPVOID param)
{
	CEsmeTransceiverCom *pTrans = (CEsmeTransceiverCom *) param;

	//route to instance method, so it can access instance attributes
	pTrans->processPacket(pak);
}


//actuallly SMPP packets are in turns handled here 
void CEsmeTransceiverCom::processPacket(CPacketBase *pak)
{

		switch (pak->getCommandId())
		{


			case SMPP_ENQUIRE_LINK:
			{
				//SMSC requested us to send querylink response

				CEnquireLink *pPak;
				pPak = static_cast<CEnquireLink *>(pak);

				//automatic reponse for enquery link
				CEnquireLinkResp elresp(*pPak);
				sendPacket(elresp);
				
			}
			break;

			case SMPP_DELIVER_SM:
			{
				//got a deliver SM
				CDeliverSM *pPak;
				pPak = static_cast<CDeliverSM *>(pak);

				//automatic response deliversm reponse
				CDeliverSMResp dresp (*pPak);
				sendPacket(dresp);

				//notify client for the deliver SM
				NotifyClientDeliverSM(pPak);
			}
			break;

			case SMPP_BIND_TRANSCEIVER_RESP:
			{
				//bind transceiver response

				CBindTransceiverResp *pPak;
				pPak = static_cast<CBindTransceiverResp *>(pak);

				if (pPak->getCommandStatus() == 0)
				{
					m_last_error = false;
				}
				else
				{
					m_last_error = true;
				}
				SetEvent(m_response_event);
			}
			break;

			
			case SMPP_UNBIND_RESP:
			{
				//unbind response

				CUnbindResp *pPak;
				pPak = static_cast<CUnbindResp *>(pak);

				if (pPak->getCommandStatus() == 0)
				{
					m_last_error = false;
				}
				else
				{
					m_last_error = true;
				}
				SetEvent(m_response_event);
			}
			break;


			case SMPP_SUBMIT_SM_RESP:
			{
				//Submit Short Message Response

				CSubmitSMResp *pPak;
				pPak = static_cast<CSubmitSMResp *>(pak);

				if (pPak->getCommandStatus() == 0)
				{
					m_last_msg_id = pPak->getMessageId();
					m_last_error = false;
				}
				else
				{
					m_last_error = true;
				}
				SetEvent(m_response_event);
			}
			break;


			case SMPP_ENQUIRE_LINK_RESP:
			{
				//Previous EnquireLink is responsed

				CEnquireLinkResp *pPak;
				pPak = static_cast<CEnquireLinkResp *>(pak);

				if (pPak->getCommandStatus() == 0)
				{
					m_last_error = false;
					SetEvent(m_response_event);
				}
				else
				{
					m_last_error = true;
				}
				SetEvent(m_response_event);
			}
			break;


			default:
				break;
		}
}

void CEsmeTransceiverCom::NotifyClientDeliverSM(CDeliverSM *pak)
{
	IDeliverSMCom *pVal;

	//create an CDeliverSMCom instance to return
	CoCreateInstance(	CLSID_DeliverSMCom,
						NULL,
						CLSCTX_ALL,
						IID_IDeliverSMCom,
						(void **) &pVal);

	USES_CONVERSION;

	pVal->put_dataCoding(pak->getDataCoding());
	pVal->put_esmClass(pak->getEsmClass());
	pVal->put_replaceIfPresent(pak->getReplaceIfPresent());
	pVal->put_priorityFlag(pak->getPriorityFlag());
	pVal->put_protocolID(pak->getProtocolId());
	pVal->put_smDefaultMsgId(pak->getSmDefaultMsgId());
	pVal->put_registeredDelivery(pak->getRegisteredDelivery());


	//create an CSmppAddressCom for setting addresses
	ISmppAddressCom *iaddr;
	CoCreateInstance(	CLSID_SmppAddressCom,
						NULL,
						CLSCTX_ALL,
						IID_ISmppAddressCom,
						(void **) &iaddr);

	BSTR addrstr;

	//Setting source
	CSmppAddress source = pak->getSource();
	iaddr->put_TON(source.m_addr_ton);
	iaddr->put_NPI(source.m_addr_npi);
	addrstr = source.m_addr.AllocSysString();
	iaddr->put_Address(addrstr);
	SysFreeString(addrstr);

	pVal->put_Source(iaddr);

	//Setting Destination
	CSmppAddress destination = pak->getDestination();
	iaddr->put_TON(destination.m_addr_ton);
	iaddr->put_NPI(destination.m_addr_npi);
	addrstr = destination.m_addr.AllocSysString();
	iaddr->put_Address(addrstr);
	SysFreeString(addrstr);

	pVal->put_Destination(iaddr);

	iaddr->Release();


	//create an CSmppDate for setting dates
	ISmppDateCom *idate;
	CoCreateInstance(	CLSID_SmppDateCom,
						NULL,
						CLSCTX_ALL,
						IID_ISmppDateCom,
						(void **) &idate);
	
	BSTR strdate;

	//setting scheduleddelivery
	CSmppDate schdate = pak->getScheduledDelivery();
	strdate = schdate.toString().AllocSysString();
	idate->setDate(strdate);
	pVal->put_scheduledDelivery(idate);
	SysFreeString(strdate);

	//setting validityperiod
	CSmppDate vldprd = pak->getValidityPeriod();
	strdate = vldprd.toString().AllocSysString();
	idate->setDate(strdate);
	pVal->put_validityPeriod(idate);
	SysFreeString(strdate);

	idate->Release();

	//setting message
	PBYTE pdata;
	uint32 nsize;
	pak->getMessage(pdata, nsize);

	VARIANT var;

	VariantInit(&var);
	var.vt = VT_ARRAY | VT_UI1;
	SAFEARRAY *psa;
	SAFEARRAYBOUND bounds = {nsize, 0};
	psa = SafeArrayCreate(VT_UI1, 1, &bounds);
	BYTE *padata;
	SafeArrayAccessData(psa, (void **) &padata);
	memcpy(padata, pdata, nsize);
	SafeArrayUnaccessData(psa);
	var.parray = psa;

	pVal->setMessage(var);

	//fire notification event
	Fire_OnDeliverSM(pVal);

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Hong Kong Hong Kong
I'm a guy situated in Hong Kong with some knowledges in Java, VC++, C#, database, client-server, distributed, and mutithreaded computing and so on. I've been working in various companies as engineer, consultant, programmer.

Lately I was mainly working in banking & financial industries. Personally, I'm working on a trading application on my own now.

Comments and Discussions