messagingappbase/smsmtm/clientmtm/src/SMUTHDR.CPP
changeset 23 238255e8b033
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/messagingappbase/smsmtm/clientmtm/src/SMUTHDR.CPP	Fri Apr 16 14:56:15 2010 +0300
@@ -0,0 +1,1075 @@
+// Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <smuthdr.h>
+#include <csmsemailfields.h>
+#include <gsmuieoperations.h>
+
+#include <gsmumsg.h>
+#include <msvstore.h>	
+#include <cntdb.h>
+#include <gsmunonieoperations.h>
+#include <gsmuelem.h>
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS  
+#include <tmsvsmsentry.h>
+#endif
+
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+#include <msvrcpt.h> 
+#endif
+	
+const TUid KUidMsvSMSHeaderStream		= {0x10001834};
+const TInt16 KMsvSmsHeaderVersion		= 1;
+const TInt KSmcmRecipientsGranularity	= 8;
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+_LIT16(KComma, ",");
+_LIT16(KDelimiter, ";");
+#endif
+
+/** 
+Allocates and constructs a new CSmsHeader object.
+
+Use this function to create a new SMS-SUBMIT, SMS-COMMAND, SMS-DELIVER or 
+SMS-STATUS-REPORT type message.
+
+@param	aType
+The Protocol Data Unit (PDU) type for the SMS message.
+
+@param	aText
+The message text.
+
+@return
+A new CSmsHeader object.
+*/
+EXPORT_C CSmsHeader* CSmsHeader::NewL(CSmsPDU::TSmsPDUType aType, CEditableText& aText)
+	{
+	CSmsHeader* self = new(ELeave) CSmsHeader();
+	CleanupStack::PushL(self);
+	self->ConstructL(aType, aText);
+	CleanupStack::Pop(self);
+	return self;
+	}
+	
+/** 
+Allocates and constructs a new CSmsHeader object.
+
+Use this function to create a new SMS-SUBMIT, SMS-COMMAND, SMS-DELIVER or 
+SMS-STATUS-REPORT type message. This version uses a previously connected
+file server session handle.
+
+@param	aType
+The Protocol Data Unit (PDU) type for the SMS message.
+
+@param	aText
+The message text.
+
+@param aFs
+Handle to an open file server session. CSmsHeader will not close the file session.
+
+@return
+A new CSmsHeader object.
+*/
+EXPORT_C CSmsHeader* CSmsHeader::NewL(CSmsPDU::TSmsPDUType aType, CEditableText& aText, RFs& aFs)
+	{
+	CSmsHeader* self = new(ELeave) CSmsHeader();
+	CleanupStack::PushL(self);
+	self->ConstructL(aType, aText, aFs);
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/** 
+Allocates and constructs a new CSmsHeader object.
+
+Use this function to create a new SMS-DELIVER type message.
+
+@param	aMessage
+The SMS message encapsulation from the SMS stack.
+
+@return
+A new CSmsHeader object.
+*/
+EXPORT_C CSmsHeader* CSmsHeader::NewL(CSmsMessage* aMessage)
+	{
+	CSmsHeader* self = new(ELeave) CSmsHeader(aMessage);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+/**
+Destructor.
+*/
+EXPORT_C CSmsHeader::~CSmsHeader()
+	{
+	iRecipients.ResetAndDestroy();
+	delete iMessage;
+	delete iEmailFields;
+	if(iCloseFs)
+		{
+		iFs.Close();
+		}
+	}
+
+/** 
+Sets the SMS message settings for the message.
+
+This can only be used on SMS-SUBMIT, SMS-COMMAND, SMS-DELIVER or SMS-STATUS-REPORT
+type messages.
+
+NOTE - if this is an Email over SMS message then the PID of is not changed. The
+PID would have been set correctly when the email fields were set.
+
+@param	aSmsSettings
+The SMS message settings for the message
+
+@leave	KErrNotSupported
+The message PDU type was not supported, or the message conversion value was not
+supported.
+
+@panic	SMCM	0
+The message PDU is not supported (debug only).
+*/
+EXPORT_C void CSmsHeader::SetSmsSettingsL(const CSmsMessageSettings& aSmsSettings)
+	{
+	__ASSERT_DEBUG( (Type()==CSmsPDU::ESmsSubmit) || (Type()==CSmsPDU::ESmsDeliver) || (Type()==CSmsPDU::ESmsStatusReport) || (Type()==CSmsPDU::ESmsCommand), Panic(ESmutPanicUnsupportedMsgType)); 
+
+	switch(Type())
+		{
+		case(CSmsPDU::ESmsSubmit):
+			{
+			Submit().SetRejectDuplicates(aSmsSettings.RejectDuplicate());
+			Submit().SetReplyPath(aSmsSettings.ReplyPath());
+			
+			//Check if delivery report for the last segment only is required . 
+			if(aSmsSettings.LastSegmentDeliveryReport())
+				{
+				CSmsTPSRROperations& tpSRROperations = static_cast<CSmsTPSRROperations&>(iMessage->GetOperationsForNonIEL(ESmsTPSRRParameter));
+				tpSRROperations.SetSchemeL();
+				tpSRROperations.SetLastSegmentStatusReportL(ETrue);
+				}
+			else
+				{
+				Submit().SetStatusReportRequest(aSmsSettings.DeliveryReport());	
+				}
+			Submit().SetValidityPeriod(aSmsSettings.ValidityPeriod());
+			Submit().SetValidityPeriodFormat(aSmsSettings.ValidityPeriodFormat());
+			break;
+			}
+		case(CSmsPDU::ESmsCommand):
+			{
+			Command().SetStatusReportRequest(aSmsSettings.DeliveryReport());
+			break;
+			}
+		case(CSmsPDU::ESmsDeliver):
+		case(CSmsPDU::ESmsStatusReport):
+			break;
+		default:
+			{			
+			User::Leave(KErrNotSupported);
+			break;
+			}
+		};
+
+	if (Message().TextPresent())
+		SetCanConcatenate(aSmsSettings.CanConcatenate());
+
+	CSmsPDU& pdu=Message().SmsPDU();
+	if (pdu.DataCodingSchemePresent())
+		pdu.SetAlphabet(aSmsSettings.CharacterSet());
+	if (pdu.ProtocolIdentifierPresent() && iEmailFields->Length() == 0 )
+		{
+		// The email fields object for this message is empty - therefore the
+		// PID can be set. With a non-empty email fields object the PID would
+		// have been set for interworking with email and MUST not be changed.
+		pdu.SetPIDType(TSmsProtocolIdentifier::ESmsPIDTelematicInterworking);
+
+		// MessageConversion
+		switch(aSmsSettings.MessageConversion())
+			{
+			case(ESmsConvPIDNone):
+				{
+				pdu.SetTelematicDeviceIndicator(TSmsProtocolIdentifier::ESmsNoTelematicDevice);
+				break;
+				}
+			case ESmsConvFax:
+			case ESmsConvX400:
+			case ESmsConvPaging:
+			case ESmsConvMail:
+			case ESmsConvErmes:
+			case ESmsConvSpeech:
+				{
+				pdu.SetTelematicDeviceIndicator(TSmsProtocolIdentifier::ESmsTelematicDevice);
+				pdu.SetTelematicDeviceType((TSmsProtocolIdentifier::TSmsTelematicDeviceType) aSmsSettings.MessageConversion());
+				break;
+				}
+			default:
+				{
+				User::Leave(KErrNotSupported);
+				break;
+				}
+			}; 
+		}
+	}
+
+/** 
+Gets the SMS message settings for the message.
+
+This can only be used on SMS-SUBMIT type messages.
+
+@param	aSmsSettings
+The output argument with the SMS message settings.
+
+@leave	KErrNotSupoprted
+The Telematic Device type is not supported.
+
+@panic	SMCM	0
+The message PDU is not supported (debug only).
+*/
+EXPORT_C void CSmsHeader::GetSmsSettingsL(CSmsMessageSettings& aSmsSettings) const
+	{
+	__ASSERT_DEBUG( Type()==CSmsPDU::ESmsSubmit, Panic(ESmutPanicUnsupportedMsgType)); 
+	switch(Type())
+		{
+		case(CSmsPDU::ESmsSubmit):
+			{
+			aSmsSettings.SetRejectDuplicate(Submit().RejectDuplicates());
+			aSmsSettings.SetReplyPath(Submit().ReplyPath());
+			TSmsStatusReportScheme scheme = iMessage->Scheme();
+			if (scheme == ETPSRRScheme)	
+				{
+				aSmsSettings.SetLastSegmentDeliveryReport(ETrue);
+				}
+			else
+				{
+				aSmsSettings.SetDeliveryReport(Submit().StatusReportRequest());
+				}
+			aSmsSettings.SetValidityPeriod(Submit().ValidityPeriod());
+			aSmsSettings.SetValidityPeriodFormat(Submit().ValidityPeriodFormat());
+			aSmsSettings.SetCharacterSet(Submit().Alphabet());
+		
+			if (iMessage->SmsPDU().PIDType() == TSmsProtocolIdentifier::ESmsPIDTelematicInterworking)
+				{
+				if (iMessage->SmsPDU().TelematicDeviceIndicator() == TSmsProtocolIdentifier::ESmsNoTelematicDevice)
+					{
+					aSmsSettings.SetMessageConversion(ESmsConvPIDNone);
+					}
+				else //if (iMessage->SmsPDU().TelematicDeviceIndicator() == TSmsProtocolIdentifier::ESmsTelematicDevice)
+					{
+					switch (iMessage->SmsPDU().TelematicDeviceType())
+						{
+						case TSmsProtocolIdentifier::ESmsGroup3TeleFax:
+						case TSmsProtocolIdentifier::ESmsX400MessageHandlingSystem:
+						case TSmsProtocolIdentifier::ESmsNationalPagingSystem:
+						case TSmsProtocolIdentifier::ESmsInternetElectronicMail:
+						case TSmsProtocolIdentifier::ESmsERMES:
+						case TSmsProtocolIdentifier::ESmsVoiceTelephone:
+							aSmsSettings.SetMessageConversion((TSmsPIDConversion) iMessage->SmsPDU().TelematicDeviceType());
+							break;
+						default:
+							User::Leave(KErrNotSupported);
+							break;
+						}
+					}
+				}
+
+			aSmsSettings.SetCanConcatenate(CanConcatenate());
+			break;
+			}
+		default:
+			{
+			break;
+			}
+		}
+	}
+	
+/**
+Sets the email fields for the message.
+
+If the supplied email fields is not empty then the PID of the PDU of the message
+is set for interworking with email.
+
+If the supplied email fields is empty and the PID of the PDU of the message is 
+set for interworking with email then the PID is set to the default value that
+indicates no telematic device. If the PID was not set for interworking with 
+email then it is left unchanged.
+
+@param	aEmailFields
+The email fields object. A copy is made of this object.
+*/	
+EXPORT_C void CSmsHeader::SetEmailFieldsL(const CSmsEmailFields& aEmailFields)
+	{
+	__ASSERT_DEBUG( Type()==CSmsPDU::ESmsSubmit, Panic(ESmutPanicUnsupportedMsgType)); 
+
+	CSmsEmailFields* temp = CSmsEmailFields::NewL(aEmailFields);
+	delete iEmailFields;
+	iEmailFields = temp;
+	
+	CSmsPDU& pdu = Message().SmsPDU();
+	if( pdu.ProtocolIdentifierPresent() )
+		{
+		if( iEmailFields->Length() > 0 )
+			{
+			// Set the PID for interworking with email.
+			pdu.SetPIDType(TSmsProtocolIdentifier::ESmsPIDTelematicInterworking);
+			pdu.SetTelematicDeviceIndicator(TSmsProtocolIdentifier::ESmsTelematicDevice);
+			pdu.SetTelematicDeviceType(TSmsProtocolIdentifier::ESmsInternetElectronicMail);
+			}
+		else
+			{
+			// The email fields are empty - if the PID is set for interworking
+			// with email, set to indicate no telematic device.
+			if(	pdu.PIDType() == TSmsProtocolIdentifier::ESmsPIDTelematicInterworking &&
+				pdu.TelematicDeviceIndicator() == TSmsProtocolIdentifier::ESmsTelematicDevice &&
+				pdu.TelematicDeviceType() == TSmsProtocolIdentifier::ESmsInternetElectronicMail )
+				{
+				pdu.SetTelematicDeviceIndicator(TSmsProtocolIdentifier::ESmsNoTelematicDevice);
+				}
+			}
+		}
+	}
+	
+/**
+Sets the email fields for a reply message.
+
+The address field is copied from the specified email fields. The subject field 
+is formatted according to the specified subject format using the subject from 
+the specified email fields.
+
+The PID of the PDU of the message is set for interworking with email.
+
+@param	aEmailFields
+The email fields object.
+
+@param	aReplySubjectFormat
+The format of the subject field.
+
+@internalComponent
+*/
+void CSmsHeader::SetReplyEmailFieldsL(const CSmsEmailFields& aEmailFields, const TDesC& aReplySubjectFormat)
+	{
+	// Create the reply email fields - copy address and then format the subject,
+	// if one exists according to the reply prefix.
+	CSmsEmailFields* temp = CSmsEmailFields::NewL();
+	CleanupStack::PushL(temp);
+	temp->AddAddressL(aEmailFields.Addresses().MdcaPoint(0));
+	
+	SetEmailReplyForwardSubjectL(temp, aEmailFields.Subject(), aReplySubjectFormat);
+
+	CleanupStack::Pop(temp);
+	delete iEmailFields;
+	iEmailFields = temp;
+
+	// Set the PID for interworking with email.
+	CSmsPDU& pdu = Message().SmsPDU();
+	if( pdu.ProtocolIdentifierPresent() )
+		{
+		pdu.SetPIDType(TSmsProtocolIdentifier::ESmsPIDTelematicInterworking);
+		pdu.SetTelematicDeviceIndicator(TSmsProtocolIdentifier::ESmsTelematicDevice);
+		pdu.SetTelematicDeviceType(TSmsProtocolIdentifier::ESmsInternetElectronicMail);
+		}
+	}
+
+/**
+Sets the email fields for a forward message.
+
+The address field is left empty. The subject field is formatted according to the
+specified subject format using the subject from the specified email fields.
+
+The PID of the PDU of the message is set for interworking with email.
+
+@param	aEmailFields
+The email fields object.
+
+@param	aForwardSubjectFormat
+The format of the subject field.
+
+@internalComponent
+*/
+void CSmsHeader::SetForwardEmailFieldsL(const CSmsEmailFields& aEmailFields, const TDesC& aForwardSubjectFormat)
+	{
+	// Create the reply email fields - copy address and then format the subject,
+	// if one exists according to the reply prefix.
+	CSmsEmailFields* temp = CSmsEmailFields::NewL();
+	CleanupStack::PushL(temp);
+	
+	SetEmailReplyForwardSubjectL(temp, aEmailFields.Subject(), aForwardSubjectFormat);
+
+	CleanupStack::Pop(temp);
+	delete iEmailFields;
+	iEmailFields = temp;
+
+	// Set the PID for interworking with email.
+	CSmsPDU& pdu = Message().SmsPDU();
+	if( pdu.ProtocolIdentifierPresent() )
+		{
+		pdu.SetPIDType(TSmsProtocolIdentifier::ESmsPIDTelematicInterworking);
+		pdu.SetTelematicDeviceIndicator(TSmsProtocolIdentifier::ESmsTelematicDevice);
+		pdu.SetTelematicDeviceType(TSmsProtocolIdentifier::ESmsInternetElectronicMail);
+		}
+	}
+	
+void CSmsHeader::SetEmailReplyForwardSubjectL(CSmsEmailFields* aEmailFields, const TDesC& aSubject, const TDesC& aSubjectFormat)
+	{
+	TInt length = aSubject.Length();
+	if( length > 0 )
+		{
+		// Prevent a chain of the format string appearing in the subject - check
+		// to see if the format string is already the prefix of the subject.
+		TInt formatPosInSubject = KErrNotFound;
+
+		_LIT(KFormatStringSpecifier, "%S");
+		TInt formatPos = aSubjectFormat.Find(KFormatStringSpecifier);
+		if( formatPos > 0 )
+			{
+			// Look in current subject for the format string - avoid the '%'.
+			formatPosInSubject = aSubject.FindF(aSubjectFormat.Left(formatPos - 1));
+			}
+		
+		// Need to format the string if the format string is not at the start of
+		// the current subject.
+		if( formatPosInSubject != 0 )
+			{
+			// Create a buffer large enough to hold re-formated subject - need
+			// to subtract two from the prefix length (the %S).
+			length += aSubjectFormat.Length() - 2;
+			HBufC* buf = HBufC::NewLC(length);
+			TPtr ptr(buf->Des());
+			
+			// Format the reply subject and set in the email fields.
+			ptr.Format(aSubjectFormat, &aSubject);
+			aEmailFields->SetSubjectL(*buf);
+			
+			CleanupStack::PopAndDestroy(buf);
+			}
+		else
+			{
+			// Subject already contains the format string - use it.
+			aEmailFields->SetSubjectL(aSubject);
+			}
+		}
+	}
+	
+/**
+The email fields object for this message.
+
+@return
+The email fields object for this message.
+*/	
+EXPORT_C const CSmsEmailFields& CSmsHeader::EmailFields() const
+	{
+	return *iEmailFields;
+	}
+
+/** 
+Internalises the object from the specified stream.
+
+@param	aStream
+The stream to be read from.
+*/
+EXPORT_C void CSmsHeader::InternalizeL(RMsvReadStream& aStream)
+	{
+#if (!defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+
+	aStream.ReadInt16L(); //version. Not used yet
+	
+	iRecipients.ResetAndDestroy();
+	TInt count=aStream.ReadInt32L();
+	while(count--)
+		{
+		CSmsNumber* recipient=CSmsNumber::NewL();  
+		CleanupStack::PushL(recipient);
+		recipient->InternalizeL(aStream);
+		iRecipients.AppendL(recipient);
+		CleanupStack::Pop(recipient);
+		}
+
+	iFlags = aStream.ReadUint32L();
+	iBioMsgIdType = (TBioMsgIdType) aStream.ReadInt8L();
+	iMessage->InternalizeWithoutBufferL(aStream);
+#else
+	iMessage->InternalizeWithoutBufferL(aStream);
+#endif
+	}
+
+/**
+Externalises the object to the specified stream.
+
+@param	aStream
+The stream to be writen to.
+*/
+EXPORT_C void CSmsHeader::ExternalizeL(RMsvWriteStream& aStream) const
+	{
+#if (!defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+
+	aStream.WriteInt16L(KMsvSmsHeaderVersion);
+
+	TInt count=iRecipients.Count();
+	aStream.WriteInt32L(count);
+
+	for (TInt i=0; i<count; i++)
+		iRecipients[i]->ExternalizeL(aStream);
+
+	aStream.WriteUint32L(iFlags);
+	aStream.WriteInt8L(iBioMsgIdType);
+	iMessage->ExternalizeWithoutBufferL(aStream); 
+#else
+	iMessage->ExternalizeWithoutBufferL(aStream); 	
+#endif 	
+	}
+
+/**
+Restores the object from the message entry store.
+
+The SMS object is restored from the KUidMsvSMSHeaderStream in the supplied store.
+ 
+@param	aStore
+The store from which the object is restored.
+ 
+@leave	KErrNotFound
+The stream KUidMsvSMSHeaderStream does not exist in aStore.
+*/
+EXPORT_C void CSmsHeader::RestoreL(CMsvStore& aStore)
+	{
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+	ReStoreDBL(aStore);
+	RMsvReadStream in;
+	in.OpenLC(aStore,KUidMsvSMSHeaderStream);
+	InternalizeL(in);
+	CleanupStack::PopAndDestroy(&in);
+#else
+
+	RMsvReadStream in;
+	in.OpenLC(aStore,KUidMsvSMSHeaderStream);
+	InternalizeL(in);
+	CleanupStack::PopAndDestroy(&in);
+	
+	iEmailFields->RestoreL(aStore);
+	
+#endif 
+	}
+
+
+/**
+Stores the object in the message entry store.
+
+The object is written to the KUidMsvSMSHeaderStream stream. Any previous content
+is overwritten.
+
+@param	aStore
+The store to hold the stream into which the object is written.
+*/
+EXPORT_C void CSmsHeader::StoreL(CMsvStore& aStore) const
+	{
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+	StoreDbL(aStore);
+	RMsvWriteStream out;
+	out.AssignLC(aStore,KUidMsvSMSHeaderStream);
+	ExternalizeL(out);
+	out.CommitL();
+	CleanupStack::PopAndDestroy(&out);
+
+#else
+	RMsvWriteStream out;
+	out.AssignLC(aStore,KUidMsvSMSHeaderStream);
+	ExternalizeL(out);
+	out.CommitL();
+	CleanupStack::PopAndDestroy(&out);
+	
+	iEmailFields->StoreL(aStore);
+#endif
+	}
+
+
+/**
+Check  whether a CMsvStore contains an SMS header stream.
+
+@param aStore The store.
+@return ETrue if there is a   SMS header
+*/
+EXPORT_C TBool CSmsHeader::ContainsSmsHeaderL(const CMsvStore& aStore)
+    {
+    return aStore.IsPresentL(KUidMsvSMSHeaderStream);
+    }
+
+CSmsHeader::CSmsHeader(CSmsMessage* aSmsMessage)
+:	iRecipients(KSmcmRecipientsGranularity),
+	iMessage(aSmsMessage),
+	iFlags(ESmsHeaderNoFlags),
+	iBioMsgIdType(EBioMsgIdNbs),
+	iCloseFs(ETrue)
+	{
+	}
+
+void CSmsHeader::ConstructL(CSmsPDU::TSmsPDUType aType, CEditableText& aText)
+	{
+	User::LeaveIfError(iFs.Connect());
+	iMessage=CSmsMessage::NewL(iFs, aType, CSmsEditorBuffer::NewL(aText), EFalse);
+	iEmailFields = CSmsEmailFields::NewL();
+	}
+	
+void CSmsHeader::ConstructL(CSmsPDU::TSmsPDUType aType, CEditableText& aText, RFs& aFs)
+	{
+	iFs=aFs;
+	iCloseFs = EFalse;
+	iMessage=CSmsMessage::NewL(iFs, aType, CSmsEditorBuffer::NewL(aText), EFalse);
+	iEmailFields = CSmsEmailFields::NewL();
+	}
+
+void CSmsHeader::ConstructL()
+	{
+	iEmailFields = CSmsEmailFields::NewL();
+
+	// Check the PID of the SMS PDU to see if set for interworking with email.
+	CSmsPDU& pdu = Message().SmsPDU();
+	if( pdu.ProtocolIdentifierPresent() &&
+		pdu.PIDType() == TSmsProtocolIdentifier::ESmsPIDTelematicInterworking &&
+		pdu.TelematicDeviceIndicator() == TSmsProtocolIdentifier::ESmsTelematicDevice &&
+		pdu.TelematicDeviceType() == TSmsProtocolIdentifier::ESmsInternetElectronicMail )
+		{
+		__ASSERT_DEBUG( pdu.Type() == CSmsPDU::ESmsDeliver, User::Invariant() );
+		
+		// Ok, this is an email SMS - parse out the address and the optional 
+		// subject fields.
+		CSmsBufferBase& message = Message().Buffer();
+		TInt length = message.Length();
+		HBufC* buf = HBufC::NewLC(length);
+		TPtr bufPtr(buf->Des());
+		message.Extract(bufPtr, 0, length);
+		
+		TInt end = iEmailFields->ParseL(*buf);
+		
+		if( end > 0 )
+			{
+			TPtrC body((*buf).Mid(end));
+			message.Reset();
+			message.InsertL(0, body);
+			}
+		CleanupStack::PopAndDestroy(buf);
+		}
+	}
+
+void CSmsHeader::SetCanConcatenate(TBool aCanConcatenate)
+	{
+	iFlags = (iFlags & ~ESmsHeaderCanConcatenate) | (aCanConcatenate ? ESmsHeaderCanConcatenate : ESmsHeaderNoFlags);
+	}
+
+TBool CSmsHeader::CanConcatenate() const
+	{
+	return iFlags & ESmsHeaderCanConcatenate;
+	}
+
+/**
+Gets the summary information for the specified acknowledgement.
+
+If the specified acknowledgement is not recognised, then this function returns
+the default value of TMsvSmsEntryAckSummary::ENoAckSummary.
+nothing.
+
+@param
+aAckType	The requested acknowledgement summary.
+
+@return
+The acknowledgement summary information.
+
+@see
+TMsvSmsEntry::TMsvSmsEntryAckSummary
+*/
+EXPORT_C TMsvSmsEntry::TMsvSmsEntryAckSummary TMsvSmsEntry::AckSummary(TSmsAckType aAckType) const
+	{
+	TMsvSmsEntryAckSummary summary = ENoAckSummary;
+	switch( aAckType )
+		{
+	case ESmsAckTypeDelivery:
+		summary = static_cast<TMsvSmsEntryAckSummary>((iMtmData2 & EMsvSmsEntryDeliveryAckSummary) >> EMsvSmsEntryDeliveryAckSummaryShift);
+		break;
+	default:
+		// Use default summary - fail gracefully.
+		break;
+		}
+	return summary;
+	}
+
+/**
+Sets the summary information for the specified acknowlwdgement.
+
+If the specified acknowledgement is not recognised, then this function does
+nothing.
+
+@param
+aAckType	The acknowledgement summary to be set.
+
+@param
+aAckSummary	The summary information.
+
+@see
+TMsvSmsEntry::TMsvSmsEntryAckSummary
+*/
+EXPORT_C void TMsvSmsEntry::SetAckSummary(TSmsAckType aAckType, TMsvSmsEntryAckSummary aAckSummary)
+	{
+	switch( aAckType )
+		{
+	case ESmsAckTypeDelivery:
+		iMtmData2 = (iMtmData2 & ~EMsvSmsEntryDeliveryAckSummary) | ((aAckSummary << EMsvSmsEntryDeliveryAckSummaryShift) & EMsvSmsEntryDeliveryAckSummary);
+		break;
+	default:
+		// Do nothing - fail gracefully.
+		break;
+		}
+	}
+
+/**
+Gets the message log ID and a flag indicating if it is valid.
+
+The returned flag indicates whether the message log ID is valid. If it is valid
+then the message has only a single recipient that is pending a status report. In
+this case the returned message log ID refers to the recipient that is pending.
+
+If it is not valid then the message has more than one recipient that is pending 
+a status report. The message log ID should is not valid and should not be used.
+
+@param
+aMessageId	An output argument for the message log ID.
+
+@return
+A flag indicating whether the message log ID aMessageId is valid or not.
+*/
+EXPORT_C TBool TMsvSmsEntry::MessageId(TInt32& aMessageId) const
+	{
+	aMessageId = iMtmData3;
+	return iMtmData2 & EMsvSmsMessageValid;
+	}
+
+/**
+Sets the message log ID and a flag indicating if it is valid.
+
+If the message has only a single recipient that is pending a status report then
+the message log ID for that recipient can be set in the index. The flag must be
+set to true.
+
+If the message has more than one recipient that is pending a status report then
+the message log ID must not be used. The flag must be set to false.
+
+This functionality cannot be used with bio-messages. This function will panic if
+used with a bio-message.
+
+@param
+aMessageId	The message log ID. Should only be used if aIsValid is true. It has
+			a default value of zero.
+
+@param
+aIsValid	A flag indicating if the message log ID is valid. This should have
+			a value or true if the message has only a single recipient pending
+			a status report.
+			
+@panic	USER	0
+This message is a bio-message and therefore the message ID field cannot be used.
+*/
+EXPORT_C void TMsvSmsEntry::SetMessageId(TInt32 aMessageId, TBool aIsValid)
+	{
+	__ASSERT_ALWAYS( iBioType == 0, User::Invariant() );
+
+	aIsValid ? (iMtmData2 |= EMsvSmsMessageValid) : (iMtmData2 &= ~EMsvSmsMessageValid);
+	iMtmData3 = aMessageId;
+	}
+
+/** 
+Gets the reply to address if it exists, otherwise calls FromAddress().
+
+Only valid for SMS-DELIVER type messages. 
+@return
+The reply to address if it exists, otherwise the originator address as returned by FromAddress().
+*/	
+TPtrC CSmsHeader::ReplyAddressL() const
+	{
+	
+	if(Type()==CSmsPDU::ESmsDeliver)
+		{
+		//Check for a reply address field
+		CSmsReplyAddressOperations& operations = STATIC_CAST(CSmsReplyAddressOperations&,Message().GetOperationsForIEL(CSmsInformationElement::ESmsReplyAddressFormat));
+		if(!operations.ContainsReplyAddressIEL())
+			{
+			//if there is no reply to field call FromAddress()
+			return FromAddress();	
+			}	
+		//return the reply to address
+		HBufC* replyAddressHBuf=operations.GetReplyAddressL();
+		return replyAddressHBuf->Des();			
+		}	
+	else
+		{
+		return FromAddress();		
+		}
+	}
+
+#if (defined SYMBIAN_MESSAGESTORE_HEADER_BODY_USING_SQLDB)
+
+/**
+Stores the object in the message entry store in SQL DB.
+
+The object is written to the KUidMsvSMSHeaderStream stream. Any previous content
+is overwritten.
+
+@param	aStore
+The store to hold the stream into which the object is written.
+*/
+
+void CSmsHeader::StoreDbL(CMsvStore& aStore) const
+	{
+	_LIT(KDetails,"");
+	
+	CHeaderFields* smsHeaderFields = new(ELeave) CHeaderFields();
+	CleanupStack::PushL(smsHeaderFields);
+	smsHeaderFields->iUid = KUidMsvSMSHeaderStream;
+	
+	// 1. Header version field.
+	CFieldPair* smsHeaderVersionfield = new(ELeave) CFieldPair();
+	CleanupStack::PushL(smsHeaderVersionfield);
+	smsHeaderVersionfield->iFieldNumValue = KMsvSmsHeaderVersion;
+	smsHeaderFields->iFieldPairList.AppendL(smsHeaderVersionfield);
+	CleanupStack::Pop(smsHeaderVersionfield);
+	
+	// 2. Recipient count field.
+	CFieldPair* smsRecipientCountField = new(ELeave) CFieldPair();
+	CleanupStack::PushL(smsRecipientCountField);
+	smsRecipientCountField->iFieldNumValue = iRecipients.Count();
+	smsHeaderFields->iFieldPairList.AppendL(smsRecipientCountField);
+	CleanupStack::Pop(smsRecipientCountField);
+	
+	// 3. Recipients field.
+	TInt size = 0;	
+	for (TInt i=0; i < iRecipients.Count(); i++)
+		{
+		size += sizeof(CMsvRecipient::TRecipientStatus);
+		size += 16;		// CMsvRecipient::iError (4), iRetries(4) and iTime (8)
+		size += Align4(iRecipients[i]->Address().Size());	// CSmsNumber::iNumber
+		size += Align4(iRecipients[i]->Name().Size());		// CSmsNumber::iName
+		size += sizeof(TLogId);								// CSmsNumber::iLogId
+		size += sizeof(CSmsNumber::TSmsAckStatus);			// CSmsNumber::iDeliveryStatus
+		size += 10;											// For delimiters
+		}
+
+	RBuf recipients;
+	CleanupClosePushL(recipients);
+	recipients.CreateL(size);
+
+	for (TInt i=0; i<iRecipients.Count(); i++)
+		{		
+		recipients.AppendNum(iRecipients[i]->Status()); //0
+		recipients.Append(KComma);
+		recipients.AppendNum(iRecipients[i]->Error()); //1
+		recipients.Append(KComma);
+		recipients.AppendNum(iRecipients[i]->Retries()); //2
+		recipients.Append(KComma);
+		recipients.AppendNum(iRecipients[i]->Time().Int64()); //3
+		recipients.Append(KComma);
+	
+		recipients.Append(iRecipients[i]->Address()); //4
+		recipients.Append(KComma);
+		recipients.Append(iRecipients[i]->Name()); //5
+		recipients.Append(KComma);
+		recipients.AppendNum(iRecipients[i]->LogId()); //6
+		recipients.Append(KComma);
+		recipients.AppendNum(iRecipients[i]->AckStatus(ESmsAckTypeDelivery)); //7
+		recipients.Append(KDelimiter);
+		}
+		
+	CFieldPair* smsRecipientsField = new(ELeave) CFieldPair();
+	CleanupStack::PushL(smsRecipientsField);
+	smsRecipientsField->iFieldTextValue = recipients.AllocL();
+	smsHeaderFields->iFieldPairList.AppendL(smsRecipientsField);
+				
+	CleanupStack::Pop(smsRecipientsField);	// smsRecipientsField
+	CleanupStack::PopAndDestroy();			// recipients
+
+	// 4. SMS Flag
+	CFieldPair* smsSmsFlags = new(ELeave) CFieldPair();
+	CleanupStack::PushL(smsSmsFlags);
+	smsSmsFlags->iFieldNumValue = iFlags;
+	smsHeaderFields->iFieldPairList.AppendL(smsSmsFlags);
+	CleanupStack::Pop(smsSmsFlags);
+	
+	// 5. BIO Msg Id
+	CFieldPair* smsBioMsgIdType = new(ELeave) CFieldPair();
+	CleanupStack::PushL(smsBioMsgIdType);
+	smsBioMsgIdType->iFieldNumValue = iBioMsgIdType;
+	smsHeaderFields->iFieldPairList.AppendL(smsBioMsgIdType);
+	CleanupStack::Pop(smsBioMsgIdType);
+	
+			
+	CFieldPair* smsdetailField = new (ELeave)CFieldPair();
+	CleanupStack::PushL(smsdetailField);
+	smsdetailField->iFieldName =  KDetails().AllocL();
+	smsdetailField->iFieldType = ETextField;
+	smsdetailField->iFieldTextValue = KNullDesC().AllocL();
+	smsHeaderFields->iFieldPairList.AppendL(smsdetailField);
+	CleanupStack::Pop(smsdetailField);
+
+	TMsvWriteStore storeWriter(aStore);
+	storeWriter.AssignL(smsHeaderFields);
+	storeWriter.CommitL();
+	
+	CleanupStack::Pop(smsHeaderFields);
+	
+	// 6.  SMS-Email UID
+	// 7.  SMS-EMail HeaderVersion
+	// 8.  Subject
+	// 9.  AddressCount
+	// 10. Addresses
+
+	iEmailFields->StoreDBL(aStore);	
+	
+	}
+
+/**
+Restores the object from the message entry store in SQL DB.
+
+The SMS object is restored from the KUidMsvSMSHeaderStream in the supplied store.
+ 
+@param	aStore
+The store from which the object is restored.
+ 
+@leave	KErrNotFound
+The stream KUidMsvSMSHeaderStream does not exist in aStore.
+*/	
+	
+void CSmsHeader::ReStoreDBL(CMsvStore& aStore)	
+	{
+	
+	CHeaderFields* rcvHeaderRow = NULL;
+	TMsvReadStore storeReader(aStore, KUidMsvSMSHeaderStream);
+	storeReader.LoadL(rcvHeaderRow);
+
+	
+	iRecipients.ResetAndDestroy();
+	
+	TInt i = 0;
+	CFieldPair* rcvHeader = rcvHeaderRow->iFieldPairList[i];
+
+	TInt16 headerversion = rcvHeaderRow->iFieldPairList[i++]->iFieldNumValue; // header version.
+	TInt count = rcvHeaderRow->iFieldPairList[i++]->iFieldNumValue;
+	
+	HBufC* 	receipientList = rcvHeaderRow->iFieldPairList[i++]->iFieldTextValue->Des().AllocL();
+	CleanupStack::PushL(receipientList);
+	
+	TPtrC receipientListPtr = receipientList->Des();
+	GetRecipientL(receipientListPtr);
+
+	iFlags  = rcvHeaderRow->iFieldPairList[i++]->iFieldNumValue;
+	iBioMsgIdType = (TBioMsgIdType)rcvHeaderRow->iFieldPairList[i++]->iFieldNumValue ;
+
+	CleanupStack::PopAndDestroy(receipientList);
+	
+	iEmailFields->ReStoreDBL(aStore);
+	
+	}
+
+/**
+Get the recipient strring and Create the recipient.
+
+@param : aRecipientStr A TPtrC16.
+@return None.
+*/
+void CSmsHeader::GetRecipientL(TDesC16& aRecipientStrList)
+	{
+	TPtrC16 aRecipientStr = aRecipientStrList.Left(aRecipientStrList.Length());
+	
+	if(aRecipientStr.Length()>0)
+		{
+		RArray<TPtrC16> smsNumberData;
+		TInt startPos = 0;
+		TInt firstSemiColonPos = aRecipientStr.Locate(';');
+		TInt lastSemiColonPos = aRecipientStr.LocateReverse(';');
+				
+		do
+			{
+			CSmsNumber* recipientNumber=CSmsNumber::NewL();  
+			TPtrC16 str1 = aRecipientStr.Left(firstSemiColonPos+1); // First recipient
+			startPos = str1.Locate(',') ;
+			
+			while(startPos != KErrNotFound )
+				{
+				TPtrC16 str2 = str1.Left(startPos);
+				smsNumberData.Append(str2);
+				
+				startPos++;
+				str1.Set(str1.Mid(startPos, str1.Length()- startPos));
+			
+				startPos = str1.Locate(',');
+				if(startPos == KErrNotFound)
+					{
+					TPtrC16 str3;
+					str3.Set(str1.Mid(0,str1.Length()-1));
+					smsNumberData.Append(str3);
+					break;
+					}
+					
+				}
+		
+			recipientNumber->SetStatus((CMsvRecipient::TRecipientStatus)ConvertToTInt(smsNumberData[0]));
+			recipientNumber->SetError(ConvertToTInt(smsNumberData[1]));
+			recipientNumber->SetRetries(ConvertToTInt(smsNumberData[2]));
+			TInt64 time = ConvertToTInt(smsNumberData[3]);
+			recipientNumber->SetTimeValue(time);
+			
+			//CSmsNumber	
+			recipientNumber->SetAddressL(smsNumberData[4]);
+			recipientNumber->SetNameL(smsNumberData[5]);
+			
+			TLex logId(smsNumberData[6]);
+			TInt32 logIdNum;
+			logId.Val(logIdNum);
+			recipientNumber->SetLogId(logIdNum);	
+			
+			TLex ackStatus(smsNumberData[7]);
+			TInt32 ackStatusNum;
+			recipientNumber->SetAckStatus( (TSmsAckType) ackStatus.Val(ackStatusNum), CSmsNumber::ENoAckRequested);
+				
+			iRecipients.AppendL(recipientNumber);
+			smsNumberData.Reset();
+			
+			if(firstSemiColonPos != lastSemiColonPos)
+				{
+				aRecipientStr.Set(aRecipientStr.Mid(firstSemiColonPos+1,aRecipientStr.Length()-firstSemiColonPos-1));
+				firstSemiColonPos = aRecipientStr.Locate(';');
+				lastSemiColonPos = aRecipientStr.LocateReverse(';');
+				}
+			else	
+				{
+				break;	
+				}
+								
+			}while(1);
+		
+		smsNumberData.Close();				
+		}		
+	}
+
+
+/**
+ * Convert a String to an Integer.
+ * @param aStr A string to make Integer.
+ * @return TInt A integer value 
+ */
+ TInt CSmsHeader::ConvertToTInt(TDesC16& aStr)
+	{
+	TLex str(aStr);
+	TInt32 string;
+	str.Val(string);
+	return string;
+	}
+
+#endif