--- a/smsprotocols/smsstack/gsmu/src/Gsmumsg.cpp Mon May 03 13:37:20 2010 +0300
+++ b/smsprotocols/smsstack/gsmu/src/Gsmumsg.cpp Thu May 06 15:10:38 2010 +0100
@@ -1,3770 +1,3770 @@
-// 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:
-// Contains the implementation of the CSmsMessage class
-//
-//
-
-/**
- @file
-*/
-
-#include <gsmumsg.h>
-#include "Gsmumain.h"
-#include <gsmubuf.h>
-#include <gsmuset.h>
-#include <gsmusar.h>
-#include "gsmumsgadditionalattributes.h"
-#include <gsmuieoperations.h>
-#include <gsmunonieoperations.h>
-
-#include <logwrap.h> // Used for KLogNullId only
-#include <e32uid.h>
-#include <etelmm.h>
-#include <logwraplimits.h>
-
-#include <emsinformationelement.h>
-#include <emsformatie.h>
-#include <emsuserpromptie.h>
-#include <emsobjectdistributionie.h>
-#include "smsstackutils.h"
-
-/**
- * Allocates and creates a CSmsMessage instance from a TGsmSms.
- *
- * The type of SMS-XXXX message to construct is defined by the first byte of
- * the TGsmSms TPDU header.
- *
- * @param aFs Reference handle to the file system
- * @param aGsmSms Reference to TGsmSms
- * @param aBuffer The Unicode text for the message. The object takes ownership
- * of aBuffer.
- * @param aIsRPError Set to true if the message contains Reply Path Error. Default
- * is false.
- * @param aIsMobileTerminated Set to True if the message is Mobile Terminated.
- * Default is false.
- * @return New CSmsMessage object
- * @capability None
- */
-EXPORT_C CSmsMessage* CSmsMessage::NewL(RFs& aFs, const TGsmSms& aGsmSms,CSmsBufferBase* aBuffer, TBool aIsRPError,TBool aIsMobileTerminated)
- {
- LOGGSMU1("CSmsMessage::NewL()");
-
- CleanupStack::PushL(aBuffer);
- CSmsMessage* smsmessage=new(ELeave) CSmsMessage(aFs, aBuffer);
- CleanupStack::Pop();
- CleanupStack::PushL(smsmessage);
- smsmessage->ConstructL(aGsmSms, aIsRPError,aIsMobileTerminated);
- CleanupStack::Pop();
- return smsmessage;
- } // CSmsMessage::NewL
-
-
-/**
- * Allocates and creates a CSmsMessage, specifying the SMS-XXX message type with
- * a CSmsPDU::TSmsPduType.
- *
- * @param aFs Reference handle to the file system
- * @param aType The PDU type
- * @param aBuffer The Unicode text for the message. The object takes ownership
- * of aBuffer.
- * @param aIsRPError Set to true if the message contains Reply Path Error. Default
- * is false.
- * @return New CSmsMessage object
- * @capability None
- */
-EXPORT_C CSmsMessage* CSmsMessage::NewL(RFs& aFs, CSmsPDU::TSmsPDUType aType,CSmsBufferBase* aBuffer,TBool aIsRPError)
- {
- LOGGSMU1("CSmsMessage::NewL()");
-
- CleanupStack::PushL(aBuffer);
- CSmsMessage* smsmessage=new(ELeave) CSmsMessage(aFs, aBuffer);
- CleanupStack::Pop();
- CleanupStack::PushL(smsmessage);
- smsmessage->ConstructL(aType,aIsRPError);
- CleanupStack::Pop();
- return smsmessage;
- } // CSmsMessage::NewL
-
-
-/**
- * Destructor, frees resources.
- * @capability None
- */
-EXPORT_C CSmsMessage::~CSmsMessage()
- {
- LOGGSMU1("CSmsMessage::~CSmsMessage()");
-
- delete iSmsPDU;
- delete iBuffer;
- delete iCharacterSetConverter;
-
- if (iInformationElementArray)
- {
- iInformationElementArray->ResetAndDestroy();
- delete iInformationElementArray;
- }
-
- delete iAdditionalInfo;
- } // CSmsMessage::NewL
-
-
-/**
- * Internalises all object data except for the CSmsBufferBase.
- *
- * This is used when the buffer is stored elsewhere.
- *
- * @param aStream Stream to read from
- * @capability None
- */
-EXPORT_C void CSmsMessage::InternalizeWithoutBufferL(RReadStream& aStream)
- {
- LOGGSMU1("CSmsMessage::InternalizeWithoutBufferL()");
-
- InternalizeWithoutBufferAndVersionL(aStream);
- InternalizeVersionL(aStream);
-
- iAdditionalInfo->ResetAttributesL();
-
- if (iVersion > ESmsMessageV0)
- {
- iAdditionalInfo->InternalizeL(aStream, iVersion);
- }
- } // CSmsMessage::InternalizeWithoutBufferL
-
-
-/**
- * Externalises all object data except for the CSmsBufferBase.
- *
- * This is used when the buffer is stored elsewhere.
- *
- * @param aStream Stream to write to
- * @capability None
- */
-EXPORT_C void CSmsMessage::ExternalizeWithoutBufferL(RWriteStream& aStream) const
- {
- LOGGSMU1("CSmsMessage::ExternalizeWithoutBufferL()");
-
- ExternalizeWithoutBufferAndVersionL(aStream);
- ExternalizeVersionL(aStream);
-
- if (iVersion > ESmsMessageV0)
- {
- iAdditionalInfo->ExternalizeL(aStream, iVersion);
- }
- } // CSmsMessage::ExternalizeWithoutBufferL
-
-
-/**
- * Internalises all object data.
- *
- * @param aStream Stream to read from
- * @capability None
- */
-EXPORT_C void CSmsMessage::InternalizeL(RReadStream& aStream)
- {
- LOGGSMU1("CSmsMessage::InternalizeL()");
-
- InternalizeWithoutBufferAndVersionL(aStream);
- InternalizeBufferL(aStream);
- InternalizeVersionL(aStream);
-
- iAdditionalInfo->ResetAttributesL();
- if (iVersion > ESmsMessageV0)
- {
- iAdditionalInfo->InternalizeL(aStream, iVersion);
- }
- } // CSmsMessage::InternalizeL
-
-
-/**
- * Externalises all object data.
- *
- * @param aStream Stream to write to
- * @capability None
- */
-EXPORT_C void CSmsMessage::ExternalizeL(RWriteStream& aStream) const
- {
- LOGGSMU1("CSmsMessage::ExternalizeL()");
-
- ExternalizeWithoutBufferAndVersionL(aStream);
- ExternalizeBufferL(aStream);
- ExternalizeVersionL(aStream);
-
- if (iVersion > ESmsMessageV0)
- {
- iAdditionalInfo->ExternalizeL(aStream, iVersion);
- }
- } // CSmsMessage::ExternalizeL
-
-
-/**
- * Tests if the message contains text.
- *
- * @return True if the message contains text
- * @capability None
- */
-EXPORT_C TBool CSmsMessage::TextPresent() const
- {
- LOGGSMU1("CSmsMessage::TextPresent()");
-
- CSmsPDU::TSmsPDUType pdutype=SmsPDU().Type();
- return (pdutype==CSmsPDU::ESmsSubmit) ||
- (pdutype==CSmsPDU::ESmsDeliver) ||
- (((pdutype==CSmsPDU::ESmsSubmitReport) || (pdutype==CSmsPDU::ESmsDeliverReport) ||
- ((pdutype==CSmsPDU::ESmsStatusReport) && ((CSmsStatusReport&) SmsPDU()).ParameterIndicatorPresent())) &&
- SmsPDU().UserDataPresent());
- } // CSmsMessage::TextPresent
-
-
-/**
- * Gets the number of PDU's required to encode the complete message.
- *
- * @leave KErrOverflow Leaves if the number of required PDUs exceeds the maximum
- * or the message cannot be encoded.
- * @return Number of PDU's
- * @capability None
- */
-EXPORT_C TInt CSmsMessage::NumMessagePDUsL()
- {
- LOGGSMU1("CSmsMessage::NumMessagePDUsL()");
-
- TInt nummessagepdus=1;
- if (IsDecoded())
- {
- if (TextPresent())
- {
- nummessagepdus=NumMessageEmsPDUsL();
- TInt maxnummessagepdus=SmsPDU().TextConcatenated()? 0xFF: 1;
- if (nummessagepdus>maxnummessagepdus)
- {
- User::Leave(KErrOverflow);
- }
- }
-
- }
- else if (TextPresent() && SmsPDU().TextConcatenated())
- {
- nummessagepdus=SmsPDU().NumConcatenatedMessagePDUs();
- }
-
- LOGGSMU2("CSmsMessage::NumMessagePDUsL() returns %d", nummessagepdus);
-
- return nummessagepdus;
- } // CSmsMessage::NumMessagePDUsL
-
-
-/**
- * Gets the maximum message length possible with the current settings.
- *
- * If Text is compressed, this returns the maximum number of bytes available
- * with text compressed.
- *
- * @return Maximum message length
- * @capability None
- */
-EXPORT_C TInt CSmsMessage::MaxMessageLength() const
- {
- __ASSERT_DEBUG(TextPresent(),Panic(KGsmuPanicTextNotPresent));
- TInt maxmessagelength=SmsPDU().UserData().MaxBodyLengthInChars();
- if (SmsPDU().TextConcatenated())
- {
- maxmessagelength=maxmessagelength*0xFF;
- }
-
- LOGGSMU2("CSmsMessage::MaxMessageLength() returns %d", maxmessagelength);
-
- return maxmessagelength;
- } // CSmsMessage::MaxMessageLength
-
-
-/**
- *
- * @return The converted buffer length
- * @note Use with care - Expensive operation
- */
-TInt CSmsMessage::ConvertedBufferLengthL(const CSmsBufferBase& aBuffer)
- {
- // Ignore in code coverage - not used in SMS stack and not exported
- // but cannot be removed as impacts public header.
- BULLSEYE_OFF
- LOGGSMU1("CSmsMessage::ConvertedBufferLengthL()");
-
- TInt convertedBufferLength=0;
- CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,SmsPDU().Alphabet(),BinaryData());
- CSmsBufferSegmenter* segmenter=CSmsBufferSegmenter::NewLC(*converter,aBuffer);
- convertedBufferLength=segmenter->TotalConvertedLengthL(iAdditionalInfo->Alternative7bitEncoding());
- CleanupStack::PopAndDestroy(2, converter);
-
- LOGGSMU2("CSmsMessage::ConvertedBufferLengthL() returns %d", convertedBufferLength);
-
- return convertedBufferLength;
- BULLSEYE_RESTORE
- }
-
-/**
- * Gets the message length.
- *
- * In the case where the message is compressed, this function compresses the
- * text and returns the number of bytes of the compressed buffer.
- *
- * The function calls ConvertedBufferLengthL(), and is therefore an expensive
- * operation.
- *
- * @return Message length
- * @capability None
- */
-EXPORT_C TInt CSmsMessage::MessageLengthL()
- {
- LOGGSMU1("CSmsMessage::MessageLengthL()");
-
- TInt messagelength=0;
- if (!SmsPDU().TextCompressed())
- {
- messagelength=iBuffer->Length();
- if(SmsPDU().Alphabet() == TSmsDataCodingScheme::ESmsAlphabetUCS2)messagelength*=2 ;
- }
- else
- {
- User::Leave(KErrNotSupported);
- }
- return messagelength;
- } // CSmsMessage::MessageLengthL
-
-
-EXPORT_C void CSmsMessage::GetEncodingInfoL(TInt& aPdus, TInt& aUnconvertedChars,
- TInt& aDowngradedChars, TInt& aFreeUDUnitsInLastPDU)
- {
- LOGGSMU1("CSmsMessage::GetEncodingInfoL()");
-
- aPdus = 1;
- aUnconvertedChars = 0;
- aDowngradedChars = 0;
- aFreeUDUnitsInLastPDU = 0;
-
- if (TextPresent())
- {
- if (IsDecoded())
- {
- //
- // Clear the concatenated flag, EncodeBufferL() will add it if needed.
- //
- SmsPDU().SetTextConcatenatedL(EFalse, EFalse);
-
- //
- // Attempt to encode to a single PDU, and if that fails then attempt to
- // encode to a set of PDUs.
- //
- CArrayFixFlat<TGsmSms>* tmpArray = new (ELeave) CArrayFixFlat<TGsmSms>(8);
- CleanupStack::PushL(tmpArray);
-
- //
- // Encode the message...
- //
- if (!EncodeIntoSinglePDUL(*tmpArray, aUnconvertedChars,
- aDowngradedChars, aFreeUDUnitsInLastPDU))
- {
- EncodeBufferL(*tmpArray, 0, *iBuffer, aUnconvertedChars,
- aDowngradedChars, aFreeUDUnitsInLastPDU, EFalse);
-
- aPdus = iAdditionalInfo->SmsPDUArray().Count();
- if (aPdus > 255)
- {
- User::Leave(KErrOverflow);
- }
- }
-
- CleanupStack::PopAndDestroy(tmpArray);
- }
- else if (SmsPDU().TextConcatenated())
- {
- aPdus = SmsPDU().NumConcatenatedMessagePDUs();
- aUnconvertedChars = 0;
- aDowngradedChars = 0;
- aFreeUDUnitsInLastPDU = 0;
- }
- }
-
- LOGGSMU2("CSmsMessage::GetEncodingInfoL(): aPdus=%d", aPdus);
- LOGGSMU2("CSmsMessage::GetEncodingInfoL(): aUnconvertedChars=%d", aUnconvertedChars);
- LOGGSMU2("CSmsMessage::GetEncodingInfoL(): aDowngradedChars=%d", aDowngradedChars);
- LOGGSMU2("CSmsMessage::GetEncodingInfoL(): aFreeUDUnitsInLastPDU=%d", aFreeUDUnitsInLastPDU);
- } // CSmsMessage::GetEncodingInfoL
-
-
-/**
- * Gets the User Data Settings.
- *
- * @param aSettings User Data Settings
- * @capability None
- */
-EXPORT_C void CSmsMessage::UserDataSettings(TSmsUserDataSettings& aSettings) const
- {
- LOGGSMU1("CSmsMessage::UserDataSettings()");
-
- __ASSERT_DEBUG(TextPresent(),Panic(KGsmuPanicTextNotPresent));
- aSettings.SetAlphabet(SmsPDU().Alphabet());
- aSettings.SetTextCompressed(SmsPDU().TextCompressed());
- TBool is16bit;
- TBool concatenated=SmsPDU().TextConcatenated(&is16bit);
- aSettings.SetTextConcatenated(concatenated,is16bit);
- } // CSmsMessage::UserDataSettings
-
-
-/**
- * Sets the User Data Settings.
- *
- * @param aSettings User Data Settings
- * @capability None
- */
-EXPORT_C void CSmsMessage::SetUserDataSettingsL(const TSmsUserDataSettings& aSettings)
- {
- LOGGSMU1("CSmsMessage::SetUserDataSettingsL()");
-
- __ASSERT_DEBUG(TextPresent(),Panic(KGsmuPanicTextNotPresent));
- SmsPDU().SetAlphabet(aSettings.Alphabet());
- SmsPDU().SetTextCompressed(aSettings.TextCompressed());
- TBool is16bit;
- TBool concatenated=aSettings.TextConcatenated(&is16bit);
- SmsPDU().SetTextConcatenatedL(concatenated,is16bit);
- } // CSmsMessage::SetUserDataSettingsL
-
-
-/**
- * Optimizes the user data settings.
- *
- * The alphabet flag causes an alphabet to be chosen which preserves information
- * in the message and makes the number of PDUs as small as possible.
- *
- * The compression settings flag is not supported.
- *
- * The compression flag causes compression to be switched on if the resultant
- * number of PDUs is smaller.
- *
- * If user explicitly defines alphabet as UCS2 or 8-bit coding, this setting is preserved;
- * otherwise, if 7-bit (default) alphabet can not support current text of message UCS2
- * alphabet (Unicode) is used.
- *
- * The two concatenation flags are mutually exclusive as they deal with 8-bit
- * and 16-bit referenced concatenation. Both flags cause compression to be switched
- * off and if the message length is greater than the maximum message length,
- * concatenation is switched on.
- *
- * @param aOptions Combination of TSmsOptimizationFlags
- * @capability None
- */
-EXPORT_C void CSmsMessage::OptimizeSettingsL(TInt aOptions)
- {
- LOGGSMU1("CSmsMessage::OptimizeSettingsL()");
-
- __ASSERT_DEBUG(TextPresent(),Panic(KGsmuPanicTextNotPresent));
- __ASSERT_DEBUG(IsDecoded(),Panic(KGsmuPanicNotDecoded));
-
- if (aOptions&ESmsFlagOptimizeAlphabet && (SmsPDU().Alphabet()==TSmsDataCodingScheme::ESmsAlphabet7Bit))
- {
- TBool isSupported=ETrue;
- TInt numOfUnconvertibleChars;
- TInt indexOfFirstUnconvertibleChar;
-
- TInt size=iBuffer->Length();
- const TInt bufsize=128;
- TBuf<bufsize> buf;
- TInt extracted=0;
- TInt remaining=0;
- TInt toExtract=0;
- TInt pos=0;
-
- // Defect Fix. Previous for loop caused an access violation as extract size was set
- // to size of ibuffer not bufsize and caused a access violation when over 128. Implemented
- // fix copies the ibuffer in 128 chunks until its all done.
-
- while((pos<size) && isSupported)
- {
- remaining=(size - extracted);
-
- if(remaining>bufsize)
- toExtract=bufsize;
- else
- toExtract=remaining;
-
- iBuffer->Extract(buf,pos,toExtract);
- isSupported=IsSupportedL(buf,numOfUnconvertibleChars,indexOfFirstUnconvertibleChar);
- extracted=(extracted+toExtract);
- pos=extracted;
- }
-
- if(!isSupported)
- SmsPDU().SetAlphabet(TSmsDataCodingScheme::ESmsAlphabetUCS2);
- }
- } // CSmsMessage::OptimizeSettingsL
-
-
-/**
- * This function returns the currently requested alternative encoding method.
- *
- * In the case of incoming SMS messages received on the device, it will often
- * be TSmsEncodingNone unless the Information Elements imply that an
- * alternative encoding has been used.
- *
- * @return The currently selected encoding method.
- *
- * @capability None
- */
-EXPORT_C TSmsEncoding CSmsMessage::Alternative7bitEncoding() const
- {
- LOGGSMU1("CSmsMessage::Alternative7bitEncoding()");
-
- return iAdditionalInfo->Alternative7bitEncoding();
- } // CSmsMessage::Alternative7bitEncoding
-
-
-/**
- * This function allows the client to specify an alternative encoding method
- * incase the default GSM encoding cannot encode the message completely
- * without data loss.
- *
- * @param aEncoding Encoding method to select.
- *
- * @return A Symbian system wide error code. This function will return
- * KErrArgument if the encoding enum is invalid and will return
- * KErrNotSupported if the required plug-ins are not present.
- *
- * @capability None
- */
-EXPORT_C TInt CSmsMessage::SetAlternative7bitEncoding(TSmsEncoding aEncoding)
- {
- LOGGSMU2("CSmsMessage::SetAlternative7bitEncoding(%d)", aEncoding);
-
- //
- // Get the encoders that would be used for this encoding method.
- // The function will also check that the required encoder is present.
- //
- TRAPD(err,
- {
- CSmsAlphabetConverter* converter = CSmsAlphabetConverter::NewLC(*iCharacterSetConverter, iFs,
- TSmsDataCodingScheme::ESmsAlphabet7Bit,
- EFalse);
- converter->ConfirmAlternativeEncoderL(aEncoding);
- CleanupStack::PopAndDestroy(converter);
- });
-
- //
- // Set the variable if the encoders are available...
- //
- if (err == KErrNone)
- {
- iAdditionalInfo->SetAlternative7bitEncoding(aEncoding);
- }
-
- return err;
- } // CSmsMessage::SetAlternative7bitEncoding
-
-
-/**
- * Takes an encoding setting (received from a PDU) and merges it into the
- * current setting (where possible).
- *
- * @param aEncoding Encoding setting to merge.
- */
-void CSmsMessage::MergeAlternative7bitEncoding(TSmsEncoding aEncoding) const
- {
- LOGGSMU3("CSmsMessage::MergeAlternative7bitEncoding(): aEncoding=%d (currently %d)",
- aEncoding, iAdditionalInfo->Alternative7bitEncoding());
-
- switch (iAdditionalInfo->Alternative7bitEncoding())
- {
- case ESmsEncodingNone:
- {
- // Anything is can be merge with this...
- iAdditionalInfo->SetAlternative7bitEncoding(aEncoding);
- }
- break;
-
- case ESmsEncodingTurkishSingleShift:
- {
- // Only Turkish locking shift can merge...
- if (aEncoding == ESmsEncodingTurkishLockingShift)
- {
- iAdditionalInfo->SetAlternative7bitEncoding(ESmsEncodingTurkishLockingAndSingleShift);
- }
- }
- break;
-
- case ESmsEncodingTurkishLockingShift:
- {
- // Only Turkish single shift can merge...
- if (aEncoding == ESmsEncodingTurkishSingleShift)
- {
- iAdditionalInfo->SetAlternative7bitEncoding(ESmsEncodingTurkishLockingAndSingleShift);
- }
- }
- break;
-
- case ESmsEncodingPortugueseSingleShift:
- {
- // Only Portuguese locking shift can merge...
- if (aEncoding == ESmsEncodingPortugueseLockingShift)
- {
- iAdditionalInfo->SetAlternative7bitEncoding(ESmsEncodingPortugueseLockingAndSingleShift);
- }
- }
- break;
-
- case ESmsEncodingPortugueseLockingShift:
- {
- // Only Portuguese single shift can merge...
- if (aEncoding == ESmsEncodingPortugueseSingleShift)
- {
- iAdditionalInfo->SetAlternative7bitEncoding(ESmsEncodingPortugueseLockingAndSingleShift);
- }
- }
- break;
-
- case ESmsEncodingTurkishLockingAndSingleShift:
- case ESmsEncodingSpanishSingleShift:
- case ESmsEncodingPortugueseLockingAndSingleShift:
- default:
- {
- // NOP - Cannot merge anything into these...
- }
- };
-
- LOGGSMU2("CSmsMessage::MergeAlternative7bitEncoding(): New encoding=%d",
- iAdditionalInfo->Alternative7bitEncoding());
- } // CSmsMessage::MergeAlternative7bitEncoding
-
-
-/**
- * Tests if a buffer can be encoded without loss of information.
- *
- * @param aDes The buffer to test for encoding
- * @param aNumberOfUnconvertibleCharacters On return, the number of
- * unconvertible characters
- * @param aIndexOfFirstUnconvertibleCharacter On return, the index of the
- * first unconvertible character
- *
- * @return True if aDes can be encoded without loss of information
- *
- * @capability None
- */
-EXPORT_C TBool CSmsMessage::IsSupportedL(const TDesC& aDes, TInt& aNumberOfUnconvertibleCharacters,
- TInt& aIndexOfFirstUnconvertibleCharacter)
- {
- LOGGSMU1("[1] CSmsMessage::IsSupportedL()");
-
- __ASSERT_DEBUG(TextPresent(), Panic(KGsmuPanicTextNotPresent));
-
- aNumberOfUnconvertibleCharacters = 0;
- aIndexOfFirstUnconvertibleCharacter = aDes.Length();
-
- if (SmsPDU().TextCompressed())
- {
- return EFalse;
- }
-
- return SmsPDU().UserData().IsSupportedL(aDes, aNumberOfUnconvertibleCharacters,
- aIndexOfFirstUnconvertibleCharacter);
- } // CSmsMessage::IsSupportedL
-
-
-/**
- * Tests if a buffer can be encoded without loss of information.
- *
- * @param aDes The buffer to test for encoding
- * @param aNumberOfUnconvertibleCharacters On return, the number of
- * unconvertible characters
- * @param aNumberOfDowngradedCharacters On return, the number of
- * characters downgraded
- * @param aNumberRequiringAlternativeEncoding On return, the number of
- * characters needing alternative
- * encoding support
- * @param aIndexOfFirstUnconvertibleCharacter On return, the index of the
- * first unconvertible character
- *
- * @return True if aDes can be encoded without loss of information
- *
- * @capability None
- */
-EXPORT_C TBool CSmsMessage::IsSupportedL(const TDesC& aDes, TInt& aNumberOfUnconvertibleCharacters,
- TInt& aNumberOfDowngradedCharacters,
- TInt& aNumberRequiringAlternativeEncoding,
- TInt& aIndexOfFirstUnconvertibleCharacter) const
- {
- LOGGSMU1("[2] CSmsMessage::IsSupportedL()");
-
- __ASSERT_DEBUG(TextPresent(), Panic(KGsmuPanicTextNotPresent));
-
- aNumberOfUnconvertibleCharacters = 0;
- aNumberOfDowngradedCharacters = 0;
- aNumberRequiringAlternativeEncoding = 0;
- aIndexOfFirstUnconvertibleCharacter = aDes.Length();
-
- if (SmsPDU().TextCompressed())
- {
- return EFalse;
- }
-
- return SmsPDU().UserData().IsSupportedL(aDes, iAdditionalInfo->Alternative7bitEncoding(),
- aNumberOfUnconvertibleCharacters,
- aNumberOfDowngradedCharacters,
- aNumberRequiringAlternativeEncoding,
- aIndexOfFirstUnconvertibleCharacter);
- } // CSmsMessage::IsSupportedL
-
-
-/**
- * Encodes message PDUs as an array of TGsmSms objects.
- *
- * Note, this function should only be called after EncodeIntoSinglePDUL() as EncodeBufferL() now
- * automatically prepares PDUs for concatenation.
- *
- * @param aSmsArray (In) an empty array. On return, one or more encoded TGsmSms.
- * @param aReference Sets a Concatenated Message Reference (default 0)
- * @capability None
- */
-EXPORT_C void CSmsMessage::EncodeMessagePDUsL(CArrayFix<TGsmSms>& aSmsArray, TInt aReference)
- {
- LOGGSMU2("CSmsMessage::EncodeMessagePDUsL(): aReference=%d", aReference);
-
- __ASSERT_DEBUG((aSmsArray.Count()==0),Panic(KGsmuPanicSmsArrayNotEmpty));
-
- if (TextPresent())
- {
- if (SmsPDU().TextCompressed())
- {
- User::Leave(KErrNotSupported);
- }
- else
- {
- TInt unconvertedChars, downgradedChars, freeUDUnitsInLastPDU;
-
- EncodeBufferL(aSmsArray, aReference, *iBuffer, unconvertedChars,
- downgradedChars, freeUDUnitsInLastPDU);
- }
- }
- else
- {
- if(SmsPDU().Type()==CSmsPDU::ESmsCommand)
- {
- //Commands never contain text, so commands only encoded
- // in this branch.
- //
- // However Commands don't support information
- // elements (per 23.040 6.5) and the CSmsIEOperation class
- // do not allow control information elements to be added
- // to Commands, hence the next line is commented out.
- // PrepareCommandMessageL();
- }
-
- TGsmSms sms;
- SmsPDU().EncodeMessagePDUL(sms);
- aSmsArray.AppendL(sms);
- }
- } // CSmsMessage::EncodeMessagePDUsL
-
-
-/**
- * @internalComponent
- *
- * This method copies information elements from the collections contained in
- * CSmsMessageAdditionalAttributes into the working PDU.
- *
- * Command Messages comprise only 1 PDU. Therefore all information
- * elements must be present in the working PDU when encoding takes place.
- * If there is not enough space in the PDU, the message encoding will fail.
- *
- * The 23.040 has not defined any information elements that are contained in
- * Command PDUs. This method has been provided to maintain consistency with
- * previous GSMU implementations.
- *
- * @leave KErrAlreadyExists or KErrAlreadyExists
- */
-void CSmsMessage::PrepareCommandMessageL()
- {
- LOGGSMU1("CSmsMessage::PrepareCommandMessageL()");
-
- if (SmsPDU().Type()==CSmsPDU::ESmsCommand)
- {
- CSmsCommand& command = static_cast<CSmsCommand&>(SmsPDU());
-
- for (TUint8 category = 0; category < TSmsInformationElementCategories::ENumberOfCategories; category++)
- {
- switch(category)
- {
- case TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly:
- case TSmsInformationElementCategories::ECtrlSingleInstanceOnly:
- case TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed:
- {
- for (TUint j = 0; j < iAdditionalInfo->NumberOfControlInformationElements((CSmsMessageAdditionalAttributes::TCategory) category); j++)
- {
- CSmsInformationElement& informationElement = iAdditionalInfo->GetControlInformationElementL( ( (CSmsMessageAdditionalAttributes::TCategory) category), j);
- TPtr8 data = informationElement.Data();
- command.AddInformationElementL(informationElement.Identifier(), data);
- }
- break;
- }
- default:
- LOGGSMU2("CSmsMessage::PrepareCommandMessageL,default switch category = %d, id = %d", category);
- break;
- }
- }
- }
- } // CSmsMessage::PrepareCommandMessageL
-
-
-/**
- * Decodes message PDUs from an array of TGsmSms objects.
- *
- * The array contains a concatenated message, and must have the correct number
- * of PDUs.
- *
- * @param aSmsArray Concatenated message
- * @capability None
- */
-EXPORT_C void CSmsMessage::DecodeMessagePDUsL(const CArrayFix<TGsmSms>& aSmsArray)
- {
- LOGGSMU2("CSmsMessage::DecodeMessagePDUsL(): PDUs=%d", aSmsArray.Count());
-
- TInt count=aSmsArray.Count();
- SetIsComplete(ETrue);
- CArrayPtrFlat<CSmsPDU>* smspduarray=new(ELeave) CArrayPtrFlat<CSmsPDU>(8);
- CleanupStack::PushL(smspduarray);
- // With CleanupResetAndDestroyPushL, only ResetAndDestroy method of smspduarray is invoked.
- // smspduarray object is actually deleted with the first push.
- // coverity[double_push]
- CleanupResetAndDestroyPushL(*smspduarray); // Don't forget to destroy what the array elements point to.
-
- TInt i=0;
- TBool ismobileterminated=(Type()==CSmsPDU::ESmsDeliver) || (Type()==CSmsPDU::ESmsSubmitReport) || (Type()==CSmsPDU::ESmsStatusReport);
- for (; i<count; i++)
- {
- CSmsPDU* smspdu=CSmsPDU::NewL(aSmsArray[i],*iCharacterSetConverter,iFs, EFalse,ismobileterminated);
- CleanupStack::PushL(smspdu);
- TInt j=0;
- for (; (j<smspduarray->Count()) && (smspdu->ConcatenatedMessagePDUIndex()>(*smspduarray)[j]->ConcatenatedMessagePDUIndex()); j++)
- {
- }
- smspduarray->InsertL(j,smspdu);
- CleanupStack::Pop();
- }
- if (SmsPDU().TextCompressed())
- User::Leave(KErrNotSupported);
- else
- DecodeBufferL(*smspduarray,*iBuffer);
-
- CleanupStack::PopAndDestroy(2); // smspduarray elements (Reset and Destroy), smspduarray
- SetIsDecoded(ETrue);
- SmsPDU().UserData().SetBodyL(KNullDesC8);
- } // CSmsMessage::DecodeMessagePDUsL
-
-/**
- * Decodes partial complete message PDUs from an array of TGsmSms objects.
- *
- * The array contains a concatenated incomplete message, but the array of
- * TGsmSms object must be in sequence.
- *
- * NOTE:
- * It will not fully decode EMS and Control Information elements if it needs
- * to decode a partially complete class 0 SMS message. The assumption is that
- * it is necessary to display a partially complete message then only the raw
- * text will be displayed on the UI without any animation elements. The
- * rational for this design is that these information elements are normally
- * specified as being located at a specific position in a message. It will
- * complicate the design of client app if it has to re-calculate the position
- * of these elements when it receives a partially complete message under
- * Out Of Memory Conditions.
-
- * @param aSmsArray Concatenated message
- * @param aLastPartialCompleteMsg boolean value indicating this is the last
- * incomplete message for a particular concatenated message.
- * @capability None
- */
-EXPORT_C void CSmsMessage::DecodePartialCompleteMessagePDUsL(const CArrayFix<TGsmSms>& aSmsArray, TBool aLastPartialCompleteMsg)
- {
- LOGGSMU2("CSmsMessage::DecodePartialCompleteMessagePDUsL(): PDUs=%d", aSmsArray.Count());
-
- TInt count=aSmsArray.Count();
- SetIsComplete(EFalse);
- CArrayPtrFlat<CSmsPDU>* smspduarray=new(ELeave) CArrayPtrFlat<CSmsPDU>(8);
- CleanupStack::PushL(smspduarray);
- // With CleanupResetAndDestroyPushL, only ResetAndDestroy method of smspduarray is invoked.
- // smspduarray object is actually deleted with the first push.
- // coverity[double_push]
- CleanupResetAndDestroyPushL(*smspduarray); // Don't forget to destroy what the array elements point to.
-
- TBool isMobileTerminated=(Type()==CSmsPDU::ESmsDeliver);
- /*
- The loop below goes through all the sms's received & check whether the received PDUs are of Class 0
- or not. The number of PDUs received must be less than the number of concatenated PDUs constitute this message.
- Then it order the PDUs in sequence for decoding purpose.
- */
- for (TInt i=0; i<count; i++)
- {
- CSmsPDU* smspdu=CSmsPDU::NewL(aSmsArray[i],*iCharacterSetConverter,iFs, EFalse,isMobileTerminated);
- CleanupStack::PushL(smspdu);
-
- /*
- Check all the PDUs must be class 0 messages & also the number of received PDUs
- must be less than the number of concatenated PDUs constitute this message
- */
- TSmsDataCodingScheme::TSmsClass msgClass;
- if (smspdu->DataCodingSchemePresent() && smspdu->Class(msgClass))
- {
- if (msgClass != TSmsDataCodingScheme::ESmsClass0)
- {
- User::Leave(KErrNotSupported);
- }
- __ASSERT_DEBUG((count < smspdu->NumConcatenatedMessagePDUs()),Panic(KGsmuPanicWrongNumberOfMessagePDUs));
- }
- else
- {
- User::Leave(KErrNotSupported);
- }
- //The below for statement finds the position in smspduarray where the PDU should be inserted.
- //The PDUs are put in sequence for decoding purpose.
- TInt j;
- for (j=0; (j<smspduarray->Count()) && (smspdu->ConcatenatedMessagePDUIndex()>(*smspduarray)[j]->ConcatenatedMessagePDUIndex()); j++)
- {
- }
- smspduarray->InsertL(j,smspdu);
- CleanupStack::Pop();
- }
-
- if (SmsPDU().TextCompressed())
- {
- User::Leave(KErrNotSupported);
- }
- else
- {
- DecodeOnlyTextL(*smspduarray,*iBuffer);
- }
-
- iVersion = CSmsMessage::ESmsIncompleteClass0MessageV;
-
- TInt startPDU = smspduarray->At(0)->ConcatenatedMessagePDUIndex();
- TInt endPDU = smspduarray->At(smspduarray->Count()-1)->ConcatenatedMessagePDUIndex();
- AddIncompleteMessageInfoL(startPDU, endPDU, aLastPartialCompleteMsg);
-
- CleanupStack::PopAndDestroy(2); // smspduarray elements (Reset and Destroy), smspduarray
- SetIsDecoded(ETrue);
- SmsPDU().UserData().SetBodyL(KNullDesC8);
- }
-
-CSmsMessage::CSmsMessage(RFs& aFs, CSmsBufferBase* aBuffer):
- iFlags(0),
- iStatus(NMobileSmsStore::EStoredMessageUnread),
- iLogServerId(KLogNullId),
- iBuffer(aBuffer),
- iFs(aFs),
- iSlotArray(8),
- iVersion(ESmsMessageV4),
- iAdditionalInfo(NULL)
- {
- iTime.UniversalTime();
-
- TBool result = SetUTCOffset(User::UTCOffset());
- __ASSERT_DEBUG(result, Panic(KGSMUPanicUserTimeZoneOffsetOutOfRange));
- } // NMobileSmsStore::EStoredMessageUnread
-
-void CSmsMessage::ConstructL(const TGsmSms& aGsmSms, TBool aIsRPError,TBool aIsMobileTerminated)
- {
- LOGGSMU1("CSmsMessage::ConstructL()");
-
- iCharacterSetConverter=CCnvCharacterSetConverter::NewL();
- iInformationElementArray = new (ELeave) RPointerArray<CEmsInformationElement>(8);
-
- iAdditionalInfo = CSmsMessageAdditionalAttributes::NewL();
- CreateControlIEOperationsClassesL();
- CreateControlNonIEOperationsClassesL();
-
- iSmsPDU=CSmsPDU::NewL(aGsmSms,*iCharacterSetConverter,iFs, aIsRPError,aIsMobileTerminated);
- SetIsComplete(NumMessagePDUsL()==1);
- if (IsComplete() && TextPresent())
- {
- TSmsEncoding encodingUsedInSegment = SmsPDU().NationalLanguageEncoding();
-
- CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,SmsPDU().Alphabet(),BinaryData());
- TPtrC nativeChars(converter->ConvertToNativeL(SmsPDU().UserData().Body(),
- encodingUsedInSegment));
- MergeAlternative7bitEncoding(encodingUsedInSegment);
-
- if (SmsPDU().TextCompressed())
- User::Leave(KErrNotSupported);
- else
- iBuffer->InsertL(iBuffer->Length(),nativeChars);
- CleanupStack::PopAndDestroy(converter);
- CSmsPDU::TSmsPDUType pdutype= SmsPDU().Type();
- if(pdutype==CSmsPDU::ESmsCommand)
- {
- // This branch is never executed as TextPresent() never
- // returns true when pduType == command
- User::Leave(KErrArgument);
- }
- else if(SmsPDU().UserDataPresent())
- {
- TInt smscIndex(0);
-
- if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
- {
- iAdditionalInfo->SetStatusReportSchemeL(EControlParametersScheme);
- }
- else
- {
- iAdditionalInfo->SetStatusReportSchemeL(EDefaultScheme);
- }
-
- InstallControlInformationElementsL(SmsPDU().UserData(), 0);
- InstallEmsInformationElementsL(SmsPDU().UserData(),0);
- UpdateUserPromptAndODIElementsStartPosition();
- }
- }
- SetIsDecoded(IsComplete());
-
- if (TextPresent())
- SmsPDU().UserData().SetBodyL(KNullDesC8);
- } // CSmsMessage::ConstructL
-
-
-void CSmsMessage::ConstructL(CSmsPDU::TSmsPDUType aType,TBool aIsRPError)
- {
- LOGGSMU3("CSmsMessage::ConstructL(): aType=%d, aIsRPError=%d", (TInt) aType,
- aIsRPError);
-
- iCharacterSetConverter=CCnvCharacterSetConverter::NewL();
- iInformationElementArray = new (ELeave) RPointerArray<CEmsInformationElement>(2);
-
- iAdditionalInfo = CSmsMessageAdditionalAttributes::NewL();
- CreateControlIEOperationsClassesL();
- CreateControlNonIEOperationsClassesL();
-
- iSmsPDU=CSmsPDU::NewL(aType,*iCharacterSetConverter,iFs,aIsRPError);
- SetIsComplete(ETrue);
- SetIsDecoded(ETrue);
- } // CSmsMessage::ConstructL
-
-
-/**
- * Counts the number of PDUs that this message will take. To do this the
- * message will attempt to be encoded into 1 message, and if not into
- * multiple messages. Due to the processing, the function should be used
- * sparingly.
- *
- * @return Number of PDUs required.
- */
-TInt CSmsMessage::NumMessageEmsPDUsL()
- {
- LOGGSMU1("CSmsMessage::NumMessageEmsPDUsL()");
-
- //
- // Clear the concatenated flag, EncodeBufferL() will add it if needed.
- //
- SmsPDU().SetTextConcatenatedL(EFalse, EFalse);
-
- //
- // Attempt to encode to a single PDU, and if that fails then attempt to
- // encode to a set of PDUs.
- //
- CArrayFixFlat<TGsmSms>* tmpArray = new (ELeave) CArrayFixFlat<TGsmSms>(8);
- CleanupStack::PushL(tmpArray);
- TInt numMsgs = 1;
-
- if (!EncodeIntoSinglePDUL(*tmpArray))
- {
- TInt unconvertedChars, downgradedChars, freeUDUnitsInLastPDU;
-
- EncodeBufferL(*tmpArray, 0, *iBuffer, unconvertedChars,
- downgradedChars, freeUDUnitsInLastPDU, EFalse);
-
- numMsgs = iAdditionalInfo->SmsPDUArray().Count();
- }
-
- CleanupStack::PopAndDestroy(tmpArray);
-
- LOGGSMU2("CSmsMessage::NumMessageEmsPDUsL() returns %d", numMsgs);
-
- return numMsgs;
- } // CSmsMessage::NumMessageEmsPDUsL
-
-
-/**
- * @internalComponent
- *
- * This method removes all non mandatory information elements from the
- * working PDU.
- *
- * The working PDU is the PDU which is currently being encoded or decoded.
- *
- * @leave KErrAlreadyExists or KErrAlreadyExists
- */
-void CSmsMessage::ResetWorkingPDUL()
- {
- LOGGSMU1("CSmsMessage::ResetWorkingPDUL()");
-
- CSmsUserData& uData = SmsPDU().UserData();
- //remove non-mandatory EMS information elements
- for (TInt a=uData.NumInformationElements(); a>0; --a)
- {
- const CSmsInformationElement& ie = uData.InformationElement(a-1);
-
- TSmsInformationElementCategories::TInformationElementCategory category;
-
- if (TSmsInformationElementCategories::GetCategoryDefinition(ie.Identifier(), category) &&
- (category != TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUAndWithIdenticalValues) &&
- (category != TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUButWithValueSpecificToPDU) &&
- (category != TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUMultipleInstancesPerPDU))
- {
- uData.RemoveInformationElement(a-1);
- }
- }
- // reset user body
- uData.SetBodyL(KNullDesC8);
- } // CSmsMessage::ResetWorkingPDUL
-
-
-void CSmsMessage::CorrectFormattingL(TUint aCharsAddedToCurrentPDU,
- RPointerArray<CEmsInformationElement>& aCorrectedFormattingIEArray,
- TUint aCharsAlreadyAdded)
- {
- LOGGSMU3("CSmsMessage::CorrectFormattingL(): aCharsAddedToCurrentPDU=%d, aCharsAlreadyAdded=%d",
- aCharsAddedToCurrentPDU, aCharsAlreadyAdded);
-
- CSmsUserData& uData = SmsPDU().UserData();
- for (TInt a= 0; a < uData.NumInformationElements(); a++)
- {
- CSmsInformationElement& ie = uData.InformationElement(a);
- if (CSmsInformationElement::ESmsEnhancedTextFormatting==ie.Identifier())
- {
- CEmsFormatIE& formatIE=static_cast<CEmsFormatIE&>(ie);
-
- TUint oldFormatLen=formatIE.FormatLength(); //
- if(aCharsAddedToCurrentPDU < formatIE.StartPosition() + oldFormatLen)
- {
- TUint newFormatLen=aCharsAddedToCurrentPDU - formatIE.StartPosition();
- formatIE.SetFormatLength(newFormatLen);
-
- // Now, re-encode the information element - this is because we have
- // changed a message in the UserData which is using EMS elements as
- // SMS IEs. Encoding is NOT automatic
- formatIE.EncodeInformationElementL();
-
- if((TInt)(aCharsAlreadyAdded+aCharsAddedToCurrentPDU) < iBuffer->Length())
- {
- CEmsFormatIE* newie=static_cast<CEmsFormatIE*>(formatIE.DuplicateL());
- CleanupStack::PushL(newie);
- newie->SetFormatLength(oldFormatLen - newFormatLen);
- newie->SetStartPosition(aCharsAlreadyAdded+aCharsAddedToCurrentPDU);
- LOGGSMU2("CSmsMessage::CorrectFormattingL",aCorrectedFormattingIEArray.Count());
- aCorrectedFormattingIEArray.Append(newie);
- CleanupStack::Pop(newie);
- }
- }
- }
- }
- } // CSmsMessage::CorrectFormattingL
-
-
-void CSmsMessage::CorrectFormattingInSinglePDUL()
- {
- LOGGSMU1("CSmsMessage::CorrectFormattingInSinglePDUL()");
-
- CSmsUserData& uData = SmsPDU().UserData();
- for (TInt a= 0; a < uData.NumInformationElements(); a++)
- {
- CSmsInformationElement& ie = uData.InformationElement(a);
- if (CSmsInformationElement::ESmsEnhancedTextFormatting==ie.Identifier())
- {
- CEmsFormatIE& formatIE=static_cast<CEmsFormatIE&>(ie);
- TUint oldFormatLen=formatIE.FormatLength(); //
- if(iBuffer->Length() < (TInt)(formatIE.StartPosition()+ oldFormatLen))
- {
- TUint newFormatLen=iBuffer->Length() - formatIE.StartPosition();
- formatIE.SetFormatLength(newFormatLen);
-
- // reencode
- formatIE.EncodeInformationElementL();
- }
- }
- }
- } // CSmsMessage::CorrectFormattingInSinglePDUL
-
-
-/**
- * Adds a copy of the current PDU to the PDU array used to record all the
- * PDUs being encoded in a concatentated message.
- *
- * @param aDoEncode If true the PDU is added and updated. If false only a
- * NULL placeholder is stored. This allows the number of
- * PDUs to be quickly counted if the encoded PDUs are of
- * no further use.
- */
-void CSmsMessage::AddCurrentPDUToPDUArrayL(TBool aDoEncode)
- {
- LOGGSMU2("CSmsMessage::AddCurrentPDUToPDUArrayL(): Adding PDU number %d",
- iAdditionalInfo->SmsPDUArray().Count() + 1);
-
- //
- // Maximum number of PDU is 255, so if we have that already then we cannot
- // continue.
- //
- TInt numPDUs = iAdditionalInfo->SmsPDUArray().Count();
-
- if (numPDUs >= 255)
- {
- User::Leave(KErrOverflow);
- }
-
- //
- // We only do most of the work if we are actually encoding.
- //
- if (aDoEncode)
- {
- //
- // Update the Concatenated Message PDU numbers in the current PDU. This
- // means that at least the last PDU has the correct values (to update
- // all PDUs when a new PDU is added would be too slow, so we do that
- // only once at the end).
- //
- if (numPDUs > 0)
- {
- SmsPDU().SetConcatenatedMessagePDUIndex(numPDUs+1);
- SmsPDU().SetNumConcatenatedMessagePDUs(numPDUs+1);
- }
-
- //
- // Create copy of the current PDU and store it in the array...
- //
- CSmsPDU* newPDU = SmsPDU().DuplicateL();
- CleanupStack::PushL(newPDU);
- iAdditionalInfo->SmsPDUArray().AppendL(newPDU);
- CleanupStack::Pop(newPDU);
- }
- else
- {
- //
- // Otherwise just append a NULL value to allow the data PDUs to be
- // counted...
- //
- iAdditionalInfo->SmsPDUArray().AppendL(NULL);
- }
- } // CSmsMessage::AddCurrentPDUToPDUArrayL
-
-
-TBool CSmsMessage::AddIEToUserDataL(CEmsInformationElement* aIE, TInt aCharsAlreadyAdded,TUint& aCharsAddedToCurrentPDU,CSmsEMSBufferSegmenter& aSeg)
- {
- LOGGSMU1("CSmsMessage::AddIEToUserDataL()");
-
- TBool ieAdded=EFalse;
- if (SmsPDU().UserData().EmsInformationElementWillFitL(aIE,aSeg,aCharsAddedToCurrentPDU))
- {
- CEmsInformationElement* newIE=aIE->DuplicateL();
- newIE->SetStartPosition(newIE->StartPosition()-aCharsAlreadyAdded);
- CleanupStack::PushL(newIE);
- SmsPDU().UserData().AddEmsInformationElementL(newIE);
- CleanupStack::Pop(newIE);
- ieAdded=ETrue;
- }
- return ieAdded;
- } // CSmsMessage::AddIEToUserDataL
-
-
-/**
- * Fills the current PDU with the number of specified native chars.
- *
- * @param aSeg Buffer containing the native chars
- * @param aNumChars number of native characters to add.
- * @param aEncoding SMS Encoding if required.
- *
- * @return TInt Number of native characters added
- */
-TInt CSmsMessage::FillPduL(CSmsEMSBufferSegmenter& aSeg, TInt aNumChars, TSmsEncoding aEncoding)
- {
- LOGGSMU1("CSmsMessage::FillPduL()");
-
- TUint maxUDUnitsREmaining=SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
-
- if (aNumChars==0 || maxUDUnitsREmaining==0)
- {
- return 0;
- }
-
- HBufC8* buf=HBufC8::NewMaxLC(2*aNumChars);
- TPtr8 ptr(buf->Des());
- TInt numberOfUnconvertibleCharacters(0);
- TInt numberOfDowngradedCharacters(0);
-
- TInt nativeLength = aSeg.SegmentL(ptr, aNumChars, maxUDUnitsREmaining,
- numberOfUnconvertibleCharacters,
- numberOfDowngradedCharacters,
- aEncoding);
-
- SmsPDU().UserData().AppendBodyL(ptr);
-
- CleanupStack::PopAndDestroy(buf);
- return nativeLength;
- } // CSmsMessage::FillPduL
-
-
-/**
- * This method copies control information elements from the specified
- * collection into the working PDU.
- *
- * @param aCategory The category of control information element to be
- * added to the PDU.
- * @param aMandatoryInPDU Specifies whether the specified category of information
- * element must be added to this PDU.
- * @param aDoEncode Flag indicating if encoding is really wanted, or just the
- * calculation of the number of PDUs.
- *
- * @leave KErrArgument If the category is mandatory but one or more elements
- * cannot be added then the encoding will fail.
- * @leave KErrOverFlow If the information element is too big to be encoded into
- * a PDU that contains only the mandatory elements.
- */
-void CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL(TSmsInformationElementCategories::TInformationElementCategory aCategory,
- TBool aMandatoryInPDU, TBool aDoEncode)
- {
- LOGGSMU1("CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL()");
-
- TUint numberOfInformationElements = iAdditionalInfo->NumberOfControlInformationElements(aCategory);
-
- for (TInt i = 0; i < numberOfInformationElements; i++)
- {
- CSmsInformationElement& informationElement = iAdditionalInfo->GetControlInformationElementL( aCategory, i);
-
- CSmsInformationElement* cloneInformationElement = CSmsInformationElement::NewL(informationElement.Identifier(),informationElement.Data());
- CleanupStack::PushL(cloneInformationElement);
-
- if (SmsPDU().UserData().ControlInformationElementWillFitL(cloneInformationElement))
- {
- SmsPDU().UserData().UpdateInformationElementArrayL(informationElement.Identifier(),informationElement.Data());
- }
- else if (aMandatoryInPDU)
- {
- // Error Scenario, cannot fit the mandatory PDU into the User Data
- User::Leave(KErrArgument);
- }
- else
- {
- // Close off PDU and transfer to output array
- AddCurrentPDUToPDUArrayL(aDoEncode);
- ResetWorkingPDUL();
-
- // Now test whether the information element will fit into a PDU at all.
- // It is possible to make Enhanced Voice Mail Information Elements
- // bigger than the available space in the PDU.
- TBool canFit = SmsPDU().UserData().ControlInformationElementWillFitL(cloneInformationElement);
- if (canFit == EFalse)
- {
- LOGGSMU1("CSmsMessage::AddControlInformationElementsToMultiSegmentMessage, IE too bit to fit in any PDUL");
- User::Leave(KErrArgument);
- }
- i--;
- }
-
- CleanupStack::PopAndDestroy(cloneInformationElement);
- }
- } // CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL
-
-
-/**
- * This method copies control information elements from the collections of
- * control information elements contained in CSmsAdditionalAttributes into the
- * working PDU.
- *
- * @param aDoEncode Flag indicating if encoding is really wanted, or just the
- * calculation of the number of PDUs.
- *
- * @leave KErrArgument If the category is mandatory but one or more elements
- * cannot be added then the encoding will fail.
- */
-void CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL(TBool aDoEncode)
- {
- LOGGSMU1("CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL() 1");
-
- TBool mandatoryInEachPDU = ETrue;
- AddControlInformationElementsToMultiSegmentMessageL(TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly,
- mandatoryInEachPDU, aDoEncode);
- mandatoryInEachPDU = EFalse;
- AddControlInformationElementsToMultiSegmentMessageL(TSmsInformationElementCategories::ECtrlSingleInstanceOnly,
- mandatoryInEachPDU, aDoEncode);
- AddControlInformationElementsToMultiSegmentMessageL(TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed,
- mandatoryInEachPDU, aDoEncode);
- } // CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL
-
-
-/**
- * Attempts to add EMS IE to the current PDU.
- *
- * @param aSegmenter Reference to buffer segmenter.
- * @param aCharsAddedToCurrentPDU Returned number of characters added to current PDU.
- * @param aDoEncode Flag indicating if encoding is really wanted,
- * or just the calculation of the number of PDUs.
- * @param aEncoding SMS 7bit encoding if appropriate.
- * @param aCorrectedFormatingIEArray Array of IEs that have to be placed in following
- * PDUs (e.g. corrected).
- * @param aCurrEMSIEno Current IE number.
- * @param aCharsAlreadyAdded Returned number of characters added.
- *
- * @return Whether EMS IE has beenn added, in singleMode returns true if there are no more than one PDU.
- */
-TBool CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL(CSmsEMSBufferSegmenter& aSegmenter,
- TUint& aCharsAddedToCurrentPDU,
- TBool aDoEncode,
- TSmsEncoding& aEncoding,
- RPointerArray<CEmsInformationElement>& aCorrectedFormatingIEArray,
- TUint& aCurrEMSIEno,
- TUint& aCharsAlreadyAdded)
- {
- LOGGSMU1("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL()");
-
- TUint startPosition=0;
-
- // number of chars added to the current PDU
- TUint no=iInformationElementArray->Count();
- LOGGSMU2("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL no of IE %d",no);
- CEmsInformationElement* ie = NULL;
- TUint msgLen=iBuffer->Length();
- TUint filledChars=0;
-
- while(aCurrEMSIEno < no || aCorrectedFormatingIEArray.Count() > 0)
- {
- ie = NULL;
- TBool correction=EFalse;
- if(aCurrEMSIEno < no)
- {
- ie = (*iInformationElementArray)[aCurrEMSIEno];
- startPosition=ie->StartPosition();
- }
-
- if(ie == NULL || ( startPosition != aCharsAlreadyAdded) )
- {
- if(aCorrectedFormatingIEArray.Count() > 0)
- {
- correction=ETrue;
- ie = aCorrectedFormatingIEArray[0];
- startPosition=ie->StartPosition();
- }
- }
-
- __ASSERT_ALWAYS(ie !=NULL, User::Leave(KErrCorrupt));
-
- if(startPosition <= msgLen)
- {
- __ASSERT_DEBUG(startPosition>=aCharsAlreadyAdded, User::Leave(KErrUnderflow));
- startPosition -= aCharsAlreadyAdded; // startPosition now relative to current PDU.
-
- // Add all chars upto startposition.
- filledChars=0;
-
- if(startPosition > aCharsAddedToCurrentPDU)
- {
- filledChars = FillPduL(aSegmenter, startPosition-aCharsAddedToCurrentPDU, aEncoding);
- aCharsAddedToCurrentPDU+=filledChars;
- }
-
- LOGGSMU2("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL: filled %d chars", filledChars);
-
- if (aCharsAddedToCurrentPDU==startPosition)
- {
- // Try adding the IE.
- if (AddIEToUserDataL(ie, aCharsAlreadyAdded,aCharsAddedToCurrentPDU,aSegmenter))
- {
- if(correction)
- {
- aCorrectedFormatingIEArray.Remove(0);
- // aCorrectedFormatingIEArray[0] has been removed. In next loop, ie will point another element. So there is no double free.
- // coverity[double_free]
- delete ie;
- correction=EFalse;
- }
- else aCurrEMSIEno++;
- }
- else
- {
- // Information Element will not fit send PDU
- LOGGSMU1("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL: ie will not fit send Message");
- CorrectFormattingL(aCharsAddedToCurrentPDU,aCorrectedFormatingIEArray,aCharsAlreadyAdded);
-
- aCharsAlreadyAdded += aCharsAddedToCurrentPDU;
- aCharsAddedToCurrentPDU=0;
-
- AddCurrentPDUToPDUArrayL(aDoEncode);
- ResetWorkingPDUL();
-
- //
- // Find the encoding method for the next segment...
- //
- //aEncoding = ESmsEncodingNone;
- //TRAP_IGNORE(aEncoding = aSegmenter->FindBestAlternativeEncodingL(iAdditionalInfo->iAlternative7bitEncoding,
- // maxBodyLength));
- SmsPDU().SetNationalLanguageEncodingL(aEncoding);
- }
- }
- else
- {
- // native chars upto start position will not fit send PDu.
- LOGGSMU1("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL: PDU is filled with chars sending");
-
- CorrectFormattingL(aCharsAddedToCurrentPDU,aCorrectedFormatingIEArray,aCharsAlreadyAdded);
-
- aCharsAlreadyAdded += aCharsAddedToCurrentPDU;
- aCharsAddedToCurrentPDU=0;
-
- AddCurrentPDUToPDUArrayL(aDoEncode);
- ResetWorkingPDUL();
-
- //
- // Find the encoding method for the next segment...
- //
- //aEncoding = ESmsEncodingNone;
- //TRAP_IGNORE(aEncoding = aSegmenter->FindBestAlternativeEncodingL(iAdditionalInfo->iAlternative7bitEncoding,
- // maxBodyLength));
- SmsPDU().SetNationalLanguageEncodingL(aEncoding);
- }
- }
- else
- {
- aCurrEMSIEno++;
- }
- } // end of while loop for all IEs
-
- return ETrue;
- } // CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL
-
-
-/**
- * Attempts to add EMS IE to the current PDU
- *
- * @param aSegmenter
- * @return TBool whether EMS IEs have been added to segment
- */
-TBool CSmsMessage::AddEMSInformationElementsToSingleSegmentMessageL(CSmsEMSBufferSegmenter& aSegmenter,
- TSmsEncoding aEncoding)
- {
- LOGGSMU1("CSmsMessage::AddEMSInformationElementsToSingleSegmentMessageL()");
-
- TUint charsAddedToCurrentPDU=0;
- TUint numOfEmsIE=iInformationElementArray->Count();
- TUint currEmsIEindex=0;
- CEmsInformationElement* ie = NULL;
- TUint startPosition=0;
- TUint filledChars=0;
-
- while(currEmsIEindex < numOfEmsIE)
- {
- ie = (*iInformationElementArray)[currEmsIEindex];
- startPosition=ie->StartPosition();
-
- if (startPosition > charsAddedToCurrentPDU)
- {
- filledChars = FillPduL(aSegmenter, startPosition-charsAddedToCurrentPDU, aEncoding);
- charsAddedToCurrentPDU+=filledChars;
- }
-
- if (charsAddedToCurrentPDU != startPosition ||
- !AddIEToUserDataL(ie, 0,charsAddedToCurrentPDU,aSegmenter))
- {
- return EFalse;
- }
-
- ++currEmsIEindex;
- }
-
- return ETrue;
- } // CSmsMessage::AddEMSInformationElementsToSingleSegmentMessageL
-
-
-/**
- * Encode the PDU into an TGsmSms array. The Text and the EMS objects are
- * laid out with respect to start position locations and encoded into the
- * correct TGsmSms object.
- *
- * @leave KErrUnderflow if the Ems objects are not in Start position order.
- *
- * @param aSmsArray Returned array of newly created TSms objects
- * containing the encoded message.
- * @param aReference Unique reference number to be given to the
- * TGsmSms objects.
- * @param aBuffer Body Text buffer of the message.
- * @param aUnconvertedChars Exit param for the number of characters not converted.
- * @param aDowngradedChars Exit param for the number of characters downgraded.
- * @param aFreeUDUnitsInLastPDU Exit param for the number of characters free
- * in the last PDU.
- * @param aDoEncode Flag indicating if encoding is really wanted,
- * or just the calculation of the number of PDUs.
- */
-void CSmsMessage::EncodeBufferL(CArrayFix<TGsmSms>& aSmsArray, TInt aReference,
- const CSmsBufferBase& aBuffer,
- TInt& aUnconvertedChars, TInt& aDowngradedChars,
- TInt& aFreeUDUnitsInLastPDU, TBool aDoEncode)
- {
- LOGGSMU1("CSmsMessage::EncodeBufferL()");
-
- aUnconvertedChars = 0;
- aDowngradedChars = 0;
- aFreeUDUnitsInLastPDU = 0;
-
- //
- // Reset the working array of PDUs...
- //
- iAdditionalInfo->SmsPDUArray().ResetAndDestroy();
-
- TUint currEMSIEno(0);
-
- TInt smscIndex(0);
- TBool smscPresent(EFalse);
-
- TInt emailOverallHeaderLength(0);
- TInt emailIndex(0);
- TBool emailPresent(EFalse);
-
- if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
- {
- smscPresent=ETrue;
- }
- if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEIRFC822EmailHeader,emailIndex))
- {
- emailPresent=ETrue;
- emailOverallHeaderLength=SmsPDU().UserData().InformationElement(emailIndex).Data()[0];
- }
-
- //
- // Create Array for corrected format elements. These will be elements that
- // have to be moved into subsequent PDUs due to lack of space in the
- // current PDU.
- //
- RPointerArray<CEmsInformationElement> correctedFormatingIEArray(2);
- CleanupResetAndDestroyPushL(correctedFormatingIEArray);
-
- //
- // Reset the working PDU. This safes time be keeping fields we need and
- // droping any data from previous PDUs.
- //
- ResetWorkingPDUL();
-
- //
- // Automatically prepare for concatenation (any single PDU messages would
- // have been handled by EncodeIntoSinglePDUL() previously).
- //
- SmsPDU().SetTextConcatenatedL(ETrue,iIs16BitConcatenation);
-
- TInt maxBodyLength=SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
-
- //
- // Add any elements that are required to be present, and ensure they
- // have correct data stored (for example if we are recycling the working PDU).
- //
- AddControlInformationElementsToMultiSegmentMessageL(aDoEncode);
-
- //
- // Create EMS Segmenter and Buffer Converter...
- //
- CSmsAlphabetConverter* converter = CSmsAlphabetConverter::NewLC(*iCharacterSetConverter, iFs,SmsPDU().Alphabet(),
- BinaryData());
- CSmsEMSBufferSegmenter* segmenter = CSmsEMSBufferSegmenter::NewLC(*converter, aBuffer, maxBodyLength);
- TBool isUnicode = (SmsPDU().Alphabet() == TSmsDataCodingScheme::ESmsAlphabetUCS2);
-
- TBool informationToSend = ETrue;
- TUint charsAdded2CurrentPDU = 0;
- TUint charsAlreadyAdded = 0;
-
- //
- // Find the best alternative encoding for the current segment. This will be
- // set at the beginning of each PDU using the list of encoders.
- //
- TSmsEncoding encodingToUse = ESmsEncodingNone;
-
- TRAP_IGNORE(encodingToUse = segmenter->FindBestAlternativeEncodingL(iAdditionalInfo->Alternative7bitEncoding(),
- aBuffer.Length()));
- SmsPDU().SetNationalLanguageEncodingL(encodingToUse);
-
- //
- // If there are information elements to add, add them to the first PDU (or
- // to the correct formatting array for later PDUs if more appropriate).
- //
- if(iInformationElementArray->Count() >0)
- {
- AddEMSInformationElementsToMultiSegmentMessageL(*segmenter, charsAdded2CurrentPDU,
- aDoEncode, encodingToUse,
- correctedFormatingIEArray,
- currEMSIEno, charsAlreadyAdded);
- }
-
- //
- // Allocate a temporary buffer to work with...
- //
- HBufC8* buf=HBufC8::NewMaxLC(maxBodyLength);
- TPtr8 ptr(buf->Des());
-
- //
- // While there is still data to encode see how much space is left in this
- // PDU and attempt to encode something into it...
- //
- while (segmenter->MoreL())
- {
- LOGGSMU1("CSmsMessage::EncodeBufferL - there is MoreL");
-
- //
- // Calculate the space left to use in this PDU...
- //
- TInt size = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
- LOGGSMU2("CSmsMessage::EncodeBufferL - remaining size in PDU is %d",size);
-
- //
- // While there is no space, correct the formatting (which may
- // introduce any un-placed EMS Elements into the corrected format
- // array) and then start a new PDU...
- //
- while (size==0)
- {
- //
- // Store any elements not yet placed into the array for later...
- //
- CorrectFormattingL(charsAdded2CurrentPDU, correctedFormatingIEArray, charsAlreadyAdded);
-
- //
- // Store this PDU, reset the working PDU and get ready to
- // continue with the next PDU...
- //
- aFreeUDUnitsInLastPDU = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
- AddCurrentPDUToPDUArrayL(aDoEncode);
- ResetWorkingPDUL();
- informationToSend=EFalse;
- charsAlreadyAdded+=charsAdded2CurrentPDU;
- charsAdded2CurrentPDU=0;
-
- //
- // Find the encoding method for the next segment...
- //
- //encodingToUse = ESmsEncodingNone;
- //TRAP_IGNORE(encodingToUse = segmenter->FindBestAlternativeEncodingL(iAdditionalInfo->iAlternative7bitEncoding,
- // maxBodyLength));
- SmsPDU().SetNationalLanguageEncodingL(encodingToUse);
-
- //
- // Add any elements that can be placed now (from previous
- // PDUs and above)...
- //
- LOGGSMU3("CSmsMessage::EncodeBufferL: IE count %d corrected count %d",iInformationElementArray->Count(),correctedFormatingIEArray.Count() );
- if ((TUint)iInformationElementArray->Count() > currEMSIEno ||
- correctedFormatingIEArray.Count() > 0)
- {
- AddEMSInformationElementsToMultiSegmentMessageL(*segmenter,charsAdded2CurrentPDU,
- aDoEncode, encodingToUse,
- correctedFormatingIEArray,
- currEMSIEno,charsAlreadyAdded);
- }
-
- //
- // Calculate the space left remaining in this new PDU...
- //
- size = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
- LOGGSMU2("CSmsMessage::EncodeBufferL - remaining size in PDU is %d",size);
- }
-
- //
- // We have space in this PDU and no elements to place, so obtain
- // the next peice of text that can fit and append it.
- //
- segmenter->SegmentNextL(ptr, size, aUnconvertedChars, aDowngradedChars, encodingToUse);
- SmsPDU().UserData().AppendBodyL(ptr);
-
- TUint charsInSegment= isUnicode ? ptr.Length()/2 : ptr.Length();
- LOGGSMU2("CSmsMessage::EncodeBufferL: segmenting added %d chars", charsInSegment);
-
- //
- // At this point the working PDU is either full (e.g. we filled the
- // remaining space with a chuck of text, or the is some space as we
- // stored the last part of the text.
- //
- // If there are any elements not yet stored, add them to the
- // formatting array...
- //
- charsAdded2CurrentPDU+=charsInSegment;
- CorrectFormattingL(charsAdded2CurrentPDU, correctedFormatingIEArray, charsAlreadyAdded);
- charsAlreadyAdded+=charsAdded2CurrentPDU;
- LOGGSMU2("CSmsMessage::EncodeBufferL(): charsAlreadyAdded=%d", charsAlreadyAdded);
-
- //
- // Now store this PDU and reset the working PDU...
- //
- aFreeUDUnitsInLastPDU = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
- AddCurrentPDUToPDUArrayL(aDoEncode);
- ResetWorkingPDUL();
- informationToSend=EFalse;
- charsAdded2CurrentPDU=0;
-
- //
- // Find the encoding method for the next segment...
- //
- //encodingToUse = ESmsEncodingNone;
- //TRAP_IGNORE(encodingToUse = segmenter->FindBestAlternativeEncodingL(iAdditionalInfo->iAlternative7bitEncoding,
- // maxBodyLength));
- SmsPDU().SetNationalLanguageEncodingL(encodingToUse);
-
- //
- // Add any elements that can be placed now given we have a new
- // empty PDU...
- //
- LOGGSMU3("CSmsMessage::EncodeBufferL: IE count %d corrected count %d",
- iInformationElementArray->Count(), correctedFormatingIEArray.Count() );
- if ((TUint)iInformationElementArray->Count() > currEMSIEno ||
- correctedFormatingIEArray.Count() > 0)
- {
- AddEMSInformationElementsToMultiSegmentMessageL(*segmenter, charsAdded2CurrentPDU,
- aDoEncode, encodingToUse,
- correctedFormatingIEArray,
- currEMSIEno, charsAlreadyAdded);
- }
- LOGGSMU1("CSmsMessage::EncodeBufferL end Moreloop");
- }
- CleanupStack::PopAndDestroy(buf);
-
- LOGGSMU1("CSmsMessage::EncodeBufferL - last PDU");
-
- //
- // This is the last PDU. We need to check if there is a partial PDU left over
- // and add it if needed.
- //
- if (informationToSend)
- {
- aFreeUDUnitsInLastPDU = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
- AddCurrentPDUToPDUArrayL(aDoEncode);
- ResetWorkingPDUL();
- }
-
- //
- // At this point the segmenting and layouts of PDU is complete, so if we
- // find any more data something is wrong...
- //
- if (segmenter->MoreL() || correctedFormatingIEArray.Count() > 0)
- {
- User::Leave(KErrCorrupt);
- }
-
- CleanupStack::PopAndDestroy(3, &correctedFormatingIEArray); // segmenter, converter & correctedFormatingIEArray
-
- //
- // By now the PDUs are segmented and correctly setup for encoding.
- // They have not been encoded yet, as this requires the PDU total to be known.
- // So we go through the array setting the final PDU number/total PDUs and
- // perform the encoding from CSmsPDU to the TGsmPdu object.
- //
- // Note: In the case were aDoEncode is EFalse, iSmsPDUArray will be full
- // of NULL pointers as it is only the count that we need in that case.
- //
- TInt numPDUs = iAdditionalInfo->SmsPDUArray().Count();
-
- LOGGSMU2("CSmsMessage::EncodeBufferL number of PDUs: %d", iAdditionalInfo->SmsPDUArray().Count());
-
- if (aDoEncode)
- {
- CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = iAdditionalInfo->GetStatusReportScheme();
- TGsmSms gsmSms;
-
- for (TInt pdu = 0; pdu < numPDUs; pdu++)
- {
- if(scheme.Id() == EControlParametersScheme)
- {
- if(smscPresent)
- {
- CSmsSMSCCtrlParameterOperations& ieOp = (CSmsSMSCCtrlParameterOperations&)GetOperationsForIEL(CSmsInformationElement::ESmsIEISMSCControlParameters);
- TUint8 octet(0);
-
- if (ieOp.GetStatusReport(pdu, octet) == KErrNone)
- {
- iAdditionalInfo->SmsPDUArray()[pdu]->UpdateSMSCCtrlParameterL(octet);
- }
- }
- else
- {
- User::Leave(KErrNotFound);
- }
- }
- else if(scheme.Id() == ETPSRRScheme)
- {
- TSmsFirstOctet smsReportRequest;
- CSmsTPSRROperations& nonIEOp = (CSmsTPSRROperations&)GetOperationsForNonIEL(ESmsTPSRRParameter);
- smsReportRequest = nonIEOp.GetStatusReport(pdu);
-
- iAdditionalInfo->SmsPDUArray()[pdu]->UpdateTPSRRL(smsReportRequest);
- }
-
- if(emailPresent)
- {
- iAdditionalInfo->SmsPDUArray()[pdu]->UpdateEmailHeaderDataL(emailOverallHeaderLength);
- }
-
- //
- // Set the concatenation Message Reference number and PDU numbers...
- //
- iAdditionalInfo->SmsPDUArray()[pdu]->UpdateConcatenationDataL(aReference, pdu+1, numPDUs);
-
- //
- // Encode this PDU...
- //
-
- TEncodeParams encodeParams;
- encodeParams.iTimeStamp = &Time();
-
- TTimeIntervalSeconds interval = UTCOffset();
- encodeParams.iTimeIntervalInSeconds = &interval;
-
- iAdditionalInfo->SmsPDUArray()[pdu]->EncodeMessagePDUL(gsmSms, &encodeParams);
- aSmsArray.AppendL(gsmSms);
- }
-
- //
- // Since the working PDU has been reset the data in it does not match
- // the data of the last PDU. Some tests in SMS Stack assume it does
- // and therefore to retain compatibility we decode the last PDU back
- // over the working PDU.
- //
- TGsmuLex8 lex(gsmSms.Pdu());
- SmsPDU().DecodeL(lex);
- }
- } // CSmsMessage::EncodeBufferL
-
-
-/**
- * Attempts to encode into the single PDU. This function is the private version
- * to the public EncodeIntoSinglePDUL() function. It performs the work and also
- * returns more information regarding the characters encoded.
- *
- * The Text and the EMS objects are laid out with respect to start position
- * locations.
- *
- * @leave KErrUnderflow if the Ems objects are not in Start position order.
- *
- * @param aSmsArray Returned array of newly created TSms objects
- * containing the encoded message.
- * @param aUnconvertedChars Exit param for the number of characters not converted.
- * @param aDowngradedChars Exit param for the number of characters downgraded.
- * @param aFreeUDUnitsInLastPDU Exit param for the number of characters free
- * in the last PDU.
- */
-TBool CSmsMessage::EncodeIntoSinglePDUL(CArrayFix<TGsmSms>& aSmsArray, TInt& aUnconvertedChars,
- TInt& aDowngradedChars, TInt& aFreeUDUnitsInLastPDU)
- {
- LOGGSMU1("CSmsMessage::EncodeIntoSinglePDUL()");
-
- __ASSERT_DEBUG((aSmsArray.Count()==0),Panic(KGsmuPanicSmsArrayNotEmpty));
-
- aUnconvertedChars = 0;
- aDowngradedChars = 0;
- aFreeUDUnitsInLastPDU = 0;
-
- iAdditionalInfo->SmsPDUArray().ResetAndDestroy();
-
- if (!TextPresent())
- {
- if(SmsPDU().Type()==CSmsPDU::ESmsCommand)
- {
- // Commands don't contain text, so commands
- // are only encoded in this branch.
- PrepareCommandMessageL();
- }
-
- TGsmSms sms;
- SmsPDU().EncodeMessagePDUL(sms);
- aSmsArray.AppendL(sms);
- return ETrue;
- }
-
- ResetWorkingPDUL();
-
- // find the length of all the control information elements
- TUint ieLength=0;
- for (TUint8 category = 0; category < TSmsInformationElementCategories::ENumberOfCategories; category++)
- {
- switch (category)
- {
- case TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly:
- case TSmsInformationElementCategories::ECtrlSingleInstanceOnly:
- case TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed:
- {
- for (TUint j = 0; j < iAdditionalInfo->NumberOfControlInformationElements((CSmsMessageAdditionalAttributes::TCategory) category); j++)
- {
- ieLength += iAdditionalInfo->GetControlInformationElementL( ( (CSmsMessageAdditionalAttributes::TCategory) category), j).Length();
- }
- break;
- }
- default:
- break;
- }
- }
- LOGGSMU2("CSmsMessage::EncodeIntoSinglePDUL, ctrl elem len = %d", ieLength);
-
- CEmsInformationElement* emsIE =NULL;
- for (TInt num=0; num<iInformationElementArray->Count();num++)
- {
- emsIE = (*iInformationElementArray)[num];
- ieLength+=emsIE->Length();
- }
-
- TInt remainInBody=SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining(ieLength);
-
- TInt msgLength=MessageLengthL(); // in octets
-
- if( msgLength > remainInBody) return EFalse;
-
- LOGGSMU4("CSmsMessage::EncodeIntoSinglePDUL, ie len = %d, remainInBody = %d, msgLength = %d", ieLength, msgLength, remainInBody);
- // add all control information elements into working PDU.
- //
- for (TUint8 category = 0; category < TSmsInformationElementCategories::ENumberOfCategories; category++)
- {
- switch (category)
- {
- case TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly:
- case TSmsInformationElementCategories::ECtrlSingleInstanceOnly:
- case TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed:
- {
- for (TUint j = 0; j < iAdditionalInfo->NumberOfControlInformationElements((CSmsMessageAdditionalAttributes::TCategory) category); j++)
- {
- CSmsInformationElement& informationElement = iAdditionalInfo->GetControlInformationElementL( ( (CSmsMessageAdditionalAttributes::TCategory) category), j);
-
- CSmsInformationElement* cloneInformationElement = CSmsInformationElement::NewL(informationElement.Identifier(),informationElement.Data());
- CleanupStack::PushL(cloneInformationElement);
- TBool willFit = SmsPDU().UserData().ControlInformationElementWillFitL(cloneInformationElement);
- CleanupStack::PopAndDestroy(cloneInformationElement);
-
- if (willFit)
- {
- SmsPDU().UserData().UpdateInformationElementArrayL(informationElement.Identifier(),informationElement.Data());
- }
- else
- {
- ResetWorkingPDUL();
- return EFalse;
- }
- }
- break;
- }
- default:
- break;
- }
- }
-
- EncodingTPSRRFromSchemesIntoSinglePDUL();
-
- TInt maxBodyLength=SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
- CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,SmsPDU().Alphabet(),BinaryData());
- CSmsEMSBufferSegmenter* segmenter=CSmsEMSBufferSegmenter::NewLC(*converter,*iBuffer, maxBodyLength);
-
- //
- // Find the best alternative encoding for the current segment. This will be
- // set at the beginning of each PDU using the list of encoders.
- //
- TSmsEncoding encodingToUse = ESmsEncodingNone;
-
- TRAP_IGNORE(encodingToUse= segmenter->FindBestAlternativeEncodingL(iAdditionalInfo->Alternative7bitEncoding(),
- maxBodyLength));
- SmsPDU().SetNationalLanguageEncodingL(encodingToUse);
-
- if(!AddEMSInformationElementsToSingleSegmentMessageL(*segmenter, encodingToUse))
- {
- aSmsArray.Reset();
- CleanupStack::PopAndDestroy(2, converter);
- return EFalse;
- }
-
- if(segmenter->MoreL())
- {
- TInt size = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
- // Defensive code to prevent SegmentNextL being called with size of zero
- if (size == 0)
- {
- CleanupStack::PopAndDestroy(2, converter);
- aSmsArray.Reset();
- return EFalse;
- }
- HBufC8* buf=HBufC8::NewMaxLC(maxBodyLength);
- TPtr8 ptr(buf->Des());
- segmenter->SegmentNextL(ptr, size, aUnconvertedChars, aDowngradedChars, encodingToUse);
- SmsPDU().UserData().AppendBodyL(ptr);
- CleanupStack::PopAndDestroy(buf);
- }
- CorrectFormattingInSinglePDUL();
-
- if (segmenter->MoreL())
- {
- CleanupStack::PopAndDestroy(2, converter);
- aSmsArray.Reset();
- return EFalse;
- }
- CleanupStack::PopAndDestroy(2, converter);
-
- aFreeUDUnitsInLastPDU = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
-
- //
- // Encode the PDU...
- //
- TGsmSms gsmSms;
-
- TEncodeParams encodeParams;
- encodeParams.iTimeStamp = &Time();
-
- TTimeIntervalSeconds interval = UTCOffset();
- encodeParams.iTimeIntervalInSeconds = &interval;
-
- SmsPDU().EncodeMessagePDUL(gsmSms, &encodeParams);
- aSmsArray.AppendL(gsmSms);
-
- return ETrue;
- } // CSmsMessage::EncodeIntoSinglePDUL
-
-
-/**
- * Attempts to encode into the single PDU
- * The Text and the EMS objects are layed out with respect to start position locations and encoded into the correct Tsms object.
- * Ensure this function is called before EncodeMessagePDUsL to properly process single PDU messages
- *
- * @return KErrUnderflow if the Ems objects are not in Start position order.
- * @param aSmsArray returned array of newly created TSms objects containing the encoded message
- *
- * @capability None
- */
-EXPORT_C TBool CSmsMessage::EncodeIntoSinglePDUL(CArrayFix<TGsmSms>& aSmsArray)
- {
- LOGGSMU1("CSmsMessage::EncodeIntoSinglePDUL()");
-
- TInt unconvertedChars, downgradedChars, freeUDUnitsInLastPDU;
-
- return EncodeIntoSinglePDUL(aSmsArray, unconvertedChars,
- downgradedChars, freeUDUnitsInLastPDU);
- } // CSmsMessage::EncodeIntoSinglePDUL
-
-
-void CSmsMessage::EncodingTPSRRFromSchemesIntoSinglePDUL()
- {
- TInt smscIndex(0);
- TBool smscPresent(EFalse);
-
- CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = iAdditionalInfo->GetStatusReportScheme();
- if(scheme.Id() == EControlParametersScheme)
- {
- if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
- {
- smscPresent=ETrue;
- }
- if(smscPresent)
- {
- TUint8 octet(0);
-
- CSmsSMSCCtrlParameterOperations& ieOp = (CSmsSMSCCtrlParameterOperations&)GetOperationsForIEL(CSmsInformationElement::ESmsIEISMSCControlParameters);
-
- if (ieOp.GetStatusReport(0, octet) == KErrNone)
- {
- if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
- {
- SmsPDU().UserData().InformationElement(smscIndex).Data()[0] = octet;
- if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
- {
- ((CSmsSubmit&)SmsPDU()).SetStatusReportRequest(ETrue);
- }
- else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
- {
- ((CSmsDeliver&)SmsPDU()).SetStatusReportIndication(ETrue);
- }
- }
- else
- {
- User::Leave(KErrCorrupt);
- }
- }
- }
- else
- {
- User::Leave(KErrNotFound);
- }
- }
- else if(scheme.Id() == ETPSRRScheme)
- {
- TSmsFirstOctet smsReportRequest;
- CSmsTPSRROperations& nonIEOp = (CSmsTPSRROperations&)GetOperationsForNonIEL(ESmsTPSRRParameter);
- smsReportRequest = nonIEOp.GetStatusReport(0);
-
- if(smsReportRequest>=0)
- {
- if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
- {
- ((CSmsSubmit&)SmsPDU()).SetStatusReportRequest(smsReportRequest);
- }
- else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
- {
- ((CSmsDeliver&)SmsPDU()).SetStatusReportIndication(smsReportRequest);
- }
- }
- }
- } // CSmsMessage::EncodingTPSRRFromSchemesIntoSinglePDUL
-
-
-/**
- * Decode CSmsMessage
- *
- * @param aUserData Object containing the EMS objects.
- * @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
- * of the UserData.
- */
-void CSmsMessage::DecodeBufferL(CArrayPtr<CSmsPDU>& aSmsPDUArray,
- CSmsBufferBase& aBuffer)
- {
- LOGGSMU1("CSmsMessage::DecodeBufferL()");
-
- iInformationElementArray->ResetAndDestroy();
-
- TSmsStatusReportScheme schemeId = FindSchemeL(aSmsPDUArray);
-
- TInt emailLen(0);
- for (TInt i=0; i<aSmsPDUArray.Count(); i++)
- {
- CSmsUserData& usrData = (aSmsPDUArray)[i]->UserData();
- InstallControlInformationElementsL(usrData, i);
- InstallEmsInformationElementsL(usrData, aBuffer.Length());
- // Possible refactoring opportunity:
- // This would be a good place to add a method which provides processing for control information
- // elements which contain values specific to the pdu (as opposed to being constant in every PDU.
- InstallEmailHeaderInformationElementL(usrData,emailLen);
- if(schemeId == ETPSRRScheme)
- {
- InstallTPSRRInformationL(aSmsPDUArray, i);
- }
-
- CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,aSmsPDUArray[i]->Alphabet(),BinaryData());
- TSmsBufferReassembler reassembler(*converter,aBuffer);
- TSmsEncoding encodingUsedInSegment = aSmsPDUArray[i]->NationalLanguageEncoding();
-
- reassembler.ReassembleNextL(usrData.Body(),
- encodingUsedInSegment,
- i==(aSmsPDUArray.Count()-1));
-
- CleanupStack::PopAndDestroy(converter);
- MergeAlternative7bitEncoding(encodingUsedInSegment);
- }
-
- // Possible refactoring opportunity:
- // This would be a good place to add a method which provides processing for control information
- // elements which contain values specific to the pdu (as opposed to being constant in every PDU.
- if(emailLen>0)
- {
- if(emailLen>255)
- User::Leave(KErrTooBig);
- TBuf8<1> data;
- data.SetLength(1);
- data[0]=static_cast<TUint8>(emailLen);
- TInt emailIndex;
- if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEIRFC822EmailHeader,emailIndex))
- SmsPDU().UserData().InformationElement(emailIndex).Data()[0]=static_cast<TInt8>(emailLen);
- else
- SmsPDU().UserData().AddInformationElementL(CSmsInformationElement::ESmsIEIRFC822EmailHeader,data);
- }
- UpdateUserPromptAndODIElementsStartPosition();
- } // CSmsMessage::DecodeBufferL
-
-/**
- * It decodes only raw text data.
- *
- * @param aSmsPDUArray Object containing PDUs.
- * @param aBuffer where the decoded data will be stored.
- *
- */
-void CSmsMessage::DecodeOnlyTextL(CArrayPtr<CSmsPDU>& aSmsPDUArray,
- CSmsBufferBase& aBuffer)
- {
- LOGGSMU1("CSmsMessage::DecodeOnlyTextL()");
-
- for (TInt i=0; i<aSmsPDUArray.Count(); i++)
- {
- CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,aSmsPDUArray[i]->Alphabet(),BinaryData());
- TSmsBufferReassembler reassembler(*converter,aBuffer);
- TSmsEncoding encodingUsedInSegment = aSmsPDUArray[i]->NationalLanguageEncoding();
-
- reassembler.ReassembleNextL(aSmsPDUArray[i]->UserData().Body(),
- encodingUsedInSegment,
- i==(aSmsPDUArray.Count()-1));
-
- CleanupStack::PopAndDestroy(converter);
- MergeAlternative7bitEncoding(encodingUsedInSegment);
- }
- } // CSmsMessage::DecodeBufferL
-
-/**
- * It adds the incomplete message info in additional attribute field.
- *
- * @param aStartPDU starting PDU index of incomplete message.
- * @param aEndPDU end PDU index of incomplete message.
- * @param aLastPartialCompleteMsg boolean value indicating whether
- this message is the last incomplete message sent to client.
- */
-void CSmsMessage::AddIncompleteMessageInfoL(TInt aStartPDU, TInt aEndPDU, TBool aLastPartialCompleteMsg)
- {
- LOGGSMU1("CSmsMessage::AddIncompleteMessageInfoL()");
-
- CIncompleteClass0MessageInfo& incompleteClass0MsgInfo = (CIncompleteClass0MessageInfo&) iAdditionalInfo->GetNonIEOperationL(ESmsIncompleteClass0MessageParameter);
- incompleteClass0MsgInfo.SetVersion(CIncompleteClass0MessageInfo::ESmsIncompleteClass0MessageV0);
- incompleteClass0MsgInfo.SetIncompleteMessageInfoL(aStartPDU, aEndPDU, aLastPartialCompleteMsg);
- }
-
-/**
- * This method copies control information elements from the user data (passed as an
- * input argument) into either the CSmsMessage's user data (working pdu) OR one of the
- * collection of control information elements (sorted by category) which is contained
- * in CSmsMessage::iAdditionalInfo.
- *
- * @param aUserData
- * The user data which is currently being processed, and whose elements may be copied
- * into the appropriate collection belonging to the CSmsMessage.
- * @leave
- * KErrArgument if an information element's type is unknown
- *
- * @internalComponent
- */
-void CSmsMessage::InstallControlInformationElementsL(CSmsUserData& aUserData, TInt aSegmentSequenceNum)
- {
- // Installs all the information elements within the subsequent PDUs.
- LOGGSMU1("CSmsMessage::InstallControlInformationElements()");
-
- CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = iAdditionalInfo->GetStatusReportScheme();
-
- for (TInt z=0; z<aUserData.NumInformationElements(); z++)
- {
- const CSmsInformationElement& ie = aUserData.InformationElement(z);
-
- TSmsInformationElementCategories::TInformationElementCategory category;
-
- if (TSmsInformationElementCategories::GetCategoryDefinition(ie.Identifier(), category))
- {
- switch (category)
- {
- case TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUMultipleInstancesPerPDU: // e.g. Special SMS Message Indication
- LOGGSMU2("CSmsMessage::InstallControlInformationElements \
- ECtrlMandatoryInEveryPDUMultipleInstancesPerPDU id = %d", ie.Identifier());
-
- if (ie.Identifier()== CSmsInformationElement::ESmsIEISpecialSMSMessageIndication)
- {
- TBool found = EFalse;
- CArrayFixFlat<TInt>* indices = new(ELeave) CArrayFixFlat<TInt>(4);
- CleanupStack::PushL(indices);
- SmsPDU().UserData().InformationElementIndicesL(ie.Identifier(), *indices);
-
- TInt count = indices->Count();
- for (TInt i=0; ((i<count) && (found==EFalse)); i++)
- {
- TUint index = indices->operator[](i);
- CSmsInformationElement& ieAlreadyInWorkingPDU = SmsPDU().UserData().InformationElement(index);
-
- if (ieAlreadyInWorkingPDU.Data()[0] == ie.Data()[0])
- {
- ieAlreadyInWorkingPDU.Data()[1] = ie.Data()[1];
- found = ETrue;
- break;
- }
- }
- CleanupStack::PopAndDestroy(indices);
-
- if (found == EFalse)
- {
- SmsPDU().UserData().UpdateInformationElementArrayL(ie.Identifier(),ie.Data());
- }
- }
- else
- {
- // Unknown category.
- LOGGSMU3("CSmsMessage::InstallControlInformationElementsL category = %d, id = %d", category, ie.Identifier());
- User::Leave(KErrArgument);
- }
- break;
- case TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly:
- case TSmsInformationElementCategories::ECtrlSingleInstanceOnly:
- {
- LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryIn1stPDUOnly "
- "ECtrlSingleInstanceOnly, id = %d", ie.Identifier());
-
- TUint index = 0;
- if (iAdditionalInfo->Find1stInstanceOfControlInformationElement(ie.Identifier(), index))
- {
- iAdditionalInfo->DeleteControlInformationElement(category, index); // might want to pass the
- // id in as an additional check
- // this should be an exception case
- CSmsInformationElement* newInformationElement = CSmsInformationElement::NewL(ie.Identifier(),ie.Data());
-
- CleanupStack::PushL(newInformationElement);
- iAdditionalInfo->AddControlInformationElementL(category, newInformationElement);
- CleanupStack::Pop(newInformationElement);
- }
- else
- {
- CSmsInformationElement* cloneInformationElement = CSmsInformationElement::NewL(ie.Identifier(),ie.Data());
- CleanupStack::PushL(cloneInformationElement);
- iAdditionalInfo->AddControlInformationElementL(category, cloneInformationElement);
- CleanupStack::Pop(cloneInformationElement);
- }
- break;
- }
- case TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUAndWithIdenticalValues:
- {
- LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryInEveryPDUAndWithIdenticalValues "
- "ECtrlSingleInstanceOnly, id = %d", ie.Identifier());
- TInt index = 0;
- if (SmsPDU().UserData().InformationElementIndex(ie.Identifier(),index))
- {
- CSmsInformationElement* newInformationElement = CSmsInformationElement::NewL(ie.Identifier(),ie.Data());
-
- CleanupStack::PushL(newInformationElement);
- CSmsInformationElement*& indexedPDU = SmsPDU().UserData().InformationElementPtr(index);
- CSmsInformationElement* oldInformationElement = indexedPDU;
- SmsPDU().UserData().InformationElementPtr(index) = newInformationElement;
- // In next loop, oldInformationElement will point to the newly created information element. So double free is no case.
- // coverity[double_free]
- delete oldInformationElement;
- CleanupStack::Pop(newInformationElement);
- }
- else
- {
- SmsPDU().UserData().UpdateInformationElementArrayL(ie.Identifier(),ie.Data());
- }
- break;
- }
-
- case TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed:
- {
- LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryInEveryPDUAndWithIdenticalValues "
- "ECtrlSingleInstanceOnly, id = %d", ie.Identifier() );
-
- CSmsInformationElement* cloneInformationElement = CSmsInformationElement::NewL( ie.Identifier(),ie.Data() );
- CleanupStack::PushL(cloneInformationElement);
- iAdditionalInfo->AddControlInformationElementL( TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed, cloneInformationElement);
- CleanupStack::Pop(cloneInformationElement);
- break;
- }
- case TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUButWithValueSpecificToPDU:
- LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryInEveryPDUButWithValueSpecificToPDU "
- "ECtrlSingleInstanceOnly, id = %d", ie.Identifier() );
-
- if (ie.Identifier() == CSmsInformationElement::ESmsIEISMSCControlParameters)
- {
- if(scheme.Id() == EControlParametersScheme)
- {
- CSmsMessageAdditionalAttributes::CControlParametersScheme& ctrlParamScheme = (CSmsMessageAdditionalAttributes::CControlParametersScheme&)scheme;
- ctrlParamScheme.iDefaultStatusReport = 0x00;
-
- const TUint8* octet(0);
- octet = ie.Data().Ptr();
- if(*octet)
- {
- CSmsMessageAdditionalAttributes::CControlParametersScheme::TSmsSMSCCtrlParameterStatus smscCtrlParameterStatus;
- smscCtrlParameterStatus.iSegmentSequenceNum = aSegmentSequenceNum;
- smscCtrlParameterStatus.iSelectiveStatus = *octet;
- (ctrlParamScheme.iControlParametersStatusReport).AppendL(smscCtrlParameterStatus);
- }
- ctrlParamScheme.iNumOfPDUs++;
- }
- }
-
- // e.g Email Header / Concatenation Elements.
- // Consider whether EMail Header should be ported here.
- // or left as is.
- break;
- case TSmsInformationElementCategories::EEmsInformationElement:
- LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryInEveryPDUButWithValueSpecificToPDU "
- "ECtrlSingleInstanceOnly, id = %d", ie.Identifier() );
- // Will be handled in the method InstallEmsInformationElements, nothing to do here
- break;
- default:
- LOGGSMU3("CSmsMessage::InstallControlInformationElementsToMultiSegmentMessageL, default switch, category = %d, id= %d", category, ie.Identifier() );
- break;
- }
- }
- }
- } // CSmsMessage::InstallControlInformationElementsL
-
-
-/**
- * Extracts all the EMS information objects out of the given UserData into the CSmsMessage IEArray.
- *
- * @param aUserData Object containing the EMS objects.
- * @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
- * of the UserData.
- */
-void CSmsMessage::InstallEmsInformationElementsL(CSmsUserData& aUserData, TInt aCharsAlreadyAdded)
- {
- // Installs all the information elements within the subsequent PDUs.
- LOGGSMU1("CSmsMessage::InstallEmsInformationElements()");
-
- CSmsInformationElement::TSmsInformationElementIdentifier id;
- CEmsInformationElement* newIE =NULL;
-
- for (TInt z=0; z<aUserData.NumInformationElements(); z++)
- {
- const CSmsInformationElement& ie = aUserData.InformationElement(z);
-
- // is the ie an EMS information Element;
- id = ie.Identifier();
- if (CEmsFactory::Supported(id))
- {
- newIE=NULL;
- TRAPD(ret,newIE = CEmsFactory::CreateReceivedEmsIEL(ie,aCharsAlreadyAdded));
- if(newIE != NULL)
- {
- if(ret == KErrNone)
- {
- ret=AddReceivedEmsInformationElement(newIE);
- if(ret==KErrNone) // Remove the Information Element from the User Data.
- aUserData.RemoveInformationElement(z--);
- else
- // newIE is made NULL in first place and then a new IE is created. so double free is no case
- // coverity[double_free]
- delete newIE;
- }
- else
- delete newIE;
- }
- }
- }
- } // CSmsMessage::InstallEmsInformationElementsL
-
-
-/**
- * Extracts all the EMS information objects out of the given Command into the CSmsMessage IEArray.
- *
- * @param aCommand Object containing the EMS objects.
- * @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
- * of the UserData.
- */
-void CSmsMessage::InstallEmsInformationElementsL(CSmsCommand& aCommand, TInt aCharsAlreadyAdded)
- {
- // Ignore in code coverage - not used in SMS stack and not exported
- // but cannot be removed as impacts public header.
- BULLSEYE_OFF
- // Installs all the information elements within the subsequent PDUs.
- LOGGSMU1("CSmsMessage::InstallEmsInformationElements()");
-
- CSmsInformationElement::TSmsInformationElementIdentifier id;
- CEmsInformationElement* newIE=NULL;
-
- for (TInt z=0; z<aCommand.NumInformationElements(); z++)
- {
- const CSmsInformationElement& ie = aCommand.InformationElement(z);
- // is the ie an EMS information Element;
- id = ie.Identifier();
- if (CEmsFactory::Supported(id))
- {
- newIE=NULL;
- TRAPD(ret,newIE = CEmsFactory::CreateReceivedEmsIEL(ie,aCharsAlreadyAdded));
- if(newIE != NULL )
- {
- if(ret == KErrNone)
- {
- ret=AddReceivedEmsInformationElement(newIE);
- if(ret==KErrNone) // Remove the Information Element from the User Data.
- aCommand.RemoveInformationElement(z--);
- else
- // newIE is made NULL in first place and then a new IE is created. so double free is no case.
- // coverity[double_free]
- delete newIE;
- }
- else
- delete newIE;
- }
- }
- }
- BULLSEYE_RESTORE
- }
-
-TSmsStatusReportScheme CSmsMessage::FindSchemeL(const CArrayPtr<CSmsPDU>& aSmsPDUArray)
- {
- TInt smscIndex(0);
-
- if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
- {
- iAdditionalInfo->SetStatusReportSchemeL(EControlParametersScheme);
- return EControlParametersScheme;
- }
-
- TSmsFirstOctet oldTpsrr;
- TSmsFirstOctet tpsrr;
- CSmsSubmit* smsSubmit;
- CSmsDeliver* smsDeliver;
-
- if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
- {
- smsSubmit = reinterpret_cast<CSmsSubmit*>((aSmsPDUArray)[0]);
- oldTpsrr = smsSubmit->StatusReportRequest();
- }
- else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
- {
- smsDeliver = reinterpret_cast<CSmsDeliver*>((aSmsPDUArray)[0]);
- oldTpsrr = smsDeliver->StatusReportIndication();
- }
-
- for (TInt ii=1; ii<aSmsPDUArray.Count(); ii++)
- {
- if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
- {
- smsSubmit = reinterpret_cast<CSmsSubmit*>((aSmsPDUArray)[ii]);
- tpsrr = smsSubmit->StatusReportRequest();
- }
- else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
- {
- smsDeliver = reinterpret_cast<CSmsDeliver*>((aSmsPDUArray)[ii]);
- tpsrr = smsDeliver->StatusReportIndication();
- }
- if(tpsrr != oldTpsrr)
- {
- iAdditionalInfo->SetStatusReportSchemeL(ETPSRRScheme);
- return ETPSRRScheme;
- }
- }
-
- iAdditionalInfo->SetStatusReportSchemeL(EDefaultScheme);
-
- return EDefaultScheme;
- } // CSmsMessage::FindSchemeL
-
-
-void CSmsMessage::InstallTPSRRInformationL(const CArrayPtr<CSmsPDU>& aSmsPDUArray, TInt aSegmentSequenceNum)
- {
- CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = iAdditionalInfo->GetStatusReportScheme();
- CSmsMessageAdditionalAttributes::CTPSRRScheme& tpsrrScheme = (CSmsMessageAdditionalAttributes::CTPSRRScheme&)scheme;
-
- tpsrrScheme.iDefaultStatusReport = TSmsFirstOctet::ESmsStatusReportNotRequested;
- tpsrrScheme.iNumOfPDUs++;
-
- TSmsFirstOctet tpsrr;
-
- if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
- {
- CSmsSubmit* smsSubmit = reinterpret_cast<CSmsSubmit*>((aSmsPDUArray)[aSegmentSequenceNum]);
- tpsrr = smsSubmit->StatusReportRequest();
- }
- else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
- {
- CSmsDeliver* smsDeliver = reinterpret_cast<CSmsDeliver*>((aSmsPDUArray)[aSegmentSequenceNum]);
- tpsrr = smsDeliver->StatusReportIndication();
- }
-
- if(tpsrr)
- {
- CSmsMessageAdditionalAttributes::CTPSRRScheme::TSmsTPSRRStatus tpsrrStatus;
-
- tpsrrStatus.iSegmentSequenceNum = aSegmentSequenceNum;
- tpsrrStatus.iTPSRRStatus = TSmsFirstOctet::ESmsStatusReportRequested;
- tpsrrScheme.iTPSRRStatusReport.AppendL(tpsrrStatus);
- }
- } // CSmsMessage::InstallTPSRRInformationL
-
-
-/**
- * Adds EMS IE to a CSmsMessage
- *
- * @param aEmsIE EMS object to be added.
- *
- * @capability None
- */
-EXPORT_C void CSmsMessage::AddEMSInformationElementL(const CEmsInformationElement& aEmsIE)
- {
- LOGGSMU1("CSmsMessage::AddEMSInformationElementL()");
-
- if(aEmsIE.StartPosition() > (TUint)iBuffer->Length())
- {
- User::Leave(KErrOverflow);
- }
-
- if(CSmsInformationElement::ESmsEnhancedTextFormatting == aEmsIE.Identifier() && aEmsIE.Length() ==0)
- {
- User::Leave(KErrUnderflow);
- }
-
- if(CSmsInformationElement::ESmsEnhancedUserPromptIndicator == aEmsIE.Identifier())
- {
- AddEmsUserPromptL(static_cast<const CEmsUserPrompt&>(aEmsIE));
- }
- else if(CSmsInformationElement::ESmsEnhancedODI == aEmsIE.Identifier())
- {
- AddEmsObjectDistributionL(static_cast<const CEmsObjectDistribution&>(aEmsIE));
- }
- else
- {
- TInt count=iInformationElementArray->Count();
- TInt currNo=0;
- const CEmsInformationElement* emsIE=NULL;
-
- while(currNo < count)
- {
- emsIE=(*iInformationElementArray)[currNo];
- if(emsIE->StartPosition() == aEmsIE.StartPosition() && (CSmsInformationElement::ESmsEnhancedUserPromptIndicator == emsIE->Identifier() || CSmsInformationElement::ESmsEnhancedODI == emsIE->Identifier()))
- User::Leave(KErrArgument);
- else if(emsIE->StartPosition() > aEmsIE.StartPosition())
- break;
- currNo++;
- }
- User::LeaveIfError(iInformationElementArray->Insert(aEmsIE.DuplicateL(),currNo));
- }
- } // CSmsMessage::AddEMSInformationElementL
-
-
-TBool CSmsMessage::CanBeRemoved(const CEmsInformationElement& aIE, const TUint aIEIndex)
- {
- LOGGSMU1("CSmsMessage::CanBeRemoved()");
-
- TBool ret=ETrue;
- if(CSmsInformationElement::ESmsEnhancedODI == aIE.Identifier())
- return ret;
-
- TUint ieStartPosition=aIE.StartPosition();
- TUint count=iInformationElementArray->Count();
- CEmsInformationElement* ie=NULL;
-
- // is there a UserPrompt/ODI at the same position
- for (TUint i=0; i < count && ret; ++i)
- {
- ie = (*iInformationElementArray)[i];
- // Do not allow removal if start position matches a user prompt and it is not the user prompt itself being removed
- if (ie->StartPosition() == ieStartPosition && ie->Identifier() == CSmsInformationElement::ESmsEnhancedUserPromptIndicator && aIE.Identifier() != CSmsInformationElement::ESmsEnhancedUserPromptIndicator)
- ret=EFalse;
- if (ie->Identifier() == CSmsInformationElement::ESmsEnhancedODI)
- {
- // don't allow removal of IE if position inside object count of ODI
- if ((static_cast<CEmsObjectDistribution*>(ie)->ObjectCount()+i) >= aIEIndex || static_cast<CEmsObjectDistribution*>(ie)->ObjectCount() == 0)
- ret=EFalse;
- }
- }
-
- LOGGSMU2("CSmsMessage::CanBeRemoved() returns %d", ret);
-
- return ret;
- } // CSmsMessage::CanBeRemoved
-
-
-/**
- * Adds EMS IE to a CSmsMessage
- *
- * @param aEmsIE EMS object to be added.
- */
-void CSmsMessage::AddEmsUserPromptL(const CEmsUserPrompt& aUserPromptIE)
- {
- LOGGSMU1("CSmsMessage::AddEmsUserPromptL()");
-
- if(aUserPromptIE.ObjectCount() == 0 )User::Leave(KErrArgument);
-
- TUint count=iInformationElementArray->Count();
- TUint userPromptStartPosition=aUserPromptIE.StartPosition();
-
- TSmsId id=aUserPromptIE.Identifier();
- TBool allSameType=ETrue;
- TUint countOnTheSamePos=0;
- TUint firstIndex=0;
-
- // collect all IEs on the same startPosition as the new User Prompt
- CEmsInformationElement* ie=NULL;
-
- for (TUint i=0; i < count ; i++)
- {
- ie = (*iInformationElementArray)[i];
- if (ie->StartPosition() == userPromptStartPosition)
- {
- if(countOnTheSamePos==0)
- {
- firstIndex=i;
- id = ie->Identifier();
- }
- else
- {
- if(allSameType && id != ie->Identifier())allSameType=EFalse;
- else id = ie->Identifier();
- }
- ++countOnTheSamePos;
- }
- }
-
- if(countOnTheSamePos != aUserPromptIE.ObjectCount())
- User::Leave(KErrArgument);
-
-
- if( countOnTheSamePos == 1)
- {
- switch(id)
- {
- case CEmsInformationElement::ESmsEnhancedPredefinedAnimation:
- case CEmsInformationElement::ESmsEnhancedLargeAnimation :
- case CEmsInformationElement::ESmsEnhancedSmallAnimation :
- case CEmsInformationElement::ESmsEnhancedUserDefinedSound:
- case CEmsInformationElement::ESmsEnhancedLargePicture:
- case CEmsInformationElement::ESmsEnhancedSmallPicture:
- case CEmsInformationElement::ESmsEnhancedVariablePicture:
- User::LeaveIfError(iInformationElementArray->Insert(aUserPromptIE.DuplicateL(),firstIndex));
- break;
- default:
- User::Leave(KErrCorrupt);
- break;
- }
- return;
- }
-
- // stitching - more than one object
- if(allSameType && (id == CEmsInformationElement::ESmsEnhancedUserDefinedSound || id == CEmsInformationElement::ESmsEnhancedLargePicture || id == CEmsInformationElement::ESmsEnhancedSmallPicture || id == CEmsInformationElement::ESmsEnhancedVariablePicture))
- {
- User::LeaveIfError(iInformationElementArray->Insert(aUserPromptIE.DuplicateL(),firstIndex));
- return;
- }
-
- // not of the same type or not supported IE types
- User::Leave(KErrCorrupt);
- } // CSmsMessage::AddEmsUserPromptL
-
-
-/**
- * Adds EMS IE to a CSmsMessage
- *
- * @param aEmsIE EMS object to be added.
- */
-void CSmsMessage::AddEmsObjectDistributionL(const CEmsObjectDistribution& aObjectDistributionIE)
- {
- LOGGSMU1("CSmsMessage::AddEmsObjectDistributionL()");
-
- TUint count=iInformationElementArray->Count();
- TUint objectDistributionStartPosition=aObjectDistributionIE.StartPosition();
-
- TBool firstIndexFound=EFalse;
- TUint firstIndex=0;
- TUint countOnSameOrSubsequentPos=0;
-
- // collect any IEs on the same or greater startPosition as the new Object Distribution Indicator
- CEmsInformationElement* ie=NULL;
-
- for (TUint i=0; i < count; i++)
- {
- ie = (*iInformationElementArray)[i];
- if (ie->StartPosition() >= objectDistributionStartPosition)
- {
- // Only set index if at least one IE found at desired start position
- if (!firstIndexFound)
- {
- firstIndex=i;
- firstIndexFound=ETrue;
- }
- ++countOnSameOrSubsequentPos;
- }
- }
- // check number of IEs present for desired ObjectCount
- if(countOnSameOrSubsequentPos < aObjectDistributionIE.ObjectCount())
- User::Leave(KErrArgument);
-
- if (firstIndexFound)
- {
- User::LeaveIfError(iInformationElementArray->Insert(aObjectDistributionIE.DuplicateL(),firstIndex));
- return;
- }
-
- // no valid IE for ODI to apply to
- User::Leave(KErrCorrupt);
- } // CSmsMessage::AddEmsObjectDistributionL
-
-
-/**
- * Removes first EMS IE that matches the criteria from the CSmsMessage
- *
- * @param aStartPosition of a EMS object to be removed.
- * @param aEmsId type of a EMS object to be removed
- * @return pointer EMS information element
- * @capability
- * @capability None
- */
-EXPORT_C CEmsInformationElement* CSmsMessage::RemoveEMSInformationElementL(const TUint aStartPosition,const TSmsId aEmsId)
- {
- LOGGSMU1("CSmsMessage::RemoveEMSInformationElementL()");
-
- CEmsInformationElement* emsIE=NULL;
- CEmsInformationElement* ie=NULL;
-
- TUint count=iInformationElementArray->Count();
-
- for (TInt i=--count; i >=0 ; --i)
- {
- ie = (*iInformationElementArray)[i];
- if (ie->StartPosition() == aStartPosition && ie->Identifier() == aEmsId)
- {
- if(CanBeRemoved(*ie, i))
- {
- iInformationElementArray->Remove(i);
- emsIE=ie;
- }
- else
- emsIE=NULL;
- break;
- }
-
- }
- return emsIE;
- } // CSmsMessage::RemoveEMSInformationElementL
-
-
-/**
- * Removes all EMS IEs that matches the criteria from the CSmsMessage
- *
- * @param aStartPosition of a EMS object to be removed.
- * @param aEmsId type of a EMS object to be removed
- * @return pointer to array of EMS IE
- *
- * @capability None
- */
-EXPORT_C RPointerArray<CEmsInformationElement>* CSmsMessage::RemoveEMSInformationElementsL(const TUint aStartPosition,const TSmsId aEmsId)
- {
- LOGGSMU1("CSmsMessage::RemoveEMSInformationElementsL()");
-
- CEmsInformationElement* ie=NULL;
- RPointerArray<CEmsInformationElement>* selectedIEs = NULL;
- TUint count=iInformationElementArray->Count();
-
- for (TInt i=--count; i >= 0 ; --i)
- {
- ie = (*iInformationElementArray)[i];
- if (ie->StartPosition() == aStartPosition && ie->Identifier() == aEmsId)
- {
- if(CanBeRemoved(*ie, i))
- {
- if(selectedIEs == NULL)selectedIEs=new (ELeave) RPointerArray<CEmsInformationElement>(8);
- iInformationElementArray->Remove(i);
- selectedIEs->Append(ie);
- }
- }
-
- }
- return selectedIEs;
- } // CSmsMessage::RemoveEMSInformationElementsL
-
-/**
- * Resets EMS IE from a CSmsMessage
- *
- *
- * @capability None
- */
-EXPORT_C void CSmsMessage::ResetEMSL()
- {
- LOGGSMU1("CSmsMessage::ResetEMSL()");
-
- iInformationElementArray->ResetAndDestroy();
- } // CSmsMessage::ResetEMSL
-
-/**
- * Removes EMS IE from a CSmsMessage
- *
- * @return CArrayPtrFlat<const CEmsInformationElement>& of internal EMS array
- *
- * @capability None
- */
-EXPORT_C const RPointerArray<const CEmsInformationElement>& CSmsMessage::GetEMSInformationElementsL()const
- {
- LOGGSMU1("CSmsMessage::GetEMSInformationElementsL()");
-
- return (const RPointerArray<const CEmsInformationElement>&)(*iInformationElementArray);
- } // CSmsMessage::GetEMSInformationElementsL
-
-
-void CSmsMessage::UpdateUserPromptAndODIElementsStartPosition()
- {
- LOGGSMU1("CSmsMessage::UpdateUserPromptAndODIElementsStartPosition()");
-
- TUint num=iInformationElementArray->Count();
- TInt startPosition=-1;
- CEmsInformationElement* ie = NULL;
-
-
- // is the ie an EMS information Element;
-
- for(TInt i=num-1;i >=0; --i)
- {
- ie = (*iInformationElementArray)[i];
- if(ie->Identifier() == CSmsInformationElement::ESmsEnhancedUserPromptIndicator || ie->Identifier() == CSmsInformationElement::ESmsEnhancedODI)
- {
- if(startPosition >=0)
- ie->SetStartPosition(startPosition);
- else
- iInformationElementArray->Remove(i);
- }
- else
- startPosition=ie->StartPosition();
-
- }
- } // CSmsMessage::UpdateUserPromptAndODIElementsStartPosition
-
-
-TInt CSmsMessage::AddReceivedEmsInformationElement(CEmsInformationElement* aEmsIE)
- {
- LOGGSMU1("CSmsMessage::AddReceivedEmsInformationElement()");
-
- TInt ret=KErrNone;
- if(CSmsInformationElement::ESmsEnhancedUserPromptIndicator == aEmsIE->Identifier() || CSmsInformationElement::ESmsEnhancedODI == aEmsIE->Identifier())
- ret=iInformationElementArray->Append(aEmsIE);
- else
- {
- TInt count=iInformationElementArray->Count();
- TInt currNo=0;
- const CEmsInformationElement* emsIE=NULL;
- while(currNo < count)
- {
- emsIE=(*iInformationElementArray)[currNo];
- if(emsIE->StartPosition() > aEmsIE->StartPosition() && (CSmsInformationElement::ESmsEnhancedUserPromptIndicator != emsIE->Identifier() || CSmsInformationElement::ESmsEnhancedODI != emsIE->Identifier()))
- break;
- currNo++;
- }
- ret=iInformationElementArray->Insert(aEmsIE,currNo);
- }
- return ret;
- } // CSmsMessage::AddReceivedEmsInformationElement
-
-
-/**
- * Updates the slot information for the given message as described in the supplied buffer
- *
- * @param aDesc buffer, layout: byte 0 store id, byte 1..n PDU slot indexes
- * @leave KErrArgument
- *
- * @capability None
- */
-EXPORT_C void CSmsMessage::UpdateSlotsL(TDesC8& aDesc)
- {
- LOGGSMU1("CSmsMessage::UpdateSlotsL()");
-
- TGsmSmsSlotEntry newSlot;
-
- switch (aDesc[0])
- {
- case CSmsMessage::ESmsSIMStorage:
- {
- newSlot.iStore = KETelIccSmsStore;
- break;
- }
- case CSmsMessage::ESmsPhoneStorage:
- {
- newSlot.iStore = KETelMeSmsStore;
- break;
- }
- case CSmsMessage::ESmsCombinedStorage:
- {
- newSlot.iStore = KETelCombinedSmsStore;
- break;
- }
- default:
- User::Leave(KErrArgument);
- }
-
- for (TInt index = 1; index < aDesc.Size(); index++)
- {
- newSlot.iIndex = aDesc[index]; // point to PDU indexes
- iSlotArray.AppendL(newSlot);
- }
- } // CSmsMessage::UpdateSlotsL
-
-/**
- * Copy EMS elements to dest CSmsMessage
- * Uses CSmsMessage extended EMS API
- * Creates new CEmsInformationElement instance(s) and passes ownership to the dest CSmsMessage
- *
- * @return aToMessage - Destination CSmsMessage
- *
- * @capability None
- */
-EXPORT_C void CSmsMessage::CopyEmsElementsL(CSmsMessage& aToMessage) const
- {
- LOGGSMU1("CSmsMessage::CopyEmsElementsL()");
-
- // CSmsMessage extended EMS API method creates array of references to EMS elements in
- // the source message
- // Loop through the array copying each individual method using the CSmsMessage
- // and CEmsInformationElement API's
- CEmsInformationElement* dupl=NULL;
- aToMessage.ResetEMSL();
- for(TInt i = iInformationElementArray->Count()-1 ; i >=0; --i)
- {
- dupl = (*iInformationElementArray)[i]->DuplicateL();
- CleanupStack::PushL(dupl);
- aToMessage.AddEMSInformationElementL(*dupl);
- CleanupStack::PopAndDestroy(dupl);
- }
- } // CSmsMessage::CopyEmsElementsL
-
-/**
- * @capability None
- */
-EXPORT_C void CSmsMessage::AddSlotL(const TGsmSmsSlotEntry& aSlot)
- {
- LOGGSMU1("CSmsMessage::AddSlotL()");
-
- TInt count = iSlotArray.Count();
- TInt i(0);
- TBool found(EFalse);
- while(!found && i<count)
- {
- if(aSlot.iIndex == iSlotArray[i].iIndex)found=ETrue;
- else ++i;
- }
- LOGGSMU3("CSmsMessage::AddSlotL current no in: %d, adds index %d", count,aSlot.iIndex );
- LOGGSMU3("found %d at position %d",found,i);
- iSlotArray.AppendL(aSlot);
- } // CSmsMessage::AddSlotL
-
-/**
- * @capability None
- */
-EXPORT_C TBool CSmsMessage::MatchSlots(const CArrayFixFlat<TGsmSmsSlotEntry>& aSlotArray)
- {
- LOGGSMU1("CSmsMessage::MatchSlots()");
-
- TBool match = EFalse;
- TInt count = aSlotArray.Count();
- if(iSlotArray.Count() == count)
- {
- TInt i = 0;
- match = ETrue;
- while(match && i < count)
- {
- const TGsmSmsSlotEntry& newSlot=aSlotArray[i];
- const TGsmSmsSlotEntry& slot =iSlotArray[i];
- if ( ( slot.iIndex != newSlot.iIndex ) || ( slot.iStore != newSlot.iStore ) )
- match = EFalse;
- i++;
- }
-
- }
- return match;
- } // CSmsMessage::MatchSlots
-
-/**
- * c'tor
- * @capability None
- */
-EXPORT_C TGsmSmsSlotEntry::TGsmSmsSlotEntry()
- {
- } // TGsmSmsSlotEntry::TGsmSmsSlotEntry
-
-/**
- * Internalize
- *
- * @param aStream For internalizing the data
- */
-void TGsmSmsSlotEntry::InternalizeL(RReadStream& aStream)
- {
- aStream >> iStore;
- iIndex=aStream.ReadInt32L();
- } // TGsmSmsSlotEntry::InternalizeL
-
-/**
- * Externalize
- *
- * @param aStream For Externalizing the data
- */
-void TGsmSmsSlotEntry::ExternalizeL(RWriteStream& aStream) const
- {
- aStream << iStore;
- aStream.WriteInt32L(iIndex);
- } // TGsmSmsSlotEntry::ExternalizeL
-
- /**
- * Extracts all RFC 822 Email header information objects out of the given UserData into the CSmsMessage's iSmsEmailHeaderLength.
- *
- * @param aUserData Object containing the EmailHeader information element.
- * @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
- * of the UserData.
- */
-void CSmsMessage::InstallEmailHeaderInformationElementL(CSmsUserData& aUserData,TInt& aHeaderLength)
- {
- // Installs all the information elements within the subsequent PDUs.
- LOGGSMU1("CSmsMessage::InstallEmailHeaderInformationElementL()");
-
- CSmsInformationElement::TSmsInformationElementIdentifier id;
-
- for (TInt z=0; z<aUserData.NumInformationElements(); z++)
- {
- const CSmsInformationElement& ie = aUserData.InformationElement(z);
- id = (CSmsInformationElement::TSmsInformationElementIdentifier)ie.Identifier();
- if (id == CSmsInformationElement::ESmsIEIRFC822EmailHeader)
- {
- const TDesC8& des = ie.Data();
- aHeaderLength+=des[0];
- }
- }
- } // CSmsMessage::InstallEmailHeaderInformationElementL
-
-/**
- * Extracts all RFC 822 Email header information objects out of the given UserData into the CSmsMessage's iSmsEmailHeaderLength.
- *
- * @param aCommand Object containing the EmailHeader information element.
- * @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
- * of the UserData.
- */
-void CSmsMessage::InstallEmailHeaderInformationElementL(CSmsCommand& aCommand,TInt& aHeaderLength)
- {
- // Ignore in code coverage - not used in SMS stack and not exported
- // but cannot be removed as impacts public header.
- BULLSEYE_OFF
- // Installs all the information elements within the subsequent PDUs.
- LOGGSMU1("CSmsMessage::InstallEmailHeaderInformationElementL()");
-
- CSmsInformationElement::TSmsInformationElementIdentifier id;
-
- for (TInt z=0; z<aCommand.NumInformationElements(); z++)
- {
- const CSmsInformationElement& ie = aCommand.InformationElement(z);
- id = (CSmsInformationElement::TSmsInformationElementIdentifier)ie.Identifier();
- if (id == CSmsInformationElement::ESmsIEIRFC822EmailHeader)
- {
- const TDesC8& des = ie.Data();
- aHeaderLength+=des[0];
- }
- }
- BULLSEYE_RESTORE
- }
-
-// E-mail header methods
-
-/**
- * Adds a header to an email body
- *
- * @param aEMailBody The buffer to which the header gets appended
- * @param aEmailHeader The buffer which holds RFC 822 e-mail header
- * @publishedAll
- * @released
- *
- * @capability None
- */
-EXPORT_C void CSmsMessage::AddEmailHeaderL(const TDesC& aEmailHeader, const TDesC& aEmailBody)
- {
- LOGGSMU1("CSmsMessage::AddEmailHeaderL()");
-
- if(IsEmailHeader())
- User::Leave(KErrAlreadyExists);
-
- TInt len =aEmailHeader.Length();
- if(len <= 0)
- User::Leave(KErrCorrupt);
-
- if(len >= 255 )
- User::Leave(KErrTooBig);
-
-
- if(SmsPDU().UserData().NumInformationElements())
- {
- TBool is16bit = EFalse;
- TBool concatenationIEPresent= SmsPDU().TextConcatenated( &is16bit );
- if(concatenationIEPresent)
- {
- if(SmsPDU().UserData().NumInformationElements() >=2) // something more than concat IE
- User::Leave(KErrAccessDenied);
- }
- else
- User::Leave(KErrAccessDenied);
- }
-
-
- TBuf8<1> data;
- data.SetLength(1);
- data[0]=static_cast<TUint8>(len);
- SmsPDU().UserData().AddInformationElementL(CSmsInformationElement::ESmsIEIRFC822EmailHeader,data);
-
- iBuffer->Reset();
- iBuffer->InsertL(0,aEmailHeader);
- iBuffer->InsertL(iBuffer->Length(),aEmailBody);
- } // CSmsMessage::AddEmailHeaderL
-
- /**
- * Checks whether the SmsMessage contains an e-mail.
- *
- * @return ETrue if CSmsMessage contains e-mail ( e-mail header information element), otherwise EFalse
- * @publishedAll
- * @released
- *
- * @capability None
- */
-EXPORT_C TBool CSmsMessage::IsEmailHeader() const
- {
- LOGGSMU1("CSmsMessage::IsEmailHeader()");
-
- TInt emailIndex;
- return SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEIRFC822EmailHeader,emailIndex);
- } // CSmsMessage::IsEmailHeader
-
- /**
- * Extracts e-mail header and body from the SmsMessage
- *
- * @return aEMailHeader The buffer containing the extracted email header
- * @return aEMailBody The buffer containing the extracted email body
- * @return ETrue if extraction of e-mail header and body succeeds
- * @publishedAll
- * @released
- *
- * @capability None
- */
-EXPORT_C TBool CSmsMessage::GetEmailHeaderL(HBufC** aEmailHeader,HBufC** aEmailBody)
- {
- LOGGSMU1("CSmsMessage::GetEmailHeaderL()");
-
- if(IsEmailHeader())
- {
- TInt bufLen=iBuffer->Length();
- TInt emailHeaderLen(0);
- TInt emailIndex(0);
- if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEIRFC822EmailHeader,emailIndex))
- emailHeaderLen=SmsPDU().UserData().InformationElement(emailIndex).Data()[0];
- else
- User::Leave(KErrCorrupt);
-
- TInt emailBodyLen=bufLen-emailHeaderLen;
-
- if(emailBodyLen<0)
- return EFalse;
-
- *aEmailHeader=HBufC::NewL(emailHeaderLen);
- CleanupStack::PushL(*aEmailHeader);
-
- *aEmailBody=HBufC::NewL(emailBodyLen);
- CleanupStack::PushL(*aEmailBody);
-
- TPtr headerPtr((*aEmailHeader)->Des());
- iBuffer->Extract(headerPtr,0,emailHeaderLen);
-
- TPtr bodyPtr((*aEmailBody)->Des());
- iBuffer->Extract(bodyPtr,emailHeaderLen,emailBodyLen);
-
- CleanupStack::Pop(2);
- return ETrue;
- }
- return EFalse;
- } // CSmsMessage::GetEmailHeaderL
-
-
- /**
- * Extracts the offset between universal time and local time in seconds.
- * If the value is > 0, local time is ahead of universal time.
- * If the value is < 0, local time is behind universal time.
- *
- * @return TTTimeIntervalSeconds The time zone offset in seconds.
- * @publishedAll
- * @capability None
- */
-EXPORT_C TTimeIntervalSeconds CSmsMessage::UTCOffset() const
- {
- LOGGSMU1("CSmsMessage::UTCOffset()");
-
- TUint timeZoneOffset = ((iFlags & ESmsUTCOffsetSecondGranularityMask) >> ESecondBitOffset);
-
- if (iFlags & ESmsUTCOffsetSignBit)
- {
- timeZoneOffset = -timeZoneOffset;
- }
-
- return (TTimeIntervalSeconds(timeZoneOffset));
- } // CSmsMessage::UTCOffset
-
-
- /**
- * Sets the offset between universal time and local time in seconds.
- * If the value is > 0, local time is ahead of universal time.
- * If the value is < 0, local time is behind universal time.
- * The CSmsMessage Time Zone Offset has the range +/- 71100 seconds. This is same range as
- * the Service Centre Time Stamp Time Zone Offset as specified in 23.040 V4.4.0 Sect 9.2.3.11.
- *
- * @return True if input value was set successfully (in range), False otherwise
- * @publishedAll
- * @capability None
- */
-EXPORT_C TBool CSmsMessage::SetUTCOffset(const TTimeIntervalSeconds& aTimeOffset)
- {
- LOGGSMU1("CSmsMessage::SetUTCOffset()");
-
- TBool rc = ETrue;
-
- TInt timeOffset = aTimeOffset.Int();
-
- if ((timeOffset <= EMaximumSeconds) &&
- (timeOffset >= -EMaximumSeconds))
- {
- // Clear the timezone offset bits
- iFlags &= (~(ESmsUTCOffsetSecondGranularityMask |
- ESmsUTCOffsetSignBit));
-
- if (timeOffset < 0)
- {
- iFlags |= ESmsUTCOffsetSignBit;
- timeOffset = -timeOffset;
- }
-
- iFlags |= (timeOffset << ESecondBitOffset);
- }
- else
- {
- LOGGSMU2("CSmsMessage::SetUTCOffset offset [out of range] = %d",timeOffset);
- rc = EFalse;
- }
-
- return rc;
-} // CSmsMessage::SetUTCOffset
-
-
-/**
- * Returns the message version number.
- * @capability
- */
-EXPORT_C TInt CSmsMessage::Version()
- {
- LOGGSMU1("CSmsMessage::Version()");
-
- return iVersion;
- } // CSmsMessage::Version
-
-
-/**
- * @internalComponent
- * Validates and sets the message version number.
- *
- * @param aVersion version number to set.
- * @return KErrNone if aVersion is valid and successfully set, KErrArgument otherwise.
- * @capability None
- */
-EXPORT_C TInt CSmsMessage::SetVersion(TInt aVersion)
- {
- LOGGSMU2("CSmsMessage::SetVersion()", aVersion);
-
- if((aVersion>=ESmsMessageV0) && (aVersion<=ESmsMessageV4))
- {
- iVersion=aVersion;
- return KErrNone;
- }
-
- return KErrArgument;
- } // CSmsMessage::SetVersion
-
-
-/**
- * @internalComponent
- * Internalises all object data except for the CSmsBufferBase and the message version.
- *
- * This is used when the buffer is stored elsewhere.
- *
- * @param aStream Stream to read from
- * @capability None
- */
-EXPORT_C void CSmsMessage::InternalizeWithoutBufferAndVersionL(RReadStream& aStream)
- {
- LOGGSMU1("CSmsMessage::InternalizeWithoutBufferAndVersionL()");
-
- iFlags=aStream.ReadInt32L();
- iStatus=(NMobileSmsStore::TMobileSmsStoreStatus) aStream.ReadInt32L();
- iLogServerId=aStream.ReadInt32L();
- TInt64 time;
- aStream >> time;
- iTime=time;
-
- CSmsPDU* smspdu=CSmsPDU::NewL(aStream,*iCharacterSetConverter,iFs);
- delete iSmsPDU;
- iSmsPDU=smspdu;
- iIs16BitConcatenation=aStream.ReadInt32L();
-
- iInformationElementArray->ResetAndDestroy();
- CEmsFactory::InternalizeL(*iInformationElementArray, aStream);
-
- TInt count=aStream.ReadInt32L();
- iSlotArray.Reset();
- TInt i=0;
- TGsmSmsSlotEntry newSlot;
- for (; i<count; i++)
- {
- newSlot.InternalizeL(aStream);
- AddSlotL(newSlot);
- }
- } // CSmsMessage::InternalizeWithoutBufferAndVersionL
-
-
-/**
- * @internalComponent
- * Externalises all object data except for the CSmsBufferBase and the message version.
- *
- * This is used when the buffer is stored elsewhere.
- *
- * @param aStream Stream to write to
- * @capability None
- */
-EXPORT_C void CSmsMessage::ExternalizeWithoutBufferAndVersionL(RWriteStream& aStream) const
- {
- LOGGSMU1("CSmsMessage::ExternalizeWithoutBufferAndVersionL()");
-
- aStream.WriteInt32L(iFlags);
- aStream.WriteInt32L(iStatus);
- aStream.WriteInt32L(iLogServerId);
- aStream << Time().Int64();
-
- SmsPDU().ExternalizeL(aStream);
- aStream.WriteInt32L(iIs16BitConcatenation);
-
- CEmsFactory::ExternalizeL(*iInformationElementArray, aStream);
- TInt count=iSlotArray.Count();
- aStream.WriteInt32L(count);
- TInt i=0;
- for (; i<count; i++)
- {
- iSlotArray[i].ExternalizeL(aStream);
- }
- } // CSmsMessage::ExternalizeWithoutBufferAndVersionL
-
-
-/**
- * @internalComponent
- * Internalises the CSmsBufferBase.
- *
- * @param aStream Stream to read from
- * @capability None
- */
-EXPORT_C void CSmsMessage::InternalizeBufferL(RReadStream& aStream)
- {
- aStream >> *iBuffer;
- } // CSmsMessage::InternalizeBufferL
-
-
-/**
- * @internalComponent
- * Externalises the CSmsBufferBase.
- *
- * @param aStream Stream to write to
- * @capability None
- */
-EXPORT_C void CSmsMessage::ExternalizeBufferL(RWriteStream& aStream) const
- {
- aStream << *iBuffer;
- } // CSmsMessage::ExternalizeBufferL
-
-
-/**
- * @internalComponent
- * Internalises the message version.
- *
- * @param aStream Stream to read from
- * @capability None
- */
-EXPORT_C void CSmsMessage::InternalizeVersionL(RReadStream& aStream)
- {
- TInt32 versionNumber = ESmsMessageV0;
- TRAPD(err,versionNumber=aStream.ReadInt32L());
- if(err==KErrEof)
- {
- versionNumber=ESmsMessageV0;
- }
-
- iVersion=static_cast<TSmsMessageVersion> (versionNumber);
- } // CSmsMessage::InternalizeVersionL
-
-
-/**
- * @internalComponent
- * Externalises the message version.
- *
- * @param aStream Stream to write to
- * @capability None
- */
-EXPORT_C void CSmsMessage::ExternalizeVersionL(RWriteStream& aStream) const
- {
- aStream.WriteInt32L(iVersion);
- } // CSmsMessage::ExternalizeVersionL
-
-
-/**
- * @publishedAll
- *
- * Returns a reference to a specialisation of the class CSmsIEOperation. Clients can use this sub-class
- * to access the attributes of a specific type of information element encapsulated inside the CSmsMessage.
- * The ownership to the CSmsIEOperation class belongs to the CSmsMessage. When the CSmsMessage is deleted,
- * the CSmsIEOperation will also be deleted and the reference will become stale.
- *
- * @param aId
- * Specifies the sub class of CSmsIEOperation required.
- * @leave KErrNotSupported
- * When there is not accessor class available for the specified type of information element.
- * @capability None
- */
-EXPORT_C CSmsIEOperation& CSmsMessage::GetOperationsForIEL(CSmsInformationElement::TSmsInformationElementIdentifier aId) const
- {
- LOGGSMU1("CSmsMessage::GetOperationsForIEL()");
-
- if (iVersion < CSmsMessage::ESmsMessageV1)
- {
- LOGGSMU2("CSmsMessage::GetOperationsForIEL, Operation not supported, Msg Version %d", iVersion);
- User::Leave(KErrNotSupported);
- }
-
- return iAdditionalInfo->GetIEOperationL(aId);
- } // CSmsMessage::GetOperationsForIEL
-
-EXPORT_C CSmsNonIEOperation& CSmsMessage::GetOperationsForNonIEL(TSmsNonIEIdentifier aId) const
- {
- LOGGSMU1("CSmsMessage::GetOperationsForNonIEL");
-
- if (iVersion < CSmsMessage::ESmsMessageV2)
- {
- LOGGSMU2("GetOperationsForNonIEL not supported, Msg Version %d", iVersion);
- User::Leave(KErrNotSupported);
- }
-
- return iAdditionalInfo->GetNonIEOperationL(aId);
- } // CSmsMessage::GetOperationsForNonIEL
-
-
-void CSmsMessage::CreateControlIEOperationsClassesL()
- {
- LOGGSMU1("CSmsMessage::CreateControlIEOperationsClassesL()");
-
- CSmsIEOperation* iEOperation = NULL;
-
- iEOperation = CSmsIEOperation::NewL(CSmsInformationElement::ESmsHyperLinkFormat, *this, *iCharacterSetConverter, iFs);
- iAdditionalInfo->SetIEOperationL(iEOperation);
-
- iEOperation = CSmsIEOperation::NewL(CSmsInformationElement::ESmsReplyAddressFormat, *this, *iCharacterSetConverter, iFs);
- iAdditionalInfo->SetIEOperationL(iEOperation);
-
- iEOperation = CSmsIEOperation::NewL(CSmsInformationElement::ESmsEnhanceVoiceMailInformation, *this, *iCharacterSetConverter, iFs);
- iAdditionalInfo->SetIEOperationL(iEOperation);
-
- iEOperation = CSmsIEOperation::NewL(CSmsInformationElement::ESmsIEISpecialSMSMessageIndication, *this, *iCharacterSetConverter, iFs);
- iAdditionalInfo->SetIEOperationL(iEOperation);
-
- iEOperation = CSmsIEOperation::NewL( CSmsInformationElement::ESmsIEISMSCControlParameters, *this, *iCharacterSetConverter, iFs);
- iAdditionalInfo->SetIEOperationL(iEOperation);
- } // CSmsMessage::CreateControlIEOperationsClassesL
-
-
-void CSmsMessage::CreateControlNonIEOperationsClassesL()
- {
- CSmsNonIEOperation* nonIEOperation = NULL;
-
- nonIEOperation = CSmsNonIEOperation::NewL(ESmsTPSRRParameter, *this);
- iAdditionalInfo->SetNonIEOperationL(nonIEOperation);
-
- nonIEOperation = CSmsNonIEOperation::NewL(ESmsIncompleteClass0MessageParameter, *this);
- iAdditionalInfo->SetNonIEOperationL(nonIEOperation);
- } // CSmsMessage::CreateControlNonIEOperationsClassesL
-
-
-/**
- * Gets the scheme of the status report.
- *
- * @return Staus Report Scheme
- */
-EXPORT_C TSmsStatusReportScheme CSmsMessage::Scheme() const
- {
- return iAdditionalInfo->GetStatusReportScheme().Id();
- }
-
-/**
- * @publishedAll
- *
- * Used by the SMS Stack to indicate that when the message was decoded, it was determined
- * to be on the SIM. If the message's DCS byte is configured for automatic delete or the
- * PID is set to Type 0, the message may subsequently have been deleted from the SIM during
- * decoding in which case its storage status is unstored.
- *
- * @param aOnSim
- * Used to indicate that the message was on the SIM when it was decoded.
- * @capability None
- */
-EXPORT_C void CSmsMessage::SetDecodedOnSIM(TBool aOnSim)
- {
- LOGGSMU2("CSmsMessage::SetDecodedOnSIM(): %d", aOnSim);
-
- if (aOnSim)
- {
- iFlags = iFlags | EDecodedOnSimBit;
- }
- else
- {
- iFlags = iFlags & ~EDecodedOnSimBit;
- }
- } // CSmsMessage::SetDecodedOnSIM
-
-
-/**
- * @publishedAll
- *
- * Used by the SMS Stack to indicate that when the message was decoded, it was determined
- * to be on the SIM. If the message's DCS byte is configured for automatic delete or the
- * PID is set to Type 0, the message may subsequently have been deleted from the SIM during
- * decoding in which case its storage status is unstored.
- *
- * @return
- * True if the message was on the SIM during decoding,
- * False otherwise.
- * @capability None
- */
-EXPORT_C TBool CSmsMessage::DecodedOnSim()
- {
- LOGGSMU1("CSmsMessage::DecodedOnSim()");
-
- if (iFlags & EDecodedOnSimBit)
- {
- return ETrue;
- }
- else
- {
- return EFalse;
- }
- } // CSmsMessage::DecodedOnSim
-
-
-/**
- * @publishedAll
- *
- * Used by the SMS Stack to indicate that when the message was decoded, it was determined
- * that it should be forwarded to the client. The message will not be forwarded to the
- * client when the PID byte is set to type 0 (except by default for class 0 and class 2 messages).
- *
- * @param forward
- * Used to indicate that the message needs to be forwarded to clients.
- * @capability None
- */
-EXPORT_C void CSmsMessage::SetForwardToClient(TBool aForward)
- {
- LOGGSMU2("CSmsMessage::SetForwardToClient(): %d", aForward);
-
- if (aForward)
- {
- iFlags = iFlags | EForwardToClientBit;
- }
- else
- {
- iFlags = iFlags & ~EForwardToClientBit;
- }
- } // CSmsMessage::SetForwardToClient
-
-
-/**
- * @publishedAll
- *
- * Used by the SMS Stack to indicate that when the message was decoded, it was determined
- * that is should be forwarded to the client. The message will not be forwarded to the client
- * when the PID byte is set to type 0 (except by default for class 0 and class 2 messages).
- *
- * @return
- * True if the message is to be forwarded to clients
- * False otherwise.
- * @capability None
- */
-EXPORT_C TBool CSmsMessage::ForwardToClient()
- {
- LOGGSMU1("CSmsMessage::ForwardToClient()");
-
- if (iFlags & EForwardToClientBit)
- {
- return ETrue;
- }
- else
- {
- return EFalse;
- }
- } // CSmsMessage::ForwardToClient
+// 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:
+// Contains the implementation of the CSmsMessage class
+//
+//
+
+/**
+ @file
+*/
+
+#include <gsmumsg.h>
+#include "Gsmumain.h"
+#include <gsmubuf.h>
+#include <gsmuset.h>
+#include <gsmusar.h>
+#include "gsmumsgadditionalattributes.h"
+#include <gsmuieoperations.h>
+#include <gsmunonieoperations.h>
+
+#include <logwrap.h> // Used for KLogNullId only
+#include <e32uid.h>
+#include <etelmm.h>
+#include <logwraplimits.h>
+
+#include <emsinformationelement.h>
+#include <emsformatie.h>
+#include <emsuserpromptie.h>
+#include <emsobjectdistributionie.h>
+#include "smsstackutils.h"
+
+/**
+ * Allocates and creates a CSmsMessage instance from a TGsmSms.
+ *
+ * The type of SMS-XXXX message to construct is defined by the first byte of
+ * the TGsmSms TPDU header.
+ *
+ * @param aFs Reference handle to the file system
+ * @param aGsmSms Reference to TGsmSms
+ * @param aBuffer The Unicode text for the message. The object takes ownership
+ * of aBuffer.
+ * @param aIsRPError Set to true if the message contains Reply Path Error. Default
+ * is false.
+ * @param aIsMobileTerminated Set to True if the message is Mobile Terminated.
+ * Default is false.
+ * @return New CSmsMessage object
+ * @capability None
+ */
+EXPORT_C CSmsMessage* CSmsMessage::NewL(RFs& aFs, const TGsmSms& aGsmSms,CSmsBufferBase* aBuffer, TBool aIsRPError,TBool aIsMobileTerminated)
+ {
+ LOGGSMU1("CSmsMessage::NewL()");
+
+ CleanupStack::PushL(aBuffer);
+ CSmsMessage* smsmessage=new(ELeave) CSmsMessage(aFs, aBuffer);
+ CleanupStack::Pop();
+ CleanupStack::PushL(smsmessage);
+ smsmessage->ConstructL(aGsmSms, aIsRPError,aIsMobileTerminated);
+ CleanupStack::Pop();
+ return smsmessage;
+ } // CSmsMessage::NewL
+
+
+/**
+ * Allocates and creates a CSmsMessage, specifying the SMS-XXX message type with
+ * a CSmsPDU::TSmsPduType.
+ *
+ * @param aFs Reference handle to the file system
+ * @param aType The PDU type
+ * @param aBuffer The Unicode text for the message. The object takes ownership
+ * of aBuffer.
+ * @param aIsRPError Set to true if the message contains Reply Path Error. Default
+ * is false.
+ * @return New CSmsMessage object
+ * @capability None
+ */
+EXPORT_C CSmsMessage* CSmsMessage::NewL(RFs& aFs, CSmsPDU::TSmsPDUType aType,CSmsBufferBase* aBuffer,TBool aIsRPError)
+ {
+ LOGGSMU1("CSmsMessage::NewL()");
+
+ CleanupStack::PushL(aBuffer);
+ CSmsMessage* smsmessage=new(ELeave) CSmsMessage(aFs, aBuffer);
+ CleanupStack::Pop();
+ CleanupStack::PushL(smsmessage);
+ smsmessage->ConstructL(aType,aIsRPError);
+ CleanupStack::Pop();
+ return smsmessage;
+ } // CSmsMessage::NewL
+
+
+/**
+ * Destructor, frees resources.
+ * @capability None
+ */
+EXPORT_C CSmsMessage::~CSmsMessage()
+ {
+ LOGGSMU1("CSmsMessage::~CSmsMessage()");
+
+ delete iSmsPDU;
+ delete iBuffer;
+ delete iCharacterSetConverter;
+
+ if (iInformationElementArray)
+ {
+ iInformationElementArray->ResetAndDestroy();
+ delete iInformationElementArray;
+ }
+
+ delete iAdditionalInfo;
+ } // CSmsMessage::NewL
+
+
+/**
+ * Internalises all object data except for the CSmsBufferBase.
+ *
+ * This is used when the buffer is stored elsewhere.
+ *
+ * @param aStream Stream to read from
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::InternalizeWithoutBufferL(RReadStream& aStream)
+ {
+ LOGGSMU1("CSmsMessage::InternalizeWithoutBufferL()");
+
+ InternalizeWithoutBufferAndVersionL(aStream);
+ InternalizeVersionL(aStream);
+
+ iAdditionalInfo->ResetAttributesL();
+
+ if (iVersion > ESmsMessageV0)
+ {
+ iAdditionalInfo->InternalizeL(aStream, iVersion);
+ }
+ } // CSmsMessage::InternalizeWithoutBufferL
+
+
+/**
+ * Externalises all object data except for the CSmsBufferBase.
+ *
+ * This is used when the buffer is stored elsewhere.
+ *
+ * @param aStream Stream to write to
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::ExternalizeWithoutBufferL(RWriteStream& aStream) const
+ {
+ LOGGSMU1("CSmsMessage::ExternalizeWithoutBufferL()");
+
+ ExternalizeWithoutBufferAndVersionL(aStream);
+ ExternalizeVersionL(aStream);
+
+ if (iVersion > ESmsMessageV0)
+ {
+ iAdditionalInfo->ExternalizeL(aStream, iVersion);
+ }
+ } // CSmsMessage::ExternalizeWithoutBufferL
+
+
+/**
+ * Internalises all object data.
+ *
+ * @param aStream Stream to read from
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::InternalizeL(RReadStream& aStream)
+ {
+ LOGGSMU1("CSmsMessage::InternalizeL()");
+
+ InternalizeWithoutBufferAndVersionL(aStream);
+ InternalizeBufferL(aStream);
+ InternalizeVersionL(aStream);
+
+ iAdditionalInfo->ResetAttributesL();
+ if (iVersion > ESmsMessageV0)
+ {
+ iAdditionalInfo->InternalizeL(aStream, iVersion);
+ }
+ } // CSmsMessage::InternalizeL
+
+
+/**
+ * Externalises all object data.
+ *
+ * @param aStream Stream to write to
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::ExternalizeL(RWriteStream& aStream) const
+ {
+ LOGGSMU1("CSmsMessage::ExternalizeL()");
+
+ ExternalizeWithoutBufferAndVersionL(aStream);
+ ExternalizeBufferL(aStream);
+ ExternalizeVersionL(aStream);
+
+ if (iVersion > ESmsMessageV0)
+ {
+ iAdditionalInfo->ExternalizeL(aStream, iVersion);
+ }
+ } // CSmsMessage::ExternalizeL
+
+
+/**
+ * Tests if the message contains text.
+ *
+ * @return True if the message contains text
+ * @capability None
+ */
+EXPORT_C TBool CSmsMessage::TextPresent() const
+ {
+ LOGGSMU1("CSmsMessage::TextPresent()");
+
+ CSmsPDU::TSmsPDUType pdutype=SmsPDU().Type();
+ return (pdutype==CSmsPDU::ESmsSubmit) ||
+ (pdutype==CSmsPDU::ESmsDeliver) ||
+ (((pdutype==CSmsPDU::ESmsSubmitReport) || (pdutype==CSmsPDU::ESmsDeliverReport) ||
+ ((pdutype==CSmsPDU::ESmsStatusReport) && ((CSmsStatusReport&) SmsPDU()).ParameterIndicatorPresent())) &&
+ SmsPDU().UserDataPresent());
+ } // CSmsMessage::TextPresent
+
+
+/**
+ * Gets the number of PDU's required to encode the complete message.
+ *
+ * @leave KErrOverflow Leaves if the number of required PDUs exceeds the maximum
+ * or the message cannot be encoded.
+ * @return Number of PDU's
+ * @capability None
+ */
+EXPORT_C TInt CSmsMessage::NumMessagePDUsL()
+ {
+ LOGGSMU1("CSmsMessage::NumMessagePDUsL()");
+
+ TInt nummessagepdus=1;
+ if (IsDecoded())
+ {
+ if (TextPresent())
+ {
+ nummessagepdus=NumMessageEmsPDUsL();
+ TInt maxnummessagepdus=SmsPDU().TextConcatenated()? 0xFF: 1;
+ if (nummessagepdus>maxnummessagepdus)
+ {
+ User::Leave(KErrOverflow);
+ }
+ }
+
+ }
+ else if (TextPresent() && SmsPDU().TextConcatenated())
+ {
+ nummessagepdus=SmsPDU().NumConcatenatedMessagePDUs();
+ }
+
+ LOGGSMU2("CSmsMessage::NumMessagePDUsL() returns %d", nummessagepdus);
+
+ return nummessagepdus;
+ } // CSmsMessage::NumMessagePDUsL
+
+
+/**
+ * Gets the maximum message length possible with the current settings.
+ *
+ * If Text is compressed, this returns the maximum number of bytes available
+ * with text compressed.
+ *
+ * @return Maximum message length
+ * @capability None
+ */
+EXPORT_C TInt CSmsMessage::MaxMessageLength() const
+ {
+ __ASSERT_DEBUG(TextPresent(),Panic(KGsmuPanicTextNotPresent));
+ TInt maxmessagelength=SmsPDU().UserData().MaxBodyLengthInChars();
+ if (SmsPDU().TextConcatenated())
+ {
+ maxmessagelength=maxmessagelength*0xFF;
+ }
+
+ LOGGSMU2("CSmsMessage::MaxMessageLength() returns %d", maxmessagelength);
+
+ return maxmessagelength;
+ } // CSmsMessage::MaxMessageLength
+
+
+/**
+ *
+ * @return The converted buffer length
+ * @note Use with care - Expensive operation
+ */
+TInt CSmsMessage::ConvertedBufferLengthL(const CSmsBufferBase& aBuffer)
+ {
+ // Ignore in code coverage - not used in SMS stack and not exported
+ // but cannot be removed as impacts public header.
+ BULLSEYE_OFF
+ LOGGSMU1("CSmsMessage::ConvertedBufferLengthL()");
+
+ TInt convertedBufferLength=0;
+ CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,SmsPDU().Alphabet(),BinaryData());
+ CSmsBufferSegmenter* segmenter=CSmsBufferSegmenter::NewLC(*converter,aBuffer);
+ convertedBufferLength=segmenter->TotalConvertedLengthL(iAdditionalInfo->Alternative7bitEncoding());
+ CleanupStack::PopAndDestroy(2, converter);
+
+ LOGGSMU2("CSmsMessage::ConvertedBufferLengthL() returns %d", convertedBufferLength);
+
+ return convertedBufferLength;
+ BULLSEYE_RESTORE
+ }
+
+/**
+ * Gets the message length.
+ *
+ * In the case where the message is compressed, this function compresses the
+ * text and returns the number of bytes of the compressed buffer.
+ *
+ * The function calls ConvertedBufferLengthL(), and is therefore an expensive
+ * operation.
+ *
+ * @return Message length
+ * @capability None
+ */
+EXPORT_C TInt CSmsMessage::MessageLengthL()
+ {
+ LOGGSMU1("CSmsMessage::MessageLengthL()");
+
+ TInt messagelength=0;
+ if (!SmsPDU().TextCompressed())
+ {
+ messagelength=iBuffer->Length();
+ if(SmsPDU().Alphabet() == TSmsDataCodingScheme::ESmsAlphabetUCS2)messagelength*=2 ;
+ }
+ else
+ {
+ User::Leave(KErrNotSupported);
+ }
+ return messagelength;
+ } // CSmsMessage::MessageLengthL
+
+
+EXPORT_C void CSmsMessage::GetEncodingInfoL(TInt& aPdus, TInt& aUnconvertedChars,
+ TInt& aDowngradedChars, TInt& aFreeUDUnitsInLastPDU)
+ {
+ LOGGSMU1("CSmsMessage::GetEncodingInfoL()");
+
+ aPdus = 1;
+ aUnconvertedChars = 0;
+ aDowngradedChars = 0;
+ aFreeUDUnitsInLastPDU = 0;
+
+ if (TextPresent())
+ {
+ if (IsDecoded())
+ {
+ //
+ // Clear the concatenated flag, EncodeBufferL() will add it if needed.
+ //
+ SmsPDU().SetTextConcatenatedL(EFalse, EFalse);
+
+ //
+ // Attempt to encode to a single PDU, and if that fails then attempt to
+ // encode to a set of PDUs.
+ //
+ CArrayFixFlat<TGsmSms>* tmpArray = new (ELeave) CArrayFixFlat<TGsmSms>(8);
+ CleanupStack::PushL(tmpArray);
+
+ //
+ // Encode the message...
+ //
+ if (!EncodeIntoSinglePDUL(*tmpArray, aUnconvertedChars,
+ aDowngradedChars, aFreeUDUnitsInLastPDU))
+ {
+ EncodeBufferL(*tmpArray, 0, *iBuffer, aUnconvertedChars,
+ aDowngradedChars, aFreeUDUnitsInLastPDU, EFalse);
+
+ aPdus = iAdditionalInfo->SmsPDUArray().Count();
+ if (aPdus > 255)
+ {
+ User::Leave(KErrOverflow);
+ }
+ }
+
+ CleanupStack::PopAndDestroy(tmpArray);
+ }
+ else if (SmsPDU().TextConcatenated())
+ {
+ aPdus = SmsPDU().NumConcatenatedMessagePDUs();
+ aUnconvertedChars = 0;
+ aDowngradedChars = 0;
+ aFreeUDUnitsInLastPDU = 0;
+ }
+ }
+
+ LOGGSMU2("CSmsMessage::GetEncodingInfoL(): aPdus=%d", aPdus);
+ LOGGSMU2("CSmsMessage::GetEncodingInfoL(): aUnconvertedChars=%d", aUnconvertedChars);
+ LOGGSMU2("CSmsMessage::GetEncodingInfoL(): aDowngradedChars=%d", aDowngradedChars);
+ LOGGSMU2("CSmsMessage::GetEncodingInfoL(): aFreeUDUnitsInLastPDU=%d", aFreeUDUnitsInLastPDU);
+ } // CSmsMessage::GetEncodingInfoL
+
+
+/**
+ * Gets the User Data Settings.
+ *
+ * @param aSettings User Data Settings
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::UserDataSettings(TSmsUserDataSettings& aSettings) const
+ {
+ LOGGSMU1("CSmsMessage::UserDataSettings()");
+
+ __ASSERT_DEBUG(TextPresent(),Panic(KGsmuPanicTextNotPresent));
+ aSettings.SetAlphabet(SmsPDU().Alphabet());
+ aSettings.SetTextCompressed(SmsPDU().TextCompressed());
+ TBool is16bit;
+ TBool concatenated=SmsPDU().TextConcatenated(&is16bit);
+ aSettings.SetTextConcatenated(concatenated,is16bit);
+ } // CSmsMessage::UserDataSettings
+
+
+/**
+ * Sets the User Data Settings.
+ *
+ * @param aSettings User Data Settings
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::SetUserDataSettingsL(const TSmsUserDataSettings& aSettings)
+ {
+ LOGGSMU1("CSmsMessage::SetUserDataSettingsL()");
+
+ __ASSERT_DEBUG(TextPresent(),Panic(KGsmuPanicTextNotPresent));
+ SmsPDU().SetAlphabet(aSettings.Alphabet());
+ SmsPDU().SetTextCompressed(aSettings.TextCompressed());
+ TBool is16bit;
+ TBool concatenated=aSettings.TextConcatenated(&is16bit);
+ SmsPDU().SetTextConcatenatedL(concatenated,is16bit);
+ } // CSmsMessage::SetUserDataSettingsL
+
+
+/**
+ * Optimizes the user data settings.
+ *
+ * The alphabet flag causes an alphabet to be chosen which preserves information
+ * in the message and makes the number of PDUs as small as possible.
+ *
+ * The compression settings flag is not supported.
+ *
+ * The compression flag causes compression to be switched on if the resultant
+ * number of PDUs is smaller.
+ *
+ * If user explicitly defines alphabet as UCS2 or 8-bit coding, this setting is preserved;
+ * otherwise, if 7-bit (default) alphabet can not support current text of message UCS2
+ * alphabet (Unicode) is used.
+ *
+ * The two concatenation flags are mutually exclusive as they deal with 8-bit
+ * and 16-bit referenced concatenation. Both flags cause compression to be switched
+ * off and if the message length is greater than the maximum message length,
+ * concatenation is switched on.
+ *
+ * @param aOptions Combination of TSmsOptimizationFlags
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::OptimizeSettingsL(TInt aOptions)
+ {
+ LOGGSMU1("CSmsMessage::OptimizeSettingsL()");
+
+ __ASSERT_DEBUG(TextPresent(),Panic(KGsmuPanicTextNotPresent));
+ __ASSERT_DEBUG(IsDecoded(),Panic(KGsmuPanicNotDecoded));
+
+ if (aOptions&ESmsFlagOptimizeAlphabet && (SmsPDU().Alphabet()==TSmsDataCodingScheme::ESmsAlphabet7Bit))
+ {
+ TBool isSupported=ETrue;
+ TInt numOfUnconvertibleChars;
+ TInt indexOfFirstUnconvertibleChar;
+
+ TInt size=iBuffer->Length();
+ const TInt bufsize=128;
+ TBuf<bufsize> buf;
+ TInt extracted=0;
+ TInt remaining=0;
+ TInt toExtract=0;
+ TInt pos=0;
+
+ // Defect Fix. Previous for loop caused an access violation as extract size was set
+ // to size of ibuffer not bufsize and caused a access violation when over 128. Implemented
+ // fix copies the ibuffer in 128 chunks until its all done.
+
+ while((pos<size) && isSupported)
+ {
+ remaining=(size - extracted);
+
+ if(remaining>bufsize)
+ toExtract=bufsize;
+ else
+ toExtract=remaining;
+
+ iBuffer->Extract(buf,pos,toExtract);
+ isSupported=IsSupportedL(buf,numOfUnconvertibleChars,indexOfFirstUnconvertibleChar);
+ extracted=(extracted+toExtract);
+ pos=extracted;
+ }
+
+ if(!isSupported)
+ SmsPDU().SetAlphabet(TSmsDataCodingScheme::ESmsAlphabetUCS2);
+ }
+ } // CSmsMessage::OptimizeSettingsL
+
+
+/**
+ * This function returns the currently requested alternative encoding method.
+ *
+ * In the case of incoming SMS messages received on the device, it will often
+ * be TSmsEncodingNone unless the Information Elements imply that an
+ * alternative encoding has been used.
+ *
+ * @return The currently selected encoding method.
+ *
+ * @capability None
+ */
+EXPORT_C TSmsEncoding CSmsMessage::Alternative7bitEncoding() const
+ {
+ LOGGSMU1("CSmsMessage::Alternative7bitEncoding()");
+
+ return iAdditionalInfo->Alternative7bitEncoding();
+ } // CSmsMessage::Alternative7bitEncoding
+
+
+/**
+ * This function allows the client to specify an alternative encoding method
+ * incase the default GSM encoding cannot encode the message completely
+ * without data loss.
+ *
+ * @param aEncoding Encoding method to select.
+ *
+ * @return A Symbian system wide error code. This function will return
+ * KErrArgument if the encoding enum is invalid and will return
+ * KErrNotSupported if the required plug-ins are not present.
+ *
+ * @capability None
+ */
+EXPORT_C TInt CSmsMessage::SetAlternative7bitEncoding(TSmsEncoding aEncoding)
+ {
+ LOGGSMU2("CSmsMessage::SetAlternative7bitEncoding(%d)", aEncoding);
+
+ //
+ // Get the encoders that would be used for this encoding method.
+ // The function will also check that the required encoder is present.
+ //
+ TRAPD(err,
+ {
+ CSmsAlphabetConverter* converter = CSmsAlphabetConverter::NewLC(*iCharacterSetConverter, iFs,
+ TSmsDataCodingScheme::ESmsAlphabet7Bit,
+ EFalse);
+ converter->ConfirmAlternativeEncoderL(aEncoding);
+ CleanupStack::PopAndDestroy(converter);
+ });
+
+ //
+ // Set the variable if the encoders are available...
+ //
+ if (err == KErrNone)
+ {
+ iAdditionalInfo->SetAlternative7bitEncoding(aEncoding);
+ }
+
+ return err;
+ } // CSmsMessage::SetAlternative7bitEncoding
+
+
+/**
+ * Takes an encoding setting (received from a PDU) and merges it into the
+ * current setting (where possible).
+ *
+ * @param aEncoding Encoding setting to merge.
+ */
+void CSmsMessage::MergeAlternative7bitEncoding(TSmsEncoding aEncoding) const
+ {
+ LOGGSMU3("CSmsMessage::MergeAlternative7bitEncoding(): aEncoding=%d (currently %d)",
+ aEncoding, iAdditionalInfo->Alternative7bitEncoding());
+
+ switch (iAdditionalInfo->Alternative7bitEncoding())
+ {
+ case ESmsEncodingNone:
+ {
+ // Anything is can be merge with this...
+ iAdditionalInfo->SetAlternative7bitEncoding(aEncoding);
+ }
+ break;
+
+ case ESmsEncodingTurkishSingleShift:
+ {
+ // Only Turkish locking shift can merge...
+ if (aEncoding == ESmsEncodingTurkishLockingShift)
+ {
+ iAdditionalInfo->SetAlternative7bitEncoding(ESmsEncodingTurkishLockingAndSingleShift);
+ }
+ }
+ break;
+
+ case ESmsEncodingTurkishLockingShift:
+ {
+ // Only Turkish single shift can merge...
+ if (aEncoding == ESmsEncodingTurkishSingleShift)
+ {
+ iAdditionalInfo->SetAlternative7bitEncoding(ESmsEncodingTurkishLockingAndSingleShift);
+ }
+ }
+ break;
+
+ case ESmsEncodingPortugueseSingleShift:
+ {
+ // Only Portuguese locking shift can merge...
+ if (aEncoding == ESmsEncodingPortugueseLockingShift)
+ {
+ iAdditionalInfo->SetAlternative7bitEncoding(ESmsEncodingPortugueseLockingAndSingleShift);
+ }
+ }
+ break;
+
+ case ESmsEncodingPortugueseLockingShift:
+ {
+ // Only Portuguese single shift can merge...
+ if (aEncoding == ESmsEncodingPortugueseSingleShift)
+ {
+ iAdditionalInfo->SetAlternative7bitEncoding(ESmsEncodingPortugueseLockingAndSingleShift);
+ }
+ }
+ break;
+
+ case ESmsEncodingTurkishLockingAndSingleShift:
+ case ESmsEncodingSpanishSingleShift:
+ case ESmsEncodingPortugueseLockingAndSingleShift:
+ default:
+ {
+ // NOP - Cannot merge anything into these...
+ }
+ };
+
+ LOGGSMU2("CSmsMessage::MergeAlternative7bitEncoding(): New encoding=%d",
+ iAdditionalInfo->Alternative7bitEncoding());
+ } // CSmsMessage::MergeAlternative7bitEncoding
+
+
+/**
+ * Tests if a buffer can be encoded without loss of information.
+ *
+ * @param aDes The buffer to test for encoding
+ * @param aNumberOfUnconvertibleCharacters On return, the number of
+ * unconvertible characters
+ * @param aIndexOfFirstUnconvertibleCharacter On return, the index of the
+ * first unconvertible character
+ *
+ * @return True if aDes can be encoded without loss of information
+ *
+ * @capability None
+ */
+EXPORT_C TBool CSmsMessage::IsSupportedL(const TDesC& aDes, TInt& aNumberOfUnconvertibleCharacters,
+ TInt& aIndexOfFirstUnconvertibleCharacter)
+ {
+ LOGGSMU1("[1] CSmsMessage::IsSupportedL()");
+
+ __ASSERT_DEBUG(TextPresent(), Panic(KGsmuPanicTextNotPresent));
+
+ aNumberOfUnconvertibleCharacters = 0;
+ aIndexOfFirstUnconvertibleCharacter = aDes.Length();
+
+ if (SmsPDU().TextCompressed())
+ {
+ return EFalse;
+ }
+
+ return SmsPDU().UserData().IsSupportedL(aDes, aNumberOfUnconvertibleCharacters,
+ aIndexOfFirstUnconvertibleCharacter);
+ } // CSmsMessage::IsSupportedL
+
+
+/**
+ * Tests if a buffer can be encoded without loss of information.
+ *
+ * @param aDes The buffer to test for encoding
+ * @param aNumberOfUnconvertibleCharacters On return, the number of
+ * unconvertible characters
+ * @param aNumberOfDowngradedCharacters On return, the number of
+ * characters downgraded
+ * @param aNumberRequiringAlternativeEncoding On return, the number of
+ * characters needing alternative
+ * encoding support
+ * @param aIndexOfFirstUnconvertibleCharacter On return, the index of the
+ * first unconvertible character
+ *
+ * @return True if aDes can be encoded without loss of information
+ *
+ * @capability None
+ */
+EXPORT_C TBool CSmsMessage::IsSupportedL(const TDesC& aDes, TInt& aNumberOfUnconvertibleCharacters,
+ TInt& aNumberOfDowngradedCharacters,
+ TInt& aNumberRequiringAlternativeEncoding,
+ TInt& aIndexOfFirstUnconvertibleCharacter) const
+ {
+ LOGGSMU1("[2] CSmsMessage::IsSupportedL()");
+
+ __ASSERT_DEBUG(TextPresent(), Panic(KGsmuPanicTextNotPresent));
+
+ aNumberOfUnconvertibleCharacters = 0;
+ aNumberOfDowngradedCharacters = 0;
+ aNumberRequiringAlternativeEncoding = 0;
+ aIndexOfFirstUnconvertibleCharacter = aDes.Length();
+
+ if (SmsPDU().TextCompressed())
+ {
+ return EFalse;
+ }
+
+ return SmsPDU().UserData().IsSupportedL(aDes, iAdditionalInfo->Alternative7bitEncoding(),
+ aNumberOfUnconvertibleCharacters,
+ aNumberOfDowngradedCharacters,
+ aNumberRequiringAlternativeEncoding,
+ aIndexOfFirstUnconvertibleCharacter);
+ } // CSmsMessage::IsSupportedL
+
+
+/**
+ * Encodes message PDUs as an array of TGsmSms objects.
+ *
+ * Note, this function should only be called after EncodeIntoSinglePDUL() as EncodeBufferL() now
+ * automatically prepares PDUs for concatenation.
+ *
+ * @param aSmsArray (In) an empty array. On return, one or more encoded TGsmSms.
+ * @param aReference Sets a Concatenated Message Reference (default 0)
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::EncodeMessagePDUsL(CArrayFix<TGsmSms>& aSmsArray, TInt aReference)
+ {
+ LOGGSMU2("CSmsMessage::EncodeMessagePDUsL(): aReference=%d", aReference);
+
+ __ASSERT_DEBUG((aSmsArray.Count()==0),Panic(KGsmuPanicSmsArrayNotEmpty));
+
+ if (TextPresent())
+ {
+ if (SmsPDU().TextCompressed())
+ {
+ User::Leave(KErrNotSupported);
+ }
+ else
+ {
+ TInt unconvertedChars, downgradedChars, freeUDUnitsInLastPDU;
+
+ EncodeBufferL(aSmsArray, aReference, *iBuffer, unconvertedChars,
+ downgradedChars, freeUDUnitsInLastPDU);
+ }
+ }
+ else
+ {
+ if(SmsPDU().Type()==CSmsPDU::ESmsCommand)
+ {
+ //Commands never contain text, so commands only encoded
+ // in this branch.
+ //
+ // However Commands don't support information
+ // elements (per 23.040 6.5) and the CSmsIEOperation class
+ // do not allow control information elements to be added
+ // to Commands, hence the next line is commented out.
+ // PrepareCommandMessageL();
+ }
+
+ TGsmSms sms;
+ SmsPDU().EncodeMessagePDUL(sms);
+ aSmsArray.AppendL(sms);
+ }
+ } // CSmsMessage::EncodeMessagePDUsL
+
+
+/**
+ * @internalComponent
+ *
+ * This method copies information elements from the collections contained in
+ * CSmsMessageAdditionalAttributes into the working PDU.
+ *
+ * Command Messages comprise only 1 PDU. Therefore all information
+ * elements must be present in the working PDU when encoding takes place.
+ * If there is not enough space in the PDU, the message encoding will fail.
+ *
+ * The 23.040 has not defined any information elements that are contained in
+ * Command PDUs. This method has been provided to maintain consistency with
+ * previous GSMU implementations.
+ *
+ * @leave KErrAlreadyExists or KErrAlreadyExists
+ */
+void CSmsMessage::PrepareCommandMessageL()
+ {
+ LOGGSMU1("CSmsMessage::PrepareCommandMessageL()");
+
+ if (SmsPDU().Type()==CSmsPDU::ESmsCommand)
+ {
+ CSmsCommand& command = static_cast<CSmsCommand&>(SmsPDU());
+
+ for (TUint8 category = 0; category < TSmsInformationElementCategories::ENumberOfCategories; category++)
+ {
+ switch(category)
+ {
+ case TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly:
+ case TSmsInformationElementCategories::ECtrlSingleInstanceOnly:
+ case TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed:
+ {
+ for (TUint j = 0; j < iAdditionalInfo->NumberOfControlInformationElements((CSmsMessageAdditionalAttributes::TCategory) category); j++)
+ {
+ CSmsInformationElement& informationElement = iAdditionalInfo->GetControlInformationElementL( ( (CSmsMessageAdditionalAttributes::TCategory) category), j);
+ TPtr8 data = informationElement.Data();
+ command.AddInformationElementL(informationElement.Identifier(), data);
+ }
+ break;
+ }
+ default:
+ LOGGSMU2("CSmsMessage::PrepareCommandMessageL,default switch category = %d, id = %d", category);
+ break;
+ }
+ }
+ }
+ } // CSmsMessage::PrepareCommandMessageL
+
+
+/**
+ * Decodes message PDUs from an array of TGsmSms objects.
+ *
+ * The array contains a concatenated message, and must have the correct number
+ * of PDUs.
+ *
+ * @param aSmsArray Concatenated message
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::DecodeMessagePDUsL(const CArrayFix<TGsmSms>& aSmsArray)
+ {
+ LOGGSMU2("CSmsMessage::DecodeMessagePDUsL(): PDUs=%d", aSmsArray.Count());
+
+ TInt count=aSmsArray.Count();
+ SetIsComplete(ETrue);
+ CArrayPtrFlat<CSmsPDU>* smspduarray=new(ELeave) CArrayPtrFlat<CSmsPDU>(8);
+ CleanupStack::PushL(smspduarray);
+ // With CleanupResetAndDestroyPushL, only ResetAndDestroy method of smspduarray is invoked.
+ // smspduarray object is actually deleted with the first push.
+ // coverity[double_push]
+ CleanupResetAndDestroyPushL(*smspduarray); // Don't forget to destroy what the array elements point to.
+
+ TInt i=0;
+ TBool ismobileterminated=(Type()==CSmsPDU::ESmsDeliver) || (Type()==CSmsPDU::ESmsSubmitReport) || (Type()==CSmsPDU::ESmsStatusReport);
+ for (; i<count; i++)
+ {
+ CSmsPDU* smspdu=CSmsPDU::NewL(aSmsArray[i],*iCharacterSetConverter,iFs, EFalse,ismobileterminated);
+ CleanupStack::PushL(smspdu);
+ TInt j=0;
+ for (; (j<smspduarray->Count()) && (smspdu->ConcatenatedMessagePDUIndex()>(*smspduarray)[j]->ConcatenatedMessagePDUIndex()); j++)
+ {
+ }
+ smspduarray->InsertL(j,smspdu);
+ CleanupStack::Pop();
+ }
+ if (SmsPDU().TextCompressed())
+ User::Leave(KErrNotSupported);
+ else
+ DecodeBufferL(*smspduarray,*iBuffer);
+
+ CleanupStack::PopAndDestroy(2); // smspduarray elements (Reset and Destroy), smspduarray
+ SetIsDecoded(ETrue);
+ SmsPDU().UserData().SetBodyL(KNullDesC8);
+ } // CSmsMessage::DecodeMessagePDUsL
+
+/**
+ * Decodes partial complete message PDUs from an array of TGsmSms objects.
+ *
+ * The array contains a concatenated incomplete message, but the array of
+ * TGsmSms object must be in sequence.
+ *
+ * NOTE:
+ * It will not fully decode EMS and Control Information elements if it needs
+ * to decode a partially complete class 0 SMS message. The assumption is that
+ * it is necessary to display a partially complete message then only the raw
+ * text will be displayed on the UI without any animation elements. The
+ * rational for this design is that these information elements are normally
+ * specified as being located at a specific position in a message. It will
+ * complicate the design of client app if it has to re-calculate the position
+ * of these elements when it receives a partially complete message under
+ * Out Of Memory Conditions.
+
+ * @param aSmsArray Concatenated message
+ * @param aLastPartialCompleteMsg boolean value indicating this is the last
+ * incomplete message for a particular concatenated message.
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::DecodePartialCompleteMessagePDUsL(const CArrayFix<TGsmSms>& aSmsArray, TBool aLastPartialCompleteMsg)
+ {
+ LOGGSMU2("CSmsMessage::DecodePartialCompleteMessagePDUsL(): PDUs=%d", aSmsArray.Count());
+
+ TInt count=aSmsArray.Count();
+ SetIsComplete(EFalse);
+ CArrayPtrFlat<CSmsPDU>* smspduarray=new(ELeave) CArrayPtrFlat<CSmsPDU>(8);
+ CleanupStack::PushL(smspduarray);
+ // With CleanupResetAndDestroyPushL, only ResetAndDestroy method of smspduarray is invoked.
+ // smspduarray object is actually deleted with the first push.
+ // coverity[double_push]
+ CleanupResetAndDestroyPushL(*smspduarray); // Don't forget to destroy what the array elements point to.
+
+ TBool isMobileTerminated=(Type()==CSmsPDU::ESmsDeliver);
+ /*
+ The loop below goes through all the sms's received & check whether the received PDUs are of Class 0
+ or not. The number of PDUs received must be less than the number of concatenated PDUs constitute this message.
+ Then it order the PDUs in sequence for decoding purpose.
+ */
+ for (TInt i=0; i<count; i++)
+ {
+ CSmsPDU* smspdu=CSmsPDU::NewL(aSmsArray[i],*iCharacterSetConverter,iFs, EFalse,isMobileTerminated);
+ CleanupStack::PushL(smspdu);
+
+ /*
+ Check all the PDUs must be class 0 messages & also the number of received PDUs
+ must be less than the number of concatenated PDUs constitute this message
+ */
+ TSmsDataCodingScheme::TSmsClass msgClass;
+ if (smspdu->DataCodingSchemePresent() && smspdu->Class(msgClass))
+ {
+ if (msgClass != TSmsDataCodingScheme::ESmsClass0)
+ {
+ User::Leave(KErrNotSupported);
+ }
+ __ASSERT_DEBUG((count < smspdu->NumConcatenatedMessagePDUs()),Panic(KGsmuPanicWrongNumberOfMessagePDUs));
+ }
+ else
+ {
+ User::Leave(KErrNotSupported);
+ }
+ //The below for statement finds the position in smspduarray where the PDU should be inserted.
+ //The PDUs are put in sequence for decoding purpose.
+ TInt j;
+ for (j=0; (j<smspduarray->Count()) && (smspdu->ConcatenatedMessagePDUIndex()>(*smspduarray)[j]->ConcatenatedMessagePDUIndex()); j++)
+ {
+ }
+ smspduarray->InsertL(j,smspdu);
+ CleanupStack::Pop();
+ }
+
+ if (SmsPDU().TextCompressed())
+ {
+ User::Leave(KErrNotSupported);
+ }
+ else
+ {
+ DecodeOnlyTextL(*smspduarray,*iBuffer);
+ }
+
+ iVersion = CSmsMessage::ESmsIncompleteClass0MessageV;
+
+ TInt startPDU = smspduarray->At(0)->ConcatenatedMessagePDUIndex();
+ TInt endPDU = smspduarray->At(smspduarray->Count()-1)->ConcatenatedMessagePDUIndex();
+ AddIncompleteMessageInfoL(startPDU, endPDU, aLastPartialCompleteMsg);
+
+ CleanupStack::PopAndDestroy(2); // smspduarray elements (Reset and Destroy), smspduarray
+ SetIsDecoded(ETrue);
+ SmsPDU().UserData().SetBodyL(KNullDesC8);
+ }
+
+CSmsMessage::CSmsMessage(RFs& aFs, CSmsBufferBase* aBuffer):
+ iFlags(0),
+ iStatus(NMobileSmsStore::EStoredMessageUnread),
+ iLogServerId(KLogNullId),
+ iBuffer(aBuffer),
+ iFs(aFs),
+ iSlotArray(8),
+ iVersion(ESmsMessageV4),
+ iAdditionalInfo(NULL)
+ {
+ iTime.UniversalTime();
+
+ TBool result = SetUTCOffset(User::UTCOffset());
+ __ASSERT_DEBUG(result, Panic(KGSMUPanicUserTimeZoneOffsetOutOfRange));
+ } // NMobileSmsStore::EStoredMessageUnread
+
+void CSmsMessage::ConstructL(const TGsmSms& aGsmSms, TBool aIsRPError,TBool aIsMobileTerminated)
+ {
+ LOGGSMU1("CSmsMessage::ConstructL()");
+
+ iCharacterSetConverter=CCnvCharacterSetConverter::NewL();
+ iInformationElementArray = new (ELeave) RPointerArray<CEmsInformationElement>(8);
+
+ iAdditionalInfo = CSmsMessageAdditionalAttributes::NewL();
+ CreateControlIEOperationsClassesL();
+ CreateControlNonIEOperationsClassesL();
+
+ iSmsPDU=CSmsPDU::NewL(aGsmSms,*iCharacterSetConverter,iFs, aIsRPError,aIsMobileTerminated);
+ SetIsComplete(NumMessagePDUsL()==1);
+ if (IsComplete() && TextPresent())
+ {
+ TSmsEncoding encodingUsedInSegment = SmsPDU().NationalLanguageEncoding();
+
+ CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,SmsPDU().Alphabet(),BinaryData());
+ TPtrC nativeChars(converter->ConvertToNativeL(SmsPDU().UserData().Body(),
+ encodingUsedInSegment));
+ MergeAlternative7bitEncoding(encodingUsedInSegment);
+
+ if (SmsPDU().TextCompressed())
+ User::Leave(KErrNotSupported);
+ else
+ iBuffer->InsertL(iBuffer->Length(),nativeChars);
+ CleanupStack::PopAndDestroy(converter);
+ CSmsPDU::TSmsPDUType pdutype= SmsPDU().Type();
+ if(pdutype==CSmsPDU::ESmsCommand)
+ {
+ // This branch is never executed as TextPresent() never
+ // returns true when pduType == command
+ User::Leave(KErrArgument);
+ }
+ else if(SmsPDU().UserDataPresent())
+ {
+ TInt smscIndex(0);
+
+ if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
+ {
+ iAdditionalInfo->SetStatusReportSchemeL(EControlParametersScheme);
+ }
+ else
+ {
+ iAdditionalInfo->SetStatusReportSchemeL(EDefaultScheme);
+ }
+
+ InstallControlInformationElementsL(SmsPDU().UserData(), 0);
+ InstallEmsInformationElementsL(SmsPDU().UserData(),0);
+ UpdateUserPromptAndODIElementsStartPosition();
+ }
+ }
+ SetIsDecoded(IsComplete());
+
+ if (TextPresent())
+ SmsPDU().UserData().SetBodyL(KNullDesC8);
+ } // CSmsMessage::ConstructL
+
+
+void CSmsMessage::ConstructL(CSmsPDU::TSmsPDUType aType,TBool aIsRPError)
+ {
+ LOGGSMU3("CSmsMessage::ConstructL(): aType=%d, aIsRPError=%d", (TInt) aType,
+ aIsRPError);
+
+ iCharacterSetConverter=CCnvCharacterSetConverter::NewL();
+ iInformationElementArray = new (ELeave) RPointerArray<CEmsInformationElement>(2);
+
+ iAdditionalInfo = CSmsMessageAdditionalAttributes::NewL();
+ CreateControlIEOperationsClassesL();
+ CreateControlNonIEOperationsClassesL();
+
+ iSmsPDU=CSmsPDU::NewL(aType,*iCharacterSetConverter,iFs,aIsRPError);
+ SetIsComplete(ETrue);
+ SetIsDecoded(ETrue);
+ } // CSmsMessage::ConstructL
+
+
+/**
+ * Counts the number of PDUs that this message will take. To do this the
+ * message will attempt to be encoded into 1 message, and if not into
+ * multiple messages. Due to the processing, the function should be used
+ * sparingly.
+ *
+ * @return Number of PDUs required.
+ */
+TInt CSmsMessage::NumMessageEmsPDUsL()
+ {
+ LOGGSMU1("CSmsMessage::NumMessageEmsPDUsL()");
+
+ //
+ // Clear the concatenated flag, EncodeBufferL() will add it if needed.
+ //
+ SmsPDU().SetTextConcatenatedL(EFalse, EFalse);
+
+ //
+ // Attempt to encode to a single PDU, and if that fails then attempt to
+ // encode to a set of PDUs.
+ //
+ CArrayFixFlat<TGsmSms>* tmpArray = new (ELeave) CArrayFixFlat<TGsmSms>(8);
+ CleanupStack::PushL(tmpArray);
+ TInt numMsgs = 1;
+
+ if (!EncodeIntoSinglePDUL(*tmpArray))
+ {
+ TInt unconvertedChars, downgradedChars, freeUDUnitsInLastPDU;
+
+ EncodeBufferL(*tmpArray, 0, *iBuffer, unconvertedChars,
+ downgradedChars, freeUDUnitsInLastPDU, EFalse);
+
+ numMsgs = iAdditionalInfo->SmsPDUArray().Count();
+ }
+
+ CleanupStack::PopAndDestroy(tmpArray);
+
+ LOGGSMU2("CSmsMessage::NumMessageEmsPDUsL() returns %d", numMsgs);
+
+ return numMsgs;
+ } // CSmsMessage::NumMessageEmsPDUsL
+
+
+/**
+ * @internalComponent
+ *
+ * This method removes all non mandatory information elements from the
+ * working PDU.
+ *
+ * The working PDU is the PDU which is currently being encoded or decoded.
+ *
+ * @leave KErrAlreadyExists or KErrAlreadyExists
+ */
+void CSmsMessage::ResetWorkingPDUL()
+ {
+ LOGGSMU1("CSmsMessage::ResetWorkingPDUL()");
+
+ CSmsUserData& uData = SmsPDU().UserData();
+ //remove non-mandatory EMS information elements
+ for (TInt a=uData.NumInformationElements(); a>0; --a)
+ {
+ const CSmsInformationElement& ie = uData.InformationElement(a-1);
+
+ TSmsInformationElementCategories::TInformationElementCategory category;
+
+ if (TSmsInformationElementCategories::GetCategoryDefinition(ie.Identifier(), category) &&
+ (category != TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUAndWithIdenticalValues) &&
+ (category != TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUButWithValueSpecificToPDU) &&
+ (category != TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUMultipleInstancesPerPDU))
+ {
+ uData.RemoveInformationElement(a-1);
+ }
+ }
+ // reset user body
+ uData.SetBodyL(KNullDesC8);
+ } // CSmsMessage::ResetWorkingPDUL
+
+
+void CSmsMessage::CorrectFormattingL(TUint aCharsAddedToCurrentPDU,
+ RPointerArray<CEmsInformationElement>& aCorrectedFormattingIEArray,
+ TUint aCharsAlreadyAdded)
+ {
+ LOGGSMU3("CSmsMessage::CorrectFormattingL(): aCharsAddedToCurrentPDU=%d, aCharsAlreadyAdded=%d",
+ aCharsAddedToCurrentPDU, aCharsAlreadyAdded);
+
+ CSmsUserData& uData = SmsPDU().UserData();
+ for (TInt a= 0; a < uData.NumInformationElements(); a++)
+ {
+ CSmsInformationElement& ie = uData.InformationElement(a);
+ if (CSmsInformationElement::ESmsEnhancedTextFormatting==ie.Identifier())
+ {
+ CEmsFormatIE& formatIE=static_cast<CEmsFormatIE&>(ie);
+
+ TUint oldFormatLen=formatIE.FormatLength(); //
+ if(aCharsAddedToCurrentPDU < formatIE.StartPosition() + oldFormatLen)
+ {
+ TUint newFormatLen=aCharsAddedToCurrentPDU - formatIE.StartPosition();
+ formatIE.SetFormatLength(newFormatLen);
+
+ // Now, re-encode the information element - this is because we have
+ // changed a message in the UserData which is using EMS elements as
+ // SMS IEs. Encoding is NOT automatic
+ formatIE.EncodeInformationElementL();
+
+ if((TInt)(aCharsAlreadyAdded+aCharsAddedToCurrentPDU) < iBuffer->Length())
+ {
+ CEmsFormatIE* newie=static_cast<CEmsFormatIE*>(formatIE.DuplicateL());
+ CleanupStack::PushL(newie);
+ newie->SetFormatLength(oldFormatLen - newFormatLen);
+ newie->SetStartPosition(aCharsAlreadyAdded+aCharsAddedToCurrentPDU);
+ LOGGSMU2("CSmsMessage::CorrectFormattingL",aCorrectedFormattingIEArray.Count());
+ aCorrectedFormattingIEArray.Append(newie);
+ CleanupStack::Pop(newie);
+ }
+ }
+ }
+ }
+ } // CSmsMessage::CorrectFormattingL
+
+
+void CSmsMessage::CorrectFormattingInSinglePDUL()
+ {
+ LOGGSMU1("CSmsMessage::CorrectFormattingInSinglePDUL()");
+
+ CSmsUserData& uData = SmsPDU().UserData();
+ for (TInt a= 0; a < uData.NumInformationElements(); a++)
+ {
+ CSmsInformationElement& ie = uData.InformationElement(a);
+ if (CSmsInformationElement::ESmsEnhancedTextFormatting==ie.Identifier())
+ {
+ CEmsFormatIE& formatIE=static_cast<CEmsFormatIE&>(ie);
+ TUint oldFormatLen=formatIE.FormatLength(); //
+ if(iBuffer->Length() < (TInt)(formatIE.StartPosition()+ oldFormatLen))
+ {
+ TUint newFormatLen=iBuffer->Length() - formatIE.StartPosition();
+ formatIE.SetFormatLength(newFormatLen);
+
+ // reencode
+ formatIE.EncodeInformationElementL();
+ }
+ }
+ }
+ } // CSmsMessage::CorrectFormattingInSinglePDUL
+
+
+/**
+ * Adds a copy of the current PDU to the PDU array used to record all the
+ * PDUs being encoded in a concatentated message.
+ *
+ * @param aDoEncode If true the PDU is added and updated. If false only a
+ * NULL placeholder is stored. This allows the number of
+ * PDUs to be quickly counted if the encoded PDUs are of
+ * no further use.
+ */
+void CSmsMessage::AddCurrentPDUToPDUArrayL(TBool aDoEncode)
+ {
+ LOGGSMU2("CSmsMessage::AddCurrentPDUToPDUArrayL(): Adding PDU number %d",
+ iAdditionalInfo->SmsPDUArray().Count() + 1);
+
+ //
+ // Maximum number of PDU is 255, so if we have that already then we cannot
+ // continue.
+ //
+ TInt numPDUs = iAdditionalInfo->SmsPDUArray().Count();
+
+ if (numPDUs >= 255)
+ {
+ User::Leave(KErrOverflow);
+ }
+
+ //
+ // We only do most of the work if we are actually encoding.
+ //
+ if (aDoEncode)
+ {
+ //
+ // Update the Concatenated Message PDU numbers in the current PDU. This
+ // means that at least the last PDU has the correct values (to update
+ // all PDUs when a new PDU is added would be too slow, so we do that
+ // only once at the end).
+ //
+ if (numPDUs > 0)
+ {
+ SmsPDU().SetConcatenatedMessagePDUIndex(numPDUs+1);
+ SmsPDU().SetNumConcatenatedMessagePDUs(numPDUs+1);
+ }
+
+ //
+ // Create copy of the current PDU and store it in the array...
+ //
+ CSmsPDU* newPDU = SmsPDU().DuplicateL();
+ CleanupStack::PushL(newPDU);
+ iAdditionalInfo->SmsPDUArray().AppendL(newPDU);
+ CleanupStack::Pop(newPDU);
+ }
+ else
+ {
+ //
+ // Otherwise just append a NULL value to allow the data PDUs to be
+ // counted...
+ //
+ iAdditionalInfo->SmsPDUArray().AppendL(NULL);
+ }
+ } // CSmsMessage::AddCurrentPDUToPDUArrayL
+
+
+TBool CSmsMessage::AddIEToUserDataL(CEmsInformationElement* aIE, TInt aCharsAlreadyAdded,TUint& aCharsAddedToCurrentPDU,CSmsEMSBufferSegmenter& aSeg)
+ {
+ LOGGSMU1("CSmsMessage::AddIEToUserDataL()");
+
+ TBool ieAdded=EFalse;
+ if (SmsPDU().UserData().EmsInformationElementWillFitL(aIE,aSeg,aCharsAddedToCurrentPDU))
+ {
+ CEmsInformationElement* newIE=aIE->DuplicateL();
+ newIE->SetStartPosition(newIE->StartPosition()-aCharsAlreadyAdded);
+ CleanupStack::PushL(newIE);
+ SmsPDU().UserData().AddEmsInformationElementL(newIE);
+ CleanupStack::Pop(newIE);
+ ieAdded=ETrue;
+ }
+ return ieAdded;
+ } // CSmsMessage::AddIEToUserDataL
+
+
+/**
+ * Fills the current PDU with the number of specified native chars.
+ *
+ * @param aSeg Buffer containing the native chars
+ * @param aNumChars number of native characters to add.
+ * @param aEncoding SMS Encoding if required.
+ *
+ * @return TInt Number of native characters added
+ */
+TInt CSmsMessage::FillPduL(CSmsEMSBufferSegmenter& aSeg, TInt aNumChars, TSmsEncoding aEncoding)
+ {
+ LOGGSMU1("CSmsMessage::FillPduL()");
+
+ TUint maxUDUnitsREmaining=SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
+
+ if (aNumChars==0 || maxUDUnitsREmaining==0)
+ {
+ return 0;
+ }
+
+ HBufC8* buf=HBufC8::NewMaxLC(2*aNumChars);
+ TPtr8 ptr(buf->Des());
+ TInt numberOfUnconvertibleCharacters(0);
+ TInt numberOfDowngradedCharacters(0);
+
+ TInt nativeLength = aSeg.SegmentL(ptr, aNumChars, maxUDUnitsREmaining,
+ numberOfUnconvertibleCharacters,
+ numberOfDowngradedCharacters,
+ aEncoding);
+
+ SmsPDU().UserData().AppendBodyL(ptr);
+
+ CleanupStack::PopAndDestroy(buf);
+ return nativeLength;
+ } // CSmsMessage::FillPduL
+
+
+/**
+ * This method copies control information elements from the specified
+ * collection into the working PDU.
+ *
+ * @param aCategory The category of control information element to be
+ * added to the PDU.
+ * @param aMandatoryInPDU Specifies whether the specified category of information
+ * element must be added to this PDU.
+ * @param aDoEncode Flag indicating if encoding is really wanted, or just the
+ * calculation of the number of PDUs.
+ *
+ * @leave KErrArgument If the category is mandatory but one or more elements
+ * cannot be added then the encoding will fail.
+ * @leave KErrOverFlow If the information element is too big to be encoded into
+ * a PDU that contains only the mandatory elements.
+ */
+void CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL(TSmsInformationElementCategories::TInformationElementCategory aCategory,
+ TBool aMandatoryInPDU, TBool aDoEncode)
+ {
+ LOGGSMU1("CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL()");
+
+ TUint numberOfInformationElements = iAdditionalInfo->NumberOfControlInformationElements(aCategory);
+
+ for (TInt i = 0; i < numberOfInformationElements; i++)
+ {
+ CSmsInformationElement& informationElement = iAdditionalInfo->GetControlInformationElementL( aCategory, i);
+
+ CSmsInformationElement* cloneInformationElement = CSmsInformationElement::NewL(informationElement.Identifier(),informationElement.Data());
+ CleanupStack::PushL(cloneInformationElement);
+
+ if (SmsPDU().UserData().ControlInformationElementWillFitL(cloneInformationElement))
+ {
+ SmsPDU().UserData().UpdateInformationElementArrayL(informationElement.Identifier(),informationElement.Data());
+ }
+ else if (aMandatoryInPDU)
+ {
+ // Error Scenario, cannot fit the mandatory PDU into the User Data
+ User::Leave(KErrArgument);
+ }
+ else
+ {
+ // Close off PDU and transfer to output array
+ AddCurrentPDUToPDUArrayL(aDoEncode);
+ ResetWorkingPDUL();
+
+ // Now test whether the information element will fit into a PDU at all.
+ // It is possible to make Enhanced Voice Mail Information Elements
+ // bigger than the available space in the PDU.
+ TBool canFit = SmsPDU().UserData().ControlInformationElementWillFitL(cloneInformationElement);
+ if (canFit == EFalse)
+ {
+ LOGGSMU1("CSmsMessage::AddControlInformationElementsToMultiSegmentMessage, IE too bit to fit in any PDUL");
+ User::Leave(KErrArgument);
+ }
+ i--;
+ }
+
+ CleanupStack::PopAndDestroy(cloneInformationElement);
+ }
+ } // CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL
+
+
+/**
+ * This method copies control information elements from the collections of
+ * control information elements contained in CSmsAdditionalAttributes into the
+ * working PDU.
+ *
+ * @param aDoEncode Flag indicating if encoding is really wanted, or just the
+ * calculation of the number of PDUs.
+ *
+ * @leave KErrArgument If the category is mandatory but one or more elements
+ * cannot be added then the encoding will fail.
+ */
+void CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL(TBool aDoEncode)
+ {
+ LOGGSMU1("CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL() 1");
+
+ TBool mandatoryInEachPDU = ETrue;
+ AddControlInformationElementsToMultiSegmentMessageL(TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly,
+ mandatoryInEachPDU, aDoEncode);
+ mandatoryInEachPDU = EFalse;
+ AddControlInformationElementsToMultiSegmentMessageL(TSmsInformationElementCategories::ECtrlSingleInstanceOnly,
+ mandatoryInEachPDU, aDoEncode);
+ AddControlInformationElementsToMultiSegmentMessageL(TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed,
+ mandatoryInEachPDU, aDoEncode);
+ } // CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL
+
+
+/**
+ * Attempts to add EMS IE to the current PDU.
+ *
+ * @param aSegmenter Reference to buffer segmenter.
+ * @param aCharsAddedToCurrentPDU Returned number of characters added to current PDU.
+ * @param aDoEncode Flag indicating if encoding is really wanted,
+ * or just the calculation of the number of PDUs.
+ * @param aEncoding SMS 7bit encoding if appropriate.
+ * @param aCorrectedFormatingIEArray Array of IEs that have to be placed in following
+ * PDUs (e.g. corrected).
+ * @param aCurrEMSIEno Current IE number.
+ * @param aCharsAlreadyAdded Returned number of characters added.
+ *
+ * @return Whether EMS IE has beenn added, in singleMode returns true if there are no more than one PDU.
+ */
+TBool CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL(CSmsEMSBufferSegmenter& aSegmenter,
+ TUint& aCharsAddedToCurrentPDU,
+ TBool aDoEncode,
+ TSmsEncoding& aEncoding,
+ RPointerArray<CEmsInformationElement>& aCorrectedFormatingIEArray,
+ TUint& aCurrEMSIEno,
+ TUint& aCharsAlreadyAdded)
+ {
+ LOGGSMU1("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL()");
+
+ TUint startPosition=0;
+
+ // number of chars added to the current PDU
+ TUint no=iInformationElementArray->Count();
+ LOGGSMU2("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL no of IE %d",no);
+ CEmsInformationElement* ie = NULL;
+ TUint msgLen=iBuffer->Length();
+ TUint filledChars=0;
+
+ while(aCurrEMSIEno < no || aCorrectedFormatingIEArray.Count() > 0)
+ {
+ ie = NULL;
+ TBool correction=EFalse;
+ if(aCurrEMSIEno < no)
+ {
+ ie = (*iInformationElementArray)[aCurrEMSIEno];
+ startPosition=ie->StartPosition();
+ }
+
+ if(ie == NULL || ( startPosition != aCharsAlreadyAdded) )
+ {
+ if(aCorrectedFormatingIEArray.Count() > 0)
+ {
+ correction=ETrue;
+ ie = aCorrectedFormatingIEArray[0];
+ startPosition=ie->StartPosition();
+ }
+ }
+
+ __ASSERT_ALWAYS(ie !=NULL, User::Leave(KErrCorrupt));
+
+ if(startPosition <= msgLen)
+ {
+ __ASSERT_DEBUG(startPosition>=aCharsAlreadyAdded, User::Leave(KErrUnderflow));
+ startPosition -= aCharsAlreadyAdded; // startPosition now relative to current PDU.
+
+ // Add all chars upto startposition.
+ filledChars=0;
+
+ if(startPosition > aCharsAddedToCurrentPDU)
+ {
+ filledChars = FillPduL(aSegmenter, startPosition-aCharsAddedToCurrentPDU, aEncoding);
+ aCharsAddedToCurrentPDU+=filledChars;
+ }
+
+ LOGGSMU2("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL: filled %d chars", filledChars);
+
+ if (aCharsAddedToCurrentPDU==startPosition)
+ {
+ // Try adding the IE.
+ if (AddIEToUserDataL(ie, aCharsAlreadyAdded,aCharsAddedToCurrentPDU,aSegmenter))
+ {
+ if(correction)
+ {
+ aCorrectedFormatingIEArray.Remove(0);
+ // aCorrectedFormatingIEArray[0] has been removed. In next loop, ie will point another element. So there is no double free.
+ // coverity[double_free]
+ delete ie;
+ correction=EFalse;
+ }
+ else aCurrEMSIEno++;
+ }
+ else
+ {
+ // Information Element will not fit send PDU
+ LOGGSMU1("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL: ie will not fit send Message");
+ CorrectFormattingL(aCharsAddedToCurrentPDU,aCorrectedFormatingIEArray,aCharsAlreadyAdded);
+
+ aCharsAlreadyAdded += aCharsAddedToCurrentPDU;
+ aCharsAddedToCurrentPDU=0;
+
+ AddCurrentPDUToPDUArrayL(aDoEncode);
+ ResetWorkingPDUL();
+
+ //
+ // Find the encoding method for the next segment...
+ //
+ //aEncoding = ESmsEncodingNone;
+ //TRAP_IGNORE(aEncoding = aSegmenter->FindBestAlternativeEncodingL(iAdditionalInfo->iAlternative7bitEncoding,
+ // maxBodyLength));
+ SmsPDU().SetNationalLanguageEncodingL(aEncoding);
+ }
+ }
+ else
+ {
+ // native chars upto start position will not fit send PDu.
+ LOGGSMU1("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL: PDU is filled with chars sending");
+
+ CorrectFormattingL(aCharsAddedToCurrentPDU,aCorrectedFormatingIEArray,aCharsAlreadyAdded);
+
+ aCharsAlreadyAdded += aCharsAddedToCurrentPDU;
+ aCharsAddedToCurrentPDU=0;
+
+ AddCurrentPDUToPDUArrayL(aDoEncode);
+ ResetWorkingPDUL();
+
+ //
+ // Find the encoding method for the next segment...
+ //
+ //aEncoding = ESmsEncodingNone;
+ //TRAP_IGNORE(aEncoding = aSegmenter->FindBestAlternativeEncodingL(iAdditionalInfo->iAlternative7bitEncoding,
+ // maxBodyLength));
+ SmsPDU().SetNationalLanguageEncodingL(aEncoding);
+ }
+ }
+ else
+ {
+ aCurrEMSIEno++;
+ }
+ } // end of while loop for all IEs
+
+ return ETrue;
+ } // CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL
+
+
+/**
+ * Attempts to add EMS IE to the current PDU
+ *
+ * @param aSegmenter
+ * @return TBool whether EMS IEs have been added to segment
+ */
+TBool CSmsMessage::AddEMSInformationElementsToSingleSegmentMessageL(CSmsEMSBufferSegmenter& aSegmenter,
+ TSmsEncoding aEncoding)
+ {
+ LOGGSMU1("CSmsMessage::AddEMSInformationElementsToSingleSegmentMessageL()");
+
+ TUint charsAddedToCurrentPDU=0;
+ TUint numOfEmsIE=iInformationElementArray->Count();
+ TUint currEmsIEindex=0;
+ CEmsInformationElement* ie = NULL;
+ TUint startPosition=0;
+ TUint filledChars=0;
+
+ while(currEmsIEindex < numOfEmsIE)
+ {
+ ie = (*iInformationElementArray)[currEmsIEindex];
+ startPosition=ie->StartPosition();
+
+ if (startPosition > charsAddedToCurrentPDU)
+ {
+ filledChars = FillPduL(aSegmenter, startPosition-charsAddedToCurrentPDU, aEncoding);
+ charsAddedToCurrentPDU+=filledChars;
+ }
+
+ if (charsAddedToCurrentPDU != startPosition ||
+ !AddIEToUserDataL(ie, 0,charsAddedToCurrentPDU,aSegmenter))
+ {
+ return EFalse;
+ }
+
+ ++currEmsIEindex;
+ }
+
+ return ETrue;
+ } // CSmsMessage::AddEMSInformationElementsToSingleSegmentMessageL
+
+
+/**
+ * Encode the PDU into an TGsmSms array. The Text and the EMS objects are
+ * laid out with respect to start position locations and encoded into the
+ * correct TGsmSms object.
+ *
+ * @leave KErrUnderflow if the Ems objects are not in Start position order.
+ *
+ * @param aSmsArray Returned array of newly created TSms objects
+ * containing the encoded message.
+ * @param aReference Unique reference number to be given to the
+ * TGsmSms objects.
+ * @param aBuffer Body Text buffer of the message.
+ * @param aUnconvertedChars Exit param for the number of characters not converted.
+ * @param aDowngradedChars Exit param for the number of characters downgraded.
+ * @param aFreeUDUnitsInLastPDU Exit param for the number of characters free
+ * in the last PDU.
+ * @param aDoEncode Flag indicating if encoding is really wanted,
+ * or just the calculation of the number of PDUs.
+ */
+void CSmsMessage::EncodeBufferL(CArrayFix<TGsmSms>& aSmsArray, TInt aReference,
+ const CSmsBufferBase& aBuffer,
+ TInt& aUnconvertedChars, TInt& aDowngradedChars,
+ TInt& aFreeUDUnitsInLastPDU, TBool aDoEncode)
+ {
+ LOGGSMU1("CSmsMessage::EncodeBufferL()");
+
+ aUnconvertedChars = 0;
+ aDowngradedChars = 0;
+ aFreeUDUnitsInLastPDU = 0;
+
+ //
+ // Reset the working array of PDUs...
+ //
+ iAdditionalInfo->SmsPDUArray().ResetAndDestroy();
+
+ TUint currEMSIEno(0);
+
+ TInt smscIndex(0);
+ TBool smscPresent(EFalse);
+
+ TInt emailOverallHeaderLength(0);
+ TInt emailIndex(0);
+ TBool emailPresent(EFalse);
+
+ if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
+ {
+ smscPresent=ETrue;
+ }
+ if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEIRFC822EmailHeader,emailIndex))
+ {
+ emailPresent=ETrue;
+ emailOverallHeaderLength=SmsPDU().UserData().InformationElement(emailIndex).Data()[0];
+ }
+
+ //
+ // Create Array for corrected format elements. These will be elements that
+ // have to be moved into subsequent PDUs due to lack of space in the
+ // current PDU.
+ //
+ RPointerArray<CEmsInformationElement> correctedFormatingIEArray(2);
+ CleanupResetAndDestroyPushL(correctedFormatingIEArray);
+
+ //
+ // Reset the working PDU. This safes time be keeping fields we need and
+ // droping any data from previous PDUs.
+ //
+ ResetWorkingPDUL();
+
+ //
+ // Automatically prepare for concatenation (any single PDU messages would
+ // have been handled by EncodeIntoSinglePDUL() previously).
+ //
+ SmsPDU().SetTextConcatenatedL(ETrue,iIs16BitConcatenation);
+
+ TInt maxBodyLength=SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
+
+ //
+ // Add any elements that are required to be present, and ensure they
+ // have correct data stored (for example if we are recycling the working PDU).
+ //
+ AddControlInformationElementsToMultiSegmentMessageL(aDoEncode);
+
+ //
+ // Create EMS Segmenter and Buffer Converter...
+ //
+ CSmsAlphabetConverter* converter = CSmsAlphabetConverter::NewLC(*iCharacterSetConverter, iFs,SmsPDU().Alphabet(),
+ BinaryData());
+ CSmsEMSBufferSegmenter* segmenter = CSmsEMSBufferSegmenter::NewLC(*converter, aBuffer, maxBodyLength);
+ TBool isUnicode = (SmsPDU().Alphabet() == TSmsDataCodingScheme::ESmsAlphabetUCS2);
+
+ TBool informationToSend = ETrue;
+ TUint charsAdded2CurrentPDU = 0;
+ TUint charsAlreadyAdded = 0;
+
+ //
+ // Find the best alternative encoding for the current segment. This will be
+ // set at the beginning of each PDU using the list of encoders.
+ //
+ TSmsEncoding encodingToUse = ESmsEncodingNone;
+
+ TRAP_IGNORE(encodingToUse = segmenter->FindBestAlternativeEncodingL(iAdditionalInfo->Alternative7bitEncoding(),
+ aBuffer.Length()));
+ SmsPDU().SetNationalLanguageEncodingL(encodingToUse);
+
+ //
+ // If there are information elements to add, add them to the first PDU (or
+ // to the correct formatting array for later PDUs if more appropriate).
+ //
+ if(iInformationElementArray->Count() >0)
+ {
+ AddEMSInformationElementsToMultiSegmentMessageL(*segmenter, charsAdded2CurrentPDU,
+ aDoEncode, encodingToUse,
+ correctedFormatingIEArray,
+ currEMSIEno, charsAlreadyAdded);
+ }
+
+ //
+ // Allocate a temporary buffer to work with...
+ //
+ HBufC8* buf=HBufC8::NewMaxLC(maxBodyLength);
+ TPtr8 ptr(buf->Des());
+
+ //
+ // While there is still data to encode see how much space is left in this
+ // PDU and attempt to encode something into it...
+ //
+ while (segmenter->MoreL())
+ {
+ LOGGSMU1("CSmsMessage::EncodeBufferL - there is MoreL");
+
+ //
+ // Calculate the space left to use in this PDU...
+ //
+ TInt size = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
+ LOGGSMU2("CSmsMessage::EncodeBufferL - remaining size in PDU is %d",size);
+
+ //
+ // While there is no space, correct the formatting (which may
+ // introduce any un-placed EMS Elements into the corrected format
+ // array) and then start a new PDU...
+ //
+ while (size==0)
+ {
+ //
+ // Store any elements not yet placed into the array for later...
+ //
+ CorrectFormattingL(charsAdded2CurrentPDU, correctedFormatingIEArray, charsAlreadyAdded);
+
+ //
+ // Store this PDU, reset the working PDU and get ready to
+ // continue with the next PDU...
+ //
+ aFreeUDUnitsInLastPDU = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
+ AddCurrentPDUToPDUArrayL(aDoEncode);
+ ResetWorkingPDUL();
+ informationToSend=EFalse;
+ charsAlreadyAdded+=charsAdded2CurrentPDU;
+ charsAdded2CurrentPDU=0;
+
+ //
+ // Find the encoding method for the next segment...
+ //
+ //encodingToUse = ESmsEncodingNone;
+ //TRAP_IGNORE(encodingToUse = segmenter->FindBestAlternativeEncodingL(iAdditionalInfo->iAlternative7bitEncoding,
+ // maxBodyLength));
+ SmsPDU().SetNationalLanguageEncodingL(encodingToUse);
+
+ //
+ // Add any elements that can be placed now (from previous
+ // PDUs and above)...
+ //
+ LOGGSMU3("CSmsMessage::EncodeBufferL: IE count %d corrected count %d",iInformationElementArray->Count(),correctedFormatingIEArray.Count() );
+ if ((TUint)iInformationElementArray->Count() > currEMSIEno ||
+ correctedFormatingIEArray.Count() > 0)
+ {
+ AddEMSInformationElementsToMultiSegmentMessageL(*segmenter,charsAdded2CurrentPDU,
+ aDoEncode, encodingToUse,
+ correctedFormatingIEArray,
+ currEMSIEno,charsAlreadyAdded);
+ }
+
+ //
+ // Calculate the space left remaining in this new PDU...
+ //
+ size = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
+ LOGGSMU2("CSmsMessage::EncodeBufferL - remaining size in PDU is %d",size);
+ }
+
+ //
+ // We have space in this PDU and no elements to place, so obtain
+ // the next peice of text that can fit and append it.
+ //
+ segmenter->SegmentNextL(ptr, size, aUnconvertedChars, aDowngradedChars, encodingToUse);
+ SmsPDU().UserData().AppendBodyL(ptr);
+
+ TUint charsInSegment= isUnicode ? ptr.Length()/2 : ptr.Length();
+ LOGGSMU2("CSmsMessage::EncodeBufferL: segmenting added %d chars", charsInSegment);
+
+ //
+ // At this point the working PDU is either full (e.g. we filled the
+ // remaining space with a chuck of text, or the is some space as we
+ // stored the last part of the text.
+ //
+ // If there are any elements not yet stored, add them to the
+ // formatting array...
+ //
+ charsAdded2CurrentPDU+=charsInSegment;
+ CorrectFormattingL(charsAdded2CurrentPDU, correctedFormatingIEArray, charsAlreadyAdded);
+ charsAlreadyAdded+=charsAdded2CurrentPDU;
+ LOGGSMU2("CSmsMessage::EncodeBufferL(): charsAlreadyAdded=%d", charsAlreadyAdded);
+
+ //
+ // Now store this PDU and reset the working PDU...
+ //
+ aFreeUDUnitsInLastPDU = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
+ AddCurrentPDUToPDUArrayL(aDoEncode);
+ ResetWorkingPDUL();
+ informationToSend=EFalse;
+ charsAdded2CurrentPDU=0;
+
+ //
+ // Find the encoding method for the next segment...
+ //
+ //encodingToUse = ESmsEncodingNone;
+ //TRAP_IGNORE(encodingToUse = segmenter->FindBestAlternativeEncodingL(iAdditionalInfo->iAlternative7bitEncoding,
+ // maxBodyLength));
+ SmsPDU().SetNationalLanguageEncodingL(encodingToUse);
+
+ //
+ // Add any elements that can be placed now given we have a new
+ // empty PDU...
+ //
+ LOGGSMU3("CSmsMessage::EncodeBufferL: IE count %d corrected count %d",
+ iInformationElementArray->Count(), correctedFormatingIEArray.Count() );
+ if ((TUint)iInformationElementArray->Count() > currEMSIEno ||
+ correctedFormatingIEArray.Count() > 0)
+ {
+ AddEMSInformationElementsToMultiSegmentMessageL(*segmenter, charsAdded2CurrentPDU,
+ aDoEncode, encodingToUse,
+ correctedFormatingIEArray,
+ currEMSIEno, charsAlreadyAdded);
+ }
+ LOGGSMU1("CSmsMessage::EncodeBufferL end Moreloop");
+ }
+ CleanupStack::PopAndDestroy(buf);
+
+ LOGGSMU1("CSmsMessage::EncodeBufferL - last PDU");
+
+ //
+ // This is the last PDU. We need to check if there is a partial PDU left over
+ // and add it if needed.
+ //
+ if (informationToSend)
+ {
+ aFreeUDUnitsInLastPDU = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
+ AddCurrentPDUToPDUArrayL(aDoEncode);
+ ResetWorkingPDUL();
+ }
+
+ //
+ // At this point the segmenting and layouts of PDU is complete, so if we
+ // find any more data something is wrong...
+ //
+ if (segmenter->MoreL() || correctedFormatingIEArray.Count() > 0)
+ {
+ User::Leave(KErrCorrupt);
+ }
+
+ CleanupStack::PopAndDestroy(3, &correctedFormatingIEArray); // segmenter, converter & correctedFormatingIEArray
+
+ //
+ // By now the PDUs are segmented and correctly setup for encoding.
+ // They have not been encoded yet, as this requires the PDU total to be known.
+ // So we go through the array setting the final PDU number/total PDUs and
+ // perform the encoding from CSmsPDU to the TGsmPdu object.
+ //
+ // Note: In the case were aDoEncode is EFalse, iSmsPDUArray will be full
+ // of NULL pointers as it is only the count that we need in that case.
+ //
+ TInt numPDUs = iAdditionalInfo->SmsPDUArray().Count();
+
+ LOGGSMU2("CSmsMessage::EncodeBufferL number of PDUs: %d", iAdditionalInfo->SmsPDUArray().Count());
+
+ if (aDoEncode)
+ {
+ CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = iAdditionalInfo->GetStatusReportScheme();
+ TGsmSms gsmSms;
+
+ for (TInt pdu = 0; pdu < numPDUs; pdu++)
+ {
+ if(scheme.Id() == EControlParametersScheme)
+ {
+ if(smscPresent)
+ {
+ CSmsSMSCCtrlParameterOperations& ieOp = (CSmsSMSCCtrlParameterOperations&)GetOperationsForIEL(CSmsInformationElement::ESmsIEISMSCControlParameters);
+ TUint8 octet(0);
+
+ if (ieOp.GetStatusReport(pdu, octet) == KErrNone)
+ {
+ iAdditionalInfo->SmsPDUArray()[pdu]->UpdateSMSCCtrlParameterL(octet);
+ }
+ }
+ else
+ {
+ User::Leave(KErrNotFound);
+ }
+ }
+ else if(scheme.Id() == ETPSRRScheme)
+ {
+ TSmsFirstOctet smsReportRequest;
+ CSmsTPSRROperations& nonIEOp = (CSmsTPSRROperations&)GetOperationsForNonIEL(ESmsTPSRRParameter);
+ smsReportRequest = nonIEOp.GetStatusReport(pdu);
+
+ iAdditionalInfo->SmsPDUArray()[pdu]->UpdateTPSRRL(smsReportRequest);
+ }
+
+ if(emailPresent)
+ {
+ iAdditionalInfo->SmsPDUArray()[pdu]->UpdateEmailHeaderDataL(emailOverallHeaderLength);
+ }
+
+ //
+ // Set the concatenation Message Reference number and PDU numbers...
+ //
+ iAdditionalInfo->SmsPDUArray()[pdu]->UpdateConcatenationDataL(aReference, pdu+1, numPDUs);
+
+ //
+ // Encode this PDU...
+ //
+
+ TEncodeParams encodeParams;
+ encodeParams.iTimeStamp = &Time();
+
+ TTimeIntervalSeconds interval = UTCOffset();
+ encodeParams.iTimeIntervalInSeconds = &interval;
+
+ iAdditionalInfo->SmsPDUArray()[pdu]->EncodeMessagePDUL(gsmSms, &encodeParams);
+ aSmsArray.AppendL(gsmSms);
+ }
+
+ //
+ // Since the working PDU has been reset the data in it does not match
+ // the data of the last PDU. Some tests in SMS Stack assume it does
+ // and therefore to retain compatibility we decode the last PDU back
+ // over the working PDU.
+ //
+ TGsmuLex8 lex(gsmSms.Pdu());
+ SmsPDU().DecodeL(lex);
+ }
+ } // CSmsMessage::EncodeBufferL
+
+
+/**
+ * Attempts to encode into the single PDU. This function is the private version
+ * to the public EncodeIntoSinglePDUL() function. It performs the work and also
+ * returns more information regarding the characters encoded.
+ *
+ * The Text and the EMS objects are laid out with respect to start position
+ * locations.
+ *
+ * @leave KErrUnderflow if the Ems objects are not in Start position order.
+ *
+ * @param aSmsArray Returned array of newly created TSms objects
+ * containing the encoded message.
+ * @param aUnconvertedChars Exit param for the number of characters not converted.
+ * @param aDowngradedChars Exit param for the number of characters downgraded.
+ * @param aFreeUDUnitsInLastPDU Exit param for the number of characters free
+ * in the last PDU.
+ */
+TBool CSmsMessage::EncodeIntoSinglePDUL(CArrayFix<TGsmSms>& aSmsArray, TInt& aUnconvertedChars,
+ TInt& aDowngradedChars, TInt& aFreeUDUnitsInLastPDU)
+ {
+ LOGGSMU1("CSmsMessage::EncodeIntoSinglePDUL()");
+
+ __ASSERT_DEBUG((aSmsArray.Count()==0),Panic(KGsmuPanicSmsArrayNotEmpty));
+
+ aUnconvertedChars = 0;
+ aDowngradedChars = 0;
+ aFreeUDUnitsInLastPDU = 0;
+
+ iAdditionalInfo->SmsPDUArray().ResetAndDestroy();
+
+ if (!TextPresent())
+ {
+ if(SmsPDU().Type()==CSmsPDU::ESmsCommand)
+ {
+ // Commands don't contain text, so commands
+ // are only encoded in this branch.
+ PrepareCommandMessageL();
+ }
+
+ TGsmSms sms;
+ SmsPDU().EncodeMessagePDUL(sms);
+ aSmsArray.AppendL(sms);
+ return ETrue;
+ }
+
+ ResetWorkingPDUL();
+
+ // find the length of all the control information elements
+ TUint ieLength=0;
+ for (TUint8 category = 0; category < TSmsInformationElementCategories::ENumberOfCategories; category++)
+ {
+ switch (category)
+ {
+ case TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly:
+ case TSmsInformationElementCategories::ECtrlSingleInstanceOnly:
+ case TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed:
+ {
+ for (TUint j = 0; j < iAdditionalInfo->NumberOfControlInformationElements((CSmsMessageAdditionalAttributes::TCategory) category); j++)
+ {
+ ieLength += iAdditionalInfo->GetControlInformationElementL( ( (CSmsMessageAdditionalAttributes::TCategory) category), j).Length();
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ LOGGSMU2("CSmsMessage::EncodeIntoSinglePDUL, ctrl elem len = %d", ieLength);
+
+ CEmsInformationElement* emsIE =NULL;
+ for (TInt num=0; num<iInformationElementArray->Count();num++)
+ {
+ emsIE = (*iInformationElementArray)[num];
+ ieLength+=emsIE->Length();
+ }
+
+ TInt remainInBody=SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining(ieLength);
+
+ TInt msgLength=MessageLengthL(); // in octets
+
+ if( msgLength > remainInBody) return EFalse;
+
+ LOGGSMU4("CSmsMessage::EncodeIntoSinglePDUL, ie len = %d, remainInBody = %d, msgLength = %d", ieLength, msgLength, remainInBody);
+ // add all control information elements into working PDU.
+ //
+ for (TUint8 category = 0; category < TSmsInformationElementCategories::ENumberOfCategories; category++)
+ {
+ switch (category)
+ {
+ case TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly:
+ case TSmsInformationElementCategories::ECtrlSingleInstanceOnly:
+ case TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed:
+ {
+ for (TUint j = 0; j < iAdditionalInfo->NumberOfControlInformationElements((CSmsMessageAdditionalAttributes::TCategory) category); j++)
+ {
+ CSmsInformationElement& informationElement = iAdditionalInfo->GetControlInformationElementL( ( (CSmsMessageAdditionalAttributes::TCategory) category), j);
+
+ CSmsInformationElement* cloneInformationElement = CSmsInformationElement::NewL(informationElement.Identifier(),informationElement.Data());
+ CleanupStack::PushL(cloneInformationElement);
+ TBool willFit = SmsPDU().UserData().ControlInformationElementWillFitL(cloneInformationElement);
+ CleanupStack::PopAndDestroy(cloneInformationElement);
+
+ if (willFit)
+ {
+ SmsPDU().UserData().UpdateInformationElementArrayL(informationElement.Identifier(),informationElement.Data());
+ }
+ else
+ {
+ ResetWorkingPDUL();
+ return EFalse;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ EncodingTPSRRFromSchemesIntoSinglePDUL();
+
+ TInt maxBodyLength=SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
+ CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,SmsPDU().Alphabet(),BinaryData());
+ CSmsEMSBufferSegmenter* segmenter=CSmsEMSBufferSegmenter::NewLC(*converter,*iBuffer, maxBodyLength);
+
+ //
+ // Find the best alternative encoding for the current segment. This will be
+ // set at the beginning of each PDU using the list of encoders.
+ //
+ TSmsEncoding encodingToUse = ESmsEncodingNone;
+
+ TRAP_IGNORE(encodingToUse= segmenter->FindBestAlternativeEncodingL(iAdditionalInfo->Alternative7bitEncoding(),
+ maxBodyLength));
+ SmsPDU().SetNationalLanguageEncodingL(encodingToUse);
+
+ if(!AddEMSInformationElementsToSingleSegmentMessageL(*segmenter, encodingToUse))
+ {
+ aSmsArray.Reset();
+ CleanupStack::PopAndDestroy(2, converter);
+ return EFalse;
+ }
+
+ if(segmenter->MoreL())
+ {
+ TInt size = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
+ // Defensive code to prevent SegmentNextL being called with size of zero
+ if (size == 0)
+ {
+ CleanupStack::PopAndDestroy(2, converter);
+ aSmsArray.Reset();
+ return EFalse;
+ }
+ HBufC8* buf=HBufC8::NewMaxLC(maxBodyLength);
+ TPtr8 ptr(buf->Des());
+ segmenter->SegmentNextL(ptr, size, aUnconvertedChars, aDowngradedChars, encodingToUse);
+ SmsPDU().UserData().AppendBodyL(ptr);
+ CleanupStack::PopAndDestroy(buf);
+ }
+ CorrectFormattingInSinglePDUL();
+
+ if (segmenter->MoreL())
+ {
+ CleanupStack::PopAndDestroy(2, converter);
+ aSmsArray.Reset();
+ return EFalse;
+ }
+ CleanupStack::PopAndDestroy(2, converter);
+
+ aFreeUDUnitsInLastPDU = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
+
+ //
+ // Encode the PDU...
+ //
+ TGsmSms gsmSms;
+
+ TEncodeParams encodeParams;
+ encodeParams.iTimeStamp = &Time();
+
+ TTimeIntervalSeconds interval = UTCOffset();
+ encodeParams.iTimeIntervalInSeconds = &interval;
+
+ SmsPDU().EncodeMessagePDUL(gsmSms, &encodeParams);
+ aSmsArray.AppendL(gsmSms);
+
+ return ETrue;
+ } // CSmsMessage::EncodeIntoSinglePDUL
+
+
+/**
+ * Attempts to encode into the single PDU
+ * The Text and the EMS objects are layed out with respect to start position locations and encoded into the correct Tsms object.
+ * Ensure this function is called before EncodeMessagePDUsL to properly process single PDU messages
+ *
+ * @return KErrUnderflow if the Ems objects are not in Start position order.
+ * @param aSmsArray returned array of newly created TSms objects containing the encoded message
+ *
+ * @capability None
+ */
+EXPORT_C TBool CSmsMessage::EncodeIntoSinglePDUL(CArrayFix<TGsmSms>& aSmsArray)
+ {
+ LOGGSMU1("CSmsMessage::EncodeIntoSinglePDUL()");
+
+ TInt unconvertedChars, downgradedChars, freeUDUnitsInLastPDU;
+
+ return EncodeIntoSinglePDUL(aSmsArray, unconvertedChars,
+ downgradedChars, freeUDUnitsInLastPDU);
+ } // CSmsMessage::EncodeIntoSinglePDUL
+
+
+void CSmsMessage::EncodingTPSRRFromSchemesIntoSinglePDUL()
+ {
+ TInt smscIndex(0);
+ TBool smscPresent(EFalse);
+
+ CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = iAdditionalInfo->GetStatusReportScheme();
+ if(scheme.Id() == EControlParametersScheme)
+ {
+ if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
+ {
+ smscPresent=ETrue;
+ }
+ if(smscPresent)
+ {
+ TUint8 octet(0);
+
+ CSmsSMSCCtrlParameterOperations& ieOp = (CSmsSMSCCtrlParameterOperations&)GetOperationsForIEL(CSmsInformationElement::ESmsIEISMSCControlParameters);
+
+ if (ieOp.GetStatusReport(0, octet) == KErrNone)
+ {
+ if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
+ {
+ SmsPDU().UserData().InformationElement(smscIndex).Data()[0] = octet;
+ if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
+ {
+ ((CSmsSubmit&)SmsPDU()).SetStatusReportRequest(ETrue);
+ }
+ else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
+ {
+ ((CSmsDeliver&)SmsPDU()).SetStatusReportIndication(ETrue);
+ }
+ }
+ else
+ {
+ User::Leave(KErrCorrupt);
+ }
+ }
+ }
+ else
+ {
+ User::Leave(KErrNotFound);
+ }
+ }
+ else if(scheme.Id() == ETPSRRScheme)
+ {
+ TSmsFirstOctet smsReportRequest;
+ CSmsTPSRROperations& nonIEOp = (CSmsTPSRROperations&)GetOperationsForNonIEL(ESmsTPSRRParameter);
+ smsReportRequest = nonIEOp.GetStatusReport(0);
+
+ if(smsReportRequest>=0)
+ {
+ if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
+ {
+ ((CSmsSubmit&)SmsPDU()).SetStatusReportRequest(smsReportRequest);
+ }
+ else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
+ {
+ ((CSmsDeliver&)SmsPDU()).SetStatusReportIndication(smsReportRequest);
+ }
+ }
+ }
+ } // CSmsMessage::EncodingTPSRRFromSchemesIntoSinglePDUL
+
+
+/**
+ * Decode CSmsMessage
+ *
+ * @param aUserData Object containing the EMS objects.
+ * @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
+ * of the UserData.
+ */
+void CSmsMessage::DecodeBufferL(CArrayPtr<CSmsPDU>& aSmsPDUArray,
+ CSmsBufferBase& aBuffer)
+ {
+ LOGGSMU1("CSmsMessage::DecodeBufferL()");
+
+ iInformationElementArray->ResetAndDestroy();
+
+ TSmsStatusReportScheme schemeId = FindSchemeL(aSmsPDUArray);
+
+ TInt emailLen(0);
+ for (TInt i=0; i<aSmsPDUArray.Count(); i++)
+ {
+ CSmsUserData& usrData = (aSmsPDUArray)[i]->UserData();
+ InstallControlInformationElementsL(usrData, i);
+ InstallEmsInformationElementsL(usrData, aBuffer.Length());
+ // Possible refactoring opportunity:
+ // This would be a good place to add a method which provides processing for control information
+ // elements which contain values specific to the pdu (as opposed to being constant in every PDU.
+ InstallEmailHeaderInformationElementL(usrData,emailLen);
+ if(schemeId == ETPSRRScheme)
+ {
+ InstallTPSRRInformationL(aSmsPDUArray, i);
+ }
+
+ CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,aSmsPDUArray[i]->Alphabet(),BinaryData());
+ TSmsBufferReassembler reassembler(*converter,aBuffer);
+ TSmsEncoding encodingUsedInSegment = aSmsPDUArray[i]->NationalLanguageEncoding();
+
+ reassembler.ReassembleNextL(usrData.Body(),
+ encodingUsedInSegment,
+ i==(aSmsPDUArray.Count()-1));
+
+ CleanupStack::PopAndDestroy(converter);
+ MergeAlternative7bitEncoding(encodingUsedInSegment);
+ }
+
+ // Possible refactoring opportunity:
+ // This would be a good place to add a method which provides processing for control information
+ // elements which contain values specific to the pdu (as opposed to being constant in every PDU.
+ if(emailLen>0)
+ {
+ if(emailLen>255)
+ User::Leave(KErrTooBig);
+ TBuf8<1> data;
+ data.SetLength(1);
+ data[0]=static_cast<TUint8>(emailLen);
+ TInt emailIndex;
+ if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEIRFC822EmailHeader,emailIndex))
+ SmsPDU().UserData().InformationElement(emailIndex).Data()[0]=static_cast<TInt8>(emailLen);
+ else
+ SmsPDU().UserData().AddInformationElementL(CSmsInformationElement::ESmsIEIRFC822EmailHeader,data);
+ }
+ UpdateUserPromptAndODIElementsStartPosition();
+ } // CSmsMessage::DecodeBufferL
+
+/**
+ * It decodes only raw text data.
+ *
+ * @param aSmsPDUArray Object containing PDUs.
+ * @param aBuffer where the decoded data will be stored.
+ *
+ */
+void CSmsMessage::DecodeOnlyTextL(CArrayPtr<CSmsPDU>& aSmsPDUArray,
+ CSmsBufferBase& aBuffer)
+ {
+ LOGGSMU1("CSmsMessage::DecodeOnlyTextL()");
+
+ for (TInt i=0; i<aSmsPDUArray.Count(); i++)
+ {
+ CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,aSmsPDUArray[i]->Alphabet(),BinaryData());
+ TSmsBufferReassembler reassembler(*converter,aBuffer);
+ TSmsEncoding encodingUsedInSegment = aSmsPDUArray[i]->NationalLanguageEncoding();
+
+ reassembler.ReassembleNextL(aSmsPDUArray[i]->UserData().Body(),
+ encodingUsedInSegment,
+ i==(aSmsPDUArray.Count()-1));
+
+ CleanupStack::PopAndDestroy(converter);
+ MergeAlternative7bitEncoding(encodingUsedInSegment);
+ }
+ } // CSmsMessage::DecodeBufferL
+
+/**
+ * It adds the incomplete message info in additional attribute field.
+ *
+ * @param aStartPDU starting PDU index of incomplete message.
+ * @param aEndPDU end PDU index of incomplete message.
+ * @param aLastPartialCompleteMsg boolean value indicating whether
+ this message is the last incomplete message sent to client.
+ */
+void CSmsMessage::AddIncompleteMessageInfoL(TInt aStartPDU, TInt aEndPDU, TBool aLastPartialCompleteMsg)
+ {
+ LOGGSMU1("CSmsMessage::AddIncompleteMessageInfoL()");
+
+ CIncompleteClass0MessageInfo& incompleteClass0MsgInfo = (CIncompleteClass0MessageInfo&) iAdditionalInfo->GetNonIEOperationL(ESmsIncompleteClass0MessageParameter);
+ incompleteClass0MsgInfo.SetVersion(CIncompleteClass0MessageInfo::ESmsIncompleteClass0MessageV0);
+ incompleteClass0MsgInfo.SetIncompleteMessageInfoL(aStartPDU, aEndPDU, aLastPartialCompleteMsg);
+ }
+
+/**
+ * This method copies control information elements from the user data (passed as an
+ * input argument) into either the CSmsMessage's user data (working pdu) OR one of the
+ * collection of control information elements (sorted by category) which is contained
+ * in CSmsMessage::iAdditionalInfo.
+ *
+ * @param aUserData
+ * The user data which is currently being processed, and whose elements may be copied
+ * into the appropriate collection belonging to the CSmsMessage.
+ * @leave
+ * KErrArgument if an information element's type is unknown
+ *
+ * @internalComponent
+ */
+void CSmsMessage::InstallControlInformationElementsL(CSmsUserData& aUserData, TInt aSegmentSequenceNum)
+ {
+ // Installs all the information elements within the subsequent PDUs.
+ LOGGSMU1("CSmsMessage::InstallControlInformationElements()");
+
+ CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = iAdditionalInfo->GetStatusReportScheme();
+
+ for (TInt z=0; z<aUserData.NumInformationElements(); z++)
+ {
+ const CSmsInformationElement& ie = aUserData.InformationElement(z);
+
+ TSmsInformationElementCategories::TInformationElementCategory category;
+
+ if (TSmsInformationElementCategories::GetCategoryDefinition(ie.Identifier(), category))
+ {
+ switch (category)
+ {
+ case TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUMultipleInstancesPerPDU: // e.g. Special SMS Message Indication
+ LOGGSMU2("CSmsMessage::InstallControlInformationElements \
+ ECtrlMandatoryInEveryPDUMultipleInstancesPerPDU id = %d", ie.Identifier());
+
+ if (ie.Identifier()== CSmsInformationElement::ESmsIEISpecialSMSMessageIndication)
+ {
+ TBool found = EFalse;
+ CArrayFixFlat<TInt>* indices = new(ELeave) CArrayFixFlat<TInt>(4);
+ CleanupStack::PushL(indices);
+ SmsPDU().UserData().InformationElementIndicesL(ie.Identifier(), *indices);
+
+ TInt count = indices->Count();
+ for (TInt i=0; ((i<count) && (found==EFalse)); i++)
+ {
+ TUint index = indices->operator[](i);
+ CSmsInformationElement& ieAlreadyInWorkingPDU = SmsPDU().UserData().InformationElement(index);
+
+ if (ieAlreadyInWorkingPDU.Data()[0] == ie.Data()[0])
+ {
+ ieAlreadyInWorkingPDU.Data()[1] = ie.Data()[1];
+ found = ETrue;
+ break;
+ }
+ }
+ CleanupStack::PopAndDestroy(indices);
+
+ if (found == EFalse)
+ {
+ SmsPDU().UserData().UpdateInformationElementArrayL(ie.Identifier(),ie.Data());
+ }
+ }
+ else
+ {
+ // Unknown category.
+ LOGGSMU3("CSmsMessage::InstallControlInformationElementsL category = %d, id = %d", category, ie.Identifier());
+ User::Leave(KErrArgument);
+ }
+ break;
+ case TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly:
+ case TSmsInformationElementCategories::ECtrlSingleInstanceOnly:
+ {
+ LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryIn1stPDUOnly "
+ "ECtrlSingleInstanceOnly, id = %d", ie.Identifier());
+
+ TUint index = 0;
+ if (iAdditionalInfo->Find1stInstanceOfControlInformationElement(ie.Identifier(), index))
+ {
+ iAdditionalInfo->DeleteControlInformationElement(category, index); // might want to pass the
+ // id in as an additional check
+ // this should be an exception case
+ CSmsInformationElement* newInformationElement = CSmsInformationElement::NewL(ie.Identifier(),ie.Data());
+
+ CleanupStack::PushL(newInformationElement);
+ iAdditionalInfo->AddControlInformationElementL(category, newInformationElement);
+ CleanupStack::Pop(newInformationElement);
+ }
+ else
+ {
+ CSmsInformationElement* cloneInformationElement = CSmsInformationElement::NewL(ie.Identifier(),ie.Data());
+ CleanupStack::PushL(cloneInformationElement);
+ iAdditionalInfo->AddControlInformationElementL(category, cloneInformationElement);
+ CleanupStack::Pop(cloneInformationElement);
+ }
+ break;
+ }
+ case TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUAndWithIdenticalValues:
+ {
+ LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryInEveryPDUAndWithIdenticalValues "
+ "ECtrlSingleInstanceOnly, id = %d", ie.Identifier());
+ TInt index = 0;
+ if (SmsPDU().UserData().InformationElementIndex(ie.Identifier(),index))
+ {
+ CSmsInformationElement* newInformationElement = CSmsInformationElement::NewL(ie.Identifier(),ie.Data());
+
+ CleanupStack::PushL(newInformationElement);
+ CSmsInformationElement*& indexedPDU = SmsPDU().UserData().InformationElementPtr(index);
+ CSmsInformationElement* oldInformationElement = indexedPDU;
+ SmsPDU().UserData().InformationElementPtr(index) = newInformationElement;
+ // In next loop, oldInformationElement will point to the newly created information element. So double free is no case.
+ // coverity[double_free]
+ delete oldInformationElement;
+ CleanupStack::Pop(newInformationElement);
+ }
+ else
+ {
+ SmsPDU().UserData().UpdateInformationElementArrayL(ie.Identifier(),ie.Data());
+ }
+ break;
+ }
+
+ case TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed:
+ {
+ LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryInEveryPDUAndWithIdenticalValues "
+ "ECtrlSingleInstanceOnly, id = %d", ie.Identifier() );
+
+ CSmsInformationElement* cloneInformationElement = CSmsInformationElement::NewL( ie.Identifier(),ie.Data() );
+ CleanupStack::PushL(cloneInformationElement);
+ iAdditionalInfo->AddControlInformationElementL( TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed, cloneInformationElement);
+ CleanupStack::Pop(cloneInformationElement);
+ break;
+ }
+ case TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUButWithValueSpecificToPDU:
+ LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryInEveryPDUButWithValueSpecificToPDU "
+ "ECtrlSingleInstanceOnly, id = %d", ie.Identifier() );
+
+ if (ie.Identifier() == CSmsInformationElement::ESmsIEISMSCControlParameters)
+ {
+ if(scheme.Id() == EControlParametersScheme)
+ {
+ CSmsMessageAdditionalAttributes::CControlParametersScheme& ctrlParamScheme = (CSmsMessageAdditionalAttributes::CControlParametersScheme&)scheme;
+ ctrlParamScheme.iDefaultStatusReport = 0x00;
+
+ const TUint8* octet(0);
+ octet = ie.Data().Ptr();
+ if(*octet)
+ {
+ CSmsMessageAdditionalAttributes::CControlParametersScheme::TSmsSMSCCtrlParameterStatus smscCtrlParameterStatus;
+ smscCtrlParameterStatus.iSegmentSequenceNum = aSegmentSequenceNum;
+ smscCtrlParameterStatus.iSelectiveStatus = *octet;
+ (ctrlParamScheme.iControlParametersStatusReport).AppendL(smscCtrlParameterStatus);
+ }
+ ctrlParamScheme.iNumOfPDUs++;
+ }
+ }
+
+ // e.g Email Header / Concatenation Elements.
+ // Consider whether EMail Header should be ported here.
+ // or left as is.
+ break;
+ case TSmsInformationElementCategories::EEmsInformationElement:
+ LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryInEveryPDUButWithValueSpecificToPDU "
+ "ECtrlSingleInstanceOnly, id = %d", ie.Identifier() );
+ // Will be handled in the method InstallEmsInformationElements, nothing to do here
+ break;
+ default:
+ LOGGSMU3("CSmsMessage::InstallControlInformationElementsToMultiSegmentMessageL, default switch, category = %d, id= %d", category, ie.Identifier() );
+ break;
+ }
+ }
+ }
+ } // CSmsMessage::InstallControlInformationElementsL
+
+
+/**
+ * Extracts all the EMS information objects out of the given UserData into the CSmsMessage IEArray.
+ *
+ * @param aUserData Object containing the EMS objects.
+ * @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
+ * of the UserData.
+ */
+void CSmsMessage::InstallEmsInformationElementsL(CSmsUserData& aUserData, TInt aCharsAlreadyAdded)
+ {
+ // Installs all the information elements within the subsequent PDUs.
+ LOGGSMU1("CSmsMessage::InstallEmsInformationElements()");
+
+ CSmsInformationElement::TSmsInformationElementIdentifier id;
+ CEmsInformationElement* newIE =NULL;
+
+ for (TInt z=0; z<aUserData.NumInformationElements(); z++)
+ {
+ const CSmsInformationElement& ie = aUserData.InformationElement(z);
+
+ // is the ie an EMS information Element;
+ id = ie.Identifier();
+ if (CEmsFactory::Supported(id))
+ {
+ newIE=NULL;
+ TRAPD(ret,newIE = CEmsFactory::CreateReceivedEmsIEL(ie,aCharsAlreadyAdded));
+ if(newIE != NULL)
+ {
+ if(ret == KErrNone)
+ {
+ ret=AddReceivedEmsInformationElement(newIE);
+ if(ret==KErrNone) // Remove the Information Element from the User Data.
+ aUserData.RemoveInformationElement(z--);
+ else
+ // newIE is made NULL in first place and then a new IE is created. so double free is no case
+ // coverity[double_free]
+ delete newIE;
+ }
+ else
+ delete newIE;
+ }
+ }
+ }
+ } // CSmsMessage::InstallEmsInformationElementsL
+
+
+/**
+ * Extracts all the EMS information objects out of the given Command into the CSmsMessage IEArray.
+ *
+ * @param aCommand Object containing the EMS objects.
+ * @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
+ * of the UserData.
+ */
+void CSmsMessage::InstallEmsInformationElementsL(CSmsCommand& aCommand, TInt aCharsAlreadyAdded)
+ {
+ // Ignore in code coverage - not used in SMS stack and not exported
+ // but cannot be removed as impacts public header.
+ BULLSEYE_OFF
+ // Installs all the information elements within the subsequent PDUs.
+ LOGGSMU1("CSmsMessage::InstallEmsInformationElements()");
+
+ CSmsInformationElement::TSmsInformationElementIdentifier id;
+ CEmsInformationElement* newIE=NULL;
+
+ for (TInt z=0; z<aCommand.NumInformationElements(); z++)
+ {
+ const CSmsInformationElement& ie = aCommand.InformationElement(z);
+ // is the ie an EMS information Element;
+ id = ie.Identifier();
+ if (CEmsFactory::Supported(id))
+ {
+ newIE=NULL;
+ TRAPD(ret,newIE = CEmsFactory::CreateReceivedEmsIEL(ie,aCharsAlreadyAdded));
+ if(newIE != NULL )
+ {
+ if(ret == KErrNone)
+ {
+ ret=AddReceivedEmsInformationElement(newIE);
+ if(ret==KErrNone) // Remove the Information Element from the User Data.
+ aCommand.RemoveInformationElement(z--);
+ else
+ // newIE is made NULL in first place and then a new IE is created. so double free is no case.
+ // coverity[double_free]
+ delete newIE;
+ }
+ else
+ delete newIE;
+ }
+ }
+ }
+ BULLSEYE_RESTORE
+ }
+
+TSmsStatusReportScheme CSmsMessage::FindSchemeL(const CArrayPtr<CSmsPDU>& aSmsPDUArray)
+ {
+ TInt smscIndex(0);
+
+ if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
+ {
+ iAdditionalInfo->SetStatusReportSchemeL(EControlParametersScheme);
+ return EControlParametersScheme;
+ }
+
+ TSmsFirstOctet oldTpsrr;
+ TSmsFirstOctet tpsrr;
+ CSmsSubmit* smsSubmit;
+ CSmsDeliver* smsDeliver;
+
+ if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
+ {
+ smsSubmit = reinterpret_cast<CSmsSubmit*>((aSmsPDUArray)[0]);
+ oldTpsrr = smsSubmit->StatusReportRequest();
+ }
+ else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
+ {
+ smsDeliver = reinterpret_cast<CSmsDeliver*>((aSmsPDUArray)[0]);
+ oldTpsrr = smsDeliver->StatusReportIndication();
+ }
+
+ for (TInt ii=1; ii<aSmsPDUArray.Count(); ii++)
+ {
+ if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
+ {
+ smsSubmit = reinterpret_cast<CSmsSubmit*>((aSmsPDUArray)[ii]);
+ tpsrr = smsSubmit->StatusReportRequest();
+ }
+ else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
+ {
+ smsDeliver = reinterpret_cast<CSmsDeliver*>((aSmsPDUArray)[ii]);
+ tpsrr = smsDeliver->StatusReportIndication();
+ }
+ if(tpsrr != oldTpsrr)
+ {
+ iAdditionalInfo->SetStatusReportSchemeL(ETPSRRScheme);
+ return ETPSRRScheme;
+ }
+ }
+
+ iAdditionalInfo->SetStatusReportSchemeL(EDefaultScheme);
+
+ return EDefaultScheme;
+ } // CSmsMessage::FindSchemeL
+
+
+void CSmsMessage::InstallTPSRRInformationL(const CArrayPtr<CSmsPDU>& aSmsPDUArray, TInt aSegmentSequenceNum)
+ {
+ CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = iAdditionalInfo->GetStatusReportScheme();
+ CSmsMessageAdditionalAttributes::CTPSRRScheme& tpsrrScheme = (CSmsMessageAdditionalAttributes::CTPSRRScheme&)scheme;
+
+ tpsrrScheme.iDefaultStatusReport = TSmsFirstOctet::ESmsStatusReportNotRequested;
+ tpsrrScheme.iNumOfPDUs++;
+
+ TSmsFirstOctet tpsrr;
+
+ if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
+ {
+ CSmsSubmit* smsSubmit = reinterpret_cast<CSmsSubmit*>((aSmsPDUArray)[aSegmentSequenceNum]);
+ tpsrr = smsSubmit->StatusReportRequest();
+ }
+ else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
+ {
+ CSmsDeliver* smsDeliver = reinterpret_cast<CSmsDeliver*>((aSmsPDUArray)[aSegmentSequenceNum]);
+ tpsrr = smsDeliver->StatusReportIndication();
+ }
+
+ if(tpsrr)
+ {
+ CSmsMessageAdditionalAttributes::CTPSRRScheme::TSmsTPSRRStatus tpsrrStatus;
+
+ tpsrrStatus.iSegmentSequenceNum = aSegmentSequenceNum;
+ tpsrrStatus.iTPSRRStatus = TSmsFirstOctet::ESmsStatusReportRequested;
+ tpsrrScheme.iTPSRRStatusReport.AppendL(tpsrrStatus);
+ }
+ } // CSmsMessage::InstallTPSRRInformationL
+
+
+/**
+ * Adds EMS IE to a CSmsMessage
+ *
+ * @param aEmsIE EMS object to be added.
+ *
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::AddEMSInformationElementL(const CEmsInformationElement& aEmsIE)
+ {
+ LOGGSMU1("CSmsMessage::AddEMSInformationElementL()");
+
+ if(aEmsIE.StartPosition() > (TUint)iBuffer->Length())
+ {
+ User::Leave(KErrOverflow);
+ }
+
+ if(CSmsInformationElement::ESmsEnhancedTextFormatting == aEmsIE.Identifier() && aEmsIE.Length() ==0)
+ {
+ User::Leave(KErrUnderflow);
+ }
+
+ if(CSmsInformationElement::ESmsEnhancedUserPromptIndicator == aEmsIE.Identifier())
+ {
+ AddEmsUserPromptL(static_cast<const CEmsUserPrompt&>(aEmsIE));
+ }
+ else if(CSmsInformationElement::ESmsEnhancedODI == aEmsIE.Identifier())
+ {
+ AddEmsObjectDistributionL(static_cast<const CEmsObjectDistribution&>(aEmsIE));
+ }
+ else
+ {
+ TInt count=iInformationElementArray->Count();
+ TInt currNo=0;
+ const CEmsInformationElement* emsIE=NULL;
+
+ while(currNo < count)
+ {
+ emsIE=(*iInformationElementArray)[currNo];
+ if(emsIE->StartPosition() == aEmsIE.StartPosition() && (CSmsInformationElement::ESmsEnhancedUserPromptIndicator == emsIE->Identifier() || CSmsInformationElement::ESmsEnhancedODI == emsIE->Identifier()))
+ User::Leave(KErrArgument);
+ else if(emsIE->StartPosition() > aEmsIE.StartPosition())
+ break;
+ currNo++;
+ }
+ User::LeaveIfError(iInformationElementArray->Insert(aEmsIE.DuplicateL(),currNo));
+ }
+ } // CSmsMessage::AddEMSInformationElementL
+
+
+TBool CSmsMessage::CanBeRemoved(const CEmsInformationElement& aIE, const TUint aIEIndex)
+ {
+ LOGGSMU1("CSmsMessage::CanBeRemoved()");
+
+ TBool ret=ETrue;
+ if(CSmsInformationElement::ESmsEnhancedODI == aIE.Identifier())
+ return ret;
+
+ TUint ieStartPosition=aIE.StartPosition();
+ TUint count=iInformationElementArray->Count();
+ CEmsInformationElement* ie=NULL;
+
+ // is there a UserPrompt/ODI at the same position
+ for (TUint i=0; i < count && ret; ++i)
+ {
+ ie = (*iInformationElementArray)[i];
+ // Do not allow removal if start position matches a user prompt and it is not the user prompt itself being removed
+ if (ie->StartPosition() == ieStartPosition && ie->Identifier() == CSmsInformationElement::ESmsEnhancedUserPromptIndicator && aIE.Identifier() != CSmsInformationElement::ESmsEnhancedUserPromptIndicator)
+ ret=EFalse;
+ if (ie->Identifier() == CSmsInformationElement::ESmsEnhancedODI)
+ {
+ // don't allow removal of IE if position inside object count of ODI
+ if ((static_cast<CEmsObjectDistribution*>(ie)->ObjectCount()+i) >= aIEIndex || static_cast<CEmsObjectDistribution*>(ie)->ObjectCount() == 0)
+ ret=EFalse;
+ }
+ }
+
+ LOGGSMU2("CSmsMessage::CanBeRemoved() returns %d", ret);
+
+ return ret;
+ } // CSmsMessage::CanBeRemoved
+
+
+/**
+ * Adds EMS IE to a CSmsMessage
+ *
+ * @param aEmsIE EMS object to be added.
+ */
+void CSmsMessage::AddEmsUserPromptL(const CEmsUserPrompt& aUserPromptIE)
+ {
+ LOGGSMU1("CSmsMessage::AddEmsUserPromptL()");
+
+ if(aUserPromptIE.ObjectCount() == 0 )User::Leave(KErrArgument);
+
+ TUint count=iInformationElementArray->Count();
+ TUint userPromptStartPosition=aUserPromptIE.StartPosition();
+
+ TSmsId id=aUserPromptIE.Identifier();
+ TBool allSameType=ETrue;
+ TUint countOnTheSamePos=0;
+ TUint firstIndex=0;
+
+ // collect all IEs on the same startPosition as the new User Prompt
+ CEmsInformationElement* ie=NULL;
+
+ for (TUint i=0; i < count ; i++)
+ {
+ ie = (*iInformationElementArray)[i];
+ if (ie->StartPosition() == userPromptStartPosition)
+ {
+ if(countOnTheSamePos==0)
+ {
+ firstIndex=i;
+ id = ie->Identifier();
+ }
+ else
+ {
+ if(allSameType && id != ie->Identifier())allSameType=EFalse;
+ else id = ie->Identifier();
+ }
+ ++countOnTheSamePos;
+ }
+ }
+
+ if(countOnTheSamePos != aUserPromptIE.ObjectCount())
+ User::Leave(KErrArgument);
+
+
+ if( countOnTheSamePos == 1)
+ {
+ switch(id)
+ {
+ case CEmsInformationElement::ESmsEnhancedPredefinedAnimation:
+ case CEmsInformationElement::ESmsEnhancedLargeAnimation :
+ case CEmsInformationElement::ESmsEnhancedSmallAnimation :
+ case CEmsInformationElement::ESmsEnhancedUserDefinedSound:
+ case CEmsInformationElement::ESmsEnhancedLargePicture:
+ case CEmsInformationElement::ESmsEnhancedSmallPicture:
+ case CEmsInformationElement::ESmsEnhancedVariablePicture:
+ User::LeaveIfError(iInformationElementArray->Insert(aUserPromptIE.DuplicateL(),firstIndex));
+ break;
+ default:
+ User::Leave(KErrCorrupt);
+ break;
+ }
+ return;
+ }
+
+ // stitching - more than one object
+ if(allSameType && (id == CEmsInformationElement::ESmsEnhancedUserDefinedSound || id == CEmsInformationElement::ESmsEnhancedLargePicture || id == CEmsInformationElement::ESmsEnhancedSmallPicture || id == CEmsInformationElement::ESmsEnhancedVariablePicture))
+ {
+ User::LeaveIfError(iInformationElementArray->Insert(aUserPromptIE.DuplicateL(),firstIndex));
+ return;
+ }
+
+ // not of the same type or not supported IE types
+ User::Leave(KErrCorrupt);
+ } // CSmsMessage::AddEmsUserPromptL
+
+
+/**
+ * Adds EMS IE to a CSmsMessage
+ *
+ * @param aEmsIE EMS object to be added.
+ */
+void CSmsMessage::AddEmsObjectDistributionL(const CEmsObjectDistribution& aObjectDistributionIE)
+ {
+ LOGGSMU1("CSmsMessage::AddEmsObjectDistributionL()");
+
+ TUint count=iInformationElementArray->Count();
+ TUint objectDistributionStartPosition=aObjectDistributionIE.StartPosition();
+
+ TBool firstIndexFound=EFalse;
+ TUint firstIndex=0;
+ TUint countOnSameOrSubsequentPos=0;
+
+ // collect any IEs on the same or greater startPosition as the new Object Distribution Indicator
+ CEmsInformationElement* ie=NULL;
+
+ for (TUint i=0; i < count; i++)
+ {
+ ie = (*iInformationElementArray)[i];
+ if (ie->StartPosition() >= objectDistributionStartPosition)
+ {
+ // Only set index if at least one IE found at desired start position
+ if (!firstIndexFound)
+ {
+ firstIndex=i;
+ firstIndexFound=ETrue;
+ }
+ ++countOnSameOrSubsequentPos;
+ }
+ }
+ // check number of IEs present for desired ObjectCount
+ if(countOnSameOrSubsequentPos < aObjectDistributionIE.ObjectCount())
+ User::Leave(KErrArgument);
+
+ if (firstIndexFound)
+ {
+ User::LeaveIfError(iInformationElementArray->Insert(aObjectDistributionIE.DuplicateL(),firstIndex));
+ return;
+ }
+
+ // no valid IE for ODI to apply to
+ User::Leave(KErrCorrupt);
+ } // CSmsMessage::AddEmsObjectDistributionL
+
+
+/**
+ * Removes first EMS IE that matches the criteria from the CSmsMessage
+ *
+ * @param aStartPosition of a EMS object to be removed.
+ * @param aEmsId type of a EMS object to be removed
+ * @return pointer EMS information element
+ * @capability
+ * @capability None
+ */
+EXPORT_C CEmsInformationElement* CSmsMessage::RemoveEMSInformationElementL(const TUint aStartPosition,const TSmsId aEmsId)
+ {
+ LOGGSMU1("CSmsMessage::RemoveEMSInformationElementL()");
+
+ CEmsInformationElement* emsIE=NULL;
+ CEmsInformationElement* ie=NULL;
+
+ TUint count=iInformationElementArray->Count();
+
+ for (TInt i=--count; i >=0 ; --i)
+ {
+ ie = (*iInformationElementArray)[i];
+ if (ie->StartPosition() == aStartPosition && ie->Identifier() == aEmsId)
+ {
+ if(CanBeRemoved(*ie, i))
+ {
+ iInformationElementArray->Remove(i);
+ emsIE=ie;
+ }
+ else
+ emsIE=NULL;
+ break;
+ }
+
+ }
+ return emsIE;
+ } // CSmsMessage::RemoveEMSInformationElementL
+
+
+/**
+ * Removes all EMS IEs that matches the criteria from the CSmsMessage
+ *
+ * @param aStartPosition of a EMS object to be removed.
+ * @param aEmsId type of a EMS object to be removed
+ * @return pointer to array of EMS IE
+ *
+ * @capability None
+ */
+EXPORT_C RPointerArray<CEmsInformationElement>* CSmsMessage::RemoveEMSInformationElementsL(const TUint aStartPosition,const TSmsId aEmsId)
+ {
+ LOGGSMU1("CSmsMessage::RemoveEMSInformationElementsL()");
+
+ CEmsInformationElement* ie=NULL;
+ RPointerArray<CEmsInformationElement>* selectedIEs = NULL;
+ TUint count=iInformationElementArray->Count();
+
+ for (TInt i=--count; i >= 0 ; --i)
+ {
+ ie = (*iInformationElementArray)[i];
+ if (ie->StartPosition() == aStartPosition && ie->Identifier() == aEmsId)
+ {
+ if(CanBeRemoved(*ie, i))
+ {
+ if(selectedIEs == NULL)selectedIEs=new (ELeave) RPointerArray<CEmsInformationElement>(8);
+ iInformationElementArray->Remove(i);
+ selectedIEs->Append(ie);
+ }
+ }
+
+ }
+ return selectedIEs;
+ } // CSmsMessage::RemoveEMSInformationElementsL
+
+/**
+ * Resets EMS IE from a CSmsMessage
+ *
+ *
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::ResetEMSL()
+ {
+ LOGGSMU1("CSmsMessage::ResetEMSL()");
+
+ iInformationElementArray->ResetAndDestroy();
+ } // CSmsMessage::ResetEMSL
+
+/**
+ * Removes EMS IE from a CSmsMessage
+ *
+ * @return CArrayPtrFlat<const CEmsInformationElement>& of internal EMS array
+ *
+ * @capability None
+ */
+EXPORT_C const RPointerArray<const CEmsInformationElement>& CSmsMessage::GetEMSInformationElementsL()const
+ {
+ LOGGSMU1("CSmsMessage::GetEMSInformationElementsL()");
+
+ return (const RPointerArray<const CEmsInformationElement>&)(*iInformationElementArray);
+ } // CSmsMessage::GetEMSInformationElementsL
+
+
+void CSmsMessage::UpdateUserPromptAndODIElementsStartPosition()
+ {
+ LOGGSMU1("CSmsMessage::UpdateUserPromptAndODIElementsStartPosition()");
+
+ TUint num=iInformationElementArray->Count();
+ TInt startPosition=-1;
+ CEmsInformationElement* ie = NULL;
+
+
+ // is the ie an EMS information Element;
+
+ for(TInt i=num-1;i >=0; --i)
+ {
+ ie = (*iInformationElementArray)[i];
+ if(ie->Identifier() == CSmsInformationElement::ESmsEnhancedUserPromptIndicator || ie->Identifier() == CSmsInformationElement::ESmsEnhancedODI)
+ {
+ if(startPosition >=0)
+ ie->SetStartPosition(startPosition);
+ else
+ iInformationElementArray->Remove(i);
+ }
+ else
+ startPosition=ie->StartPosition();
+
+ }
+ } // CSmsMessage::UpdateUserPromptAndODIElementsStartPosition
+
+
+TInt CSmsMessage::AddReceivedEmsInformationElement(CEmsInformationElement* aEmsIE)
+ {
+ LOGGSMU1("CSmsMessage::AddReceivedEmsInformationElement()");
+
+ TInt ret=KErrNone;
+ if(CSmsInformationElement::ESmsEnhancedUserPromptIndicator == aEmsIE->Identifier() || CSmsInformationElement::ESmsEnhancedODI == aEmsIE->Identifier())
+ ret=iInformationElementArray->Append(aEmsIE);
+ else
+ {
+ TInt count=iInformationElementArray->Count();
+ TInt currNo=0;
+ const CEmsInformationElement* emsIE=NULL;
+ while(currNo < count)
+ {
+ emsIE=(*iInformationElementArray)[currNo];
+ if(emsIE->StartPosition() > aEmsIE->StartPosition() && (CSmsInformationElement::ESmsEnhancedUserPromptIndicator != emsIE->Identifier() || CSmsInformationElement::ESmsEnhancedODI != emsIE->Identifier()))
+ break;
+ currNo++;
+ }
+ ret=iInformationElementArray->Insert(aEmsIE,currNo);
+ }
+ return ret;
+ } // CSmsMessage::AddReceivedEmsInformationElement
+
+
+/**
+ * Updates the slot information for the given message as described in the supplied buffer
+ *
+ * @param aDesc buffer, layout: byte 0 store id, byte 1..n PDU slot indexes
+ * @leave KErrArgument
+ *
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::UpdateSlotsL(TDesC8& aDesc)
+ {
+ LOGGSMU1("CSmsMessage::UpdateSlotsL()");
+
+ TGsmSmsSlotEntry newSlot;
+
+ switch (aDesc[0])
+ {
+ case CSmsMessage::ESmsSIMStorage:
+ {
+ newSlot.iStore = KETelIccSmsStore;
+ break;
+ }
+ case CSmsMessage::ESmsPhoneStorage:
+ {
+ newSlot.iStore = KETelMeSmsStore;
+ break;
+ }
+ case CSmsMessage::ESmsCombinedStorage:
+ {
+ newSlot.iStore = KETelCombinedSmsStore;
+ break;
+ }
+ default:
+ User::Leave(KErrArgument);
+ }
+
+ for (TInt index = 1; index < aDesc.Size(); index++)
+ {
+ newSlot.iIndex = aDesc[index]; // point to PDU indexes
+ iSlotArray.AppendL(newSlot);
+ }
+ } // CSmsMessage::UpdateSlotsL
+
+/**
+ * Copy EMS elements to dest CSmsMessage
+ * Uses CSmsMessage extended EMS API
+ * Creates new CEmsInformationElement instance(s) and passes ownership to the dest CSmsMessage
+ *
+ * @return aToMessage - Destination CSmsMessage
+ *
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::CopyEmsElementsL(CSmsMessage& aToMessage) const
+ {
+ LOGGSMU1("CSmsMessage::CopyEmsElementsL()");
+
+ // CSmsMessage extended EMS API method creates array of references to EMS elements in
+ // the source message
+ // Loop through the array copying each individual method using the CSmsMessage
+ // and CEmsInformationElement API's
+ CEmsInformationElement* dupl=NULL;
+ aToMessage.ResetEMSL();
+ for(TInt i = iInformationElementArray->Count()-1 ; i >=0; --i)
+ {
+ dupl = (*iInformationElementArray)[i]->DuplicateL();
+ CleanupStack::PushL(dupl);
+ aToMessage.AddEMSInformationElementL(*dupl);
+ CleanupStack::PopAndDestroy(dupl);
+ }
+ } // CSmsMessage::CopyEmsElementsL
+
+/**
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::AddSlotL(const TGsmSmsSlotEntry& aSlot)
+ {
+ LOGGSMU1("CSmsMessage::AddSlotL()");
+
+ TInt count = iSlotArray.Count();
+ TInt i(0);
+ TBool found(EFalse);
+ while(!found && i<count)
+ {
+ if(aSlot.iIndex == iSlotArray[i].iIndex)found=ETrue;
+ else ++i;
+ }
+ LOGGSMU3("CSmsMessage::AddSlotL current no in: %d, adds index %d", count,aSlot.iIndex );
+ LOGGSMU3("found %d at position %d",found,i);
+ iSlotArray.AppendL(aSlot);
+ } // CSmsMessage::AddSlotL
+
+/**
+ * @capability None
+ */
+EXPORT_C TBool CSmsMessage::MatchSlots(const CArrayFixFlat<TGsmSmsSlotEntry>& aSlotArray)
+ {
+ LOGGSMU1("CSmsMessage::MatchSlots()");
+
+ TBool match = EFalse;
+ TInt count = aSlotArray.Count();
+ if(iSlotArray.Count() == count)
+ {
+ TInt i = 0;
+ match = ETrue;
+ while(match && i < count)
+ {
+ const TGsmSmsSlotEntry& newSlot=aSlotArray[i];
+ const TGsmSmsSlotEntry& slot =iSlotArray[i];
+ if ( ( slot.iIndex != newSlot.iIndex ) || ( slot.iStore != newSlot.iStore ) )
+ match = EFalse;
+ i++;
+ }
+
+ }
+ return match;
+ } // CSmsMessage::MatchSlots
+
+/**
+ * c'tor
+ * @capability None
+ */
+EXPORT_C TGsmSmsSlotEntry::TGsmSmsSlotEntry()
+ {
+ } // TGsmSmsSlotEntry::TGsmSmsSlotEntry
+
+/**
+ * Internalize
+ *
+ * @param aStream For internalizing the data
+ */
+void TGsmSmsSlotEntry::InternalizeL(RReadStream& aStream)
+ {
+ aStream >> iStore;
+ iIndex=aStream.ReadInt32L();
+ } // TGsmSmsSlotEntry::InternalizeL
+
+/**
+ * Externalize
+ *
+ * @param aStream For Externalizing the data
+ */
+void TGsmSmsSlotEntry::ExternalizeL(RWriteStream& aStream) const
+ {
+ aStream << iStore;
+ aStream.WriteInt32L(iIndex);
+ } // TGsmSmsSlotEntry::ExternalizeL
+
+ /**
+ * Extracts all RFC 822 Email header information objects out of the given UserData into the CSmsMessage's iSmsEmailHeaderLength.
+ *
+ * @param aUserData Object containing the EmailHeader information element.
+ * @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
+ * of the UserData.
+ */
+void CSmsMessage::InstallEmailHeaderInformationElementL(CSmsUserData& aUserData,TInt& aHeaderLength)
+ {
+ // Installs all the information elements within the subsequent PDUs.
+ LOGGSMU1("CSmsMessage::InstallEmailHeaderInformationElementL()");
+
+ CSmsInformationElement::TSmsInformationElementIdentifier id;
+
+ for (TInt z=0; z<aUserData.NumInformationElements(); z++)
+ {
+ const CSmsInformationElement& ie = aUserData.InformationElement(z);
+ id = (CSmsInformationElement::TSmsInformationElementIdentifier)ie.Identifier();
+ if (id == CSmsInformationElement::ESmsIEIRFC822EmailHeader)
+ {
+ const TDesC8& des = ie.Data();
+ aHeaderLength+=des[0];
+ }
+ }
+ } // CSmsMessage::InstallEmailHeaderInformationElementL
+
+/**
+ * Extracts all RFC 822 Email header information objects out of the given UserData into the CSmsMessage's iSmsEmailHeaderLength.
+ *
+ * @param aCommand Object containing the EmailHeader information element.
+ * @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
+ * of the UserData.
+ */
+void CSmsMessage::InstallEmailHeaderInformationElementL(CSmsCommand& aCommand,TInt& aHeaderLength)
+ {
+ // Ignore in code coverage - not used in SMS stack and not exported
+ // but cannot be removed as impacts public header.
+ BULLSEYE_OFF
+ // Installs all the information elements within the subsequent PDUs.
+ LOGGSMU1("CSmsMessage::InstallEmailHeaderInformationElementL()");
+
+ CSmsInformationElement::TSmsInformationElementIdentifier id;
+
+ for (TInt z=0; z<aCommand.NumInformationElements(); z++)
+ {
+ const CSmsInformationElement& ie = aCommand.InformationElement(z);
+ id = (CSmsInformationElement::TSmsInformationElementIdentifier)ie.Identifier();
+ if (id == CSmsInformationElement::ESmsIEIRFC822EmailHeader)
+ {
+ const TDesC8& des = ie.Data();
+ aHeaderLength+=des[0];
+ }
+ }
+ BULLSEYE_RESTORE
+ }
+
+// E-mail header methods
+
+/**
+ * Adds a header to an email body
+ *
+ * @param aEMailBody The buffer to which the header gets appended
+ * @param aEmailHeader The buffer which holds RFC 822 e-mail header
+ * @publishedAll
+ * @released
+ *
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::AddEmailHeaderL(const TDesC& aEmailHeader, const TDesC& aEmailBody)
+ {
+ LOGGSMU1("CSmsMessage::AddEmailHeaderL()");
+
+ if(IsEmailHeader())
+ User::Leave(KErrAlreadyExists);
+
+ TInt len =aEmailHeader.Length();
+ if(len <= 0)
+ User::Leave(KErrCorrupt);
+
+ if(len >= 255 )
+ User::Leave(KErrTooBig);
+
+
+ if(SmsPDU().UserData().NumInformationElements())
+ {
+ TBool is16bit = EFalse;
+ TBool concatenationIEPresent= SmsPDU().TextConcatenated( &is16bit );
+ if(concatenationIEPresent)
+ {
+ if(SmsPDU().UserData().NumInformationElements() >=2) // something more than concat IE
+ User::Leave(KErrAccessDenied);
+ }
+ else
+ User::Leave(KErrAccessDenied);
+ }
+
+
+ TBuf8<1> data;
+ data.SetLength(1);
+ data[0]=static_cast<TUint8>(len);
+ SmsPDU().UserData().AddInformationElementL(CSmsInformationElement::ESmsIEIRFC822EmailHeader,data);
+
+ iBuffer->Reset();
+ iBuffer->InsertL(0,aEmailHeader);
+ iBuffer->InsertL(iBuffer->Length(),aEmailBody);
+ } // CSmsMessage::AddEmailHeaderL
+
+ /**
+ * Checks whether the SmsMessage contains an e-mail.
+ *
+ * @return ETrue if CSmsMessage contains e-mail ( e-mail header information element), otherwise EFalse
+ * @publishedAll
+ * @released
+ *
+ * @capability None
+ */
+EXPORT_C TBool CSmsMessage::IsEmailHeader() const
+ {
+ LOGGSMU1("CSmsMessage::IsEmailHeader()");
+
+ TInt emailIndex;
+ return SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEIRFC822EmailHeader,emailIndex);
+ } // CSmsMessage::IsEmailHeader
+
+ /**
+ * Extracts e-mail header and body from the SmsMessage
+ *
+ * @return aEMailHeader The buffer containing the extracted email header
+ * @return aEMailBody The buffer containing the extracted email body
+ * @return ETrue if extraction of e-mail header and body succeeds
+ * @publishedAll
+ * @released
+ *
+ * @capability None
+ */
+EXPORT_C TBool CSmsMessage::GetEmailHeaderL(HBufC** aEmailHeader,HBufC** aEmailBody)
+ {
+ LOGGSMU1("CSmsMessage::GetEmailHeaderL()");
+
+ if(IsEmailHeader())
+ {
+ TInt bufLen=iBuffer->Length();
+ TInt emailHeaderLen(0);
+ TInt emailIndex(0);
+ if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEIRFC822EmailHeader,emailIndex))
+ emailHeaderLen=SmsPDU().UserData().InformationElement(emailIndex).Data()[0];
+ else
+ User::Leave(KErrCorrupt);
+
+ TInt emailBodyLen=bufLen-emailHeaderLen;
+
+ if(emailBodyLen<0)
+ return EFalse;
+
+ *aEmailHeader=HBufC::NewL(emailHeaderLen);
+ CleanupStack::PushL(*aEmailHeader);
+
+ *aEmailBody=HBufC::NewL(emailBodyLen);
+ CleanupStack::PushL(*aEmailBody);
+
+ TPtr headerPtr((*aEmailHeader)->Des());
+ iBuffer->Extract(headerPtr,0,emailHeaderLen);
+
+ TPtr bodyPtr((*aEmailBody)->Des());
+ iBuffer->Extract(bodyPtr,emailHeaderLen,emailBodyLen);
+
+ CleanupStack::Pop(2);
+ return ETrue;
+ }
+ return EFalse;
+ } // CSmsMessage::GetEmailHeaderL
+
+
+ /**
+ * Extracts the offset between universal time and local time in seconds.
+ * If the value is > 0, local time is ahead of universal time.
+ * If the value is < 0, local time is behind universal time.
+ *
+ * @return TTTimeIntervalSeconds The time zone offset in seconds.
+ * @publishedAll
+ * @capability None
+ */
+EXPORT_C TTimeIntervalSeconds CSmsMessage::UTCOffset() const
+ {
+ LOGGSMU1("CSmsMessage::UTCOffset()");
+
+ TUint timeZoneOffset = ((iFlags & ESmsUTCOffsetSecondGranularityMask) >> ESecondBitOffset);
+
+ if (iFlags & ESmsUTCOffsetSignBit)
+ {
+ timeZoneOffset = -timeZoneOffset;
+ }
+
+ return (TTimeIntervalSeconds(timeZoneOffset));
+ } // CSmsMessage::UTCOffset
+
+
+ /**
+ * Sets the offset between universal time and local time in seconds.
+ * If the value is > 0, local time is ahead of universal time.
+ * If the value is < 0, local time is behind universal time.
+ * The CSmsMessage Time Zone Offset has the range +/- 71100 seconds. This is same range as
+ * the Service Centre Time Stamp Time Zone Offset as specified in 23.040 V4.4.0 Sect 9.2.3.11.
+ *
+ * @return True if input value was set successfully (in range), False otherwise
+ * @publishedAll
+ * @capability None
+ */
+EXPORT_C TBool CSmsMessage::SetUTCOffset(const TTimeIntervalSeconds& aTimeOffset)
+ {
+ LOGGSMU1("CSmsMessage::SetUTCOffset()");
+
+ TBool rc = ETrue;
+
+ TInt timeOffset = aTimeOffset.Int();
+
+ if ((timeOffset <= EMaximumSeconds) &&
+ (timeOffset >= -EMaximumSeconds))
+ {
+ // Clear the timezone offset bits
+ iFlags &= (~(ESmsUTCOffsetSecondGranularityMask |
+ ESmsUTCOffsetSignBit));
+
+ if (timeOffset < 0)
+ {
+ iFlags |= ESmsUTCOffsetSignBit;
+ timeOffset = -timeOffset;
+ }
+
+ iFlags |= (timeOffset << ESecondBitOffset);
+ }
+ else
+ {
+ LOGGSMU2("CSmsMessage::SetUTCOffset offset [out of range] = %d",timeOffset);
+ rc = EFalse;
+ }
+
+ return rc;
+} // CSmsMessage::SetUTCOffset
+
+
+/**
+ * Returns the message version number.
+ * @capability
+ */
+EXPORT_C TInt CSmsMessage::Version()
+ {
+ LOGGSMU1("CSmsMessage::Version()");
+
+ return iVersion;
+ } // CSmsMessage::Version
+
+
+/**
+ * @internalComponent
+ * Validates and sets the message version number.
+ *
+ * @param aVersion version number to set.
+ * @return KErrNone if aVersion is valid and successfully set, KErrArgument otherwise.
+ * @capability None
+ */
+EXPORT_C TInt CSmsMessage::SetVersion(TInt aVersion)
+ {
+ LOGGSMU2("CSmsMessage::SetVersion()", aVersion);
+
+ if((aVersion>=ESmsMessageV0) && (aVersion<=ESmsMessageV4))
+ {
+ iVersion=aVersion;
+ return KErrNone;
+ }
+
+ return KErrArgument;
+ } // CSmsMessage::SetVersion
+
+
+/**
+ * @internalComponent
+ * Internalises all object data except for the CSmsBufferBase and the message version.
+ *
+ * This is used when the buffer is stored elsewhere.
+ *
+ * @param aStream Stream to read from
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::InternalizeWithoutBufferAndVersionL(RReadStream& aStream)
+ {
+ LOGGSMU1("CSmsMessage::InternalizeWithoutBufferAndVersionL()");
+
+ iFlags=aStream.ReadInt32L();
+ iStatus=(NMobileSmsStore::TMobileSmsStoreStatus) aStream.ReadInt32L();
+ iLogServerId=aStream.ReadInt32L();
+ TInt64 time;
+ aStream >> time;
+ iTime=time;
+
+ CSmsPDU* smspdu=CSmsPDU::NewL(aStream,*iCharacterSetConverter,iFs);
+ delete iSmsPDU;
+ iSmsPDU=smspdu;
+ iIs16BitConcatenation=aStream.ReadInt32L();
+
+ iInformationElementArray->ResetAndDestroy();
+ CEmsFactory::InternalizeL(*iInformationElementArray, aStream);
+
+ TInt count=aStream.ReadInt32L();
+ iSlotArray.Reset();
+ TInt i=0;
+ TGsmSmsSlotEntry newSlot;
+ for (; i<count; i++)
+ {
+ newSlot.InternalizeL(aStream);
+ AddSlotL(newSlot);
+ }
+ } // CSmsMessage::InternalizeWithoutBufferAndVersionL
+
+
+/**
+ * @internalComponent
+ * Externalises all object data except for the CSmsBufferBase and the message version.
+ *
+ * This is used when the buffer is stored elsewhere.
+ *
+ * @param aStream Stream to write to
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::ExternalizeWithoutBufferAndVersionL(RWriteStream& aStream) const
+ {
+ LOGGSMU1("CSmsMessage::ExternalizeWithoutBufferAndVersionL()");
+
+ aStream.WriteInt32L(iFlags);
+ aStream.WriteInt32L(iStatus);
+ aStream.WriteInt32L(iLogServerId);
+ aStream << Time().Int64();
+
+ SmsPDU().ExternalizeL(aStream);
+ aStream.WriteInt32L(iIs16BitConcatenation);
+
+ CEmsFactory::ExternalizeL(*iInformationElementArray, aStream);
+ TInt count=iSlotArray.Count();
+ aStream.WriteInt32L(count);
+ TInt i=0;
+ for (; i<count; i++)
+ {
+ iSlotArray[i].ExternalizeL(aStream);
+ }
+ } // CSmsMessage::ExternalizeWithoutBufferAndVersionL
+
+
+/**
+ * @internalComponent
+ * Internalises the CSmsBufferBase.
+ *
+ * @param aStream Stream to read from
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::InternalizeBufferL(RReadStream& aStream)
+ {
+ aStream >> *iBuffer;
+ } // CSmsMessage::InternalizeBufferL
+
+
+/**
+ * @internalComponent
+ * Externalises the CSmsBufferBase.
+ *
+ * @param aStream Stream to write to
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::ExternalizeBufferL(RWriteStream& aStream) const
+ {
+ aStream << *iBuffer;
+ } // CSmsMessage::ExternalizeBufferL
+
+
+/**
+ * @internalComponent
+ * Internalises the message version.
+ *
+ * @param aStream Stream to read from
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::InternalizeVersionL(RReadStream& aStream)
+ {
+ TInt32 versionNumber = ESmsMessageV0;
+ TRAPD(err,versionNumber=aStream.ReadInt32L());
+ if(err==KErrEof)
+ {
+ versionNumber=ESmsMessageV0;
+ }
+
+ iVersion=static_cast<TSmsMessageVersion> (versionNumber);
+ } // CSmsMessage::InternalizeVersionL
+
+
+/**
+ * @internalComponent
+ * Externalises the message version.
+ *
+ * @param aStream Stream to write to
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::ExternalizeVersionL(RWriteStream& aStream) const
+ {
+ aStream.WriteInt32L(iVersion);
+ } // CSmsMessage::ExternalizeVersionL
+
+
+/**
+ * @publishedAll
+ *
+ * Returns a reference to a specialisation of the class CSmsIEOperation. Clients can use this sub-class
+ * to access the attributes of a specific type of information element encapsulated inside the CSmsMessage.
+ * The ownership to the CSmsIEOperation class belongs to the CSmsMessage. When the CSmsMessage is deleted,
+ * the CSmsIEOperation will also be deleted and the reference will become stale.
+ *
+ * @param aId
+ * Specifies the sub class of CSmsIEOperation required.
+ * @leave KErrNotSupported
+ * When there is not accessor class available for the specified type of information element.
+ * @capability None
+ */
+EXPORT_C CSmsIEOperation& CSmsMessage::GetOperationsForIEL(CSmsInformationElement::TSmsInformationElementIdentifier aId) const
+ {
+ LOGGSMU1("CSmsMessage::GetOperationsForIEL()");
+
+ if (iVersion < CSmsMessage::ESmsMessageV1)
+ {
+ LOGGSMU2("CSmsMessage::GetOperationsForIEL, Operation not supported, Msg Version %d", iVersion);
+ User::Leave(KErrNotSupported);
+ }
+
+ return iAdditionalInfo->GetIEOperationL(aId);
+ } // CSmsMessage::GetOperationsForIEL
+
+EXPORT_C CSmsNonIEOperation& CSmsMessage::GetOperationsForNonIEL(TSmsNonIEIdentifier aId) const
+ {
+ LOGGSMU1("CSmsMessage::GetOperationsForNonIEL");
+
+ if (iVersion < CSmsMessage::ESmsMessageV2)
+ {
+ LOGGSMU2("GetOperationsForNonIEL not supported, Msg Version %d", iVersion);
+ User::Leave(KErrNotSupported);
+ }
+
+ return iAdditionalInfo->GetNonIEOperationL(aId);
+ } // CSmsMessage::GetOperationsForNonIEL
+
+
+void CSmsMessage::CreateControlIEOperationsClassesL()
+ {
+ LOGGSMU1("CSmsMessage::CreateControlIEOperationsClassesL()");
+
+ CSmsIEOperation* iEOperation = NULL;
+
+ iEOperation = CSmsIEOperation::NewL(CSmsInformationElement::ESmsHyperLinkFormat, *this, *iCharacterSetConverter, iFs);
+ iAdditionalInfo->SetIEOperationL(iEOperation);
+
+ iEOperation = CSmsIEOperation::NewL(CSmsInformationElement::ESmsReplyAddressFormat, *this, *iCharacterSetConverter, iFs);
+ iAdditionalInfo->SetIEOperationL(iEOperation);
+
+ iEOperation = CSmsIEOperation::NewL(CSmsInformationElement::ESmsEnhanceVoiceMailInformation, *this, *iCharacterSetConverter, iFs);
+ iAdditionalInfo->SetIEOperationL(iEOperation);
+
+ iEOperation = CSmsIEOperation::NewL(CSmsInformationElement::ESmsIEISpecialSMSMessageIndication, *this, *iCharacterSetConverter, iFs);
+ iAdditionalInfo->SetIEOperationL(iEOperation);
+
+ iEOperation = CSmsIEOperation::NewL( CSmsInformationElement::ESmsIEISMSCControlParameters, *this, *iCharacterSetConverter, iFs);
+ iAdditionalInfo->SetIEOperationL(iEOperation);
+ } // CSmsMessage::CreateControlIEOperationsClassesL
+
+
+void CSmsMessage::CreateControlNonIEOperationsClassesL()
+ {
+ CSmsNonIEOperation* nonIEOperation = NULL;
+
+ nonIEOperation = CSmsNonIEOperation::NewL(ESmsTPSRRParameter, *this);
+ iAdditionalInfo->SetNonIEOperationL(nonIEOperation);
+
+ nonIEOperation = CSmsNonIEOperation::NewL(ESmsIncompleteClass0MessageParameter, *this);
+ iAdditionalInfo->SetNonIEOperationL(nonIEOperation);
+ } // CSmsMessage::CreateControlNonIEOperationsClassesL
+
+
+/**
+ * Gets the scheme of the status report.
+ *
+ * @return Staus Report Scheme
+ */
+EXPORT_C TSmsStatusReportScheme CSmsMessage::Scheme() const
+ {
+ return iAdditionalInfo->GetStatusReportScheme().Id();
+ }
+
+/**
+ * @publishedAll
+ *
+ * Used by the SMS Stack to indicate that when the message was decoded, it was determined
+ * to be on the SIM. If the message's DCS byte is configured for automatic delete or the
+ * PID is set to Type 0, the message may subsequently have been deleted from the SIM during
+ * decoding in which case its storage status is unstored.
+ *
+ * @param aOnSim
+ * Used to indicate that the message was on the SIM when it was decoded.
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::SetDecodedOnSIM(TBool aOnSim)
+ {
+ LOGGSMU2("CSmsMessage::SetDecodedOnSIM(): %d", aOnSim);
+
+ if (aOnSim)
+ {
+ iFlags = iFlags | EDecodedOnSimBit;
+ }
+ else
+ {
+ iFlags = iFlags & ~EDecodedOnSimBit;
+ }
+ } // CSmsMessage::SetDecodedOnSIM
+
+
+/**
+ * @publishedAll
+ *
+ * Used by the SMS Stack to indicate that when the message was decoded, it was determined
+ * to be on the SIM. If the message's DCS byte is configured for automatic delete or the
+ * PID is set to Type 0, the message may subsequently have been deleted from the SIM during
+ * decoding in which case its storage status is unstored.
+ *
+ * @return
+ * True if the message was on the SIM during decoding,
+ * False otherwise.
+ * @capability None
+ */
+EXPORT_C TBool CSmsMessage::DecodedOnSim()
+ {
+ LOGGSMU1("CSmsMessage::DecodedOnSim()");
+
+ if (iFlags & EDecodedOnSimBit)
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ } // CSmsMessage::DecodedOnSim
+
+
+/**
+ * @publishedAll
+ *
+ * Used by the SMS Stack to indicate that when the message was decoded, it was determined
+ * that it should be forwarded to the client. The message will not be forwarded to the
+ * client when the PID byte is set to type 0 (except by default for class 0 and class 2 messages).
+ *
+ * @param forward
+ * Used to indicate that the message needs to be forwarded to clients.
+ * @capability None
+ */
+EXPORT_C void CSmsMessage::SetForwardToClient(TBool aForward)
+ {
+ LOGGSMU2("CSmsMessage::SetForwardToClient(): %d", aForward);
+
+ if (aForward)
+ {
+ iFlags = iFlags | EForwardToClientBit;
+ }
+ else
+ {
+ iFlags = iFlags & ~EForwardToClientBit;
+ }
+ } // CSmsMessage::SetForwardToClient
+
+
+/**
+ * @publishedAll
+ *
+ * Used by the SMS Stack to indicate that when the message was decoded, it was determined
+ * that is should be forwarded to the client. The message will not be forwarded to the client
+ * when the PID byte is set to type 0 (except by default for class 0 and class 2 messages).
+ *
+ * @return
+ * True if the message is to be forwarded to clients
+ * False otherwise.
+ * @capability None
+ */
+EXPORT_C TBool CSmsMessage::ForwardToClient()
+ {
+ LOGGSMU1("CSmsMessage::ForwardToClient()");
+
+ if (iFlags & EForwardToClientBit)
+ {
+ return ETrue;
+ }
+ else
+ {
+ return EFalse;
+ }
+ } // CSmsMessage::ForwardToClient