smsprotocols/smsstack/gsmu/src/Gsmuelem.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:40:21 +0100
branchRCL_3
changeset 20 07a122eea281
parent 19 630d2f34d719
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201035 Kit: 201035

// 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:
// This file implements the different PDU elements
// 
//

/**
 @file
*/

#include <gsmuelem.h>
#include <gsmumsg.h>
#include "Gsmumain.h"
#include <gsmusar.h>
#include "gsmupriv.h"
#include <s32strm.h>
#include <etelmm.h>
#include <gsmuetel.h>
#include <exterror.h>
#include <emsinformationelement.h>
#include <emsformatie.h>
#include <charconv.h>

/**
 *  Question Mark character.
 */
const TInt  KReplacementCharacter = 0x003f;


/**
 *  Constructs the object with a descriptor. The extraction mark and next character members are initialised to point to the start of the string.
 *  
 *  @param aSource Descriptor to be assigned by reference
 */
TGsmuLex8::TGsmuLex8(const TDesC8& aSource): TLex8(aSource)
	{
	//NOP
	} // TGsmuLex8::TGsmuLex8


/**
 *  Gets the next character in the string and increments the next character position.
 *  
 *  @return The next character in the string
 *  @leave Leaves with KErrGsmuDecoding if at end of string
 */
TUint8 TGsmuLex8::GetL()
	{
	if (Eos())
		LeaveL();

	return static_cast<TUint8>(Get());
	} // TGsmuLex8::GetL


/**
 *  Increments the next character position by aNumber
 *  
 *  @param aNumber The number of characters to increment the next character position by.
 *  @leave If the increment puts the next character position before the start or beyond the end of the string, the function leaves with KErrGsmuDecoding.
 */
void TGsmuLex8::IncL(TInt aNumber)
	{
	if (aNumber != 0)
		{
		if (aNumber < 0 || Eos() || Remainder().Length() < aNumber)
			LeaveL();
		else
			Inc(aNumber);
		}
	} // TGsmuLex8::IncL


/**
 *  Checks there are enough remaining characters, then returns a TPtrC containing the next aLength characters. Does not increment the current position.
 *  
 *  @param aLength Number of characters to return
 *  @return Remainder().Left(aLength)
 *  @leave Leaves with KErrGsmuDecoding if there are insufficient characters remaining
 */
TPtrC8 TGsmuLex8::NextWithNoIncL(TInt aLength) const
	{
	return NextWithNoIncL(aLength, EFalse);
	}

/**
 * Checks there are enough remaining characters, then returns a TPtrC containing the next aLength characters. Does not increment the current position.
 *
 * @param aLength Number of characters to return
 * @param aAcceptTruncation ETrue if a mismatch between length indicator and actual length is acceptable. EFalse otherwise.
 * @return Remainder().Left(aLength) if aAcceptTruncation is EFalse. Remainder() otherwise.
 * @leave Leaves with KErrGsmuDecoding if there are insufficient characters remaining, unless aAcceptTruncation is ETrue.
 */
TPtrC8 TGsmuLex8::NextWithNoIncL(TInt aLength, TBool aAcceptTruncation) const
	{
	const TPtrC8 remainder(Remainder());

	if ( (aLength < 0) || (remainder.Length()< aLength && !aAcceptTruncation) )
		{
		LeaveL();
		}
	
  if (!aAcceptTruncation)
		{
		return Remainder().Left(aLength);
		}
	// aAcceptTruncation is ETrue
	else if (remainder.Length() < aLength)
		{
		return Remainder();
		}
	// otherwise, no need for truncation:
  
	return Remainder().Left(aLength);
	}


/**
 *  Calls TGsmuLeax8::NextWithNoIncL then increments the next character position by aLength
 *  
 *  @param aLength Number of characters to return and increment the next character position
 *  @return Remainder().Left(aLength)
 *  @leave If the increment puts the next character position before the start or beyond the end of the string, the function leaves with KErrGsmuDecoding.
 */
TPtrC8 TGsmuLex8::NextAndIncL(TInt aLength)
	{
	const TPtrC8 next(NextWithNoIncL(aLength));
	IncL(aLength);
	return next;
	} // TGsmuLeax8::NextWithNoIncL


const TSmsOctet& TSmsOctet::operator = (TInt aValue)
	{
	iValue = static_cast<TUint8>(aValue);
	return *this;
	} // TSmsOctet::operator


TUint8* TSmsOctet::EncodeL(TUint8* aPtr) const
	{
	*aPtr=iValue;
	return aPtr+1;
	} // TSmsOctet::EncodeL


TSmsFirstOctet::TSmsFirstOctet(TInt aValue):
	TSmsOctet(aValue)
	{
	} // TSmsFirstOctet::TSmsFirstOctet


const TSmsFirstOctet& TSmsFirstOctet::operator = (TInt aValue)
	{
	TSmsOctet::operator = (aValue);
	return *this;
	} // TSmsFirstOctet::operator


TSmsFailureCause::TSmsFailureCause():
	TSmsOctet(ESmsErrorUnspecified)
	{
	} // TSmsFailureCause::TSmsFailureCause


TSmsStatus::TSmsStatus():
	TSmsOctet(ESmsShortMessageReceivedBySME)
	{
	} // TSmsStatus::TSmsStatus


CSmsCommandData* CSmsCommandData::NewL(TSmsFirstOctet& aFirstOctet)
	{
	LOGGSMU1("CSmsCommandData::NewL()");

	CSmsCommandData* commanddata=new(ELeave) CSmsCommandData(aFirstOctet);
	CleanupStack::PushL(commanddata);
	TPtrC8 ptr;
	commanddata->SetDataL(ptr);
	CleanupStack::Pop();
	return commanddata;
	} // CSmsCommandData::NewL


CSmsCommandData::~CSmsCommandData()
	{
	iInformationElementArray.ResetAndDestroy();
	delete iBuffer;
	} // CSmsCommandData::NewL


/**
 *  Duplicates this CSmsCommandData object.
 * 
 *  @return  Pointer to the newly created CSmsCommandData object.
 */
CSmsCommandData* CSmsCommandData::DuplicateL() const
	{
	LOGGSMU1("CSmsCommandData::DuplicateL()");

	CSmsCommandData*  smsCommandData = CSmsCommandData::NewL(iFirstOctet);
	CleanupStack::PushL(smsCommandData);

	smsCommandData->SetDataL(Data());

	for (TInt ie = 0;  ie < iInformationElementArray.Count();  ie++)
		{
		smsCommandData->AddInformationElementL(iInformationElementArray[ie]->Identifier(),
											   iInformationElementArray[ie]->Data());
		}

	CleanupStack::Pop(smsCommandData);

	return smsCommandData;
	} // CSmsCommandData::DuplicateL


CSmsInformationElement& CSmsCommandData::InformationElement(TInt aIndex) const
	{
	LOGGSMU1("CSmsCommandData::InformationElement()");

	CSmsInformationElement* ie=iInformationElementArray[aIndex];
	return *ie;
	} // CSmsCommandData::InformationElement


CSmsInformationElement*& CSmsCommandData::InformationElementPtr(TInt aIndex)
    {
    // Ignore in code coverage - not used in SMS stack and not exported
    // but cannot be removed as impacts public header.
    BULLSEYE_OFF    
    LOGGSMU1("CSmsCommandData::InformationElementPtr()");
    return iInformationElementArray[aIndex];
    BULLSEYE_RESTORE
    }

TBool CSmsCommandData::InformationElementIndex(CSmsInformationElement::TSmsInformationElementIdentifier aIdentifier,
		TInt& aIndex) const
	{
	LOGGSMU1("CSmsCommandData::InformationElementIndex()");

	TBool found=EFalse;
	TInt count=NumInformationElements();
	for (TInt i=0; (!found) && (i<count); i++)
		if (InformationElement(i).Identifier()==aIdentifier)
			{
			found=ETrue;
			aIndex=i;
			}
	return found;
	} // CSmsCommandData::InformationElementIndex


void CSmsCommandData::AddInformationElementL(const TSmsId aIdentifier,const TDesC8& aData)
	{
	LOGGSMU1("CSmsCommandData::AddInformationElementL()");

	//
	// Currently there is no restriction on how many instances of an information element can be
	// placed in the collection.
	// No restriction will be placed on the number of Special SMS Message Indications that can be
	// added in order to maintain FC.
	// (cf CSmsUserData::AddInformationElementL(const TSmsId aIdentifier,const TDesC8& aData);
	//
	CSmsInformationElement* informationelement=CSmsInformationElement::NewL(aIdentifier,aData);
	CleanupStack::PushL(informationelement);
	iInformationElementArray.AppendL(informationelement);
	CleanupStack::Pop();
	if (NumInformationElements()>=1)
		SetHeaderPresent(ETrue);
	} // CSmsCommandData::AddInformationElementL


void CSmsCommandData::RemoveInformationElement(TInt aIndex)
	{
	LOGGSMU1("CSmsCommandData::RemoveInformationElement()");
	// Since iInformationElementArray[aIndex] is removed from iInformationElementArray, no double free issue.
	// coverity[double_free]
	delete iInformationElementArray[aIndex];
	iInformationElementArray[aIndex] = NULL;
	iInformationElementArray.Delete(aIndex);

	if (NumInformationElements()==0)
		{
		SetHeaderPresent(EFalse);
		}
	} // CSmsCommandData::RemoveInformationElement


TPtrC8 CSmsCommandData::Data() const
	{
	LOGGSMU1("CSmsCommandData::Data()");

	TPtrC8 ptr;
	ptr.Set(iBuffer->Des());
	return ptr;
	} // CSmsCommandData::Data


void CSmsCommandData::SetDataL(const TDesC8& aData)
	{
	LOGGSMU1("CSmsCommandData::SetDataL()");

	TInt length=aData.Length();
	__ASSERT_DEBUG(length<=KSmsMaxDataSize,Panic(KGsmuPanicCommandDataLengthTooLong));
	HBufC8* buffer=HBufC8::NewL(length);
	delete iBuffer;
	iBuffer=buffer;
	iBuffer->Des().SetLength(length);
	iBuffer->Des().Copy(aData);
	} // CSmsCommandData::SetDataL


TUint8* CSmsCommandData::EncodeL(TUint8* aPtr) const
	{
	LOGGSMU1("CSmsCommandData::EncodeL()");

	__ASSERT_DEBUG(iBuffer->Length()<=MaxDataLength(),Panic(KGsmuPanicCommandDataBufferTooLong));
	TSmsOctet datalength=iBuffer->Length()+TSmsOctet(TotalHeaderLengthInUDLUnits());
	aPtr=datalength.EncodeL(aPtr);
	TPtr8 ptr((TUint8*) aPtr,datalength);

    if (HeaderPresent())
        {
		TSmsOctet headerLength(HeaderLength());
		aPtr=headerLength.EncodeL(aPtr);
		for (TInt i=0; i<NumInformationElements(); i++)
		    {
			aPtr=iInformationElementArray[i]->EncodeL(aPtr);
		    }
        }

	ptr.Copy(iBuffer->Des());
	aPtr+=TInt(iBuffer->Length());
	return aPtr;
	} // CSmsCommandData::EncodeL


void CSmsCommandData::DecodeL(TGsmuLex8& aPdu)
	{
	LOGGSMU1("CSmsCommandData::DecodeL()");

	iInformationElementArray.ResetAndDestroy();
	const TBool headerPresent=HeaderPresent();
	TSmsOctet dataLength;
	dataLength.DecodeL(aPdu);

	if (headerPresent)
		{
		TSmsOctet headerLength;
		headerLength.DecodeL(aPdu);
		if ((1+headerLength)>KSmsMaxDataSize)
			User::Leave(KErrGsmSMSTpduNotSupported);
		while (HeaderLength()<headerLength)
			{
			CSmsInformationElement* informationElement=CSmsInformationElement::NewL();
			CleanupStack::PushL(informationElement);
			informationElement->DecodeL(aPdu);
			iInformationElementArray.AppendL(informationElement);
			CleanupStack::Pop(informationElement);
			}
		if (HeaderLength()!=headerLength)
			User::Leave(KErrGsmSMSTpduNotSupported);
		}
	const TInt totalHeaderLength=TotalHeaderLengthInUDLUnits();
	const TInt totalDataLength=dataLength-totalHeaderLength;
	const TPtrC8 next(aPdu.NextAndIncL(totalDataLength));
	SetDataL(next);
	} // CSmsCommandData::DecodeL


void CSmsCommandData::InternalizeL(RReadStream& aStream)
	{
	iInformationElementArray.ResetAndDestroy();
	TInt numInformationElements=aStream.ReadInt32L();
	for (TInt i=0; i<numInformationElements; i++)
		{
		CSmsInformationElement* informationElement=CSmsInformationElement::NewL();
		CleanupStack::PushL(informationElement);
		aStream >> *informationElement;
		iInformationElementArray.AppendL(informationElement);
		CleanupStack::Pop();
		}
	HBufC8* buffer=HBufC8::NewL(aStream,KSmsMaxDataSize);
	delete iBuffer;
	iBuffer=buffer;
	} // CSmsCommandData::InternalizeL


void CSmsCommandData::ExternalizeL(RWriteStream& aStream) const
	{
	TInt numInformationElements=iInformationElementArray.Count();
	aStream.WriteInt32L(numInformationElements);
	for (TInt i=0; i<numInformationElements; i++)
		aStream << *iInformationElementArray[i];
	aStream << *iBuffer;
	} // CSmsCommandData::ExternalizeL


CSmsCommandData::CSmsCommandData(TSmsFirstOctet& aFirstOctet):
	iFirstOctet(aFirstOctet),
	iInformationElementArray(8)
	{
	} // CSmsCommandData::CSmsCommandData


TInt CSmsCommandData::HeaderLength() const
	{
	LOGGSMU1("CSmsCommandData::HeaderLength()");

	TInt headerLength=0;
	for (TInt i=0; i<NumInformationElements(); i++)
		headerLength+=iInformationElementArray[i]->Length();
	return headerLength;
	} // CSmsCommandData::HeaderLength


TInt CSmsCommandData::TotalHeaderLengthInUDLUnits() const
	{
	LOGGSMU1("CSmsCommandData::TotalHeaderLengthInUDLUnits()");

	if (iInformationElementArray.Count()==0)
		return 0;
	else
		return (HeaderLength()+1);   // +1 stands for  UDHL
	} // CSmsCommandData::TotalHeaderLengthInUDLUnits


TBool CSmsCommandData::HeaderPresent() const
	{
	LOGGSMU1("CSmsCommandData::HeaderPresent()");

	return (iFirstOctet&TSmsFirstOctet::ESmsUDHIMask)==TSmsFirstOctet::ESmsUDHIHeaderPresent;
	} // CSmsCommandData::HeaderPresent


void CSmsCommandData::SetHeaderPresent(TBool aHeaderPresent)
	{
	LOGGSMU1("CSmsCommandData::SetHeaderPresent()");

	iFirstOctet=aHeaderPresent? (iFirstOctet&(~TSmsFirstOctet::ESmsUDHIMask))|TSmsFirstOctet::ESmsUDHIHeaderPresent: (iFirstOctet&(~TSmsFirstOctet::ESmsUDHIMask))|TSmsFirstOctet::ESmsUDHIHeaderNotPresent;
	} // CSmsCommandData::SetHeaderPresent


TSmsParameterIndicator::TSmsParameterIndicator():
	TSmsOctet(ESmsPIDProtocolIdentifierPresent|ESmsPIDUserDataPresent|ESmsPIDDataCodingSchemePresent)
	{
	} // TSmsParameterIndicator::TSmsParameterIndicator


TSmsCommandType::TSmsCommandType():
	TSmsOctet(ESmsCommandTypeEnquiry)
	{
	} // TSmsCommandType::TSmsCommandType


TSmsProtocolIdentifier::TSmsProtocolIdentifier():
	TSmsOctet((TInt)ESmsPIDTelematicInterworking|(TInt)ESmsNoTelematicDevice)
	{
	} // TSmsProtocolIdentifier::TSmsProtocolIdentifier


TSmsProtocolIdentifier::TSmsTelematicDeviceIndicator TSmsProtocolIdentifier::TelematicDeviceIndicator() const
	{
	__ASSERT_DEBUG(PIDType()==ESmsPIDTelematicInterworking,Panic(KGsmuPanicNoTelematicInterworking));
	return (TSmsTelematicDeviceIndicator) (iValue&EPIDTelematicDeviceIndicatorMask);
	} // TSmsProtocolIdentifier::TSmsTelematicDeviceIndicator


void TSmsProtocolIdentifier::SetTelematicDeviceIndicator(TSmsTelematicDeviceIndicator aIndicator)
	{
	LOGGSMU1("TSmsProtocolIdentifier::SetTelematicDeviceIndicator()");

	__ASSERT_DEBUG(PIDType()==ESmsPIDTelematicInterworking,Panic(KGsmuPanicNoTelematicInterworking));

	//iValue=(TUint8) ((iValue&ESmsPIDTypeMask)|aIndicator);
	iValue=(TUint8) ((iValue&(~EPIDTelematicDeviceIndicatorMask))|aIndicator);
	} // TSmsProtocolIdentifier::SetTelematicDeviceIndicator


TSmsProtocolIdentifier::TSmsTelematicDeviceType TSmsProtocolIdentifier::TelematicDeviceType() const
	{
	__ASSERT_DEBUG(TelematicDeviceIndicator()==ESmsTelematicDevice,Panic(KGsmuPanicNoTelematicDevice));
	return (TSmsTelematicDeviceType) (iValue&ESmsTelematicDeviceTypeMask);
	} // TSmsProtocolIdentifier::TSmsTelematicDeviceType


void TSmsProtocolIdentifier::SetTelematicDeviceType(TSmsTelematicDeviceType aDeviceType)
	{
	LOGGSMU1("TSmsProtocolIdentifier::SetTelematicDeviceType()");

	__ASSERT_DEBUG(TelematicDeviceIndicator()==ESmsTelematicDevice,Panic(KGsmuPanicNoTelematicDevice));
	iValue=(TUint8) ((iValue&(~ESmsTelematicDeviceTypeMask))|aDeviceType);
	} // TSmsProtocolIdentifier::SetTelematicDeviceType


TInt TSmsProtocolIdentifier::ShortMessageALProtocol() const
    {
    // Ignore in code coverage - not used in SMS stack and not exported
    // but cannot be removed as impacts public header.
    BULLSEYE_OFF    
    LOGGSMU1("TSmsProtocolIdentifier::ShortMessageALProtocol()");
    
    __ASSERT_DEBUG(TelematicDeviceIndicator()==ESmsNoTelematicDevice,Panic(KGsmuPanicNoTelematicDevice));
    return (TSmsShortMessageALProtocol) (iValue&ESmsShortMessageALProtocolMask);
    BULLSEYE_RESTORE
    }

void TSmsProtocolIdentifier::SetShortMessageALProtocol(TSmsShortMessageALProtocol aProtocol)
    {
    // Ignore in code coverage - not used in SMS stack and not exported
    // but cannot be removed as impacts public header.
    BULLSEYE_OFF    
    LOGGSMU1("TSmsProtocolIdentifier::SetShortMessageALProtocol()");
    
    __ASSERT_DEBUG(TelematicDeviceIndicator()==ESmsNoTelematicDevice,Panic(KGsmuPanicNoTelematicDevice));
    iValue=(TUint8) ((iValue&(~ESmsShortMessageALProtocolMask))|aProtocol);
    BULLSEYE_RESTORE
    }

TInt TSmsProtocolIdentifier::ShortMessageType() const
	{
	LOGGSMU1("TSmsProtocolIdentifier::ShortMessageType()");

	__ASSERT_DEBUG(PIDType()==ESmsPIDShortMessageType,Panic(KGsmuPanicNoShortMessageType));
	return (TSmsShortMessageType) (iValue&ESmsShortMessageTypeMask);
	} // TSmsProtocolIdentifier::ShortMessageType


void TSmsProtocolIdentifier::SetShortMessageType(TSmsShortMessageType aShortMessageType)
	{
	LOGGSMU1("TSmsProtocolIdentifier::SetShortMessageType()");

	__ASSERT_DEBUG(PIDType()==ESmsPIDShortMessageType,Panic(KGsmuPanicNoShortMessageType));
	//iValue=(TUint8) ((iValue&(~ESmsPIDTypeMask))|aShortMessageType);
	iValue=(TUint8) ((iValue&(~ESmsShortMessageTypeMask))|aShortMessageType);
	} // TSmsProtocolIdentifier::SetShortMessageType


TSmsDataCodingScheme::TSmsDataCodingScheme():
	TSmsOctet((TInt)ESmsDCSTextUncompressedWithNoClassInfo|(TInt)ESmsAlphabet7Bit|(TInt)ESmsClass0)
	// Constructor is expected to set the octet = 0, This is needed by
	// CSmsDeliverReport::DecodeL, CSmsSubmitReport::DecodeL and CSmsStatusReport::DecodeL, per
	// 23.040 v6.5.0 section 9.2.3.27.
	{
	} // CSmsDeliverReport::DecodeL


TBool TSmsDataCodingScheme::TextCompressed() const
	{
	LOGGSMU1("TSmsDataCodingScheme::TextCompressed()");

	TInt bits7to4=Bits7To4();
	return (bits7to4==ESmsDCSTextCompressedWithNoClassInfo)    || (bits7to4==ESmsDCSTextCompressedWithClassInfo)      ||
           (bits7to4==ESmsDCSAutoDelNoClassInfoCompressedText) || (bits7to4==ESmsDCSAutoDelClassInfoTextCompressedText);
	} // TSmsDataCodingScheme::TextCompressed


void TSmsDataCodingScheme::SetTextCompressed(TBool aCompressed)
	{
	LOGGSMU1("TSmsDataCodingScheme::SetTextCompressed()");

	TInt bits7to4=Bits7To4();
	if (aCompressed)
		{
		switch (bits7to4)
			{
			case (ESmsDCSTextUncompressedWithNoClassInfo):
				{
				iValue=(TUint8) (ESmsDCSTextCompressedWithNoClassInfo|(iValue&(~ESmsDCSBits7To4Mask)));
				break;
				}
			case (ESmsDCSAutoDelNoClassInfoUncompressedText):
				{
				iValue=(TUint8) (ESmsDCSAutoDelNoClassInfoCompressedText|(iValue&(~ESmsDCSBits7To4Mask)));
				break;
				}
			case (ESmsDCSAutoDelClassInfoUncompressedText):
				{
				iValue=(TUint8) (ESmsDCSAutoDelClassInfoTextCompressedText|(iValue&(~ESmsDCSBits7To4Mask)));
				break;
				}
			case (ESmsDCSTextUncompressedWithClassInfo):
			case (ESmsDCSTextUncompressed7BitOr8Bit):
				{
				iValue=(TUint8) (ESmsDCSTextCompressedWithClassInfo|(iValue&(~ESmsDCSBits7To4Mask)));
				break;
				}
			case (ESmsDCSTextCompressedWithNoClassInfo):
			case (ESmsDCSTextCompressedWithClassInfo):
			case (ESmsDCSAutoDelNoClassInfoCompressedText):
			case (ESmsDCSAutoDelClassInfoTextCompressedText):
				break;
			default:
                break;
                // has to be tested, what happens in this default case
				//Panic(KGsmuPanicNotSupportedWithDCSBits7To4);
			}
		}
	else
		{
		switch (bits7to4)
			{
			case (ESmsDCSTextCompressedWithNoClassInfo):
				{
				iValue=(TUint8) (ESmsDCSTextUncompressedWithNoClassInfo|(iValue&(~ESmsDCSBits7To4Mask)));
				break;
				}
			case (ESmsDCSTextCompressedWithClassInfo):
				{
				iValue=(TUint8) (ESmsDCSTextUncompressedWithClassInfo|(iValue&(~ESmsDCSBits7To4Mask)));
				break;
				}
			case (ESmsDCSAutoDelNoClassInfoCompressedText):
				{
				iValue=(TUint8) (ESmsDCSAutoDelNoClassInfoUncompressedText|(iValue&(~ESmsDCSBits7To4Mask)));
				break;
				}
			case (ESmsDCSAutoDelClassInfoTextCompressedText):
				{
				iValue=(TUint8) ( ESmsDCSAutoDelClassInfoUncompressedText|(iValue&(~ESmsDCSBits7To4Mask)));
				break;
				}
			case (ESmsDCSTextUncompressedWithNoClassInfo):
			case (ESmsDCSTextUncompressedWithClassInfo):
            case (ESmsDCSAutoDelClassInfoUncompressedText):
            case (ESmsDCSAutoDelNoClassInfoUncompressedText):
			case (ESmsDCSTextUncompressed7BitOr8Bit):
			default:
				{
				}
			}
		}
	} // TSmsDataCodingScheme::SetTextCompressed


TSmsDataCodingScheme::TSmsAlphabet TSmsDataCodingScheme::Alphabet() const
	{
	LOGGSMU1("TSmsDataCodingScheme::TSmsAlphabet()");

	TInt bits7to4=Bits7To4();
	TInt alphabet=ESmsAlphabet7Bit;
	switch (bits7to4)
		{
		case (ESmsDCSTextUncompressedWithNoClassInfo):
		case (ESmsDCSTextUncompressedWithClassInfo):
		case (ESmsDCSTextCompressedWithNoClassInfo):  //  Alphabet not used in these cases
		case (ESmsDCSTextCompressedWithClassInfo):
		case (ESmsDCSAutoDelNoClassInfoUncompressedText):
		case (ESmsDCSAutoDelClassInfoUncompressedText):
		case (ESmsDCSAutoDelNoClassInfoCompressedText):
		case (ESmsDCSAutoDelClassInfoTextCompressedText):
			{
			alphabet=iValue&ESmsAlphabetMask;
			break;
			}
		case (ESmsDCSTextUncompressed7BitOr8Bit):
			{
			alphabet=iValue&ESmsAlphabet8Bit;  //  N.B. only one bit used to code alphabet
			break;
			}
		case (ESmsDCSMessageWaitingIndicationDiscardMessage):
		case (ESmsDCSMessageWaitingIndication7Bit):
			{
			alphabet=ESmsAlphabet7Bit;
			break;
			}
		case (ESmsDCSMessageWaitingIndicationUCS2):
			{
			alphabet=ESmsAlphabetUCS2;
			break;
			}
		default:
		    LOGGSMU1("TSmsDataCodingScheme::Alphabet() WARNING! default case has been reached");
            break;
 		}
	return (TSmsAlphabet) alphabet;
	} // TSmsDataCodingScheme::TSmsAlphabet

void TSmsDataCodingScheme::SetAlphabet(TSmsAlphabet aAlphabet)
	{
	LOGGSMU1("TSmsDataCodingScheme::SetAlphabet()");

	TInt bits7to4=Bits7To4();
	switch (bits7to4)
		{
		case (ESmsDCSTextUncompressedWithNoClassInfo):
		case (ESmsDCSTextUncompressedWithClassInfo):
		case (ESmsDCSTextCompressedWithNoClassInfo):  //  Alphabet not used in these cases
		case (ESmsDCSTextCompressedWithClassInfo):
		case (ESmsDCSAutoDelNoClassInfoUncompressedText):
		case (ESmsDCSAutoDelClassInfoUncompressedText):
		case (ESmsDCSAutoDelNoClassInfoCompressedText):
		case (ESmsDCSAutoDelClassInfoTextCompressedText):
			{
			iValue=(TUint8) ((iValue&(~ESmsAlphabetMask))|aAlphabet);
			break;
			}
		case (ESmsDCSTextUncompressed7BitOr8Bit):
			{
			if ((aAlphabet==ESmsAlphabet7Bit) || (aAlphabet==ESmsAlphabet8Bit))
				{
				iValue=(TUint8) ((iValue&(~ESmsAlphabet8Bit))|aAlphabet);  //  N.B. only one bit used to code alphabet
				}
			break;
			}
		case (ESmsDCSMessageWaitingIndicationDiscardMessage):
			{
            if (aAlphabet!=ESmsAlphabet7Bit)
                {
                LOGGSMU3("TSmsDataCodingScheme::SetAlphabet() WARNING! Not Supported With Discard Message  [Bits7To4=%d], [aAlphabet=%d]", bits7to4, aAlphabet);
                }
			break;
			}
		case (ESmsDCSMessageWaitingIndication7Bit):
			{
 			if (aAlphabet==ESmsAlphabetUCS2)
 			    {
				iValue=(TUint8) (ESmsDCSMessageWaitingIndicationUCS2|(iValue&(~ESmsDCSBits7To4Mask)));
 			    }
 			else 
                {
        		LOGGSMU3("TSmsDataCodingScheme::SetAlphabet() WARNING! Not Supported With Discard Message  [Bits7To4=%d], [aAlphabet=%d]", bits7to4, aAlphabet);
			    }	     
			break;
			}
		case (ESmsDCSMessageWaitingIndicationUCS2):
			{
  			if (aAlphabet==ESmsAlphabet7Bit)
			    {
				iValue=(TUint8) (ESmsDCSMessageWaitingIndication7Bit|(iValue&(~ESmsDCSBits7To4Mask)));
			    }
			else 
			    {
				LOGGSMU3("TSmsDataCodingScheme::SetAlphabet() WARNING! Not Supported With Discard Message  [Bits7To4=%d], [aAlphabet=%d]", bits7to4, aAlphabet);
			    }
			break;
			}
		default:
		    LOGGSMU1("TSmsDataCodingScheme::SetAlphabet() WARNING! default case has been reached");
            break;
      		}
	} // TSmsDataCodingScheme::SetAlphabet


