smsprotocols/smsstack/gsmu/src/Gsmumsg.cpp
changeset 0 3553901f7fa8
child 9 2492a6e4aed7
equal deleted inserted replaced
-1:000000000000 0:3553901f7fa8
       
     1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Contains the implementation of the CSmsMessage class
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file
       
    20 */
       
    21 
       
    22 #include <gsmumsg.h>
       
    23 #include "Gsmumain.h"
       
    24 #include <gsmubuf.h>
       
    25 #include <gsmuset.h>
       
    26 #include <gsmusar.h>
       
    27 #include "gsmumsgadditionalattributes.h"
       
    28 #include <gsmuieoperations.h>
       
    29 #include <gsmunonieoperations.h>
       
    30 
       
    31 #include <logwrap.h> //  Used for KLogNullId only
       
    32 #include <e32uid.h>
       
    33 #include <etelmm.h>
       
    34 #include <logwraplimits.h>
       
    35 
       
    36 #include <emsinformationelement.h>
       
    37 #include <emsformatie.h>
       
    38 #include <emsuserpromptie.h>
       
    39 #include <emsobjectdistributionie.h>
       
    40 #include "smsstackutils.h"
       
    41 
       
    42 /**
       
    43  *  Allocates and creates a CSmsMessage instance from a TGsmSms.
       
    44  *  
       
    45  *  The type of SMS-XXXX message to construct is defined by the first byte of
       
    46  *  the TGsmSms TPDU header.
       
    47  *  
       
    48  *  @param aFs Reference handle to the file system
       
    49  *  @param aGsmSms Reference to TGsmSms
       
    50  *  @param aBuffer The Unicode text for the message. The object takes ownership
       
    51  *  of aBuffer.
       
    52  *  @param aIsRPError Set to true if the message contains Reply Path Error. Default
       
    53  *  is false.
       
    54  *  @param aIsMobileTerminated Set to True if the message is Mobile Terminated.
       
    55  *  Default is false.
       
    56  *  @return New CSmsMessage object
       
    57  *  @capability None
       
    58  */
       
    59 EXPORT_C CSmsMessage* CSmsMessage::NewL(RFs& aFs, const TGsmSms& aGsmSms,CSmsBufferBase* aBuffer, TBool aIsRPError,TBool aIsMobileTerminated)
       
    60 	{
       
    61 	LOGGSMU1("CSmsMessage::NewL()");
       
    62 	
       
    63 	CleanupStack::PushL(aBuffer);
       
    64 	CSmsMessage* smsmessage=new(ELeave) CSmsMessage(aFs, aBuffer);
       
    65 	CleanupStack::Pop();
       
    66 	CleanupStack::PushL(smsmessage);
       
    67 	smsmessage->ConstructL(aGsmSms, aIsRPError,aIsMobileTerminated);
       
    68 	CleanupStack::Pop();
       
    69 	return smsmessage;
       
    70 	} // CSmsMessage::NewL
       
    71 
       
    72 
       
    73 /**
       
    74  *  Allocates and creates a CSmsMessage, specifying the SMS-XXX message type with
       
    75  *  a CSmsPDU::TSmsPduType.
       
    76  *  
       
    77  *  @param aFs Reference handle to the file system
       
    78  *  @param aType The PDU type
       
    79  *  @param aBuffer The Unicode text for the message. The object takes ownership
       
    80  *  of aBuffer.
       
    81  *  @param aIsRPError Set to true if the message contains Reply Path Error. Default
       
    82  *  is false.
       
    83  *  @return New CSmsMessage object
       
    84  *  @capability None
       
    85  */
       
    86 EXPORT_C CSmsMessage* CSmsMessage::NewL(RFs& aFs, CSmsPDU::TSmsPDUType aType,CSmsBufferBase* aBuffer,TBool aIsRPError)
       
    87 	{
       
    88 	LOGGSMU1("CSmsMessage::NewL()");
       
    89 
       
    90 	CleanupStack::PushL(aBuffer);
       
    91 	CSmsMessage* smsmessage=new(ELeave) CSmsMessage(aFs, aBuffer);
       
    92 	CleanupStack::Pop();
       
    93 	CleanupStack::PushL(smsmessage);
       
    94 	smsmessage->ConstructL(aType,aIsRPError);
       
    95 	CleanupStack::Pop();
       
    96 	return smsmessage;
       
    97 	} // CSmsMessage::NewL
       
    98 
       
    99 
       
   100 /**
       
   101  *  Destructor, frees resources.
       
   102  *  @capability None
       
   103  */
       
   104 EXPORT_C CSmsMessage::~CSmsMessage()
       
   105 	{
       
   106 	LOGGSMU1("CSmsMessage::~CSmsMessage()");
       
   107 
       
   108 	delete iSmsPDU;
       
   109 	delete iBuffer;
       
   110 	delete iCharacterSetConverter;
       
   111 
       
   112 	if (iInformationElementArray)
       
   113 		{
       
   114 		iInformationElementArray->ResetAndDestroy();
       
   115 		delete iInformationElementArray;
       
   116 		}
       
   117 
       
   118 	delete iAdditionalInfo;
       
   119 	} // CSmsMessage::NewL
       
   120 
       
   121 
       
   122 /**
       
   123  *  Internalises all object data except for the CSmsBufferBase.
       
   124  *  
       
   125  *  This is used when the buffer is stored elsewhere.
       
   126  *  
       
   127  *  @param aStream Stream to read from
       
   128  *  @capability None
       
   129  */
       
   130 EXPORT_C void CSmsMessage::InternalizeWithoutBufferL(RReadStream& aStream)
       
   131 	{
       
   132 	LOGGSMU1("CSmsMessage::InternalizeWithoutBufferL()");
       
   133 
       
   134 	InternalizeWithoutBufferAndVersionL(aStream);
       
   135 	InternalizeVersionL(aStream);
       
   136 
       
   137 	iAdditionalInfo->ResetAttributesL();
       
   138 
       
   139 	if (iVersion > ESmsMessageV0)
       
   140         {
       
   141         iAdditionalInfo->InternalizeL(aStream, iVersion);
       
   142 		}
       
   143 	} // CSmsMessage::InternalizeWithoutBufferL
       
   144 
       
   145 
       
   146 /**
       
   147  *  Externalises all object data except for the CSmsBufferBase.
       
   148  *  
       
   149  *  This is used when the buffer is stored elsewhere.
       
   150  *  
       
   151  *  @param aStream Stream to write to
       
   152  *  @capability None
       
   153  */
       
   154 EXPORT_C void CSmsMessage::ExternalizeWithoutBufferL(RWriteStream& aStream) const
       
   155 	{
       
   156 	LOGGSMU1("CSmsMessage::ExternalizeWithoutBufferL()");
       
   157 
       
   158 	ExternalizeWithoutBufferAndVersionL(aStream);
       
   159 	ExternalizeVersionL(aStream);
       
   160 
       
   161 	if (iVersion > ESmsMessageV0)
       
   162 		{
       
   163 		iAdditionalInfo->ExternalizeL(aStream, iVersion);
       
   164 		}
       
   165 	} // CSmsMessage::ExternalizeWithoutBufferL
       
   166 
       
   167 
       
   168 /**
       
   169  *  Internalises all object data.
       
   170  *  
       
   171  *  @param aStream Stream to read from
       
   172  *  @capability None
       
   173  */
       
   174 EXPORT_C void CSmsMessage::InternalizeL(RReadStream& aStream)
       
   175 	{
       
   176 	LOGGSMU1("CSmsMessage::InternalizeL()");
       
   177 
       
   178 	InternalizeWithoutBufferAndVersionL(aStream);
       
   179 	InternalizeBufferL(aStream);
       
   180 	InternalizeVersionL(aStream);
       
   181 
       
   182 	iAdditionalInfo->ResetAttributesL();
       
   183 	if (iVersion > ESmsMessageV0)
       
   184 		{
       
   185 		iAdditionalInfo->InternalizeL(aStream, iVersion);
       
   186 		}
       
   187 	} // CSmsMessage::InternalizeL
       
   188 
       
   189 
       
   190 /**
       
   191  *  Externalises all object data.
       
   192  *  
       
   193  *  @param aStream Stream to write to
       
   194  *  @capability None
       
   195  */
       
   196 EXPORT_C void CSmsMessage::ExternalizeL(RWriteStream& aStream) const
       
   197 	{
       
   198 	LOGGSMU1("CSmsMessage::ExternalizeL()");
       
   199 
       
   200 	ExternalizeWithoutBufferAndVersionL(aStream);
       
   201 	ExternalizeBufferL(aStream);
       
   202 	ExternalizeVersionL(aStream);
       
   203 
       
   204 	if (iVersion > ESmsMessageV0)
       
   205 		{
       
   206 		iAdditionalInfo->ExternalizeL(aStream, iVersion);
       
   207 		}
       
   208 	} // CSmsMessage::ExternalizeL
       
   209 
       
   210 
       
   211 /**
       
   212  *  Tests if the message contains text.
       
   213  *  
       
   214  *  @return True if the message contains text
       
   215  *  @capability None
       
   216  */
       
   217 EXPORT_C TBool CSmsMessage::TextPresent() const
       
   218 	{
       
   219 	LOGGSMU1("CSmsMessage::TextPresent()");
       
   220 
       
   221 	CSmsPDU::TSmsPDUType pdutype=SmsPDU().Type();
       
   222 	return (pdutype==CSmsPDU::ESmsSubmit) ||
       
   223 	       (pdutype==CSmsPDU::ESmsDeliver) ||
       
   224 	     (((pdutype==CSmsPDU::ESmsSubmitReport) || (pdutype==CSmsPDU::ESmsDeliverReport) ||
       
   225 	      ((pdutype==CSmsPDU::ESmsStatusReport) && ((CSmsStatusReport&) SmsPDU()).ParameterIndicatorPresent())) &&
       
   226 	      SmsPDU().UserDataPresent());
       
   227 	} // CSmsMessage::TextPresent
       
   228 
       
   229 
       
   230 /**
       
   231  *  Gets the number of PDU's required to encode the complete message.
       
   232  *  
       
   233  *  @leave KErrOverflow Leaves if the number of required PDUs exceeds the maximum
       
   234  *  or the message cannot be encoded.
       
   235  *  @return Number of PDU's
       
   236  *  @capability None
       
   237  */
       
   238 EXPORT_C TInt CSmsMessage::NumMessagePDUsL()
       
   239 	{
       
   240 	LOGGSMU1("CSmsMessage::NumMessagePDUsL()");
       
   241 
       
   242 	TInt nummessagepdus=1;
       
   243 	if (IsDecoded())
       
   244 		{
       
   245 		if (TextPresent())
       
   246 			{
       
   247 			nummessagepdus=NumMessageEmsPDUsL();
       
   248 			TInt maxnummessagepdus=SmsPDU().TextConcatenated()? 0xFF: 1;
       
   249  			if (nummessagepdus>maxnummessagepdus)
       
   250 				{
       
   251  				User::Leave(KErrOverflow);
       
   252 				}
       
   253 			}
       
   254 
       
   255 		}
       
   256 	else if (TextPresent() && SmsPDU().TextConcatenated())
       
   257 		{
       
   258 		nummessagepdus=SmsPDU().NumConcatenatedMessagePDUs();
       
   259 		}
       
   260 
       
   261 	LOGGSMU2("CSmsMessage::NumMessagePDUsL() returns %d", nummessagepdus);
       
   262 
       
   263 	return nummessagepdus;
       
   264 	} // CSmsMessage::NumMessagePDUsL
       
   265 
       
   266 
       
   267 /**
       
   268  *  Gets the maximum message length possible with the current settings.
       
   269  *  
       
   270  *  If Text is compressed, this returns the maximum number of bytes available
       
   271  *  with text compressed.
       
   272  *  
       
   273  *  @return Maximum message length
       
   274  *  @capability None
       
   275  */
       
   276 EXPORT_C TInt CSmsMessage::MaxMessageLength() const
       
   277 	{
       
   278 	__ASSERT_DEBUG(TextPresent(),Panic(KGsmuPanicTextNotPresent));
       
   279 	TInt maxmessagelength=SmsPDU().UserData().MaxBodyLengthInChars();
       
   280 	if (SmsPDU().TextConcatenated())
       
   281 		{
       
   282 		maxmessagelength=maxmessagelength*0xFF;
       
   283 		}
       
   284 
       
   285 	LOGGSMU2("CSmsMessage::MaxMessageLength() returns %d", maxmessagelength);
       
   286 
       
   287 	return maxmessagelength;
       
   288 	} // CSmsMessage::MaxMessageLength
       
   289 
       
   290 
       
   291 /**
       
   292  *  
       
   293  *  @return The converted buffer length
       
   294  *  @note Use with care - Expensive operation
       
   295  */
       
   296 TInt CSmsMessage::ConvertedBufferLengthL(const CSmsBufferBase& aBuffer)
       
   297     {
       
   298     // Ignore in code coverage - not used in SMS stack and not exported
       
   299     // but cannot be removed as impacts public header.
       
   300     BULLSEYE_OFF    
       
   301     LOGGSMU1("CSmsMessage::ConvertedBufferLengthL()");
       
   302     
       
   303     TInt convertedBufferLength=0;
       
   304     CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,SmsPDU().Alphabet(),BinaryData());
       
   305     CSmsBufferSegmenter* segmenter=CSmsBufferSegmenter::NewLC(*converter,aBuffer);
       
   306     convertedBufferLength=segmenter->TotalConvertedLengthL(iAdditionalInfo->Alternative7bitEncoding());
       
   307     CleanupStack::PopAndDestroy(2, converter);
       
   308     
       
   309     LOGGSMU2("CSmsMessage::ConvertedBufferLengthL() returns %d", convertedBufferLength);
       
   310     
       
   311     return convertedBufferLength;
       
   312     BULLSEYE_RESTORE
       
   313     }
       
   314 
       
   315 /**
       
   316  *  Gets the message length.
       
   317  *  
       
   318  *  In the case where the message is compressed, this function compresses the
       
   319  *  text and returns the number of bytes of the compressed buffer.
       
   320  *  
       
   321  *  The function calls ConvertedBufferLengthL(), and is therefore an expensive
       
   322  *  operation.
       
   323  *  
       
   324  *  @return Message length
       
   325  *  @capability None
       
   326  */
       
   327 EXPORT_C TInt CSmsMessage::MessageLengthL()
       
   328 	{
       
   329 	LOGGSMU1("CSmsMessage::MessageLengthL()");
       
   330 
       
   331 	TInt messagelength=0;
       
   332 	if (!SmsPDU().TextCompressed())
       
   333 		{
       
   334 		messagelength=iBuffer->Length();
       
   335 		if(SmsPDU().Alphabet() == TSmsDataCodingScheme::ESmsAlphabetUCS2)messagelength*=2 ;
       
   336 		}
       
   337 	else
       
   338 		{
       
   339 		User::Leave(KErrNotSupported);
       
   340 		}
       
   341 	return messagelength;
       
   342 	} // CSmsMessage::MessageLengthL
       
   343 
       
   344 
       
   345 EXPORT_C void CSmsMessage::GetEncodingInfoL(TInt& aPdus, TInt& aUnconvertedChars,
       
   346 		                                    TInt& aDowngradedChars, TInt& aFreeUDUnitsInLastPDU)
       
   347 	{
       
   348 	LOGGSMU1("CSmsMessage::GetEncodingInfoL()");
       
   349 
       
   350 	aPdus                 = 1;
       
   351 	aUnconvertedChars     = 0;
       
   352 	aDowngradedChars      = 0;
       
   353 	aFreeUDUnitsInLastPDU = 0;
       
   354 
       
   355 	if (TextPresent())
       
   356 		{
       
   357 		if (IsDecoded())
       
   358 			{
       
   359 			//
       
   360 			// Clear the concatenated flag, EncodeBufferL() will add it if needed.
       
   361 			//
       
   362 			SmsPDU().SetTextConcatenatedL(EFalse, EFalse);
       
   363 
       
   364 			//
       
   365 			// Attempt to encode to a single PDU, and if that fails then attempt to
       
   366 			// encode to a set of PDUs.
       
   367 			//
       
   368 			CArrayFixFlat<TGsmSms>*  tmpArray = new (ELeave) CArrayFixFlat<TGsmSms>(8);
       
   369 			CleanupStack::PushL(tmpArray);
       
   370 			
       
   371 			//
       
   372 			// Encode the message...
       
   373 			//
       
   374 			if (!EncodeIntoSinglePDUL(*tmpArray, aUnconvertedChars,
       
   375                                       aDowngradedChars, aFreeUDUnitsInLastPDU))
       
   376 				{
       
   377 				EncodeBufferL(*tmpArray, 0, *iBuffer, aUnconvertedChars,
       
   378 						      aDowngradedChars, aFreeUDUnitsInLastPDU, EFalse);
       
   379 
       
   380 				aPdus = iAdditionalInfo->SmsPDUArray().Count();
       
   381 				if (aPdus > 255)
       
   382 					{
       
   383 	 				User::Leave(KErrOverflow);
       
   384 					}
       
   385 				}
       
   386 
       
   387 			CleanupStack::PopAndDestroy(tmpArray);
       
   388 			}
       
   389 		else if (SmsPDU().TextConcatenated())
       
   390 			{
       
   391 			aPdus                 = SmsPDU().NumConcatenatedMessagePDUs();
       
   392 			aUnconvertedChars     = 0;
       
   393 			aDowngradedChars      = 0;
       
   394 			aFreeUDUnitsInLastPDU = 0;
       
   395 			}
       
   396 		}
       
   397 
       
   398 	LOGGSMU2("CSmsMessage::GetEncodingInfoL(): aPdus=%d", aPdus);
       
   399 	LOGGSMU2("CSmsMessage::GetEncodingInfoL(): aUnconvertedChars=%d", aUnconvertedChars);
       
   400 	LOGGSMU2("CSmsMessage::GetEncodingInfoL(): aDowngradedChars=%d", aDowngradedChars);
       
   401 	LOGGSMU2("CSmsMessage::GetEncodingInfoL(): aFreeUDUnitsInLastPDU=%d", aFreeUDUnitsInLastPDU);
       
   402 	} // CSmsMessage::GetEncodingInfoL
       
   403 
       
   404 
       
   405 /**
       
   406  *  Gets the User Data Settings.
       
   407  *  
       
   408  *  @param aSettings User Data Settings
       
   409  *  @capability None
       
   410  */
       
   411 EXPORT_C void CSmsMessage::UserDataSettings(TSmsUserDataSettings& aSettings) const
       
   412 	{
       
   413 	LOGGSMU1("CSmsMessage::UserDataSettings()");
       
   414 
       
   415 	__ASSERT_DEBUG(TextPresent(),Panic(KGsmuPanicTextNotPresent));
       
   416 	aSettings.SetAlphabet(SmsPDU().Alphabet());
       
   417 	aSettings.SetTextCompressed(SmsPDU().TextCompressed());
       
   418 	TBool is16bit;
       
   419 	TBool concatenated=SmsPDU().TextConcatenated(&is16bit);
       
   420 	aSettings.SetTextConcatenated(concatenated,is16bit);
       
   421 	} // CSmsMessage::UserDataSettings
       
   422 
       
   423 
       
   424 /**
       
   425  *  Sets the User Data Settings.
       
   426  *  
       
   427  *  @param aSettings User Data Settings
       
   428  *  @capability None
       
   429  */
       
   430 EXPORT_C void CSmsMessage::SetUserDataSettingsL(const TSmsUserDataSettings& aSettings)
       
   431 	{
       
   432 	LOGGSMU1("CSmsMessage::SetUserDataSettingsL()");
       
   433 
       
   434 	__ASSERT_DEBUG(TextPresent(),Panic(KGsmuPanicTextNotPresent));
       
   435 	SmsPDU().SetAlphabet(aSettings.Alphabet());
       
   436 	SmsPDU().SetTextCompressed(aSettings.TextCompressed());
       
   437 	TBool is16bit;
       
   438 	TBool concatenated=aSettings.TextConcatenated(&is16bit);
       
   439 	SmsPDU().SetTextConcatenatedL(concatenated,is16bit);
       
   440 	} // CSmsMessage::SetUserDataSettingsL
       
   441 
       
   442 
       
   443 /**
       
   444  *  Optimizes the user data settings.
       
   445  *  
       
   446  *  The alphabet flag causes an alphabet to be chosen which preserves information
       
   447  *  in the message and makes the number of PDUs as small as possible.
       
   448  *  
       
   449  *  The compression settings flag is not supported.
       
   450  *  
       
   451  *  The compression flag causes compression to be switched on if the resultant
       
   452  *  number of PDUs is smaller.
       
   453  *  
       
   454  *  If user explicitly defines alphabet as UCS2 or 8-bit coding, this setting is preserved;
       
   455  *  otherwise, if 7-bit (default) alphabet can not support current text of message UCS2
       
   456  *  alphabet (Unicode) is used.
       
   457  *  
       
   458  *  The two concatenation flags are mutually exclusive as they deal with 8-bit
       
   459  *  and 16-bit referenced concatenation. Both flags cause compression to be switched
       
   460  *  off and if the message length is greater than the maximum message length,
       
   461  *  concatenation is switched on.
       
   462  *  
       
   463  *  @param aOptions Combination of TSmsOptimizationFlags
       
   464  *  @capability None
       
   465  */
       
   466 EXPORT_C void CSmsMessage::OptimizeSettingsL(TInt aOptions)
       
   467 	{
       
   468 	LOGGSMU1("CSmsMessage::OptimizeSettingsL()");
       
   469 
       
   470 	__ASSERT_DEBUG(TextPresent(),Panic(KGsmuPanicTextNotPresent));
       
   471 	__ASSERT_DEBUG(IsDecoded(),Panic(KGsmuPanicNotDecoded));
       
   472 
       
   473 	if (aOptions&ESmsFlagOptimizeAlphabet && (SmsPDU().Alphabet()==TSmsDataCodingScheme::ESmsAlphabet7Bit))
       
   474 		{
       
   475 		TBool isSupported=ETrue;
       
   476 		TInt numOfUnconvertibleChars;
       
   477 		TInt indexOfFirstUnconvertibleChar;
       
   478 
       
   479 		TInt size=iBuffer->Length();
       
   480 		const TInt bufsize=128;
       
   481 		TBuf<bufsize> buf;
       
   482 		TInt extracted=0;
       
   483 		TInt remaining=0;
       
   484 		TInt toExtract=0;
       
   485 		TInt pos=0;
       
   486 
       
   487 		// Defect Fix. Previous for loop caused an access violation as extract size was set
       
   488 		// to size of ibuffer not bufsize and caused a access violation when over 128. Implemented
       
   489 		// fix copies the ibuffer in 128 chunks until its all done.
       
   490 
       
   491 		while((pos<size) && isSupported)
       
   492 			{
       
   493 			remaining=(size - extracted);
       
   494 
       
   495 			if(remaining>bufsize)
       
   496 				toExtract=bufsize;
       
   497 			else
       
   498 				toExtract=remaining;
       
   499 
       
   500 			iBuffer->Extract(buf,pos,toExtract);
       
   501 			isSupported=IsSupportedL(buf,numOfUnconvertibleChars,indexOfFirstUnconvertibleChar);
       
   502 			extracted=(extracted+toExtract);
       
   503 			pos=extracted;
       
   504 			}
       
   505 
       
   506 		if(!isSupported)
       
   507 			SmsPDU().SetAlphabet(TSmsDataCodingScheme::ESmsAlphabetUCS2);
       
   508 		}
       
   509 	} // CSmsMessage::OptimizeSettingsL
       
   510 
       
   511 
       
   512 /**
       
   513  *  This function returns the currently requested alternative encoding method.
       
   514  * 
       
   515  *  In the case of incoming SMS messages received on the device, it will often
       
   516  *  be TSmsEncodingNone unless the Information Elements imply that an
       
   517  *  alternative encoding has been used.
       
   518  * 
       
   519  *  @return The currently selected encoding method.
       
   520  * 
       
   521  *  @capability None
       
   522  */
       
   523 EXPORT_C TSmsEncoding CSmsMessage::Alternative7bitEncoding() const
       
   524 	{
       
   525 	LOGGSMU1("CSmsMessage::Alternative7bitEncoding()");
       
   526 
       
   527 	return iAdditionalInfo->Alternative7bitEncoding();
       
   528 	} // CSmsMessage::Alternative7bitEncoding
       
   529 
       
   530 
       
   531 /**
       
   532  *  This function allows the client to specify an alternative encoding method
       
   533  *  incase the default GSM encoding cannot encode the message completely
       
   534  *  without data loss.
       
   535  * 
       
   536  *  @param aEncoding  Encoding method to select.
       
   537  * 
       
   538  *  @return A Symbian system wide error code.  This function will return
       
   539  *          KErrArgument if the encoding enum is invalid and will return
       
   540  *          KErrNotSupported if the required plug-ins are not present.
       
   541  * 
       
   542  *  @capability None
       
   543  */
       
   544 EXPORT_C TInt CSmsMessage::SetAlternative7bitEncoding(TSmsEncoding aEncoding)
       
   545 	{
       
   546 	LOGGSMU2("CSmsMessage::SetAlternative7bitEncoding(%d)", aEncoding);
       
   547 
       
   548 	//
       
   549 	// Get the encoders that would be used for this encoding method.
       
   550 	// The function will also check that the required encoder is present.
       
   551 	//
       
   552 	TRAPD(err,
       
   553 		{
       
   554 		CSmsAlphabetConverter*  converter = CSmsAlphabetConverter::NewLC(*iCharacterSetConverter, iFs,
       
   555 																	     TSmsDataCodingScheme::ESmsAlphabet7Bit,
       
   556 																	     EFalse);
       
   557 		converter->ConfirmAlternativeEncoderL(aEncoding);
       
   558 		CleanupStack::PopAndDestroy(converter);
       
   559 		});
       
   560 	
       
   561 	//
       
   562 	// Set the variable if the encoders are available...
       
   563 	//
       
   564 	if (err == KErrNone)
       
   565 		{
       
   566 		iAdditionalInfo->SetAlternative7bitEncoding(aEncoding);
       
   567 		}
       
   568 	
       
   569 	return err;
       
   570 	} // CSmsMessage::SetAlternative7bitEncoding
       
   571 
       
   572 
       
   573 /**
       
   574  *  Takes an encoding setting (received from a PDU) and merges it into the
       
   575  *  current setting (where possible).
       
   576  *  
       
   577  *  @param aEncoding  Encoding setting to merge.
       
   578  */
       
   579 void CSmsMessage::MergeAlternative7bitEncoding(TSmsEncoding aEncoding) const
       
   580 	{
       
   581 	LOGGSMU3("CSmsMessage::MergeAlternative7bitEncoding(): aEncoding=%d (currently %d)",
       
   582 			 aEncoding, iAdditionalInfo->Alternative7bitEncoding());
       
   583 
       
   584 	switch (iAdditionalInfo->Alternative7bitEncoding())
       
   585 		{
       
   586 		case ESmsEncodingNone:
       
   587 			{
       
   588 			// Anything is can be merge with this...
       
   589 			iAdditionalInfo->SetAlternative7bitEncoding(aEncoding);
       
   590 			}
       
   591 			break;
       
   592 		
       
   593 		case ESmsEncodingTurkishSingleShift:
       
   594 			{
       
   595 			// Only Turkish locking shift can merge...
       
   596 			if (aEncoding == ESmsEncodingTurkishLockingShift)
       
   597 				{
       
   598 				iAdditionalInfo->SetAlternative7bitEncoding(ESmsEncodingTurkishLockingAndSingleShift);
       
   599 				}
       
   600 			}
       
   601 			break;
       
   602 		
       
   603 		case ESmsEncodingTurkishLockingShift:
       
   604 			{
       
   605 			// Only Turkish single shift can merge...
       
   606 			if (aEncoding == ESmsEncodingTurkishSingleShift)
       
   607 				{
       
   608 				iAdditionalInfo->SetAlternative7bitEncoding(ESmsEncodingTurkishLockingAndSingleShift);
       
   609 				}
       
   610 			}
       
   611 			break;
       
   612 		
       
   613 		case ESmsEncodingPortugueseSingleShift:
       
   614 			{
       
   615 			// Only Portuguese locking shift can merge...
       
   616 			if (aEncoding == ESmsEncodingPortugueseLockingShift)
       
   617 				{
       
   618 				iAdditionalInfo->SetAlternative7bitEncoding(ESmsEncodingPortugueseLockingAndSingleShift);
       
   619 				}
       
   620 			}
       
   621 			break;
       
   622 		
       
   623 		case ESmsEncodingPortugueseLockingShift:
       
   624 			{
       
   625 			// Only Portuguese single shift can merge...
       
   626 			if (aEncoding == ESmsEncodingPortugueseSingleShift)
       
   627 				{
       
   628 				iAdditionalInfo->SetAlternative7bitEncoding(ESmsEncodingPortugueseLockingAndSingleShift);
       
   629 				}
       
   630 			}
       
   631 			break;
       
   632 		
       
   633 		case ESmsEncodingTurkishLockingAndSingleShift:
       
   634 		case ESmsEncodingSpanishSingleShift:
       
   635 		case ESmsEncodingPortugueseLockingAndSingleShift:
       
   636 		default:
       
   637 			{
       
   638 			// NOP - Cannot merge anything into these...
       
   639 			}
       
   640 		};
       
   641 
       
   642 	LOGGSMU2("CSmsMessage::MergeAlternative7bitEncoding(): New encoding=%d",
       
   643 			 iAdditionalInfo->Alternative7bitEncoding());
       
   644 	} // CSmsMessage::MergeAlternative7bitEncoding
       
   645 
       
   646 
       
   647 /**
       
   648  *  Tests if a buffer can be encoded without loss of information.
       
   649  *  
       
   650  *  @param aDes                                 The buffer to test for encoding
       
   651  *  @param aNumberOfUnconvertibleCharacters     On return, the number of 
       
   652  *                                              unconvertible characters
       
   653  *  @param aIndexOfFirstUnconvertibleCharacter  On return, the index of the
       
   654  *                                              first unconvertible character
       
   655  * 
       
   656  *  @return True if aDes can be encoded without loss of information
       
   657  * 
       
   658  *  @capability None
       
   659  */
       
   660 EXPORT_C TBool CSmsMessage::IsSupportedL(const TDesC& aDes, TInt& aNumberOfUnconvertibleCharacters,
       
   661 		                                 TInt& aIndexOfFirstUnconvertibleCharacter)
       
   662 	{
       
   663 	LOGGSMU1("[1] CSmsMessage::IsSupportedL()");
       
   664 
       
   665 	__ASSERT_DEBUG(TextPresent(), Panic(KGsmuPanicTextNotPresent));
       
   666 
       
   667 	aNumberOfUnconvertibleCharacters    = 0;
       
   668 	aIndexOfFirstUnconvertibleCharacter = aDes.Length();
       
   669 
       
   670 	if (SmsPDU().TextCompressed())
       
   671 		{
       
   672 		return EFalse;
       
   673 		}
       
   674 
       
   675 	return SmsPDU().UserData().IsSupportedL(aDes, aNumberOfUnconvertibleCharacters,
       
   676                                             aIndexOfFirstUnconvertibleCharacter);
       
   677 	} // CSmsMessage::IsSupportedL
       
   678 
       
   679 
       
   680 /**
       
   681  *  Tests if a buffer can be encoded without loss of information.
       
   682  *  
       
   683  *  @param aDes                                 The buffer to test for encoding
       
   684  *  @param aNumberOfUnconvertibleCharacters     On return, the number of 
       
   685  *                                              unconvertible characters
       
   686  *  @param aNumberOfDowngradedCharacters        On return, the number of 
       
   687  *                                              characters downgraded
       
   688  *  @param aNumberRequiringAlternativeEncoding  On return, the number of 
       
   689  *                                              characters needing alternative
       
   690  *                                              encoding support
       
   691  *  @param aIndexOfFirstUnconvertibleCharacter  On return, the index of the
       
   692  *                                              first unconvertible character
       
   693  * 
       
   694  *  @return True if aDes can be encoded without loss of information
       
   695  * 
       
   696  *  @capability None
       
   697  */
       
   698 EXPORT_C TBool CSmsMessage::IsSupportedL(const TDesC& aDes, TInt& aNumberOfUnconvertibleCharacters,
       
   699 		                                 TInt& aNumberOfDowngradedCharacters,
       
   700 		                                 TInt& aNumberRequiringAlternativeEncoding,
       
   701 		                                 TInt& aIndexOfFirstUnconvertibleCharacter) const
       
   702 	{
       
   703 	LOGGSMU1("[2] CSmsMessage::IsSupportedL()");
       
   704 
       
   705 	__ASSERT_DEBUG(TextPresent(), Panic(KGsmuPanicTextNotPresent));
       
   706 
       
   707 	aNumberOfUnconvertibleCharacters    = 0;
       
   708 	aNumberOfDowngradedCharacters       = 0;
       
   709 	aNumberRequiringAlternativeEncoding = 0;
       
   710 	aIndexOfFirstUnconvertibleCharacter = aDes.Length();
       
   711 
       
   712 	if (SmsPDU().TextCompressed())
       
   713 		{
       
   714 		return EFalse;
       
   715 		}
       
   716 
       
   717 	return SmsPDU().UserData().IsSupportedL(aDes, iAdditionalInfo->Alternative7bitEncoding(),
       
   718 											aNumberOfUnconvertibleCharacters,
       
   719 	                                        aNumberOfDowngradedCharacters,
       
   720                                             aNumberRequiringAlternativeEncoding,
       
   721                                             aIndexOfFirstUnconvertibleCharacter);
       
   722 	} // CSmsMessage::IsSupportedL
       
   723 
       
   724 
       
   725 /**
       
   726  *  Encodes message PDUs as an array of TGsmSms objects.
       
   727  *  
       
   728  *  Note, this function should only be called after EncodeIntoSinglePDUL() as EncodeBufferL() now
       
   729  *  automatically prepares PDUs for concatenation.
       
   730  *  
       
   731  *  @param aSmsArray (In) an empty array. On return, one or more encoded TGsmSms.
       
   732  *  @param aReference Sets a Concatenated Message Reference (default 0)
       
   733  *  @capability None
       
   734  */
       
   735 EXPORT_C void CSmsMessage::EncodeMessagePDUsL(CArrayFix<TGsmSms>& aSmsArray, TInt aReference)
       
   736 	{
       
   737 	LOGGSMU2("CSmsMessage::EncodeMessagePDUsL(): aReference=%d", aReference);
       
   738 
       
   739 	__ASSERT_DEBUG((aSmsArray.Count()==0),Panic(KGsmuPanicSmsArrayNotEmpty));
       
   740 	
       
   741 	if (TextPresent())
       
   742 		{
       
   743 		if (SmsPDU().TextCompressed())
       
   744 			{
       
   745 			User::Leave(KErrNotSupported);
       
   746 			}
       
   747 		else
       
   748 			{
       
   749 			TInt  unconvertedChars, downgradedChars, freeUDUnitsInLastPDU;
       
   750 				
       
   751 			EncodeBufferL(aSmsArray, aReference, *iBuffer, unconvertedChars,
       
   752 					      downgradedChars, freeUDUnitsInLastPDU);
       
   753 			}
       
   754 		}
       
   755 	else
       
   756 		{
       
   757         if(SmsPDU().Type()==CSmsPDU::ESmsCommand)
       
   758             {
       
   759             //Commands never contain text, so commands only encoded
       
   760             // in this branch.
       
   761             //
       
   762             // However  Commands don't support information
       
   763             // elements (per 23.040 6.5) and the CSmsIEOperation class
       
   764             // do not allow control information elements to be added
       
   765             // to Commands, hence the next line is commented out.
       
   766             // PrepareCommandMessageL();
       
   767             }
       
   768 
       
   769  		TGsmSms sms;
       
   770  		SmsPDU().EncodeMessagePDUL(sms);
       
   771  		aSmsArray.AppendL(sms);
       
   772 		}
       
   773 	} // CSmsMessage::EncodeMessagePDUsL
       
   774 
       
   775 
       
   776 /**
       
   777  *  @internalComponent
       
   778  *  
       
   779  *  This method copies information elements from the collections contained in
       
   780  *  CSmsMessageAdditionalAttributes into the working PDU.
       
   781  *  
       
   782  *  Command Messages comprise only 1 PDU. Therefore all information
       
   783  *  elements must be present in the working PDU when encoding takes place.
       
   784  *  If there is not enough space in the PDU, the message encoding will fail.
       
   785  *  
       
   786  *  The 23.040 has not defined any information elements that are contained in
       
   787  *  Command PDUs. This method has been provided to maintain consistency with
       
   788  *  previous GSMU implementations.
       
   789  *  
       
   790  *  @leave KErrAlreadyExists or KErrAlreadyExists
       
   791  */
       
   792 void CSmsMessage::PrepareCommandMessageL()
       
   793     {
       
   794     LOGGSMU1("CSmsMessage::PrepareCommandMessageL()");
       
   795 
       
   796     if (SmsPDU().Type()==CSmsPDU::ESmsCommand)
       
   797         {
       
   798         CSmsCommand& command = static_cast<CSmsCommand&>(SmsPDU());
       
   799 
       
   800         for (TUint8 category = 0; category < TSmsInformationElementCategories::ENumberOfCategories; category++)
       
   801             {
       
   802             switch(category)
       
   803                 {
       
   804                 case TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly:
       
   805                 case TSmsInformationElementCategories::ECtrlSingleInstanceOnly:
       
   806                 case TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed:
       
   807                     {
       
   808                     for (TUint j = 0; j < iAdditionalInfo->NumberOfControlInformationElements((CSmsMessageAdditionalAttributes::TCategory) category); j++)
       
   809                         {
       
   810                         CSmsInformationElement& informationElement = iAdditionalInfo->GetControlInformationElementL( ( (CSmsMessageAdditionalAttributes::TCategory) category), j);
       
   811                         TPtr8 data = informationElement.Data();
       
   812                         command.AddInformationElementL(informationElement.Identifier(), data);
       
   813                         }
       
   814                     break;
       
   815                     }
       
   816                 default:
       
   817                 LOGGSMU2("CSmsMessage::PrepareCommandMessageL,default switch category = %d, id = %d", category);
       
   818                     break;
       
   819                 }
       
   820             }
       
   821         }
       
   822     } // CSmsMessage::PrepareCommandMessageL
       
   823 
       
   824 
       
   825 /**
       
   826  *  Decodes message PDUs from an array of TGsmSms objects.
       
   827  *  
       
   828  *  The array contains a concatenated message, and must have the correct number
       
   829  *  of PDUs.
       
   830  *  
       
   831  *  @param aSmsArray Concatenated message
       
   832  *  @capability None
       
   833  */
       
   834 EXPORT_C void CSmsMessage::DecodeMessagePDUsL(const CArrayFix<TGsmSms>& aSmsArray)
       
   835 	{
       
   836     LOGGSMU2("CSmsMessage::DecodeMessagePDUsL(): PDUs=%d", aSmsArray.Count());
       
   837 
       
   838 	TInt count=aSmsArray.Count();
       
   839 	SetIsComplete(ETrue);
       
   840 	CArrayPtrFlat<CSmsPDU>* smspduarray=new(ELeave) CArrayPtrFlat<CSmsPDU>(8);
       
   841 	CleanupStack::PushL(smspduarray);
       
   842 	// With CleanupResetAndDestroyPushL, only ResetAndDestroy method of smspduarray is invoked. 
       
   843 	// smspduarray object is actually deleted with the first push. 
       
   844 	// coverity[double_push]
       
   845 	CleanupResetAndDestroyPushL(*smspduarray);  // Don't forget to destroy what the array elements point to.
       
   846 
       
   847 	TInt i=0;
       
   848 	TBool ismobileterminated=(Type()==CSmsPDU::ESmsDeliver) || (Type()==CSmsPDU::ESmsSubmitReport) || (Type()==CSmsPDU::ESmsStatusReport);
       
   849 	for (; i<count; i++)
       
   850 		{
       
   851 		CSmsPDU* smspdu=CSmsPDU::NewL(aSmsArray[i],*iCharacterSetConverter,iFs, EFalse,ismobileterminated);
       
   852 		CleanupStack::PushL(smspdu);
       
   853 		TInt j=0;
       
   854 		for (; (j<smspduarray->Count()) && (smspdu->ConcatenatedMessagePDUIndex()>(*smspduarray)[j]->ConcatenatedMessagePDUIndex()); j++)
       
   855 			{
       
   856 			}
       
   857 		smspduarray->InsertL(j,smspdu);
       
   858 		CleanupStack::Pop();
       
   859 		}
       
   860 	if (SmsPDU().TextCompressed())
       
   861 		User::Leave(KErrNotSupported);
       
   862 	else
       
   863 		DecodeBufferL(*smspduarray,*iBuffer);
       
   864 
       
   865 	CleanupStack::PopAndDestroy(2);  //  smspduarray elements (Reset and Destroy), smspduarray
       
   866 	SetIsDecoded(ETrue);
       
   867 	SmsPDU().UserData().SetBodyL(KNullDesC8);
       
   868 	} // CSmsMessage::DecodeMessagePDUsL
       
   869 
       
   870 /**
       
   871  *  Decodes partial complete message PDUs from an array of TGsmSms objects.
       
   872  *  
       
   873  *  The array contains a concatenated incomplete message, but the array of
       
   874  *  TGsmSms object must be in sequence.
       
   875  *  
       
   876  *	NOTE:
       
   877  *	It will not fully decode EMS and Control Information elements if it needs 
       
   878  *	to decode a partially complete class 0 SMS message. The assumption is that 
       
   879  *	it is necessary to display a partially complete message then only the raw 
       
   880  *	text will be displayed on the UI without any animation elements. The 
       
   881  *	rational for this design is that these information elements are normally 
       
   882  *	specified as being located at a specific position in a message. It will 
       
   883  *	complicate the design of client app if it has to re-calculate the position 
       
   884  *	of these elements when it receives a partially complete message under 
       
   885  *	Out Of Memory Conditions.
       
   886  
       
   887  *  @param aSmsArray Concatenated message
       
   888  *	@param aLastPartialCompleteMsg boolean value indicating this is the last
       
   889  *			incomplete message for a particular concatenated message.
       
   890  *  @capability None
       
   891  */
       
   892 EXPORT_C void CSmsMessage::DecodePartialCompleteMessagePDUsL(const CArrayFix<TGsmSms>& aSmsArray, TBool aLastPartialCompleteMsg)
       
   893 	{
       
   894 	LOGGSMU2("CSmsMessage::DecodePartialCompleteMessagePDUsL(): PDUs=%d", aSmsArray.Count());
       
   895 
       
   896 	TInt count=aSmsArray.Count();
       
   897 	SetIsComplete(EFalse);
       
   898 	CArrayPtrFlat<CSmsPDU>* smspduarray=new(ELeave) CArrayPtrFlat<CSmsPDU>(8);
       
   899 	CleanupStack::PushL(smspduarray);
       
   900 	// With CleanupResetAndDestroyPushL, only ResetAndDestroy method of smspduarray is invoked. 
       
   901 	// smspduarray object is actually deleted with the first push. 
       
   902 	// coverity[double_push]
       
   903 	CleanupResetAndDestroyPushL(*smspduarray);  // Don't forget to destroy what the array elements point to.
       
   904 
       
   905 	TBool isMobileTerminated=(Type()==CSmsPDU::ESmsDeliver);
       
   906 	/*
       
   907 	The loop below goes through all the sms's received & check whether the received PDUs are of Class 0
       
   908 	or not. The number of PDUs received must be less than the number of concatenated PDUs constitute this message.
       
   909 	Then it order the PDUs in sequence for decoding purpose.
       
   910 	*/
       
   911 	for (TInt i=0; i<count; i++)
       
   912 		{
       
   913 		CSmsPDU* smspdu=CSmsPDU::NewL(aSmsArray[i],*iCharacterSetConverter,iFs, EFalse,isMobileTerminated);
       
   914 		CleanupStack::PushL(smspdu);
       
   915 
       
   916 		/*
       
   917 		Check all the PDUs must be class 0 messages & also the number of received PDUs
       
   918 		must be less than the number of concatenated PDUs constitute this message
       
   919 		*/
       
   920 		TSmsDataCodingScheme::TSmsClass  msgClass;
       
   921 		if (smspdu->DataCodingSchemePresent()  &&  smspdu->Class(msgClass))
       
   922 			{
       
   923 			if (msgClass != TSmsDataCodingScheme::ESmsClass0)
       
   924 				{
       
   925 				User::Leave(KErrNotSupported);
       
   926 				}
       
   927 			__ASSERT_DEBUG((count < smspdu->NumConcatenatedMessagePDUs()),Panic(KGsmuPanicWrongNumberOfMessagePDUs));
       
   928 			}
       
   929 		else
       
   930 			{
       
   931 			User::Leave(KErrNotSupported);
       
   932 			}
       
   933 		//The below for statement finds the position in smspduarray where the PDU should be inserted.
       
   934 		//The PDUs are put in sequence for decoding purpose.
       
   935 		TInt j;
       
   936 		for (j=0; (j<smspduarray->Count()) && (smspdu->ConcatenatedMessagePDUIndex()>(*smspduarray)[j]->ConcatenatedMessagePDUIndex()); j++)
       
   937 			{
       
   938 			}
       
   939 		smspduarray->InsertL(j,smspdu);
       
   940 		CleanupStack::Pop();
       
   941 		}
       
   942 
       
   943 	if (SmsPDU().TextCompressed())
       
   944 		{
       
   945 		User::Leave(KErrNotSupported);
       
   946 		}
       
   947 	else
       
   948 		{
       
   949 		DecodeOnlyTextL(*smspduarray,*iBuffer);
       
   950 		}
       
   951 
       
   952 	iVersion = CSmsMessage::ESmsIncompleteClass0MessageV;
       
   953 
       
   954 	TInt startPDU = smspduarray->At(0)->ConcatenatedMessagePDUIndex();
       
   955 	TInt endPDU = smspduarray->At(smspduarray->Count()-1)->ConcatenatedMessagePDUIndex();
       
   956 	AddIncompleteMessageInfoL(startPDU, endPDU, aLastPartialCompleteMsg);
       
   957 
       
   958 	CleanupStack::PopAndDestroy(2);  //  smspduarray elements (Reset and Destroy), smspduarray
       
   959 	SetIsDecoded(ETrue);
       
   960 	SmsPDU().UserData().SetBodyL(KNullDesC8);	
       
   961 	}
       
   962 
       
   963 CSmsMessage::CSmsMessage(RFs& aFs, CSmsBufferBase* aBuffer):
       
   964     iFlags(0),
       
   965     iStatus(NMobileSmsStore::EStoredMessageUnread),
       
   966     iLogServerId(KLogNullId),
       
   967     iBuffer(aBuffer),
       
   968     iFs(aFs),
       
   969 	iSlotArray(8),
       
   970 	iVersion(ESmsMessageV4),
       
   971 	iAdditionalInfo(NULL)
       
   972     {
       
   973     iTime.UniversalTime();
       
   974 
       
   975     TBool result = SetUTCOffset(User::UTCOffset());
       
   976     __ASSERT_DEBUG(result, Panic(KGSMUPanicUserTimeZoneOffsetOutOfRange));
       
   977     } // NMobileSmsStore::EStoredMessageUnread
       
   978 
       
   979 void CSmsMessage::ConstructL(const TGsmSms& aGsmSms, TBool aIsRPError,TBool aIsMobileTerminated)
       
   980 	{
       
   981     LOGGSMU1("CSmsMessage::ConstructL()");
       
   982 
       
   983 	iCharacterSetConverter=CCnvCharacterSetConverter::NewL();
       
   984 	iInformationElementArray = new (ELeave) RPointerArray<CEmsInformationElement>(8);
       
   985 
       
   986 	iAdditionalInfo = CSmsMessageAdditionalAttributes::NewL();
       
   987 	CreateControlIEOperationsClassesL();
       
   988 	CreateControlNonIEOperationsClassesL();
       
   989 
       
   990 	iSmsPDU=CSmsPDU::NewL(aGsmSms,*iCharacterSetConverter,iFs, aIsRPError,aIsMobileTerminated);
       
   991 	SetIsComplete(NumMessagePDUsL()==1);
       
   992 	if (IsComplete() && TextPresent())
       
   993 		{
       
   994 		TSmsEncoding  encodingUsedInSegment = SmsPDU().NationalLanguageEncoding();
       
   995 		
       
   996 		CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,SmsPDU().Alphabet(),BinaryData());
       
   997 		TPtrC nativeChars(converter->ConvertToNativeL(SmsPDU().UserData().Body(),
       
   998 													  encodingUsedInSegment));
       
   999 		MergeAlternative7bitEncoding(encodingUsedInSegment);
       
  1000 		
       
  1001 		if (SmsPDU().TextCompressed())
       
  1002 			User::Leave(KErrNotSupported);
       
  1003 		else
       
  1004 			iBuffer->InsertL(iBuffer->Length(),nativeChars);
       
  1005 		CleanupStack::PopAndDestroy(converter);
       
  1006 		CSmsPDU::TSmsPDUType pdutype= SmsPDU().Type();
       
  1007 		if(pdutype==CSmsPDU::ESmsCommand)
       
  1008 			{
       
  1009 			// This branch is never executed as TextPresent() never
       
  1010 			// returns true when pduType == command
       
  1011             User::Leave(KErrArgument);
       
  1012 			}
       
  1013 		else if(SmsPDU().UserDataPresent())
       
  1014 			{
       
  1015 			TInt smscIndex(0);
       
  1016 
       
  1017 			if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
       
  1018 				{
       
  1019 				iAdditionalInfo->SetStatusReportSchemeL(EControlParametersScheme);
       
  1020 				}
       
  1021 			else
       
  1022 				{
       
  1023 				iAdditionalInfo->SetStatusReportSchemeL(EDefaultScheme);	
       
  1024 				}
       
  1025 				
       
  1026             InstallControlInformationElementsL(SmsPDU().UserData(), 0);
       
  1027 			InstallEmsInformationElementsL(SmsPDU().UserData(),0);
       
  1028 			UpdateUserPromptAndODIElementsStartPosition();
       
  1029 			}
       
  1030 		}
       
  1031 	SetIsDecoded(IsComplete());
       
  1032 
       
  1033 	if (TextPresent())
       
  1034 		SmsPDU().UserData().SetBodyL(KNullDesC8);
       
  1035 	} // CSmsMessage::ConstructL
       
  1036 
       
  1037 
       
  1038 void CSmsMessage::ConstructL(CSmsPDU::TSmsPDUType aType,TBool aIsRPError)
       
  1039 	{
       
  1040     LOGGSMU3("CSmsMessage::ConstructL(): aType=%d, aIsRPError=%d", (TInt) aType,
       
  1041     		 aIsRPError);
       
  1042 
       
  1043 	iCharacterSetConverter=CCnvCharacterSetConverter::NewL();
       
  1044 	iInformationElementArray = new (ELeave) RPointerArray<CEmsInformationElement>(2);
       
  1045 
       
  1046 	iAdditionalInfo = CSmsMessageAdditionalAttributes::NewL();
       
  1047 	CreateControlIEOperationsClassesL();
       
  1048 	CreateControlNonIEOperationsClassesL();
       
  1049 
       
  1050 	iSmsPDU=CSmsPDU::NewL(aType,*iCharacterSetConverter,iFs,aIsRPError);
       
  1051 	SetIsComplete(ETrue);
       
  1052 	SetIsDecoded(ETrue);
       
  1053 	} // CSmsMessage::ConstructL
       
  1054 
       
  1055 
       
  1056 /**
       
  1057  *  Counts the number of PDUs that this message will take. To do this the
       
  1058  *  message will attempt to be encoded into 1 message, and if not into
       
  1059  *  multiple messages. Due to the processing, the function should be used
       
  1060  *  sparingly.
       
  1061  * 
       
  1062  *  @return  Number of PDUs required.
       
  1063  */
       
  1064 TInt CSmsMessage::NumMessageEmsPDUsL()
       
  1065 	{
       
  1066 	LOGGSMU1("CSmsMessage::NumMessageEmsPDUsL()");
       
  1067 
       
  1068 	//
       
  1069 	// Clear the concatenated flag, EncodeBufferL() will add it if needed.
       
  1070 	//
       
  1071 	SmsPDU().SetTextConcatenatedL(EFalse, EFalse);
       
  1072 
       
  1073 	//
       
  1074 	// Attempt to encode to a single PDU, and if that fails then attempt to
       
  1075 	// encode to a set of PDUs.
       
  1076 	//
       
  1077 	CArrayFixFlat<TGsmSms>*  tmpArray = new (ELeave) CArrayFixFlat<TGsmSms>(8);
       
  1078 	CleanupStack::PushL(tmpArray);
       
  1079 	TInt numMsgs = 1;
       
  1080 	
       
  1081 	if (!EncodeIntoSinglePDUL(*tmpArray))
       
  1082 		{
       
  1083 		TInt  unconvertedChars, downgradedChars, freeUDUnitsInLastPDU;
       
  1084 		
       
  1085 		EncodeBufferL(*tmpArray, 0, *iBuffer, unconvertedChars,
       
  1086 			          downgradedChars, freeUDUnitsInLastPDU, EFalse);
       
  1087 
       
  1088 		numMsgs = iAdditionalInfo->SmsPDUArray().Count();
       
  1089 		}
       
  1090 
       
  1091 	CleanupStack::PopAndDestroy(tmpArray);
       
  1092 	
       
  1093     LOGGSMU2("CSmsMessage::NumMessageEmsPDUsL() returns %d", numMsgs);
       
  1094 
       
  1095 	return numMsgs;
       
  1096 	} // CSmsMessage::NumMessageEmsPDUsL
       
  1097 
       
  1098 
       
  1099 /**
       
  1100  *  @internalComponent
       
  1101  *  
       
  1102  *  This method removes all non mandatory information elements from the
       
  1103  *  working PDU.
       
  1104  *  
       
  1105  *  The working PDU is the PDU which is currently being encoded or decoded.
       
  1106  *  
       
  1107  *  @leave KErrAlreadyExists or KErrAlreadyExists
       
  1108  */
       
  1109 void CSmsMessage::ResetWorkingPDUL()
       
  1110 	{
       
  1111 	LOGGSMU1("CSmsMessage::ResetWorkingPDUL()");
       
  1112 	
       
  1113 	CSmsUserData& uData = SmsPDU().UserData();
       
  1114 	//remove non-mandatory EMS information elements
       
  1115 	for (TInt a=uData.NumInformationElements(); a>0; --a)
       
  1116         {
       
  1117         const CSmsInformationElement& ie = uData.InformationElement(a-1);
       
  1118 
       
  1119          TSmsInformationElementCategories::TInformationElementCategory category;
       
  1120 
       
  1121         if (TSmsInformationElementCategories::GetCategoryDefinition(ie.Identifier(), category)  &&
       
  1122         	(category !=  TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUAndWithIdenticalValues)    &&
       
  1123             (category !=  TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUButWithValueSpecificToPDU) &&
       
  1124             (category !=  TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUMultipleInstancesPerPDU))
       
  1125             {
       
  1126             uData.RemoveInformationElement(a-1);
       
  1127             }
       
  1128         }
       
  1129     // reset user body
       
  1130     uData.SetBodyL(KNullDesC8);
       
  1131     } // CSmsMessage::ResetWorkingPDUL
       
  1132 
       
  1133 
       
  1134 void CSmsMessage::CorrectFormattingL(TUint aCharsAddedToCurrentPDU,
       
  1135 									 RPointerArray<CEmsInformationElement>& aCorrectedFormattingIEArray,
       
  1136 									 TUint aCharsAlreadyAdded)
       
  1137 	{
       
  1138 	LOGGSMU3("CSmsMessage::CorrectFormattingL(): aCharsAddedToCurrentPDU=%d, aCharsAlreadyAdded=%d",
       
  1139 			 aCharsAddedToCurrentPDU, aCharsAlreadyAdded);
       
  1140 
       
  1141 	CSmsUserData& uData = SmsPDU().UserData();
       
  1142 	for (TInt a= 0; a < uData.NumInformationElements(); a++)
       
  1143 		{
       
  1144 		CSmsInformationElement& ie = uData.InformationElement(a);
       
  1145 		if (CSmsInformationElement::ESmsEnhancedTextFormatting==ie.Identifier())
       
  1146 			{
       
  1147 			CEmsFormatIE& formatIE=static_cast<CEmsFormatIE&>(ie);
       
  1148 
       
  1149 			TUint oldFormatLen=formatIE.FormatLength(); //
       
  1150 			if(aCharsAddedToCurrentPDU < formatIE.StartPosition() + oldFormatLen)
       
  1151 				{
       
  1152 				TUint newFormatLen=aCharsAddedToCurrentPDU - formatIE.StartPosition();
       
  1153 				formatIE.SetFormatLength(newFormatLen);
       
  1154 
       
  1155 				// Now, re-encode the information element - this is because we have
       
  1156 				// changed a message in the UserData which is using EMS elements as
       
  1157 				// SMS IEs. Encoding is NOT automatic
       
  1158 				formatIE.EncodeInformationElementL();
       
  1159 
       
  1160 				if((TInt)(aCharsAlreadyAdded+aCharsAddedToCurrentPDU) < iBuffer->Length())
       
  1161 					{
       
  1162 					CEmsFormatIE* newie=static_cast<CEmsFormatIE*>(formatIE.DuplicateL());
       
  1163 					CleanupStack::PushL(newie);
       
  1164 					newie->SetFormatLength(oldFormatLen - newFormatLen);
       
  1165 					newie->SetStartPosition(aCharsAlreadyAdded+aCharsAddedToCurrentPDU);
       
  1166 					LOGGSMU2("CSmsMessage::CorrectFormattingL",aCorrectedFormattingIEArray.Count());
       
  1167 					aCorrectedFormattingIEArray.Append(newie);
       
  1168 					CleanupStack::Pop(newie);
       
  1169 					}
       
  1170 				}
       
  1171 			}
       
  1172 		}
       
  1173 	} // CSmsMessage::CorrectFormattingL
       
  1174 
       
  1175 
       
  1176 void CSmsMessage::CorrectFormattingInSinglePDUL()
       
  1177 	{
       
  1178 	LOGGSMU1("CSmsMessage::CorrectFormattingInSinglePDUL()");
       
  1179 
       
  1180 	CSmsUserData& uData = SmsPDU().UserData();
       
  1181 	for (TInt a= 0; a < uData.NumInformationElements(); a++)
       
  1182 		{
       
  1183 		CSmsInformationElement& ie = uData.InformationElement(a);
       
  1184 		if (CSmsInformationElement::ESmsEnhancedTextFormatting==ie.Identifier())
       
  1185 			{
       
  1186 			CEmsFormatIE& formatIE=static_cast<CEmsFormatIE&>(ie);
       
  1187 			TUint oldFormatLen=formatIE.FormatLength(); //
       
  1188 			if(iBuffer->Length() < (TInt)(formatIE.StartPosition()+ oldFormatLen))
       
  1189 				{
       
  1190 				TUint newFormatLen=iBuffer->Length() - formatIE.StartPosition();
       
  1191 				formatIE.SetFormatLength(newFormatLen);
       
  1192 
       
  1193 				// reencode
       
  1194 				formatIE.EncodeInformationElementL();
       
  1195 				}
       
  1196 			}
       
  1197 		}
       
  1198 	} // CSmsMessage::CorrectFormattingInSinglePDUL
       
  1199 
       
  1200 
       
  1201 /**
       
  1202  *  Adds a copy of the current PDU to the PDU array used to record all the
       
  1203  *  PDUs being encoded in a concatentated message.
       
  1204  * 
       
  1205  *  @param  aDoEncode  If true the PDU is added and updated. If false only a
       
  1206  *                     NULL placeholder is stored. This allows the number of
       
  1207  *                     PDUs to be quickly counted if the encoded PDUs are of
       
  1208  *                     no further use.
       
  1209  */
       
  1210 void CSmsMessage::AddCurrentPDUToPDUArrayL(TBool aDoEncode)
       
  1211 	{
       
  1212 	LOGGSMU2("CSmsMessage::AddCurrentPDUToPDUArrayL(): Adding PDU number %d",
       
  1213 			 iAdditionalInfo->SmsPDUArray().Count() + 1);
       
  1214 	
       
  1215 	//
       
  1216 	// Maximum number of PDU is 255, so if we have that already then we cannot
       
  1217 	// continue.
       
  1218 	//
       
  1219 	TInt  numPDUs = iAdditionalInfo->SmsPDUArray().Count();
       
  1220 
       
  1221 	if (numPDUs >= 255)
       
  1222 		{
       
  1223 		User::Leave(KErrOverflow);
       
  1224 		}
       
  1225 	
       
  1226 	//
       
  1227 	// We only do most of the work if we are actually encoding.
       
  1228 	//
       
  1229 	if (aDoEncode)
       
  1230 		{
       
  1231 		//
       
  1232 		// Update the Concatenated Message PDU numbers in the current PDU. This
       
  1233 		// means that at least the last PDU has the correct values (to update
       
  1234 		// all PDUs when a new PDU is added would be too slow, so we do that
       
  1235 		// only once at the end).
       
  1236 		//
       
  1237 		if (numPDUs > 0)
       
  1238 			{
       
  1239 			SmsPDU().SetConcatenatedMessagePDUIndex(numPDUs+1);
       
  1240 			SmsPDU().SetNumConcatenatedMessagePDUs(numPDUs+1);
       
  1241 			}
       
  1242 	
       
  1243 		//
       
  1244 		// Create copy of the current PDU and store it in the array...
       
  1245 		//
       
  1246 		CSmsPDU*  newPDU = SmsPDU().DuplicateL();
       
  1247 		CleanupStack::PushL(newPDU);
       
  1248 		iAdditionalInfo->SmsPDUArray().AppendL(newPDU);
       
  1249 		CleanupStack::Pop(newPDU);
       
  1250 		}
       
  1251 	else
       
  1252 		{
       
  1253 		//
       
  1254 		// Otherwise just append a NULL value to allow the data PDUs to be
       
  1255 		// counted...
       
  1256 		//
       
  1257 		iAdditionalInfo->SmsPDUArray().AppendL(NULL);
       
  1258 		}
       
  1259 	} // CSmsMessage::AddCurrentPDUToPDUArrayL
       
  1260 
       
  1261 
       
  1262 TBool CSmsMessage::AddIEToUserDataL(CEmsInformationElement* aIE, TInt aCharsAlreadyAdded,TUint& aCharsAddedToCurrentPDU,CSmsEMSBufferSegmenter& aSeg)
       
  1263 	{
       
  1264 	LOGGSMU1("CSmsMessage::AddIEToUserDataL()");
       
  1265 
       
  1266 	TBool ieAdded=EFalse;
       
  1267 	if (SmsPDU().UserData().EmsInformationElementWillFitL(aIE,aSeg,aCharsAddedToCurrentPDU))
       
  1268 		{
       
  1269 		CEmsInformationElement* newIE=aIE->DuplicateL();
       
  1270 		newIE->SetStartPosition(newIE->StartPosition()-aCharsAlreadyAdded);
       
  1271 	    CleanupStack::PushL(newIE);
       
  1272 		SmsPDU().UserData().AddEmsInformationElementL(newIE);
       
  1273 		CleanupStack::Pop(newIE);
       
  1274 		ieAdded=ETrue;
       
  1275 		}
       
  1276 	return ieAdded;
       
  1277 	} // CSmsMessage::AddIEToUserDataL
       
  1278 
       
  1279 
       
  1280 /**
       
  1281  *  Fills the current PDU with the number of specified native chars.
       
  1282  *  
       
  1283  *  @param aSeg Buffer containing the native chars
       
  1284  *  @param aNumChars number of native characters to add.
       
  1285  *  @param aEncoding  SMS Encoding if required.
       
  1286  * 
       
  1287  *  @return TInt Number of native characters added
       
  1288  */
       
  1289 TInt CSmsMessage::FillPduL(CSmsEMSBufferSegmenter& aSeg, TInt aNumChars, TSmsEncoding aEncoding)
       
  1290 	{
       
  1291 	LOGGSMU1("CSmsMessage::FillPduL()");
       
  1292 
       
  1293 	TUint maxUDUnitsREmaining=SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
       
  1294 
       
  1295 	if (aNumChars==0 || maxUDUnitsREmaining==0)
       
  1296 		{
       
  1297 		return 0;
       
  1298 		}
       
  1299 
       
  1300 	HBufC8* buf=HBufC8::NewMaxLC(2*aNumChars);
       
  1301 	TPtr8 ptr(buf->Des());
       
  1302 	TInt numberOfUnconvertibleCharacters(0); 
       
  1303 	TInt numberOfDowngradedCharacters(0);
       
  1304 
       
  1305 	TInt nativeLength = aSeg.SegmentL(ptr, aNumChars, maxUDUnitsREmaining,
       
  1306 			                          numberOfUnconvertibleCharacters,
       
  1307 			                          numberOfDowngradedCharacters,
       
  1308 			                          aEncoding);
       
  1309 
       
  1310 	SmsPDU().UserData().AppendBodyL(ptr);
       
  1311 
       
  1312 	CleanupStack::PopAndDestroy(buf);
       
  1313 	return nativeLength;
       
  1314 	} // CSmsMessage::FillPduL
       
  1315 
       
  1316 
       
  1317 /**
       
  1318  *  This method copies control information elements from the specified
       
  1319  *  collection into the working PDU.
       
  1320  *  
       
  1321  *  @param aCategory        The category of control information element to be
       
  1322  *                          added to the PDU.
       
  1323  *  @param aMandatoryInPDU  Specifies whether the specified category of information
       
  1324  *                          element must be added to this PDU.
       
  1325  *  @param aDoEncode        Flag indicating if encoding is really wanted, or just the
       
  1326  *                          calculation of the number of PDUs.
       
  1327  *
       
  1328  *  @leave KErrArgument     If the category is mandatory but one or more elements
       
  1329  *                          cannot be added then the encoding will fail.
       
  1330  *  @leave KErrOverFlow     If the information element is too big to be encoded into
       
  1331  *                          a PDU that contains only the mandatory elements.
       
  1332  */
       
  1333 void CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL(TSmsInformationElementCategories::TInformationElementCategory aCategory,
       
  1334 			                                                          TBool aMandatoryInPDU, TBool aDoEncode)
       
  1335     {
       
  1336     LOGGSMU1("CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL()");
       
  1337 
       
  1338     TUint numberOfInformationElements = iAdditionalInfo->NumberOfControlInformationElements(aCategory);
       
  1339 
       
  1340     for (TInt i = 0; i < numberOfInformationElements; i++)
       
  1341         {
       
  1342         CSmsInformationElement& informationElement = iAdditionalInfo->GetControlInformationElementL( aCategory, i);
       
  1343 
       
  1344         CSmsInformationElement* cloneInformationElement = CSmsInformationElement::NewL(informationElement.Identifier(),informationElement.Data());
       
  1345         CleanupStack::PushL(cloneInformationElement);
       
  1346 
       
  1347         if (SmsPDU().UserData().ControlInformationElementWillFitL(cloneInformationElement))
       
  1348             {
       
  1349             SmsPDU().UserData().UpdateInformationElementArrayL(informationElement.Identifier(),informationElement.Data());
       
  1350             }
       
  1351         else if (aMandatoryInPDU)
       
  1352                 {
       
  1353                 // Error Scenario, cannot fit the mandatory PDU into the User Data
       
  1354                 User::Leave(KErrArgument);
       
  1355                 }
       
  1356              else
       
  1357                 {
       
  1358                 // Close off PDU and transfer to output array
       
  1359                 AddCurrentPDUToPDUArrayL(aDoEncode);
       
  1360                 ResetWorkingPDUL();
       
  1361 
       
  1362                 // Now test whether the information element will fit into a PDU at all.
       
  1363                 // It is possible to make Enhanced Voice Mail Information Elements
       
  1364                 // bigger than the available space in the PDU.
       
  1365                 TBool canFit = SmsPDU().UserData().ControlInformationElementWillFitL(cloneInformationElement);
       
  1366                 if (canFit == EFalse)
       
  1367                     {
       
  1368                     LOGGSMU1("CSmsMessage::AddControlInformationElementsToMultiSegmentMessage, IE too bit to fit in any PDUL");
       
  1369                     User::Leave(KErrArgument);
       
  1370                     }
       
  1371                 i--;
       
  1372                 }
       
  1373 
       
  1374         CleanupStack::PopAndDestroy(cloneInformationElement);
       
  1375         }
       
  1376     } // CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL
       
  1377 
       
  1378 
       
  1379 /**
       
  1380  *  This method copies control information elements from the collections of
       
  1381  *  control information elements contained in CSmsAdditionalAttributes into the
       
  1382  *  working PDU.
       
  1383  *  
       
  1384  *  @param aDoEncode  Flag indicating if encoding is really wanted, or just the
       
  1385  *                    calculation of the number of PDUs.
       
  1386  *
       
  1387  *  @leave KErrArgument  If the category is mandatory but one or more elements
       
  1388  *                       cannot be added then the encoding will fail.
       
  1389  */
       
  1390 void CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL(TBool aDoEncode)
       
  1391     {
       
  1392     LOGGSMU1("CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL() 1");
       
  1393 
       
  1394     TBool mandatoryInEachPDU = ETrue;
       
  1395     AddControlInformationElementsToMultiSegmentMessageL(TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly,
       
  1396     													mandatoryInEachPDU, aDoEncode);
       
  1397     mandatoryInEachPDU = EFalse;
       
  1398     AddControlInformationElementsToMultiSegmentMessageL(TSmsInformationElementCategories::ECtrlSingleInstanceOnly,
       
  1399     													mandatoryInEachPDU, aDoEncode);
       
  1400     AddControlInformationElementsToMultiSegmentMessageL(TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed,
       
  1401     													mandatoryInEachPDU, aDoEncode);
       
  1402     } // CSmsMessage::AddControlInformationElementsToMultiSegmentMessageL
       
  1403 
       
  1404 
       
  1405 /**
       
  1406  *  Attempts to add EMS IE to the current PDU.
       
  1407  *  
       
  1408  *  @param aSegmenter                  Reference to buffer segmenter.
       
  1409  *  @param aCharsAddedToCurrentPDU     Returned number of characters added to current PDU.
       
  1410  *  @param aDoEncode                   Flag indicating if encoding is really wanted,
       
  1411  *                                     or just the calculation of the number of PDUs.
       
  1412  *  @param aEncoding                   SMS 7bit encoding if appropriate.
       
  1413  *  @param aCorrectedFormatingIEArray  Array of IEs that have to be placed in following
       
  1414  *                                     PDUs (e.g. corrected).
       
  1415  *  @param aCurrEMSIEno                Current IE number.
       
  1416  *  @param aCharsAlreadyAdded          Returned number of characters added.
       
  1417  *
       
  1418  *  @return Whether EMS IE has beenn added, in singleMode returns true if there are no more than one PDU.
       
  1419  */
       
  1420 TBool CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL(CSmsEMSBufferSegmenter& aSegmenter,
       
  1421 																   TUint& aCharsAddedToCurrentPDU,
       
  1422 																   TBool aDoEncode,
       
  1423 																   TSmsEncoding& aEncoding,
       
  1424 																   RPointerArray<CEmsInformationElement>& aCorrectedFormatingIEArray,
       
  1425 																   TUint& aCurrEMSIEno,
       
  1426 																   TUint& aCharsAlreadyAdded)
       
  1427 	{
       
  1428 	LOGGSMU1("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL()");
       
  1429 
       
  1430 	TUint startPosition=0;
       
  1431 
       
  1432 	 // number of chars added to the current PDU
       
  1433 	TUint no=iInformationElementArray->Count();
       
  1434 	LOGGSMU2("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL no of IE %d",no);
       
  1435 	CEmsInformationElement* ie = NULL;
       
  1436 	TUint msgLen=iBuffer->Length();
       
  1437 	TUint filledChars=0;
       
  1438 
       
  1439 	while(aCurrEMSIEno < no || aCorrectedFormatingIEArray.Count() > 0)
       
  1440 	{
       
  1441 		ie = NULL;
       
  1442 		TBool correction=EFalse;
       
  1443 		if(aCurrEMSIEno < no)
       
  1444 			{
       
  1445 			ie = (*iInformationElementArray)[aCurrEMSIEno];
       
  1446 			startPosition=ie->StartPosition();
       
  1447 			}
       
  1448 
       
  1449 		if(ie == NULL || ( startPosition != aCharsAlreadyAdded) )
       
  1450 		{
       
  1451 			if(aCorrectedFormatingIEArray.Count() > 0)
       
  1452 			{
       
  1453 				correction=ETrue;
       
  1454 				ie = aCorrectedFormatingIEArray[0];
       
  1455 				startPosition=ie->StartPosition();
       
  1456 			}
       
  1457 		}
       
  1458 
       
  1459 		__ASSERT_DEBUG(ie !=NULL, User::Leave(KErrCorrupt));
       
  1460 
       
  1461 		if(startPosition <= msgLen)
       
  1462 			{
       
  1463 			__ASSERT_DEBUG(startPosition>=aCharsAlreadyAdded, User::Leave(KErrUnderflow));
       
  1464 			startPosition -= aCharsAlreadyAdded; // startPosition now relative to current PDU.
       
  1465 
       
  1466 			// Add all chars upto startposition.
       
  1467 			filledChars=0;
       
  1468 
       
  1469 			if(startPosition > aCharsAddedToCurrentPDU)
       
  1470 				{
       
  1471 				filledChars = FillPduL(aSegmenter, startPosition-aCharsAddedToCurrentPDU, aEncoding);
       
  1472 				aCharsAddedToCurrentPDU+=filledChars;
       
  1473 				}
       
  1474 
       
  1475 			LOGGSMU2("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL: filled %d chars", filledChars);
       
  1476 
       
  1477 			if (aCharsAddedToCurrentPDU==startPosition)
       
  1478 				{
       
  1479 				// Try adding the IE.
       
  1480 				if (AddIEToUserDataL(ie, aCharsAlreadyAdded,aCharsAddedToCurrentPDU,aSegmenter))
       
  1481 					{
       
  1482 					if(correction)
       
  1483 					{
       
  1484 						aCorrectedFormatingIEArray.Remove(0);
       
  1485 						// aCorrectedFormatingIEArray[0] has been removed. In next loop, ie will point another element. So there is no double free.
       
  1486 						// coverity[double_free]
       
  1487 						delete ie;
       
  1488 						correction=EFalse;
       
  1489 					}
       
  1490 					else aCurrEMSIEno++;
       
  1491 					}
       
  1492 				else
       
  1493 					{
       
  1494 					// Information Element will not fit send PDU
       
  1495 					LOGGSMU1("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL: ie will not fit send Message");
       
  1496 					CorrectFormattingL(aCharsAddedToCurrentPDU,aCorrectedFormatingIEArray,aCharsAlreadyAdded);
       
  1497 
       
  1498 					aCharsAlreadyAdded += aCharsAddedToCurrentPDU;
       
  1499 					aCharsAddedToCurrentPDU=0;
       
  1500 
       
  1501 					AddCurrentPDUToPDUArrayL(aDoEncode);
       
  1502 					ResetWorkingPDUL();
       
  1503 
       
  1504 					//
       
  1505 					// Find the encoding method for the next segment...
       
  1506 					//
       
  1507 					//aEncoding = ESmsEncodingNone;
       
  1508 					//TRAP_IGNORE(aEncoding = aSegmenter->FindBestAlternativeEncodingL(iAdditionalInfo->iAlternative7bitEncoding,
       
  1509 					//												                   maxBodyLength));
       
  1510 					SmsPDU().SetNationalLanguageEncodingL(aEncoding);
       
  1511 					}
       
  1512 				}
       
  1513 			else
       
  1514 				{
       
  1515 				// native chars upto start position will not fit send PDu.
       
  1516 				LOGGSMU1("CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL: PDU is filled with chars sending");
       
  1517 
       
  1518 				CorrectFormattingL(aCharsAddedToCurrentPDU,aCorrectedFormatingIEArray,aCharsAlreadyAdded);
       
  1519 
       
  1520 				aCharsAlreadyAdded += aCharsAddedToCurrentPDU;
       
  1521 				aCharsAddedToCurrentPDU=0;
       
  1522 
       
  1523 				AddCurrentPDUToPDUArrayL(aDoEncode);
       
  1524 				ResetWorkingPDUL();
       
  1525 
       
  1526 				//
       
  1527 				// Find the encoding method for the next segment...
       
  1528 				//
       
  1529 				//aEncoding = ESmsEncodingNone;
       
  1530 				//TRAP_IGNORE(aEncoding = aSegmenter->FindBestAlternativeEncodingL(iAdditionalInfo->iAlternative7bitEncoding,
       
  1531 				//												                   maxBodyLength));
       
  1532 				SmsPDU().SetNationalLanguageEncodingL(aEncoding);
       
  1533 				}
       
  1534 			}
       
  1535 		else
       
  1536 			{
       
  1537 			aCurrEMSIEno++;
       
  1538 			}
       
  1539 		}		// end of while loop for all IEs
       
  1540 
       
  1541 	return ETrue;
       
  1542 	} // CSmsMessage::AddEMSInformationElementsToMultiSegmentMessageL
       
  1543 
       
  1544 
       
  1545 /**
       
  1546  *  Attempts to add EMS IE to the current PDU
       
  1547  *  
       
  1548  *  @param aSegmenter
       
  1549  *  @return TBool whether EMS IEs have been added to segment
       
  1550  */
       
  1551 TBool CSmsMessage::AddEMSInformationElementsToSingleSegmentMessageL(CSmsEMSBufferSegmenter& aSegmenter,
       
  1552 																	TSmsEncoding aEncoding)
       
  1553 	{
       
  1554 	LOGGSMU1("CSmsMessage::AddEMSInformationElementsToSingleSegmentMessageL()");
       
  1555 
       
  1556 	TUint charsAddedToCurrentPDU=0;
       
  1557 	TUint numOfEmsIE=iInformationElementArray->Count();
       
  1558 	TUint currEmsIEindex=0;
       
  1559 	CEmsInformationElement* ie = NULL;
       
  1560 	TUint startPosition=0;
       
  1561 	TUint filledChars=0;
       
  1562 
       
  1563 	while(currEmsIEindex < numOfEmsIE)
       
  1564 		{
       
  1565 		ie = (*iInformationElementArray)[currEmsIEindex];
       
  1566 		startPosition=ie->StartPosition();
       
  1567 
       
  1568 		if (startPosition > charsAddedToCurrentPDU)
       
  1569 			{
       
  1570 			filledChars = FillPduL(aSegmenter, startPosition-charsAddedToCurrentPDU, aEncoding);
       
  1571 			charsAddedToCurrentPDU+=filledChars;
       
  1572 			}
       
  1573 
       
  1574 		if (charsAddedToCurrentPDU != startPosition ||
       
  1575 			!AddIEToUserDataL(ie, 0,charsAddedToCurrentPDU,aSegmenter))
       
  1576 			{
       
  1577 			return EFalse;
       
  1578 			}
       
  1579 
       
  1580 		++currEmsIEindex;
       
  1581 		}
       
  1582 
       
  1583 	return ETrue;
       
  1584 	} // CSmsMessage::AddEMSInformationElementsToSingleSegmentMessageL
       
  1585 
       
  1586 
       
  1587 /**
       
  1588  *  Encode the PDU into an TGsmSms array. The Text and the EMS objects are
       
  1589  *  laid out with respect to start position locations and encoded into the
       
  1590  *  correct TGsmSms object.
       
  1591  *  
       
  1592  *  @leave KErrUnderflow if the Ems objects are not in Start position order.
       
  1593  *
       
  1594  *  @param aSmsArray               Returned array of newly created TSms objects
       
  1595  *                                 containing the encoded message.
       
  1596  *  @param aReference              Unique reference number to be given to the
       
  1597  *                                 TGsmSms objects.
       
  1598  *  @param aBuffer                 Body Text buffer of the message.
       
  1599  *  @param aUnconvertedChars       Exit param for the number of characters not converted.
       
  1600  *  @param aDowngradedChars        Exit param for the number of characters downgraded.
       
  1601  *  @param aFreeUDUnitsInLastPDU   Exit param for the number of characters free
       
  1602  *                                 in the last PDU.
       
  1603  *  @param aDoEncode               Flag indicating if encoding is really wanted,
       
  1604  *                                 or just the calculation of the number of PDUs.
       
  1605  */
       
  1606 void CSmsMessage::EncodeBufferL(CArrayFix<TGsmSms>& aSmsArray, TInt aReference,
       
  1607 								const CSmsBufferBase& aBuffer,
       
  1608 								TInt& aUnconvertedChars, TInt& aDowngradedChars,
       
  1609 						        TInt& aFreeUDUnitsInLastPDU, TBool aDoEncode)
       
  1610 	{
       
  1611 	LOGGSMU1("CSmsMessage::EncodeBufferL()");
       
  1612 
       
  1613 	aUnconvertedChars     = 0;
       
  1614 	aDowngradedChars      = 0;
       
  1615 	aFreeUDUnitsInLastPDU = 0;
       
  1616 	
       
  1617 	//
       
  1618 	// Reset the working array of PDUs...
       
  1619 	//
       
  1620 	iAdditionalInfo->SmsPDUArray().ResetAndDestroy();
       
  1621 
       
  1622 	TUint currEMSIEno(0);
       
  1623 	
       
  1624 	TInt smscIndex(0);
       
  1625 	TBool smscPresent(EFalse);
       
  1626 	
       
  1627 	TInt emailOverallHeaderLength(0);
       
  1628 	TInt emailIndex(0);
       
  1629 	TBool emailPresent(EFalse);
       
  1630 	
       
  1631 	if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
       
  1632 		{
       
  1633 		smscPresent=ETrue;
       
  1634 		}
       
  1635 	if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEIRFC822EmailHeader,emailIndex))
       
  1636 		{
       
  1637 		emailPresent=ETrue;
       
  1638 		emailOverallHeaderLength=SmsPDU().UserData().InformationElement(emailIndex).Data()[0];
       
  1639 		}
       
  1640 
       
  1641 	//
       
  1642 	// Create Array for corrected format elements. These will be elements that
       
  1643 	// have to be moved into subsequent PDUs due to lack of space in the
       
  1644 	// current PDU.
       
  1645 	//
       
  1646 	RPointerArray<CEmsInformationElement>  correctedFormatingIEArray(2);
       
  1647 	CleanupResetAndDestroyPushL(correctedFormatingIEArray);
       
  1648 
       
  1649 	//
       
  1650 	// Reset the working PDU. This safes time be keeping fields we need and
       
  1651 	// droping any data from previous PDUs.
       
  1652 	//
       
  1653 	ResetWorkingPDUL();
       
  1654 
       
  1655 	//
       
  1656 	// Automatically prepare for concatenation (any single PDU messages would
       
  1657 	// have been handled by EncodeIntoSinglePDUL() previously).
       
  1658 	//
       
  1659 	SmsPDU().SetTextConcatenatedL(ETrue,iIs16BitConcatenation);
       
  1660 
       
  1661 	TInt maxBodyLength=SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
       
  1662 
       
  1663 	//
       
  1664 	// Add any elements that are required to be present, and ensure they
       
  1665 	// have correct data stored (for example if we are recycling the working PDU).
       
  1666 	//
       
  1667 	AddControlInformationElementsToMultiSegmentMessageL(aDoEncode);
       
  1668 
       
  1669 	//
       
  1670 	// Create EMS Segmenter and Buffer Converter...
       
  1671 	//
       
  1672 	CSmsAlphabetConverter*  converter = CSmsAlphabetConverter::NewLC(*iCharacterSetConverter, iFs,SmsPDU().Alphabet(),
       
  1673 			                                                         BinaryData());
       
  1674 	CSmsEMSBufferSegmenter*  segmenter = CSmsEMSBufferSegmenter::NewLC(*converter, aBuffer, maxBodyLength);
       
  1675 	TBool  isUnicode = (SmsPDU().Alphabet() == TSmsDataCodingScheme::ESmsAlphabetUCS2);
       
  1676 
       
  1677 	TBool informationToSend     = ETrue;
       
  1678 	TUint charsAdded2CurrentPDU = 0;
       
  1679 	TUint charsAlreadyAdded     = 0;
       
  1680 
       
  1681 	//
       
  1682 	// Find the best alternative encoding for the current segment. This will be
       
  1683 	// set at the beginning of each PDU using the list of encoders.
       
  1684 	//
       
  1685 	TSmsEncoding  encodingToUse = ESmsEncodingNone;
       
  1686 
       
  1687 	TRAP_IGNORE(encodingToUse = segmenter->FindBestAlternativeEncodingL(iAdditionalInfo->Alternative7bitEncoding(),
       
  1688 													                    aBuffer.Length()));
       
  1689 	SmsPDU().SetNationalLanguageEncodingL(encodingToUse);
       
  1690 	
       
  1691 	//
       
  1692 	// If there are information elements to add, add them to the first PDU (or
       
  1693 	// to the correct formatting array for later PDUs if more appropriate).
       
  1694 	//
       
  1695 	if(iInformationElementArray->Count() >0)
       
  1696 		{
       
  1697 		AddEMSInformationElementsToMultiSegmentMessageL(*segmenter, charsAdded2CurrentPDU,
       
  1698 														aDoEncode, encodingToUse,
       
  1699 														correctedFormatingIEArray,
       
  1700 														currEMSIEno, charsAlreadyAdded);
       
  1701 		}
       
  1702 
       
  1703 	//
       
  1704 	// Allocate a temporary buffer to work with...
       
  1705 	//
       
  1706 	HBufC8* buf=HBufC8::NewMaxLC(maxBodyLength);
       
  1707 	TPtr8 ptr(buf->Des());
       
  1708 
       
  1709 	//
       
  1710 	// While there is still data to encode see how much space is left in this
       
  1711 	// PDU and attempt to encode something into it...
       
  1712 	//
       
  1713 	while (segmenter->MoreL())
       
  1714 			{
       
  1715 			LOGGSMU1("CSmsMessage::EncodeBufferL - there is MoreL");
       
  1716 			
       
  1717 			//
       
  1718 			// Calculate the space left to use in this PDU...
       
  1719 			//
       
  1720 			TInt size = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
       
  1721 			LOGGSMU2("CSmsMessage::EncodeBufferL - remaining size in PDU is %d",size);
       
  1722 
       
  1723 			//
       
  1724 			// While there is no space, correct the formatting (which may
       
  1725 			// introduce any un-placed EMS Elements into the corrected format
       
  1726 			// array) and then start a new PDU...
       
  1727 			//
       
  1728 			while (size==0)
       
  1729 				{
       
  1730 				//
       
  1731 				// Store any elements not yet placed into the array for later...
       
  1732 				//
       
  1733 				CorrectFormattingL(charsAdded2CurrentPDU, correctedFormatingIEArray, charsAlreadyAdded);
       
  1734 
       
  1735 				//
       
  1736 				// Store this PDU, reset the working PDU and get ready to
       
  1737 				// continue with the next PDU...
       
  1738 				//
       
  1739 				aFreeUDUnitsInLastPDU = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
       
  1740 				AddCurrentPDUToPDUArrayL(aDoEncode);
       
  1741 				ResetWorkingPDUL();
       
  1742 				informationToSend=EFalse;
       
  1743 				charsAlreadyAdded+=charsAdded2CurrentPDU;
       
  1744 				charsAdded2CurrentPDU=0;
       
  1745 
       
  1746 				//
       
  1747 				// Find the encoding method for the next segment...
       
  1748 				//
       
  1749 				//encodingToUse = ESmsEncodingNone;
       
  1750 				//TRAP_IGNORE(encodingToUse = segmenter->FindBestAlternativeEncodingL(iAdditionalInfo->iAlternative7bitEncoding,
       
  1751 				//												                    maxBodyLength));
       
  1752 				SmsPDU().SetNationalLanguageEncodingL(encodingToUse);
       
  1753 
       
  1754 				//
       
  1755 				// Add any elements that can be placed now (from previous
       
  1756 				// PDUs and above)... 
       
  1757 				//
       
  1758 				LOGGSMU3("CSmsMessage::EncodeBufferL: IE count  %d corrected  count %d",iInformationElementArray->Count(),correctedFormatingIEArray.Count() );
       
  1759 				if ((TUint)iInformationElementArray->Count() > currEMSIEno  ||
       
  1760 					correctedFormatingIEArray.Count() > 0)
       
  1761 					{
       
  1762 					AddEMSInformationElementsToMultiSegmentMessageL(*segmenter,charsAdded2CurrentPDU,
       
  1763 																	aDoEncode, encodingToUse,
       
  1764 																	correctedFormatingIEArray,
       
  1765 																	currEMSIEno,charsAlreadyAdded);
       
  1766 					}
       
  1767 
       
  1768 				//
       
  1769 				// Calculate the space left remaining in this new PDU...
       
  1770 				//
       
  1771 				size = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
       
  1772 				LOGGSMU2("CSmsMessage::EncodeBufferL - remaining size in PDU is %d",size);
       
  1773 				}
       
  1774 			
       
  1775 			//
       
  1776 			// We have space in this PDU and no elements to place, so obtain
       
  1777 			// the next peice of text that can fit and append it.
       
  1778 			//
       
  1779 			segmenter->SegmentNextL(ptr, size, aUnconvertedChars, aDowngradedChars, encodingToUse);
       
  1780 			SmsPDU().UserData().AppendBodyL(ptr);
       
  1781 
       
  1782 			TUint charsInSegment= isUnicode ? ptr.Length()/2 : ptr.Length();
       
  1783 			LOGGSMU2("CSmsMessage::EncodeBufferL: segmenting added %d chars", charsInSegment);
       
  1784 
       
  1785 			//
       
  1786 			// At this point the working PDU is either full (e.g. we filled the
       
  1787 			// remaining space with a chuck of text, or the is some space as we
       
  1788 			// stored the last part of the text.
       
  1789 			//
       
  1790 			// If there are any elements not yet stored, add them to the
       
  1791 			// formatting array...
       
  1792 			//
       
  1793 			charsAdded2CurrentPDU+=charsInSegment;
       
  1794 			CorrectFormattingL(charsAdded2CurrentPDU, correctedFormatingIEArray, charsAlreadyAdded);
       
  1795 			charsAlreadyAdded+=charsAdded2CurrentPDU;
       
  1796 			LOGGSMU2("CSmsMessage::EncodeBufferL(): charsAlreadyAdded=%d", charsAlreadyAdded);
       
  1797 			
       
  1798 			//
       
  1799 			// Now store this PDU and reset the working PDU...
       
  1800 			//
       
  1801 			aFreeUDUnitsInLastPDU = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
       
  1802 			AddCurrentPDUToPDUArrayL(aDoEncode);
       
  1803 			ResetWorkingPDUL();
       
  1804 			informationToSend=EFalse;
       
  1805 			charsAdded2CurrentPDU=0;
       
  1806 			
       
  1807 			//
       
  1808 			// Find the encoding method for the next segment...
       
  1809 			//
       
  1810 			//encodingToUse = ESmsEncodingNone;
       
  1811 			//TRAP_IGNORE(encodingToUse = segmenter->FindBestAlternativeEncodingL(iAdditionalInfo->iAlternative7bitEncoding,
       
  1812 			//												                    maxBodyLength));
       
  1813 			SmsPDU().SetNationalLanguageEncodingL(encodingToUse);
       
  1814 
       
  1815 			//
       
  1816 			// Add any elements that can be placed now given we have a new
       
  1817 			// empty PDU... 
       
  1818 			//
       
  1819 			LOGGSMU3("CSmsMessage::EncodeBufferL: IE count  %d corrected  count %d",
       
  1820 			         iInformationElementArray->Count(), correctedFormatingIEArray.Count() );
       
  1821 			if ((TUint)iInformationElementArray->Count() > currEMSIEno  ||
       
  1822 				correctedFormatingIEArray.Count() > 0)
       
  1823 				{
       
  1824 				AddEMSInformationElementsToMultiSegmentMessageL(*segmenter, charsAdded2CurrentPDU,
       
  1825 																aDoEncode, encodingToUse,
       
  1826 																correctedFormatingIEArray,
       
  1827 																currEMSIEno, charsAlreadyAdded);
       
  1828 				}
       
  1829 			LOGGSMU1("CSmsMessage::EncodeBufferL end Moreloop");
       
  1830 			}
       
  1831 	CleanupStack::PopAndDestroy(buf);
       
  1832 
       
  1833 	LOGGSMU1("CSmsMessage::EncodeBufferL - last PDU");
       
  1834 	
       
  1835 	//
       
  1836 	// This is the last PDU. We need to check if there is a partial PDU left over
       
  1837 	// and add it if needed.
       
  1838 	//
       
  1839 	if (informationToSend)
       
  1840 		{
       
  1841 		aFreeUDUnitsInLastPDU = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
       
  1842 		AddCurrentPDUToPDUArrayL(aDoEncode);
       
  1843 		ResetWorkingPDUL();
       
  1844 		}
       
  1845 
       
  1846 	//
       
  1847 	// At this point the segmenting and layouts of PDU is complete, so if we
       
  1848 	// find any more data something is wrong...
       
  1849 	//
       
  1850 	if (segmenter->MoreL()  ||  correctedFormatingIEArray.Count() > 0)
       
  1851 		{
       
  1852 		User::Leave(KErrCorrupt);
       
  1853 		}
       
  1854 
       
  1855 	CleanupStack::PopAndDestroy(3, &correctedFormatingIEArray); // segmenter, converter & correctedFormatingIEArray
       
  1856 
       
  1857 	//
       
  1858 	// By now the PDUs are segmented and correctly setup for encoding.
       
  1859 	// They have not been encoded yet, as this requires the PDU total to be known.
       
  1860 	// So we go through the array setting the final PDU number/total PDUs and
       
  1861 	// perform the encoding from CSmsPDU to the TGsmPdu object.
       
  1862 	//
       
  1863 	// Note: In the case were aDoEncode is EFalse, iSmsPDUArray will be full
       
  1864 	//       of NULL pointers as it is only the count that we need in that case.
       
  1865 	//
       
  1866 	TInt  numPDUs = iAdditionalInfo->SmsPDUArray().Count();
       
  1867 
       
  1868 	LOGGSMU2("CSmsMessage::EncodeBufferL number of PDUs: %d", iAdditionalInfo->SmsPDUArray().Count());
       
  1869 	
       
  1870 	if (aDoEncode)
       
  1871 		{
       
  1872 		CSmsMessageAdditionalAttributes::CSmsStatusReportScheme&  scheme = iAdditionalInfo->GetStatusReportScheme();
       
  1873 		TGsmSms  gsmSms;
       
  1874 		
       
  1875 		for (TInt pdu = 0;  pdu < numPDUs;  pdu++)
       
  1876 			{
       
  1877 			if(scheme.Id() == EControlParametersScheme)
       
  1878 				{
       
  1879 				if(smscPresent)				
       
  1880 					{
       
  1881 					CSmsSMSCCtrlParameterOperations&  ieOp = (CSmsSMSCCtrlParameterOperations&)GetOperationsForIEL(CSmsInformationElement::ESmsIEISMSCControlParameters);
       
  1882 					TUint8 octet(0);
       
  1883 
       
  1884 					if (ieOp.GetStatusReport(pdu, octet) == KErrNone)
       
  1885 						{					
       
  1886 						iAdditionalInfo->SmsPDUArray()[pdu]->UpdateSMSCCtrlParameterL(octet);
       
  1887 						}
       
  1888 					}
       
  1889 				else
       
  1890 					{
       
  1891 					User::Leave(KErrNotFound);
       
  1892 					}
       
  1893 				}
       
  1894 			else if(scheme.Id() == ETPSRRScheme)
       
  1895 				{
       
  1896 				TSmsFirstOctet smsReportRequest;
       
  1897 				CSmsTPSRROperations& nonIEOp = (CSmsTPSRROperations&)GetOperationsForNonIEL(ESmsTPSRRParameter);
       
  1898 				smsReportRequest = nonIEOp.GetStatusReport(pdu);
       
  1899 								
       
  1900 				iAdditionalInfo->SmsPDUArray()[pdu]->UpdateTPSRRL(smsReportRequest);
       
  1901 				}
       
  1902 
       
  1903 			if(emailPresent)				
       
  1904 				{
       
  1905 				iAdditionalInfo->SmsPDUArray()[pdu]->UpdateEmailHeaderDataL(emailOverallHeaderLength);
       
  1906 				}
       
  1907 
       
  1908 			//
       
  1909 			// Set the concatenation Message Reference number and PDU numbers...
       
  1910 			//
       
  1911 			iAdditionalInfo->SmsPDUArray()[pdu]->UpdateConcatenationDataL(aReference, pdu+1, numPDUs);
       
  1912 
       
  1913 			//
       
  1914 			// Encode this PDU...
       
  1915 			//
       
  1916 			
       
  1917 			TEncodeParams encodeParams;
       
  1918 			encodeParams.iTimeStamp = &Time();
       
  1919 			
       
  1920 			TTimeIntervalSeconds interval = UTCOffset();
       
  1921 			encodeParams.iTimeIntervalInSeconds = &interval;
       
  1922 						
       
  1923 			iAdditionalInfo->SmsPDUArray()[pdu]->EncodeMessagePDUL(gsmSms, &encodeParams);
       
  1924 	 		aSmsArray.AppendL(gsmSms);
       
  1925 			}
       
  1926 
       
  1927 		//
       
  1928 		// Since the working PDU has been reset the data in it does not match
       
  1929 		// the data of the last PDU. Some tests in SMS Stack assume it does
       
  1930 		// and therefore to retain compatibility we decode the last PDU back
       
  1931 		// over the working PDU.
       
  1932 		//
       
  1933 		TGsmuLex8 lex(gsmSms.Pdu());
       
  1934 		SmsPDU().DecodeL(lex);
       
  1935 		}
       
  1936 	} // CSmsMessage::EncodeBufferL
       
  1937 
       
  1938 
       
  1939 /**
       
  1940  *  Attempts to encode into the single PDU. This function is the private version
       
  1941  *  to the public EncodeIntoSinglePDUL() function. It performs the work and also
       
  1942  *  returns more information regarding the characters encoded.
       
  1943  *  
       
  1944  *  The Text and the EMS objects are laid out with respect to start position
       
  1945  *  locations.
       
  1946  *  
       
  1947  *  @leave KErrUnderflow if the Ems objects are not in Start position order.
       
  1948  *
       
  1949  *  @param aSmsArray               Returned array of newly created TSms objects
       
  1950  *                                 containing the encoded message.
       
  1951  *  @param aUnconvertedChars       Exit param for the number of characters not converted.
       
  1952  *  @param aDowngradedChars        Exit param for the number of characters downgraded.
       
  1953  *  @param aFreeUDUnitsInLastPDU   Exit param for the number of characters free
       
  1954  *                                 in the last PDU.
       
  1955  */
       
  1956 TBool CSmsMessage::EncodeIntoSinglePDUL(CArrayFix<TGsmSms>& aSmsArray, TInt& aUnconvertedChars,
       
  1957 		                                TInt& aDowngradedChars, TInt& aFreeUDUnitsInLastPDU)
       
  1958 	{
       
  1959 	LOGGSMU1("CSmsMessage::EncodeIntoSinglePDUL()");
       
  1960 
       
  1961 	__ASSERT_DEBUG((aSmsArray.Count()==0),Panic(KGsmuPanicSmsArrayNotEmpty));
       
  1962 
       
  1963 	aUnconvertedChars     = 0;
       
  1964 	aDowngradedChars      = 0;
       
  1965 	aFreeUDUnitsInLastPDU = 0;
       
  1966 
       
  1967 	iAdditionalInfo->SmsPDUArray().ResetAndDestroy();
       
  1968 
       
  1969 	if (!TextPresent())
       
  1970 		{
       
  1971         if(SmsPDU().Type()==CSmsPDU::ESmsCommand)
       
  1972             {
       
  1973             // Commands don't contain text, so commands
       
  1974             // are only encoded in this branch.
       
  1975             PrepareCommandMessageL();
       
  1976             }
       
  1977 
       
  1978 		TGsmSms sms;
       
  1979 		SmsPDU().EncodeMessagePDUL(sms);
       
  1980 		aSmsArray.AppendL(sms);
       
  1981 		return ETrue;
       
  1982 		}
       
  1983 
       
  1984 	ResetWorkingPDUL();
       
  1985 
       
  1986     // find the length of all the control information elements
       
  1987     TUint ieLength=0;
       
  1988     for (TUint8 category = 0; category <  TSmsInformationElementCategories::ENumberOfCategories; category++)
       
  1989         {
       
  1990         switch (category)
       
  1991             {
       
  1992             case  TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly:
       
  1993             case  TSmsInformationElementCategories::ECtrlSingleInstanceOnly:
       
  1994             case  TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed:
       
  1995                 {
       
  1996                 for (TUint j = 0; j < iAdditionalInfo->NumberOfControlInformationElements((CSmsMessageAdditionalAttributes::TCategory) category); j++)
       
  1997                     {
       
  1998                     ieLength += iAdditionalInfo->GetControlInformationElementL( ( (CSmsMessageAdditionalAttributes::TCategory) category), j).Length();
       
  1999                     }
       
  2000                 break;
       
  2001                 }
       
  2002             default:
       
  2003                 break;
       
  2004             }
       
  2005         }
       
  2006     LOGGSMU2("CSmsMessage::EncodeIntoSinglePDUL, ctrl elem len = %d", ieLength);
       
  2007 
       
  2008 	CEmsInformationElement* emsIE =NULL;
       
  2009 	for (TInt num=0; num<iInformationElementArray->Count();num++)
       
  2010 		{
       
  2011 		emsIE = (*iInformationElementArray)[num];
       
  2012         ieLength+=emsIE->Length();
       
  2013 		}
       
  2014 
       
  2015 	TInt remainInBody=SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining(ieLength);
       
  2016 
       
  2017 	TInt msgLength=MessageLengthL(); // in octets
       
  2018 
       
  2019 	if( msgLength > remainInBody) return EFalse;
       
  2020 
       
  2021     LOGGSMU4("CSmsMessage::EncodeIntoSinglePDUL, ie len = %d, remainInBody = %d, msgLength = %d", ieLength, msgLength, remainInBody);
       
  2022     //  add all control information elements into working PDU.
       
  2023     //
       
  2024     for (TUint8 category = 0; category <  TSmsInformationElementCategories::ENumberOfCategories; category++)
       
  2025         {
       
  2026         switch (category)
       
  2027             {
       
  2028             case  TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly:
       
  2029             case  TSmsInformationElementCategories::ECtrlSingleInstanceOnly:
       
  2030             case  TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed:
       
  2031                 {
       
  2032                 for (TUint j = 0; j < iAdditionalInfo->NumberOfControlInformationElements((CSmsMessageAdditionalAttributes::TCategory) category); j++)
       
  2033                     {
       
  2034                     CSmsInformationElement& informationElement = iAdditionalInfo->GetControlInformationElementL( ( (CSmsMessageAdditionalAttributes::TCategory) category), j);
       
  2035 
       
  2036                     CSmsInformationElement* cloneInformationElement = CSmsInformationElement::NewL(informationElement.Identifier(),informationElement.Data());
       
  2037                     CleanupStack::PushL(cloneInformationElement);
       
  2038                     TBool willFit = SmsPDU().UserData().ControlInformationElementWillFitL(cloneInformationElement);
       
  2039                     CleanupStack::PopAndDestroy(cloneInformationElement);
       
  2040 
       
  2041                     if (willFit)
       
  2042                         {
       
  2043                         SmsPDU().UserData().UpdateInformationElementArrayL(informationElement.Identifier(),informationElement.Data());
       
  2044                         }
       
  2045                     else
       
  2046                         {
       
  2047                         ResetWorkingPDUL();
       
  2048                         return EFalse;
       
  2049                         }
       
  2050                     }
       
  2051                 break;
       
  2052                 }
       
  2053             default:
       
  2054                 break;
       
  2055             }
       
  2056         }
       
  2057 		
       
  2058 	EncodingTPSRRFromSchemesIntoSinglePDUL();
       
  2059 
       
  2060 	TInt maxBodyLength=SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
       
  2061 	CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,SmsPDU().Alphabet(),BinaryData());
       
  2062 	CSmsEMSBufferSegmenter* segmenter=CSmsEMSBufferSegmenter::NewLC(*converter,*iBuffer, maxBodyLength);
       
  2063 
       
  2064 	//
       
  2065 	// Find the best alternative encoding for the current segment. This will be
       
  2066 	// set at the beginning of each PDU using the list of encoders.
       
  2067 	//
       
  2068 	TSmsEncoding  encodingToUse = ESmsEncodingNone;
       
  2069 
       
  2070 	TRAP_IGNORE(encodingToUse= segmenter->FindBestAlternativeEncodingL(iAdditionalInfo->Alternative7bitEncoding(),
       
  2071 													                   maxBodyLength));
       
  2072 	SmsPDU().SetNationalLanguageEncodingL(encodingToUse);
       
  2073 	
       
  2074 	if(!AddEMSInformationElementsToSingleSegmentMessageL(*segmenter, encodingToUse))
       
  2075 		{
       
  2076 		aSmsArray.Reset();
       
  2077 		CleanupStack::PopAndDestroy(2, converter);
       
  2078 		return EFalse;
       
  2079 		}
       
  2080 
       
  2081 	if(segmenter->MoreL())
       
  2082 			{
       
  2083 			TInt size = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
       
  2084 			// Defensive code to prevent SegmentNextL being called with size of zero
       
  2085 			if (size == 0)
       
  2086 				{
       
  2087 				CleanupStack::PopAndDestroy(2, converter);
       
  2088 				aSmsArray.Reset();
       
  2089 				return EFalse;
       
  2090 				}
       
  2091 			HBufC8* buf=HBufC8::NewMaxLC(maxBodyLength);
       
  2092 			TPtr8 ptr(buf->Des());
       
  2093 			segmenter->SegmentNextL(ptr, size, aUnconvertedChars, aDowngradedChars, encodingToUse);
       
  2094 			SmsPDU().UserData().AppendBodyL(ptr);
       
  2095 			CleanupStack::PopAndDestroy(buf);
       
  2096 			}
       
  2097 	CorrectFormattingInSinglePDUL();
       
  2098 
       
  2099 	if (segmenter->MoreL())
       
  2100 		{
       
  2101 		CleanupStack::PopAndDestroy(2, converter);
       
  2102 		aSmsArray.Reset();
       
  2103 		return EFalse;
       
  2104 		}
       
  2105 	CleanupStack::PopAndDestroy(2, converter);
       
  2106 
       
  2107 	aFreeUDUnitsInLastPDU = SmsPDU().UserData().MaxPackedUDUnitsInBodyRemaining();
       
  2108 
       
  2109 	//
       
  2110 	// Encode the PDU...
       
  2111 	//
       
  2112 	TGsmSms  gsmSms;
       
  2113 		
       
  2114 	TEncodeParams encodeParams;
       
  2115 	encodeParams.iTimeStamp = &Time();
       
  2116 		
       
  2117 	TTimeIntervalSeconds interval = UTCOffset();
       
  2118 	encodeParams.iTimeIntervalInSeconds = &interval;
       
  2119 		
       
  2120 	SmsPDU().EncodeMessagePDUL(gsmSms, &encodeParams);
       
  2121 	aSmsArray.AppendL(gsmSms);
       
  2122 
       
  2123 	return ETrue;
       
  2124 	} // CSmsMessage::EncodeIntoSinglePDUL
       
  2125 
       
  2126 
       
  2127 /**
       
  2128  *  Attempts to encode into the single PDU
       
  2129  *  The Text and the EMS objects are layed out with respect to start position locations and encoded into the correct Tsms object.
       
  2130  *  Ensure this function is called before EncodeMessagePDUsL to properly process single PDU messages
       
  2131  *  
       
  2132  *  @return KErrUnderflow if the Ems objects are not in Start position order.
       
  2133  *  @param aSmsArray returned array of newly created TSms objects containing the encoded message
       
  2134  *  
       
  2135  *  @capability None
       
  2136  */
       
  2137 EXPORT_C TBool CSmsMessage::EncodeIntoSinglePDUL(CArrayFix<TGsmSms>& aSmsArray)
       
  2138 	{
       
  2139 	LOGGSMU1("CSmsMessage::EncodeIntoSinglePDUL()");
       
  2140 	
       
  2141 	TInt  unconvertedChars, downgradedChars, freeUDUnitsInLastPDU;
       
  2142 	
       
  2143 	return EncodeIntoSinglePDUL(aSmsArray, unconvertedChars,
       
  2144                                 downgradedChars, freeUDUnitsInLastPDU);
       
  2145 	} // CSmsMessage::EncodeIntoSinglePDUL
       
  2146 
       
  2147 
       
  2148 void CSmsMessage::EncodingTPSRRFromSchemesIntoSinglePDUL()
       
  2149 	{
       
  2150 	TInt smscIndex(0);
       
  2151 	TBool smscPresent(EFalse);
       
  2152 	
       
  2153 	CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = iAdditionalInfo->GetStatusReportScheme();	
       
  2154 	if(scheme.Id() == EControlParametersScheme)
       
  2155 		{
       
  2156 		if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
       
  2157 			{
       
  2158 			smscPresent=ETrue;
       
  2159 			}
       
  2160 		if(smscPresent)				
       
  2161 			{
       
  2162 			TUint8 octet(0);
       
  2163 
       
  2164 			CSmsSMSCCtrlParameterOperations& ieOp = (CSmsSMSCCtrlParameterOperations&)GetOperationsForIEL(CSmsInformationElement::ESmsIEISMSCControlParameters);
       
  2165 			
       
  2166 			if (ieOp.GetStatusReport(0, octet) == KErrNone)
       
  2167 				{
       
  2168 				if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
       
  2169 					{
       
  2170 					SmsPDU().UserData().InformationElement(smscIndex).Data()[0] = octet;
       
  2171 					if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
       
  2172 						{
       
  2173 						((CSmsSubmit&)SmsPDU()).SetStatusReportRequest(ETrue);	
       
  2174 						}
       
  2175 					else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
       
  2176 						{
       
  2177 						((CSmsDeliver&)SmsPDU()).SetStatusReportIndication(ETrue);
       
  2178 						}
       
  2179 					}
       
  2180 				else
       
  2181 					{
       
  2182 					User::Leave(KErrCorrupt);	
       
  2183 					}	
       
  2184 				}
       
  2185 			}
       
  2186 		else
       
  2187 			{
       
  2188 			User::Leave(KErrNotFound);
       
  2189 			}	
       
  2190 		}
       
  2191 	else if(scheme.Id() == ETPSRRScheme)
       
  2192 		{
       
  2193 		TSmsFirstOctet smsReportRequest;
       
  2194 		CSmsTPSRROperations& nonIEOp = (CSmsTPSRROperations&)GetOperationsForNonIEL(ESmsTPSRRParameter);
       
  2195 		smsReportRequest = nonIEOp.GetStatusReport(0);
       
  2196 		
       
  2197 		if(smsReportRequest>=0)
       
  2198 			{
       
  2199 			if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
       
  2200 				{
       
  2201 				((CSmsSubmit&)SmsPDU()).SetStatusReportRequest(smsReportRequest);	
       
  2202 				}
       
  2203 			else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
       
  2204 				{
       
  2205 				((CSmsDeliver&)SmsPDU()).SetStatusReportIndication(smsReportRequest);
       
  2206 				}	
       
  2207 			}
       
  2208 		}	
       
  2209 	} // CSmsMessage::EncodingTPSRRFromSchemesIntoSinglePDUL
       
  2210 
       
  2211 
       
  2212 /**
       
  2213  *  Decode CSmsMessage
       
  2214  *  
       
  2215  *  @param aUserData Object containing the EMS objects.
       
  2216  *  @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
       
  2217  *  of the UserData.
       
  2218  */
       
  2219 void CSmsMessage::DecodeBufferL(CArrayPtr<CSmsPDU>& aSmsPDUArray,
       
  2220 								CSmsBufferBase& aBuffer)
       
  2221 	{
       
  2222 	LOGGSMU1("CSmsMessage::DecodeBufferL()");
       
  2223 
       
  2224 	iInformationElementArray->ResetAndDestroy();
       
  2225 
       
  2226 	TSmsStatusReportScheme schemeId = FindSchemeL(aSmsPDUArray);
       
  2227 	
       
  2228 	TInt emailLen(0);
       
  2229 	for (TInt i=0; i<aSmsPDUArray.Count(); i++)
       
  2230 		{
       
  2231 		CSmsUserData& usrData = (aSmsPDUArray)[i]->UserData();
       
  2232 		InstallControlInformationElementsL(usrData, i);
       
  2233 		InstallEmsInformationElementsL(usrData, aBuffer.Length());
       
  2234         // Possible refactoring opportunity:
       
  2235         // This would be a good place to add a method which provides processing for control information
       
  2236         // elements which contain values specific to the pdu (as opposed to being constant in every PDU.
       
  2237         InstallEmailHeaderInformationElementL(usrData,emailLen);
       
  2238         if(schemeId == ETPSRRScheme)
       
  2239         	{
       
  2240         	InstallTPSRRInformationL(aSmsPDUArray, i);
       
  2241         	}
       
  2242         
       
  2243 		CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,aSmsPDUArray[i]->Alphabet(),BinaryData());
       
  2244 		TSmsBufferReassembler reassembler(*converter,aBuffer);
       
  2245         TSmsEncoding  encodingUsedInSegment = aSmsPDUArray[i]->NationalLanguageEncoding();
       
  2246 		
       
  2247         reassembler.ReassembleNextL(usrData.Body(),
       
  2248 									encodingUsedInSegment,
       
  2249 									i==(aSmsPDUArray.Count()-1));
       
  2250         
       
  2251 		CleanupStack::PopAndDestroy(converter);		
       
  2252 		MergeAlternative7bitEncoding(encodingUsedInSegment);
       
  2253 		}
       
  2254 
       
  2255     // Possible refactoring opportunity:
       
  2256     // This would be a good place to add a method which provides processing for control information
       
  2257     // elements which contain values specific to the pdu (as opposed to being constant in every PDU.
       
  2258     if(emailLen>0)
       
  2259 		{
       
  2260 		if(emailLen>255)
       
  2261 			User::Leave(KErrTooBig);
       
  2262 		TBuf8<1> data;
       
  2263 		data.SetLength(1);
       
  2264 		data[0]=static_cast<TUint8>(emailLen);
       
  2265 		TInt emailIndex;
       
  2266 		if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEIRFC822EmailHeader,emailIndex))
       
  2267 			SmsPDU().UserData().InformationElement(emailIndex).Data()[0]=static_cast<TInt8>(emailLen);
       
  2268 		else
       
  2269 			SmsPDU().UserData().AddInformationElementL(CSmsInformationElement::ESmsIEIRFC822EmailHeader,data);
       
  2270 		}
       
  2271 	UpdateUserPromptAndODIElementsStartPosition();
       
  2272 	} // CSmsMessage::DecodeBufferL
       
  2273 
       
  2274 /**
       
  2275  *  It decodes only raw text data.
       
  2276  *  
       
  2277  *  @param aSmsPDUArray Object containing PDUs.
       
  2278  *  @param aBuffer where the decoded data will be stored.
       
  2279  *
       
  2280  */
       
  2281 void CSmsMessage::DecodeOnlyTextL(CArrayPtr<CSmsPDU>& aSmsPDUArray,
       
  2282 								CSmsBufferBase& aBuffer)
       
  2283 	{
       
  2284 	LOGGSMU1("CSmsMessage::DecodeOnlyTextL()");
       
  2285 
       
  2286 	for (TInt i=0; i<aSmsPDUArray.Count(); i++)
       
  2287 		{
       
  2288         CSmsAlphabetConverter* converter=CSmsAlphabetConverter::NewLC(*iCharacterSetConverter,iFs,aSmsPDUArray[i]->Alphabet(),BinaryData());
       
  2289         TSmsBufferReassembler reassembler(*converter,aBuffer);
       
  2290 		TSmsEncoding  encodingUsedInSegment = aSmsPDUArray[i]->NationalLanguageEncoding();
       
  2291         
       
  2292 		reassembler.ReassembleNextL(aSmsPDUArray[i]->UserData().Body(),
       
  2293 									encodingUsedInSegment,
       
  2294 									i==(aSmsPDUArray.Count()-1));
       
  2295 		
       
  2296 		CleanupStack::PopAndDestroy(converter);
       
  2297 		MergeAlternative7bitEncoding(encodingUsedInSegment);
       
  2298 		}
       
  2299 	} // CSmsMessage::DecodeBufferL
       
  2300 
       
  2301 /**
       
  2302  *  It adds the incomplete message info in additional attribute field.
       
  2303  *  
       
  2304  *  @param aStartPDU starting PDU index of incomplete message.
       
  2305  *  @param aEndPDU end PDU index of incomplete message.
       
  2306  *  @param aLastPartialCompleteMsg boolean value indicating whether 
       
  2307  				this message is the last incomplete message sent to client.
       
  2308  */
       
  2309 void CSmsMessage::AddIncompleteMessageInfoL(TInt aStartPDU, TInt aEndPDU, TBool aLastPartialCompleteMsg)
       
  2310 	{
       
  2311 	LOGGSMU1("CSmsMessage::AddIncompleteMessageInfoL()");
       
  2312 
       
  2313 	CIncompleteClass0MessageInfo& incompleteClass0MsgInfo = (CIncompleteClass0MessageInfo&) iAdditionalInfo->GetNonIEOperationL(ESmsIncompleteClass0MessageParameter);
       
  2314 	incompleteClass0MsgInfo.SetVersion(CIncompleteClass0MessageInfo::ESmsIncompleteClass0MessageV0);
       
  2315 	incompleteClass0MsgInfo.SetIncompleteMessageInfoL(aStartPDU, aEndPDU, aLastPartialCompleteMsg);
       
  2316 	}
       
  2317 
       
  2318 /**
       
  2319  *  This method copies control information elements from the user data (passed as an
       
  2320  *  input argument) into either the CSmsMessage's user data (working pdu) OR one of the
       
  2321  *  collection of control information elements (sorted by category) which is contained
       
  2322  *  in CSmsMessage::iAdditionalInfo.
       
  2323  *  
       
  2324  *  @param aUserData
       
  2325  *  The user data which is currently being processed, and whose elements may be copied
       
  2326  *  into the appropriate collection belonging to the CSmsMessage.
       
  2327  *  @leave
       
  2328  *  KErrArgument if an information element's type is unknown
       
  2329  *  
       
  2330  *  @internalComponent
       
  2331  */
       
  2332 void CSmsMessage::InstallControlInformationElementsL(CSmsUserData& aUserData, TInt aSegmentSequenceNum)
       
  2333     {
       
  2334 	// Installs all the information elements within the subsequent PDUs.
       
  2335 	LOGGSMU1("CSmsMessage::InstallControlInformationElements()");
       
  2336 
       
  2337     CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = iAdditionalInfo->GetStatusReportScheme();
       
  2338     
       
  2339 	for (TInt z=0; z<aUserData.NumInformationElements(); z++)
       
  2340 		{
       
  2341 		const CSmsInformationElement& ie = aUserData.InformationElement(z);
       
  2342 
       
  2343          TSmsInformationElementCategories::TInformationElementCategory category;
       
  2344 
       
  2345         if (TSmsInformationElementCategories::GetCategoryDefinition(ie.Identifier(), category))
       
  2346         	{
       
  2347             switch (category)
       
  2348                 {
       
  2349                 case  TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUMultipleInstancesPerPDU: // e.g. Special SMS Message Indication
       
  2350                     LOGGSMU2("CSmsMessage::InstallControlInformationElements \
       
  2351                     ECtrlMandatoryInEveryPDUMultipleInstancesPerPDU id = %d", ie.Identifier());
       
  2352 
       
  2353                     if (ie.Identifier()== CSmsInformationElement::ESmsIEISpecialSMSMessageIndication)
       
  2354                         {
       
  2355                         TBool found = EFalse;
       
  2356                         CArrayFixFlat<TInt>* indices = new(ELeave) CArrayFixFlat<TInt>(4);
       
  2357                         CleanupStack::PushL(indices);
       
  2358                         SmsPDU().UserData().InformationElementIndicesL(ie.Identifier(), *indices);
       
  2359 
       
  2360                         TInt count = indices->Count();
       
  2361 		                for (TInt i=0; ((i<count) && (found==EFalse)); i++)
       
  2362 		                    {
       
  2363 		                    TUint index = indices->operator[](i);
       
  2364 		                    CSmsInformationElement& ieAlreadyInWorkingPDU = SmsPDU().UserData().InformationElement(index);
       
  2365 
       
  2366                             if (ieAlreadyInWorkingPDU.Data()[0] == ie.Data()[0])
       
  2367                                 {
       
  2368                                 ieAlreadyInWorkingPDU.Data()[1] = ie.Data()[1];
       
  2369                                 found = ETrue;
       
  2370                                 break;
       
  2371                                 }
       
  2372 		                    }
       
  2373                         CleanupStack::PopAndDestroy(indices);
       
  2374 
       
  2375                         if (found == EFalse)
       
  2376                             {
       
  2377                             SmsPDU().UserData().UpdateInformationElementArrayL(ie.Identifier(),ie.Data());
       
  2378                             }
       
  2379                         }
       
  2380                     else
       
  2381                         {
       
  2382                         // Unknown category.
       
  2383                         LOGGSMU3("CSmsMessage::InstallControlInformationElementsL category = %d, id = %d", category, ie.Identifier());
       
  2384                         User::Leave(KErrArgument);
       
  2385                         }
       
  2386                     break;
       
  2387                 case  TSmsInformationElementCategories::ECtrlMandatoryIn1stPDUOnly:
       
  2388                 case  TSmsInformationElementCategories::ECtrlSingleInstanceOnly:
       
  2389                     {
       
  2390                     LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryIn1stPDUOnly "
       
  2391                                  "ECtrlSingleInstanceOnly, id = %d", ie.Identifier());
       
  2392 
       
  2393                     TUint index = 0;
       
  2394                     if (iAdditionalInfo->Find1stInstanceOfControlInformationElement(ie.Identifier(), index))
       
  2395                         {
       
  2396                         iAdditionalInfo->DeleteControlInformationElement(category, index); //  might want to pass the
       
  2397                                                                                                 //  id in as an additional check
       
  2398                                                                                                 //  this should be an exception case
       
  2399                         CSmsInformationElement* newInformationElement = CSmsInformationElement::NewL(ie.Identifier(),ie.Data());
       
  2400 
       
  2401                     	CleanupStack::PushL(newInformationElement);
       
  2402                     	iAdditionalInfo->AddControlInformationElementL(category, newInformationElement);
       
  2403                         CleanupStack::Pop(newInformationElement);
       
  2404                         }
       
  2405                      else
       
  2406                         {
       
  2407                         CSmsInformationElement* cloneInformationElement = CSmsInformationElement::NewL(ie.Identifier(),ie.Data());
       
  2408                         CleanupStack::PushL(cloneInformationElement);
       
  2409                         iAdditionalInfo->AddControlInformationElementL(category, cloneInformationElement);
       
  2410                         CleanupStack::Pop(cloneInformationElement);
       
  2411                         }
       
  2412                     break;
       
  2413                     }
       
  2414                 case  TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUAndWithIdenticalValues:
       
  2415                     {
       
  2416                     LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryInEveryPDUAndWithIdenticalValues "
       
  2417                                  "ECtrlSingleInstanceOnly, id = %d", ie.Identifier());
       
  2418                     TInt index = 0;
       
  2419                     if (SmsPDU().UserData().InformationElementIndex(ie.Identifier(),index))
       
  2420                         {
       
  2421                         CSmsInformationElement* newInformationElement = CSmsInformationElement::NewL(ie.Identifier(),ie.Data());
       
  2422 
       
  2423                     	CleanupStack::PushL(newInformationElement);
       
  2424                         CSmsInformationElement*& indexedPDU = SmsPDU().UserData().InformationElementPtr(index);
       
  2425                         CSmsInformationElement* oldInformationElement = indexedPDU;
       
  2426                         SmsPDU().UserData().InformationElementPtr(index) = newInformationElement;
       
  2427 						// In next loop, oldInformationElement will point to the newly created information element. So double free is no case.
       
  2428 						// coverity[double_free]
       
  2429                         delete oldInformationElement;
       
  2430                         CleanupStack::Pop(newInformationElement);
       
  2431                         }
       
  2432                     else
       
  2433                         {
       
  2434                         SmsPDU().UserData().UpdateInformationElementArrayL(ie.Identifier(),ie.Data());
       
  2435                         }
       
  2436                     break;
       
  2437                     }
       
  2438 
       
  2439                 case  TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed:
       
  2440                     {
       
  2441                     LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryInEveryPDUAndWithIdenticalValues "
       
  2442                                  "ECtrlSingleInstanceOnly, id = %d", ie.Identifier() );
       
  2443 
       
  2444                     CSmsInformationElement* cloneInformationElement = CSmsInformationElement::NewL( ie.Identifier(),ie.Data() );
       
  2445                     CleanupStack::PushL(cloneInformationElement);
       
  2446                     iAdditionalInfo->AddControlInformationElementL( TSmsInformationElementCategories::ECtrlMultipleInstancesAllowed, cloneInformationElement);
       
  2447                     CleanupStack::Pop(cloneInformationElement);
       
  2448                     break;
       
  2449                     }
       
  2450                 case  TSmsInformationElementCategories::ECtrlMandatoryInEveryPDUButWithValueSpecificToPDU:
       
  2451                     LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryInEveryPDUButWithValueSpecificToPDU "
       
  2452                                  "ECtrlSingleInstanceOnly, id = %d", ie.Identifier() );
       
  2453                     
       
  2454                     if (ie.Identifier() == CSmsInformationElement::ESmsIEISMSCControlParameters)
       
  2455                     	{
       
  2456                        	if(scheme.Id() == EControlParametersScheme)
       
  2457                     		{
       
  2458                     		CSmsMessageAdditionalAttributes::CControlParametersScheme& ctrlParamScheme = (CSmsMessageAdditionalAttributes::CControlParametersScheme&)scheme;
       
  2459                     		ctrlParamScheme.iDefaultStatusReport = 0x00;
       
  2460                     		
       
  2461 	                       	const TUint8* octet(0);
       
  2462 	                    	octet = ie.Data().Ptr();
       
  2463 	                    	if(*octet)
       
  2464                     			{
       
  2465                     			CSmsMessageAdditionalAttributes::CControlParametersScheme::TSmsSMSCCtrlParameterStatus smscCtrlParameterStatus;
       
  2466 								smscCtrlParameterStatus.iSegmentSequenceNum = aSegmentSequenceNum;
       
  2467 								smscCtrlParameterStatus.iSelectiveStatus = *octet;
       
  2468 								(ctrlParamScheme.iControlParametersStatusReport).AppendL(smscCtrlParameterStatus);
       
  2469                     			}
       
  2470                     		ctrlParamScheme.iNumOfPDUs++;
       
  2471 	                    	}
       
  2472 	                    }
       
  2473                 
       
  2474                     // e.g  Email Header / Concatenation Elements.
       
  2475                     // Consider whether EMail Header should be ported here.
       
  2476                     // or left as is.
       
  2477                     break;
       
  2478                 case  TSmsInformationElementCategories::EEmsInformationElement:
       
  2479                     LOGGSMU2("CSmsMessage::InstallControlInformationElements ECtrlMandatoryInEveryPDUButWithValueSpecificToPDU "
       
  2480                                  "ECtrlSingleInstanceOnly, id = %d", ie.Identifier() );
       
  2481                     // Will be handled in the method InstallEmsInformationElements, nothing to do here
       
  2482                     break;
       
  2483                 default:
       
  2484                     LOGGSMU3("CSmsMessage::InstallControlInformationElementsToMultiSegmentMessageL, default switch, category = %d, id= %d", category, ie.Identifier() );
       
  2485                     break;
       
  2486                 }
       
  2487             }
       
  2488     	}
       
  2489     } // CSmsMessage::InstallControlInformationElementsL
       
  2490 
       
  2491 
       
  2492 /**
       
  2493  *  Extracts all the EMS information objects out of the given UserData into the CSmsMessage IEArray.
       
  2494  *  
       
  2495  *  @param aUserData Object containing the EMS objects.
       
  2496  *  @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
       
  2497  *  of the UserData.
       
  2498  */
       
  2499 void  CSmsMessage::InstallEmsInformationElementsL(CSmsUserData& aUserData, TInt aCharsAlreadyAdded)
       
  2500 	{
       
  2501 	// Installs all the information elements within the subsequent PDUs.
       
  2502 	LOGGSMU1("CSmsMessage::InstallEmsInformationElements()");
       
  2503 
       
  2504 	CSmsInformationElement::TSmsInformationElementIdentifier id;
       
  2505 	CEmsInformationElement* newIE =NULL;
       
  2506 
       
  2507 	for (TInt z=0; z<aUserData.NumInformationElements(); z++)
       
  2508 		{
       
  2509 		const CSmsInformationElement& ie = aUserData.InformationElement(z);
       
  2510 
       
  2511 		// is the ie an EMS information Element;
       
  2512 		id = ie.Identifier();
       
  2513 		if (CEmsFactory::Supported(id))
       
  2514 			{
       
  2515 			newIE=NULL;
       
  2516 			TRAPD(ret,newIE = CEmsFactory::CreateReceivedEmsIEL(ie,aCharsAlreadyAdded));
       
  2517 			if(newIE != NULL)
       
  2518 				{
       
  2519 				if(ret == KErrNone)
       
  2520 					{
       
  2521 					ret=AddReceivedEmsInformationElement(newIE);
       
  2522 					if(ret==KErrNone)  // Remove the Information Element from the User Data.
       
  2523 						aUserData.RemoveInformationElement(z--);
       
  2524 					else
       
  2525 						// newIE is made NULL in first place and then a new IE is created. so double free is no case
       
  2526 						// coverity[double_free]
       
  2527 						delete newIE;
       
  2528 					}
       
  2529 				else
       
  2530 					delete newIE;
       
  2531 				}
       
  2532 			}
       
  2533 		}
       
  2534 	} // CSmsMessage::InstallEmsInformationElementsL
       
  2535 
       
  2536 
       
  2537 /**
       
  2538  *  Extracts all the EMS information objects out of the given Command into the CSmsMessage IEArray.
       
  2539  *  
       
  2540  *  @param aCommand Object containing the EMS objects.
       
  2541  *  @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
       
  2542  *  of the UserData.
       
  2543  */
       
  2544 void  CSmsMessage::InstallEmsInformationElementsL(CSmsCommand& aCommand, TInt aCharsAlreadyAdded)
       
  2545     {
       
  2546     // Ignore in code coverage - not used in SMS stack and not exported
       
  2547     // but cannot be removed as impacts public header.
       
  2548     BULLSEYE_OFF    
       
  2549     // Installs all the information elements within the subsequent PDUs.
       
  2550     LOGGSMU1("CSmsMessage::InstallEmsInformationElements()");
       
  2551     
       
  2552     CSmsInformationElement::TSmsInformationElementIdentifier id;
       
  2553     CEmsInformationElement* newIE=NULL;
       
  2554     
       
  2555     for (TInt z=0; z<aCommand.NumInformationElements(); z++)
       
  2556         {
       
  2557         const CSmsInformationElement& ie = aCommand.InformationElement(z);
       
  2558         // is the ie an EMS information Element;
       
  2559         id = ie.Identifier();
       
  2560         if (CEmsFactory::Supported(id))
       
  2561             {
       
  2562             newIE=NULL;
       
  2563             TRAPD(ret,newIE = CEmsFactory::CreateReceivedEmsIEL(ie,aCharsAlreadyAdded));
       
  2564             if(newIE != NULL )
       
  2565                 {
       
  2566                     if(ret == KErrNone)
       
  2567                     {
       
  2568                         ret=AddReceivedEmsInformationElement(newIE);
       
  2569                         if(ret==KErrNone)  // Remove the Information Element from the User Data.
       
  2570                             aCommand.RemoveInformationElement(z--);
       
  2571                         else
       
  2572                             // newIE is made NULL in first place and then a new IE is created. so double free is no case.
       
  2573                             // coverity[double_free]
       
  2574                             delete newIE;
       
  2575                     }
       
  2576                     else
       
  2577                         delete newIE;
       
  2578                 }
       
  2579             }
       
  2580         }
       
  2581     BULLSEYE_RESTORE
       
  2582     }
       
  2583 
       
  2584 TSmsStatusReportScheme CSmsMessage::FindSchemeL(const CArrayPtr<CSmsPDU>& aSmsPDUArray)
       
  2585 	{
       
  2586 	TInt smscIndex(0);
       
  2587 	
       
  2588 	if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEISMSCControlParameters,smscIndex))
       
  2589 		{
       
  2590 		iAdditionalInfo->SetStatusReportSchemeL(EControlParametersScheme);
       
  2591 		return EControlParametersScheme;
       
  2592 		}
       
  2593 		
       
  2594 	TSmsFirstOctet oldTpsrr;
       
  2595 	TSmsFirstOctet tpsrr;
       
  2596 	CSmsSubmit* smsSubmit;
       
  2597 	CSmsDeliver* smsDeliver;
       
  2598 	
       
  2599 	if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
       
  2600 		{
       
  2601 		smsSubmit = reinterpret_cast<CSmsSubmit*>((aSmsPDUArray)[0]);
       
  2602 		oldTpsrr = smsSubmit->StatusReportRequest();
       
  2603 		}
       
  2604 	else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
       
  2605 		{
       
  2606 		smsDeliver = reinterpret_cast<CSmsDeliver*>((aSmsPDUArray)[0]);
       
  2607 		oldTpsrr = smsDeliver->StatusReportIndication();
       
  2608 		}
       
  2609 		
       
  2610 	for (TInt ii=1; ii<aSmsPDUArray.Count(); ii++)
       
  2611 		{
       
  2612 		if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
       
  2613 			{
       
  2614 			smsSubmit = reinterpret_cast<CSmsSubmit*>((aSmsPDUArray)[ii]);
       
  2615 			tpsrr = smsSubmit->StatusReportRequest();
       
  2616 			}
       
  2617 		else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
       
  2618 			{
       
  2619 			smsDeliver = reinterpret_cast<CSmsDeliver*>((aSmsPDUArray)[ii]);
       
  2620 			tpsrr = smsDeliver->StatusReportIndication();
       
  2621 			}
       
  2622 		if(tpsrr != oldTpsrr)
       
  2623 			{
       
  2624 			iAdditionalInfo->SetStatusReportSchemeL(ETPSRRScheme);
       
  2625 			return ETPSRRScheme;
       
  2626 			}
       
  2627 		}
       
  2628 	
       
  2629 	iAdditionalInfo->SetStatusReportSchemeL(EDefaultScheme);
       
  2630 
       
  2631 	return EDefaultScheme;
       
  2632 	} // CSmsMessage::FindSchemeL
       
  2633 
       
  2634 	
       
  2635 void CSmsMessage::InstallTPSRRInformationL(const CArrayPtr<CSmsPDU>& aSmsPDUArray, TInt aSegmentSequenceNum)
       
  2636 	{
       
  2637     CSmsMessageAdditionalAttributes::CSmsStatusReportScheme& scheme = iAdditionalInfo->GetStatusReportScheme();
       
  2638     CSmsMessageAdditionalAttributes::CTPSRRScheme& tpsrrScheme = (CSmsMessageAdditionalAttributes::CTPSRRScheme&)scheme;
       
  2639     
       
  2640     tpsrrScheme.iDefaultStatusReport = TSmsFirstOctet::ESmsStatusReportNotRequested;
       
  2641     tpsrrScheme.iNumOfPDUs++;
       
  2642     
       
  2643     TSmsFirstOctet tpsrr;
       
  2644     
       
  2645     if (SmsPDU().Type() == CSmsPDU::ESmsSubmit)
       
  2646 		{
       
  2647 		CSmsSubmit* smsSubmit = reinterpret_cast<CSmsSubmit*>((aSmsPDUArray)[aSegmentSequenceNum]);
       
  2648 		tpsrr = smsSubmit->StatusReportRequest();
       
  2649 		}
       
  2650 	else if (SmsPDU().Type() == CSmsPDU::ESmsDeliver)
       
  2651 		{
       
  2652 		CSmsDeliver* smsDeliver = reinterpret_cast<CSmsDeliver*>((aSmsPDUArray)[aSegmentSequenceNum]);
       
  2653 		tpsrr = smsDeliver->StatusReportIndication();
       
  2654 		}
       
  2655     
       
  2656     if(tpsrr)
       
  2657     	{
       
  2658     	CSmsMessageAdditionalAttributes::CTPSRRScheme::TSmsTPSRRStatus tpsrrStatus;
       
  2659 
       
  2660     	tpsrrStatus.iSegmentSequenceNum = aSegmentSequenceNum;
       
  2661 		tpsrrStatus.iTPSRRStatus = TSmsFirstOctet::ESmsStatusReportRequested;
       
  2662 		tpsrrScheme.iTPSRRStatusReport.AppendL(tpsrrStatus);	
       
  2663     	}
       
  2664 	} // CSmsMessage::InstallTPSRRInformationL
       
  2665 
       
  2666 
       
  2667 /**
       
  2668  *  Adds EMS IE to a CSmsMessage
       
  2669  *  
       
  2670  *  @param aEmsIE EMS object to be added.
       
  2671  *  
       
  2672  *  @capability None
       
  2673  */
       
  2674 EXPORT_C void CSmsMessage::AddEMSInformationElementL(const CEmsInformationElement& aEmsIE)
       
  2675 	{
       
  2676 	LOGGSMU1("CSmsMessage::AddEMSInformationElementL()");
       
  2677 
       
  2678 	if(aEmsIE.StartPosition() > (TUint)iBuffer->Length())
       
  2679 		{
       
  2680 		User::Leave(KErrOverflow);
       
  2681 		}
       
  2682 
       
  2683 	if(CSmsInformationElement::ESmsEnhancedTextFormatting == aEmsIE.Identifier() && aEmsIE.Length() ==0)
       
  2684 		{
       
  2685 		User::Leave(KErrUnderflow);
       
  2686 		}
       
  2687 
       
  2688 	if(CSmsInformationElement::ESmsEnhancedUserPromptIndicator == aEmsIE.Identifier())
       
  2689 		{
       
  2690 		AddEmsUserPromptL(static_cast<const CEmsUserPrompt&>(aEmsIE));
       
  2691 		}
       
  2692 	else if(CSmsInformationElement::ESmsEnhancedODI == aEmsIE.Identifier())
       
  2693 		{
       
  2694 		AddEmsObjectDistributionL(static_cast<const CEmsObjectDistribution&>(aEmsIE));
       
  2695 		}
       
  2696 	else
       
  2697 		{
       
  2698 		TInt count=iInformationElementArray->Count();
       
  2699 		TInt currNo=0;
       
  2700 		const CEmsInformationElement* emsIE=NULL;
       
  2701 
       
  2702 		while(currNo < count)
       
  2703 		{
       
  2704 			emsIE=(*iInformationElementArray)[currNo];
       
  2705 			if(emsIE->StartPosition() == aEmsIE.StartPosition() && (CSmsInformationElement::ESmsEnhancedUserPromptIndicator == emsIE->Identifier() || CSmsInformationElement::ESmsEnhancedODI == emsIE->Identifier()))
       
  2706 				User::Leave(KErrArgument);
       
  2707 			else if(emsIE->StartPosition() > aEmsIE.StartPosition())
       
  2708 				break;
       
  2709 			currNo++;
       
  2710 		}
       
  2711 		User::LeaveIfError(iInformationElementArray->Insert(aEmsIE.DuplicateL(),currNo));
       
  2712 		}
       
  2713 	} // CSmsMessage::AddEMSInformationElementL
       
  2714 
       
  2715 
       
  2716 TBool CSmsMessage::CanBeRemoved(const CEmsInformationElement& aIE, const TUint aIEIndex)
       
  2717 	{
       
  2718 	LOGGSMU1("CSmsMessage::CanBeRemoved()");
       
  2719 
       
  2720 	TBool ret=ETrue;
       
  2721 	if(CSmsInformationElement::ESmsEnhancedODI == aIE.Identifier())
       
  2722 		return ret;
       
  2723 
       
  2724 	TUint ieStartPosition=aIE.StartPosition();
       
  2725 	TUint count=iInformationElementArray->Count();
       
  2726 	CEmsInformationElement* ie=NULL;
       
  2727 
       
  2728 	// is there a UserPrompt/ODI at the same position
       
  2729 	for (TUint i=0; i < count && ret; ++i)
       
  2730 		{
       
  2731 		ie = (*iInformationElementArray)[i];
       
  2732 		// Do not allow removal if start position matches a user prompt and it is not the user prompt itself being removed
       
  2733 		if (ie->StartPosition() == ieStartPosition && ie->Identifier() == CSmsInformationElement::ESmsEnhancedUserPromptIndicator && aIE.Identifier() != CSmsInformationElement::ESmsEnhancedUserPromptIndicator)
       
  2734 		    ret=EFalse;
       
  2735 		if (ie->Identifier() == CSmsInformationElement::ESmsEnhancedODI)
       
  2736 		    {
       
  2737 		    // don't allow removal of IE if position inside object count of ODI
       
  2738 		    if ((static_cast<CEmsObjectDistribution*>(ie)->ObjectCount()+i) >= aIEIndex || static_cast<CEmsObjectDistribution*>(ie)->ObjectCount() == 0)
       
  2739 		        ret=EFalse;
       
  2740 		    }
       
  2741 		}
       
  2742 
       
  2743 	LOGGSMU2("CSmsMessage::CanBeRemoved() returns %d", ret);
       
  2744 
       
  2745 	return ret;
       
  2746 	} // CSmsMessage::CanBeRemoved
       
  2747 
       
  2748 
       
  2749 /**
       
  2750  *  Adds EMS IE to a CSmsMessage
       
  2751  *  
       
  2752  *  @param aEmsIE EMS object to be added.
       
  2753  */
       
  2754 void CSmsMessage::AddEmsUserPromptL(const CEmsUserPrompt& aUserPromptIE)
       
  2755 	{
       
  2756 	LOGGSMU1("CSmsMessage::AddEmsUserPromptL()");
       
  2757 
       
  2758 		if(aUserPromptIE.ObjectCount() == 0 )User::Leave(KErrArgument);
       
  2759 
       
  2760 		TUint count=iInformationElementArray->Count();
       
  2761 		TUint userPromptStartPosition=aUserPromptIE.StartPosition();
       
  2762 
       
  2763 		TSmsId id=aUserPromptIE.Identifier();
       
  2764 		TBool allSameType=ETrue;
       
  2765 		TUint countOnTheSamePos=0;
       
  2766 		TUint firstIndex=0;
       
  2767 
       
  2768 		// collect all IEs on the same startPosition as the new User Prompt
       
  2769 		CEmsInformationElement* ie=NULL;
       
  2770 
       
  2771 		for (TUint i=0; i < count ; i++)
       
  2772 		{
       
  2773 			ie = (*iInformationElementArray)[i];
       
  2774 			if (ie->StartPosition() == userPromptStartPosition)
       
  2775 			{
       
  2776 				if(countOnTheSamePos==0)
       
  2777 				{
       
  2778 					firstIndex=i;
       
  2779 					id = ie->Identifier();
       
  2780 				}
       
  2781 				else
       
  2782 				{
       
  2783 					if(allSameType && id != ie->Identifier())allSameType=EFalse;
       
  2784 					else id = ie->Identifier();
       
  2785 				}
       
  2786 				++countOnTheSamePos;
       
  2787 			}
       
  2788 		}
       
  2789 
       
  2790 		if(countOnTheSamePos != aUserPromptIE.ObjectCount())
       
  2791 			User::Leave(KErrArgument);
       
  2792 
       
  2793 
       
  2794 	if( countOnTheSamePos == 1)
       
  2795 	{
       
  2796 		switch(id)
       
  2797 		{
       
  2798 		case CEmsInformationElement::ESmsEnhancedPredefinedAnimation:
       
  2799 		case CEmsInformationElement::ESmsEnhancedLargeAnimation :
       
  2800 		case CEmsInformationElement::ESmsEnhancedSmallAnimation	:
       
  2801 		case CEmsInformationElement::ESmsEnhancedUserDefinedSound:
       
  2802 		case CEmsInformationElement::ESmsEnhancedLargePicture:
       
  2803 		case CEmsInformationElement::ESmsEnhancedSmallPicture:
       
  2804 		case CEmsInformationElement::ESmsEnhancedVariablePicture:
       
  2805 		User::LeaveIfError(iInformationElementArray->Insert(aUserPromptIE.DuplicateL(),firstIndex));
       
  2806 			break;
       
  2807 		default:
       
  2808 		User::Leave(KErrCorrupt);
       
  2809 			break;
       
  2810 		}
       
  2811 		return;
       
  2812 	}
       
  2813 
       
  2814 	// stitching - more than one object
       
  2815 	if(allSameType  && (id == CEmsInformationElement::ESmsEnhancedUserDefinedSound || id == CEmsInformationElement::ESmsEnhancedLargePicture || id == CEmsInformationElement::ESmsEnhancedSmallPicture || id == CEmsInformationElement::ESmsEnhancedVariablePicture))
       
  2816 		{
       
  2817 		User::LeaveIfError(iInformationElementArray->Insert(aUserPromptIE.DuplicateL(),firstIndex));
       
  2818 		return;
       
  2819 		}
       
  2820 
       
  2821     //  not of the same type or not supported IE types
       
  2822 	User::Leave(KErrCorrupt);
       
  2823 	} // CSmsMessage::AddEmsUserPromptL
       
  2824 
       
  2825 
       
  2826 /**
       
  2827  *  Adds EMS IE to a CSmsMessage
       
  2828  *  
       
  2829  *  @param aEmsIE EMS object to be added.
       
  2830  */
       
  2831 void CSmsMessage::AddEmsObjectDistributionL(const CEmsObjectDistribution& aObjectDistributionIE)
       
  2832     {
       
  2833 	LOGGSMU1("CSmsMessage::AddEmsObjectDistributionL()");
       
  2834 
       
  2835     TUint count=iInformationElementArray->Count();
       
  2836     TUint objectDistributionStartPosition=aObjectDistributionIE.StartPosition();
       
  2837 
       
  2838     TBool firstIndexFound=EFalse;
       
  2839     TUint firstIndex=0;
       
  2840     TUint countOnSameOrSubsequentPos=0;
       
  2841 
       
  2842     // collect any IEs on the same or greater startPosition as the new Object Distribution Indicator
       
  2843     CEmsInformationElement* ie=NULL;
       
  2844 
       
  2845     for (TUint i=0; i < count; i++)
       
  2846         {
       
  2847         ie = (*iInformationElementArray)[i];
       
  2848         if (ie->StartPosition() >= objectDistributionStartPosition)
       
  2849             {
       
  2850             // Only set index if at least one IE found at desired start position
       
  2851             if (!firstIndexFound)
       
  2852                 {
       
  2853                 firstIndex=i;
       
  2854                 firstIndexFound=ETrue;
       
  2855                 }
       
  2856             ++countOnSameOrSubsequentPos;
       
  2857             }
       
  2858         }
       
  2859     // check number of IEs present for desired ObjectCount
       
  2860     if(countOnSameOrSubsequentPos < aObjectDistributionIE.ObjectCount())
       
  2861         User::Leave(KErrArgument);
       
  2862 
       
  2863     if (firstIndexFound)
       
  2864         {
       
  2865         User::LeaveIfError(iInformationElementArray->Insert(aObjectDistributionIE.DuplicateL(),firstIndex));
       
  2866         return;
       
  2867         }
       
  2868 
       
  2869     //  no valid IE for ODI to apply to
       
  2870     User::Leave(KErrCorrupt);
       
  2871     } // CSmsMessage::AddEmsObjectDistributionL
       
  2872 
       
  2873 
       
  2874 /**
       
  2875  *  Removes first EMS IE that matches the criteria from the CSmsMessage
       
  2876  *  
       
  2877  *  @param aStartPosition of a EMS object to be removed.
       
  2878  *  @param aEmsId type of a EMS object to be removed
       
  2879  *  @return pointer EMS information element
       
  2880  *  @capability
       
  2881  *  @capability None
       
  2882  */
       
  2883 EXPORT_C CEmsInformationElement* CSmsMessage::RemoveEMSInformationElementL(const TUint aStartPosition,const TSmsId aEmsId)
       
  2884 	{
       
  2885 	LOGGSMU1("CSmsMessage::RemoveEMSInformationElementL()");
       
  2886 
       
  2887 	CEmsInformationElement* emsIE=NULL;
       
  2888 	CEmsInformationElement* ie=NULL;
       
  2889 
       
  2890 	TUint count=iInformationElementArray->Count();
       
  2891 
       
  2892 	for (TInt i=--count; i >=0 ; --i)
       
  2893 		{
       
  2894 		ie = (*iInformationElementArray)[i];
       
  2895 		if (ie->StartPosition() == aStartPosition && ie->Identifier() == aEmsId)
       
  2896 			{
       
  2897 				if(CanBeRemoved(*ie, i))
       
  2898 				{
       
  2899 					iInformationElementArray->Remove(i);
       
  2900 					emsIE=ie;
       
  2901 				}
       
  2902 				else
       
  2903 					emsIE=NULL;
       
  2904 				break;
       
  2905 			}
       
  2906 
       
  2907 		}
       
  2908 	return emsIE;
       
  2909 	} // CSmsMessage::RemoveEMSInformationElementL
       
  2910 
       
  2911 
       
  2912 /**
       
  2913  *  Removes all EMS IEs that matches the criteria from the CSmsMessage
       
  2914  *  
       
  2915  *  @param aStartPosition of a EMS object to be removed.
       
  2916  *  @param aEmsId type of a EMS object to be removed
       
  2917  *  @return pointer to array of EMS IE
       
  2918  *  
       
  2919  *  @capability None
       
  2920  */
       
  2921 EXPORT_C RPointerArray<CEmsInformationElement>* CSmsMessage::RemoveEMSInformationElementsL(const TUint aStartPosition,const TSmsId aEmsId)
       
  2922 	{
       
  2923 	LOGGSMU1("CSmsMessage::RemoveEMSInformationElementsL()");
       
  2924 
       
  2925 	CEmsInformationElement* ie=NULL;
       
  2926 	RPointerArray<CEmsInformationElement>* selectedIEs = NULL;
       
  2927 	TUint count=iInformationElementArray->Count();
       
  2928 
       
  2929 	for (TInt i=--count; i >= 0 ; --i)
       
  2930 		{
       
  2931 		ie = (*iInformationElementArray)[i];
       
  2932 		if (ie->StartPosition() == aStartPosition && ie->Identifier() == aEmsId)
       
  2933 			{
       
  2934 				if(CanBeRemoved(*ie, i))
       
  2935 				{
       
  2936 					if(selectedIEs == NULL)selectedIEs=new (ELeave) RPointerArray<CEmsInformationElement>(8);
       
  2937 					iInformationElementArray->Remove(i);
       
  2938 					selectedIEs->Append(ie);
       
  2939 				}
       
  2940 			}
       
  2941 
       
  2942 		}
       
  2943 	return selectedIEs;
       
  2944 	} // CSmsMessage::RemoveEMSInformationElementsL
       
  2945 
       
  2946 /**
       
  2947  *  Resets EMS IE from a CSmsMessage
       
  2948  *  
       
  2949  *  
       
  2950  *  @capability None
       
  2951  */
       
  2952 EXPORT_C void  CSmsMessage::ResetEMSL()
       
  2953 	{
       
  2954 	LOGGSMU1("CSmsMessage::ResetEMSL()");
       
  2955 
       
  2956 	iInformationElementArray->ResetAndDestroy();
       
  2957 	} // CSmsMessage::ResetEMSL
       
  2958 
       
  2959 /**
       
  2960  *  Removes EMS IE from a CSmsMessage
       
  2961  *  
       
  2962  *  @return CArrayPtrFlat<const CEmsInformationElement>& of internal EMS array
       
  2963  *  
       
  2964  *  @capability None
       
  2965  */
       
  2966 EXPORT_C const RPointerArray<const CEmsInformationElement>& CSmsMessage::GetEMSInformationElementsL()const
       
  2967 	{
       
  2968 	LOGGSMU1("CSmsMessage::GetEMSInformationElementsL()");
       
  2969 
       
  2970 	 return (const RPointerArray<const CEmsInformationElement>&)(*iInformationElementArray);
       
  2971 	} // CSmsMessage::GetEMSInformationElementsL
       
  2972 
       
  2973 
       
  2974 void CSmsMessage::UpdateUserPromptAndODIElementsStartPosition()
       
  2975 	{
       
  2976 	LOGGSMU1("CSmsMessage::UpdateUserPromptAndODIElementsStartPosition()");
       
  2977 
       
  2978 		TUint num=iInformationElementArray->Count();
       
  2979 		TInt startPosition=-1;
       
  2980 		CEmsInformationElement* ie = NULL;
       
  2981 
       
  2982 
       
  2983 		// is the ie an EMS information Element;
       
  2984 
       
  2985 		for(TInt i=num-1;i >=0; --i)
       
  2986 		{
       
  2987 			ie = (*iInformationElementArray)[i];
       
  2988 			if(ie->Identifier() == CSmsInformationElement::ESmsEnhancedUserPromptIndicator || ie->Identifier() == CSmsInformationElement::ESmsEnhancedODI)
       
  2989 			{
       
  2990 				if(startPosition >=0)
       
  2991 					ie->SetStartPosition(startPosition);
       
  2992 				else
       
  2993 					iInformationElementArray->Remove(i);
       
  2994 			}
       
  2995 			else
       
  2996 				startPosition=ie->StartPosition();
       
  2997 
       
  2998 		}
       
  2999 	} // CSmsMessage::UpdateUserPromptAndODIElementsStartPosition
       
  3000 
       
  3001 
       
  3002 TInt CSmsMessage::AddReceivedEmsInformationElement(CEmsInformationElement* aEmsIE)
       
  3003 	{
       
  3004 	LOGGSMU1("CSmsMessage::AddReceivedEmsInformationElement()");
       
  3005 
       
  3006 	TInt ret=KErrNone;
       
  3007 	if(CSmsInformationElement::ESmsEnhancedUserPromptIndicator == aEmsIE->Identifier() || CSmsInformationElement::ESmsEnhancedODI == aEmsIE->Identifier())
       
  3008 		ret=iInformationElementArray->Append(aEmsIE);
       
  3009 	else
       
  3010 		{
       
  3011 			TInt count=iInformationElementArray->Count();
       
  3012 			TInt currNo=0;
       
  3013 			const CEmsInformationElement* emsIE=NULL;
       
  3014 			while(currNo < count)
       
  3015 			{
       
  3016 				emsIE=(*iInformationElementArray)[currNo];
       
  3017 				if(emsIE->StartPosition() > aEmsIE->StartPosition() && (CSmsInformationElement::ESmsEnhancedUserPromptIndicator != emsIE->Identifier() || CSmsInformationElement::ESmsEnhancedODI != emsIE->Identifier()))
       
  3018 					break;
       
  3019 				currNo++;
       
  3020 			}
       
  3021 			ret=iInformationElementArray->Insert(aEmsIE,currNo);
       
  3022 		}
       
  3023 	return ret;
       
  3024 	} // CSmsMessage::AddReceivedEmsInformationElement
       
  3025 
       
  3026 
       
  3027 /**
       
  3028  *  Updates the slot information for the given message as described in the supplied buffer
       
  3029  *  
       
  3030  *  @param aDesc buffer, layout: byte 0 store id, byte 1..n PDU slot indexes
       
  3031  *  @leave KErrArgument
       
  3032  *  
       
  3033  *  @capability None
       
  3034  */
       
  3035 EXPORT_C void CSmsMessage::UpdateSlotsL(TDesC8& aDesc)
       
  3036     {
       
  3037 	LOGGSMU1("CSmsMessage::UpdateSlotsL()");
       
  3038 
       
  3039     TGsmSmsSlotEntry newSlot;
       
  3040 
       
  3041     switch (aDesc[0])
       
  3042         {
       
  3043         case CSmsMessage::ESmsSIMStorage:
       
  3044             {
       
  3045             newSlot.iStore = KETelIccSmsStore;
       
  3046             break;
       
  3047             }
       
  3048         case CSmsMessage::ESmsPhoneStorage:
       
  3049             {
       
  3050             newSlot.iStore = KETelMeSmsStore;
       
  3051             break;
       
  3052             }
       
  3053         case CSmsMessage::ESmsCombinedStorage:
       
  3054             {
       
  3055             newSlot.iStore = KETelCombinedSmsStore;
       
  3056             break;
       
  3057             }
       
  3058         default:
       
  3059             User::Leave(KErrArgument);
       
  3060         }
       
  3061 
       
  3062     for (TInt index = 1; index < aDesc.Size(); index++)
       
  3063         {
       
  3064         newSlot.iIndex = aDesc[index]; // point to PDU indexes
       
  3065         iSlotArray.AppendL(newSlot);
       
  3066         }
       
  3067     } // CSmsMessage::UpdateSlotsL
       
  3068 
       
  3069 /**
       
  3070  *  Copy EMS elements to dest CSmsMessage
       
  3071  *  Uses CSmsMessage extended EMS API
       
  3072  *  Creates new CEmsInformationElement instance(s) and passes ownership to the dest CSmsMessage
       
  3073  *  
       
  3074  *  @return aToMessage  - Destination CSmsMessage
       
  3075  *  
       
  3076  *  @capability None
       
  3077  */
       
  3078 EXPORT_C void CSmsMessage::CopyEmsElementsL(CSmsMessage& aToMessage) const
       
  3079 	{
       
  3080 	LOGGSMU1("CSmsMessage::CopyEmsElementsL()");
       
  3081 
       
  3082 	// CSmsMessage extended EMS API method creates array of references to EMS elements in
       
  3083 	// the source message
       
  3084 	// Loop through the array copying each individual method using the CSmsMessage
       
  3085 	// and CEmsInformationElement API's
       
  3086 	CEmsInformationElement* dupl=NULL;
       
  3087 	aToMessage.ResetEMSL();
       
  3088 	for(TInt i = iInformationElementArray->Count()-1 ; i >=0; --i)
       
  3089 		{
       
  3090 		dupl = (*iInformationElementArray)[i]->DuplicateL();
       
  3091 		CleanupStack::PushL(dupl);
       
  3092 		aToMessage.AddEMSInformationElementL(*dupl);
       
  3093 		CleanupStack::PopAndDestroy(dupl);
       
  3094 		}
       
  3095 	} // CSmsMessage::CopyEmsElementsL
       
  3096 
       
  3097 /**
       
  3098  *  @capability None
       
  3099  */
       
  3100 EXPORT_C void CSmsMessage::AddSlotL(const TGsmSmsSlotEntry& aSlot)
       
  3101 	{
       
  3102 	LOGGSMU1("CSmsMessage::AddSlotL()");
       
  3103 
       
  3104 		TInt count = iSlotArray.Count();
       
  3105 		TInt i(0);
       
  3106 		TBool found(EFalse);
       
  3107 		while(!found && i<count)
       
  3108 		{
       
  3109 			if(aSlot.iIndex == iSlotArray[i].iIndex)found=ETrue;
       
  3110 			else ++i;
       
  3111 		}
       
  3112 		LOGGSMU3("CSmsMessage::AddSlotL current no in: %d, adds index %d", count,aSlot.iIndex );
       
  3113 		LOGGSMU3("found %d at position %d",found,i);
       
  3114 		iSlotArray.AppendL(aSlot);
       
  3115 	} // CSmsMessage::AddSlotL
       
  3116 
       
  3117 /**
       
  3118  *  @capability None
       
  3119  */
       
  3120 EXPORT_C TBool CSmsMessage::MatchSlots(const CArrayFixFlat<TGsmSmsSlotEntry>& aSlotArray)
       
  3121 	{
       
  3122 	LOGGSMU1("CSmsMessage::MatchSlots()");
       
  3123 
       
  3124 		TBool match = EFalse;
       
  3125 		TInt count = aSlotArray.Count();
       
  3126 		if(iSlotArray.Count() == count)
       
  3127 		{
       
  3128 			TInt i = 0;
       
  3129 			match = ETrue;
       
  3130 			while(match && i < count)
       
  3131 				{
       
  3132 				const TGsmSmsSlotEntry& newSlot=aSlotArray[i];
       
  3133 				const TGsmSmsSlotEntry& slot =iSlotArray[i];
       
  3134 				if ( ( slot.iIndex != newSlot.iIndex ) || ( slot.iStore != newSlot.iStore ) )
       
  3135 						match = EFalse;
       
  3136 				i++;
       
  3137 				}
       
  3138 
       
  3139 		}
       
  3140 		return match;
       
  3141 	} // CSmsMessage::MatchSlots
       
  3142 
       
  3143 /**
       
  3144  *  c'tor
       
  3145  *  @capability None
       
  3146  */
       
  3147 EXPORT_C TGsmSmsSlotEntry::TGsmSmsSlotEntry()
       
  3148 	{
       
  3149 	} // TGsmSmsSlotEntry::TGsmSmsSlotEntry
       
  3150 
       
  3151 /**
       
  3152  *  Internalize
       
  3153  *  
       
  3154  *  @param aStream For internalizing the data
       
  3155  */
       
  3156 void TGsmSmsSlotEntry::InternalizeL(RReadStream& aStream)
       
  3157 	{
       
  3158 	aStream >> iStore;
       
  3159 	iIndex=aStream.ReadInt32L();
       
  3160 	} // TGsmSmsSlotEntry::InternalizeL
       
  3161 
       
  3162 /**
       
  3163  *  Externalize
       
  3164  *  
       
  3165  *  @param aStream For Externalizing the data
       
  3166  */
       
  3167 void TGsmSmsSlotEntry::ExternalizeL(RWriteStream& aStream) const
       
  3168 	{
       
  3169 	aStream << iStore;
       
  3170 	aStream.WriteInt32L(iIndex);
       
  3171 	} // TGsmSmsSlotEntry::ExternalizeL
       
  3172 
       
  3173  /**
       
  3174   *  Extracts all RFC 822 Email header information objects out of the given UserData into the CSmsMessage's iSmsEmailHeaderLength.
       
  3175   *  
       
  3176   *  @param aUserData Object containing the EmailHeader information element.
       
  3177   *  @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
       
  3178   *  of the UserData.
       
  3179   */
       
  3180 void  CSmsMessage::InstallEmailHeaderInformationElementL(CSmsUserData& aUserData,TInt& aHeaderLength)
       
  3181  	{
       
  3182  	// Installs all the information elements within the subsequent PDUs.
       
  3183  	LOGGSMU1("CSmsMessage::InstallEmailHeaderInformationElementL()");
       
  3184 
       
  3185  	CSmsInformationElement::TSmsInformationElementIdentifier id;
       
  3186 
       
  3187  	for (TInt z=0; z<aUserData.NumInformationElements(); z++)
       
  3188  		{
       
  3189  		const CSmsInformationElement& ie = aUserData.InformationElement(z);
       
  3190  		id = (CSmsInformationElement::TSmsInformationElementIdentifier)ie.Identifier();
       
  3191  		if (id == CSmsInformationElement::ESmsIEIRFC822EmailHeader)
       
  3192  			{
       
  3193  				const TDesC8& des = ie.Data();
       
  3194  				aHeaderLength+=des[0];
       
  3195  			}
       
  3196  		}
       
  3197  	} // CSmsMessage::InstallEmailHeaderInformationElementL
       
  3198 
       
  3199 /**
       
  3200  *  Extracts all RFC 822 Email header information objects out of the given UserData into the CSmsMessage's iSmsEmailHeaderLength.
       
  3201  *  
       
  3202  *  @param aCommand Object containing the EmailHeader information element.
       
  3203  *  @param aCharsAlreadyAdded The current, running, start position to be applied to the objects taken out
       
  3204  *  of the UserData.
       
  3205  */
       
  3206 void CSmsMessage::InstallEmailHeaderInformationElementL(CSmsCommand& aCommand,TInt& aHeaderLength)
       
  3207     {
       
  3208     // Ignore in code coverage - not used in SMS stack and not exported
       
  3209     // but cannot be removed as impacts public header.
       
  3210     BULLSEYE_OFF    
       
  3211     // Installs all the information elements within the subsequent PDUs.
       
  3212     LOGGSMU1("CSmsMessage::InstallEmailHeaderInformationElementL()");
       
  3213     
       
  3214     CSmsInformationElement::TSmsInformationElementIdentifier id;
       
  3215     
       
  3216     for (TInt z=0; z<aCommand.NumInformationElements(); z++)
       
  3217         {
       
  3218         const CSmsInformationElement& ie = aCommand.InformationElement(z);
       
  3219         id = (CSmsInformationElement::TSmsInformationElementIdentifier)ie.Identifier();
       
  3220         if (id == CSmsInformationElement::ESmsIEIRFC822EmailHeader)
       
  3221             {
       
  3222             const TDesC8& des = ie.Data();
       
  3223             aHeaderLength+=des[0];
       
  3224             }
       
  3225         }
       
  3226     BULLSEYE_RESTORE
       
  3227     }
       
  3228 
       
  3229 // E-mail header methods
       
  3230 
       
  3231 /**
       
  3232  *  Adds a header to an email body
       
  3233  *  
       
  3234  *  @param aEMailBody The buffer to which the header gets appended
       
  3235  *  @param aEmailHeader The buffer which holds RFC 822 e-mail header
       
  3236  *  @publishedAll
       
  3237  *  @released
       
  3238  *  
       
  3239  *  @capability None
       
  3240  */
       
  3241 EXPORT_C void CSmsMessage::AddEmailHeaderL(const TDesC& aEmailHeader, const TDesC& aEmailBody)
       
  3242  	{
       
  3243  	LOGGSMU1("CSmsMessage::AddEmailHeaderL()");
       
  3244 
       
  3245  	if(IsEmailHeader())
       
  3246  		User::Leave(KErrAlreadyExists);
       
  3247 
       
  3248  	TInt len =aEmailHeader.Length();
       
  3249  	if(len <= 0)
       
  3250  		User::Leave(KErrCorrupt);
       
  3251 
       
  3252 	if(len >= 255 )
       
  3253  		User::Leave(KErrTooBig);
       
  3254 
       
  3255 
       
  3256 	if(SmsPDU().UserData().NumInformationElements())
       
  3257 		{
       
  3258 		TBool is16bit = EFalse;
       
  3259 		TBool concatenationIEPresent= SmsPDU().TextConcatenated( &is16bit );
       
  3260 		if(concatenationIEPresent)
       
  3261 			{
       
  3262 			if(SmsPDU().UserData().NumInformationElements() >=2) // something more than concat IE
       
  3263 				User::Leave(KErrAccessDenied);
       
  3264 			}
       
  3265 		else
       
  3266 			User::Leave(KErrAccessDenied);
       
  3267 		}
       
  3268 
       
  3269 
       
  3270 	TBuf8<1> data;
       
  3271 	data.SetLength(1);
       
  3272 	data[0]=static_cast<TUint8>(len);
       
  3273 	SmsPDU().UserData().AddInformationElementL(CSmsInformationElement::ESmsIEIRFC822EmailHeader,data);
       
  3274 
       
  3275  	iBuffer->Reset();
       
  3276  	iBuffer->InsertL(0,aEmailHeader);
       
  3277  	iBuffer->InsertL(iBuffer->Length(),aEmailBody);
       
  3278  	} // CSmsMessage::AddEmailHeaderL
       
  3279 
       
  3280  /**
       
  3281   *  Checks whether the SmsMessage contains an e-mail.
       
  3282   *  
       
  3283   *  @return ETrue if CSmsMessage contains e-mail ( e-mail header information element), otherwise EFalse
       
  3284   *  @publishedAll
       
  3285   *  @released
       
  3286   *  
       
  3287   *  @capability None
       
  3288   */
       
  3289 EXPORT_C TBool CSmsMessage::IsEmailHeader() const
       
  3290  	{
       
  3291  	LOGGSMU1("CSmsMessage::IsEmailHeader()");
       
  3292 
       
  3293 	TInt emailIndex;
       
  3294 	return SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEIRFC822EmailHeader,emailIndex);
       
  3295  	} // CSmsMessage::IsEmailHeader
       
  3296 
       
  3297  /**
       
  3298   *  Extracts e-mail header and body from the SmsMessage
       
  3299   *  
       
  3300   *  @return aEMailHeader The buffer containing the extracted email header
       
  3301   *  @return aEMailBody The buffer containing the extracted email body
       
  3302   *  @return ETrue if extraction of e-mail header and body succeeds
       
  3303   *  @publishedAll
       
  3304   *  @released
       
  3305   *  
       
  3306   *  @capability None
       
  3307   */
       
  3308 EXPORT_C TBool CSmsMessage::GetEmailHeaderL(HBufC** aEmailHeader,HBufC** aEmailBody)
       
  3309  	{
       
  3310  	LOGGSMU1("CSmsMessage::GetEmailHeaderL()");
       
  3311 
       
  3312  	if(IsEmailHeader())
       
  3313  		{
       
  3314  			TInt bufLen=iBuffer->Length();
       
  3315  			TInt emailHeaderLen(0);
       
  3316 			TInt emailIndex(0);
       
  3317 			if(SmsPDU().UserData().InformationElementIndex(CSmsInformationElement::ESmsIEIRFC822EmailHeader,emailIndex))
       
  3318 				emailHeaderLen=SmsPDU().UserData().InformationElement(emailIndex).Data()[0];
       
  3319 			else
       
  3320 				User::Leave(KErrCorrupt);
       
  3321 
       
  3322  			TInt emailBodyLen=bufLen-emailHeaderLen;
       
  3323 
       
  3324  			if(emailBodyLen<0)
       
  3325  				return EFalse;
       
  3326 
       
  3327  			*aEmailHeader=HBufC::NewL(emailHeaderLen);
       
  3328  			CleanupStack::PushL(*aEmailHeader);
       
  3329 
       
  3330  			*aEmailBody=HBufC::NewL(emailBodyLen);
       
  3331  			CleanupStack::PushL(*aEmailBody);
       
  3332 
       
  3333  			TPtr headerPtr((*aEmailHeader)->Des());
       
  3334  			iBuffer->Extract(headerPtr,0,emailHeaderLen);
       
  3335 
       
  3336  			TPtr bodyPtr((*aEmailBody)->Des());
       
  3337  			iBuffer->Extract(bodyPtr,emailHeaderLen,emailBodyLen);
       
  3338 
       
  3339  			CleanupStack::Pop(2);
       
  3340  			return ETrue;
       
  3341  		}
       
  3342  	return EFalse;
       
  3343  	} // CSmsMessage::GetEmailHeaderL
       
  3344 
       
  3345 
       
  3346  /**
       
  3347   *  Extracts the offset between universal time and local time in seconds.
       
  3348   *  If the value is > 0, local time is ahead of universal time.
       
  3349   *  If the value is < 0, local time is behind universal time.
       
  3350   *  
       
  3351   *  @return TTTimeIntervalSeconds The time zone offset in seconds.
       
  3352   *  @publishedAll
       
  3353   *  @capability None
       
  3354   */
       
  3355 EXPORT_C TTimeIntervalSeconds CSmsMessage::UTCOffset() const
       
  3356     {
       
  3357     LOGGSMU1("CSmsMessage::UTCOffset()");
       
  3358 
       
  3359     TUint timeZoneOffset = ((iFlags & ESmsUTCOffsetSecondGranularityMask) >> ESecondBitOffset);
       
  3360 
       
  3361     if (iFlags & ESmsUTCOffsetSignBit)
       
  3362         {
       
  3363         timeZoneOffset = -timeZoneOffset;
       
  3364         }
       
  3365 
       
  3366     return (TTimeIntervalSeconds(timeZoneOffset));
       
  3367     } // CSmsMessage::UTCOffset
       
  3368 
       
  3369 
       
  3370  /**
       
  3371   *  Sets the offset between universal time and local time in seconds.
       
  3372   *  If the value is > 0, local time is ahead of universal time.
       
  3373   *  If the value is < 0, local time is behind universal time.
       
  3374   *  The CSmsMessage Time Zone Offset has the range +/- 71100 seconds. This is same range as
       
  3375   *  the Service Centre Time Stamp Time Zone Offset as specified in 23.040 V4.4.0 Sect 9.2.3.11.
       
  3376   *  
       
  3377   *  @return True if input value was set successfully (in range), False otherwise
       
  3378   *  @publishedAll
       
  3379   *  @capability None
       
  3380   */
       
  3381 EXPORT_C TBool CSmsMessage::SetUTCOffset(const TTimeIntervalSeconds& aTimeOffset)
       
  3382     {
       
  3383     LOGGSMU1("CSmsMessage::SetUTCOffset()");
       
  3384 
       
  3385     TBool rc = ETrue;
       
  3386 
       
  3387     TInt timeOffset = aTimeOffset.Int();
       
  3388 
       
  3389     if ((timeOffset <=  EMaximumSeconds) &&
       
  3390         (timeOffset >= -EMaximumSeconds))
       
  3391         {
       
  3392         // Clear the timezone offset bits
       
  3393         iFlags &= (~(ESmsUTCOffsetSecondGranularityMask   |
       
  3394                      ESmsUTCOffsetSignBit));
       
  3395 
       
  3396         if (timeOffset < 0)
       
  3397             {
       
  3398             iFlags |= ESmsUTCOffsetSignBit;
       
  3399             timeOffset = -timeOffset;
       
  3400             }
       
  3401 
       
  3402         iFlags |= (timeOffset << ESecondBitOffset);
       
  3403         }
       
  3404     else
       
  3405         {
       
  3406         LOGGSMU2("CSmsMessage::SetUTCOffset offset [out of range] = %d",timeOffset);
       
  3407         rc = EFalse;
       
  3408         }
       
  3409 
       
  3410     return rc;
       
  3411 } // CSmsMessage::SetUTCOffset
       
  3412 
       
  3413 
       
  3414 /**
       
  3415  *  Returns the message version number.
       
  3416  *  @capability
       
  3417  */
       
  3418 EXPORT_C TInt CSmsMessage::Version()
       
  3419  	{
       
  3420  	LOGGSMU1("CSmsMessage::Version()");
       
  3421 
       
  3422  	return iVersion;
       
  3423  	} // CSmsMessage::Version
       
  3424 
       
  3425 
       
  3426 /**
       
  3427  *  @internalComponent
       
  3428  *  Validates and sets the message version number.
       
  3429  *  
       
  3430  *  @param aVersion version number to set.
       
  3431  *  @return KErrNone if aVersion is valid and successfully set, KErrArgument otherwise.
       
  3432  *  @capability None
       
  3433  */
       
  3434 EXPORT_C TInt CSmsMessage::SetVersion(TInt aVersion)
       
  3435 	{
       
  3436  	LOGGSMU2("CSmsMessage::SetVersion()", aVersion);
       
  3437 
       
  3438 	if((aVersion>=ESmsMessageV0) && (aVersion<=ESmsMessageV4))
       
  3439 		{
       
  3440 		iVersion=aVersion;
       
  3441 		return KErrNone;
       
  3442 		}
       
  3443 
       
  3444 	return KErrArgument;
       
  3445 	} // CSmsMessage::SetVersion
       
  3446 
       
  3447 
       
  3448 /**
       
  3449  *  @internalComponent
       
  3450  *  Internalises all object data except for the CSmsBufferBase and the message version.
       
  3451  *  
       
  3452  *  This is used when the buffer is stored elsewhere.
       
  3453  *  
       
  3454  *  @param aStream Stream to read from
       
  3455  *  @capability None
       
  3456  */
       
  3457 EXPORT_C void CSmsMessage::InternalizeWithoutBufferAndVersionL(RReadStream& aStream)
       
  3458 	{
       
  3459  	LOGGSMU1("CSmsMessage::InternalizeWithoutBufferAndVersionL()");
       
  3460 
       
  3461 	iFlags=aStream.ReadInt32L();
       
  3462 	iStatus=(NMobileSmsStore::TMobileSmsStoreStatus) aStream.ReadInt32L();
       
  3463 	iLogServerId=aStream.ReadInt32L();
       
  3464 	TInt64 time;
       
  3465 	aStream >> time;
       
  3466 	iTime=time;
       
  3467 
       
  3468 	CSmsPDU* smspdu=CSmsPDU::NewL(aStream,*iCharacterSetConverter,iFs);
       
  3469 	delete iSmsPDU;
       
  3470 	iSmsPDU=smspdu;
       
  3471 	iIs16BitConcatenation=aStream.ReadInt32L();
       
  3472 
       
  3473 	iInformationElementArray->ResetAndDestroy();
       
  3474 	CEmsFactory::InternalizeL(*iInformationElementArray, aStream);
       
  3475 
       
  3476 	TInt count=aStream.ReadInt32L();
       
  3477 	iSlotArray.Reset();
       
  3478 	TInt i=0;
       
  3479 	TGsmSmsSlotEntry newSlot;
       
  3480 	for (; i<count; i++)
       
  3481 		{
       
  3482 		newSlot.InternalizeL(aStream);
       
  3483 		AddSlotL(newSlot);
       
  3484 		}
       
  3485 	} // CSmsMessage::InternalizeWithoutBufferAndVersionL
       
  3486 
       
  3487 
       
  3488 /**
       
  3489  *  @internalComponent
       
  3490  *  Externalises all object data except for the CSmsBufferBase and the message version.
       
  3491  *  
       
  3492  *  This is used when the buffer is stored elsewhere.
       
  3493  *  
       
  3494  *  @param aStream Stream to write to
       
  3495  *  @capability None
       
  3496  */
       
  3497 EXPORT_C void CSmsMessage::ExternalizeWithoutBufferAndVersionL(RWriteStream& aStream) const
       
  3498 	{
       
  3499  	LOGGSMU1("CSmsMessage::ExternalizeWithoutBufferAndVersionL()");
       
  3500 
       
  3501 	aStream.WriteInt32L(iFlags);
       
  3502 	aStream.WriteInt32L(iStatus);
       
  3503 	aStream.WriteInt32L(iLogServerId);
       
  3504 	aStream << Time().Int64();
       
  3505 
       
  3506 	SmsPDU().ExternalizeL(aStream);
       
  3507 	aStream.WriteInt32L(iIs16BitConcatenation);
       
  3508 
       
  3509 	CEmsFactory::ExternalizeL(*iInformationElementArray, aStream);
       
  3510 	TInt count=iSlotArray.Count();
       
  3511 	aStream.WriteInt32L(count);
       
  3512 	TInt i=0;
       
  3513 	for (; i<count; i++)
       
  3514 		{
       
  3515 		iSlotArray[i].ExternalizeL(aStream);
       
  3516 		}
       
  3517 	} // CSmsMessage::ExternalizeWithoutBufferAndVersionL
       
  3518 
       
  3519 
       
  3520 /**
       
  3521  *  @internalComponent
       
  3522  *  Internalises the CSmsBufferBase.
       
  3523  *  
       
  3524  *  @param aStream Stream to read from
       
  3525  *  @capability None
       
  3526  */
       
  3527 EXPORT_C void CSmsMessage::InternalizeBufferL(RReadStream& aStream)
       
  3528 	{
       
  3529 	aStream >> *iBuffer;
       
  3530 	} // CSmsMessage::InternalizeBufferL
       
  3531 
       
  3532 
       
  3533 /**
       
  3534  *  @internalComponent
       
  3535  *  Externalises the CSmsBufferBase.
       
  3536  *  
       
  3537  *  @param aStream Stream to write to
       
  3538  *  @capability None
       
  3539  */
       
  3540 EXPORT_C void CSmsMessage::ExternalizeBufferL(RWriteStream& aStream) const
       
  3541 	{
       
  3542 	aStream << *iBuffer;
       
  3543 	} // CSmsMessage::ExternalizeBufferL
       
  3544 
       
  3545 
       
  3546 /**
       
  3547  *  @internalComponent
       
  3548  *  Internalises the message version.
       
  3549  *  
       
  3550  *  @param aStream Stream to read from
       
  3551  *  @capability None
       
  3552  */
       
  3553 EXPORT_C void CSmsMessage::InternalizeVersionL(RReadStream& aStream)
       
  3554 	{
       
  3555 	TInt32 versionNumber = ESmsMessageV0;
       
  3556 	TRAPD(err,versionNumber=aStream.ReadInt32L());
       
  3557 	if(err==KErrEof)
       
  3558 		{
       
  3559 		versionNumber=ESmsMessageV0;
       
  3560 		}
       
  3561 
       
  3562 	iVersion=static_cast<TSmsMessageVersion> (versionNumber);
       
  3563 	} // CSmsMessage::InternalizeVersionL
       
  3564 
       
  3565 
       
  3566 /**
       
  3567  *  @internalComponent
       
  3568  *  Externalises the message version.
       
  3569  *  
       
  3570  *  @param aStream Stream to write to
       
  3571  *  @capability None
       
  3572  */
       
  3573 EXPORT_C void CSmsMessage::ExternalizeVersionL(RWriteStream& aStream) const
       
  3574 	{
       
  3575 	aStream.WriteInt32L(iVersion);
       
  3576 	} // CSmsMessage::ExternalizeVersionL
       
  3577 
       
  3578 
       
  3579 /**
       
  3580  *  @publishedAll
       
  3581  *  
       
  3582  *  Returns a reference to a specialisation of the class CSmsIEOperation. Clients can use this sub-class
       
  3583  *  to access the attributes of a specific type of information element encapsulated inside the CSmsMessage.
       
  3584  *  The ownership to the CSmsIEOperation class belongs to the CSmsMessage. When the CSmsMessage is deleted,
       
  3585  *  the CSmsIEOperation will also be deleted and the reference will become stale.
       
  3586  *  
       
  3587  *  @param aId
       
  3588  *  Specifies the sub class of CSmsIEOperation required.
       
  3589  *  @leave KErrNotSupported
       
  3590  *  When there is not accessor class available for the specified type of information element.
       
  3591  *  @capability None
       
  3592  */
       
  3593 EXPORT_C CSmsIEOperation& CSmsMessage::GetOperationsForIEL(CSmsInformationElement::TSmsInformationElementIdentifier aId) const
       
  3594     {
       
  3595     LOGGSMU1("CSmsMessage::GetOperationsForIEL()");
       
  3596 
       
  3597     if (iVersion < CSmsMessage::ESmsMessageV1)
       
  3598         {
       
  3599         LOGGSMU2("CSmsMessage::GetOperationsForIEL, Operation not supported, Msg Version %d", iVersion);
       
  3600         User::Leave(KErrNotSupported);
       
  3601         }
       
  3602 
       
  3603     return iAdditionalInfo->GetIEOperationL(aId);
       
  3604     } // CSmsMessage::GetOperationsForIEL
       
  3605 
       
  3606 EXPORT_C CSmsNonIEOperation& CSmsMessage::GetOperationsForNonIEL(TSmsNonIEIdentifier aId) const
       
  3607 	{
       
  3608 	LOGGSMU1("CSmsMessage::GetOperationsForNonIEL");
       
  3609 
       
  3610 	if (iVersion < CSmsMessage::ESmsMessageV2)
       
  3611 		{
       
  3612 		LOGGSMU2("GetOperationsForNonIEL not supported, Msg Version %d", iVersion);
       
  3613 		User::Leave(KErrNotSupported);
       
  3614 		}
       
  3615 
       
  3616 	return iAdditionalInfo->GetNonIEOperationL(aId);
       
  3617 	} // CSmsMessage::GetOperationsForNonIEL
       
  3618 
       
  3619 
       
  3620 void CSmsMessage::CreateControlIEOperationsClassesL()
       
  3621     {
       
  3622  	LOGGSMU1("CSmsMessage::CreateControlIEOperationsClassesL()");
       
  3623 
       
  3624     CSmsIEOperation* iEOperation = NULL;
       
  3625 
       
  3626     iEOperation = CSmsIEOperation::NewL(CSmsInformationElement::ESmsHyperLinkFormat, *this,	*iCharacterSetConverter, iFs);
       
  3627     iAdditionalInfo->SetIEOperationL(iEOperation);
       
  3628 
       
  3629     iEOperation = CSmsIEOperation::NewL(CSmsInformationElement::ESmsReplyAddressFormat, *this,	*iCharacterSetConverter, iFs);
       
  3630     iAdditionalInfo->SetIEOperationL(iEOperation);
       
  3631 
       
  3632     iEOperation = CSmsIEOperation::NewL(CSmsInformationElement::ESmsEnhanceVoiceMailInformation, *this,	*iCharacterSetConverter, iFs);
       
  3633     iAdditionalInfo->SetIEOperationL(iEOperation);
       
  3634 
       
  3635     iEOperation = CSmsIEOperation::NewL(CSmsInformationElement::ESmsIEISpecialSMSMessageIndication, *this,	*iCharacterSetConverter, iFs);
       
  3636     iAdditionalInfo->SetIEOperationL(iEOperation);
       
  3637     
       
  3638     iEOperation = CSmsIEOperation::NewL( CSmsInformationElement::ESmsIEISMSCControlParameters, *this,	*iCharacterSetConverter, iFs);
       
  3639     iAdditionalInfo->SetIEOperationL(iEOperation);
       
  3640     } // CSmsMessage::CreateControlIEOperationsClassesL
       
  3641 
       
  3642     
       
  3643 void CSmsMessage::CreateControlNonIEOperationsClassesL()
       
  3644     {
       
  3645     CSmsNonIEOperation* nonIEOperation = NULL;
       
  3646 
       
  3647     nonIEOperation = CSmsNonIEOperation::NewL(ESmsTPSRRParameter, *this);
       
  3648     iAdditionalInfo->SetNonIEOperationL(nonIEOperation);
       
  3649 
       
  3650 	nonIEOperation = CSmsNonIEOperation::NewL(ESmsIncompleteClass0MessageParameter, *this);
       
  3651 	iAdditionalInfo->SetNonIEOperationL(nonIEOperation);
       
  3652 	} // CSmsMessage::CreateControlNonIEOperationsClassesL
       
  3653 
       
  3654 
       
  3655 /**
       
  3656  *  Gets the scheme of the status report.
       
  3657  *  
       
  3658  *  @return Staus Report Scheme 
       
  3659  */
       
  3660 EXPORT_C TSmsStatusReportScheme CSmsMessage::Scheme() const
       
  3661 	{
       
  3662 	return iAdditionalInfo->GetStatusReportScheme().Id();
       
  3663 	}
       
  3664 
       
  3665 /**
       
  3666  *  @publishedAll
       
  3667  *  
       
  3668  *  Used by the SMS Stack to indicate that when the message was decoded, it was determined
       
  3669  *  to be on the SIM. If the message's DCS byte is configured for automatic delete or the
       
  3670  *  PID is set to Type 0, the message may subsequently have been deleted from the SIM during
       
  3671  *  decoding in which case its storage status is unstored.
       
  3672  *  
       
  3673  *  @param aOnSim
       
  3674  *  Used to indicate that the message was on the SIM when it was decoded.
       
  3675  *  @capability None
       
  3676  */
       
  3677 EXPORT_C void  CSmsMessage::SetDecodedOnSIM(TBool aOnSim)
       
  3678     {
       
  3679  	LOGGSMU2("CSmsMessage::SetDecodedOnSIM(): %d", aOnSim);
       
  3680 
       
  3681     if (aOnSim)
       
  3682         {
       
  3683         iFlags = iFlags | EDecodedOnSimBit;
       
  3684         }
       
  3685     else
       
  3686         {
       
  3687         iFlags = iFlags & ~EDecodedOnSimBit;
       
  3688         }
       
  3689     } // CSmsMessage::SetDecodedOnSIM
       
  3690 
       
  3691 
       
  3692 /**
       
  3693  *  @publishedAll
       
  3694  *  
       
  3695  *  Used by the SMS Stack to indicate that when the message was decoded, it was determined
       
  3696  *  to be on the SIM. If the message's DCS byte is configured for automatic delete or the
       
  3697  *  PID is set to Type 0, the message may subsequently have been deleted from the SIM during
       
  3698  *  decoding in which case its storage status is unstored.
       
  3699  *  
       
  3700  *  @return
       
  3701  *  True if the message was on the SIM during decoding,
       
  3702  *  False otherwise.
       
  3703  *  @capability None
       
  3704  */
       
  3705 EXPORT_C TBool CSmsMessage::DecodedOnSim()
       
  3706     {
       
  3707     LOGGSMU1("CSmsMessage::DecodedOnSim()");
       
  3708 
       
  3709     if (iFlags & EDecodedOnSimBit)
       
  3710         {
       
  3711         return ETrue;
       
  3712         }
       
  3713     else
       
  3714         {
       
  3715         return EFalse;
       
  3716         }
       
  3717     } // CSmsMessage::DecodedOnSim
       
  3718 
       
  3719 
       
  3720 /**
       
  3721  *  @publishedAll
       
  3722  *  
       
  3723  *  Used by the SMS Stack to indicate that when the message was decoded, it was determined
       
  3724  *  that it should be forwarded to the client. The message will not be forwarded to the
       
  3725  *  client when the PID byte is set to type 0 (except by default for class 0 and class 2 messages).
       
  3726  *  
       
  3727  *  @param forward
       
  3728  *  Used to indicate that the message needs to be forwarded to clients.
       
  3729  *  @capability None
       
  3730  */
       
  3731 EXPORT_C void CSmsMessage::SetForwardToClient(TBool aForward)
       
  3732     {
       
  3733  	LOGGSMU2("CSmsMessage::SetForwardToClient(): %d", aForward);
       
  3734 
       
  3735     if (aForward)
       
  3736         {
       
  3737         iFlags = iFlags | EForwardToClientBit;
       
  3738         }
       
  3739     else
       
  3740         {
       
  3741         iFlags = iFlags & ~EForwardToClientBit;
       
  3742         }
       
  3743     } // CSmsMessage::SetForwardToClient
       
  3744 
       
  3745 
       
  3746 /**
       
  3747  *  @publishedAll
       
  3748  *  
       
  3749  *  Used by the SMS Stack to indicate that when the message was decoded, it was determined
       
  3750  *  that is should be forwarded to the client. The message will not be forwarded to the client
       
  3751  *  when the PID byte is set to type 0 (except by default for class 0 and class 2 messages).
       
  3752  *  
       
  3753  *  @return
       
  3754  *  True if the message is to be forwarded to clients
       
  3755  *  False otherwise.
       
  3756  *  @capability None
       
  3757  */
       
  3758 EXPORT_C TBool CSmsMessage::ForwardToClient()
       
  3759     {
       
  3760     LOGGSMU1("CSmsMessage::ForwardToClient()");
       
  3761 
       
  3762     if (iFlags & EForwardToClientBit)
       
  3763         {
       
  3764         return ETrue;
       
  3765         }
       
  3766     else
       
  3767         {
       
  3768         return EFalse;
       
  3769         }
       
  3770     } // CSmsMessage::ForwardToClient