smsprotocols/smsstack/wapprot/Src/wapdgrm.cpp
changeset 0 3553901f7fa8
child 5 7ef16719d8cb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smsprotocols/smsstack/wapprot/Src/wapdgrm.cpp	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,708 @@
+// Copyright (c) 1997-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:
+//
+
+#include "gsmubuf.h"
+#include "gsmuset.h"
+#include "Gsmuelem.h"
+#include "Gsmumsg.h"
+#include "gsmusar.h"
+#include "gsmupdu.h"
+#include "WAPDGRM.H"
+#include "ws_main.h"
+#include "smsstackutils.h"
+
+//
+// For incoming short message
+//
+CWapDatagram* CWapDatagram::NewL(const CSmsMessage& aSms)
+    {
+    LOGWAPPROT2("CWapDatagram::NewL(): aSms=0x%08x", (TInt) &aSms);
+
+    CWapDatagram* datagram = new (ELeave)CWapDatagram();
+
+    CleanupStack::PushL(datagram);
+    datagram->ConstructL(aSms);
+    CleanupStack::Pop();
+
+    LOGWAPPROT2("CWapDatagram::NewL(): iFromPort: %d", datagram->iFromPort);
+    LOGWAPPROT2("CWapDatagram::NewL(): iToPort: %d", datagram->iToPort);
+    LOGWAPPROT2("CWapDatagram::NewL(): iReference: %d", datagram->iReference);
+    LOGWAPPROT2("CWapDatagram::NewL(): iTotalSegments: %d", datagram->iTotalSegments);
+    LOGWAPPROT2("CWapDatagram::NewL(): iSegmentNumber: %d", datagram->iSegmentNumber);
+    LOGWAPPROT2("CWapDatagram::NewL(): iIsComplete: %d", datagram->iIsComplete);
+    LOGWAPPROT2("CWapDatagram::NewL(): iReference: %d", datagram->iReference);
+    LOGWAPPROT2("CWapDatagram::NewL(): iIsTextHeader: %d", datagram->iIsTextHeader);
+    LOGWAPPROT2("CWapDatagram::NewL(): iLogServerId: %d", datagram->iLogServerId);
+    LOGWAPPROT2("CWapDatagram::NewL(): i16BitPorts: %d", datagram->i16BitPorts);
+
+    // assert destination port
+	if (datagram->i16BitPorts)
+		{
+		if (datagram->iToPort>=0  &&  datagram->iToPort<=65535)
+			{
+			LOGWAPPROT1("iToPort OK");
+			}
+		else
+			{
+			LOGWAPPROT1("iToPort FAILED");
+			}
+		}
+    else
+		{
+        if (datagram->iToPort>=0  &&  datagram->iToPort<=255)
+			{
+		    LOGWAPPROT1("iToPort OK");
+			}
+		else
+			{
+			LOGWAPPROT1("iToPort FAILED");
+			}
+		}
+
+	if (datagram->i16BitPorts)
+		{
+		if (datagram->iFromPort>=0  &&  datagram->iFromPort<=65535)
+			{
+			LOGWAPPROT1("iFromPort OK");
+			}
+		else
+			{
+			LOGWAPPROT1("iFromPort FAILED");
+			}
+		}
+    else
+		{
+        if (datagram->iFromPort>=0  &&  datagram->iFromPort<=255)
+			{
+		    LOGWAPPROT1("iFromPort OK");
+			}
+		else
+			{
+			LOGWAPPROT1("iFromPort FAILED");
+			}
+		}
+
+    return datagram;
+    } // CWapDatagram::NewL
+
+
+//
+// For outgoing short messages
+//
+CWapDatagram* CWapDatagram::NewL(const TDesC8& aSendBuffer)
+    {
+    LOGWAPPROT2("CWapDatagram::NewL(): aSendBuffer=0x%08x", (TInt) &aSendBuffer);
+
+    CWapDatagram* datagram = new (ELeave)CWapDatagram();
+
+    CleanupStack::PushL(datagram);
+    datagram->Construct(aSendBuffer);
+    CleanupStack::Pop();
+
+    return datagram;
+    } // CWapDatagram::NewL
+
+
+CWapDatagram::~CWapDatagram()
+    {
+    LOGWAPPROT1("CWapDatagram::~CWapDatagram()");
+
+	delete iRecvbuf;
+    delete iBuffer;
+    delete iSegment;
+    } // CWapDatagram::~CWapDatagram
+
+
+//
+// What about service centre address ?
+// aSmsMessageArray contains CSmsMessage objects
+//
+void CWapDatagram::EncodeConcatenatedMessagesL(RFs& aFs, CArrayPtr<CSmsMessage>& aSmsMessageArray)
+    {
+    LOGWAPPROT2("CWapDatagram::EncodeConcatenatedMessagesL(): %d messages", aSmsMessageArray.Count());
+
+    // Couple of checkings makes sense
+    __ASSERT_DEBUG(iToPort >=0 && iToAddress.Length()>=0
+            && (iUserDataSettings.Alphabet()==TSmsDataCodingScheme::ESmsAlphabet8Bit
+                 || iUserDataSettings.Alphabet()==TSmsDataCodingScheme::ESmsAlphabet7Bit),
+            Panic(KPanicUsageError));
+
+    // Determine CSmsMessage encoding by character width
+    if (iUserDataSettings.Alphabet() == TSmsDataCodingScheme::ESmsAlphabet8Bit)
+        {
+        CSmsBufferBase* SmsBuffer = CSmsBuffer::NewL();
+
+        CleanupStack::PushL(SmsBuffer);
+        ConvertL(iSendBuffer,*SmsBuffer);
+        CleanupStack::Pop(); // SmsBuffer, popped here since it is pushed again in the following NewL call
+        CSmsMessage* SmsMessage = CSmsMessage::NewL(aFs, CSmsPDU::ESmsSubmit,SmsBuffer,EFalse);
+        CleanupStack::PushL(SmsMessage);
+        // one and only object
+        aSmsMessageArray.AppendL(SmsMessage);
+        CleanupStack::Pop(); // SmsMessage
+
+        SetSmsMessageSettingsL(*SmsMessage,ETrue);
+        }
+    else
+        {
+        // contruct TWapTextMessage object
+        TWapTextMessage* Segment = new (ELeave) TWapTextMessage(KNullDesC8);
+        CleanupStack::PushL(Segment);
+        CArrayPtrFlat<HBufC8>* SegmentArray = new (ELeave) CArrayPtrFlat<HBufC8> (8);
+        CleanupStack::PushL(SegmentArray);
+        CleanupResetAndDestroyPushL(*SegmentArray);
+
+        Segment->SetDestinationPort(iToPort,i16BitPorts);
+        Segment->SetSourcePort(iFromPort,i16BitPorts);
+        Segment->SetReferenceNumber(iReference);
+        Segment->SetUserData(iSendBuffer);
+        Segment->SetOtherHeader(iOtherHeader);
+        Segment->EncodeSegmentsL(*SegmentArray);
+
+        // contruct array of CSmsMessages
+        TInt Count = SegmentArray->Count();
+        for (TInt i=0; i<Count; i++)
+            {
+            CSmsBufferBase* SmsBuffer = CSmsBuffer::NewL();
+
+            CleanupStack::PushL(SmsBuffer);
+            ConvertL(*(SegmentArray->At(i)),*SmsBuffer);
+            CleanupStack::Pop(); // SmsBuffer, popped here since it is pushed again in the following NewL call
+            CSmsMessage* SmsMessage=CSmsMessage::NewL(aFs, CSmsPDU::ESmsSubmit,SmsBuffer,EFalse);
+            CleanupStack::PushL(SmsMessage);
+            aSmsMessageArray.AppendL(SmsMessage);
+            CleanupStack::Pop(); // SmsMessage
+
+            SetSmsMessageSettingsL(*SmsMessage,EFalse);
+            }
+        CleanupStack::PopAndDestroy(3, Segment);  // SegmentArray elements (Reset and Destroy), SegmentArray, Segment
+
+        }
+    } // CWapDatagram::EncodeConcatenatedMessagesL
+
+void CWapDatagram::DecodeConcatenatedMessagesL(CArrayPtr<TSegmentData>& aSmsMessageArray)
+    {
+    LOGWAPPROT1("CWapDatagram::DecodeConcatenatedMessagesL()");
+
+    // The TSegmentData elements are in the random order in the array
+    TInt Count = aSmsMessageArray.Count();
+    TInt i=0;
+
+    if (Count > 0)
+        {
+        TInt DataLength = 0;  // total length of data
+        TInt TempLength = 0;
+
+        // Every TSegmentData should be equal length except last segment
+        // Use that 'constant' segment length as indexes
+        // Count the actual data length
+        for(i=0; i<Count; i++)
+            {
+            TempLength = aSmsMessageArray.At(i)->iData.Length();
+            DataLength += TempLength;
+            }
+
+        TSegmentData* Segment = NULL;
+
+        if (iBuffer)
+            {
+            delete iBuffer;
+            iBuffer = NULL;
+            }
+        iBuffer = HBufC8::NewL(DataLength );
+
+        TPtr8 BufferPtr(iBuffer->Des());
+        BufferPtr.SetLength(DataLength );
+
+        TInt segmentStartPosition=0;
+
+        for(i=0; i<Count; i++)
+            {
+              if (segmentStartPosition >= DataLength)  
+                  {
+                  // Once the start position is out of range,
+                  // there is no point in continuing reconstructing the
+                  // wapdatagram.
+                  break;
+				 }			
+			
+            Segment = aSmsMessageArray.At(i);
+			TPtr8 CopyBufferPtr(&(BufferPtr[segmentStartPosition]),0,160);
+			CopyBufferPtr.Copy(Segment->iData);
+ 			segmentStartPosition+=Segment->iData.Length();
+            }
+        }
+    iIsComplete = ETrue;
+    } // CWapDatagram::DecodeConcatenatedMessagesL
+
+
+void CWapDatagram::InternalizeL(RReadStream& aStream)
+    {
+    aStream >> iUserDataSettings;
+    aStream >> iToAddress;
+    iToPort = aStream.ReadInt32L();
+    aStream >> iFromAddress;
+    iFromPort = aStream.ReadInt32L();
+    TInt64 time;
+    aStream >> time;
+    iTime = time;
+    iUTCOffset = aStream.ReadInt32L();
+    iIsTextHeader = aStream.ReadInt32L();
+    iReference = aStream.ReadInt32L();
+    iTotalSegments = aStream.ReadInt32L();
+    iSegmentNumber = aStream.ReadInt32L();
+    iLogServerId = aStream.ReadInt32L();
+    iVersionNumber = aStream.ReadInt32L();
+    iSpare1 =  aStream.ReadInt32L();
+    iSpare2 =  aStream.ReadInt32L();
+    iSpare3 =  aStream.ReadInt32L();
+	
+    // Required for version 1, which is reading and internalizing extra SMS parameters from stream
+    if(iVersionNumber == EFirstVersion)
+    	{
+    	TInt length = aStream.ReadInt32L();
+    	if(length>0)
+    		{
+    		HBufC8* smsBuffer=HBufC8::NewMaxLC(length);
+			TPtr8 recvbuftmp = smsBuffer->Des();
+			aStream >> recvbuftmp;
+			if(!iRecvbuf)
+				{
+				iRecvbuf = CBufFlat::NewL(KSmsBufferExpansion);
+				}
+			iRecvbuf->ResizeL(recvbuftmp.Size());
+			iRecvbuf->Write(0, recvbuftmp);
+			CleanupStack::PopAndDestroy(smsBuffer);
+			}
+    	}
+    
+    } // CWapDatagram::InternalizeL
+
+
+//
+//	Reads iBuffer from stream (for 8Bit messages)
+//
+void CWapDatagram::InternalizeBufferL(RReadStream& aStream)
+	{
+	TInt length;
+	length=aStream.ReadInt32L();
+	iBuffer=HBufC8::NewMaxL(length);
+	TPtr8 tmp = iBuffer->Des();
+	aStream >> tmp;
+	iIsComplete = ETrue;
+	}
+
+
+void CWapDatagram::ExternalizeL(RWriteStream& aStream) const
+    {
+    aStream << iUserDataSettings;
+    aStream << iToAddress;
+    aStream.WriteInt32L(iToPort);
+
+    aStream << iFromAddress;
+    aStream.WriteInt32L(iFromPort);
+    aStream << iTime.Int64();
+    aStream.WriteInt32L(iUTCOffset.Int());
+
+    aStream.WriteInt32L(iIsTextHeader);
+    aStream.WriteInt32L(iReference);
+    aStream.WriteInt32L(iTotalSegments);
+    aStream.WriteInt32L(iSegmentNumber);
+
+    aStream.WriteInt32L(iLogServerId);
+
+    aStream.WriteInt32L(iVersionNumber);
+    aStream.WriteInt32L(iSpare1);
+    aStream.WriteInt32L(iSpare2);
+    aStream.WriteInt32L(iSpare3);
+	
+	// Externalizing the SMS params if exists
+	if(iRecvbuf)
+		{
+		TPtr8 recvbuftmp = iRecvbuf->Ptr(0);
+		aStream.WriteInt32L(recvbuftmp.Length());
+		aStream << recvbuftmp;
+		}
+	else
+		{
+		aStream.WriteInt32L(0);
+		}
+    }
+
+
+//
+// writes iBuffer to writeStream for 8-bit incomming messages
+//
+void CWapDatagram::ExternalizeBufferL(RWriteStream& aStream) const
+	{
+	TInt length= WapDatagramLength();
+	aStream.WriteInt32L(length);
+	TPtr8 tmp= iBuffer->Des();
+	aStream << tmp;
+
+	} // CWapDatagram::ExternalizeBufferL
+
+
+//
+// Outgoing
+//
+void CWapDatagram::Construct(const TDesC8& aSendBuffer)
+    {
+    LOGWAPPROT1("CWapDatagram::Construct()");
+	
+	// Set version number to 1, as we have had to make 
+	// changes to CWapDatagram for CR0929
+	iVersionNumber = EFirstVersion;
+	
+    iSendBuffer.Set(aSendBuffer);
+    } // CWapDatagram::Construct
+
+
+//
+// Incoming
+// code actualy supports 7-bit characters and port numbers
+// encoded in information elements (IE) although it is not
+// a requirement
+//
+void CWapDatagram::ConstructL(const CSmsMessage& aSms)
+    {
+    LOGWAPPROT1("CWapDatagram::ConstructL()");
+
+	// Set version number to 1, as we have had to make 
+	// changes to CWapDatagram for CR0929
+	iVersionNumber = EFirstVersion;
+
+	iRecvbuf = CBufFlat::NewL(KSmsBufferExpansion);
+
+	RBufWriteStream writestream(*iRecvbuf);
+	writestream.Open(*iRecvbuf);
+	CleanupClosePushL(writestream);
+	
+	// Externalizing everything within CSMSMessage except buffer
+	aSms.ExternalizeWithoutBufferL(writestream);
+	
+	CleanupStack::PopAndDestroy();  //  writestream
+
+	iRecvbuf->Compress();
+
+    const CSmsBufferBase& SmsBufferBase = aSms.Buffer();
+
+    GetDatagramSettings(aSms);
+
+    // Get the data from CSmsMessage and convert
+    // SmsBuffer store Unicode short message from CSmsMessage
+    ConvertL(SmsBufferBase,&iBuffer);
+	GetDatagramSettingsL();
+
+    iIsComplete = ETrue;
+    if (iUserDataSettings.Alphabet() == TSmsDataCodingScheme::ESmsAlphabet7Bit)
+        {
+        // this is a good candidate to include a text header.
+        if (iIsTextHeader)
+            {
+            // there is still a minor chance that message is complete:
+            // one fragment long datagram
+            if (iTotalSegments == 1)
+                {
+                // Get the segment data
+                TPtr8 PtrNarrow = iBuffer->Des();
+                PtrNarrow.Zero();
+                iSegment->UserData(PtrNarrow);
+                }
+            else
+                {
+                iIsComplete = EFalse;
+                // delete incomplete message from iBuffer;
+                delete iBuffer;
+                iBuffer = 0;
+                }
+            }
+        else
+            // This means that IEs with 7-bits are used
+            // Happily we support it
+            // But what TODO if we are here due to an error, because
+            // 7-bit with IEs should never happen ?
+            iIsComplete = ETrue;
+
+        }
+    } // CWapDatagram::ConstructL
+
+
+//
+// Set WAP datagram private members from a text based concatenated message
+// Copies contents of iBuffer to iSmsBuffer
+// Allocates iSegment object
+//
+void CWapDatagram::GetDatagramSettingsL()
+    {
+    LOGWAPPROT1("CWapDatagram::GetDatagramSettingsL()");
+
+	/* The WAP stack always receives 8 bit WAP datagrams from the SMS Stack as a single CSmsMessage.
+	This is because 8 bit WAP messages which cannot be encoded into a single PDU are sent in a segmented SMS
+	message which is reassembled inside the SMS Stack; the SMS Stack always passes the WAP stack
+	a single CSmsMessage containing a single WAP message regardless of the message length.
+	The WAP stack can receive 7 Bit WAP datagrams either as a single CSmsMessage or as a number of CSmsMessages
+	which need to be reassembled into a single WAP message by the WAP stack.  The latter method is provided to maintain backward
+	compatibility with early versions of the WAP stack which were implemented before the concatenation function was
+	available in the SMS stack.*/
+
+	/* 160 is the maximum number of character that can be fitted in a single PDU using 7 bit encoding */
+	if((iUserDataSettings.Alphabet()== TSmsDataCodingScheme::ESmsAlphabet8Bit) ||
+	(iUserDataSettings.Alphabet()== TSmsDataCodingScheme::ESmsAlphabet7Bit && iBuffer->Length()>160 ))
+		{
+		iSegment = new (ELeave)TWapTextMessage(*iBuffer);
+		}
+	else if (iBuffer->Length()<=160)
+        {
+        iSmsBuffer = *iBuffer;
+		iSegment = new (ELeave)TWapTextMessage(iSmsBuffer);
+        iIsTextHeader = iSegment->Parse();
+
+        if (iIsTextHeader)
+            {
+            iFromPort = iSegment->SourcePort(&i16BitPorts);
+            iToPort = iSegment->DestinationPort(&i16BitPorts);
+            iReference = iSegment->ReferenceNumber();
+            iTotalSegments = iSegment->TotalSegments();
+            iSegmentNumber = iSegment->SegmentNumber();
+            }
+        }
+	else
+		{
+        delete iSegment;
+        iSegment = 0;
+		}
+     } // CWapDatagram::GetDatagramSettingsL
+
+
+//
+// Set WAP datagram private members from information element structures
+//
+void CWapDatagram::GetDatagramSettings(const CSmsMessage& aSms)
+    {
+    LOGWAPPROT1("CWapDatagram::GetDatagramSettings()");
+
+    const CSmsPDU& Pdu = aSms.SmsPDU();
+
+    __ASSERT_DEBUG(Pdu.Type()==CSmsPDU::ESmsDeliver || Pdu.Type()==CSmsPDU::ESmsSubmit, // this line is testing purposes only
+			Panic(KPanicUsageError));
+
+    aSms.UserDataSettings(iUserDataSettings);
+
+    Pdu.ApplicationPortAddressing(iToPort,iFromPort,&i16BitPorts);
+    if (iFromPort == (-1))
+        iFromPort = iToPort;
+
+    // From WAP datagram point of view following numbers are applicable
+    iReference = 0;
+    iTotalSegments = 1;
+    iSegmentNumber = 1;
+
+    iFromAddress = aSms.ToFromAddress();
+    iToAddress = KNullDesC;
+    iTime = aSms.Time();
+
+    TBool result = SetUTCOffset(aSms.UTCOffset());
+    __ASSERT_DEBUG(result, Panic(KPanicSmsMsgTimeZoneOutOfRange));
+    } // CWapDatagram::GetDatagramSettings
+
+
+//
+// Set Alphabet information of iUserDataSettings before calling the method
+// Converts from 7/8-bit to UNICODE
+//
+void CWapDatagram::ConvertL(const TDesC8& aNarrowChars,CSmsBufferBase& aSmsBuffer) const
+    {
+    LOGWAPPROT1("CWapDatagram::ConvertL()");
+
+	// Convert the data in segments of specified max size
+	const TInt KMaxSegmentSize=CSmsBufferBase::EMaxBufLength;
+
+	// Create converter and reassembler
+	RFs fs;
+	CCnvCharacterSetConverter* charConv=CCnvCharacterSetConverter::NewLC();
+	CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*charConv,fs,iUserDataSettings.Alphabet(),ETrue);
+	TSmsBufferReassembler reassembler(*converter,aSmsBuffer);
+
+	// Rassemble
+	TInt elementsRemaining=aNarrowChars.Length();
+	while (elementsRemaining)
+		{
+		TInt segmentLength=Min(KMaxSegmentSize,elementsRemaining);
+		TPtrC8 ptr(aNarrowChars.Ptr()+aNarrowChars.Length()-elementsRemaining,segmentLength);
+		reassembler.ReassembleNextL(ptr, ESmsEncodingNone,
+									elementsRemaining==segmentLength);
+		elementsRemaining-=segmentLength;
+		}
+
+	CleanupStack::PopAndDestroy(2);	// charConv,
+    } // CWapDatagram::ConvertL
+
+
+//
+// Converts from UNICODE to 7/8-bit
+//
+void CWapDatagram::ConvertL(const CSmsBufferBase& aSmsBuffer,HBufC8** aNarrowChars) const
+    {
+    LOGWAPPROT1("CWapDatagram::ConvertL()");
+
+	// Convert the data in segments of specified max size
+	const TInt KMaxSegmentSize=CSmsBufferBase::EMaxBufLength;
+
+	// Delete the existing buffer
+	if (*aNarrowChars)
+		{
+		delete *aNarrowChars;
+		*aNarrowChars=NULL;
+		}
+
+	// Create converter and segmenter
+	RFs fs;
+	CCnvCharacterSetConverter* charConv=CCnvCharacterSetConverter::NewLC();
+	CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*charConv,fs,iUserDataSettings.Alphabet(),ETrue);
+	CSmsBufferSegmenter* segmenter=CSmsBufferSegmenter::NewLC(*converter,aSmsBuffer,KMaxSegmentSize);
+
+	// Create a new buffer based on converted length
+	TInt convertedLength=segmenter->TotalConvertedLengthL(ESmsEncodingNone);
+	*aNarrowChars=HBufC8::NewMaxL(((convertedLength+KMaxSegmentSize-1)/KMaxSegmentSize)*KMaxSegmentSize);
+	TPtr8 narrowPtr=(*aNarrowChars)->Des();
+
+	// Now do the conversion
+	TInt elementsConverted=0;
+	TInt unconvertedChars=0;
+	TInt downgradedChars=0;
+	TBool complete=EFalse;
+	while (elementsConverted<convertedLength)
+		{
+		__ASSERT_DEBUG(elementsConverted<convertedLength,Panic(KPanicTooLongData));
+		TPtr8 ptr((TUint8*)narrowPtr.Ptr()+elementsConverted,0,KMaxSegmentSize);
+		complete=segmenter->SegmentNextL(ptr, unconvertedChars, downgradedChars, ESmsEncodingNone);
+		elementsConverted+=ptr.Length();
+		}
+    if((!complete || (convertedLength!=elementsConverted)) &&  convertedLength)
+        User::Leave( KErrCorrupt );
+	narrowPtr.SetLength(convertedLength);
+
+	CleanupStack::PopAndDestroy(3);	// charConv,converter,segmenter
+    } // CWapDatagram::ConvertL
+
+
+void CWapDatagram::SetSmsMessageSettingsL(CSmsMessage& aSmsMessage, TBool aSetPorts)
+    {
+    LOGWAPPROT1("CWapDatagram::SetSmsMessageSettingsL()");
+
+    CSmsPDU& Pdu = aSmsMessage.SmsPDU();
+
+    aSmsMessage.SetToFromAddressL(iToAddress);
+    aSmsMessage.SetUserDataSettingsL(iUserDataSettings);
+    aSmsMessage.SetTime(iTime);
+
+    TBool result = aSmsMessage.SetUTCOffset(iUTCOffset);
+    __ASSERT_DEBUG(result, Panic(KPanicWapDgrmTimeZoneOutOfRange));
+    
+    if (aSetPorts)
+        {
+        if (iFromPort == (-1))
+            iFromPort = iToPort;
+
+        // Determine whether long or short form is used
+        if (iFromPort > 255 || iToPort>255)
+            i16BitPorts = ETrue;
+
+	    Pdu.SetApplicationPortAddressingL(ETrue,iToPort,iFromPort,i16BitPorts);
+		// WAP implementation guidelines recommend DCS of 0x15, however
+		// some gateways / SCs will only accept DCS 0xf5
+		Pdu.SetBits7To4(TSmsDataCodingScheme::ESmsDCSTextUncompressed7BitOr8Bit);
+		Pdu.SetAlphabet(TSmsDataCodingScheme::ESmsAlphabet8Bit);
+		Pdu.SetClass(ETrue,TSmsDataCodingScheme::ESmsClass1);
+        }
+    } // CWapDatagram::SetSmsMessageSettingsL
+
+
+CWapDatagram::CWapDatagram():
+    iUserDataSettings(),
+    iToAddress(KNullDesC),
+    iFromAddress(KNullDesC),
+    i16BitPorts(EFalse),
+    iFromPort(-1),
+    iToPort(-1),
+    iTime(),
+    iUTCOffset(0),
+    iIsComplete(EFalse),
+    iReference(0),
+    iTotalSegments(0),
+    iSegmentNumber(0),
+    iIsTextHeader(EFalse),
+    iSegment(NULL),
+    iSmsBuffer(KNullDesC8),
+    iBuffer(NULL),
+    iSendBuffer(KNullDesC8),
+    iOtherHeader(KNullDesC8),
+    iLogServerId(0),
+    iVersionNumber(EBaseVersion),// Set version number to EBaseVersion by default.
+    iSpare1(0),
+    iSpare2(0),
+    iSpare3(0),
+    iRecvbuf(NULL)
+    {
+    iTime.UniversalTime();
+
+    TBool result = SetUTCOffset(User::UTCOffset());
+   __ASSERT_DEBUG(result, Panic(KPanicUserSuppliedTimeZoneOutOfRange));
+
+    iUserDataSettings.SetAlphabet(TSmsDataCodingScheme::ESmsAlphabet8Bit);
+    __DECLARE_NAME(_S("CWapDatagram"));
+    } // CWapDatagram::CWapDatagram
+
+
+//
+// Return the location of the link
+//
+TInt CWapDatagram::LinkOffset()
+	{
+	LOGWAPPROT1("CWapDatagram::LinkOffset()");
+
+
+	return _FOFF(CWapDatagram,iLink);
+	} // CWapDatagram::LinkOffset
+
+
+TBool CWapDatagram::SetUTCOffset(const TTimeIntervalSeconds& aUTCOffset)
+    {
+    LOGWAPPROT1("CWapDatagram::SetUTCOffset()");
+
+    TBool rc = ETrue;
+    TInt utcOffset = aUTCOffset.Int();
+
+    if ((utcOffset <=  CSmsMessage::EMaximumSeconds) &&
+        (utcOffset >= -CSmsMessage::EMaximumSeconds))
+       {
+       iUTCOffset = utcOffset;
+       }
+    else
+       {
+       LOGWAPPROT2("CWapDatagram:SetUTCOffset offset [out of range] = %d",utcOffset);
+       rc = EFalse;
+       }
+
+    return rc;
+    } // CWapDatagram::SetUTCOffset
+    
+
+
+CBufFlat* CWapDatagram::SmsExternalisedStream() const
+	{
+	return iRecvbuf;
+	}