TBool TSmsDataCodingScheme::Class(TSmsClass& aClass) const
	{
	LOGGSMU1("TSmsDataCodingScheme::Class()");

	switch (Bits7To4())
		{
		case (ESmsDCSTextUncompressedWithClassInfo):
		case (ESmsDCSTextCompressedWithClassInfo):
		case (ESmsDCSAutoDelClassInfoUncompressedText):
		case (ESmsDCSAutoDelClassInfoTextCompressedText):
		case (ESmsDCSTextUncompressed7BitOr8Bit):
			aClass=(TSmsClass) (iValue&ESmsClassMask);
			return ETrue;
		default:
			return EFalse;
		}
	} // TSmsDataCodingScheme::Class


void TSmsDataCodingScheme::SetClass(TBool aClassDefined,TSmsDataCodingScheme::TSmsClass aClass)
	{
	LOGGSMU1("TSmsDataCodingScheme::SetClass()");

	TInt bits7to4=Bits7To4();
	if (aClassDefined)
		{
		switch (bits7to4)
			{
			case (ESmsDCSTextUncompressedWithNoClassInfo):
				{
				iValue=(TUint8) (ESmsDCSTextUncompressedWithClassInfo|(iValue&ESmsAlphabetMask|aClass));
				break;
				}
			case (ESmsDCSTextCompressedWithNoClassInfo):
				{
				iValue=(TUint8) (ESmsDCSTextCompressedWithClassInfo|(iValue&ESmsAlphabetMask|aClass));
				break;
				}
			case (ESmsDCSAutoDelNoClassInfoUncompressedText):
				{
				iValue=(TUint8) (ESmsDCSAutoDelClassInfoUncompressedText|(iValue&ESmsAlphabetMask|aClass));
				break;
				}
			case (ESmsDCSAutoDelNoClassInfoCompressedText):
				{
				iValue=(TUint8) (ESmsDCSAutoDelClassInfoTextCompressedText|(iValue&ESmsAlphabetMask|aClass));
				break;
				}
			case (ESmsDCSTextUncompressedWithClassInfo):
			case (ESmsDCSTextCompressedWithClassInfo):
			case (ESmsDCSAutoDelClassInfoUncompressedText):
			case (ESmsDCSAutoDelClassInfoTextCompressedText):
			case (ESmsDCSTextUncompressed7BitOr8Bit):

				{
				iValue=(TUint8) (iValue&(~ESmsClassMask)|aClass);
				break;
				}
			default:
		        LOGGSMU1("WARNING! default case has been reached");
                break;
			}
		}
	else
		{
		switch (bits7to4)
			{
			case (ESmsDCSTextUncompressedWithClassInfo):
				{
				iValue=(TUint8) (ESmsDCSTextUncompressedWithNoClassInfo|(iValue&ESmsAlphabetMask)|aClass);
				break;
				}
			case (ESmsDCSTextCompressedWithClassInfo):
				{
				iValue=(TUint8) (ESmsDCSTextCompressedWithNoClassInfo|(iValue&ESmsAlphabetMask)|aClass);
				break;
				}
			case (ESmsDCSAutoDelClassInfoUncompressedText):
				{
				iValue=(TUint8) (ESmsDCSAutoDelNoClassInfoUncompressedText|(iValue&ESmsAlphabetMask)|aClass);
				break;
				}
			case (ESmsDCSAutoDelClassInfoTextCompressedText):
				{
				iValue=(TUint8) (ESmsDCSAutoDelNoClassInfoCompressedText|(iValue&ESmsAlphabetMask)|aClass);
				break;
				}
			case (ESmsDCSTextUncompressed7BitOr8Bit):
				{
				iValue=(TUint8) (ESmsDCSTextUncompressedWithNoClassInfo|(iValue&ESmsAlphabetMask)|aClass);
				break;
				}
			case (ESmsDCSTextUncompressedWithNoClassInfo):
			case (ESmsDCSTextCompressedWithNoClassInfo):
			case (ESmsDCSAutoDelNoClassInfoUncompressedText):
			case (ESmsDCSAutoDelNoClassInfoCompressedText):
			case (ESmsDCSMessageWaitingIndicationDiscardMessage):
			case (ESmsDCSMessageWaitingIndication7Bit):
			case (ESmsDCSMessageWaitingIndicationUCS2):
			default:
				{
				}
			}
		}
	} // TSmsDataCodingScheme::SetClass


TSmsDataCodingScheme::TSmsIndicationState TSmsDataCodingScheme::IndicationState() const
	{
	LOGGSMU1("TSmsDataCodingScheme::IndicationState()");

	TInt bits7to4=Bits7To4();
	TSmsIndicationState state=ESmsIndicationInactive;
	switch (bits7to4)
		{
		case (ESmsDCSMessageWaitingIndicationDiscardMessage):
		case (ESmsDCSMessageWaitingIndication7Bit):
		case (ESmsDCSMessageWaitingIndicationUCS2):
			{
			state=(TSmsIndicationState) (iValue&ESmsIndicationStateMask);
			break;
			}
		default:
		    LOGGSMU1("WARNING! default case has been reached");
            break;
  		}
	return state;
	} // TSmsDataCodingScheme::TSmsIndicationState


void TSmsDataCodingScheme::SetIndicationState(TSmsIndicationState aState)
	{
	LOGGSMU1("TSmsDataCodingScheme::SetIndicationState()");

	TInt bits7to4=Bits7To4();
	switch (bits7to4)
		{
		case (ESmsDCSMessageWaitingIndicationDiscardMessage):
		case (ESmsDCSMessageWaitingIndication7Bit):
		case (ESmsDCSMessageWaitingIndicationUCS2):
			{
			iValue=(TUint8) (aState | (iValue&(~ESmsIndicationStateMask)));
			break;
			}
		default:
		    LOGGSMU1("TSmsDataCodingScheme::SetIndicationState() WARNING! default case has been reached");
            break;
  		}
	} // TSmsDataCodingScheme::SetIndicationState


TSmsDataCodingScheme::TSmsIndicationType TSmsDataCodingScheme::IndicationType() const
	{
	LOGGSMU1("TSmsDataCodingScheme::IndicationType()");

	TInt bits7to4=Bits7To4();
	TSmsIndicationType type=ESmsVoicemailMessageWaiting;
	switch (bits7to4)
		{
		case (ESmsDCSMessageWaitingIndicationDiscardMessage):
		case (ESmsDCSMessageWaitingIndication7Bit):
		case (ESmsDCSMessageWaitingIndicationUCS2):
			{
			type=(TSmsIndicationType) (iValue&ESmsIndicationTypeMask);
			break;
			}
		default:
		    LOGGSMU1("TSmsDataCodingScheme::IndicationType() WARNING default case has been reached");
            break;
		}
	return type;
	} // TSmsDataCodingScheme::TSmsIndicationType


void TSmsDataCodingScheme::SetIndicationType(TSmsIndicationType aType)
	{
	LOGGSMU1("TSmsDataCodingScheme::SetIndicationType()");

	TInt bits7to4=Bits7To4();
	switch (bits7to4)
		{
		case (ESmsDCSMessageWaitingIndicationDiscardMessage):
		case (ESmsDCSMessageWaitingIndication7Bit):
		case (ESmsDCSMessageWaitingIndicationUCS2):
			{
			iValue=(TUint8) (aType | (iValue&(~ESmsIndicationTypeMask)));
			break;
			}
		default:
		    LOGGSMU1("TSmsDataCodingScheme::SetIndicationType() WARNING! default case has been reached");
            break;
 		}
	} // TSmsDataCodingScheme::SetIndicationType


/**
 *  Allocates and creates a CSmsAlphabetConverter object, specifying an Alphabet
 *  Coding scheme and a Binary flag.
 *  
 *  @param aCharacterSetConverter Pre-initialised character set converter
 *  @param aFs File system handle
 *  @param aSmsAlphabet Data coding scheme alphabet
 *  @param aIsBinary Set to true for WAP or compressed data
 *  @return New CSmsAlphabetConverter object
 *  @capability None
 */
EXPORT_C CSmsAlphabetConverter* CSmsAlphabetConverter::NewLC(CCnvCharacterSetConverter& aCharacterSetConverter,RFs& aFs,TSmsDataCodingScheme::TSmsAlphabet aSmsAlphabet,TBool aIsBinary)
	{
	LOGGSMU1("CSmsAlphabetConverter::NewLC()");

	CSmsAlphabetConverter* converter=new (ELeave)CSmsAlphabetConverter(aCharacterSetConverter,aFs,aSmsAlphabet,aIsBinary);
	CleanupStack::PushL(converter);
	converter->ConstructL();
	return converter;
	} // CSmsAlphabetConverter::NewLC


/**
 *  Destructor.
 *  @capability None
 */
EXPORT_C CSmsAlphabetConverter::~CSmsAlphabetConverter()
    {
    delete iConvertedNativeCharacters;
    delete iConvertedUDElements;
    delete iUnconvertedNativeCharacters;
    delete iUnconvertedUDElements;
    } // CSmsAlphabetConverter::NewLC


//
// C'tor - standard stuff
//
CSmsAlphabetConverter::CSmsAlphabetConverter(CCnvCharacterSetConverter& aCharacterSetConverter,RFs& aFs,TSmsDataCodingScheme::TSmsAlphabet aSmsAlphabet,TBool aIsBinary)
    : iCharacterSetConverter(aCharacterSetConverter),
    iFs(aFs),
    iSmsAlphabet(aSmsAlphabet),
    iIsBinary(aIsBinary),
    iUnconvertedNativeCharactersPtr(NULL,0),
    iUnconvertedUDElementsPtr(NULL,0)
    {
    } // CSmsAlphabetConverter::CSmsAlphabetConverter


//
// Ensures this is a supported character set if not binary conversion
//
void CSmsAlphabetConverter::ConstructL()
	{
	LOGGSMU1("CSmsAlphabetConverter::ConstructL()");


	if (!iIsBinary)
		{
		switch (iSmsAlphabet)
			{
			case TSmsDataCodingScheme::ESmsAlphabet7Bit:
			case TSmsDataCodingScheme::ESmsAlphabet8Bit:
			case TSmsDataCodingScheme::ESmsAlphabetUCS2:
				{
				// Supported
				break;
				}
			default:
				{
				// Not supported
				User::Leave(KErrGsmSMSDataCodingSchemeNotSupported);
				break;
				}
			}
		}
	} // CSmsAlphabetConverter::ConstructL


//
// Returns whether the character set converter is invoked.  Provided to allow
// clients to provided efficient converted length calculation where no
// conversion is required.
//
void CSmsAlphabetConverter::ConversionPropertiesL(TSmsAlphabetConversionProperties& aConversionProperties) const
	{
	LOGGSMU1("CSmsAlphabetConverter::ConversionPropertiesL()");


	// Set defaults
	aConversionProperties.iWidthConversion=ESmsAlphabetWidthConversionFixed;
	aConversionProperties.iUDElementsPerNativeCharacter=1;
	// Modify if different
	if (iIsBinary)
		return;
	switch (iSmsAlphabet)
		{
		case TSmsDataCodingScheme::ESmsAlphabet7Bit:
		case TSmsDataCodingScheme::ESmsAlphabet8Bit:
			{
			aConversionProperties.iWidthConversion=ESmsAlphabetWidthConversionVariable;
			break;
			}
		case TSmsDataCodingScheme::ESmsAlphabetUCS2:
			{
			aConversionProperties.iUDElementsPerNativeCharacter=sizeof(TText);
			break;
			}
		default:
			{
			User::Leave(KErrGsmSMSDataCodingSchemeNotSupported);
			}
		}
	} // CSmsAlphabetConverter::ConversionPropertiesL


/**
 *  Converts from the native character set to unpacked user data elements of the
 *  desired character set.
 *  
 *  The function stores the converted data internally.
 *  
 *  @param aNativeCharacters The native character set data (Unicode only)
 *  @return Converted characters
 *  @capability None
 */
EXPORT_C TPtrC8 CSmsAlphabetConverter::ConvertFromNativeL(const TDesC& aNativeCharacters)
	{
	LOGGSMU1("CSmsAlphabetConverter::ConvertFromNativeL()");

	TInt  numberOfUnconvertibleCharacters, numberOfDowngradedCharacters;

	return ConvertFromNativeL(aNativeCharacters, ESmsEncodingNone,
			                  numberOfUnconvertibleCharacters,
			                  numberOfDowngradedCharacters);
	} // CSmsAlphabetConverter::ConvertFromNativeL


/**
 *  Converts from the native character set to unpacked user data elements of the
 *  desired character set.
 *  
 *  The function stores the converted data internally.
 *  
 *  @param aNativeCharacters                 The native character set data (Unicode only)
 *  @param aNumberOfUnconvertibleCharacters  Number of characters unconverted
 *  @param aNumberOfDowngradedCharacters     Number of characters downgraded
 *  @param aEncoding                         Alternative 7bit encoding to used (if needed)
 * 
 *  @return Converted characters
 * 
 *  @capability None
 */
EXPORT_C TPtrC8 CSmsAlphabetConverter::ConvertFromNativeL(const TDesC& aNativeCharacters,
                                                          TSmsEncoding aEncoding,
                                                          TInt& aNumberOfUnconvertibleCharacters,
			                                              TInt& aNumberOfDowngradedCharacters)
	{
	LOGGSMU2("CSmsAlphabetConverter::ConvertFromNativeL(): aEncoding=%d", aEncoding);
	
	aNumberOfUnconvertibleCharacters = 0;
	aNumberOfDowngradedCharacters    = 0;

	// Check for some shortcuts
	if (iIsBinary ||  iSmsAlphabet == TSmsDataCodingScheme::ESmsAlphabet8Bit)
		{
		// Binary data stored as padded unicode
		TPtr8 outputPtr=CheckAllocBufferL(&iConvertedUDElements,aNativeCharacters.Length(),0);
		outputPtr.Copy(aNativeCharacters);
		iUnconvertedNativeCharactersPtr.Zero();
		return outputPtr;
		}
	else if (iSmsAlphabet==TSmsDataCodingScheme::ESmsAlphabetUCS2)
		{
		TInt nativeCharactersLength = aNativeCharacters.Length();
		// 16-bit copy with possible endianess correction
		TInt elementCount=nativeCharactersLength*2;
		TPtr8 outputPtr(CheckAllocBufferL(&iConvertedUDElements,elementCount,elementCount));
	    for (TInt i=0;i<nativeCharactersLength;i++)
		    {
		    outputPtr[2*i]=(TUint8)(aNativeCharacters[i]>>8);
		    outputPtr[2*i+1]=(TUint8)aNativeCharacters[i];
		    }
		iUnconvertedNativeCharactersPtr.Zero();
		return outputPtr;
		}
	else // No shortcuts, do proper conversion
		{
		PrepareForConversionFromNativeL(aEncoding);
		
		// Create input buffer
		TInt newInputLength=iUnconvertedNativeCharactersPtr.Length()+aNativeCharacters.Length();
		iUnconvertedNativeCharactersPtr.Set(CheckAllocBufferL(&iUnconvertedNativeCharacters,newInputLength,iUnconvertedNativeCharactersPtr.Length()));
		iUnconvertedNativeCharactersPtr.Append(aNativeCharacters);

		// Ensure buffer is at least the length of the input buffer
		TPtr8 outputPtr=CheckAllocBufferL(&iConvertedUDElements,iUnconvertedNativeCharactersPtr.Length(),0);

		TInt retryCount=0;
		TInt unconvertedCount=iUnconvertedNativeCharactersPtr.Length();
		while (unconvertedCount)
			{
			TInt  tempNumberOfUnconvertibleCharacters = 0;
			TInt  tempNumberOfDowngradedCharacters    = 0;
			
			// Get a pointer to unfilled area of output buffer
			TPtr8 fillPtr((TUint8*)outputPtr.Ptr()+outputPtr.Length(),0,outputPtr.MaxLength()-outputPtr.Length());
			// Try the conversion & get number of unconverted characters
			TInt newUnconvertedCount=iCharacterSetConverter.ConvertFromUnicode(fillPtr,iUnconvertedNativeCharactersPtr);
			if (newUnconvertedCount<0)
				break;

			// Compare what is converted with the original, to get downgrade count
			TPtr  tempBufPtr((TUint16*)iUnconvertedNativeCharactersPtr.Ptr(), 0, fillPtr.Length());
			TInt  offset      = aNativeCharacters.Length() - unconvertedCount;
			TInt  state       = CCnvCharacterSetConverter::KStateDefault;
			TInt  notRestored = iCharacterSetConverter.ConvertToUnicode(tempBufPtr, fillPtr, state);
			
			if (notRestored > 0)
				{
				tempNumberOfUnconvertibleCharacters += notRestored;
				}
			
			for (TInt pos = 0;  pos < tempBufPtr.Length();  pos++)
				{
				if (tempBufPtr[pos] != aNativeCharacters[offset + pos])
					{
					if (tempBufPtr[pos] != KReplacementCharacter)
						{
						tempNumberOfDowngradedCharacters++;
						}
					else
						{
						tempNumberOfUnconvertibleCharacters++;
						}
					}
				}

			//
			// If characters were downgraded or unconverted then replace them
			// with downgrades from the PREQ2090 converter.
			//
			if (tempNumberOfUnconvertibleCharacters > 0  &&
				aEncoding != ESmsEncodingNone)
				{
				HBufC8*  downgradesBuf = HBufC8::NewLC(iUnconvertedNativeCharactersPtr.Length());
				HBufC*  nativeBuf = HBufC::NewLC(iUnconvertedNativeCharactersPtr.Length());
				TPtr8  downgradesPtr = downgradesBuf->Des();
				TPtr  nativePtr = nativeBuf->Des();

				PrepareForConversionFromNativeL(ESmsEncodingNone);

				// Attempt to convert the text
	 			TInt ret = iCharacterSetConverter.ConvertFromUnicode(downgradesPtr, iUnconvertedNativeCharactersPtr);
		 		if (ret >= 0)
		 			{
					// Compare what is converted with the original...
					state       = CCnvCharacterSetConverter::KStateDefault;
					notRestored = iCharacterSetConverter.ConvertToUnicode(nativePtr, downgradesPtr, state);
						
					if (notRestored >= 0)
						{
						// Merge in the downgrades
						TInt  pos;
						
						for (pos = 0;  pos < tempBufPtr.Length();  pos++)
							{
							if (tempBufPtr[pos] != aNativeCharacters[offset + pos])
								{
								if (tempBufPtr[pos] != KReplacementCharacter)
									{
									tempBufPtr[pos] = nativePtr[pos];
									}
								}
							}

						// Reconvert...
						PrepareForConversionFromNativeL(aEncoding);

						newUnconvertedCount=iCharacterSetConverter.ConvertFromUnicode(fillPtr,iUnconvertedNativeCharactersPtr);
						if (newUnconvertedCount<0)
							break;

						// Recount the changed characters...
						tempNumberOfUnconvertibleCharacters = 0;
						tempNumberOfDowngradedCharacters    = 0;

						for (pos = 0;  pos < tempBufPtr.Length();  pos++)
							{
							if (tempBufPtr[pos] != aNativeCharacters[offset + pos])
								{
								if (tempBufPtr[pos] != KReplacementCharacter)
									{
									tempNumberOfDowngradedCharacters++;
									}
								else
									{
									tempNumberOfUnconvertibleCharacters++;
									}
								}
							}
		 				}
					}
				
				CleanupStack::PopAndDestroy(2, downgradesBuf);
				}

			//
			// Store these downgraded/unconvertible character counts...
			//
			aNumberOfDowngradedCharacters    += tempNumberOfDowngradedCharacters;
			aNumberOfUnconvertibleCharacters += tempNumberOfUnconvertibleCharacters;
			
			// Update original buffer length, check retry count and realloc if req'd
			outputPtr.SetLength(outputPtr.Length()+fillPtr.Length());
			if (newUnconvertedCount==unconvertedCount)
				{
				if (++retryCount>KMaxSmsAlphabetConversionRetries)
					{
					__ASSERT_DEBUG(EFalse,Panic(KGsmuPanicConversionRetriedOut));
					break;
					}
				}
			else
				{
				iUnconvertedNativeCharactersPtr.Delete(0,unconvertedCount-newUnconvertedCount);
				retryCount=0;
				}
			unconvertedCount=newUnconvertedCount;
			// Check for realloc
			if (unconvertedCount)
				outputPtr.Set(CheckAllocBufferL(&iConvertedUDElements,iConvertedUDElements->Length()+Max(unconvertedCount,KMinSmsAlphabetConversionAllocIncrement),outputPtr.Length()));
			}

		return outputPtr;
		}
	} // CSmsAlphabetConverter::ConvertFromNativeL


/**
 *  Converts the user data elements of the specified character set to the native
 *  character set.
 *  
 *  @param aUDElements The converted character set data
 * 
 *  @return Native character set data (Unicode only)
 * 
 *  @capability None
 */
EXPORT_C TPtrC CSmsAlphabetConverter::ConvertToNativeL(const TDesC8& aUDElements)
	{
	LOGGSMU1("CSmsAlphabetConverter::ConvertToNativeL()");

	return ConvertToNativeL(aUDElements, ESmsEncodingNone);
	} // CSmsAlphabetConverter::ConvertToNativeL


/**
 *  Converts the user data elements of the specified character set to the native
 *  character set.
 *  
 *  @param aUDElements The converted character set data
 *  @param aEncoding   Alternative 7bit encoding to used (if needed)
 * 
 *  @return Native character set data (Unicode only)
 * 
 *  @capability None
 */
EXPORT_C TPtrC CSmsAlphabetConverter::ConvertToNativeL(const TDesC8& aUDElements,
													   TSmsEncoding aEncoding)
	{
	LOGGSMU2("CSmsAlphabetConverter::ConvertToNativeL(): aEncoding=%d", aEncoding);

	// Check for some shortcuts
	if (iIsBinary ||  iSmsAlphabet == TSmsDataCodingScheme::ESmsAlphabet8Bit)
		{
		// Binary data stored as padded unicode
		TPtr16 outputPtr=CheckAllocBufferL(&iConvertedNativeCharacters,aUDElements.Length(),0);
		outputPtr.Copy(aUDElements);
		iUnconvertedUDElementsPtr.Zero();
		return outputPtr;
		}
	else if (iSmsAlphabet==TSmsDataCodingScheme::ESmsAlphabetUCS2)
		{
		// 16-bit copy with possible endianess correction
		TInt charCount=aUDElements.Length()/2;
		TPtr16 outputPtr=CheckAllocBufferL(&iConvertedNativeCharacters,charCount,charCount);
	    for (TInt i=0; i<charCount; i++)
		    {
		    outputPtr[i]=(TText)(aUDElements[2*i]<<8);
		    outputPtr[i]=(TText)(outputPtr[i]+(aUDElements[2*i+1]));
		    }
		iUnconvertedUDElementsPtr.Zero();
		return outputPtr;
		}
	else
		{
		PrepareForConversionToNativeL(aEncoding);

		// Create input buffer with unconverted characters prepended
		TInt newInputLength=iUnconvertedUDElementsPtr.Length()+aUDElements.Length();
		iUnconvertedUDElementsPtr.Set(CheckAllocBufferL(&iUnconvertedUDElements,newInputLength,iUnconvertedUDElementsPtr.Length()));
		iUnconvertedUDElementsPtr.Append(aUDElements);

		// Ensure buffer is at least the length of the input buffer
		TPtr outputPtr=CheckAllocBufferL(&iConvertedNativeCharacters,iUnconvertedUDElementsPtr.Length(),0);

		TInt retryCount=0;
		TInt unconvertedCount=iUnconvertedUDElementsPtr.Length();
		TInt state=CCnvCharacterSetConverter::KStateDefault;
		while (unconvertedCount)
			{
			// Get a pointer to unfilled area of output buffer
			TPtr16 fillPtr((TUint16*)outputPtr.Ptr()+outputPtr.Length(),0,outputPtr.MaxLength()-outputPtr.Length());
			// Try the conversion & get number of unconverted characters
			TInt newUnconvertedCount=iCharacterSetConverter.ConvertToUnicode(fillPtr,iUnconvertedUDElementsPtr,state);
			if (newUnconvertedCount<0)
				break;
			// Update original buffer length & check retry count
			outputPtr.SetLength(outputPtr.Length()+fillPtr.Length());
			if (newUnconvertedCount==unconvertedCount)
				{
				if (++retryCount>KMaxSmsAlphabetConversionRetries)
					{
					__ASSERT_DEBUG(EFalse,Panic(KGsmuPanicConversionRetriedOut));
					break;
					}
				}
			else
				{
				iUnconvertedUDElementsPtr.Delete(0,unconvertedCount-newUnconvertedCount);
				retryCount=0;
				}
			unconvertedCount=newUnconvertedCount;
			// Check for realloc
			if (unconvertedCount)
				outputPtr.Set(CheckAllocBufferL(&iConvertedNativeCharacters,iConvertedNativeCharacters->Length()+Max(unconvertedCount,KMinSmsAlphabetConversionAllocIncrement),outputPtr.Length()));
			}
		return outputPtr;
		}
	} // CSmsAlphabetConverter::ConvertToNativeL


/**
 *  Tests if the character is supported by the current character set.
 *  This function can be used with 7bit and 8bit alphabets.
 * 
 *  @param aChar  Character to investigate.
 * 
 *  @return  ETrue if the character is supported.
 * 
 *  @note Since the function is based on the old behaviour (pre-PREQ2090)
 *        it does not accept a downgraded character or alternative encoding
 *        as being supported.
 */
TBool CSmsAlphabetConverter::IsSupportedL(TChar aChar)
	{
	LOGGSMU2("[1] CSmsAlphabetConverter::IsSupportedL(aChar=0x%04x)", (TUint) aChar);

	TBool isDowngrade, isRequiresAlternativeEncoding;

    TBool  supported = IsSupportedL(aChar, ESmsEncodingNone,
            isDowngrade, isRequiresAlternativeEncoding);
	
	LOGGSMU2("CSmsAlphabetConverter::IsSupportedL(): supported=%d.", supported);

	return supported;
	} // CSmsAlphabetConverter::IsSupportedL


/**
 *  Tests if the descriptor text is supported by the current character set.
 *  This function can be used with 7bit and 8bit alphabets.
 * 
 *  @param aDes                                 Text string to check.
 *  @param aNumberOfUnconvertibleCharacters     Exit param for the number of
 *                                              characters unconvertible.
 *  @param aIndexOfFirstUnconvertibleCharacter  Exit param for the first
 *                                              unconverted character.
 * 
 *  @return  ETrue if the character is supported.
 */
