smsprotocols/smsstack/wapprot/Src/ws_prvdr.cpp
changeset 0 3553901f7fa8
child 19 630d2f34d719
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smsprotocols/smsstack/wapprot/Src/ws_prvdr.cpp	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,737 @@
+// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+// Implements CWapSmsProvider and CWapSmsProviderWrite
+// 
+//
+
+/**
+ @file
+*/
+
+#include <e32std.h>
+#include <wap_sock.h>
+#include "ws_main.h"
+#include "es_wsms.h"
+#include "WAPDGRM.H"
+#include "ws_obsvr.h"
+#include "smsprot.h"
+#include <es_mbuf.h>
+
+//
+// implementation of CWapSmsProvider
+//
+
+	// CWapSmsProvider policies
+	static _LIT_SECURITY_POLICY_C1(wapSmsProviderSetLocalNamePolicy, ECapabilityNetworkServices );
+	static _LIT_SECURITY_POLICY_C1(wapSmsProviderSetOptionPolicy, ECapability_None);
+	static _LIT_SECURITY_POLICY_C1(wapSmsProviderGetLengthIoctlPolicy,ECapability_None);
+	static _LIT_SECURITY_POLICY_C1(wapSmsProviderGetMessageParamLengthIoctlPolicy,ECapability_None);
+	static _LIT_SECURITY_POLICY_C1(wapSmsProviderGetMessageParametersIoctlPolicy,ECapabilityReadDeviceData);
+	static _LIT_SECURITY_POLICY_C1(wapSmsProviderWritePolicy,ECapabilityNetworkServices);
+
+
+/**
+ *  Factory
+ */
+CWapSmsProvider* CWapSmsProvider::NewL(CWapSmsProtocol* aProtocol)
+	{
+	LOGWAPPROT1("CWapSmsProvider::NewL()");
+
+	CWapSmsProvider* provider=new(ELeave) CWapSmsProvider(aProtocol);
+	CleanupStack::PushL(provider);
+	provider->iWapSmsProviderWrite = CWapSmsProviderWrite::NewL(*provider);
+	CleanupStack::Pop();
+	return provider;
+	} // CWapSmsProvider::NewL
+
+
+/**
+ *  Constructor
+ */
+CWapSmsProvider::CWapSmsProvider(CWapSmsProtocol* aProtocol)
+    :iMessageType(ESmartMessage)
+    ,iProtocol(aProtocol)
+    ,iSendPending(EFalse)
+	,iIoctlOutstanding(EFalse)
+	,iIsNewStyleClient(EFalse)
+	,iStatusReportScheme(EWapSmsDefault)
+    {
+    iRecvdMsgQueue.SetOffset(CWapDatagram::LinkOffset());
+    } // CWapSmsProvider::CWapSmsProvider
+
+
+/**
+ *  Destructor
+ */
+CWapSmsProvider::~CWapSmsProvider()
+    {
+    iSAPLink.Deque();
+
+    while(!iRecvdMsgQueue.IsEmpty())
+        {
+        CWapDatagram* msg = iRecvdMsgQueue.First();
+        iRecvdMsgQueue.Remove(*msg);
+        delete msg;
+        }
+
+    delete iWapSmsProviderWrite;
+    } // CWapSmsProvider::~CWapSmsProvider
+
+
+/**
+ *  Return WAPSMS options
+ */
+TInt CWapSmsProvider::GetOption(TUint aLevel,TUint aName, TDes8& aOption)const
+	{
+	LOGWAPPROT1("CWapSmsProvider::GetOption");
+
+	TInt ret=KErrNone;
+	if (TInt(aLevel)==KWapSmsOptionLevel && TInt(aName)==KWapSmsOptionNameDCS)
+		aOption = TPtrC8((TText8*)&iDataCodingScheme,sizeof(TWapSmsDataCodingScheme));
+	else
+		ret=iProtocol->GetOption(aLevel,aName,aOption,NULL);
+	return ret;
+	} // CWapSmsProvider::GetOption
+
+
+/**
+ *  Set WAPSMS options
+ *  
+ *  @capability None
+ *  
+ */
+TInt CWapSmsProvider::SetOption(TUint aLevel, TUint aName, const TDesC8& aOption)
+	{
+	LOGWAPPROT1("CWapSmsProvider::SetOption");
+	if(!iSecurityChecker || (iSecurityChecker->CheckPolicy(wapSmsProviderSetOptionPolicy,"CWapSmsProvider SetOption policy check") != KErrNone))
+		{
+		return KErrPermissionDenied;
+		}
+
+	TInt ret=KErrNone;
+	if (TInt(aLevel)==KWapSmsOptionLevel)
+	{
+		switch(TInt(aName))
+		{
+		case KWapSmsOptionNameDCS:
+			{
+			iDataCodingScheme = static_cast<TWapSmsDataCodingScheme>(*aOption.Ptr());
+			break;
+			}
+		case KWapSmsOptionWapDatagram:
+			{
+			iMessageType=EWapDatagram;
+			break;
+			}
+		case KWapSmsStatusReportScheme:
+			{
+			iStatusReportScheme = static_cast<TWapSmsStatusReportScheme>(*aOption.Ptr());
+			break;				
+			}
+		case KWapSmsOptionNewStyleClient:
+			{
+			iIsNewStyleClient = ETrue;
+			break;
+			}
+		case KWapSmsOptionOKToDeleteMessage:
+			{
+			//Get the first message from the queue
+			CWapDatagram* msg = iRecvdMsgQueue.First();
+			//Find and delete from SAR
+			TBool found=iProtocol->FindAndDeleteMsg(*msg);
+			if(!found)
+				{
+				LOGWAPPROT1("CWapSmsProvider::SetOption: Error. Couldn't find the message in the SAR for deletion");
+				break;
+				}
+			//Remove from the queue
+			iRecvdMsgQueue.Remove(*msg);
+			delete msg;
+			break;
+			}
+		default:
+			ret=KErrNotSupported;
+		}
+
+	}
+	else
+	{
+		ret=iProtocol->SetOption(aLevel,aName,aOption,NULL);
+	}
+	return ret;
+	} // CWapSmsProvider::SetOption
+
+
+/**
+ *  Shutdown the SAP
+ */
+void CWapSmsProvider::Shutdown(TCloseType aType)
+	{
+	LOGWAPPROT1("CWapSmsProvider::Shutdown");
+	if (aType!=CServProviderBase::EImmediate)
+		iSocket->CanClose();
+	} // CWapSmsProvider::Shutdown
+
+
+/**
+ *  Setup datagram with socket specific options and forward to protocol
+ *  Return zero to block the send - will be completed by CWapSapMessageSender
+ *  
+ *  @capability NetworkServices
+ */
+TInt CWapSmsProvider::Write(RMBufChain& aBufChain, TUint /*options*/, TSockAddr* aAddr)
+	{
+	LOGWAPPROT1("CWapSmsProvider::Write()");
+
+		if(!iSecurityChecker || (iSecurityChecker->CheckPolicy(wapSmsProviderWritePolicy,"CWapSmsProvider Write policy check") != KErrNone))
+		{
+		return KErrPermissionDenied;
+		}
+	// @note: LOGIFH2A2 macro for logging esock write
+#ifdef SMSLOGGERIF
+	TInt length = aBufChain.Length();
+	LOGWAPPROT2("CWapSmsProvider::Write [%d bytes]", length);
+	TBuf8<0x100> dumpBuf;
+	if(length > 0x100)
+		{
+
+		TInt parts=0;
+		TInt offset = 0;
+ 		while (offset < length)
+ 			{
+			aBufChain.CopyOut(dumpBuf, offset);
+			offset += length;
+ 			LOGIF2(_L8("ESock WAP concantonated part: %d"),parts++);
+ 			LOGIF2(_L8("ESOCK WRITE: %S"),&dumpBuf);
+ 			LOGIFH2A2(_L8("ESOCK WRITE: "),dumpBuf);
+ 			}
+
+ 	}
+ 	else
+ 	{
+		aBufChain.CopyOut(dumpBuf, 0);
+ 		LOGIF2(_L8("ESOCK WRITE: %S"),&dumpBuf);
+ 		LOGIFH2A2(_L8("ESOCK WRITE: "),dumpBuf);
+	}
+#endif
+
+	// Note that if this fails somehow it still frees the buf chain and sets itself active - it's
+	// not clear to me whether this is good behaviour but it's the pre-mbuf behaviour too
+	iWapSmsProviderWrite->Start(aBufChain, *aAddr);
+	return KErrNone;
+	} // CWapSmsProvider::Write
+
+
+/**
+ *  Read a datagram off the queue
+ */
+TInt CWapSmsProvider::GetData(RMBufChain& aBufChain, TUint aLength, TUint /*options*/,TSockAddr* aAddr)
+	{
+	LOGWAPPROT1("CWapSmsProvider::GetData()");
+
+	CWapDatagram* msg = iRecvdMsgQueue.First();
+	if(!iIsNewStyleClient)
+		{
+		iRecvdMsgQueue.Remove(*msg);
+		}
+	TInt err = msg->WapDatagram(aBufChain, aLength);
+
+	//@note: LOGIFH2A2 macro for logging esock getdata
+	LOGWAPPROT1("CWapSmsProvider::GetData");
+	// Logging migrated to WapDatagram() for ease of descriptor ref
+
+	if (err > 0 && aAddr)
+		{
+		TWapAddr* wapAddr = reinterpret_cast<TWapAddr*>(aAddr);
+		TInt toPort,fromPort;
+		msg->Ports(fromPort,toPort);
+		wapAddr->SetWapPort(static_cast<TWapPortNumber>(fromPort));
+		TBuf8<KMaxSockAddrSize> addrBuf;
+		addrBuf.Copy(msg->FromAddress());
+		wapAddr->SetWapAddress(addrBuf);
+		}
+	if(!iIsNewStyleClient)
+		{
+		delete msg;
+		}
+	return err > 0? 1: err;		// datagrams are atoms not byte counts
+	} // CWapSmsProvider::GetData
+
+
+/**
+ *  New data has arrived notify ESOCK.
+ */
+void CWapSmsProvider::NewData(CWapDatagram* aMsg)
+	{
+	TBool notifyEsock = EFalse;
+	LOGWAPPROT1("CWapSmsProvider::NewData");
+
+	if(iIoctlOutstanding && iName==KSOGetLength && iIsNewStyleClient)
+		{
+		TPckgBuf<TInt> buf= aMsg->WapDatagramLength();
+		iSocket->IoctlComplete(&buf);
+		iIoctlOutstanding= EFalse;
+		iName= NULL;
+		notifyEsock = ETrue;
+		}
+	else if(iIoctlOutstanding && iName==KSOGetMessageParametersLength && iIsNewStyleClient)
+		{
+		CBufFlat* buffer = aMsg->SmsExternalisedStream();
+		TPckgBuf<TInt> buf = buffer->Size();
+		iSocket->IoctlComplete(&buf);
+		iIoctlOutstanding= EFalse;
+		iName= NULL;
+		notifyEsock = ETrue;
+		}
+	else if(iIoctlOutstanding && iName==KSOGetMessageParameters && iIsNewStyleClient)
+		{
+		CBufFlat* buffer = aMsg->SmsExternalisedStream();
+		TPtr8 buf = buffer->Ptr(0);
+		iSocket->IoctlComplete(&buf);
+		iIoctlOutstanding= EFalse;
+		iName= NULL;
+		notifyEsock = ETrue;
+		}
+	else if(iName!=KSOGetLength && iName!=KSOGetMessageParametersLength && iName!=KSOGetMessageParameters && iIsNewStyleClient)
+		{
+		notifyEsock= EFalse;
+		}
+
+	if(!iIsNewStyleClient || notifyEsock)
+		iSocket->NewData(1);
+	//else we notify ESock in IOCTL for new client
+	} // CWapSmsProvider::NewData
+
+
+/**
+ *  Error happened, notify ESOCK
+ */
+void CWapSmsProvider::Error(TInt aError, TUint aOperationMask)
+	{
+	LOGWAPPROT3("CWapSmsProvider::Error [aError=%d, mask=%d] ", aError, aOperationMask);
+
+	iSocket->Error(aError, aOperationMask);
+	} // CWapSmsProvider::Error
+
+
+/**
+ *  Return the offset to the dblquelink
+ */
+TInt CWapSmsProvider::LinkOffset()
+	{
+	LOGWAPPROT1("CWapSmsProvider::LinkOffset");
+
+	return _FOFF(CWapSmsProvider,iSAPLink);
+	} // CWapSmsProvider::LinkOffset
+
+
+/**
+ *  Return the address associated with the sap
+ */
+void CWapSmsProvider::LocalName(TSockAddr& aAddr) const
+	{
+	LOGWAPPROT1("CWapSmsProvider::LocalName");
+
+	Mem::Copy(&aAddr,&iLocalAddress,sizeof(TSockAddr));
+	} // CWapSmsProvider::LocalName
+
+
+/**
+ *  Set the local address of the sap - called by RSocket::Bind
+ *  
+ *  @capability NetworkServices
+ */
+TInt CWapSmsProvider::SetLocalName(TSockAddr& aAddr)
+	{
+	LOGWAPPROT1("CWapSmsProvider::SetLocalName()");
+
+		if(!iSecurityChecker || (iSecurityChecker->CheckPolicy(wapSmsProviderSetLocalNamePolicy,"CWapSmsProvider SetLocalName policy check") != KErrNone))
+		{
+		return KErrPermissionDenied;
+		}
+	TWapAddr* wapAddr = reinterpret_cast<TWapAddr*>(&aAddr);
+	LOGWAPPROT2("CWapSmsProvider::SetLocalName %d",wapAddr->WapPort());
+	// Due ESOCK interface port EWapPortUnspecified value (-1)  can be transferred as a maximum unsigned 16 int
+	if (wapAddr->WapPort()==EWapPortUnspecified || wapAddr->WapPort()==static_cast<TUint16>(EWapPortUnspecified))
+		{
+		if(!iProtocol->AllocateLocalAddress(iLocalAddress))
+			return KErrInUse;
+		else return KErrNone;
+		}
+
+
+	TInt ret=iProtocol->AddrAlreadyUsedByWAP(*wapAddr,this);
+	if(ret == KErrInUse) return ret;
+	else if(ret == KErrAlreadyExists) return KErrNone;
+
+	TSmsAddr addr;
+	if(wapAddr->Port() <=255)
+		addr.SetSmsAddrFamily(ESmsAddrApplication8BitPort);
+	else
+		addr.SetSmsAddrFamily(ESmsAddrApplication16BitPort);
+
+	addr.SetPort(wapAddr->Port());
+
+	if((iProtocol->SmsProtocol()->SmsAddrIsAlreadyUsed(NULL,addr)))
+		return KErrInUse;
+
+	Mem::Copy(&iLocalAddress,&aAddr,sizeof(TSockAddr));
+	TInt err;
+	TRAP(err,ret = iProtocol->CheckSarL(*wapAddr,this));
+	if(err!=KErrNone)
+			return err;
+	if(ret!=KErrNone)
+		{
+		Error(ret,MSocketNotify::EErrorAllOperations);
+		}
+	return KErrNone;
+	} // RSocket::Bind
+
+
+/**
+ *  Returns true if aAddr matches the local address of the sap
+ */
+TBool CWapSmsProvider::MatchesLocalAddress(const TWapAddr& aAddr)
+	{
+	LOGWAPPROT1("CWapSmsProvider::MatchesLocalAddress");
+
+	return (iLocalAddress == aAddr);
+	} // CWapSmsProvider::MatchesLocalAddress
+
+//
+
+
+/**
+ *  Called to perform specific IO control by the client (i.e. Wap Messaging API).The client is able
+ *  to get the size of the datagram once it has been received or confirm the receipt
+ *  of the message.
+ *  
+ *  Only one ioctl request may be outstanding at any one time.
+ *  
+ *  Implementation of pure virtual CServProviderBase::Ioctl().
+ *  
+ *  @param aLevel the IOCTL level. // Can be only KSolWapProv
+ *  @param aName the IOCTL name.
+ *  @param aOption the IOCTL option.
+ *  
+ */
+void CWapSmsProvider::Ioctl(TUint aLevel,TUint aName,TDes8 * /*aOption*/)
+	{
+	LOGWAPPROT3("CWapSmsProvider::Ioctl [aLevel=%d, aName=%d]", aLevel, aName);
+	LOGWAPPROT2("CWapSmsProtocol::Ioctl [provider=0x%08x]",this);
+
+	iName=aName;
+	switch (aLevel)
+		{
+		case KSolWapProv:
+			{
+		    if(iIoctlOutstanding || !iIsNewStyleClient)
+				{
+				Error(KErrInUse,MSocketNotify::EErrorIoctl);
+				break;
+				}
+			switch (iName)
+				{
+				case KSOGetLength:
+				//
+				// Get the length
+				//
+					{
+					if(!iSecurityChecker || (iSecurityChecker->CheckPolicy(wapSmsProviderGetLengthIoctlPolicy,"CWapSmsProvider GetLength Ioctl policy check") != KErrNone))
+        				{
+        				Error(KErrPermissionDenied,MSocketNotify::EErrorIoctl);
+        				return;
+        				}
+					iIoctlOutstanding = ETrue;
+					//check the queue for any other message for this client and call new data if any exist
+					if(!iRecvdMsgQueue.IsEmpty())
+						{
+						CWapDatagram* msg = iRecvdMsgQueue.First();
+						//check the datagram.
+						if(msg->IsComplete())
+							{
+							NewData(msg);
+							}
+						else
+							{
+							//	else notify the client with error.
+							//	Note:this can happen if client uses 8-Bit port number for 7-Bit datagram
+							Error(KErrGeneral,MSocketNotify::EErrorIoctl);
+							iIoctlOutstanding = EFalse;
+							}
+
+						}
+					break;
+					}
+				
+				case KSOGetMessageParametersLength:
+				//
+				// Get the Message Parameters Length
+				//
+					{
+					if(!iSecurityChecker || (iSecurityChecker->CheckPolicy(wapSmsProviderGetMessageParamLengthIoctlPolicy,"CWapSmsProvider KSOGetMessageParametersLength Ioctl policy check") != KErrNone))
+        				{
+        				Error(KErrPermissionDenied,MSocketNotify::EErrorIoctl);
+        				return;
+        				}
+					iIoctlOutstanding = ETrue;
+					//check the queue for any other message for this client and call new data if any exist
+					if(!iRecvdMsgQueue.IsEmpty())
+						{
+						CWapDatagram* msg = iRecvdMsgQueue.First();
+						//check the datagram.
+						if(msg->IsComplete())
+							{
+							NewData(msg);
+							}
+						else
+							{
+							//	else notify the client with error.
+							//	Note:this can happen if client uses 8-Bit port number for 7-Bit datagram
+							Error(KErrGeneral,MSocketNotify::EErrorIoctl);
+							iIoctlOutstanding = EFalse;
+							}
+
+						}
+					break;
+					}
+					
+				case KSOGetMessageParameters:
+				//
+				// Get the Message Parameters
+				//
+					{
+					if(!iSecurityChecker || (iSecurityChecker->CheckPolicy(wapSmsProviderGetMessageParametersIoctlPolicy,"CWapSmsProvider GetMessageParameters Ioctl policy check") != KErrNone))
+        				{
+        				Error(KErrPermissionDenied,MSocketNotify::EErrorIoctl);
+        				return;
+        				}
+					iIoctlOutstanding = ETrue;
+					//check the queue for any other message for this client and call new data if any exist
+					if(!iRecvdMsgQueue.IsEmpty())
+						{
+						CWapDatagram* msg = iRecvdMsgQueue.First();
+						//check the datagram.
+						if(msg->IsComplete())
+							{
+							NewData(msg);
+							}
+						else
+							{
+							//	else notify the client with error.
+							//	Note:this can happen if client uses 8-Bit port number for 7-Bit datagram
+							Error(KErrGeneral,MSocketNotify::EErrorIoctl);
+							iIoctlOutstanding = EFalse;
+							}
+
+						}
+					break;
+					}
+
+
+				default:
+				//
+				// Unsupported ioctl name
+				//
+					{
+					// Error gracefully
+					Error(KErrNotSupported,MSocketNotify::EErrorIoctl);
+					}
+				}
+			break;
+			}
+		default:
+			// Gracefully error in release build
+			Error(KErrNotSupported,MSocketNotify::EErrorIoctl);
+		}
+	} // CServProviderBase::Ioctl
+
+
+/**
+ *  Cancel IOCTL- can only have one outstanding IOCTL at a time
+ */
+void CWapSmsProvider::CancelIoctl(TUint aLevel,TUint aName)
+	{
+	LOGWAPPROT1("CWapSmsProvider::CancelIoctl()");
+
+	if(!iIoctlOutstanding || (aName!=iName) || (aLevel!=KSolWapProv))
+		{
+		Error(KErrNotFound,MSocketNotify::EErrorIoctl);
+		}
+	else
+		{
+		iIoctlOutstanding=EFalse;
+		}
+	} // CWapSmsProvider::CancelIoctl
+
+
+/**
+ *  Start the provider- does nothing
+ */
+void CWapSmsProvider::Start()
+	{
+	LOGWAPPROT1("CWapSmsProvider::Start()");
+
+	} // CWapSmsProvider::Start
+
+void CWapSmsProvider::AddToQueue(CWapDatagram* aMsg)
+/**
+ *  Adding the datagram to received messages queue
+ */
+	{
+	LOGWAPPROT1("CWapSmsProvider::AddToQueue...");
+
+	iRecvdMsgQueue.AddLast(*aMsg);
+	NewData(aMsg);
+	} // CWapSmsProvider::AddToQueue
+
+
+TInt CWapSmsProvider::SecurityCheck(MProvdSecurityChecker* aSecurityChecker)
+ 	{
+ 	LOGWAPPROT1("CWapSmsProvider::SecurityCheck()");
+
+ 	iSecurityChecker=aSecurityChecker;
+	return KErrNone;
+ 	} // CWapSmsProvider::SecurityCheck
+
+
+TWapSmsStatusReportScheme CWapSmsProvider::GetStatusReportScheme()
+	{
+	return iStatusReportScheme;
+	}
+
+	
+TWapSmsDataCodingScheme CWapSmsProvider::GetDataCodingScheme()
+	{
+	return iDataCodingScheme;
+	}
+
+
+//
+// implementation of CWapSmsProviderWrite
+//
+
+
+/**
+ *  2 phase constructor
+ */
+CWapSmsProviderWrite* CWapSmsProviderWrite::NewL(CWapSmsProvider& aWapSmsProvider)
+	{
+	LOGWAPPROT1("CWapSmsProviderWrite::NewL");
+	CWapSmsProviderWrite* self = new (ELeave) CWapSmsProviderWrite(aWapSmsProvider);
+	CleanupStack::PushL(self);
+	self->iMsgSender = CWapSapMessageSender::NewL(aWapSmsProvider.iProtocol->SmsProtocol(), &aWapSmsProvider);
+	CleanupStack::Pop(self);
+	return self;
+	} // CWapSmsProviderWrite::NewL
+
+
+/**
+ *  Constructor
+ */
+CWapSmsProviderWrite::CWapSmsProviderWrite(CWapSmsProvider& aWapSmsProvider)
+    :CActive(EPriorityStandard)
+    ,iWapSmsProvider(aWapSmsProvider)
+    {
+    LOGWAPPROT1("CWapSmsProviderWrite::CWapSmsProviderWrite()");
+
+    CActiveScheduler::Add(this);
+    } // CWapSmsProviderWrite::CWapSmsProviderWrite
+
+
+/**
+ *  Destructor
+ */
+CWapSmsProviderWrite::~CWapSmsProviderWrite()
+    {
+    Cancel();
+    delete iMsgSender;
+    delete iDes;
+    } // CWapSmsProviderWrite::~CWapSmsProviderWrite
+
+
+void CWapSmsProviderWrite::Start(RMBufChain& aBufChain, TSockAddr& aAddr)
+   	{
+   	LOGWAPPROT1("CWapSmsProviderWrite::Start");
+   	iWapAddr = reinterpret_cast<TWapAddr&>(aAddr);
+   	delete iDes;
+   	iDes = NULL;
+ 	TRAPD(err, (iDes = HBufC8::NewL(aBufChain.Length())) );
+ 	if(err == KErrNone)
+ 		{
+ 		TPtr8 desBuf(iDes->Des());
+ 		desBuf.SetLength(aBufChain.Length());
+ 		aBufChain.CopyOut(desBuf, 0);
+ 		// Logging migrated from CWapSmsProvider::GetData
+ 		LOGSMSIF2("ESOCK READ: \"%S\"", iDes);
+ 		LOGSMSIFHEXBUF(_L8("ESOCK READ"), *iDes);
+ 		LOGSMSIFTIMESTAMP();
+ 		}
+ 	aBufChain.Free();
+
+   	TRequestStatus* status = &iStatus;
+   	User::RequestComplete(status, err);
+   	SetActive();
+   	} // CWapSmsProviderWrite::Start
+
+
+void CWapSmsProviderWrite::RunL()
+	{
+	LOGWAPPROT1("CWapSmsProviderWrite::RunL");
+	User::LeaveIfError(iStatus.Int());
+
+	//no need to use cleanup stack
+	CWapDatagram* datagram = CWapDatagram::NewL(*iDes);
+
+	if (iWapSmsProvider.iDataCodingScheme == EWapSms7BitDCS)
+		datagram->SetAlphabet(TSmsDataCodingScheme::ESmsAlphabet7Bit);
+	else
+		datagram->SetAlphabet(TSmsDataCodingScheme::ESmsAlphabet8Bit);
+	
+	if (iWapSmsProvider.iStatusReportScheme == EWapSmsTPSRR)
+		{
+		datagram->SetStatusReportScheme(ETPSRRScheme);
+		}
+	else
+		{
+		datagram->SetStatusReportScheme(EDefaultScheme);
+		} 
+		
+	TBuf<KMaxSockAddrSize> addrBuf;
+	addrBuf.Copy(iWapAddr.WapAddress());
+	datagram->SetToAddress(addrBuf);
+	TInt fromPort = iWapSmsProvider.iLocalAddress.WapPort();
+	datagram->SetPorts(fromPort, iWapAddr.WapPort());
+
+	iMsgSender->SendDatagramL(datagram); // takes ownership of datagram
+	} // CWapSmsProviderWrite::RunL
+
+
+TInt CWapSmsProviderWrite::RunError(TInt aError)
+	{
+	LOGWAPPROT1("CWapSmsProviderWrite::RunError");
+	iWapSmsProvider.Error(aError, MSocketNotify::EErrorSend);
+	return KErrNone;
+	} // CWapSmsProviderWrite::RunError
+
+
+void CWapSmsProviderWrite::DoCancel()
+	{
+	LOGWAPPROT1("CWapSmsProviderWrite::DoCancel");
+	TRequestStatus* status = &iStatus;
+	User::RequestComplete(status, KErrCancel);
+	} // CWapSmsProviderWrite::DoCancel
+
+
+// EOF - WS_PRVDR.CPP