diff -r 000000000000 -r 3553901f7fa8 smsprotocols/smsstack/wapprot/Src/wapdgrm.cpp --- /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& 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); + 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 + // 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 (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; + }