TBool CSmsAlphabetConverter::IsSupportedL(const TDesC& aDes, TInt& aNumberOfUnconvertibleCharacters,
                                          TInt& aIndexOfFirstUnconvertibleCharacter)
	{
	LOGGSMU2("[2] CSmsAlphabetConverter::IsSupportedL(aDes=\"%S\")", &aDes);

	TInt desLength = aDes.Length();
	//
	// Initialise the exit params...
	//
	aNumberOfUnconvertibleCharacters    = 0;
	aIndexOfFirstUnconvertibleCharacter = desLength;

    //
    // Create buffers for the input converted to 7Bit and a buffer for it once
    // converted back again...
    //
    HBufC8* encodedBuf       = HBufC8::NewLC(desLength*2); // worse case
    HBufC*  backToUnicodeAfterStdBuf = HBufC::NewLC(desLength);
    TPtr8  encoded(encodedBuf->Des());
    TPtr  backToUnicodeAfterStd(backToUnicodeAfterStdBuf->Des());

    //
    // Convert the input string to standard 7bit (with downgrades if needed)...
    // 
    PrepareForConversionFromNativeL(ESmsEncodingNone);

    TInt  notConverted = iCharacterSetConverter.ConvertFromUnicode(encoded, aDes);

    if (notConverted > 0)
        {
        aNumberOfUnconvertibleCharacters += notConverted;
        }
    else if (notConverted < 0)
        {
        aNumberOfUnconvertibleCharacters = desLength;
        }
    
    //
    // Convert it back again to the native format...
    //
    TInt  state       = CCnvCharacterSetConverter::KStateDefault;
    TInt  notRestored = iCharacterSetConverter.ConvertToUnicode(backToUnicodeAfterStd, encoded, state);

    if (notRestored > 0)
        {
        aNumberOfUnconvertibleCharacters += notRestored;
        }
    else if (notRestored < 0)
        {
        aNumberOfUnconvertibleCharacters = desLength;
        }

    //
    // Work out if the string is acceptable as it is (e.g. no unconvertible
    // and no downgrades). We only need do this if the previous conversions were
    // complete with no issues.
    //
    for (TInt pos = desLength-1;  pos >= 0;  --pos)
        {
        if (backToUnicodeAfterStd[pos] != aDes[pos])
            {
            aNumberOfUnconvertibleCharacters++;
            aIndexOfFirstUnconvertibleCharacter = pos;
            }
        }
    
    CleanupStack::PopAndDestroy(backToUnicodeAfterStdBuf);
    CleanupStack::PopAndDestroy(encodedBuf);
	
	//
	// Useful logging...
	//
	TBool  supported = (aNumberOfUnconvertibleCharacters == 0);

	LOGGSMU2("CSmsAlphabetConverter::IsSupportedL(): aNumberOfUnconvertibleCharacters=%d.", aNumberOfUnconvertibleCharacters);
	LOGGSMU2("CSmsAlphabetConverter::IsSupportedL(): aIndexOfFirstUnconvertibleCharacter=%d.", aIndexOfFirstUnconvertibleCharacter);
	LOGGSMU2("CSmsAlphabetConverter::IsSupportedL(): supported=%d.", supported);

	return supported;
	} // CSmsAlphabetConverter::IsSupportedL


/**
 *  Tests if the character is supported by the current character set.
 *  This function can be used with 7bit and 8bit alphabets.
 * 
 *  @param aChar                         Character to investigate.
 *  @param aEncoding                     Alternative 7bit encoding (if used).
 *  @param aIsDowngrade                  Exit param set to ETrue if the
 *                                       character has to be downgraded.
 *  @param aRequiresAlternativeEncoding  Exit param set to ETrue if the
 *                                       alternative encoding has to be
 *                                       used to encode it.
 * 
 *  @return  ETrue if the character is supported.
 */
TBool CSmsAlphabetConverter::IsSupportedL(TChar aChar, TSmsEncoding aEncoding,
		                                  TBool& aIsDowngrade,
                                          TBool& aRequiresAlternativeEncoding)
	{
	LOGGSMU2("[3] CSmsAlphabetConverter::IsSupportedL(aChar=0x%04x)", (TUint) aChar);

	//
	// Convert the character...
	//
	TInt  numberOfUnconvertibleCharacters, numberOfDowngradedCharacters, 
            numberRequiringAlternativeEncoding, indexOfFirstUnconvertibleCharacter;
	TBuf<4>   toEncode;

	toEncode.SetLength(1);
	toEncode[0]=(TText)aChar;

	TBool supported = IsSupportedL(toEncode, aEncoding, 
	        numberOfUnconvertibleCharacters,
	        numberOfDowngradedCharacters,
	        numberRequiringAlternativeEncoding,
	        indexOfFirstUnconvertibleCharacter);

	//
	// Calculate the exit params...
	//
	aIsDowngrade                 = (numberOfDowngradedCharacters > 0);
	aRequiresAlternativeEncoding = (numberRequiringAlternativeEncoding > 0);
	    
	//
	// Useful logging...
	//
	LOGGSMU2("CSmsAlphabetConverter::IsSupportedL(): aIsDowngrade=%d.", aIsDowngrade);
	LOGGSMU2("CSmsAlphabetConverter::IsSupportedL(): aRequiresAlternativeEncoding=%d.", aRequiresAlternativeEncoding);
	LOGGSMU2("CSmsAlphabetConverter::IsSupportedL(): supported=%d.", supported);

	return supported;
	} // CSmsAlphabetConverter::IsSupportedL


/**
 *  Tests if the descriptor text is supported by the current character set.
 *  This function can be used with 7bit and 8bit alphabets.
 * 
 *  @param aDes                                 Text string to check.
 *  @param aEncoding                            Alternative 7bit encoding (if used).
 *  @param aNumberOfUnconvertibleCharacters     Exit param for the number of
 *                                              characters unconvertible.
 *  @param aNumberOfDowngradedCharacters        Exit param for the number of
 *                                              downgraded characters.
 *  @param aNumberRequiringAlternativeEncoding  Exit param for the number of
 *                                              characters requiring use of
 *                                              the alternative encoder.
 *  @param aIndexOfFirstUnconvertibleCharacter  Exit param for the first
 *                                              unconverted character.
 * 
 *  @return  ETrue if the character is supported.
 */
TBool CSmsAlphabetConverter::IsSupportedL(const TDesC& aDes, TSmsEncoding aEncoding,
										  TInt& aNumberOfUnconvertibleCharacters,
                                          TInt& aNumberOfDowngradedCharacters,
                                          TInt& aNumberRequiringAlternativeEncoding,
                                          TInt& aIndexOfFirstUnconvertibleCharacter)
	{
	LOGGSMU2("[4] CSmsAlphabetConverter::IsSupportedL(aDes=\"%S\")", &aDes);

	TInt desLength = aDes.Length();
	//
	// Initialise the exit params...
	//
	aNumberOfUnconvertibleCharacters    = 0;
	aNumberOfDowngradedCharacters       = 0;
	aNumberRequiringAlternativeEncoding = 0;
	aIndexOfFirstUnconvertibleCharacter = desLength;
	
	//
	// Create buffers for the input converted to 7Bit and a buffer for it once
	// converted back again...
	//
    HBufC8* encodedBuf       = HBufC8::NewLC(desLength*2); // worse case
    HBufC*  backToUnicodeAfterStdBuf = HBufC::NewLC(desLength);
    TPtr8  encoded(encodedBuf->Des());
    TPtr  backToUnicodeAfterStd(backToUnicodeAfterStdBuf->Des());

    //
    // Convert the input string to standard 7bit (with downgrades if needed)...
    // 
    PrepareForConversionFromNativeL(ESmsEncodingNone);

    TInt  notConverted = iCharacterSetConverter.ConvertFromUnicode(encoded, aDes);

    if (notConverted > 0)
        {
        aNumberOfUnconvertibleCharacters += notConverted;
        }
    else if (notConverted < 0)
        {
        aNumberOfUnconvertibleCharacters = desLength;
        }
    
    //
    // Convert it back again to the native format...
    //
    TInt  state       = CCnvCharacterSetConverter::KStateDefault;
    TInt  notRestored = iCharacterSetConverter.ConvertToUnicode(backToUnicodeAfterStd, encoded, state);

    if (notRestored > 0)
        {
        aNumberOfUnconvertibleCharacters += notRestored;
        }
    else if (notRestored < 0)
        {
        aNumberOfUnconvertibleCharacters = desLength;
        }

    //
    // Work out if the string is acceptable as it is (e.g. no unconvertible
    // and no downgrades).
    //
    for (TInt pos = desLength-1;  pos >= 0;  --pos)
        {
        if (backToUnicodeAfterStd[pos] != aDes[pos])
            {
            if (backToUnicodeAfterStd[pos] != KReplacementCharacter)
                {
                aNumberOfDowngradedCharacters++;
                }
            else
                {
                aNumberOfUnconvertibleCharacters++;
                aIndexOfFirstUnconvertibleCharacter = pos;
                }
            }
        }

    TInt  totalCharFaultsSoFar = aNumberOfUnconvertibleCharacters + 
                                    aNumberOfDowngradedCharacters;
    
    //
    // If the total unconvertible plus downgrades is zero, then there is nothing
    // more to do as the string can be converted to 7bit with no issues and no
    // other encoder is needed.
    //
    // Otherwise we have to look at the alternative encoder...
    //
    if (totalCharFaultsSoFar == 0)
        {
        //
        // We are done (the return counts are already zero and therefore
        // correct at this point too!).
        //
        }
    else if (iSmsAlphabet != TSmsDataCodingScheme::ESmsAlphabet7Bit  ||
             aEncoding == ESmsEncodingNone)
        {
        //
        // The string was not perfectly converted, but there is no alternative
        // encoder to try.  We are done.
        //
        }
    else
        {
        //
        // Initialise the params...
        //
        TInt  tmpDowngradedCharacters        = 0;
        TInt  tmpUnconvertibleCharacters     = 0;
        TInt  tmpIndexOfFirstUnconvertibleCharacter = desLength;
		
        //
        // Convert the input string to the alternative encoding...
        //
        PrepareForConversionFromNativeL(aEncoding);

        notConverted = iCharacterSetConverter.ConvertFromUnicode(encoded, aDes);
        if (notConverted > 0)
            {
            tmpUnconvertibleCharacters = notConverted;
            }
        else if (notConverted < 0)
            {
            tmpUnconvertibleCharacters = desLength;
            }

        //
        // Convert it back again to the native format...
        //
        HBufC*  backToUnicodeAfterAltBuf = HBufC::NewLC(desLength);
        TPtr  backToUnicodeAfterAlt(backToUnicodeAfterAltBuf->Des());
        TInt  state       = CCnvCharacterSetConverter::KStateDefault;
        TInt  notRestored = iCharacterSetConverter.ConvertToUnicode(backToUnicodeAfterAlt, encoded, state);

        if (notRestored > 0)
            {
            tmpUnconvertibleCharacters += notRestored;
            }
        else if (notRestored < 0)
            {
            tmpUnconvertibleCharacters = desLength;
            }

        //
        // Now work out which characters are downgrades, require alternative encoding
        // or are unsupported.
        //
        for (TInt pos = desLength-1;  pos >= 0;  --pos)
            {
            if (backToUnicodeAfterStd[pos] != aDes[pos])
                {
                // Not supported by standard encoder...
                if (backToUnicodeAfterAlt[pos] == aDes[pos])
                    {
                    // Supported by alternative encoder...
                    aNumberRequiringAlternativeEncoding++;
                    }
                else if (backToUnicodeAfterStd[pos] != KReplacementCharacter)
                    {
                    // Downgraded by standard encoder...
                    tmpDowngradedCharacters++;
                    }
                else if (backToUnicodeAfterAlt[pos] != KReplacementCharacter)
                    {
                    // Downgraded by alternative encoder...
                    tmpDowngradedCharacters++;
                    aNumberRequiringAlternativeEncoding++;
                    }
                else
                    {
                    // Unconvertible...
                    tmpUnconvertibleCharacters++;
                    tmpIndexOfFirstUnconvertibleCharacter = pos;
                    }
                }
            }

        // Is this better?  
        if ( totalCharFaultsSoFar >= (tmpUnconvertibleCharacters + tmpDowngradedCharacters) )
            {
            // Best conversion is the alternative conversion
            aNumberOfUnconvertibleCharacters     = tmpUnconvertibleCharacters;
            aNumberOfDowngradedCharacters        = tmpDowngradedCharacters;
            aIndexOfFirstUnconvertibleCharacter  = tmpIndexOfFirstUnconvertibleCharacter;
            }
        else
            {
            // Best conversion is the standard conversion
            aNumberRequiringAlternativeEncoding = 0;
            }
        
        CleanupStack::PopAndDestroy(backToUnicodeAfterAltBuf);
        }
    
    CleanupStack::PopAndDestroy(backToUnicodeAfterStdBuf);
    CleanupStack::PopAndDestroy(encodedBuf);

	//
	// Useful logging...
	//
	TBool  supported = (aNumberOfUnconvertibleCharacters == 0);

	LOGGSMU2("CSmsAlphabetConverter::IsSupportedL(): aNumberOfUnconvertibleCharacters=%d.", aNumberOfUnconvertibleCharacters);
	LOGGSMU2("CSmsAlphabetConverter::IsSupportedL(): aNumberOfDowngradedCharacters=%d.", aNumberOfDowngradedCharacters);
	LOGGSMU2("CSmsAlphabetConverter::IsSupportedL(): aNumberRequiringAlternativeEncoding=%d.", aNumberRequiringAlternativeEncoding);
	LOGGSMU2("CSmsAlphabetConverter::IsSupportedL(): aIndexOfFirstUnconvertibleCharacter=%d.", aIndexOfFirstUnconvertibleCharacter);
	LOGGSMU2("CSmsAlphabetConverter::IsSupportedL(): supported=%d.", supported);

	return supported;
	} // CSmsAlphabetConverter::IsSupportedL


/**
 *  Given a piece of text and an alternative encoding, this function works out
 *  which encoding is best to use and returns the ID of that converter.
 * 
 *  @param aNativeCharacters      Text to use as a sample.
 *  @param aEncoding              Suggested alternative 7bit encoding method.
 * 
 *  @return Encoding that should be used.
 */
TSmsEncoding CSmsAlphabetConverter::FindBestAlternativeEncodingL(const TDesC& aNativeCharacters,
									                     		 TSmsEncoding aSuggestedEncoding)
	{
	LOGGSMU2("CSmsAlphabetConverter::FindBestAlternativeEncodingL(): aSuggestedEncoding=%d",
			 aSuggestedEncoding);

	TSmsEncoding  encodingToUse = ESmsEncodingNone;

	//
	// If this is not 7bit or the alternative encoding is not set then do
	// nothing...
	//
	if (aSuggestedEncoding != ESmsEncodingNone  &&
		iSmsAlphabet == TSmsDataCodingScheme::ESmsAlphabet7Bit)
		{
		TInt  numberOfUnconvertibleCharacters, numberOfDowngradedCharacters;
		TInt  numberRequiringAlternativeEncoding, indexOfFirstUnconvertibleCharacter;
		
		//
		// First try the default encoding (but in this case treat downgrades
		// as unconverted, since later encoders might do better)...
		//
		IsSupportedL(aNativeCharacters, ESmsEncodingNone,
					 numberOfUnconvertibleCharacters,
                     numberOfDowngradedCharacters,
                     numberRequiringAlternativeEncoding,
                     indexOfFirstUnconvertibleCharacter);

		TInt leastUnconvertibleCharacters = numberOfUnconvertibleCharacters + numberOfDowngradedCharacters;

		//
		// Create a list of alternative encodings to try...
		//
		TSmsEncoding  encodingList[8];
		TInt          encodingCount = 0;
		
		if (aSuggestedEncoding == ESmsEncodingTurkishLockingAndSingleShift)
			{
			encodingList[encodingCount++] = ESmsEncodingTurkishSingleShift;
			encodingList[encodingCount++] = ESmsEncodingTurkishLockingShift;
			}
		else if (aSuggestedEncoding == ESmsEncodingPortugueseLockingAndSingleShift)
			{
			encodingList[encodingCount++] = ESmsEncodingPortugueseSingleShift;
			encodingList[encodingCount++] = ESmsEncodingPortugueseLockingShift;
			}

		encodingList[encodingCount++] = aSuggestedEncoding;
		encodingList[encodingCount++] = ESmsEncodingNone;

		//
		// Now try the all the alternatives...
		//
		for (TInt  encoder = 0;  encoder < encodingCount;  encoder++)
			{
			IsSupportedL(aNativeCharacters, encodingList[encoder],
						 numberOfUnconvertibleCharacters,
	                     numberOfDowngradedCharacters,
	                     numberRequiringAlternativeEncoding,
	                     indexOfFirstUnconvertibleCharacter);
			if (numberOfUnconvertibleCharacters + numberOfDowngradedCharacters < leastUnconvertibleCharacters)
				{
				encodingToUse = encodingList[encoder];
				leastUnconvertibleCharacters = numberOfUnconvertibleCharacters + numberOfDowngradedCharacters;
				}
			}
		}

	LOGGSMU2("CSmsAlphabetConverter::FindBestAlternativeEncodingL(): encodingToUse=%d", encodingToUse);

	return encodingToUse;
	} // CSmsAlphabetConverter::FindBestAlternativeEncoding


/**
 *  Confirms that the requested encoding method is present (e.g. the converter
 *  plug-in can be loaded).
 * 
 *  @param aEncoding  Alternative 7bit encoding method.
 * 
 *  @leave KErrNotSupported if the encoder is not available.
 */
void CSmsAlphabetConverter::ConfirmAlternativeEncoderL(TSmsEncoding aEncoding) const
	{
	//
	// Check the ID for the encoder exists...
	//
	if (aEncoding != ESmsEncodingNone)
		{
		TUint  encoderID;
		
		GetAlternativeEncoderIDL(aEncoding, encoderID);
		
		//
		// Confirm it can be loaded...
		//
		if (iCharacterSetConverter.PrepareToConvertToOrFromL(encoderID, iFs) != CCnvCharacterSetConverter::EAvailable)
			{
			User::Leave(KErrNotSupported);
			}
		}
	} // CSmsAlphabetConverter::ConfirmAlternativeEncoderL


/**
 *  Prepares the converted for conversion from native charset.
 *  Character set specific preparation is performed here.
 * 
 *  @param aEncoding  Alternative 7bit encoding to use if required.
 */
void CSmsAlphabetConverter::PrepareForConversionFromNativeL(TSmsEncoding aEncoding)
	{
	LOGGSMU2("CSmsAlphabetConverter::PrepareForConversionFromNativeL(): aEncoding=%d",
			 aEncoding);

	__ASSERT_DEBUG(iIsBinary==EFalse,Panic(KGsmuPanicUnsupportedAlphabet));
	switch (iSmsAlphabet)
		{
		case TSmsDataCodingScheme::ESmsAlphabet7Bit:
			{
			//
			// If an alternative encoding has been specified then try and
			// load that converter...
			//
			if (aEncoding != ESmsEncodingNone)
				{
				TUint  alternativeEncoderID;
				
				GetAlternativeEncoderIDL(aEncoding, alternativeEncoderID);
				if (alternativeEncoderID != 0)
					{
					CCnvCharacterSetConverter::TAvailability  availability;
		
					LOGGSMU2("CSmsAlphabetConverter::PrepareForConversionFromNativeL(): Converter 0x%08x",
							 alternativeEncoderID);
					
					availability = iCharacterSetConverter.PrepareToConvertToOrFromL(alternativeEncoderID, iFs);
					if (availability == CCnvCharacterSetConverter::EAvailable)
						{
			 			// Force unicode line termination characters to simple line feed
			 			iCharacterSetConverter.SetDowngradeForExoticLineTerminatingCharacters(
				 				CCnvCharacterSetConverter::EDowngradeExoticLineTerminatingCharactersToJustLineFeed);
					
						// Job done, return
			 			return;
						}
					
					// Plug-in could not be loaded, so drop through and load the default!
					}
				}
			
			//
			// Check for the PREQ2090 7bit converter with Eastern European
			// downgrade support first, otherwise if the plug-in is not found
			// use the standard internal converter.
			//
			CCnvCharacterSetConverter::TAvailability  availability;
			
			availability = iCharacterSetConverter.PrepareToConvertToOrFromL(KCharacterSetIdentifierExtendedSms7Bit, iFs);
			if (availability == CCnvCharacterSetConverter::ENotAvailable)
				{
				availability = iCharacterSetConverter.PrepareToConvertToOrFromL(KCharacterSetIdentifierSms7Bit, iFs);
				if (availability == CCnvCharacterSetConverter::ENotAvailable)
					{
					User::Leave(KErrNotFound);
					}
				}

 			// Force unicode line termination characters to simple line feed
 			iCharacterSetConverter.SetDowngradeForExoticLineTerminatingCharacters(
 				CCnvCharacterSetConverter::EDowngradeExoticLineTerminatingCharactersToJustLineFeed);
			break;
			}
		case TSmsDataCodingScheme::ESmsAlphabet8Bit:
			{
			CCnvCharacterSetConverter::TAvailability availability=iCharacterSetConverter.PrepareToConvertToOrFromL(KCharacterSetIdentifierCodePage1252,iFs);
			if (availability==CCnvCharacterSetConverter::ENotAvailable)
				{
				User::Leave(KErrNotFound);
				}

 			// Force unicode line termination characters to simple line feed
 			iCharacterSetConverter.SetDowngradeForExoticLineTerminatingCharacters(
 				CCnvCharacterSetConverter::EDowngradeExoticLineTerminatingCharactersToJustLineFeed);
			break;
			}
		case TSmsDataCodingScheme::ESmsAlphabetUCS2:
		default:
			{
            User::Leave(KErrNotSupported);
			}
		}
	} // CSmsAlphabetConverter::PrepareForConversionFromNativeL


/**
 *  Prepares the converted for conversion to unicode.  Character set
 *  specific preparation is performed here.
 * 
 *  @param aEncoding  Alternative 7bit encoding to use if required.
 */
void CSmsAlphabetConverter::PrepareForConversionToNativeL(TSmsEncoding aEncoding)
	{
	LOGGSMU2("CSmsAlphabetConverter::PrepareForConversionToNativeL(): aEncoding=%d",
			 aEncoding);

	switch (iSmsAlphabet)
		{
		case TSmsDataCodingScheme::ESmsAlphabet7Bit:
			{
			//
			// If an alternative encoding has been specified then try and
			// load that converter...
			//
			if (aEncoding != ESmsEncodingNone)
				{
				TUint  alternativeEncoderID;
				
				GetAlternativeEncoderIDL(aEncoding, alternativeEncoderID);
				if (alternativeEncoderID != 0)
					{
					CCnvCharacterSetConverter::TAvailability  availability;
		
					LOGGSMU2("CSmsAlphabetConverter::PrepareForConversionFromNativeL(): Converter 0x%08x",
							 alternativeEncoderID);
					
					availability = iCharacterSetConverter.PrepareToConvertToOrFromL(alternativeEncoderID, iFs);
					if (availability == CCnvCharacterSetConverter::EAvailable)
						{
						// Job done, return
			 			return;
						}
					
					// Plug-in could not be loaded, so drop through and load the default!
					}
				}
			
			//
			// Always use the internal converter, as it is quicker to prepare
			// and the PREQ2090 7bit converter with Eastern European downgrade
			// offers no benefit when converting to native.
			//
			CCnvCharacterSetConverter::TAvailability availability=iCharacterSetConverter.PrepareToConvertToOrFromL(KCharacterSetIdentifierSms7Bit,iFs);
			if (availability==CCnvCharacterSetConverter::ENotAvailable)
				{
				User::Leave(KErrNotFound);
				}
			break;
			}
		case TSmsDataCodingScheme::ESmsAlphabet8Bit:
			{
			CCnvCharacterSetConverter::TAvailability availability=iCharacterSetConverter.PrepareToConvertToOrFromL(KCharacterSetIdentifierCodePage1252,iFs);
			if (availability==CCnvCharacterSetConverter::ENotAvailable)
				{
				User::Leave(KErrNotFound);
				}
			break;
			}
		case TSmsDataCodingScheme::ESmsAlphabetUCS2:
		default:
			{
			User::Leave(KErrNotSupported);
			}
		}
	} // CSmsAlphabetConverter::PrepareForConversionToNativeL


/**
 *  This function returns the alternative encoding converters that are used
 *  incase the default GSM encoding cannot encode the message completely
 *  without data loss.
 * 
 *  @param aEncoding   Encoding to obtain the converter for.
 *  @param aEncoderID  Returned converter UID if present.
 * 
 *  @leave KErrArgument if the encoding enum is invalid or
 */
void CSmsAlphabetConverter::GetAlternativeEncoderIDL(TSmsEncoding aEncoding, TUint& aEncoderID) const
	{
	LOGGSMU2("CSmsAlphabetConverter::GetAlternativeEncoderIDL(%d)", aEncoding);

	aEncoderID = 0;
	
	//
	// Decide on appropriate encoders.
	//
	switch (aEncoding)
		{
		case ESmsEncodingNone:
			{
			// Nothing to set.
			}
			break;
		
		case ESmsEncodingTurkishSingleShift:
			{
			aEncoderID = KCharacterSetIdentifierTurkishSingleSms7Bit;
			}
			break;
		
		case ESmsEncodingTurkishLockingShift:
			{
			aEncoderID = KCharacterSetIdentifierTurkishLockingSms7Bit;
			}
			break;
		
		case ESmsEncodingTurkishLockingAndSingleShift:
			{
			aEncoderID = KCharacterSetIdentifierTurkishLockingAndSingleSms7Bit;
			}
			break;
		
		case ESmsEncodingSpanishSingleShift:
			{
			aEncoderID = KCharacterSetIdentifierSpanishSingleSms7Bit;
			}
			break;
		
		case ESmsEncodingPortugueseSingleShift:
			{
			aEncoderID = KCharacterSetIdentifierPortugueseSingleSms7Bit;
			}
			break;
		
		case ESmsEncodingPortugueseLockingShift:
			{
			aEncoderID = KCharacterSetIdentifierPortugueseLockingSms7Bit;
			}
			break;
		
		case ESmsEncodingPortugueseLockingAndSingleShift:
			{
			aEncoderID = KCharacterSetIdentifierPortugueseLockingAndSingleSms7Bit;
			}
			break;

		default:
			{
			//
			// Invalid encoder method!
			//
			User::Leave(KErrArgument);
			}
		};
	} // CSmsAlphabetConverter::GetAlternativeEncoderIDL


//
// Ensures the allocated 16 bit buffer is at least of the specified length
//
TPtr16 CSmsAlphabetConverter::CheckAllocBufferL(HBufC16** aBuffer,TInt aMaxLength,TInt aUsedLength)
	{
	LOGGSMU1("CSmsAlphabetConverter::CheckAllocBufferL()");

	if (*aBuffer!=NULL)
		{
		if ((*aBuffer)->Length()<aMaxLength)
			{
			*aBuffer=(*aBuffer)->ReAllocL(aMaxLength);
			(*aBuffer)->Des().SetLength(aMaxLength);
			}
		}
	else
		{
		*aBuffer=HBufC16::NewMaxL(aMaxLength);
		}
	return TPtr16((TUint16*)(*aBuffer)->Des().Ptr(),aUsedLength,(*aBuffer)->Length());
	} // CSmsAlphabetConverter::CheckAllocBufferL


//
// Ensures the allocated 8 bit buffer is at least of the specified length
//
TPtr8 CSmsAlphabetConverter::CheckAllocBufferL(HBufC8** aBuffer,TInt aMaxLength,TInt aUsedLength)
	{
	LOGGSMU1("CSmsAlphabetConverter::CheckAllocBufferL()");

	if (*aBuffer!=NULL)
		{
		if ((*aBuffer)->Length()<aMaxLength)
			{
			*aBuffer=(*aBuffer)->ReAllocL(aMaxLength);
			(*aBuffer)->Des().SetLength(aMaxLength);
			}
		}
	else
		{
		*aBuffer=HBufC8::NewMaxL(aMaxLength);
		}
	return TPtr8((TUint8*)(*aBuffer)->Des().Ptr(),aUsedLength,(*aBuffer)->Length());
	} // CSmsAlphabetConverter::CheckAllocBufferL


/**
 *  @internalComponent
 *  
 *  Determines whether the address format matches the specified type.
 *  
 *  @param aType Specifies an indicator type, as defined in the Common PCN Handset Specification
 *  @return returns ETrue if address is of specified type, EFalse otherwise 
 */
EXPORT_C TBool TGsmSmsTelNumber::IsInstanceOf(TTypeOfIndicator aType)
    {
    LOGGSMU1("TGsmSmsTelNumber::IsInstanceOf()");

    TBool rc = EFalse;

    (void) aType;

    if((aType == EVoiceMessageWaitingIndicator)
     && ((iTypeOfAddress & TGsmSmsTypeOfAddress::EGsmSmsTONMask)==EGsmSmsTONAlphaNumeric)
     && (iTelNumber.Length()==ECPHSSizeOfAddressField)
     && ((iTelNumber[ECPHSAddressIndicatorType] & ECPSHIndicatorTypeBitMask) == ECPSHVoiceMailId)
     && ((iTelNumber[ECPHSAddressIndicatorId] & ECPSHIndicatorIdBitMask) == ECPSHIndicatorId ))
      rc = ETrue;

    return rc;
    } // TGsmSmsTelNumber::IsInstanceOf


//
// CSmsAddress
//

CSmsAddress* CSmsAddress::NewL(CCnvCharacterSetConverter& aCharacterSetConverter,RFs& aFs)
	{
	LOGGSMU1("CSmsAddress::NewL()");

	CSmsAddress* address=new(ELeave) CSmsAddress(aCharacterSetConverter,aFs);
	CleanupStack::PushL(address);
	TPtrC ptr;
	address->SetAddressL(ptr);
	CleanupStack::Pop();
	return address;
	} // CSmsAddress::NewL


