smsprotocols/smsstack/smsprot/Src/smspenum.cpp
changeset 0 3553901f7fa8
child 14 7ef16719d8cb
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smsprotocols/smsstack/smsprot/Src/smspenum.cpp	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,1165 @@
+// 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:
+//
+
+/**
+ @file
+*/
+
+#include "smspenum.h"
+#include "smspproc.h"
+#include "smsuset.h"
+#include "smspmain.h"
+#include "smspstor.h"
+#include "Gsmumsg.h"
+#include "SmsuTimer.h"
+#include "exterror.h"
+
+// constant used to handle inconsistency between slots used and total slots
+const TInt KSmsDefaultTotalMessageStoreSlots = 50;
+
+
+/**
+ *  Creates new CSmsStoreRead instance
+ *  
+ *  @param aSmsComm Used to set CSmsPDUProcess object
+ *  @param aSmsSettings Used to start CSmsTimeout object
+ *  @param aSmsMessaging Used to get message store info and open store
+ *  @param aReassemblyStore Used to set CSmsPDUProcess object
+ *  @param aSegmentationStore Used to set CSmsPDUProcess object
+ *  @param aPriority Used to set CSmsPDUProcess object
+ *  @param aSmsMonitorDiskSpace Used to set CSmsPDUProcess object
+ *  
+ *  @leave Leaves if ContructL() leaves, or not enough memory is available.
+ *  @return a new CSmsStoreRead object.
+ */
+CSmsStoreRead* CSmsStoreRead::NewL(MSmsComm& aSmsComm,
+								   const TSmsSettings& aSmsSettings,
+								   RMobileSmsMessaging& aSmsMessaging,
+								   CFacadeSmsReassemblyStore& aReassemblyStore,
+								   CSmsSegmentationStore& aSegmentationStore,
+								   TInt aPriority,
+								   CSmsMonitorDiskSpace& aSmsMonitorDiskSpace)
+	{
+	LOGSMSPROT1("CSmsStoreRead::NewL()");
+
+	CSmsStoreRead* smsStoreRead = new ( ELeave ) CSmsStoreRead(aSmsComm,
+															   aSmsSettings,
+															   aSmsMessaging,
+															   aReassemblyStore,
+															   aSegmentationStore,
+															   aPriority,
+															   aSmsMonitorDiskSpace);
+	CleanupStack::PushL(smsStoreRead);
+	smsStoreRead->ConstructL();
+	CleanupStack::Pop(smsStoreRead);
+	return smsStoreRead;
+	} // CSmsStoreRead::NewL
+
+
+/**
+ *  Constructor
+ *  
+ *  @param aSmsComm Used to set CSmsPDUProcess object
+ *  @param aSmsSettings Used to start CSmsTimeout object
+ *  @param aSmsMessaging Used to get message store info and open store
+ *  @param aReassemblyStore Used to  set CSmsPDUProcess object
+ *  @param aSegmentationStore Used to  set CSmsPDUProcess object
+ *  @param aPriority Used to  set CSmsPDUProcess object
+ *  @param aSmsMonitorDiskSpace Used to set CSmsPDUProcess object
+ */
+CSmsStoreRead::CSmsStoreRead(MSmsComm& aSmsComm,
+							 const TSmsSettings& aSmsSettings,
+							 RMobileSmsMessaging& aSmsMessaging,
+							 CFacadeSmsReassemblyStore& aReassemblyStore,
+							 CSmsSegmentationStore& aSegmentationStore,
+							 TInt aPriority,
+							 CSmsMonitorDiskSpace& aSmsMonitorDiskSpace)
+  : CSmsuActiveBase(aPriority),
+	iState(ESmsStoreReadIdle),
+	iSmsComm(aSmsComm),
+	iSmsSettings(aSmsSettings),
+	iSmsMessaging(aSmsMessaging),
+	iReassemblyStore(aReassemblyStore),
+	iSegmentationStore(aSegmentationStore),
+	iSmsMonitorDiskSpace(aSmsMonitorDiskSpace),
+	iStoreInfoPckg(iStoreInfo),
+	iEntryV1Pckg(iSmsEntry)
+	{
+	} // CSmsStoreRead::CSmsStoreRead
+
+
+/**
+ *  Calls ConstructTimeoutL from the class CSmsuActiveBase
+ */
+void CSmsStoreRead::ConstructL()
+	{
+	LOGSMSPROT1("CSmsStoreRead::ConstructL()");
+
+	ConstructTimeoutL();
+	ReadConfigurableSmsSettingsL();
+	} // CSmsStoreRead::ConstructL
+
+
+/**
+ *  
+ *  Synopsis:
+ *  
+ *  Certain pieces of Release 6 functionality cause breaks to existing functionality.
+ *  These are disabled by default, but can be configured as follows.
+ *  
+ *  (1) Class 2 messages on the SIM will be deleted when the DCS
+ *  byte specifies that "the message is specified for automatic deletion"
+ *  See 23.038 Section 4, "SMS Data Coding Scheme" and when the following
+ *  text segment is included in the smswap.sms.ESK file:
+ *  
+ *  [Release6Configurability]
+ *  AutomaticDeletionOfClass2= 1
+ *  
+ *  (2) Class 2 messages on the SIM will be deleted and will not be
+ *  forwarded to the client when the PID  byte specifies that the
+ *  message is type 0 as per 23.40 v6.5.0  9.2.3.9 and when the
+ *  following text segment is included in the  smswap.sms.ESK file:
+ *  
+ *  [Release6Configurability]
+ *  DiscardType0_Class2Message= 1
+ *  
+ *  
+ *  (3) Class 0 messages will not be forwarded to the SMS Stack client
+ *  when the PID byte specifies that the message is type 0 as per
+ *  23.40 v6.5.0 9.2.3.9 and when the following text segment is included
+ *  in the smswap.sms.esk file:
+ *  [Release6Configurability]
+ *  DiscardType0_Class0Message= 1
+ *  
+ *  Note: The Release 6 Configuration Option tag [Release6Configurability]
+ *  must only be specified once in the configuration file, even if
+ *  more than one Release 6 configuration option is specified. For example:
+ *  [Release6Configurability]
+ *  AutomaticDeletionOfClass2=  1
+ *  DiscardType0_Class2Message= 1
+ *  DiscardType0_Class0Message= 1
+ *  
+ */
+void CSmsStoreRead::ReadConfigurableSmsSettingsL()
+    {
+    LOGSMSPROT1("CSmsStoreRead::ReadConfigurableSmsSettingsL()");
+
+    CESockIniData*  ini = NULL;
+    TRAPD(ret, ini=CESockIniData::NewL(_L("smswap.sms.esk")));
+    if(ret!=KErrNone)
+        {
+        LOGSMSPROT2("CSmsStoreRead::ReadConfigurableSmsSettingsL(): ret=%d", ret);
+        User::Leave(ret);
+        }
+
+    CleanupStack::PushL(ini);
+    
+    //
+    // Save Release 6 options...
+    //
+    TBool status(EFalse);
+
+    if (ini->FindVar(_L("Release6Configurability"),
+    				 _L("AutomaticDeletionOfClass2"), status))
+    	{
+        iConfigAutomaticDeletionForClass2 = status;
+        }
+
+	LOGSMSPROT2("CSmsStoreRead::ReadConfigurableSmsSettingsL(): iConfigAutomaticDeletionForClass2=%d",
+				iConfigAutomaticDeletionForClass2);
+
+    if (ini->FindVar(_L("Release6Configurability"),
+    				 _L("DiscardType0_Class2Message"), status))
+    	{
+        iConfigDiscardingType0Class2 = status;
+        }
+
+	LOGSMSPROT2("CSmsStoreRead::ReadConfigurableSmsSettingsL(): iConfigDiscardingType0Class2=%d",
+				iConfigDiscardingType0Class2);
+
+    if (ini->FindVar(_L("Release6Configurability"),
+    				 _L("DiscardType0_Class0Message"), status))
+    	{
+        iConfigDiscardingType0Class0 = status;
+        }
+
+	LOGSMSPROT2("CSmsStoreRead::ReadConfigurableSmsSettingsL(): iConfigDiscardingType0Class0=%d",
+				iConfigDiscardingType0Class0);
+
+    CleanupStack::PopAndDestroy(ini);
+    } // CSmsStoreRead::ReadConfigurableSmsSettingsL
+
+
+/**
+ *  Starts CSmsStoreRead active object
+ *  Calls GetMessageStoreInfo method from the MM API
+ *  
+ *  @param aStatus Reguest status
+ *  @param aStoreIndex Index to the store to be read
+ */
+void CSmsStoreRead::Start( TRequestStatus& aStatus, TInt aStoreIndex )
+	{
+	LOGSMSPROT1("CSmsStoreRead::Start()");
+
+	iState = ESmsStoreReadGettingStoreInfo;
+	// Initialises current slot index
+	iCurrentSlotIndex = 0;
+
+	// Gets current store info
+	iSmsMessaging.GetMessageStoreInfo( iStatus, aStoreIndex, iStoreInfoPckg );
+
+	Queue(aStatus);
+	TimedSetActive(iSmsSettings.Timeout());
+	} // CSmsStoreRead::Start
+
+
+/**
+ *  Called by CSmsuActive object to run this object
+ *  Cancels timeout timer
+ *  State ESmsStoreReadGettingStoreInfo:
+ *  Change state to ESmsStoreReadReadingList or ESmsStoreReadReadingSlot
+ *  Sets value of the total entries if inconsistency between slots used and total slots
+ *  If store can be read opens store, otherwise leaves with KErrNotSupported
+ *  If store can be read att once, starts two-phased reading of the message list,
+ *  Otherwise start reading store slot by slot
+ *  State ESmsStoreReadReadingList:
+ *  Gets readed store list
+ *  Starts process Pdus
+ *  State ESmsStoreReadReadingSlot:
+ *  Adds readed store entry to the entry list
+ *  Starts reading of the next slot
+ *  Starts process Pdus when all entries are read and
+ *  State ESmsStoreReadIdle is unexpected state
+ *  
+ *  @leave Leaves if there was an error
+ *  @leave Leaves if open store leaves
+ *  @leave Leaves with KErrNotSupported if store has no read access
+ *  @leave Panic if complete is called while state is ESmsStoreReadIdle
+ */
+void CSmsStoreRead::DoRunL()
+	{
+	LOGSMSPROT2("CSmsStoreRead::DoRunL [iStatus=%d]", iStatus.Int() );
+
+	TInt status = iStatus.Int();
+
+	//status is KErrNotFound or KErrGsmSMSInvalidMemoryIndex if last read entry was empty
+	//status is KErrCorrupt if the TSY declares a PDU to be corrupt
+ 	if (status != KErrNone  &&  status != KErrNotFound  &&
+ 	    status != KErrCorrupt  &&  status != KErrGsmSMSInvalidMemoryIndex)
+ 	    {
+		User::Leave(status); //< Trapped in CSmsuActiveBase::RunError() which calls Complete().
+		}
+
+    switch ( iState )
+		{
+		case ESmsStoreReadGettingStoreInfo:
+			{
+			if ( ( iStoreInfo.iTotalEntries == 0 ) && ( iStoreInfo.iUsedEntries > 0 ) )
+				{
+				// Handle inconsistency between slots used & total slots (7110!)
+				iStoreInfo.iTotalEntries = KSmsDefaultTotalMessageStoreSlots;
+				}
+			// Checks reading capabilities of the current store
+			if ( iStoreInfo.iCaps & RMobilePhoneStore::KCapsReadAccess )
+				{
+				// Opens current store
+				User::LeaveIfError( iSmsStorage.Open( iSmsMessaging, iStoreInfo.iName ) );
+				}
+			else
+				{
+				User::Leave( KErrNotSupported );
+				}
+			if ( iStoreInfo.iCaps & static_cast<TUint32>(RMobilePhoneStore::KCapsWholeStore) )
+				{
+				iState = ESmsStoreReadReadingList;
+				delete iRetrieveMobilePhoneSmsList;
+				iRetrieveMobilePhoneSmsList = NULL;
+				// Create CRetrieveMobilePhoneSmsList object
+				iRetrieveMobilePhoneSmsList = CRetrieveMobilePhoneSmsList::NewL(
+					iSmsStorage, RMobileSmsStore::KETelMobileGsmSmsEntryV1 );
+				// Starts two-phased reading of the message list
+				iRetrieveMobilePhoneSmsList->Start(iStatus);
+				TimedSetActive(KDefaultEnumerateTimeoutSeconds);
+				}
+			else if ( iStoreInfo.iCaps & RMobilePhoneStore::KCapsIndividualEntry )
+				{
+				iState = ESmsStoreReadReadingSlot;
+				// Reads next single message from the store
+				delete iMobilePhoneGsmSmsList;
+				iMobilePhoneGsmSmsList = NULL;
+				iMobilePhoneGsmSmsList = CMobilePhoneGsmSmsList::NewL();
+				ReadNextSlotL();
+				}
+			else
+				{
+				User::Leave( KErrNotSupported );
+				}
+			}
+			break;
+
+		case ESmsStoreReadReadingSlot:
+			{
+			if ( iStatus == KErrNone )
+				{
+				// Add current message to the list
+				iMobilePhoneGsmSmsList->AddEntryL( iSmsEntry );
+				LOGSMSIFSMSENTRY(_L8("SMSENTRY: "), iSmsEntry);
+				iStoreInfo.iUsedEntries--;
+				}
+			// Reads next single message from the store
+			ReadNextSlotL();
+			}
+			break;
+
+		case ESmsStoreReadReadingList:
+			{
+			// Gets whole message list
+			if (iStatus != KErrNotFound  &&
+			    iStatus != KErrGsmSMSInvalidMemoryIndex  &&
+			    iStatus != KErrCorrupt)	//ReadList has completed if iStatus is KErrNotFound => empty list
+				{
+				CMobilePhoneGsmSmsList* tempList = iRetrieveMobilePhoneSmsList->RetrieveGsmListL();
+				delete iMobilePhoneGsmSmsList;
+				iMobilePhoneGsmSmsList = tempList;
+				ProcessPduL();
+				}
+			else
+				{
+				iStatus = KErrNone;	//iStatus is used as completion object for this AO call, so set to status to KErrNone as we do not want to propogate KErrNotFound back to phone enumeration AO as it is not actually an error.
+				}
+			}
+			break;
+
+		default:
+			{
+			SmspPanic(KSmspPanicUnexpectedState);
+			}
+			break;
+		}
+
+	//
+	// DoRunL() will now return to CSmsuActiveBase which if the object
+	// is not active, will call Complete().
+	//
+	} // CSmsStoreRead::DoRunL
+
+
+/**
+ *  private method for reading one slot from the store
+ */
+void CSmsStoreRead::ReadNextSlotL()
+	{
+	LOGSMSPROT1("CSmsStoreRead::ReadNextSlotL()");
+
+	//Increments current slot index
+	iCurrentSlotIndex++;
+	// Sets message entry index
+	iSmsEntry.iIndex = iCurrentSlotIndex;
+
+	if (iStoreInfo.iUsedEntries > 0  &&
+		iCurrentSlotIndex <= iStoreInfo.iTotalEntries)
+		{
+		// Reads message from the store
+		iSmsStorage.Read( iStatus, iEntryV1Pckg );
+		SetActive();
+		}
+	else
+		{
+		ProcessPduL();
+		}
+	} // CSmsStoreRead::ReadNextSlotL
+
+
+/**
+ *  private method for process one slot from the entry list
+ */
+void CSmsStoreRead::ProcessPduL()
+	{
+	LOGSMSPROT1("CSmsStoreRead::ProcessPduL()");
+
+	// Increments slot index
+	for ( iCurrentSlotIndex = 0; iCurrentSlotIndex < iMobilePhoneGsmSmsList->Enumerate(); iCurrentSlotIndex++ )
+		{
+		CSmsPDUProcessor*  pduProcessor = CSmsPDUProcessor::NewL(iSmsComm, iSmsSettings, iReassemblyStore,
+											 iSegmentationStore, iSmsMonitorDiskSpace);
+		CleanupStack::PushL(pduProcessor);
+
+		pduProcessor->SetApplyAutoDeletionToClass2(iConfigAutomaticDeletionForClass2);
+		pduProcessor->SetDiscardType0Class0(iConfigDiscardingType0Class0);
+		pduProcessor->SetDiscardType0Class2(iConfigDiscardingType0Class2);
+
+		// Gets message from the list
+		iSlot = iMobilePhoneGsmSmsList->GetEntryL( iCurrentSlotIndex );
+
+		// Sets store name to the slot
+		iSlot.iStore = iStoreInfo.iName;
+
+		//User::LeaveIfError( Decode( iSlot ) );
+        // ALR-56UJLB - Enumerating messages on SIM may fail
+        // if there is a corrupt message on SIM
+        // the enumeration of a submit pdu with a 9210
+        // return KErrcorrupt, because the submit pdu
+        // is stored as a deliver pdu in the SIM store
+        // that is a defect in the modem software of the 9210
+        // but in this case none of the messages have been passed
+        // to the client, this has been fixed here
+		TRAPD(ret, pduProcessor->DecodeAndProcessPDUL(iSlot, ETrue));
+		LOGSMSPROT2("CSmsStoreRead::ProcessPduL(): DecodeAndProcessPDUL() returned %d", ret);
+
+		if (ret == KErrNone)
+			{
+			if (pduProcessor->IsForwardMessageToClient())
+				{
+				//
+				// Note, at this point we have not placed the message in
+				// the reassembly store.
+				//
+				pduProcessor->ProcessMessageIfCompleteL();
+				}
+			}
+		 else if (ret == KErrCorrupt)
+			{
+      		pduProcessor->DeletePDUL();
+			}
+		else if (ret ==  KErrDiskFull  ||  ret ==  KErrNoMemory)
+			{
+		 	//
+		 	// Permanant error, can't continue message enumeration,
+		 	// so just leave...
+		 	//
+		 	User::Leave(ret);
+			}
+			
+		CleanupStack::PopAndDestroy(pduProcessor);
+		}
+	} // CSmsStoreRead::ProcessPduL
+
+
+/**
+ *  Called by CSmsuActive object to cancel this object
+ *  Cancels timeout timer
+ *  State ESmsStoreReadGettingStoreInfo:
+ *  Cancels reading of the message store info
+ *  State ESmsStoreReadReadingList:
+ *  Cancels reading of the message store list
+ *  State ESmsStoreReadReadingSlot:
+ *  Cancels reading of the single slot
+ *  State ESmsStoreReadIdle is unexpected state
+ *  
+ *  @leave Panic if complete is called while state is ESmsStoreReadIdle
+ */
+void CSmsStoreRead::DoCancel()
+	{
+	LOGSMSPROT1("CSmsStoreRead::DoCancel()");
+
+	TimedSetActiveCancel();
+
+	switch (iState)
+		{
+		case ESmsStoreReadGettingStoreInfo:
+			{
+			// Cancels message store info reading
+			iSmsMessaging.CancelAsyncRequest(EMobileSmsMessagingGetMessageStoreInfo);
+			}
+			break;
+
+		case ESmsStoreReadReadingList:
+			{
+			// Cancels message list reading
+			iRetrieveMobilePhoneSmsList->Cancel();
+			}
+			break;
+
+		case ESmsStoreReadReadingSlot:
+			{
+			// Cancels slot reading
+ 			iSmsStorage.CancelAsyncRequest( EMobilePhoneStoreRead );
+ 			iState = ESmsStoreReadReadingSlotCancel;
+			}
+			break;
+
+		default:
+			{
+			SmspPanic(KSmspPanicUnexpectedState);
+			}
+			break;
+		}
+
+	//
+	// Handle completion of this Active Object. Note that the object
+	// may well still be active at this point...
+	//
+	if (TimedOut())
+		{
+		Complete(KErrTimedOut);
+		}
+	else
+		{
+		Complete(KErrCancel);
+		}
+	} // CSmsStoreRead::DoCancel
+
+
+/**
+ *  Completes store read request
+ *  
+ *  Closes phone side store if necessary.
+ *  
+ *  @param aStatus a status value
+ *  @leave Panic if complete is called while state is ESmsStoreReadIdle
+ */
+void CSmsStoreRead::Complete(TInt aStatus)
+	{
+	LOGSMSPROT1("CSmsStoreRead::Complete()");
+
+	__ASSERT_DEBUG(iState != ESmsStoreReadIdle, SmspPanic(KSmspPanicUnexpectedState));
+
+	//
+	// Close the store if needed...
+	//
+	if (iState != ESmsStoreReadReadingSlotCancel)
+		{
+		CloseStore();
+		}
+
+	//
+	// Call the base function to perform the actual complete...
+	//
+	CSmsuActiveBase::Complete(aStatus);
+
+	iState = ESmsStoreReadIdle;
+	} // CSmsStoreRead::Complete
+
+
+/**
+ *  Closes the store
+ */
+void CSmsStoreRead::CloseStore()
+ 	{
+ 	iSmsStorage.Close();
+ 	} // CSmsStoreRead::CloseStore
+
+
+/**
+ *  Destructor
+ */
+CSmsStoreRead::~CSmsStoreRead()
+	{
+	Cancel();
+
+	// Deletes created instances
+	delete iRetrieveMobilePhoneSmsList;
+	delete iMobilePhoneGsmSmsList;
+	} // CSmsStoreRead::~CSmsStoreRead
+
+
+/**
+ *  Creates new CSmsPhoneEnumeration instance
+ *  
+ *  @param aSmsComm Used to complete enumeration
+ *  @param aSmsSettings Used to create CSmsStoreRead object and start timer
+ *  @param aReassemblyStore Used to create CSmsStoreRead object
+ *  @param aSegmentationStore Used to create CSmsStoreRead object
+ *  @param aGsmPhone Used to Initialise phone and open RMobileSmsMessaging for enumerate message
+ *  @param aPriority Used to set CSmsuActiveBase object
+ */
+CSmsPhoneEnumeration* CSmsPhoneEnumeration::NewL( MSmsComm& aSmsComm,
+												  const TSmsSettings& aSmsSettings,
+												  CFacadeSmsReassemblyStore& aReassemblyStore,
+												  CSmsSegmentationStore& aSegmentationStore,
+												  RMobilePhone& aGsmPhone,
+												  TInt aPriority,
+												  CSmsMonitorDiskSpace& aSmsMonitorDiskSpace )
+	{
+	LOGSMSPROT1("CSmsPhoneEnumeration::NewL()");
+
+	CSmsPhoneEnumeration* smsPhoneEnumeration =
+		new ( ELeave ) CSmsPhoneEnumeration( aSmsComm,
+											 aSmsSettings,
+											 aGsmPhone,
+											 aPriority );
+	CleanupStack::PushL( smsPhoneEnumeration );
+	smsPhoneEnumeration->ConstructL( aReassemblyStore, aSegmentationStore, aSmsMonitorDiskSpace );
+	CleanupStack::Pop( smsPhoneEnumeration );
+	return smsPhoneEnumeration;
+	} // CSmsPhoneEnumeration::NewL
+
+
+/**
+ *  Constructor
+ *  
+ *  @param aSmsComm Used to complete enumeration
+ *  @param aSmsSettings Used to create CSmsStoreRead object and start timer
+ *  @param aReassemblyStore Used to create CSmsStoreRead object
+ *  @param aSegmentationStore Used to create CSmsStoreRead object
+ *  @param aGsmPhone Used to Initialise phone and open RMobileSmsMessaging for enumerate message
+ *  @param aPriority Used to set CSmsuActiveBase object
+ */
+CSmsPhoneEnumeration::CSmsPhoneEnumeration( MSmsComm& aSmsComm,
+											const TSmsSettings& aSmsSettings,
+											RMobilePhone& aGsmPhone,
+											TInt aPriority )
+	:CSmsuActiveBase( aPriority )
+	,iState( ESmsPhoneEnumerationIdle )
+	,iSmsComm( aSmsComm )
+	,iSmsSettings( aSmsSettings )
+	,iGsmPhone( aGsmPhone )
+	{
+	} // CSmsPhoneEnumeration::CSmsPhoneEnumeration
+
+
+/**
+ *  Destructor
+ */
+CSmsPhoneEnumeration::~CSmsPhoneEnumeration()
+	{
+	Cancel();
+	//deletes created instances
+	delete iSmsStoreRead;
+	} // CSmsPhoneEnumeration::~CSmsPhoneEnumeration
+
+
+/**
+ *  Starts CSmsPhoneEnumeration active object
+ *  Calls Initialise method from RMobilePhone object
+ *  Sets timed active
+ */
+void CSmsPhoneEnumeration::Start()
+	{
+	LOGSMSPROT1("CSmsPhoneEnumeration::Start()");
+
+	iState = ESmsPhoneEnumerationInitializing;
+	iCurrentStore = 0;
+	iGsmPhone.Initialise( iStatus );
+	TimedSetActive( iSmsSettings.Timeout() );
+	} // CSmsPhoneEnumeration::Start
+
+
+/**
+ *  Called by CSmsuActive object to run this object
+ *  Cancels timeout timer
+ *  State ESmsPhoneEnumerationInitializing:
+ *  Change State to ESmsPhoneEnumerationReadingStores
+ *  Calls Open method from class RMobileSmsMessaging
+ *  If opening returns KErrNone
+ *  Gets number of enumerate message stores
+ *  Marks initialization begin in phone image
+ *  Starts CSmsStoreRead active object to read first store
+ *  State ESmsPhoneEnumerationReadingStores:
+ *  Reads all existing stores
+ *  State Completes when all stores are readed
+ *  State ESmsPhoneEnumerationIdle is unexpected state
+ *  Completes if object is not active
+ *  
+ *  @leave Leaves if there was an error
+ *  @leave Panic if called while state is ESmsPhoneEnumerationIdle
+ */
+void CSmsPhoneEnumeration::DoRunL()
+	{
+	LOGSMSPROT3("CSmsPhoneEnumeration::RunL [iStatus=%d], [iState=%d]", iStatus.Int(), iState );
+
+    switch (iState)
+		{
+		case ESmsPhoneEnumerationInitializing:
+			{
+		    if (iStatus.Int() == KErrNone)
+    			{
+				iState = ESmsPhoneEnumerationReadingStores;
+				User::LeaveIfError(iSmsMessaging.Open(iGsmPhone));
+				User::LeaveIfError(iSmsMessaging.EnumerateMessageStores(iNumStores));
+
+				iSmsStoreRead->Start(iStatus, iCurrentStore);
+				SetActive();
+				}
+			}
+			break;
+
+		case ESmsPhoneEnumerationReadingStores:
+			{
+		    if (iStatus.Int() == KErrNone)
+    			{
+				iCurrentStore++;
+				if (iCurrentStore < iNumStores)
+					{
+					iSmsStoreRead->Start( iStatus, iCurrentStore );
+					SetActive();
+					}
+				}
+			}
+			break;
+
+		default:
+			{
+			SmspPanic(KSmspPanicUnexpectedState);
+			}
+			break;
+		}
+
+	//
+	// DoRunL() will now return to CSmsuActiveBase which if the object
+	// is not active, will call Complete().
+	//
+	} // CSmsPhoneEnumeration::DoRunL
+
+
+void CSmsPhoneEnumeration::DoCancel()
+	{
+	LOGSMSPROT1("CSmsPhoneEnumeration::DoCancel()");
+
+	TimedSetActiveCancel();
+
+	switch (iState)
+		{
+		case ESmsPhoneEnumerationInitializing:
+			{
+			iGsmPhone.InitialiseCancel();
+			}
+			break;
+
+		case ESmsPhoneEnumerationReadingStores:
+			{
+			iSmsStoreRead->Cancel();
+			iSmsStoreRead->CloseStore();
+			}
+			break;
+
+		default:
+			{
+			SmspPanic(KSmspPanicUnexpectedState);
+			}
+			break;
+		}
+
+	//
+	// Handle completion of this Active Object. Note that the object
+	// may well still be active at this point...
+	//
+	if (TimedOut())
+		{
+		Complete(KErrTimedOut);
+		}
+	else
+		{
+		Complete(KErrCancel);
+		}
+	} // CSmsPhoneEnumeration::DoCancel
+
+
+/**
+ *  Creates instances to the classes CSmsTimeout and CSmsStoreRead
+ */
+void CSmsPhoneEnumeration::ConstructL(CFacadeSmsReassemblyStore& aReassemblyStore,CSmsSegmentationStore& aSegmentationStore,CSmsMonitorDiskSpace& aSmsMonitorDiskSpace)
+	{
+	LOGSMSPROT1("CSmsPhoneEnumeration::ConstructL()");
+
+	iSmsStoreRead = CSmsStoreRead::NewL(iSmsComm, iSmsSettings, iSmsMessaging, aReassemblyStore, aSegmentationStore, Priority(), aSmsMonitorDiskSpace);
+	ConstructTimeoutL();
+	} // CSmsPhoneEnumeration::ConstructL
+
+
+void CSmsPhoneEnumeration::Complete(TInt aStatus)
+	{
+	LOGSMSPROT2("CSmsPhoneEnumeration::Complete [aStatus=%d]", aStatus);
+
+	//
+	// Call the base function to perform the actual complete...
+	//
+	CSmsuActiveBase::Complete(aStatus);
+
+	//
+	// Finish up...
+	//
+	iState = ESmsPhoneEnumerationIdle;
+	iSmsMessaging.Close();
+	
+	//
+	// Send an event to say that the enumeration is complete...
+	//
+	iSmsComm.PhoneEnumerationCompleted(aStatus);
+	} // CSmsPhoneEnumeration::Complete
+
+
+/**
+ *  Creates new CSmsMessageWrite instance
+ *  
+ *  @param aSmsSettings Used to start CSmsTimeout object
+ *  @param aGsmPhone Used to Initialise phone
+ *  @param aSegmentationStore Used to get next 8 or 16bit reference
+ */
+CSmsMessageWrite* CSmsMessageWrite::NewL( MSmsComm& aSmsComm, const TSmsSettings& aSmsSettings,
+										  RMobilePhone& aGsmPhone,
+										  CSmsSegmentationStore& aSegmentationStore
+										  )
+	{
+	LOGSMSPROT1("CSmsMessageWrite::NewL()");
+
+	CSmsMessageWrite* smsMessageWrite = new (ELeave) CSmsMessageWrite(aSmsComm, aSmsSettings,
+																	  aGsmPhone,
+																	  aSegmentationStore);
+	CleanupStack::PushL(smsMessageWrite);
+	smsMessageWrite->ConstructL();
+	CleanupStack::Pop(smsMessageWrite);
+	return smsMessageWrite;
+	} // CSmsMessageWrite::NewL
+
+
+/**
+ *  Destructor
+ */
+CSmsMessageWrite::~CSmsMessageWrite()
+	{
+	LOGSMSPROT1("CSmsMessageWrite::~CSmsMessageWrite()");
+
+	Cancel();
+	iSmsStorage.Close();
+	iSmsMessaging.Close();
+	} // CSmsMessageWrite::~CSmsMessageWrite
+
+
+void CSmsMessageWrite::Start( CSmsMessage* aSmsMessage, TRequestStatus& aStatus )
+	{
+	Queue(aStatus);
+
+	iSmsStorage.Close();
+	iSmsMessaging.Close();
+
+	iState = ESmsMessageWriteInitializing;
+
+
+	iSmsMessage = aSmsMessage;
+    LOGSMSPROT3("CSmsMessageWrite::Start  Storage=[%d]   Type=[%d]", iSmsMessage->Storage(), iSmsMessage->Type());
+	iCurrentStore = 0;
+	iStoreInfo.iName = KNullDesC;
+
+	switch (iSmsMessage->Storage())
+		{
+		case CSmsMessage::ESmsSIMStorage:
+			{
+ 			iSlot.iStore = KETelIccSmsStore;
+			}
+			break;
+
+		case CSmsMessage::ESmsPhoneStorage:
+			{
+ 			iSlot.iStore = KETelMeSmsStore;
+			}
+			break;
+
+		case CSmsMessage::ESmsCombinedStorage:
+			{
+ 			iSlot.iStore = KETelCombinedSmsStore;
+			}
+			break;
+
+		default:
+			{
+			Complete(KErrArgument);
+			return;
+			}
+		}
+
+	switch (iSmsMessage->Type())
+		{
+		case CSmsPDU::ESmsSubmit:
+		case CSmsPDU::ESmsCommand:
+			{
+			iSlot.iMsgStatus = RMobileSmsStore::EStoredMessageUnsent;
+			}
+			break;
+
+		case CSmsPDU::ESmsDeliver:
+		case CSmsPDU::ESmsStatusReport:
+			{
+			// Check read status in iSmsMessage
+			if (iSmsMessage->Status() == NMobileSmsStore::EStoredMessageRead)
+		 		{
+	 			iSlot.iMsgStatus = RMobileSmsStore::EStoredMessageRead;
+	 			}
+	 		else
+	 			{
+				iSlot.iMsgStatus = RMobileSmsStore::EStoredMessageUnread;
+	 			}
+			break;
+			}
+		default:
+			{
+			SmspPanic(ESmspUnexpectedSmsPDUType);
+			}
+			break;
+		}
+
+	//
+	// Begin initialising...
+	//
+	iGsmPhone.Initialise(iStatus);
+	TimedSetActive(iSmsSettings.Timeout());
+	} // CSmsMessageWrite::Start
+
+
+void CSmsMessageWrite::DoRunL()
+	{
+	LOGSMSPROT3("CSmsMessageWrite::DoRunL [iStatus=%d iState=%d]", iStatus.Int() , iState);
+
+	switch (iState)
+		{
+		case ESmsMessageWriteInitializing:
+			{
+			if (iStatus.Int() == KErrNone)
+				{
+				iState = ESmsMessageWriteGettingStoreInfo;
+				iSmsMessaging.Close();
+				User::LeaveIfError(iSmsMessaging.Open(iGsmPhone));
+				User::LeaveIfError(iSmsMessaging.EnumerateMessageStores(iNumStores));
+	 			iSmsMessaging.GetMessageStoreInfo(iStatus, iCurrentStore, iStoreInfoPckg);
+
+				TimedSetActive(iSmsSettings.Timeout());
+				}
+			}
+			break;
+
+		case ESmsMessageWriteGettingStoreInfo:
+			{
+			if (iStatus.Int() == KErrNone)
+				{
+				if (iStoreInfo.iName == iSlot.iStore)
+					{
+					if ((iStoreInfo.iCaps & RMobilePhoneStore::KCapsWriteAccess) == 0)
+						{
+						User::Leave(KErrNotSupported);
+						}
+
+					iState = ESmsMessageWriteWritingPDUs;
+					SegmentMessageL();
+					WriteNextSlot();
+					}
+				else
+					{
+					iCurrentStore++;
+					if (iCurrentStore < iNumStores)
+						{
+	 					iSmsMessaging.GetMessageStoreInfo(iStatus, iCurrentStore, iStoreInfoPckg);
+						TimedSetActive(iSmsSettings.Timeout());
+						}
+					else
+						{
+						User::Leave(KErrNotFound); //< TODO Is this correct?
+						}
+					}
+				}
+			}
+			break;
+
+		case ESmsMessageWriteWritingPDUs:
+			{
+			if (iStatus.Int() == KErrNone)
+				{
+				iSmsArray.Delete( 0 );
+				iSlot.iIndex = iEntryToWrite.iIndex;
+
+				//
+				// Initialise slot entry for transfer to array
+				//
+				TGsmSmsSlotEntry smsSlotEntry;
+
+				smsSlotEntry.iIndex = iSlot.iIndex;
+				smsSlotEntry.iStore = iSlot.iStore;
+				iSmsMessage->AddSlotL(smsSlotEntry);
+				WriteNextSlot();
+				}
+			}
+			break;
+
+		default:
+			{
+			SmspPanic(KSmspPanicUnexpectedState);
+			}
+			break;
+		}
+
+	//
+	// DoRunL() will now return to CSmsuActiveBase which if the object
+	// is not active, will call Complete().
+	//
+	} // CSmsMessageWrite::DoRunL
+
+
+void CSmsMessageWrite::DoCancel()
+	{
+	LOGSMSPROT1("CSmsMessageWrite::DoCancel()");
+
+	TimedSetActiveCancel();
+
+	switch (iState)
+		{
+		case ESmsMessageWriteInitializing:
+			{
+			iGsmPhone.InitialiseCancel();
+			}
+			break;
+
+		case ESmsMessageWriteGettingStoreInfo:
+			{
+			iSmsMessaging.CancelAsyncRequest(EMobileSmsMessagingGetMessageStoreInfo);
+			}
+			break;
+
+		case ESmsMessageWriteWritingPDUs:
+			{
+			iSmsStorage.CancelAsyncRequest(EMobilePhoneStoreWrite);
+			}
+			break;
+
+		default:
+			{
+			SmspPanic(KSmspPanicUnexpectedState);
+			}
+			break;
+		}
+
+	//
+	// Handle completion of this Active Object. Note that the object
+	// may well still be active at this point...
+	//
+	if (TimedOut())
+		{
+		Complete(KErrTimedOut);
+		}
+	else
+		{
+		Complete(KErrCancel);
+		}
+	} // CSmsMessageWrite::DoCancel
+
+
+CSmsMessageWrite::CSmsMessageWrite(MSmsComm& aSmsComm, const TSmsSettings& aSmsSettings,
+								   RMobilePhone& aGsmPhone,
+								   CSmsSegmentationStore& aSegmentationStore)
+  : CSmsuActiveBase(KSmsSessionPriority),
+	iSmsComm(aSmsComm),
+	iState(ESmsMessageWriteIdle),
+	iSmsSettings(aSmsSettings),
+	iGsmPhone(aGsmPhone),
+	iStoreInfoPckg (iStoreInfo),
+	iWriteEntryV1Pckg(iEntryToWrite),
+	iSegmentationStore(aSegmentationStore),
+	iSmsArray(8)
+	{
+	LOGSMSPROT1("CSmsMessageWrite::CSmsMessageWrite()");
+
+	} // CSmsMessageWrite::CSmsMessageWrite
+
+
+void CSmsMessageWrite::ConstructL()
+	{
+	LOGSMSPROT1("CSmsMessageWrite::ConstructL()");
+
+	ConstructTimeoutL();
+	} // CSmsMessageWrite::ConstructL
+
+
+void CSmsMessageWrite::SegmentMessageL()
+	{
+	LOGSMSPROT1("CSmsMessageWrite::SegmentMessageL()");
+
+	if (iStoreInfo.iTotalEntries == iStoreInfo.iUsedEntries)
+		{
+		User::Leave(KErrNoMemory);
+		}
+
+	TInt reference = 0;
+
+	TBool is16bit = EFalse;
+	TBool concatenationIEPresent = EFalse;
+
+	//
+	// Ensure text present before testing concatenation requirement
+	//
+	if (iSmsMessage->TextPresent())
+		{
+		concatenationIEPresent= iSmsMessage->SmsPDU().TextConcatenated( &is16bit );
+		iSmsMessage->SmsPDU().SetTextConcatenatedL(EFalse,EFalse);
+		}
+
+	if (!iSmsMessage->EncodeIntoSinglePDUL(iSmsArray))
+		{
+		if (concatenationIEPresent && is16bit)
+			{
+			iSmsMessage->Set16BitConcatenation(ETrue);
+			}
+
+		reference=is16bit? iSegmentationStore.Next16BitReferenceL(): iSegmentationStore.Next8BitReferenceL();
+		iSmsMessage->EncodeMessagePDUsL(iSmsArray, reference);
+		}
+
+	TInt spare=iStoreInfo.iTotalEntries-iStoreInfo.iUsedEntries;
+	if (spare<iSmsArray.Count())
+		{
+		User::Leave(KErrNoMemory);
+		}
+
+	User::LeaveIfError(iSmsStorage.Open(iSmsMessaging,iSlot.iStore));
+	} // CSmsMessageWrite::SegmentMessageL
+
+
+void CSmsMessageWrite::WriteNextSlot()
+	{
+	LOGSMSPROT1("CSmsMessageWrite::WriteNextSlot()");
+
+	if (iSmsArray.Count()>0)
+		{
+		iState=ESmsMessageWriteWritingPDUs;
+		//Set PDU to the slot
+		iSlot.iMsgData=iSmsArray[0].Pdu();
+		//Sets Service Centre Address to the slot
+
+		iSlot.iServiceCentre.iTelNumber = iSmsArray[0].Sca().iTelNumber;
+		NMobilePhone::TMobileTON ton = static_cast<NMobilePhone::TMobileTON>(static_cast<TInt>(iSlot.iServiceCentre.iTypeOfNumber));
+		NMobilePhone::TMobileNPI npi = static_cast<NMobilePhone::TMobileNPI>(static_cast<TInt>(iSlot.iServiceCentre.iNumberPlan));
+		iSmsArray[0].Sca().iTypeOfAddress.ConvertToETelMM( ton, npi );
+
+		iEntryToWrite = iSlot;
+		iEntryToWrite.iIndex = -1;
+ 		iSmsStorage.Write( iStatus, iWriteEntryV1Pckg );
+		TimedSetActive( iSmsSettings.Timeout() );
+		}
+	} // CSmsMessageWrite::WriteNextSlot
+
+
+void CSmsMessageWrite::Complete(TInt aStatus)
+	{
+	LOGSMSPROT2("CSmsMessageWrite::Complete [aStatus=%d]", aStatus);
+
+	__ASSERT_DEBUG(iState != ESmsMessageWriteIdle, SmspPanic(KSmspPanicUnexpectedState));
+
+	//
+	// Finish up...
+	//
+	iSmsArray.Reset();
+
+	if (aStatus != KErrNone   &&
+		iSmsMessage != NULL   &&  iSmsMessage->iSlotArray.Count() >0)
+		{
+		iSmsComm.DeletePDUs(iSmsMessage->iSlotArray, NULL);
+		}
+
+	iSmsMessage = NULL;
+	iState      = ESmsMessageWriteIdle;
+
+	//
+	// Call the base function to perform the actual complete...
+	//
+	CSmsuActiveBase::Complete(aStatus);
+	} // CSmsMessageWrite::Complete
+