diff -r 6b1d113cdff3 -r 6638e7f4bd8f smsprotocols/smsstack/wapprot/Src/wapdgrm.cpp --- a/smsprotocols/smsstack/wapprot/Src/wapdgrm.cpp Mon May 03 13:37:20 2010 +0300 +++ b/smsprotocols/smsstack/wapprot/Src/wapdgrm.cpp Thu May 06 15:10:38 2010 +0100 @@ -1,707 +1,707 @@ -// 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& 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* SegmentArray = new (ELeave) CArrayPtrFlat (8); - CleanupStack::PushL(SegmentArray); - // coverity[double_push] - 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; iAt(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& 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; iiData.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= 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 - 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 (elementsConvertedSegmentNextL(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; - } +// 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& 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* SegmentArray = new (ELeave) CArrayPtrFlat (8); + CleanupStack::PushL(SegmentArray); + // coverity[double_push] + 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; iAt(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& 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; iiData.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= 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 + 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 (elementsConvertedSegmentNextL(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; + }