CSmsAddress::~CSmsAddress()
    {
    delete iBuffer;
    } // CSmsAddress::NewL


/**
 *  Duplicates this CSmsAddress object.
 * 
 *  @return  Pointer to the newly created CSmsAddress object.
 */
CSmsAddress* CSmsAddress::DuplicateL() const
	{
	LOGGSMU1("CSmsAddress::DuplicateL()");

	CSmsAddress*  address = CSmsAddress::NewL(iCharacterSetConverter, iFs);
	CleanupStack::PushL(address);

	address->SetRawAddressL(iTypeOfAddress, *iBuffer);
	
	CleanupStack::Pop();

	return address;
	} // CSmsAddress::DuplicateL


TPtrC CSmsAddress::Address() const
	{
	LOGGSMU1("CSmsAddress::Address()");

	TPtrC ptr;
	if (iBuffer)
		ptr.Set(iBuffer->Des());
	return ptr;
	} // CSmsAddress::Address


void CSmsAddress::SetRawAddressL(TGsmSmsTypeOfAddress aTypeOfAddress, TPtrC aBufferPtr)
    {
    LOGGSMU1("CSmsAddress::SetRawAddressL()");

    iTypeOfAddress = aTypeOfAddress;

    NewBufferL(aBufferPtr.Length());

	*iBuffer=aBufferPtr;
    } // CSmsAddress::SetRawAddressL


TGsmSmsTypeOfAddress& CSmsAddress::TypeOfAddress()
    {
    LOGGSMU1("CSmsAddress::TypeOfAddress()");

    return iTypeOfAddress;
    } // CSmsAddress::TypeOfAddress


void CSmsAddress::SetAddressL(const TDesC& aAddress)
	{
	LOGGSMU1("CSmsAddress::SetAddressL()");

	TInt length=aAddress.Length();
	NewBufferL(length);
	iBuffer->Des().Copy(aAddress);

	const TGsmSmsTypeOfNumber typeofnumber=length && (iBuffer->Des()[0]=='+')? EGsmSmsTONInternationalNumber: EGsmSmsTONUnknown;
	iTypeOfAddress.SetTON(typeofnumber);
	} // CSmsAddress::SetAddressL


void CSmsAddress::ParsedAddress(TGsmSmsTelNumber& aParsedAddress) const
	{
	aParsedAddress.iTypeOfAddress = iTypeOfAddress;

	TInt maxparsedlength=aParsedAddress.iTelNumber.MaxLength();

	if (iTypeOfAddress.TON()==EGsmSmsTONAlphaNumeric)
		{
		TInt parsedlength=Address().Length();
		if (parsedlength>maxparsedlength)
			parsedlength=maxparsedlength;
		aParsedAddress.iTelNumber.Copy(Address().Mid(0,parsedlength));
		}
	else
		{
		aParsedAddress.iTelNumber.SetLength(maxparsedlength);

		TInt length=iBuffer->Des().Length();
		TInt parsedlength=0;
		for (TInt i=0; (i<length) && (parsedlength<maxparsedlength); i++)
			{
			TText ch=iBuffer->Des()[i];
            switch(ch)
                {
                case '*':
                case '#':
                case 'a':
                case 'b':
                case 'c':
                    aParsedAddress.iTelNumber[parsedlength]=(TUint8) ch;
                    parsedlength++;
                    break;                    
                default:
                    if ((ch>='0') && (ch<='9'))
                        {
                        aParsedAddress.iTelNumber[parsedlength]=(TUint8) ch;
                        parsedlength++;
                        }
                    break;
                }			
			}

		aParsedAddress.iTelNumber.SetLength(parsedlength);
		}
	}


void CSmsAddress::SetParsedAddressL(const TGsmSmsTelNumber& aParsedAddress)
	{
	LOGGSMU1("CSmsAddress::SetParsedAddressL()");

	iTypeOfAddress=aParsedAddress.iTypeOfAddress;
	DoSetParsedAddressL(aParsedAddress.iTelNumber);
	} // CSmsAddress::SetParsedAddressL


TUint8 CSmsAddress::SizeL()
    {
    LOGGSMU1("CSmsAddress::SizeL()");

    TUint8 size = 0;

    TBuf8<KSmsAddressMaxAddressLength> testBuffer;
    testBuffer.SetLength(KSmsAddressMaxAddressLength);
    TUint8* startPtr = &testBuffer[0];
    TUint8* endPtr = NULL;

    TRAPD(err,endPtr = EncodeL(startPtr));

    if (err != KErrNone)
        {
        User::Leave(KErrArgument);
        }
    else
        {
        // handle architectures whose address space increments or whose address space decrements.
        (endPtr > startPtr) ? (size = endPtr - startPtr) : (size = startPtr - endPtr);
        }

	return size;
    } // CSmsAddress::SizeL


TUint8* CSmsAddress::EncodeL(TUint8* aPtr) const
	{
	TGsmSmsTelNumber parsedaddress;
	ParsedAddress(parsedaddress);

	switch (iTypeOfAddress.TON())
		{
		case EGsmSmsTONAlphaNumeric:
			{
			// Mark buffer for length encoding after conversion
			TUint8* lengthPtr=aPtr++;
			// Encode type
			aPtr=iTypeOfAddress.EncodeL(aPtr);
			// 7-bit conversion
			TPtrC address=Address();
			TInt convertedNumUDUnits=0;
			TPtr8 packedPtr(aPtr,0,KSmsAddressMaxAddressValueLength);
			TSmsAlphabetPacker packer(TSmsDataCodingScheme::ESmsAlphabet7Bit,EFalse,0);
			aPtr+=packer.ConvertAndPackL(iCharacterSetConverter,iFs,packedPtr,address,convertedNumUDUnits);
			// Now encode length
			TSmsOctet length=(convertedNumUDUnits*7+3)/4;
			length.EncodeL(lengthPtr);
			break;
			}
		case EGsmSmsTONInternationalNumber:
		default:
			{
			TSmsOctet length=parsedaddress.iTelNumber.Length();
			if (length > KSmsAddressMaxAddressValueLength * 2)
			// each address value occupies one nibble.
                {
                User::Leave(KErrArgument);
                }
			aPtr=length.EncodeL(aPtr);
			aPtr=iTypeOfAddress.EncodeL(aPtr);
			TSmsOctet octet;
			for (TInt i=0; i<length; i++)
				{
                if ((i%2)==0)  //  even
                    {
                    switch(parsedaddress.iTelNumber[i])
                        {
                        case '*':
                            {
                            octet=10; // 1010 as a binary, according to 23.040 …
                            }
                            break;

                        case '#':
                            {
                            octet=11; // 1011 as a binary, according to 23.040…
                            }
                            break; 

                        case 'a':
                            {
                            octet=12; // 1100 as a binary, according to 23.040...
                            }
                            break;

                        case 'b':
                            {
                            octet=13; // 1101 as a binary, according to 23.040…
                            }
                            break;

                        case 'c':
                            {
                            octet=14; // 1110 as a binary, according to 23.040…
                            }
                            break;

                        default:
                            octet=(parsedaddress.iTelNumber[i])-'0';
                            break;
                        }
                    } 
                else
                    {
                    TInt tempOctet = 0;
       
                    switch(parsedaddress.iTelNumber[i])
                        {
                        case '*':
                            {
                            tempOctet=10; // 1010 as a binary, according to 23.040…
                            }
                            break;

                        case '#':
                            {
                            tempOctet=11; // 1011 as a binary, according to 23.040…
                            }
                            break;

                        case 'a':
                            {
                            tempOctet=12; // 1100 as a binary, according to 23.040…
                            }
                            break;

                        case 'b':
                            {
                            tempOctet=13; // 1101 as a binary, according to 23.040…
                            }
                            break;

                        case 'c':
                            {
                            tempOctet=14; // 1110 as a binary, according to 23.040…
                            }
                            break;

                        default:
                            tempOctet=(parsedaddress.iTelNumber[i])-'0';
                            break;
                        }
                    octet=octet|tempOctet<<4;
                    aPtr=octet.EncodeL(aPtr);				
				    }
                
			    } // end for loop

			if (length%2)   // odd number of semioctets
				{
				octet=octet|0xF0;
				aPtr=octet.EncodeL(aPtr);
				}
						
		    } // end default case
	    }
	return aPtr;
	}


void CSmsAddress::DecodeL(TGsmuLex8& aPdu)
	{
	TSmsOctet length;  //represents the number of valid semi-octets
	length.DecodeL(aPdu);
	iTypeOfAddress.DecodeL(aPdu);

	switch (iTypeOfAddress.TON())
		{
		case EGsmSmsTONAlphaNumeric:
			{
			const TUint cphs1 = aPdu.GetL();
			const TUint cphs2 = aPdu.GetL();
			aPdu.UnGet();
			aPdu.UnGet();

			const TPtrC8 remainder(aPdu.Remainder());
			// we assume that it is a cphs message waiting indicator
            // we might want to do further tests tobe sure that it is a CPHS message
			if(    (length==4)
				&& ((cphs1 & 0x7E) == 0x10) // x001 000x constant value
				&& ((cphs2 & 0x7E) == 0x00) // x000 000x constant value
			  )
				{
				TGsmSmsTelNumber parsedaddress;
				parsedaddress.iTelNumber.SetLength(length);
				//Copy the two bytes of the cphs message waiting address into the parsed address
				parsedaddress.iTelNumber[0]=(TUint8)length;
				parsedaddress.iTelNumber[1]= (TUint8)iTypeOfAddress;
				parsedaddress.iTelNumber[2]= (TUint8)aPdu.GetL();
				parsedaddress.iTelNumber[3]= (TUint8)aPdu.GetL();
				DoSetParsedAddressL(parsedaddress.iTelNumber);
				}
			else if(length==11 && remainder.Left(6).CompareF(KMOSES) ==KErrNone ) //check for MOSES
				{
					DoSetParsedAddressL(KNETWORK);
					aPdu.IncL(6);
				}
			else
				{
				// Encoded length is number of semi-octets used to store address using
				// 7-bit char set - determine number of user data units required
				const TInt numUDUnits=length*4/7;
				// Unpack the data - assume max converted length twice the unconverted length
				// VEP Why this assumption, the length will be doubled at the client because of that??
				// EXT-568BMW
				// Fix is not to multiply by 2
				//NewBufferL(2*numUDUnits);
				NewBufferL(numUDUnits);
				TPtr unpackedPtr((TText*)iBuffer->Des().Ptr(),0,iBuffer->Length());

				if (remainder.Length() < KSmsAddressMaxAddressValueLength)
					User::Leave(KErrGsmuDecoding);

				TPtrC8 packedPtr(remainder.Ptr(), KSmsAddressMaxAddressValueLength);
				TSmsAlphabetPacker unpacker(TSmsDataCodingScheme::ESmsAlphabet7Bit,EFalse,0);
				unpacker.UnpackAndConvertL(iCharacterSetConverter,iFs,packedPtr,unpackedPtr,numUDUnits);
				aPdu.IncL(length / 2);
				if ((length % 2) != 0)
					aPdu.IncL();
				}
			break;
			}
		case EGsmSmsTONInternationalNumber:
		default:
			{
			TGsmSmsTelNumber parsedaddress;
			if (length>parsedaddress.iTelNumber.MaxLength())
				User::Leave(KErrGsmuDecoding);
			parsedaddress.iTelNumber.SetLength(length);
			TSmsOctet octet;
			for (TInt i=0; i<length; i++)
				{
				if ((i%2)==0)  //  even
					{
                    TUint8 tempOctet = 0;
                    octet.DecodeL(aPdu);
                    tempOctet = (TUint8)octet&0x0F; // four topmost bits set to zero
                    
                    switch(tempOctet)
                        {
                        case 10: // 1010
                            {
                            parsedaddress.iTelNumber[i] = '*';
                            }
                            break;

                        case 11: // 1011
                            {
                            parsedaddress.iTelNumber[i] = '#';
                            }
                            break; 

                        case 12: // 1100
                            {
                            parsedaddress.iTelNumber[i] = 'a';
                            }
                            break;

                        case 13: //1101
                            {
                            parsedaddress.iTelNumber[i] = 'b'; 
                            }
                            break;

                        case 14: //1110
                            {
                            parsedaddress.iTelNumber[i] = 'c';
                            }
                            break;

                        case 15: 
                            // Skip if 1111 is received 
                            break;

                        default:
                            parsedaddress.iTelNumber[i]=(TUint8) (tempOctet+'0');
                            break;
                        }
					}
				else
                    {
                    TUint8 tempOctet = 0;
                    octet&0xF0; // four least significant bits…
                    tempOctet = (TUint8)octet>>4;

                    switch(tempOctet)
                        {
                        case 10: // 1010
                            {
                            parsedaddress.iTelNumber[i] = '*';
                            }
                            break;

                        case 11: // 1011
                            {
                            parsedaddress.iTelNumber[i] = '#';
                            }
                            break;

                        case 12: // 1100
                            {
                            parsedaddress.iTelNumber[i] = 'a';
                            }
                            break;

                        case 13: // 1101
                            {
                            parsedaddress.iTelNumber[i] = 'b';
                            }
                            break;

                        case 14: // 1110
                            {
                            parsedaddress.iTelNumber[i] = 'c';
                            }
                            break;

                        case 15: 
                            // Skip if 1111 is received 
                            break;

                        default:
                            parsedaddress.iTelNumber[i]=(TUint8) (tempOctet+'0'); 
                            // unwanted bits zeroed in the beginning
       
                            break;
                        }
                    }
				}
			DoSetParsedAddressL(parsedaddress.iTelNumber);
			}
		}
	}

void CSmsAddress::InternalizeL(RReadStream& aStream)
	{
	aStream >> iTypeOfAddress;
	HBufC* buffer=HBufC::NewL(aStream,256);
	delete iBuffer;
	iBuffer=buffer;
	} // CSmsAddress::InternalizeL


void CSmsAddress::ExternalizeL(RWriteStream& aStream) const
	{
	aStream << iTypeOfAddress;
	aStream << *iBuffer;
	} // CSmsAddress::ExternalizeL


CSmsAddress::CSmsAddress(CCnvCharacterSetConverter& aCharacterSetConverter,RFs& aFs):
	iCharacterSetConverter(aCharacterSetConverter),
	iFs(aFs),
	iTypeOfAddress(EGsmSmsTONUnknown, EGsmSmsNPIISDNTelephoneNumberingPlan)
	{
	} // CSmsAddress::CSmsAddress


void CSmsAddress::NewBufferL(TInt aLength)
	{
	LOGGSMU1("CSmsAddress::NewBufferL()");

    HBufC* buffer=HBufC::NewL(aLength);
    delete iBuffer;
    iBuffer=buffer;
    iBuffer->Des().SetLength(aLength);
    iBuffer->Des().FillZ();
	}


void CSmsAddress::DoSetParsedAddressL(const TDesC& aAddress)
	{
	LOGGSMU2("CSmsAddress::DoSetParsedAddressL() the length of the Address [Length = %d", aAddress.Length());

	TInt length=aAddress.Length();
	if ((iTypeOfAddress.TON()==EGsmSmsTONInternationalNumber) &&
	    (length && (aAddress[0]!='+')))
		{
		NewBufferL(length+1);
		iBuffer->Des()[0]='+';
		TPtr ptr((TText*) (iBuffer->Des().Ptr()+1),length,length);
		ptr.Copy(aAddress);
		}
	else
		{
		NewBufferL(length);
		iBuffer->Des().Copy(aAddress);
		}
	} // CSmsAddress::DoSetParsedAddressL


TSmsServiceCenterTimeStamp::TSmsServiceCenterTimeStamp()
	{
	iTimeZoneNumQuarterHours = 0;
	} // TSmsServiceCenterTimeStamp::TSmsServiceCenterTimeStamp


void TSmsServiceCenterTimeStamp::SetTimeOffset(TInt aNumQuarterHours)
	{
	__ASSERT_DEBUG((aNumQuarterHours>=-KSmsMaxTimeZoneNumQuarterHours) && (aNumQuarterHours<=KSmsMaxTimeZoneNumQuarterHours),Panic(KGsmuPanicNumQuarterHoursOutOfRange));
	iTimeZoneNumQuarterHours=aNumQuarterHours;
	} // TSmsServiceCenterTimeStamp::SetTimeOffset


TUint8* TSmsServiceCenterTimeStamp::EncodeL(TUint8* aPtr) const
    {
    LOGGSMU1("TSmsServiceCenterTimeStamp::EncodeL()");

    TInt numquarterhours=iTimeZoneNumQuarterHours;

    TInt timeZoneOffsetInSeconds = numquarterhours * CSmsMessage::E15MinutesRepresentedInSeconds;
    TTimeIntervalSeconds offsetFromUTCToLocal(timeZoneOffsetInSeconds);

    TTime time = iTime;
    time += offsetFromUTCToLocal;

    TDateTime datetime=time.DateTime();

    TSmsOctet octet;
    octet.FillSemiOctets(datetime.Year()%100);
    aPtr=octet.EncodeL(aPtr);
    octet.FillSemiOctets(datetime.Month()+1);
    aPtr=octet.EncodeL(aPtr);
    octet.FillSemiOctets(datetime.Day()+1);
    aPtr=octet.EncodeL(aPtr);
    octet.FillSemiOctets(datetime.Hour());
    aPtr=octet.EncodeL(aPtr);
    octet.FillSemiOctets(datetime.Minute());
    aPtr=octet.EncodeL(aPtr);
    octet.FillSemiOctets(datetime.Second());
    aPtr=octet.EncodeL(aPtr);

    TInt signbit=ESmsTimeZonePositive;
    if (numquarterhours<0)
        {
        numquarterhours=-numquarterhours;
        signbit=ESmsTimeZoneNegative;
        }

    TSmsOctet timezone;
    timezone.FillSemiOctets(numquarterhours);
    timezone=timezone|signbit;
    return timezone.EncodeL(aPtr);
    } // TSmsServiceCenterTimeStamp::EncodeL


void TSmsServiceCenterTimeStamp::DecodeL(TGsmuLex8& aPdu, TInt& aTimeError)
	{
	LOGGSMU1("TSmsServiceCenterTimeStamp::DecodeL()");

	TSmsOctet octet;
	octet.DecodeL(aPdu);
	TInt year=octet.SemiOctetsToNum();
	if (year>95)
		year+=1900;
	else
		year+=2000;
	octet.DecodeL(aPdu);
	TInt month=octet.SemiOctetsToNum();
	octet.DecodeL(aPdu);

	TInt day=octet.SemiOctetsToNum();
	octet.DecodeL(aPdu);
	TInt hour=octet.SemiOctetsToNum();
	octet.DecodeL(aPdu);
	TInt minute=octet.SemiOctetsToNum();
	octet.DecodeL(aPdu);
	TInt second=octet.SemiOctetsToNum();

    TDateTime datetime;
    aTimeError = datetime.Set(year,(TMonth) (month-1),day-1,hour,minute,second,0);

    TSmsOctet timezone;
    timezone.DecodeL(aPdu);

    TInt signBit = (timezone&ESmsTimeZoneSignBitMask) ?  ESmsTimeZoneNegative : ESmsTimeZonePositive;
    timezone=timezone &(~ESmsTimeZoneSignBitMask); // clear sign bit

    TInt offsetToUTCInSeconds = 0;
    if (timezone.SemiOctetsToNum() <= KSmsMaxTimeZoneNumQuarterHours)
        {
        offsetToUTCInSeconds = ((TInt) timezone.SemiOctetsToNum()) * CSmsMessage::E15MinutesRepresentedInSeconds;
        if (signBit == ESmsTimeZoneNegative)    
            {
            offsetToUTCInSeconds = -offsetToUTCInSeconds;
            }

        TTimeIntervalSeconds offsetToUTC(offsetToUTCInSeconds) ;      

        if (aTimeError == KErrNone)
            {
            TTime time = datetime;    	
            time -= offsetToUTC;
            iTime = time;
    	
            iTimeZoneNumQuarterHours=(signBit == ESmsTimeZonePositive) ? timezone.SemiOctetsToNum(): -timezone.SemiOctetsToNum();
            }
            
        }
    else // Time zone out of range, set to 0 per 23.040 4.4.0 Section 9.2.3.11
        {
    	if (aTimeError == KErrNone)
            {    		
            iTime = datetime;    	
    	    iTimeZoneNumQuarterHours=0;
    	    }            
        }
	} // TSmsServiceCenterTimeStamp::DecodeL


void TSmsServiceCenterTimeStamp::InternalizeL(RReadStream& aStream)
	{
	TInt64 time;
	aStream >> time;
	iTime=time;
	iTimeZoneNumQuarterHours=aStream.ReadInt32L();
	} // TSmsServiceCenterTimeStamp::InternalizeL


void TSmsServiceCenterTimeStamp::ExternalizeL(RWriteStream& aStream) const
	{
	aStream << iTime.Int64();
	aStream.WriteInt32L(iTimeZoneNumQuarterHours);
	} // TSmsServiceCenterTimeStamp::ExternalizeL


TSmsValidityPeriod::TSmsValidityPeriod(TSmsFirstOctet& aFirstOctet):
	iFirstOctet(aFirstOctet),
	iTimeIntervalMinutes(EOneDayUnitInMinutes)
	{
	} // TSmsValidityPeriod::TSmsValidityPeriod


TTime TSmsValidityPeriod::Time() const
	{
	LOGGSMU1("TSmsValidityPeriod::Time()");

	TTime time;
	time.UniversalTime();
	time+=iTimeIntervalMinutes;
	return time;
	} // TSmsValidityPeriod::Time


TUint8* TSmsValidityPeriod::EncodeL(TUint8* aPtr) const
	{
	LOGGSMU1("TSmsValidityPeriod::EncodeL()");

	TInt validityperiodformat=ValidityPeriodFormat();
	switch (validityperiodformat)
		{
		case (TSmsFirstOctet::ESmsVPFNone):
			break;
		case (TSmsFirstOctet::ESmsVPFInteger):
			{
			TInt timeintervalminutes=iTimeIntervalMinutes.Int();
			__ASSERT_DEBUG((timeintervalminutes>=EFiveMinuteUnitInMinutes) && (timeintervalminutes<=63*EOneWeekUnitLimitInMinutes),Panic(KGsmuPanicValidityPeriodOutOfRange));
			TSmsOctet octet;
			if (timeintervalminutes<=EFiveMinuteUnitLimitInMinutes)
                octet=((timeintervalminutes/EFiveMinuteUnitInMinutes)-1);
			else if (timeintervalminutes<=EHalfHourUnitLimitInMinutes)
                octet=(((timeintervalminutes-(EHalfHourUnitLimitInMinutes/2))/EHalfHourUnitInMinutes)+EFiveMinuteUnitLimit);

			else if (timeintervalminutes<=EOneDayUnitLimitInMinutes)
                octet=((timeintervalminutes/EOneDayUnitInMinutes)+166);
			else
                octet=((timeintervalminutes/EOneWeekUnitInMinutes)+192);

			aPtr=octet.EncodeL(aPtr);
			break;
			}
		case (TSmsFirstOctet::ESmsVPFSemiOctet):
			{
			TSmsServiceCenterTimeStamp timestamp;
			timestamp.SetTime(Time());

	 		TTimeIntervalSeconds timeIntervalInSeconds(User::UTCOffset());
			timestamp.SetTimeOffset(timeIntervalInSeconds.Int() / CSmsMessage::E15MinutesRepresentedInSeconds);

			aPtr=timestamp.EncodeL(aPtr);
			break;
			}
		default:
            __ASSERT_DEBUG(EFalse,Panic(KGsmuPanicUnsupportedValidityPeriodFormat));
			User::Leave(KErrGsmSMSTPVPFNotSupported);
            break;
		};
	return aPtr;
	} // TSmsValidityPeriod::EncodeL
	
TUint8* TSmsValidityPeriod::EncodeL(TUint8* aPtr, const TEncodeParams* aEncodeParams) const
	{
	LOGGSMU1("TSmsValidityPeriod::EncodeL()");

	TInt validityperiodformat=ValidityPeriodFormat();
	switch (validityperiodformat)
		{
		case (TSmsFirstOctet::ESmsVPFNone):
			break;
		case (TSmsFirstOctet::ESmsVPFInteger):
			{
			TInt timeintervalminutes=iTimeIntervalMinutes.Int();
			__ASSERT_DEBUG((timeintervalminutes>=EFiveMinuteUnitInMinutes) && (timeintervalminutes<=63*EOneWeekUnitLimitInMinutes),Panic(KGsmuPanicValidityPeriodOutOfRange));
			TSmsOctet octet;
			if (timeintervalminutes<=EFiveMinuteUnitLimitInMinutes)
                octet=((timeintervalminutes/EFiveMinuteUnitInMinutes)-1);
			else if (timeintervalminutes<=EHalfHourUnitLimitInMinutes)
                octet=(((timeintervalminutes-(EHalfHourUnitLimitInMinutes/2))/EHalfHourUnitInMinutes)+EFiveMinuteUnitLimit);

			else if (timeintervalminutes<=EOneDayUnitLimitInMinutes)
                octet=((timeintervalminutes/EOneDayUnitInMinutes)+166);
			else
                octet=((timeintervalminutes/EOneWeekUnitInMinutes)+192);

			aPtr=octet.EncodeL(aPtr);
			break;
			}
		case (TSmsFirstOctet::ESmsVPFSemiOctet):
			{			
			//The reason TSmsValidityPeriod::EncodeL(TUint8* aPtr, const TEncodeParams* aEncodeParams) was
			//created was to allow the CSmsMessage's time stamp to be used when generating the validity time.
			//The CSmsMessage's time stamp is typically created when the message is constructed by the SMS Stack client.
			//This means the validity time is based from the point the SMS Stack client actually sends the message, rather
			//than the SMS Stack encodes it
						
			TSmsServiceCenterTimeStamp timestamp;
			timestamp.SetTime( *aEncodeParams->iTimeStamp + iTimeIntervalMinutes ); 									    		    		    		    		    

	 		TTimeIntervalSeconds timeIntervalInSeconds( *aEncodeParams->iTimeIntervalInSeconds );
			timestamp.SetTimeOffset(timeIntervalInSeconds.Int() / CSmsMessage::E15MinutesRepresentedInSeconds);

			aPtr=timestamp.EncodeL(aPtr);
			break;
			}
		default:
            __ASSERT_DEBUG(EFalse,Panic(KGsmuPanicUnsupportedValidityPeriodFormat));
			User::Leave(KErrGsmSMSTPVPFNotSupported);
            break;
		};
	return aPtr;
	} // TSmsValidityPeriod::EncodeL	

void TSmsValidityPeriod::DecodeL(TGsmuLex8& aPdu)
	{
	LOGGSMU1("TSmsValidityPeriod::DecodeL()");

	TInt validityperiodformat=ValidityPeriodFormat();
	switch (validityperiodformat)
		{
		case (TSmsFirstOctet::ESmsVPFNone):
			break;
		case (TSmsFirstOctet::ESmsVPFInteger):
			{
			TSmsOctet octet;
			octet.DecodeL(aPdu);
            if (octet<=EFiveMinuteUnitLimit)
                iTimeIntervalMinutes=(octet+1)*EFiveMinuteUnitInMinutes;
			else if (octet<=EHalfHourUnitLimit)
                iTimeIntervalMinutes=((EOneDayUnitInMinutes/2)+((octet-EFiveMinuteUnitLimit)*EHalfHourUnitInMinutes));
			else if (octet<=EOneDayUnitLimit)
                iTimeIntervalMinutes=(octet-166)*EOneDayUnitInMinutes;
			else
                iTimeIntervalMinutes=(octet-192)*EOneWeekUnitInMinutes;
			break;
			}
		case (TSmsFirstOctet::ESmsVPFSemiOctet):
			{
			TSmsServiceCenterTimeStamp timestamp;
			TInt timeError;
			timestamp.DecodeL(aPdu, timeError);
			User::LeaveIfError(timeError);
			TTime time;
			time.UniversalTime();
			timestamp.Time().MinutesFrom(time,iTimeIntervalMinutes);
			break;
			}
		default:
            __ASSERT_DEBUG(EFalse,Panic(KGsmuPanicUnsupportedValidityPeriodFormat));
			User::Leave(KErrGsmSMSTPVPFNotSupported);
            break;
		};
	} // TSmsValidityPeriod::DecodeL


void TSmsValidityPeriod::InternalizeL(RReadStream& aStream)
	{
	TInt timeintervalinminutes=aStream.ReadInt32L();
	iTimeIntervalMinutes=timeintervalinminutes;
	} // TSmsValidityPeriod::InternalizeL


void TSmsValidityPeriod::ExternalizeL(RWriteStream& aStream) const
	{
	aStream.WriteInt32L(iTimeIntervalMinutes.Int());
	} // TSmsValidityPeriod::ExternalizeL


CSmsInformationElement* CSmsInformationElement::NewL(TSmsInformationElementIdentifier aIdentifier,const TDesC8& aData)
	{
	LOGGSMU1("CSmsInformationElement::NewL()");

	CSmsInformationElement* informationelement=new(ELeave) CSmsInformationElement(aIdentifier);
	CleanupStack::PushL(informationelement);
	informationelement->ConstructL(aData);
	CleanupStack::Pop();
	return informationelement;
	} // CSmsInformationElement::NewL


CSmsInformationElement* CSmsInformationElement::NewL()
	{
	LOGGSMU1("CSmsInformationElement::NewL()");

	CSmsInformationElement* informationelement=new(ELeave) CSmsInformationElement(ESmsIEIConcatenatedShortMessages8BitReference);
	CleanupStack::PushL(informationelement);
	TPtrC8 data;
	informationelement->ConstructL(data);
	CleanupStack::Pop();
	return informationelement;
	} // CSmsInformationElement::NewL


/**
 *  Destructor.
 */
CSmsInformationElement::~CSmsInformationElement()
	{
	delete iData;
	} // CSmsInformationElement::NewL


/**
 *  Gets the Information Element data.
 *  
 *  @return Information Element data
 *  @capability None
 */
EXPORT_C TPtr8 CSmsInformationElement::Data()
	{
	LOGGSMU1("CSmsInformationElement::Data()");

	return iData->Des();
	} // CSmsInformationElement::Data


/**
 *  Gets the (const) Information Element data.
 *  
 *  @return Information Element data
 *  @capability None
 */
EXPORT_C const TDesC8& CSmsInformationElement::Data() const
	{
	LOGGSMU1("CSmsInformationElement::Data()");

	return *iData;
	} // CSmsInformationElement::Data


/**
 *  Gets the Information Element Identifier.
 *  
 *  @return Information Element Identifier
 *  @capability None
 */
EXPORT_C CSmsInformationElement::TSmsInformationElementIdentifier CSmsInformationElement::Identifier() const
	{
	return TSmsId(TInt(iIdentifier));
	} // CSmsInformationElement::TSmsInformationElementIdentifier


TUint8* CSmsInformationElement::EncodeL(TUint8* aPtr) const
	{
	LOGGSMU1("CSmsInformationElement::EncodeL()");

	TSmsOctet id=iIdentifier;
	aPtr=id.EncodeL(aPtr);
	TSmsOctet informationelementlength=iData->Des().Length();
	aPtr=informationelementlength.EncodeL(aPtr);
	Mem::Copy(aPtr,iData->Des().Ptr(),informationelementlength);
	aPtr+=TInt(informationelementlength);
	return aPtr;
	} // CSmsInformationElement::EncodeL


void CSmsInformationElement::DecodeL(TGsmuLex8& aPdu)
	{
	LOGGSMU1("CSmsInformationElement::DecodeL()");

	TSmsOctet id;
	id.DecodeL(aPdu);
	iIdentifier=static_cast<TSmsInformationElementIdentifier>((TInt)id);

	TSmsOctet informationelementlength;
	informationelementlength.DecodeL(aPdu);

 	switch(iIdentifier)
 	{
 	case (ESmsIEIConcatenatedShortMessages8BitReference):
 		if(informationelementlength !=3)
 			User::Leave(KErrGsmSMSTpduNotSupported);
 		break;
 	case (ESmsIEISpecialSMSMessageIndication):
 		if(informationelementlength !=2)
 			User::Leave(KErrGsmSMSTpduNotSupported);
 		break;
 	case (ESmsIEIApplicationPortAddressing8Bit):
 		if(informationelementlength !=2)
 			User::Leave(KErrGsmSMSTpduNotSupported);
 		break;
 	case (ESmsIEIApplicationPortAddressing16Bit):
 		if(informationelementlength !=4)
 			User::Leave(KErrGsmSMSTpduNotSupported);
 		break;
 	case (ESmsIEISMSCControlParameters):
 		if(informationelementlength !=1)
 			User::Leave(KErrGsmSMSTpduNotSupported);
 		break;
 	case (ESmsIEIUDHSourceIndicator):
 		if(informationelementlength !=1)
 			User::Leave(KErrGsmSMSTpduNotSupported);
 		break;
 	case (ESmsIEIConcatenatedShortMessages16BitReference):
 		if(informationelementlength !=4)
 			User::Leave(KErrGsmSMSTpduNotSupported);
 		break;
 	case (ESmsIEIRFC822EmailHeader):
 		if(informationelementlength !=1)
 			User::Leave(KErrGsmSMSTpduNotSupported);
 		break;
  	case (ESmsHyperLinkFormat):
 		if(informationelementlength !=4)
 			User::Leave(KErrGsmSMSTpduNotSupported);
 		break;
  	case (ESmsNationalLanguageSingleShift):
 		if(informationelementlength != 1)
 			User::Leave(KErrGsmSMSTpduNotSupported);
 		break;
  	case (ESmsNationalLanguageLockingShift):
 		if(informationelementlength != 1)
 			User::Leave(KErrGsmSMSTpduNotSupported);
 		break;
 	case (ESmsIEISIMToolkitSecurityHeaders1):
 	case (ESmsIEISIMToolkitSecurityHeaders2):
 	case (ESmsIEISIMToolkitSecurityHeaders3):
 	case (ESmsIEISIMToolkitSecurityHeaders4):
 	case (ESmsIEISIMToolkitSecurityHeaders5):
 	case (ESmsIEISIMToolkitSecurityHeaders6):
 	case (ESmsIEISIMToolkitSecurityHeaders7):
 	case (ESmsIEISIMToolkitSecurityHeaders8):
 	case (ESmsIEISIMToolkitSecurityHeaders9):
 	case (ESmsIEISIMToolkitSecurityHeaders10):
 	case (ESmsIEISIMToolkitSecurityHeaders11):
 	case (ESmsIEISIMToolkitSecurityHeaders12):
 	case (ESmsIEISIMToolkitSecurityHeaders13):
 	case (ESmsIEISIMToolkitSecurityHeaders14):
 	case (ESmsIEISIMToolkitSecurityHeaders15):
 	case (ESmsIEISIMToolkitSecurityHeaders16):
 	if(informationelementlength !=0)
 			User::Leave(KErrGsmSMSTpduNotSupported);
 		break;
 	default:
 		break;
 	}

	const TPtrC8 data(aPdu.NextAndIncL(informationelementlength));
	NewDataL(informationelementlength);
	TPtr8 ptr(iData->Des());
	ptr.Copy(data);
	} // CSmsInformationElement::DecodeL


void CSmsInformationElement::InternalizeL(RReadStream& aStream)
	{
	TSmsOctet id;
	aStream >> id;
	iIdentifier=static_cast<TSmsInformationElementIdentifier>((TInt)id);
	delete iData;
	iData=NULL;
	iData=HBufC8::NewL(aStream,CSmsUserData::KSmsMaxUserDataSize);
	} // CSmsInformationElement::InternalizeL


void CSmsInformationElement::ExternalizeL(RWriteStream& aStream) const
	{
	TSmsOctet id;
	id=(TInt)iIdentifier;
	aStream << id;
	aStream << *iData;
	} // CSmsInformationElement::ExternalizeL


void CSmsInformationElement::ConstructL(const TDesC8& aData)
	{
	LOGGSMU1("CSmsInformationElement::ConstructL()");

	NewDataL(aData.Length());
	iData->Des().Copy(aData);
	} // CSmsInformationElement::ConstructL


void CSmsInformationElement::NewDataL(TInt aLength)
	{
	LOGGSMU1("CSmsInformationElement::NewDataL()");

	HBufC8* data=HBufC8::NewL(aLength);
	delete iData;
	iData=data;
	iData->Des().SetLength(aLength);
	} // CSmsInformationElement::NewDataL


TUint CSmsInformationElement::Length()const
	{
	LOGGSMU1("CSmsInformationElement::Length()");

	return 2+iData->Length();  // 2 stands for IEID and IEDL
	} // CSmsInformationElement::Length


/**
 *  @internalComponent
 *  
 *  This method maps an information element to an index into an array of categories.
 *  
 *  @param aId
 *  The information Element Identifier.
 *  @param aIndex
 *  The index into the array of categories
 *  @return
 *  True if the information element can be mapped.
 *  False otherwise.
 */
TBool TSmsInformationElementCategories::TranslateCategoryToIndex(TInformationElementId aId, TInt& aIndex)
    {
    LOGGSMU1("CSmsMessage::TranslateCategoryToIndex");

    TBool rc = ETrue;

    if (aId < CSmsInformationElement::ESmsIEMaximum)
        {
        switch (aId)
            {
            case CSmsInformationElement::ESmsIEIConcatenatedShortMessages8BitReference:
            case CSmsInformationElement::ESmsIEIConcatenatedShortMessages16BitReference:
            case CSmsInformationElement::ESmsIEISMSCControlParameters:
            case CSmsInformationElement::ESmsIEIRFC822EmailHeader:
                {
                aIndex = EIndexCtrlMandatoryInEveryPDUButWithValueSpecificToPDU;
                break;
                }
            case CSmsInformationElement::ESmsIEISpecialSMSMessageIndication:
                {
                aIndex = EIndexCtrlMandatoryInEveryPDUMultipleInstancesPerPDU;
                break;
                }
            case CSmsInformationElement::ESmsHyperLinkFormat:
                {
                aIndex = EIndexCtrlMultipleInstancesAllowed;
                break;
                }
            case CSmsInformationElement::ESmsNationalLanguageSingleShift:
            case CSmsInformationElement::ESmsNationalLanguageLockingShift:
                {
                aIndex = EIndexCtrlOptionalInEveryPDUWithValueSpecificToPDU;
                break;
                }
            case CSmsInformationElement::ESmsReplyAddressFormat:
                {
                aIndex = EIndexCtrlMandatoryIn1stPDUOnly;
                break;
                }
            case CSmsInformationElement::ESmsEnhanceVoiceMailInformation:
                {
                aIndex = EIndexCtrlSingleInstanceOnly;
                break;
                }
            case CSmsInformationElement::ESmsEnhancedTextFormatting:
            case CSmsInformationElement::ESmsEnhancedPredefinedSound:
            case CSmsInformationElement::ESmsEnhancedUserDefinedSound:
            case CSmsInformationElement::ESmsEnhancedPredefinedAnimation:
            case CSmsInformationElement::ESmsEnhancedLargeAnimation:
            case CSmsInformationElement::ESmsEnhancedSmallAnimation:
            case CSmsInformationElement::ESmsEnhancedLargePicture:
            case CSmsInformationElement::ESmsEnhancedSmallPicture:
            case CSmsInformationElement::ESmsEnhancedVariablePicture:
            case CSmsInformationElement::ESmsEnhancedUserPromptIndicator:
            case CSmsInformationElement::ESmsEnhancedExtendedObject:
            case CSmsInformationElement::ESmsEnhancedReusedExtendedObject:
            case CSmsInformationElement::ESmsEnhancedCompressionControl:
            case CSmsInformationElement::ESmsEnhancedODI:
            case CSmsInformationElement::ESmsEnhancedStandardWVG:
            case CSmsInformationElement::ESmsEnhancedCharacterSizeWVG:
            case CSmsInformationElement::ESmsEnhancedextendedObjectDataRequest:
                {
                aIndex = EIndexEmsInformationElement;
                break;
                }
            case CSmsInformationElement::ESmsIEIReserved:
            case CSmsInformationElement::ESmsIEIValueNotUsed:
                {
                rc = EFalse;
                break;
                }
            default:
                {
                aIndex = EIndexCtrlMandatoryInEveryPDUAndWithIdenticalValues;
                break;
                }
            }
        }
    else
        {
        rc = EFalse;
        LOGGSMU3("CSmsMessage::TranslateCategoryToIndex id = %d, found = %d", aId, rc);
        }
    return rc;
    } // TSmsInformationElementCategories::TranslateCategoryToIndex


/**
 *  @internalComponent
 *  
 *  This method gets an information element identifier's category.
 *  
 *  @param aId
 *  The information Element Identifier.
 *  @param aCategory
 *  The category of information element.
 *  @return
 *  ETrue if successful, EFalse if an information identifier is unknown or cannot
 *  be mapped.
 */
TBool TSmsInformationElementCategories::GetCategoryDefinition(TInformationElementId aId, TInformationElementCategory& aCategory)
    {
    LOGGSMU1("TSmsInformationElementCategories::GetCategoryDefinition");
    TInt index;

    if (TranslateCategoryToIndex(aId,index))
        {
        aCategory = categories[index];
        }
    else
        {
        LOGGSMU2("TSmsInformationElementCategories::GetCategoryDefinition, Failure, aId = %d", aId);
        return EFalse;
        }

    return ETrue;
    } // TSmsInformationElementCategories::GetCategoryDefinition


const TSmsInformationElementCategories::TInformationElementCategory TSmsInformationElementCategories::categories[TSmsInformationElementCategories::ENumberOfIndices] =
    {
    TSmsInformationElementCategories::EEmsInformationElement,                           // EDefaultEMSIndex
    TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUAndWithIdenticalValues,   // EDefaultControlIndex
    TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUMultipleInstancesPerPDU,  // EIndexForSpecialSMSMessageIndication, Concatenated Short Messages
    TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUButWithValueSpecificToPDU,// EIndexForIRFC822EmailHeader, Application Port Addresses
    TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly,                       // EIndexReplyAddressFormat
    TSmsInformationElementCategories::ECtrlSingleInstanceOnly,                          // EIndexEnhanceVoiceMailInformation
    TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed                     // EIndexForHyperLinkFormat
    };


CSmsUserData* CSmsUserData::NewL(CCnvCharacterSetConverter& aCharacterSetConverter,RFs& aFs,TSmsFirstOctet& aFirstOctet,const TSmsDataCodingScheme& aDataCodingScheme)
	{
	LOGGSMU1("CSmsUserData::NewL()");

	CSmsUserData* userdata=new(ELeave) CSmsUserData(aCharacterSetConverter,aFs,aFirstOctet,aDataCodingScheme);
	CleanupStack::PushL(userdata);
	userdata->ConstructL();
	CleanupStack::Pop();
	return userdata;
	} // CSmsUserData::NewL


/**
 *  Destructor.
 */
CSmsUserData::~CSmsUserData()
    {
    iInformationElementArray.ResetAndDestroy();
    delete iBody;
    } // CSmsUserData::NewL


/**
 *  Gets an information element by index.
 *  
 *  @param aIndex Index of the information element within the User Data
 *  @return Information element
 *  @capability None
 */
EXPORT_C  CSmsInformationElement& CSmsUserData::InformationElement(TInt aIndex) const
	{
	LOGGSMU1("CSmsUserData::InformationElement()");

	return *iInformationElementArray[aIndex];
	} // CSmsUserData::InformationElement


CSmsInformationElement*& CSmsUserData::InformationElementPtr(TInt aIndex)
    {
    LOGGSMU1("CSmsUserData::InformationElementPtr()");

    return iInformationElementArray[aIndex];
    } // CSmsUserData::InformationElementPtr


/**
 *  Gets the index of an information element.
 *  
 *  @param aIdentifier An information element Identifier to search for
 *  @param aIndex The index within the User Data of the information element (if
 *  found). If more than 1 instance of this information element exists, then
 *  the 1st instance will be returned.
 *  
 *  Use InformationELementIndexL to get all elements.
 *  @return True if aIdentifier is found in the User Data
 *  @capability None
 */
EXPORT_C TBool CSmsUserData::InformationElementIndex(CSmsInformationElement::TSmsInformationElementIdentifier aIdentifier,TInt& aIndex) const
	{
	LOGGSMU1("CSmsUserData::InformationElementIndex()");

	TBool found=EFalse;
	TInt count=NumInformationElements();
	for (TInt i=0; (!found) && (i<count); i++)
		if (InformationElement(i).Identifier()==aIdentifier)
			{
			found=ETrue;
			aIndex=i;
			}
	return found;
	} // CSmsUserData::InformationElementIndex


/**
 *  Gets the last index of an information element.
 *  
 *  @param aIdentifier An information element Identifier to search for
 *  @param aIndex The index within the User Data of the information element (if
 *  found). If more than 1 instance of this information element exists, then
 *  the last instance will be returned.
 *  
 *  Use InformationELementIndexL to get all elements.
 *  @return True if aIdentifier is found in the User Data
 *  @capability None
 */
EXPORT_C TBool CSmsUserData::InformationElementLastIndex(CSmsInformationElement::TSmsInformationElementIdentifier aIdentifier,TInt& aIndex) const
	{
	LOGGSMU1("CSmsUserData::InformationElementLastIndex()");

	TBool found=EFalse;
	TInt count=NumInformationElements();
	for (TInt i=count-1; (!found) && (i>=0); i--)
		if (InformationElement(i).Identifier()==aIdentifier)
			{
			found=ETrue;
			aIndex=i;
			}
	return found;
	} // CSmsUserData::InformationElementLastIndex


/**
 *  @internalComponent
 *  
 *  Locates every information element of type aIdentifier and
 *  stores its location index in the output array aIndices.
 *  
 *  @param aIdentifer
 *  The information element Identifier to search for
 *  @param aIndices
 *  A collection containing the location index for each information element of this type.
 */
void CSmsUserData::InformationElementIndicesL(CSmsInformationElement::TSmsInformationElementIdentifier aIdentifier, CArrayFixFlat<TInt>& aIndices) const
    {
    LOGGSMU1("CSmsUserData::InformationElementIndicesL()");

    aIndices.Reset();
    
	TInt count=NumInformationElements();
	for (TInt i=0; i<count; i++)
	    {
    	if (InformationElement(i).Identifier()==aIdentifier)
            {
            aIndices.AppendL(i);
            }
        }
    } // CSmsUserData::InformationElementIndicesL


/**
 *  Note that whilst a pointer to the aIe is passed as an
 *  input argument, the information element is still owned
 *  by the calling function, regardless of the return code.
 *  @param aInformationElement An EMS Information Element
 */
TBool CSmsUserData::EmsInformationElementWillFitL(CEmsInformationElement* aIe,CSmsEMSBufferSegmenter& aSeg,TUint& aCharsAddedToCurrentPDU)
	{
	LOGGSMU1("CSmsUserData::EmsInformationElementWillFitL()");

	// Before using an EmsInformationElement polymorphically as an SmsIE,
	// we need to make sure that the IE has been encoded
	aIe->EncodeInformationElementL();
	iInformationElementArray.AppendL(aIe);

	TInt sizeLeft=MaxPackedUDUnitsInBodyRemaining();
	iInformationElementArray.Delete(iInformationElementArray.Count()-1);
	if(sizeLeft==0 && iBody && (iBody->Length() > 0) && (*iBody)[iBody->Length()-1] == KSms7BitAlphabetEscapeChar)
	{
		--aCharsAddedToCurrentPDU;
		--aSeg.iElementsExtracted;
		TPtr8 ptr(iBody->Des());
		ptr.Delete(iBody->Length()-1,1);
		--sizeLeft;
	}
	return sizeLeft>=0;
	} // CSmsUserData::EmsInformationElementWillFitL


/**
 *  Tests whether the control information element will fit in the current PDU.
 *  
 *  Note that whilst a pointer to the aIe is passed as an
 *  input argument, the information element is still owned
 *  by the calling function, regardless of the return code.
 *  
 *  @param aInformationElement A pointer to an information Element
 *  @capability None
 */
TBool CSmsUserData::ControlInformationElementWillFitL(CSmsInformationElement* aIe)
    {
    LOGGSMU1("CSmsUserData::ControlInformationElementWillFitL()");

    if (aIe == NULL)
        {
        User::Leave(KErrGeneral);
        }

    TSmsInformationElementCategories::TInformationElementCategory category;

    if (TSmsInformationElementCategories::GetCategoryDefinition(aIe->Identifier(), category) == EFalse  ||
    	category == TSmsInformationElementCategories::EEmsInformationElement)
        {
        User::Leave(KErrArgument);
        }

    iInformationElementArray.AppendL(aIe);

    TInt sizeLeft=MaxPackedUDUnitsInBodyRemaining();
    iInformationElementArray.Delete(iInformationElementArray.Count()-1);

    // Not considering whether escape characters exist in the buffer
    // as control information elements do not add text to the buffer.

    return sizeLeft>=0;
    } // CSmsUserData::ControlInformationElementWillFitL


/**
 *  Adds an information element.
 *  This method can be used to create information elements in the range:
 *  00 - 09 - i.e. Control Information Elements
 *  It can be used to create information elements in the following ranges
 *  (on the assumption that the information element is intended to be encoded into
 *  every PDU):
 *  24 - 25 - i.e. National Language Encodings
 *  70 - 7F - i.e. SIM Tool Kit Security Headers
 *  80 - 9F - i.e  SMS to SME specific use
 *  C0 - CF - i.e. SC specific use
 *  
 *  Information elements in the following ranges should not be
 *  added using this interface. Instead they should be added using
 *  the following identified interfaces:
 *  0A-1F - Use the interfaces provided to support EMS Elements
 *  20 - Use the interfaces provided for Email in CSmsMessage
 *  21 - Use the interface provided by CSmsHyperLinkOperations
 *  22 - Use the interface provided by CSmsReplyAddressOperations
 *  23 - Use the interface provided by CSmsEnhancedVoiceMailOperations
 *  
 *  This interface should not be used for information element in the following
 *  ranges, these are reserved for future use in TS23.040 V6.5.0 and their
 *  characteristics and repeatability have not yet been defined.
 *  26-6F
 *  A0-BF
 *  E0-FF
 *  
 *  @param aIdentifier An information element Identifier for aData
 *  @param aData The information element to add to the User Data
 *  @leave
 *  KErrNotSupported if the information element is not supported via this interface.
 *  @capability None
 */
EXPORT_C void CSmsUserData::AddInformationElementL(TSmsId aIdentifier,const TDesC8& aData)
    {
    LOGGSMU1("CSmsUserData::AddInformationElementL");

    if  ((aIdentifier >= 0x21) && (aIdentifier <= 0x23) ||
         (aIdentifier >= 0x26) && (aIdentifier <= 0x6F) ||
         (aIdentifier >= 0xA0) && (aIdentifier <= 0xBF) ||
         (aIdentifier >= 0xE0) && (aIdentifier <= 0xFF))
        {
        User::Leave(KErrNotSupported);
        }
    UpdateInformationElementArrayL(aIdentifier, aData);

    } // CSmsUserData::AddInformationElementL


/**
 *  @internalComponent
 *  
 *  Either adds an information element to
 *  iInformationElementArray.
 *  
 *  @param aIdentifier An information element Identifier for aData
 *  @param aData The information element to add to the User Data
 */
void CSmsUserData::UpdateInformationElementArrayL(TSmsId aIdentifier,const TDesC8& aData)
    {
    LOGGSMU1("CSmsUserData::UpdateInformationElementsL");

    TInt count=NumInformationElements();
    if(!CEmsFactory::Supported(aIdentifier))
        {
        for (TInt i=0; i<count; i++)
            {
 	        if (InformationElement(i).Identifier()==aIdentifier)
                {
                TSmsInformationElementCategories::TInformationElementCategory category;
                
                if (TSmsInformationElementCategories::GetCategoryDefinition(aIdentifier, category) == EFalse)
                	{
                	User::Leave(KErrArgument);
                	}

                switch (category)
                    {
                    case TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUMultipleInstancesPerPDU:
                        {
                        if (InformationElement(i).Identifier() == CSmsInformationElement::ESmsIEISpecialSMSMessageIndication)
                            {
                            LOGGSMU3("CSmsUserData::AddInformationElementL1 category = %d, identifier = %d",category,aIdentifier);

                            //if Msg type is the same, swap with the most recent value
                            if ((InformationElement(i).Data()[0] & ((TUint8) EGsmSmsSpecialMessageIndicationTypeMask)) ==
                                (aData[0] & ((TUint8) EGsmSmsSpecialMessageIndicationTypeMask)))
                                {
                                User::Leave(KErrAlreadyExists);
                                }
                            }
                        else
                            {
                            LOGGSMU4("CSmsUserData::AddInformationElementL3 category = %d, identifier = %d, data = %S",category,aIdentifier, &aData);
                            User::Leave(KErrArgument);
                            }
                        break;
                        }
                    case TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUAndWithIdenticalValues:
                    case TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly:
                    case TSmsInformationElementCategories::ECtrlSingleInstanceOnly:
                        {
                        LOGGSMU3("CSmsUserData::AddInformationElementL4 category = %d, identifier = %d",category,aIdentifier);
                        User::Leave(KErrAlreadyExists);
                        break;
                        }
                    case TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed:
                        {
                        LOGGSMU3("CSmsUserData::AddInformationElementL5 category = %d, identifier = %d",category,aIdentifier);
                        break;
                        }
                    case TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUButWithValueSpecificToPDU:
                        {
                        LOGGSMU3("CSmsUserData::AddInformationElementL6 category = %d, identifier = %d",category,aIdentifier);
                        User::Leave(KErrAlreadyExists);
                        // currently the email header is updated in:
                        // void CSmsMessage::DecodeBufferL(CArrayPtr<CSmsPDU>& aSmsPDUArray,CSmsBufferBase& aBuffer)
                        break;
                        }
                    default:
                        {
                        LOGGSMU3("CSmsUserData::AddInformationElementL8 category = %d, identifier = %d",category,aIdentifier);
                        User::Leave(KErrNotSupported);
                        break;
                        }
                    }
                }
            }
        }

    	CSmsInformationElement* informationElement=CSmsInformationElement::NewL(aIdentifier,aData);
    	CleanupStack::PushL(informationElement);
    	iInformationElementArray.AppendL(informationElement);
    	CleanupStack::Pop();
    	SetHeaderPresent(ETrue);
    } // CSmsUserData::UpdateInformationElementArrayL


void CSmsUserData::AddEmsInformationElementL(CEmsInformationElement* aIe)
	{
	LOGGSMU1("CSmsUserData::AddEmsInformationElementL()");

	// Before using an EmsInformationElement polymorphically as an SmsIE,
	// we need to make sure that the IE has been encoded
	aIe->EncodeInformationElementL();
	iInformationElementArray.AppendL(aIe);
	SetHeaderPresent(ETrue);
	} // CSmsUserData::AddEmsInformationElementL


/**
 *  Removes an information element at the specified index.
 *  
 *  @param aIndex Information element index
 *  @capability None
 */
EXPORT_C void CSmsUserData::RemoveInformationElement(TInt aIndex)
	{
	LOGGSMU1("CSmsUserData::RemoveInformationElement()");
	// Since iInformationElementArray[aIndex] pointer is removed from iInformationElementArray, there is no double free issue.
	// coverity[double_free]
	delete iInformationElementArray[aIndex];
	iInformationElementArray[aIndex] = NULL;
	iInformationElementArray.Delete(aIndex);

	if (NumInformationElements()==0)
		{
		SetHeaderPresent(EFalse);
		}
	} // CSmsUserData::RemoveInformationElement


TInt CSmsUserData::MaxPackedUDUnitsInBodyRemaining() const
	{
	LOGGSMU1("CSmsUserData::MaxPackedUDUnitsInBodyRemaining()");

	TInt totalHeaderLengthInUDLUnits=TotalHeaderLengthInUDLUnits();
	TInt maxPackedUDUnitsInBody=0;
	if (iDataCodingScheme.TextCompressed()||(iDataCodingScheme.Alphabet()!=TSmsDataCodingScheme::ESmsAlphabet7Bit))
		{
		maxPackedUDUnitsInBody=KSmsMaxUserDataSize-totalHeaderLengthInUDLUnits;
		if (iDataCodingScheme.Alphabet()==TSmsDataCodingScheme::ESmsAlphabetUCS2)
			{
			// Cannot split unicode character across PDU boundary
			maxPackedUDUnitsInBody&=~1;
			}
		}
	else // 7-bit
		{
		maxPackedUDUnitsInBody=(8*KSmsMaxUserDataSize)/7-totalHeaderLengthInUDLUnits;
		}

	if (iBody)
		return maxPackedUDUnitsInBody-=iBody->Length();
	return maxPackedUDUnitsInBody;
	} // CSmsUserData::MaxPackedUDUnitsInBodyRemaining


TInt CSmsUserData::MaxPackedUDUnitsInBodyRemaining(TUint aIELen) const
	{
	LOGGSMU1("CSmsUserData::MaxPackedUDUnitsInBodyRemaining()");

	TInt totalHeaderLengthInUDLUnits=TotalHeaderLengthInUDLUnits(aIELen);
	TInt maxPackedUDUnitsInBody=0;
	if (iDataCodingScheme.TextCompressed()||(iDataCodingScheme.Alphabet()!=TSmsDataCodingScheme::ESmsAlphabet7Bit))
		{
		maxPackedUDUnitsInBody=KSmsMaxUserDataSize-totalHeaderLengthInUDLUnits;
		if (iDataCodingScheme.Alphabet()==TSmsDataCodingScheme::ESmsAlphabetUCS2)
			{
			// Cannot split unicode character across PDU boundary
			maxPackedUDUnitsInBody&=~1;
			}
		}
	else // 7-bit
		{
		maxPackedUDUnitsInBody=(8*KSmsMaxUserDataSize)/7-totalHeaderLengthInUDLUnits;
		}

	if (iBody)
		return maxPackedUDUnitsInBody-=iBody->Length();
	return maxPackedUDUnitsInBody;
	} // CSmsUserData::MaxPackedUDUnitsInBodyRemaining


/**
 *  @capability None
 */
EXPORT_C TInt CSmsUserData::MaxBodyLengthInChars() const
	{
	LOGGSMU1("CSmsUserData::MaxBodyLengthInChars()");

	TInt totalheaderlengthinudlunits=TotalHeaderLengthInUDLUnits();
	TInt maxbodylengthinchars=0;
	if (iDataCodingScheme.TextCompressed())
		{
		maxbodylengthinchars=KSmsMaxUserDataSize-totalheaderlengthinudlunits;
		}
	else
		{
		switch (iDataCodingScheme.Alphabet())
			{
			case (TSmsDataCodingScheme::ESmsAlphabet7Bit):
				{
				maxbodylengthinchars=(8*KSmsMaxUserDataSize)/7-totalheaderlengthinudlunits;
				break;
				}
			case (TSmsDataCodingScheme::ESmsAlphabet8Bit):
				{
				maxbodylengthinchars=KSmsMaxUserDataSize-totalheaderlengthinudlunits;
				break;
				}
			case (TSmsDataCodingScheme::ESmsAlphabetUCS2):
				{
				maxbodylengthinchars=(KSmsMaxUserDataSize-totalheaderlengthinudlunits)/2;
				break;
				}
			default:
			    LOGGSMU1("CSmsUserData::MaxBodyLengthInChars() WARNING! default case has been reached");
                break;
 			}
		}
	return maxbodylengthinchars;
	} // CSmsUserData::MaxBodyLengthInChars


/**
 *  Gets the unpacked User Data Elements.
 *  
 *  @return Unpacked User Data Elements
 *  @capability None
 */
EXPORT_C TPtrC8 CSmsUserData::Body() const
	{
	LOGGSMU1("CSmsUserData::Body()");

	return iBody->Des();
	} // CSmsUserData::Body


/**
 *  Sets the User Data (unpacked).
 *  
 *  @param aBody Unpacked User Data Elements
 *  @capability None
 */
EXPORT_C void CSmsUserData::SetBodyL(const TDesC8& aBody)
	{
	LOGGSMU1("CSmsUserData::SetBodyL()");

	//Some tests fail with this line in, despite it being a valid condition!
	//__ASSERT_DEBUG(aBody.Length() <= MaxBodyLengthInChars(), User::Leave(KErrTooBig));

	NewBodyL(aBody.Length());
	iBody->Des().Copy(aBody);
	} // CSmsUserData::SetBodyL


void CSmsUserData::AppendBodyL(const TDesC8& aBody)
	{
	LOGGSMU1("CSmsUserData::AppendBodyL()");

	if (iBody)
		{
		//Some tests fail with this line in, despite it being a valid condition!
		//__ASSERT_DEBUG(aBody.Length() + iBody->Length() <= MaxBodyLengthInChars(), User::Leave(KErrTooBig));

		iBody = iBody->ReAllocL(aBody.Length()+iBody->Length());
		iBody->Des().Append(aBody);
		}
	else
		{
		SetBodyL(aBody);
		}
	} // CSmsUserData::AppendBodyL


/**
 *  Tests if the character is supported by the current character set.
 *  This function can be used with 7bit and 8bit alphabets.
 * 
 *  @param aChar  Character to investigate.
 * 
 *  @return  ETrue if the character is supported.
 * 
 *  @note Since the function is based on the old behaviour (pre-PREQ2090)
 *        it does not accept a downgraded character or alternative encoding
 *        as being supported.
 *
 *  @capability None
 */
EXPORT_C TBool CSmsUserData::IsSupportedL(TChar aChar)
	{
	LOGGSMU1("CSmsUserData::IsSupportedL()");

	CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(iCharacterSetConverter,iFs,iDataCodingScheme.Alphabet(),IsBinaryData());
	TBool result=converter->IsSupportedL(aChar);
	CleanupStack::PopAndDestroy();

	return result;
	} // CSmsUserData::IsSupportedL


/**
 *  Tests if the descriptor text is supported by the current character set.
 *  This function can be used with 7bit and 8bit alphabets.
 * 
 *  @param aDes                                 Text string to check.
 *  @param aNumberOfUnconvertibleCharacters     Exit param for the number of
 *                                              characters unconvertible.
 *  @param aIndexOfFirstUnconvertibleCharacter  Exit param for the first
 *                                              unconverted character.
 * 
 *  @return  ETrue if the character is supported.
 *
 *  @capability None
 */
EXPORT_C TBool CSmsUserData::IsSupportedL(const TDesC& aDes, TInt& aNumberOfUnconvertibleCharacters,
                                          TInt& aIndexOfFirstUnconvertibleCharacter) const
	{
	LOGGSMU1("[1] CSmsUserData::IsSupportedL()");

	CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(iCharacterSetConverter,iFs,iDataCodingScheme.Alphabet(),IsBinaryData());
	TBool result=converter->IsSupportedL(aDes, aNumberOfUnconvertibleCharacters,
			                             aIndexOfFirstUnconvertibleCharacter);
	CleanupStack::PopAndDestroy();

	return result;
	} // CSmsUserData::IsSupportedL


/**
 *  Tests if the descriptor text is supported by the current character set.
 *  This function can be used with 7bit and 8bit alphabets.
 * 
 *  @param aDes                                 Text string to check.
 *  @param aEncoding                            Alternative encoding method.
 *  @param aNumberOfUnconvertibleCharacters     Exit param for the number of
 *                                              characters unconvertible.
 *  @param aNumberOfDowngradedCharacters        Exit param for the number of
 *                                              downgraded characters.
 *  @param aNumberRequiringAlternativeEncoding  Exit param for the number of
 *                                              characters requiring use of
 *                                              the alternative encoder.
 *  @param aIndexOfFirstUnconvertibleCharacter  Exit param for the first
 *                                              unconverted character.
 * 
 *  @return  ETrue if the character is supported.
 *
 *  @capability None
 */
EXPORT_C TBool CSmsUserData::IsSupportedL(const TDesC& aDes, TSmsEncoding aEncoding,
										  TInt& aNumberOfUnconvertibleCharacters,
                                          TInt& aNumberOfDowngradedCharacters,
                                          TInt& aNumberRequiringAlternativeEncoding,
                                          TInt& aIndexOfFirstUnconvertibleCharacter) const
	{
	LOGGSMU1("[2] CSmsUserData::IsSupportedL()");

	CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(iCharacterSetConverter,iFs,iDataCodingScheme.Alphabet(),IsBinaryData());
	TBool result=converter->IsSupportedL(aDes, aEncoding,
			                             aNumberOfUnconvertibleCharacters,
			                             aNumberOfDowngradedCharacters,
			                             aNumberRequiringAlternativeEncoding,
			                             aIndexOfFirstUnconvertibleCharacter);
	CleanupStack::PopAndDestroy();

	return result;
	} // CSmsUserData::IsSupportedL


TUint8* CSmsUserData::EncodeL(TUint8* aPtr) const
	{
	LOGGSMU1("CSmsUserData::EncodeL()");

	__ASSERT_DEBUG(0<=MaxPackedUDUnitsInBodyRemaining(),Panic(KGsmuPanicUserDataBodyTooLong));
	// Encode the user data length
	TInt totalHeaderLengthInUDLUnits=TotalHeaderLengthInUDLUnits();
	TSmsOctet userDataLength=totalHeaderLengthInUDLUnits+TSmsOctet(BodyLengthInUDLUnits());
	aPtr=userDataLength.EncodeL(aPtr);
	// Encode any user data header
	if (HeaderPresent())
		{
		TSmsOctet headerLength=HeaderLength();
		aPtr=headerLength.EncodeL(aPtr);
		TInt numInformationElements=NumInformationElements();
		for (TInt i=0; i<numInformationElements; i++)
			aPtr=iInformationElementArray[i]->EncodeL(aPtr);
		}
	// Pack the user data body
	TInt startBit=0;
	if (iDataCodingScheme.Alphabet()==TSmsDataCodingScheme::ESmsAlphabet7Bit)
		startBit=(totalHeaderLengthInUDLUnits*7)%8;
	TSmsAlphabetPacker packer(iDataCodingScheme.Alphabet(),IsBinaryData(),startBit);
	TPtr8 ptr((TUint8*)aPtr,0,packer.PackedOctetsRequiredL(Body().Length()));
	aPtr+=packer.PackL(ptr,Body());
	return aPtr;
	} // CSmsUserData::EncodeL


void CSmsUserData::DecodeL(TGsmuLex8& aPdu)
	{
	DecodeL(aPdu, EFalse);
	}

void CSmsUserData::DecodeL(TGsmuLex8& aPdu, TBool aAcceptTruncation)
	{	
	LOGGSMU1("CSmsUserData::DecodeL()");

	// Reset current data
	iInformationElementArray.ResetAndDestroy();
	// Decode the user data
	TSmsOctet userDataLength;
	userDataLength.DecodeL(aPdu);
	TSmsOctet headerLength;
	// Decode any user data header
	TBool headerPresent=HeaderPresent();
	/*
	if (headerPresent || IsHeaderPresent(aPtr,dataLength))
	*/
	if (headerPresent)
		{
		headerLength.DecodeL(aPdu);
		if ((1+headerLength)>KSmsMaxUserDataSize)
			User::Leave(KErrGsmSMSTpduNotSupported);
		while (HeaderLength()<headerLength)
			{
			CSmsInformationElement* informationelement=CSmsInformationElement::NewL();
			CleanupStack::PushL(informationelement);
			informationelement->DecodeL(aPdu);
			iInformationElementArray.AppendL(informationelement);
			CleanupStack::Pop(informationelement);
			}
		if (HeaderLength()!=headerLength)
			User::Leave(KErrGsmSMSTpduNotSupported);
		}
	// Decode the body - make sure we have enough buffer
	TInt headerLengthInUDLUnits=TotalHeaderLengthInUDLUnits();
	TInt bodyLengthInUDLUnits=userDataLength-headerLengthInUDLUnits;

	if(bodyLengthInUDLUnits <=0)
	{
		NewBodyL(0);
		return;
	}

	NewBodyL(bodyLengthInUDLUnits);

	// Unpack the body
	TInt startBit=0;
	if (iDataCodingScheme.Alphabet()==TSmsDataCodingScheme::ESmsAlphabet7Bit)
		startBit=(headerLengthInUDLUnits*7)%8;
	TSmsAlphabetPacker unpacker(iDataCodingScheme.Alphabet(),IsBinaryData(),startBit);
	TInt bodyLengthInOctets=unpacker.PackedOctetsRequiredL(bodyLengthInUDLUnits);
	TPtr8 destPtr((TUint8*)iBody->Des().Ptr(),0,bodyLengthInUDLUnits);

	const TPtrC8 sourcePtr(aPdu.NextWithNoIncL(bodyLengthInOctets,aAcceptTruncation));
	if ( aAcceptTruncation && sourcePtr.Length() < bodyLengthInOctets)
		{
		// field was truncated in an acceptable situation (User Data in Status Report PDU)
		bodyLengthInUDLUnits = unpacker.NumUDUnitsL(sourcePtr.Length());
		}
	unpacker.UnpackL(sourcePtr,destPtr,bodyLengthInUDLUnits);

	//@note No need to call aPdu.IncL() because CSmsUserData is always at the end of a PDU
	} // CSmsUserData::DecodeL


void CSmsUserData::InternalizeL(RReadStream& aStream)
	{
	iInformationElementArray.ResetAndDestroy();
	TInt numiformationelements=aStream.ReadInt32L();
	// The "header present" flag must mirror whether information elements are present, and
	// the parental iFirstOctet should already be set by its InternalizeL()
	__ASSERT_DEBUG(((!HeaderPresent() && numiformationelements == 0) || (HeaderPresent() && numiformationelements > 0)), Panic(KGsmuPanicInformationElementIndexOutOfRange));
	for (TInt i=0; i<numiformationelements; i++)
		{
		CSmsInformationElement* informationelement=CSmsInformationElement::NewL();
		CleanupStack::PushL(informationelement);
		aStream >> *informationelement;
		iInformationElementArray.AppendL(informationelement);
		CleanupStack::Pop();
		}
	delete iBody;
	iBody=NULL;
	iBody=HBufC8::NewL(aStream,KSmsMaxUserDataLengthInChars);
	} // CSmsUserData::InternalizeL


void CSmsUserData::ExternalizeL(RWriteStream& aStream) const
	{
	TInt numiformationelements=iInformationElementArray.Count();
	aStream.WriteInt32L(numiformationelements);
	for (TInt i=0; i<numiformationelements; i++)
		aStream << *iInformationElementArray[i];
	aStream << *iBody;
	} // CSmsUserData::ExternalizeL


CSmsUserData::CSmsUserData(CCnvCharacterSetConverter& aCharacterSetConverter,RFs& aFs,TSmsFirstOctet& aFirstOctet,const TSmsDataCodingScheme& aDataCodingScheme):
    iCharacterSetConverter(aCharacterSetConverter),
    iFs(aFs),
    iFirstOctet(aFirstOctet),
    iDataCodingScheme(aDataCodingScheme),
    iInformationElementArray(8)
    {
    } // CSmsUserData::CSmsUserData


void CSmsUserData::ConstructL()
	{
	LOGGSMU1("CSmsUserData::ConstructL()");

	NewBodyL(0);
	} // CSmsUserData::ConstructL


/**
 *  Duplicates this CSmsUserData object.
 * 
 *  @return  Pointer to the newly created CSmsUserData object.
 */
CSmsUserData* CSmsUserData::DuplicateL(TSmsFirstOctet& aFirstOctet,
									   const TSmsDataCodingScheme& aDataCodingScheme) const
	{
	LOGGSMU1("CSmsUserData::DuplicateL()");

	CSmsUserData*  userdata = CSmsUserData::NewL(iCharacterSetConverter, iFs,
	                                             aFirstOctet, aDataCodingScheme);
	CleanupStack::PushL(userdata);

	userdata->SetBodyL(Body());

	for (TInt ie = 0;  ie < iInformationElementArray.Count();  ie++)
		{
		CSmsInformationElement*  oldIE = iInformationElementArray[ie];

		if (CEmsFactory::Supported(oldIE->Identifier()))
			{
			CEmsInformationElement*  newIE = static_cast<CEmsInformationElement*>(oldIE)->DuplicateL();
			
			CleanupStack::PushL(newIE);
			userdata->AddEmsInformationElementL(newIE);
			CleanupStack::Pop(newIE);
			}
		else
			{
			userdata->UpdateInformationElementArrayL(oldIE->Identifier(), oldIE->Data());
			}
		}

	CleanupStack::Pop();

	return userdata;
	} // CSmsUserData::DuplicateL


TInt CSmsUserData::HeaderLength() const
	{
	LOGGSMU1("CSmsUserData::HeaderLength()");

	TInt numinformationelements=NumInformationElements();
	TInt headerlength=0;
	for (TInt i=0; i<numinformationelements; i++)
		headerlength+=iInformationElementArray[i]->Length();
	return headerlength;
	} // CSmsUserData::HeaderLength


TInt CSmsUserData::TotalHeaderLengthInUDLUnits() const
	{
	LOGGSMU1("CSmsUserData::TotalHeaderLengthInUDLUnits()");

	TInt totalheaderlengthinudlunits=0;
	if (iInformationElementArray.Count()>0)
		{
		TInt totalheaderlength=1+HeaderLength();
		if (iDataCodingScheme.TextCompressed())
			{
			totalheaderlengthinudlunits=totalheaderlength;
			}
		else
			{
			switch(iDataCodingScheme.Alphabet())
				{
				case (TSmsDataCodingScheme::ESmsAlphabet7Bit):
					{
					totalheaderlengthinudlunits=((8*totalheaderlength)+6)/7; //  Rounds up
					break;
					}
				case (TSmsDataCodingScheme::ESmsAlphabet8Bit):
				case (TSmsDataCodingScheme::ESmsAlphabetUCS2):
					{
					totalheaderlengthinudlunits=totalheaderlength;
					break;
					}
				default:
				    LOGGSMU1("CSmsUserData::TotalHeaderLengthInUDLUnits() WARNING default case has been reached");
                    break;
				}
			}
		}
	return totalheaderlengthinudlunits;
	} // CSmsUserData::TotalHeaderLengthInUDLUnits


TInt CSmsUserData::TotalHeaderLengthInUDLUnits(TInt aIElen) const
	{
	LOGGSMU1("CSmsUserData::TotalHeaderLengthInUDLUnits()");

		TInt totalheaderlengthinudlunits=0;
		TInt totalheaderlength=aIElen;

		if (iInformationElementArray.Count()>0)
			totalheaderlength+=HeaderLength();

		if(totalheaderlength)totalheaderlength+=1; //UDHL

		if (iDataCodingScheme.TextCompressed())
			{
			totalheaderlengthinudlunits=totalheaderlength;
			}
		else
			{
			switch(iDataCodingScheme.Alphabet())
				{
				case (TSmsDataCodingScheme::ESmsAlphabet7Bit):
					{
					totalheaderlengthinudlunits=((8*totalheaderlength)+6)/7; //  Rounds up
					break;
					}
				case (TSmsDataCodingScheme::ESmsAlphabet8Bit):
				case (TSmsDataCodingScheme::ESmsAlphabetUCS2):
					{
					totalheaderlengthinudlunits=totalheaderlength;
					break;
					}
				default:
                    break;
				}
			}
		return totalheaderlengthinudlunits;
	} // CSmsUserData::TotalHeaderLengthInUDLUnits


TInt CSmsUserData::BodyLengthInUDLUnits() const
	{
	LOGGSMU1("CSmsUserData::BodyLengthInUDLUnits()");

	return iBody->Des().Length();
	} // CSmsUserData::BodyLengthInUDLUnits


void CSmsUserData::NewBodyL(TInt aLength)
	{
	LOGGSMU1("CSmsUserData::NewBodyL()");


		HBufC8* body=HBufC8::NewL(aLength);
		delete iBody;
		iBody=body;
		iBody->Des().SetLength(aLength);

	} // CSmsUserData::NewBodyL


TBool CSmsUserData::HeaderPresent() const
	{
	LOGGSMU1("CSmsUserData::HeaderPresent()");

	return (iFirstOctet&TSmsFirstOctet::ESmsUDHIMask)==TSmsFirstOctet::ESmsUDHIHeaderPresent;
	} // CSmsUserData::HeaderPresent


void CSmsUserData::SetHeaderPresent(TBool aHeaderPresent)
	{
	LOGGSMU1("CSmsUserData::SetHeaderPresent()");

	iFirstOctet=aHeaderPresent? (iFirstOctet&(~TSmsFirstOctet::ESmsUDHIMask))|TSmsFirstOctet::ESmsUDHIHeaderPresent: (iFirstOctet&(~TSmsFirstOctet::ESmsUDHIMask))|TSmsFirstOctet::ESmsUDHIHeaderNotPresent;
	} // CSmsUserData::SetHeaderPresent


TBool CSmsUserData::IsBinaryData() const
	{
	LOGGSMU1("CSmsUserData::IsBinaryData()");

	TInt index=0;
	return (iDataCodingScheme.TextCompressed()) ||
			((iDataCodingScheme.Alphabet()==TSmsDataCodingScheme::ESmsAlphabet8Bit) &&
			(InformationElementIndex(CSmsInformationElement::ESmsIEIApplicationPortAddressing8Bit,index) ||
	        InformationElementIndex(CSmsInformationElement::ESmsIEIApplicationPortAddressing16Bit,index)));
	} // CSmsUserData::IsBinaryData


/**
 *  Converts type of number and numbering plan identification information
 *  from the type of address parameter to the NMobilePhone::TMobileTON
 *  and NMobilePhone::TMobileNPI format.
 *  
 *  @return aTon The number type
 *  @return aNpi The numbering plan
 *  
 *  @capability None
 */
EXPORT_C void TGsmSmsTypeOfAddress::ConvertToETelMM(NMobilePhone::TMobileTON& aTon,NMobilePhone::TMobileNPI& aNpi) const
    {
    LOGGSMU1("TGsmSmsTypeOfAddress::ConvertToETelMM()");

    switch (TON())
    {
		case EGsmSmsTONInternationalNumber:
            {
            aTon = (NMobilePhone::EInternationalNumber);
            break;
            }
        case EGsmSmsTONNationalNumber:
            {
            aTon = (NMobilePhone::ENationalNumber);
            break;
            }
        case EGsmSmsTONNetworkSpecificNumber:
            {
            aTon = (NMobilePhone::ENetworkSpecificNumber);
            break;
            }
        case EGsmSmsTONSubscriberNumber:
            {
            aTon = (NMobilePhone::ESubscriberNumber);
            break;
            }
        case EGsmSmsTONAlphaNumeric:
            {
            aTon = (NMobilePhone::EAlphanumericNumber);
            break;
            }
        case EGsmSmsTONAbbreviatedNumber:
            {
            aTon = (NMobilePhone::EAbbreviatedNumber);
            break;
            }

        default:
            {
            aTon = (NMobilePhone::EUnknownNumber);
            break;
            }
		}

    switch (NPI())
		{
        case EGsmSmsNPIISDNTelephoneNumberingPlan:
            {
            aNpi = (NMobilePhone::EIsdnNumberPlan);
            break;
            }
        case EGsmSmsNPIDataNumberingPlan:
            {
            aNpi = (NMobilePhone::EDataNumberPlan);
            break;
            }
        case EGsmSmsNPITelexNumberingPlan:
            {
            aNpi = (NMobilePhone::ETelexNumberPlan);
            break;
            }
        case EGsmSmsNPINationalNumberingPlan:
            {
            aNpi = (NMobilePhone::ENationalNumberPlan);
            break;
            }
        case EGsmSmsNPIPrivateNumberingPlan:
            {
            aNpi = (NMobilePhone::EPrivateNumberPlan);
            break;
            }
        case EGsmSmsNPIERMESNumberingPlan:
            {
            aNpi = (NMobilePhone::EERMESNumberPlan);
            break;
            }

        default:
            {
            aNpi = (NMobilePhone::EUnknownNumberingPlan);
            break;
            }
		}
	} // NMobilePhone::TMobileNPI


/**
 *  Converts type of number and numbering plan identification information
 *  from the NMobilePhone::TMobileTON and NMobilePhone::TMobileNPI format
 *  to the type of address parameter.
 *  
 *  @param aTon The number type
 *  @param aNpi The numbering plan
 *  
 *  @capability None
 */
EXPORT_C void TGsmSmsTypeOfAddress::SetFromETelMM(NMobilePhone::TMobileTON aTon,NMobilePhone::TMobileNPI aNpi)
    {
    LOGGSMU1("TGsmSmsTypeOfAddress::SetFromETelMM()");

    switch (aTon)
    {
		case NMobilePhone::EInternationalNumber:
            {
            SetTON( EGsmSmsTONInternationalNumber );
            break;
            }
        case NMobilePhone::ENationalNumber:
            {
            SetTON( EGsmSmsTONNationalNumber );
            break;
            }
        case NMobilePhone::ENetworkSpecificNumber:
            {
            SetTON( EGsmSmsTONNetworkSpecificNumber );
            break;
            }
        case NMobilePhone::ESubscriberNumber:
            {
            SetTON( EGsmSmsTONSubscriberNumber );
            break;
            }
        case NMobilePhone::EAlphanumericNumber:
            {
            SetTON( EGsmSmsTONAlphaNumeric );
            break;
            }
        case NMobilePhone::EAbbreviatedNumber:
            {
            SetTON( EGsmSmsTONAbbreviatedNumber );
            break;
            }

        default:
            {
            SetTON( EGsmSmsTONUnknown );
            break;
            }
		}

    switch (aNpi)
		{
        case NMobilePhone::EIsdnNumberPlan:
            {
            SetNPI( EGsmSmsNPIISDNTelephoneNumberingPlan );
            break;
            }
        case NMobilePhone::EDataNumberPlan:
            {
            SetNPI( EGsmSmsNPIDataNumberingPlan );
            break;
            }
        case NMobilePhone::ETelexNumberPlan:
            {
            SetNPI( EGsmSmsNPITelexNumberingPlan );
            break;
            }
        case NMobilePhone::ENationalNumberPlan:
            {
            SetNPI( EGsmSmsNPINationalNumberingPlan );
            break;
            }
        case NMobilePhone::EPrivateNumberPlan:
            {
            SetNPI( EGsmSmsNPIPrivateNumberingPlan );
            break;
            }
        case NMobilePhone::EERMESNumberPlan:
            {
            SetNPI( EGsmSmsNPIERMESNumberingPlan );
            break;
            }

        default:
            {
            SetNPI( EGsmSmsNPIUnknown );
            break;
            }
		}
	} // NMobilePhone::TMobileTON


/**
 *  @publishedAll
 *  
 *  Indicates whether this message is a Voice Mail Notification
 *  or a Voice Mail Deletion Confirmation.
 *  
 *  @return
 *  TVoiceMailInfoType, indicating whether this message is a Voice Mail
 *  Notification or a Voice Mail Deletion Confirmation.
 *  
 *  @capability None
 */
EXPORT_C TVoiceMailInfoType CEnhancedVoiceMailBoxInformation::Type() const
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::Type()");

	return iType;
	} // CEnhancedVoiceMailBoxInformation::Type


/**
 *  @publishedAll
 *  
 *  Sets the subscriber profile per 23.040 v6.5 Section 9.2.3.24.13.1.
 *  
 *  @param aProfile
 *  The required subscriber profile
 *  
 *  @capability None
 */
EXPORT_C void CEnhancedVoiceMailBoxInformation::SetProfile(TSmsMessageProfileType aProfile)
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::SetProfile()");

	iProfile = aProfile;
	} // CEnhancedVoiceMailBoxInformation::SetProfile


/**
 *  @publishedAll
 *  
 *  Gets the subscriber profile per 23.040 v6.5 Section 9.2.3.24.13.1.
 *  
 *  @param aProfile
 *  The current subscriber profile
 *  
 *  @capability None
 */
EXPORT_C TSmsMessageProfileType CEnhancedVoiceMailBoxInformation::Profile() const
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::Profile()");

	return iProfile;
	} // CEnhancedVoiceMailBoxInformation::Profile


/**
 *  @publishedAll
 *  
 *  Configures the storage directive
 *  
 *  @param aIsStored
 *  Set to True if the SM is to be stored in the ME or USIM,
 *  False is the SM is to be discarded.
 *  
 *  @capability None
 */
EXPORT_C void CEnhancedVoiceMailBoxInformation::SetStorage(TBool aIsStored)
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::SetStorage()");

	iStorage = aIsStored;
	} // CEnhancedVoiceMailBoxInformation::SetStorage


/**
 *  @publishedAll
 *  
 *  Indicates whether the SM is to be stored or discarded
 *  
 *  @return
 *  True if the SM is to be stored in the ME or USIM,
 *  False is the SM is to be discarded.
 *  
 *  @capability None
 */
EXPORT_C TBool CEnhancedVoiceMailBoxInformation::Store() const
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::Store()");

	return iStorage;
	} // CEnhancedVoiceMailBoxInformation::Store


/**
 *  @publishedAll
 *  
 *  Used to set or reset the voice mail status to almost full.
 *  
 *  @param aIsStored
 *  Set to True the voice mail system is almost full.
 *  Set to False otherwise.
 *  
 *  @capability None
 */
EXPORT_C void CEnhancedVoiceMailBoxInformation::SetAlmostMaximumCapacity(TBool aIsAlmostFull)
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::SetAlmostMaximumCapacity()");

	iAlmostFull = aIsAlmostFull;
	} // CEnhancedVoiceMailBoxInformation::SetAlmostMaximumCapacity


/**
 *  @publishedAll
 *  
 *  Indicates whether the voice mail system is almost at full capacity.
 *  
 *  @return
 *  True, if the voice mail system is almost full.
 *  False otherwise.
 *  
 *  @capability None
 */
EXPORT_C TBool CEnhancedVoiceMailBoxInformation::AlmostMaximumCapacity() const
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::AlmostMaximumCapacity()");

	return iAlmostFull;
	} // CEnhancedVoiceMailBoxInformation::AlmostMaximumCapacity


/**
 *  @publishedAll
 *  
 *  Used to set or reset the voice mail status to full.
 *  
 *  @param aIsStored
 *  Set to True the voice mail system is full.
 *  Set to False otherwise.
 *  
 *  @capability None
 */
EXPORT_C void CEnhancedVoiceMailBoxInformation::SetMaximumCapacity(TBool aIsFull)
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::SetMaximumCapacity()");

	iFull = aIsFull;
	} // CEnhancedVoiceMailBoxInformation::SetMaximumCapacity


/**
 *  @publishedAll
 *  
 *  Indicates whether the voice mail status is full.
 *  
 *  @return
 *  True if the voice mail system is almost full.
 *  False otherwise.
 *  
 *  @capability None
 */
EXPORT_C TBool CEnhancedVoiceMailBoxInformation::MaximumCapacity() const
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::MaximumCapacity()");

	return iFull;
	} // CEnhancedVoiceMailBoxInformation::MaximumCapacity


/**
 *  @publishedAll
 *  
 *  Indicates whether the message contains extension bytes
 *  
 *  @return
 *  True if the message contains extension bytes.
 *  False otherwise.
 *  
 *  @capability None
 */
EXPORT_C TBool CEnhancedVoiceMailBoxInformation::ExtensionIndicator() const
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::ExtensionIndicator()");

	return iExtensionIndicator;
	} // CEnhancedVoiceMailBoxInformation::ExtensionIndicator


void CEnhancedVoiceMailBoxInformation::NewBufferL(TInt aLength)
	{
	LOGGSMU2("CEnhancedVoiceMailBoxInformation::NewBufferL, length = %d",aLength);

	HBufC* buffer=HBufC::NewL(aLength);
	delete iAccessAddress;
	iAccessAddress=buffer;
	iAccessAddress->Des().SetLength(aLength);
	iAccessAddress->Des().FillZ();
	} // CEnhancedVoiceMailBoxInformation::NewBufferL


/**
 *  @publishedAll
 *  
 *  Used to set the voice mail box number, overwriting any pre-existing number.
 *  
 *  @param aAddress
 *  The voice mail box address.
 *  
 *  @capability None
 */
EXPORT_C void  CEnhancedVoiceMailBoxInformation::SetAccessAddressL(const TDesC& aAddress)
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::SetAccessAddressL()");

	TInt length=aAddress.Length();
	NewBufferL(length);
	iAccessAddress->Des().Copy(aAddress);

	const TGsmSmsTypeOfNumber typeofnumber=length && (iAccessAddress->Des()[0]=='+')? EGsmSmsTONInternationalNumber: EGsmSmsTONUnknown;
	iTypeOfAddress.SetTON(typeofnumber);
	} // CEnhancedVoiceMailBoxInformation::SetAccessAddressL


/**
 *  @publishedAll
 *  
 *  Retrieves the voice mail box number.
 *  
 *  @return
 *  A pointer to the voice mail box number.
 *  
 *  @capability None
 */
EXPORT_C TPtrC CEnhancedVoiceMailBoxInformation::AccessAddress() const
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::AccessAddress()");

	TPtrC ptr;
	if (iAccessAddress)
	    ptr.Set(iAccessAddress->Des());
	return ptr;
	} // CEnhancedVoiceMailBoxInformation::AccessAddress


/**
 *  @publishedAll
 *  
 *  Used to set the voice mail box number as a parsed address
 *  
 *  @param aParsedAddress
 *  The parsed address to be used as the voice mail box number.
 *  
 *  @capability None
 */
EXPORT_C void  CEnhancedVoiceMailBoxInformation::SetParsedAccessAddressL(const TGsmSmsTelNumber& aParsedAddress)
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::SetParsedAccessAddressL()");

   	iTypeOfAddress=aParsedAddress.iTypeOfAddress;
	DoSetParsedAddressL(aParsedAddress.iTelNumber);
	} // CEnhancedVoiceMailBoxInformation::SetParsedAccessAddressL


/**
 *  @publishedAll
 *  
 *  Used to get the voice mail box number as a parsed address.
 *  
 *  @param aParsedAddress
 *  An output parameter which is set to the parsed address.
 *  
 *  @capability None
 */
EXPORT_C void  CEnhancedVoiceMailBoxInformation::ParsedAccessAddress(TGsmSmsTelNumber& aParsedAddress) const
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::ParsedAccessAddress()");

	aParsedAddress.iTypeOfAddress = iTypeOfAddress;

	TInt maxparsedlength=aParsedAddress.iTelNumber.MaxLength();

	if (iTypeOfAddress.TON()==EGsmSmsTONAlphaNumeric)
		{
		TInt parsedlength=AccessAddress().Length();
		if (parsedlength>maxparsedlength)
			parsedlength=maxparsedlength;
		aParsedAddress.iTelNumber.Copy(AccessAddress().Mid(0,parsedlength));
		}
	else
		{
		aParsedAddress.iTelNumber.SetLength(maxparsedlength);

		TInt length=iAccessAddress->Des().Length();
		TInt parsedlength=0;
		for (TInt i=0; (i<length) && (parsedlength<maxparsedlength); i++)
			{
			TText ch=iAccessAddress->Des()[i];
			if ((ch>='0') && (ch<='9'))
				{
				aParsedAddress.iTelNumber[parsedlength]=(TUint8) ch;
				parsedlength++;
				}
			}

		aParsedAddress.iTelNumber.SetLength(parsedlength);
		}
	} // CEnhancedVoiceMailBoxInformation::ParsedAccessAddress


void CEnhancedVoiceMailBoxInformation::DoSetParsedAddressL(const TDesC& aAddress)
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::DoSetParsedAddressL()");

	TInt length=aAddress.Length();
	if ((iTypeOfAddress.TON()==EGsmSmsTONInternationalNumber) &&
	    (length && (aAddress[0]!='+')))
		{
		NewBufferL(length+1);
		iAccessAddress->Des()[0]='+';
		TPtr ptr((TText*) (iAccessAddress->Des().Ptr()+1),length,length);
		ptr.Copy(aAddress);
		}
	else
		{
		NewBufferL(length);
		iAccessAddress->Des().Copy(aAddress);
		}
	} // CEnhancedVoiceMailBoxInformation::DoSetParsedAddressL


/**
 *  @publishedAll
 *  
 *  Sets the number of voice messages to a value in the range 0 to 255.
 *  
 *  @param aNumber
 *  The number of voice messages.
 *  
 *  @capability None
 */
EXPORT_C void   CEnhancedVoiceMailBoxInformation::SetNumberOfVoiceMessages(TUint8 aNumber)
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::SetNumberOfVoiceMessages()");

	iNumberOfVoiceMessages=aNumber;
	} // CEnhancedVoiceMailBoxInformation::SetNumberOfVoiceMessages


/**
 *  @publishedAll
 *  
 *  Retrieves the number of voice messages that are unread.
 *  
 *  @return
 *  The number of unread voice messages.
 *  
 *  @capability None
 */
EXPORT_C TUint8 CEnhancedVoiceMailBoxInformation::NumberOfVoiceMessages() const
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::NumberOfVoiceMessages()");

	return iNumberOfVoiceMessages;
	} // CEnhancedVoiceMailBoxInformation::NumberOfVoiceMessages


TUint8* CEnhancedVoiceMailBoxInformation::EncodeL(TUint8* aPtr, CCnvCharacterSetConverter& aCharacterSetConverter, RFs& aFs) const
	{
	*aPtr =  (((TUint8) iType)       & EMask1Bit )       +
	        ((((TUint8) iProfile)    & EMask2Bits) << 2) +
	        ((((TUint8) iStorage)    & EMask1Bit ) << 4) +
	        ((((TUint8) iAlmostFull) & EMask1Bit ) << 5) +
	        ((((TUint8) iFull)       & EMask1Bit ) << 6) +
	         (((TUint8) iExtensionIndicator      ) << 7);

	LOGGSMU2("CEnhancedVoiceMailBoxInformation::EncodeL 1st byte = %d",*aPtr);
	aPtr++;

	// Create an address object to encode the mail box access address into the
	// format required by 23.040 v6.5.0 section 9.1.2.5.
	CSmsAddress* address = CSmsAddress::NewL(aCharacterSetConverter,aFs);
	CleanupStack::PushL(address);
	TPtrC accessAddressPtr;
	if (iAccessAddress)
	    {
		accessAddressPtr.Set(iAccessAddress->Des());
	    }
	address->SetRawAddressL(iTypeOfAddress,accessAddressPtr);
	aPtr = address->EncodeL(aPtr);
	CleanupStack::PopAndDestroy(address);

	*aPtr = (TUint8) iNumberOfVoiceMessages;
	aPtr++;

	return aPtr;
	} // CEnhancedVoiceMailBoxInformation::EncodeL


void CEnhancedVoiceMailBoxInformation::DecodeL(TGsmuLex8& aVoiceMailInfo, CCnvCharacterSetConverter& aCharacterSetConverter, RFs& aFs)
	{
	TUint8 Byte1 = aVoiceMailInfo.GetL();

	iType               = (TVoiceMailInfoType)       (Byte1       & EMask1Bit);
	iProfile            = (TSmsMessageProfileType ) ((Byte1 >> 2) & EMask2Bits);
	iStorage            = (TBool)                   ((Byte1 >> 4) & EMask1Bit);
	iAlmostFull         = (TBool)                   ((Byte1 >> 5) & EMask1Bit);
	iFull               = (TBool)                   ((Byte1 >> 6) & EMask1Bit);
	iExtensionIndicator = (TBool)                   ((Byte1 >> 7) & EMask1Bit);

	LOGGSMU2("CEnhancedVoiceMailBoxInformation::DecodeL 1st byte = %d", Byte1);

	// Create an address object to deccode the mail box access address from the
	// format required by 23.040 v6.5.0 section 9.1.2.5.
	CSmsAddress* decodedAddress = CSmsAddress::NewL(aCharacterSetConverter,aFs);
	CleanupStack::PushL(decodedAddress);

	// CSmsAddress::DecodeL is also used to decode source and destination addresses.
	// CSmsAddress::DecodeL expects internally that alphanumeric addresses will be size
	// CSmsAddress::KSmsAddressMaxAddressValueLength=10.
	// Need to add padding bytes to bring the address field up to the maximum size.
	const TPtrC8 remainder(aVoiceMailInfo.Remainder());

	if (remainder.Length() < CSmsAddress::KSmsAddressMaxAddressLength)
	    {
	    TBuf8<CSmsAddress::KSmsAddressMaxAddressLength> data;
	    data = remainder;
	    TInt actualLength = data.Length();
	    data.SetLength(CSmsAddress::KSmsAddressMaxAddressLength);

	    for (TUint8 j = actualLength; j < CSmsAddress::KSmsAddressMaxAddressLength; j++)
	        {
	        data[j] = 0;
	        }

	    TGsmuLex8 encodedAddress(data);
	    decodedAddress->DecodeL(encodedAddress);
	    // might want to check that aVoiceMailInfo can be incremented
	    // by encodedAddress.Offset.
	    aVoiceMailInfo.Inc(encodedAddress.Offset());
	    }
	else
	    {
	    decodedAddress->DecodeL(aVoiceMailInfo);
	    }

	TInt length=(decodedAddress->Address()).Length();
	NewBufferL(length);
	iAccessAddress->Des().Copy((decodedAddress->Address().Ptr()),length);

	iTypeOfAddress = decodedAddress->TypeOfAddress();

	CleanupStack::PopAndDestroy(decodedAddress);

	iNumberOfVoiceMessages = aVoiceMailInfo.GetL();
	LOGGSMU2("CEnhancedVoiceMailBoxInformation::DecodeL iNumberOfVoiceMessages = %d", iNumberOfVoiceMessages);
	} // CEnhancedVoiceMailBoxInformation::DecodeL


CEnhancedVoiceMailBoxInformation::CEnhancedVoiceMailBoxInformation()
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::CEnhancedVoiceMailBoxInformation()");

	// Consider changing this over to a Panic.
	iType               = EGsmSmsVoiceMailNotification;
	iOctet1Bit1         = EFalse;
	iProfile            = EGsmSmsProfileId1;
	iStorage            = EFalse;
	iAlmostFull         = EFalse;
	iFull               = EFalse;
	iExtensionIndicator = EFalse;
	iTypeOfAddress      = 0;
	} // CEnhancedVoiceMailBoxInformation::CEnhancedVoiceMailBoxInformation


CEnhancedVoiceMailBoxInformation::CEnhancedVoiceMailBoxInformation(TVoiceMailInfoType aTVoiceMailInfoType)
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::CEnhancedVoiceMailBoxInformation()");

	iType               = aTVoiceMailInfoType;
	iOctet1Bit1         = EFalse;
	iProfile            = EGsmSmsProfileId1;
	iStorage            = EFalse;
	iAlmostFull         = EFalse;
	iFull               = EFalse;
	iExtensionIndicator = EFalse;
	iTypeOfAddress      = 0;
	} // CEnhancedVoiceMailBoxInformation::CEnhancedVoiceMailBoxInformation


/**
 *  @internalComponent
 *  
 *  Prevent clients from using the copy constructor by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
CEnhancedVoiceMailBoxInformation::CEnhancedVoiceMailBoxInformation(const CEnhancedVoiceMailBoxInformation&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CEnhancedVoiceMailBoxInformation::CEnhancedVoiceMailBoxInformation");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    BULLSEYE_RESTORE
    }

/**
 *  @internalComponent
 *  
 *  Prevent clients from using the equality operator by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
TBool CEnhancedVoiceMailBoxInformation::operator==(const CEnhancedVoiceMailBoxInformation&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CEnhancedVoiceMailBoxInformation::operator==");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    return EFalse;
    BULLSEYE_RESTORE
    }

/**
 *  @internalComponent
 *  
 *  Prevent clients from using the assignment operator by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
void CEnhancedVoiceMailBoxInformation::operator=(const CEnhancedVoiceMailBoxInformation&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CEnhancedVoiceMailBoxInformation::operator=");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    BULLSEYE_RESTORE
    }

void CEnhancedVoiceMailBoxInformation::ConstructL()
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::ConstructL()");

	NewBufferL(0);
	} // CEnhancedVoiceMailBoxInformation::ConstructL


CEnhancedVoiceMailBoxInformation::~CEnhancedVoiceMailBoxInformation()
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::~CEnhancedVoiceMailBoxInformation");
	delete iAccessAddress;
	} // CEnhancedVoiceMailBoxInformation::ConstructL


CEnhancedVoiceMailBoxInformation* CEnhancedVoiceMailBoxInformation::NewL()
	{
	LOGGSMU1("CEnhancedVoiceMailBoxInformation::NewL()");

	CEnhancedVoiceMailBoxInformation* aCEnhancedVoiceMailBoxInformation=new(ELeave) CEnhancedVoiceMailBoxInformation();
	CleanupStack::PushL(aCEnhancedVoiceMailBoxInformation);
	aCEnhancedVoiceMailBoxInformation->ConstructL();
	CleanupStack::Pop(aCEnhancedVoiceMailBoxInformation);
	return aCEnhancedVoiceMailBoxInformation;
	} // CEnhancedVoiceMailBoxInformation::NewL


/**
 *  @publishedAll
 *  
 *  Sets the message id to a value between 0 and 65535.
 *  
 *  @param aNumber
 *  The message id
 *  
 *  @capability None
 */
EXPORT_C void CVoiceMailNotification::SetMessageId(TUint16 aMessageId)
	{
	LOGGSMU1("CVoiceMailNotification::SetMessageId()");

	iMessageId = aMessageId;
	} // CVoiceMailNotification::SetMessageId


/**
 *  @publishedAll
 *  
 *  Retrieves the message id, a value in the range 0 to 65535.
 *  
 *  @return
 *  The message id,
 *  
 *  @capability None
 */
EXPORT_C TUint16 CVoiceMailNotification::MessageId() const
	{
	LOGGSMU1("CVoiceMailNotification::MessageId()");

	return iMessageId;
	} // CVoiceMailNotification::MessageId


/**
 *  @publishedAll
 *  
 *  Sets the voice mail message length to a value between 0 and 255
 *  
 *  @param aLength
 *  The voice mail message length.
 *  
 *  @capability None
 */
EXPORT_C void CVoiceMailNotification::SetMessageLength(TUint8 aLength)
	{
	LOGGSMU1("CVoiceMailNotification::SetMessageLength()");

	iMessageLength=aLength;
	} // CVoiceMailNotification::SetMessageLength


/**
 *  @publishedAll
 *  
 *  Retrieves the voice mail message length, a value in the range 0 to 255.
 *  
 *  @return
 *  The voice mail message length.
 *  
 *  @capability None
 */
EXPORT_C TUint8 CVoiceMailNotification::MessageLength() const
	{
	LOGGSMU1("CVoiceMailNotification::MessageLength()");

	return iMessageLength;
	} // CVoiceMailNotification::MessageLength


/**
 *  @publishedAll
 *  
 *  Sets the number of days that the voice message will be retained to
 *  a value between 0 and 31. Values in excess of 31 will be capped at
 *  31.
 *  
 *  @param aDays
 *  The number of retention days.
 *  
 *  @capability None
 */
EXPORT_C void CVoiceMailNotification::SetRetentionDays(TUint8 aDays)
	{
	LOGGSMU1("CVoiceMailNotification::SetRetentionDays()");

	if (aDays > 31)
	    {
	    iRetentionDays = 31;
	    }
	else
	    {
	    iRetentionDays = aDays;
	    }
	} // CVoiceMailNotification::SetRetentionDays


/**
 *  @publishedAll
 *  
 *  Retrieves the number of days the voice message will be retained.
 *  
 *  @return
 *  The number of days the voice message will be retained.
 *  
 *  @capability None
 */
EXPORT_C TUint8 CVoiceMailNotification::RetentionDays() const
	{
	LOGGSMU1("CVoiceMailNotification::RetentionDays()");

	return iRetentionDays;
	} // CVoiceMailNotification::RetentionDays


/**
 *  @publishedAll
 *  
 *  Sets the message priority to urgent
 *  
 *  @param aPriority
 *  Set to True if the priority is urgent,
 *  Otherwise set to False.
 *  
 *  @capability None
 */
EXPORT_C void CVoiceMailNotification::SetPriorityIndication(TBool aPriority)
	{
	LOGGSMU1("CVoiceMailNotification::SetPriorityIndication()");

	iPriorityIndication=aPriority;
	} // CVoiceMailNotification::SetPriorityIndication


/**
 *  @publishedAll
 *  
 *  Retrieves the priority indication.
 *  
 *  @return
 *  True if the priority is urgent,
 *  False otherwise.
 *  
 *  @capability None
 */
EXPORT_C TBool CVoiceMailNotification::PriorityIndication() const
	{
	LOGGSMU1("CVoiceMailNotification::PriorityIndication()");

	return iPriorityIndication;
	} // CVoiceMailNotification::PriorityIndication


/**
 *  @publishedAll
 *  
 *  Indicates whether the voice mail notification contains extension bytes.
 *  
 *  @return
 *  True if the voice mail notification contains extension bytes.
 *  False otherwise.
 *  
 *  @capability None
 */
EXPORT_C TBool CVoiceMailNotification::MessageExtensionIndication() const
	{
	LOGGSMU1("CVoiceMailNotification::MessageExtensionIndication()");

	return iMessageExtensionIndicator;
	} // CVoiceMailNotification::MessageExtensionIndication


void CVoiceMailNotification::NewBufferL(TInt aLength)
	{
	LOGGSMU1("CVoiceMailNotification::NewBufferL()");

	HBufC* buffer=HBufC::NewL(aLength);
	delete iCallingLineIdentity;
	iCallingLineIdentity=buffer;
	iCallingLineIdentity->Des().SetLength(aLength);
	iCallingLineIdentity->Des().FillZ();
	} // CVoiceMailNotification::NewBufferL


/**
 *  @publishedAll
 *  
 *  Used to set the calling line idenity
 *  
 *  @param aLineIdentity
 *  
 *  @capability None
 */
EXPORT_C void  CVoiceMailNotification::SetCallingLineIdentityL(TDesC& aLineIdentity)
	{
	LOGGSMU1("CVoiceMailNotification::SetCallingLineIdentityL()");

	TInt length=aLineIdentity.Length();
	NewBufferL(length);
	iCallingLineIdentity->Des().Copy(aLineIdentity);

	const TGsmSmsTypeOfNumber typeofnumber=length && (iCallingLineIdentity->Des()[0]=='+')? EGsmSmsTONInternationalNumber: EGsmSmsTONUnknown;
	iTypeOfAddress.SetTON(typeofnumber);
	} // CVoiceMailNotification::SetCallingLineIdentityL


/**
 *  @publishedAll
 *  
 *  Retrieves the Calling Line Identity
 *  
 *  @return
 *  A pointer to the Calling Line Identity.
 *  
 *  @capability None
 */
EXPORT_C TPtrC CVoiceMailNotification::CallingLineIdentity() const
	{
	LOGGSMU1("CVoiceMailNotification::CallingLineIdentity()");

	TPtrC ptr;
	if (iCallingLineIdentity)
	    ptr.Set(iCallingLineIdentity->Des());
	return ptr;
	} // CVoiceMailNotification::CallingLineIdentity


/**
 *  @publishedAll
 *  
 *  Set the Calling Line Id as a parsed address.
 *  
 *  @param aParsedAddress
 *  The Calling Line Id as a parsed address.
 *  
 *  @capability None
 */
EXPORT_C void CVoiceMailNotification::SetParsedCallingLineIdentityL(TGsmSmsTelNumber& aParsedAddress)
	{
	LOGGSMU1("CVoiceMailNotification::SetParsedCallingLineIdentityL()");

	iTypeOfAddress=aParsedAddress.iTypeOfAddress;
	DoSetParsedAddressL(aParsedAddress.iTelNumber);
	} // CVoiceMailNotification::SetParsedCallingLineIdentityL


/**
 *  @publishedAll
 *  
 *  Gets the Calling Line Id as a parsed address.
 *  
 *  @param aParsedAddress
 *  An output parameter which is to be set to the parsed calling line ID.
 *  
 *  @capability None
 */
EXPORT_C void CVoiceMailNotification::ParsedCallingLineIdentity(TGsmSmsTelNumber& aParsedAddress) const
	{
	LOGGSMU1("CVoiceMailNotification::ParsedCallingLineIdentity()");

	aParsedAddress.iTypeOfAddress = iTypeOfAddress;

	TInt maxparsedlength=aParsedAddress.iTelNumber.MaxLength();

	if (iTypeOfAddress.TON()==EGsmSmsTONAlphaNumeric)
		{
		TInt parsedlength=CallingLineIdentity().Length();
		if (parsedlength>maxparsedlength)
			parsedlength=maxparsedlength;
		aParsedAddress.iTelNumber.Copy(CallingLineIdentity().Mid(0,parsedlength));
		}
	else
		{
		aParsedAddress.iTelNumber.SetLength(maxparsedlength);

		TInt length=iCallingLineIdentity->Des().Length();
		TInt parsedlength=0;
		for (TInt i=0; (i<length) && (parsedlength<maxparsedlength); i++)
			{
			TText ch=iCallingLineIdentity->Des()[i];
			if ((ch>='0') && (ch<='9'))
				{
				aParsedAddress.iTelNumber[parsedlength]=(TUint8) ch;
				parsedlength++;
				}
			}

		aParsedAddress.iTelNumber.SetLength(parsedlength);
		}
	} // CVoiceMailNotification::ParsedCallingLineIdentity


void CVoiceMailNotification::NewExtensionL(TInt aLength)
	{
	LOGGSMU1("CVoiceMailNotification::NewExtensionL()");

	HBufC* buffer=HBufC::NewL(aLength);
	delete iExtension;
	iExtension=buffer;
	iExtension->Des().SetLength(aLength);
	iExtension->Des().FillZ();
	} // CVoiceMailNotification::NewExtensionL


/*void CVoiceMailNotification::SetExtension(TDesC& aExtension)
	{
	LOGGSMU1("CVoiceMailNotification::SetExtension()");

	TInt length=aExtension.Length();
	NewExtensionL(length);
	iExtension->Des().Copy(aExtension);
	} // CVoiceMailNotification::SetExtension

TPtrC CVoiceMailNotification::Extension() const
	{
	LOGGSMU1("CVoiceMailNotification::Extension()");

	TPtrC ptr;
	if (iExtension)
	    ptr.Set(iExtension->Des());
	return ptr;
	}*/


/**
 *  @internalComponent
 *  
 *  Determines the size of the encoded Voice Mail Notification.
 *  
 *  @param aCharacterSetConverter  A reference to a character set converter.
 *  @param aFs  A reference to the file server.
 *  @return The size of the encoded Voice Mail Notification
 *  
 *  @capability None
 */
TUint8 CVoiceMailNotification::SizeL(CCnvCharacterSetConverter& aCharacterSetConverter, RFs& aFs)
	{
	LOGGSMU1("CVoiceMailNotification::SizeL()");

	const TUint8 KTotalSizeOfFixedLengthAttributes = 4;
	TUint8 size = KTotalSizeOfFixedLengthAttributes;

	// need to find the size of the calling line ID.
	CSmsAddress* address = CSmsAddress::NewL(aCharacterSetConverter,aFs);
	CleanupStack::PushL(address);

	TPtrC callingLineIdentityPtr;
	if (iCallingLineIdentity)
	    {
		callingLineIdentityPtr.Set(iCallingLineIdentity->Des());
	    }

	address->SetRawAddressL(iTypeOfAddress,callingLineIdentityPtr);

	size += address->SizeL();
	CleanupStack::PopAndDestroy(address);

	return size;
	} // CVoiceMailNotification::SizeL


TUint8* CVoiceMailNotification::EncodeL(TUint8* aPtr, CCnvCharacterSetConverter& aCharacterSetConverter, RFs& aFs) const
	{
	// When changes are made to this function that affect the
	// number of bytes that are encoded, this should be reflected in
	// CVoiceMailNotification::SizeL()
	LOGGSMU1("CVoiceMailNotification::EncodeL");


	*aPtr =   (TUint8)  (iMessageId                         >> 8);  // Message Id MSB
	aPtr++;
	*aPtr =   (TUint8)   iMessageId;                                // Message Id LSB
	aPtr++;
	*aPtr =   (TUint8)   iMessageLength;
	aPtr++;
	*aPtr =   ((TUint8)  (iRetentionDays & EMask5Bits))             +
	         (((TUint8)   iPriorityIndication)               << 6)  +
	         (((TUint8)   iMessageExtensionIndicator)        << 7);
	aPtr++;

	CSmsAddress* address = CSmsAddress::NewL(aCharacterSetConverter,aFs);
	CleanupStack::PushL(address);

	TPtrC callingLineIdentityPtr;
	if (iCallingLineIdentity)
	    {
		callingLineIdentityPtr.Set(iCallingLineIdentity->Des());
	    }

	address->SetRawAddressL(iTypeOfAddress,callingLineIdentityPtr);

	aPtr = address->EncodeL(aPtr);
	CleanupStack::PopAndDestroy(address);

	return aPtr;
	} // CVoiceMailNotification::EncodeL


void CVoiceMailNotification::DecodeL(TGsmuLex8& aVoiceMailInfo, CCnvCharacterSetConverter& aCharacterSetConverter, RFs& aFs)
	{
	LOGGSMU1("CVoiceMailNotification::DecodeL");

	iMessageId = (((TUint16) aVoiceMailInfo.GetL()) << 8);
	iMessageId += ((TUint16) aVoiceMailInfo.GetL());

	iMessageLength=aVoiceMailInfo.GetL();

	TUint8 currentByte = aVoiceMailInfo.GetL();

	iRetentionDays             =   currentByte       & EMask5Bits;
	iPriorityIndication        = ((currentByte >> 6) & EMask1Bit);
	iMessageExtensionIndicator = ((currentByte >> 7) & EMask1Bit);

	CSmsAddress* decodedAddress = CSmsAddress::NewL(aCharacterSetConverter,aFs);
	CleanupStack::PushL(decodedAddress);

	const TPtrC8 remainder(aVoiceMailInfo.Remainder());
	// The address information element makes an assumption that aVoiceMail must
	// be of size CSmsAddress::KSmsAddressMaxAddressLength
	// Provide padding to ensure that this is the case.
	if (remainder.Length() < CSmsAddress::KSmsAddressMaxAddressLength)
	    {
	    TBuf8<CSmsAddress::KSmsAddressMaxAddressLength> data;
	    data = remainder;
	    TInt actualLength = data.Length();
	    data.SetLength(CSmsAddress::KSmsAddressMaxAddressLength);

	    for (TUint8 j = actualLength; j < CSmsAddress::KSmsAddressMaxAddressLength; j++)
	        {
	        data[j] = 0;
	        }

	    TGsmuLex8 encodedAddress(data);
	    decodedAddress->DecodeL(encodedAddress);
	    // Should be the last piece of data to be decoded
	    // The next line is included for completeness.
	    aVoiceMailInfo.Inc(encodedAddress.Offset());
	    }
	else
	    {
	    decodedAddress->DecodeL(aVoiceMailInfo);
	    }

	TInt length=(decodedAddress->Address()).Length();
	NewBufferL(length);
	iCallingLineIdentity->Des().Copy((decodedAddress->Address().Ptr()),length);

	iTypeOfAddress = decodedAddress->TypeOfAddress();

	CleanupStack::PopAndDestroy(decodedAddress);

	if (iMessageExtensionIndicator)
	    {
	    TUint8 extensionLength = aVoiceMailInfo.GetL();
	    aVoiceMailInfo.Inc(extensionLength);
	    }
	} // CVoiceMailNotification::DecodeL


/**
 *  @internalComponent
 *  
 *  Prevent clients from using the copy constructor by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
CVoiceMailNotification::CVoiceMailNotification(const CVoiceMailNotification&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CVoiceMailNotification::CVoiceMailNotification");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    BULLSEYE_RESTORE
    }

/**
 *  @internalComponent
 *  
 *  Prevent clients from using the equality operator by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
TBool CVoiceMailNotification::operator==(const CVoiceMailNotification&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CVoiceMailNotification::operator==");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    return EFalse;
    BULLSEYE_RESTORE
    }

/**
 *  @internalComponent
 *  
 *  Prevent clients from using the assignment operator by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
void CVoiceMailNotification::operator=(const CVoiceMailNotification&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CVoiceMailNotification::operator=");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    BULLSEYE_RESTORE
    }

CVoiceMailNotification::CVoiceMailNotification()
	{
	LOGGSMU1("CVoiceMailNotification::CVoiceMailNotification()");

	iMessageId                 = 0;
	iMessageLength             = 0;
	iRetentionDays             = 0;
	iOctetN8Bit1               = EFalse;
	iPriorityIndication        = EFalse;
	iMessageExtensionIndicator = EFalse;
	iTypeOfAddress             = 0;
	} // CVoiceMailNotification::CVoiceMailNotification


/**
 *  @publishedAll
 *  
 *  Class Destructor
 *  
 *  @capability None
 */
EXPORT_C CVoiceMailNotification::~CVoiceMailNotification()
	{
	LOGGSMU1("CVoiceMailNotification::~CVoiceMailNotification");
	delete iCallingLineIdentity;
	delete iExtension;
	} // CVoiceMailNotification::CVoiceMailNotification


void CVoiceMailNotification::ConstructL()
	{
	LOGGSMU1("CVoiceMailNotification::ConstructL()");

	NewBufferL(0);
	NewExtensionL(0);
	} // CVoiceMailNotification::ConstructL


/**
 *  @publishedAll
 *  
 *  Class construction method.
 *  
 *  @capability None
 */
EXPORT_C CVoiceMailNotification* CVoiceMailNotification::NewL()
	{
	LOGGSMU1("CVoiceMailNotification::NewL()");

	CVoiceMailNotification* aCVoiceMailNotification=new(ELeave) CVoiceMailNotification();
	CleanupStack::PushL(aCVoiceMailNotification);
	aCVoiceMailNotification->ConstructL();
	CleanupStack::Pop(aCVoiceMailNotification);
	return aCVoiceMailNotification;
	} // CVoiceMailNotification::NewL


void CVoiceMailNotification::DoSetParsedAddressL(const TDesC& aAddress)
	{
	LOGGSMU1("CVoiceMailNotification::DoSetParsedAddressL()");

	TInt length=aAddress.Length();
	if ((iTypeOfAddress.TON()==EGsmSmsTONInternationalNumber) &&
	    (length && (aAddress[0]!='+')))
		{
		NewBufferL(length+1);
		iCallingLineIdentity->Des()[0]='+';
		TPtr ptr((TText*) (iCallingLineIdentity->Des().Ptr()+1),length,length);
		ptr.Copy(aAddress);
		}
	else
		{
		NewBufferL(length);
		iCallingLineIdentity->Des().Copy(aAddress);
		}
	} // CVoiceMailNotification::DoSetParsedAddressL


/**
 *  @publishedAll
 *  
 *  Retrieves the number of voice message notifications contained in
 *  this information. The range is 0 to 15.
 *  
 *  @return
 *  The number of voice message notifications in this information element.
 *  
 *  @capability None
 */
EXPORT_C TUint8 CEnhancedVoiceMailNotification::NumberOfVoiceMails()
	{
	LOGGSMU1("CEnhancedVoiceMailNotification::NumberOfVoiceMails()");

	return (TUint8) iNotifications->Count();
	} // CEnhancedVoiceMailNotification::NumberOfVoiceMails


/*void CEnhancedVoiceMailNotification::SetExtension(TDesC& aExtension)
	{
	LOGGSMU1("CEnhancedVoiceMailNotification::SetExtension()");

	TInt length=aExtension.Length();
	NewExtensionL(length);
	iExtension->Des().Copy(aExtension);
	} // CEnhancedVoiceMailNotification::SetExtension

TPtrC CEnhancedVoiceMailNotification::Extension() const
	{
	LOGGSMU1("CEnhancedVoiceMailNotification::Extension()");

	TPtrC ptr;
	if (iExtension)
	    ptr.Set(iExtension->Des());
	return ptr;
	}*/


/**
 *  @publishedAll
 *  
 *  Provides a reference to the collection that is used to contain the Voice Mail Notifications.
 *  A maximum of 15 voice mail confirmations is supported. If more that 15 voice mails notifications are added
 *  the CEnhancedVoiceMailNotification will not be added to the CSmsMessage by the CSmsEnhancedVoiceMailOperations
 *  class.
 *  
 *  @return
 *  A reference to the collection that is used to contain the Voice Mail Notifications.
 *  
 *  @capability None
 */
EXPORT_C RPointerArray<CVoiceMailNotification>& CEnhancedVoiceMailNotification::GetVoiceMailNotifications()
	{
	LOGGSMU1("CEnhancedVoiceMailNotification::GetVoiceMailNotifications()");

	return *iNotifications;
	} // CEnhancedVoiceMailNotification::GetVoiceMailNotifications


void CEnhancedVoiceMailNotification::NewExtensionL(TInt aLength)
	{
	LOGGSMU1("CEnhancedVoiceMailNotification::NewExtensionL()");

	HBufC* buffer=HBufC::NewL(aLength);
	delete iExtension;
	iExtension=buffer;
	iExtension->Des().SetLength(aLength);
	iExtension->Des().FillZ();
	} // CEnhancedVoiceMailNotification::NewExtensionL


/**
 *  @publishedAll
 *  
 *  Class construction method.
 *  
 *  @capability None
 */
EXPORT_C  CEnhancedVoiceMailNotification* CEnhancedVoiceMailNotification::NewL()
	{
	LOGGSMU1("CEnhancedVoiceMailNotification::NewL()");

	CEnhancedVoiceMailNotification* aCEnhancedVoiceMailNotification=new(ELeave) CEnhancedVoiceMailNotification();
	CleanupStack::PushL(aCEnhancedVoiceMailNotification);
	aCEnhancedVoiceMailNotification->CEnhancedVoiceMailBoxInformation::ConstructL();
	aCEnhancedVoiceMailNotification->ConstructL();
	CleanupStack::Pop(aCEnhancedVoiceMailNotification);
	return aCEnhancedVoiceMailNotification;
	} // CEnhancedVoiceMailNotification::NewL


CEnhancedVoiceMailNotification::CEnhancedVoiceMailNotification() : CEnhancedVoiceMailBoxInformation(EGsmSmsVoiceMailNotification)
	{
	} // CEnhancedVoiceMailNotification::CEnhancedVoiceMailNotification


/**
 *  @internalComponent
 *  
 *  Prevent clients from using the copy constructor by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
CEnhancedVoiceMailNotification::CEnhancedVoiceMailNotification(const CEnhancedVoiceMailNotification&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CEnhancedVoiceMailNotification::CEnhancedVoiceMailNotification");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    BULLSEYE_RESTORE
    }

/**
 *  @internalComponent
 *  
 *  Prevent clients from using the equality operator by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
TBool CEnhancedVoiceMailNotification::operator==(const CEnhancedVoiceMailNotification&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CEnhancedVoiceMailNotification::operator==");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    return EFalse;
    BULLSEYE_RESTORE
    }

/**
 *  @internalComponent
 *  
 *  Prevent clients from using the assignment operator by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
void CEnhancedVoiceMailNotification::operator=(const CEnhancedVoiceMailNotification&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CEnhancedVoiceMailNotification::operator=");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    BULLSEYE_RESTORE
    }

/**
 *  @publishedAll
 *  
 *  Class destructor.
 *  
 *  @capability None
 */
EXPORT_C  CEnhancedVoiceMailNotification::~CEnhancedVoiceMailNotification()
	{
	LOGGSMU1("CEnhancedVoiceMailNotification::~CEnhancedVoiceMailNotification");
	delete iExtension;
	iNotifications->ResetAndDestroy();
	iNotifications->Close();
	delete iNotifications;
	} // CEnhancedVoiceMailNotification::operator


void CEnhancedVoiceMailNotification::ConstructL()
	{
	LOGGSMU1("CEnhancedVoiceMailNotification::ConstructL()");

	NewExtensionL(0);
	iNotifications = new (ELeave) RPointerArray<CVoiceMailNotification>(KMaxNumberOfNotifications);
	} // CEnhancedVoiceMailNotification::ConstructL


TUint8* CEnhancedVoiceMailNotification::EncodeL(TUint8* aCurrentPtr, CCnvCharacterSetConverter& aCharacterSetConverter, RFs& aFs) const
	{
	LOGGSMU1("CEnhancedVoiceMailNotification::EncodeL");

	TUint8* startPtr   = aCurrentPtr;

	aCurrentPtr = CEnhancedVoiceMailBoxInformation::EncodeL(aCurrentPtr, aCharacterSetConverter, aFs);

	TUint8 count = (TUint8)  iNotifications->Count();
	if (count > KMaxNumberOfNotifications)
	    {
	    User::Leave(KErrArgument);
	    }

	*aCurrentPtr = (count & KSmsNotificationBitMask);
	aCurrentPtr++;

	TInt16 spaceAlreadyAllocated = 0; // handle architectures whose address space increments and whose address space decrements.
	(aCurrentPtr > startPtr) ? (spaceAlreadyAllocated = aCurrentPtr - startPtr) : (spaceAlreadyAllocated = startPtr - aCurrentPtr);

	TInt16 remainingSize = (TInt16)(CEnhancedVoiceMailNotification::KSmsMaxEnhancedVoiceMailSize - spaceAlreadyAllocated);
	for (TUint i = 0; i < count; i++)
	    {
	    remainingSize -= (TInt16)(*iNotifications)[i]->SizeL(aCharacterSetConverter,aFs);
	    if (remainingSize < 0)
	        {
	        User::Leave(KErrArgument);
	        }

	    aCurrentPtr = (*iNotifications)[i]->EncodeL(aCurrentPtr, aCharacterSetConverter, aFs);
	    }

	return aCurrentPtr;
	} // CEnhancedVoiceMailNotification::EncodeL


void CEnhancedVoiceMailNotification::DecodeL(TGsmuLex8& aVoiceMailInfo, CCnvCharacterSetConverter& aCharacterSetConverter, RFs& aFs)
	{
	LOGGSMU1("CEnhancedVoiceMailNotification::DecodeL");

	CEnhancedVoiceMailBoxInformation::DecodeL(aVoiceMailInfo, aCharacterSetConverter, aFs);

	TUint8 numberOfNotifications = (aVoiceMailInfo.GetL() & KSmsNotificationBitMask);

	if (iExtensionIndicator)
	    {
	    TUint8 extensionLength = aVoiceMailInfo.GetL();
	    aVoiceMailInfo.Inc(extensionLength);
	    }

	for (TUint8 i = 0; i < numberOfNotifications; i++)
	    {
	    CVoiceMailNotification* voiceMailNotification = CVoiceMailNotification::NewL();
	    CleanupStack::PushL(voiceMailNotification);
	    voiceMailNotification->DecodeL(aVoiceMailInfo, aCharacterSetConverter, aFs);
	    iNotifications->AppendL(voiceMailNotification);
	    CleanupStack::Pop(voiceMailNotification);
	    }
	} // CEnhancedVoiceMailNotification::DecodeL


/**
 *  @publishedAll
 *  
 *  Sets the message ID of the specific Voice Mail message
 *  whose deletion is being confirmed.
 *  
 *  @param aMessageId
 *  The message ID of the specific voice mail message whose deletion
 *  is being confirmed.
 *  
 *  @capability None
 */
EXPORT_C void CVoiceMailDeletion::SetMessageId(TUint16 aMessageId)
	{
	LOGGSMU1("CVoiceMailDeletion::SetMessageId()");

	iMessageId=aMessageId;
	} // CVoiceMailDeletion::SetMessageId


/**
 *  @publishedAll
 *  
 *  Retrieves the message ID of the Voice Mail message
 *  whose deletion is being confirmed, range 0 to 65535.
 *  
 *  @return
 *  The message ID of the Voice Mail message whose deletion
 *  is being confirmed, range 0 to 65535.
 *  
 *  @capability None
 */
EXPORT_C TUint16 CVoiceMailDeletion::MessageId() const
	{
	LOGGSMU1("CVoiceMailDeletion::MessageId()");

	return iMessageId;
	} // CVoiceMailDeletion::MessageId


/**
 *  @publishedAll
 *  
 *  Indicates whether the voice mail deletion contains extension bytes.
 *  
 *  @return
 *  True if the voice mail deletion contains extension bytes.
 *  False otherwise.
 *  
 *  @capability None
 */
EXPORT_C TBool CVoiceMailDeletion::MessageExtensionIndication() const
	{
	LOGGSMU1("CVoiceMailDeletion::MessageExtensionIndication()");

	return iExtensionIndicator;
	} // CVoiceMailDeletion::MessageExtensionIndication


TUint8 CVoiceMailDeletion::SizeL()
	{
	LOGGSMU1("CVoiceMailDeletion::SizeL()");

	const TUint8 KSizeOfVoiceMailDeletion = 3;
	return KSizeOfVoiceMailDeletion;
	} // CVoiceMailDeletion::SizeL


TUint8* CVoiceMailDeletion::EncodeL(TUint8* aPtr) const
	{
	// When changes are made which affect the
	// number of bytes encoded, this should be
	// reflected in VoiceMailDeletion::SizeL()
	LOGGSMU1("CVoiceMailDeletion::EncodeL");

	*aPtr =  (TUint8) (iMessageId >> 8);
	aPtr++;
	*aPtr =  (TUint8) iMessageId;
	aPtr++;
	*aPtr = ((TUint8) iExtensionIndicator) << 7;
	aPtr++;
	return aPtr;
	} // CVoiceMailDeletion::EncodeL


void CVoiceMailDeletion::DecodeL(TGsmuLex8& aVoiceMailInfo)
	{
	LOGGSMU1("CVoiceMailDeletion::DecodeL");

	iMessageId = (((TUint16) aVoiceMailInfo.GetL()) << 8) +
	              ((TUint16) aVoiceMailInfo.GetL());
	iExtensionIndicator =    (aVoiceMailInfo.GetL() >> 7);

	if (iExtensionIndicator)
	    {
	    TUint8 extensionLength = aVoiceMailInfo.GetL();
	    aVoiceMailInfo.Inc(extensionLength);
	    }
	} // CVoiceMailDeletion::DecodeL


CVoiceMailDeletion::CVoiceMailDeletion()
	{
	iMessageId = 0;
	iExtensionIndicator = EFalse;
	} // CVoiceMailDeletion::CVoiceMailDeletion


/**
 *  @internalComponent
 *  
 *  Prevent clients from using the copy constructor by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
CVoiceMailDeletion::CVoiceMailDeletion(const CVoiceMailDeletion&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CVoiceMailDeletion::CVoiceMailDeletion");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    BULLSEYE_RESTORE
    }

/**
 *  @internalComponent
 *  
 *  Prevent clients from using the equality operator by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
TBool CVoiceMailDeletion::operator==(const CVoiceMailDeletion&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CVoiceMailDeletion::operator==");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    return EFalse;
    BULLSEYE_RESTORE
    }

/**
 *  @internalComponent
 *  
 *  Prevent clients from using the assignment operator by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
void CVoiceMailDeletion::operator=(const CVoiceMailDeletion&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CVoiceMailDeletion::operator=");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    BULLSEYE_RESTORE
    }

/**
 *  @publishedAll
 *  
 *  Class destructor.
 *  
 *  @capability None
 */
EXPORT_C CVoiceMailDeletion::~CVoiceMailDeletion()
	{
	LOGGSMU1("CVoiceMailDeletion::~CVoiceMailDeletion");

	delete iExtension;
	} // CVoiceMailDeletion::operator


void CVoiceMailDeletion::ConstructL()
	{
	LOGGSMU1("CVoiceMailDeletion::ConstructL()");

	NewBufferL(0);
	} // CVoiceMailDeletion::ConstructL


void CVoiceMailDeletion::NewBufferL(TInt aLength)
	{
	LOGGSMU1("CVoiceMailDeletion::NewBufferL()");

	HBufC* buffer=HBufC::NewL(aLength);
	delete iExtension;
	iExtension=buffer;
	iExtension->Des().SetLength(aLength);
	iExtension->Des().FillZ();
	} // CVoiceMailDeletion::NewBufferL


/**
 *  @publishedAll
 *  
 *  Class constructor
 *  
 *  @capability None
 */
EXPORT_C CVoiceMailDeletion* CVoiceMailDeletion::NewL()
	{
	LOGGSMU1("CVoiceMailDeletion::NewL()");

	CVoiceMailDeletion* voiceMailDeletion=new(ELeave) CVoiceMailDeletion();
	CleanupStack::PushL(voiceMailDeletion);
	voiceMailDeletion->ConstructL();
	CleanupStack::Pop(voiceMailDeletion);
	return voiceMailDeletion;
	} // CVoiceMailDeletion::NewL


/*
void CVoiceMailDeletion::SetExtension(TDesC& aExtension)
	{
	LOGGSMU1("CVoiceMailDeletion::SetExtension()");

	TInt length=aExtension.Length();
	NewBufferL(length);
	iExtension->Des().Copy(aExtension);
	} // CVoiceMailDeletion::SetExtension


TPtrC CVoiceMailDeletion::Extension() const
	{
	LOGGSMU1("CVoiceMailDeletion::Extension()");

	TPtrC ptr;
	if (iExtension)
	    ptr.Set(iExtension->Des());
	return ptr;
	}*/


void CEnhancedVoiceMailDeleteConfirmations::NewExtensionL(TInt aLength)
	{
	LOGGSMU1("CEnhancedVoiceMailDeleteConfirmations::NewExtensionL()");

	HBufC* buffer=HBufC::NewL(aLength);
	delete iExtension;
	iExtension=buffer;
	iExtension->Des().SetLength(aLength);
	iExtension->Des().FillZ();
	} // CEnhancedVoiceMailDeleteConfirmations::NewExtensionL


CEnhancedVoiceMailDeleteConfirmations::CEnhancedVoiceMailDeleteConfirmations() : CEnhancedVoiceMailBoxInformation(EGsmSmsVoiceMailDeleteConfirmation)
	{
	//NOP
	} // CEnhancedVoiceMailDeleteConfirmations::CEnhancedVoiceMailDeleteConfirmations


/**
 *  @publishedAll
 *  
 *  Class destructor
 *  
 *  @capability None
 */
EXPORT_C  CEnhancedVoiceMailDeleteConfirmations::~CEnhancedVoiceMailDeleteConfirmations()
	{
	LOGGSMU1("CEnhancedVoiceMailDeleteConfirmations::~CEnhancedVoiceMailDeleteConfirmations");

	delete iExtension;
	iVoiceMailDeletions->ResetAndDestroy();
	iVoiceMailDeletions->Close();
	delete iVoiceMailDeletions;
	} // CEnhancedVoiceMailDeleteConfirmations::CEnhancedVoiceMailDeleteConfirmations


/**
 *  @internalComponent
 *  
 *  Prevent clients from using the copy constructor by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
CEnhancedVoiceMailDeleteConfirmations::CEnhancedVoiceMailDeleteConfirmations(const CEnhancedVoiceMailDeleteConfirmations&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CEnhancedVoiceMailDeleteConfirmations::CEnhancedVoiceMailDeleteConfirmations");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    BULLSEYE_RESTORE
    }

/**
 *  @internalComponent
 *  
 *  Prevent clients from using the equality operator by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
TBool CEnhancedVoiceMailDeleteConfirmations::operator==(const CEnhancedVoiceMailDeleteConfirmations&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CEnhancedVoiceMailDeleteConfirmations::operator==");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    return EFalse;
    BULLSEYE_RESTORE
    }

/**
 *  @internalComponent
 *  
 *  Prevent clients from using the assignment operator by including it in the class definition
 *  but making it protected and not exporting it.
 *  
 *  @capability None
 */
void CEnhancedVoiceMailDeleteConfirmations::operator=(const CEnhancedVoiceMailDeleteConfirmations&)
    {
    // Ignore in code coverage - not intended to be used
    BULLSEYE_OFF    
    LOGGSMU1("CEnhancedVoiceMailDeleteConfirmations::operator=");
    Panic(KGsmuPanicMethodBodyNotImplemented);
    BULLSEYE_RESTORE
    }

void CEnhancedVoiceMailDeleteConfirmations::ConstructL()
	{
	LOGGSMU1("CEnhancedVoiceMailDeleteConfirmations::ConstructL()");

	NewExtensionL(0);

	iVoiceMailDeletions = new (ELeave) RPointerArray<CVoiceMailDeletion>(15);
	} // CEnhancedVoiceMailDeleteConfirmations::ConstructL


/**
 *  @publishedAll
 *  
 *  Class constructor
 *  
 *  @capability None
 */
EXPORT_C  CEnhancedVoiceMailDeleteConfirmations* CEnhancedVoiceMailDeleteConfirmations::NewL()
	{
	LOGGSMU1("CEnhancedVoiceMailDeleteConfirmations::NewL()");

	CEnhancedVoiceMailDeleteConfirmations* aCEnhancedVoiceMailDeleteConfirmations=new(ELeave) CEnhancedVoiceMailDeleteConfirmations();
	CleanupStack::PushL(aCEnhancedVoiceMailDeleteConfirmations);
	aCEnhancedVoiceMailDeleteConfirmations->CEnhancedVoiceMailBoxInformation::ConstructL();
	aCEnhancedVoiceMailDeleteConfirmations->ConstructL();
	CleanupStack::Pop(aCEnhancedVoiceMailDeleteConfirmations);
	return aCEnhancedVoiceMailDeleteConfirmations;
	} // CEnhancedVoiceMailDeleteConfirmations::NewL


/**
 *  @publishedAll
 *  
 *  Indicates the number of message IDs that follow in this IE.
 *  
 *  @return
 *  The number of message IDs that follow.
 *  
 *  @capability None
 */
EXPORT_C TUint8  CEnhancedVoiceMailDeleteConfirmations::NumberOfDeletes()
	{
	LOGGSMU1("CEnhancedVoiceMailDeleteConfirmations::NumberOfDeletes()");

	return iVoiceMailDeletions->Count();
	} // CEnhancedVoiceMailDeleteConfirmations::NumberOfDeletes


/**
 *  @publishedAll
 *  
 *  Provides a reference to the collection that is used to contain the Voice Mail Deletion
 *  notifications. Up to 31 instances of CVoiceMailDeletion can be stored. If more than
 *  31 instances are added, the CEnhancedVoiceMailDeleteConfirmations will not be added to
 *  the CSmsMessage.
 *  
 *  @return
 *  A reference to the collection that is used to contain the Voice Mail Deletion
 *  notifications.
 *  
 *  @capability None
 */
EXPORT_C RPointerArray<CVoiceMailDeletion>& CEnhancedVoiceMailDeleteConfirmations::GetVoiceMailDeletions()
	{
	LOGGSMU1("CEnhancedVoiceMailDeleteConfirmations::GetVoiceMailDeletions()");

	return *iVoiceMailDeletions;
	} // CEnhancedVoiceMailDeleteConfirmations::GetVoiceMailDeletions


/*
void CEnhancedVoiceMailDeleteConfirmations::SetExtension(TDesC& aExtension)
	{
	LOGGSMU1("CEnhancedVoiceMailDeleteConfirmations::SetExtension()");

	TInt length=aExtension.Length();
	NewBufferL(length);
	iExtension->Des().Copy(aExtension);
	} // CEnhancedVoiceMailDeleteConfirmations::SetExtension


TPtrC CEnhancedVoiceMailDeleteConfirmations::Extension() const
	{
	LOGGSMU1("CEnhancedVoiceMailDeleteConfirmations::Extension()");

	TPtrC ptr;
	if (iExtension)
		{
		ptr.Set(iExtension->Des());
		}
	return ptr;
	}*/


TUint8* CEnhancedVoiceMailDeleteConfirmations::EncodeL(TUint8* aCurrentPtr, CCnvCharacterSetConverter& aCharacterSetConverter, RFs& aFs) const
	{
	LOGGSMU1("CEnhancedVoiceMailDeleteConfirmations::EncodeL");

	TUint8* startPtr   = aCurrentPtr;

	aCurrentPtr = CEnhancedVoiceMailBoxInformation::EncodeL(aCurrentPtr, aCharacterSetConverter, aFs);

	TUint8 count = ((TUint8)iVoiceMailDeletions->Count());

	if (count > KMaxNumberOfNotifications)
	    {
	    User::Leave(KErrArgument);
	    }

	*aCurrentPtr= (count & KSmsNotificationBitMask);
	aCurrentPtr++;

	TInt16 spaceAlreadyAllocated; // handle architectures whose address space increments and whose address space decrements.
	(aCurrentPtr > startPtr) ? (spaceAlreadyAllocated = aCurrentPtr - startPtr) : (spaceAlreadyAllocated = startPtr - aCurrentPtr);

	// allow space for id and length bytes
	TInt16 remainingSize = (TInt16)(CEnhancedVoiceMailBoxInformation::KSmsMaxEnhancedVoiceMailSize - spaceAlreadyAllocated);

	for (TUint i = 0; i < count; i++)
	    {
	    remainingSize -= (TInt16)(*iVoiceMailDeletions)[i]->SizeL();
	    if (remainingSize < 0)
	        {
	        User::Leave(KErrArgument);
	        }

	    aCurrentPtr = (*iVoiceMailDeletions)[i]->EncodeL(aCurrentPtr);
	    }

	return aCurrentPtr;
	} // CEnhancedVoiceMailDeleteConfirmations::EncodeL


void CEnhancedVoiceMailDeleteConfirmations::DecodeL(TGsmuLex8& aVoiceMailInfo, CCnvCharacterSetConverter& aCharacterSetConverter, RFs& aFs)
	{
	LOGGSMU1("CEnhancedVoiceMailDeleteConfirmations::DecodeL");

	CEnhancedVoiceMailBoxInformation::DecodeL(aVoiceMailInfo, aCharacterSetConverter, aFs);

	TUint numberOfVMDeletions = (aVoiceMailInfo.GetL() & KSmsNotificationBitMask);

	if (iExtensionIndicator)
		{
		TUint8 extensionLength = aVoiceMailInfo.GetL();
		aVoiceMailInfo.Inc(extensionLength);
		}

	for (TUint8 i = 0; i < numberOfVMDeletions; i++)
		{
		// Create a Voice Mail Deletion
		CVoiceMailDeletion* voiceMailDeletion = CVoiceMailDeletion::NewL();
		CleanupStack::PushL(voiceMailDeletion);
		voiceMailDeletion->DecodeL(aVoiceMailInfo);
		CleanupStack::Pop(voiceMailDeletion);
		iVoiceMailDeletions->Append(voiceMailDeletion);
		}
	} // CEnhancedVoiceMailDeleteConfirmations::DecodeL