smsprotocols/smsstack/smsprot/Src/smsprot.cpp
changeset 0 3553901f7fa8
child 19 630d2f34d719
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/smsprotocols/smsstack/smsprot/Src/smsprot.cpp	Tue Feb 02 01:41:59 2010 +0200
@@ -0,0 +1,2140 @@
+// Copyright (c) 2003-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:
+// Implements the CSmsProtocol and its helper classes.
+// 
+//
+
+/**
+ @file
+*/
+
+#include <commsdattypesv1_1.h>
+#include <logwrap.h>
+#include "Gsmumsg.h"
+#include "gsmubuf.h"
+#include "Gsmuelem.h"
+#include "gsmunonieoperations.h"
+
+#include "smsprot.h"
+#include "smspfacadestor.h"
+#include "smspmodm.h"
+#include "smspenum.h"
+#include "smspread.h"
+#include "smspdel.h"
+#include "smspproc.h"
+#include "smspmondsk.h"
+#include "smspmain.h"
+#include "smspver.h"
+#include "smsppara.h"
+#include "SmsuBackup.h"
+#include <es_prot_internal.h>
+
+using namespace CommsDat;
+
+//
+// Class implementations
+//
+
+// application port range according to 3GPP TS 23.040 v4.4.0
+// chapters 9.2.3.24.3 and 9.2.3.24.4
+
+const TInt KMin8BitPortNumber = 240;
+const TInt KMax8BitPortNumber = 255;
+
+const TInt KMin16BitPortNumber = 16000;
+const TInt KMax16BitPortNumber = 16999;
+
+
+/**
+ *  2 phase constructor
+ *  
+ */
+CSmsProtocolFamily * CSmsProtocolFamily::NewL()
+	{
+	LOGSMSPROT4("CSmsProtocolFamily::NewL [version %d.%d.%d]",
+			 KSmsPrtMajorVersionNumber,
+			 KSmsPrtMinorVersionNumber,
+			 KSmsPrtBuildVersionNumber
+			 );
+	return new (ELeave)CSmsProtocolFamily;
+	} // CSmsProtocolFamily::NewL
+
+
+/**
+ *  Implementation of the pure virtual CProtocolFamilyBase::Install().
+ *  Called by the socket server after creation of this object.
+ *  Does nothing.
+ *  
+ */
+TInt CSmsProtocolFamily::Install()
+	{
+	LOGSMSPROT1("CSmsProtocolFamily::Install");
+	return KErrNone;
+	} // CProtocolFamilyBase::Install
+
+
+/**
+ *  Implementation of the pure virtual CProtocolFamilyBase::Remove().
+ *  Called by the socket server before unloading the library for the SMS
+ *  protocol family.
+ *  Does nothing.
+ *  
+ */
+TInt CSmsProtocolFamily::Remove()
+	{
+	LOGSMSPROT1("CSmsProtocolFamily::Remove");
+	return KErrNone;
+	} // CProtocolFamilyBase::Remove
+
+
+/**
+ *  Implementation of the pure virtual CProtocolFamilyBase::NewProtocolL().
+ *  Called by the socket server to create the CSmsProtocol object.
+ *  
+ *  @param aSockType not used, assumes datagram.
+ *  @param aProtocol not used, assumes KSmsDatagram, the only protocol provided.
+ *  @return a new instance of the CSmsProtocol class.
+ *  
+ */
+CProtocolBase * CSmsProtocolFamily::NewProtocolL(TUint /*aSockType*/,TUint /*aProtocol*/)
+	{
+	LOGSMSPROT1("CSmsProtocolFamily::NewProtocolL");
+	return CSmsProtocol::NewL();
+	} // CProtocolFamilyBase::NewProtocolL
+
+
+/**
+ *  Implementation of the pure virtual CProtocolFamilyBase::ProtocolList().
+ *  Called by the socket server during initialisation to retrieve a list
+ *  of the protocols we support.
+ *  Only KSmsDatagram is supported.
+ *  
+ *  @return aProtocolList a pointer to an array of protocol description objects
+ *  that this function creates and fills in.
+ *  @return the number of protocols supported (1).
+ *  
+ */
+TUint CSmsProtocolFamily::ProtocolList(TServerProtocolDesc *& aProtocolList)
+	{
+	LOGSMSPROT1("CSmsProtocolFamily::ProtocolList");
+
+	TRAPD(ret, (aProtocolList=new(ELeave) TServerProtocolDesc[1]));
+	if(ret!=KErrNone)
+		{
+		LOGSMSPROT2("WARNING! new TServerProtocolDesc left with %d", ret);
+		return 0;
+		}
+
+	// Datagram protocol
+	aProtocolList[0].iName=KSmsDatagram;
+	aProtocolList[0].iAddrFamily=KSMSAddrFamily;
+	aProtocolList[0].iSockType=KSockDatagram;
+	aProtocolList[0].iProtocol=KSMSDatagramProtocol;
+	aProtocolList[0].iVersion=TVersion(KSmsPrtMajorVersionNumber,KSmsPrtMinorVersionNumber,KSmsPrtBuildVersionNumber);
+	aProtocolList[0].iByteOrder=ELittleEndian;
+	aProtocolList[0].iServiceInfo=KSMSDatagramServiceInfo;
+	aProtocolList[0].iNamingServices=0;
+	aProtocolList[0].iSecurity=KSocketNoSecurity;
+	aProtocolList[0].iMessageSize=KSMSMaxDatagramSize;
+	aProtocolList[0].iServiceTypeInfo=ESocketSupport;
+	aProtocolList[0].iNumSockets=KSMSNumberSockets;
+
+	return 1;
+	} // CProtocolFamilyBase::ProtocolList
+
+
+/**
+ *  Constructor (empty)
+ */
+CSmsProtocolFamily::CSmsProtocolFamily()
+	{
+	} // CSmsProtocolFamily::CSmsProtocolFamily
+
+
+/**
+ *  The single exported function, called by the socket server to create
+ *  an instance of our CProtocolFamilyBase derived class.
+ *  
+ */
+EXPORT_C CProtocolFamilyBase* InstallSMS()
+	{
+	LOGSMSPROT1("CSmsProtocolFamily::CSmsProtocolFamily()");
+
+	CSmsProtocolFamily*  smsProtocolFamily(NULL);
+	
+	TRAP_IGNORE(smsProtocolFamily = CSmsProtocolFamily::NewL());
+
+	return smsProtocolFamily;
+	} // CSmsProtocolFamily::CSmsProtocolFamily
+
+
+//
+// implementation of CSmsProtocol
+//
+
+
+/**
+ *  2 phase constructor.
+ *  
+ */
+CSmsProtocol* CSmsProtocol::NewL()
+	{
+	LOGSMSPROT1("CSmsProtocol::NewL()");
+
+	return new (ELeave) CSmsProtocol();
+	} // CSmsProtocol::NewL
+
+
+/**
+ *  Destructor, ensures all outstanding queues are empty,
+ *  all resource handles are closed, and all allocated memory freed.
+ *  
+ */
+CSmsProtocol::~CSmsProtocol()
+    {
+    delete iSmsPhoneInitialization;
+    delete iSmsModemNotification;
+
+    delete iSendQueue;
+	delete iSetBearer;	// referenced by iSendQueue
+
+    delete iSmsPDURead;
+	delete iReceiveMode;	// referenced by iSmsPDURead
+    delete iSmsPhoneEnumeration;
+    delete iWriteQueue;
+    delete iDeleteQueue;
+
+
+    delete iSmsReadParams;
+    delete iSmsWriteParams;
+    delete iSmsMonitorDiskSpace;
+
+    delete iReassemblyStore;
+
+    if(iSegmentationStore)
+        {
+        iSegmentationStore->Close();
+        delete iSegmentationStore;
+        }
+    iFs.Close();
+
+    iSmsMessaging.Close();
+    iGsmPhone.Close();
+    iEnumerationPhone.Close();
+    iWritePhone.Close();
+    iTelServer.Close();
+	delete iBackupRestoreSession;
+	delete iBootTimer;
+    } // CSmsProtocol::~CSmsProtocol
+
+
+
+/**
+ *  Override of CProtocolBase::NewSAPL().
+ *  Called by the server to create a new SMS service access point object.
+ *  
+ *  @param aSocketType the socket type
+ *  @leave Leaves if aSocketType is not KSockDatagram.
+ *  @leave Leaves if not enough memory is available.
+ *  @return a new CSmsProvider object.
+ *  
+ */
+CServProviderBase *CSmsProtocol::NewSAPL(TUint aSocketType)
+	{
+	LOGSMSPROT2("*CSmsProtocol::NewSAPL [sockettype=%d]", aSocketType);
+	if (aSocketType!=KSockDatagram)
+		User::Leave(KErrNotSupported);
+	return CSmsProvider::NewL(*this);
+	} // CProtocolBase::NewSAPL
+
+
+/**
+ *  Override of CProtocolBase::InitL().
+ *  Called by the socket server to allow any resource initialisation
+ *  by the protocol.
+ *  
+ *  The following tasks are performed:
+ *  - All member objects constructed (deferred from ConstructL() for efficiency reasons; see comment there)
+ *  - TSY Name read from Comms Database
+ *  - Event notification state machines started
+ *  - Modem checked to see if it is already connected, and if so, a number of
+ *  state machines started (otherwise wait until we receive notification of connection).
+ *  
+ */
+void CSmsProtocol::InitL(TDesC& /*aTag*/)
+	{
+	LOGSMSPROT1("CSmsProtocol::InitL");
+
+	User::LeaveIfError(iFs.Connect());
+
+	iReassemblyStore=CFacadeSmsReassemblyStore::NewL(iFs, *this);
+	iReassemblyStore->InitL();
+
+	LOGSMSPROT1("CSmsProtocol::InitL Constructing members");
+
+	ReadConfigurableSettingsL();
+
+	iBootTimer = CSmsProtocolBootTimer::NewL(*this);
+	iBootTimer->Start(iSmsSettings.BootTimerTimeout().Int());
+
+	iSegmentationStore=CSmsSegmentationStore::NewL(iFs);
+
+	iSetBearer=CSmspSetBearer::NewL(iSmsSettings, iSmsMessaging, KSmsSessionPriority);
+
+	iReceiveMode = CSmspReceiveMode::NewL(iSmsSettings, iSmsMessaging, iMobileSmsCaps, KSmsSessionPriority);
+
+	iSmsModemNotification=CSmsModemNotification::NewL(*this);
+
+	iSendQueue = CSmspSendQueue::NewL(*this, *iSegmentationStore, iSmsSettings, iMobileSmsCaps, iSmsMessaging, KSmsSessionPriority, *iSetBearer);
+
+	iSmsMonitorDiskSpace=CSmsMonitorDiskSpace::NewL(*this, iSmsMessaging,iFs);
+
+	iSmsPDURead=CSmsPDURead::NewL(*this, iSmsSettings, iSmsMessaging,*iReassemblyStore,*iSegmentationStore, iMobileSmsCaps, KSmsSessionPriority, *iReceiveMode, *iSmsMonitorDiskSpace);
+
+	iSmsPhoneInitialization = new (ELeave) CSmsPhoneInitialization(iSmsMessaging, iGsmPhone, *iSmsPDURead, iMobileSmsCaps, KSmsSessionPriority, iSetBearer);
+
+	iBackupRestoreSession = CBackupAndRestore::NewL(*this);
+
+/* THIS CODE SHOULD NEVER BE NECESSARY - who could have called CProtocolBase::InitL() if not ESOCK, which means
+ * a running C32 already. However, if this is a wrong analysis then reinstate the code but with an explanatory comment
+#if defined (__WINS__)
+	// Make sure C32 is started under WINS
+	TInt ret=StartC32();
+	if (ret!=KErrAlreadyExists)
+		User::LeaveIfError(ret);
+#endif
+*/
+	LOGSMSPROT1("CSmsProtocol::InitL Querying CommDb");
+
+	// Read the global modem ID setting from  Cooms Database
+	TUint32 modemId = 0;
+
+	
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+	CMDBSession* sess = CMDBSession::NewL(KCDVersion1_2);
+#else
+	CMDBSession* sess = CMDBSession::NewL(KCDVersion1_1);
+#endif
+	CleanupStack::PushL(sess);
+
+	CMDBField<TUint32>* globalSettingField = new(ELeave) CMDBField<TUint32>(KCDTIdModemPhoneServicesSMS);
+	CleanupStack::PushL(globalSettingField);
+	globalSettingField->SetRecordId(1);
+	globalSettingField->LoadL(*sess);
+	modemId = *globalSettingField;
+	CleanupStack::PopAndDestroy(globalSettingField);
+
+	CMDBField<TDesC>* tsyField = new(ELeave) CMDBField<TDesC>(KCDTIdTsyName);
+	CleanupStack::PushL(tsyField);
+	tsyField->SetRecordId(modemId);
+	tsyField->LoadL(*sess);
+	iGsmTsyName = *tsyField;
+	CleanupStack::PopAndDestroy(tsyField);
+
+	CleanupStack::PopAndDestroy(sess);
+
+#ifdef _SMS_LOGGING_ENABLED
+	TBuf8<KCommsDbSvrMaxFieldLength> buf8;
+	buf8.Copy(iGsmTsyName);
+	LOGSMSPROT3("CSmsProtocol::InitL [modemId=%d tsy=%S]",
+				modemId, &buf8);
+#endif
+
+	// Start event notification state machines
+	iSmsModemNotification->Start();
+
+	// Intialise the SmsStack to the state that the phone has been found in
+	iModemDetection=iSmsModemNotification->ModemState();
+
+	if (iModemDetection == RPhone::EDetectedPresent && !iBackupRestoreSession->IsBackupOrRestoreInProgress())
+		{
+		DoPowerUpL(); //Call the leaving version because powering up must work here
+		}
+	else
+		{
+		PowerDown();
+		}
+
+	//
+	// Define the Disk Space Monitor P&S variable...
+	//
+	TInt  ret;
+
+	TSecurityPolicy  readPolicy(ECapabilityReadDeviceData);
+	TSecurityPolicy  writePolicy(ECapabilityWriteDeviceData);
+	
+	ret = RProperty::Define(KUidPSSMSStackCategory, KUidPSSMSStackDiskSpaceMonitorKey,
+							KUidPSSMSStackDiskSpaceMonitorKeyType, readPolicy, writePolicy);
+	if (ret != KErrNone  &&  ret != KErrAlreadyExists)
+		{
+		User::Leave(ret);
+		}
+
+	User::LeaveIfError(RProperty::Set(KUidPSSMSStackCategory,
+									  KUidPSSMSStackDiskSpaceMonitorKey, ESmsDiskSpaceAvailable));
+	} // CProtocolBase::InitL
+
+
+/**
+ *  Override of CProtocolBase::StartL().
+ *  Called by the socket server to indicate all bindings are complete
+ *  and that datagram processing can begin.
+ *  
+ *  Binding is not supported so this indication is not important to us.
+ *  
+ */
+void CSmsProtocol::StartL(void)
+	{
+	LOGSMSPROT1("CSmsProtocol::StartL");
+	} // CSmsProtocol::StartL
+
+
+/**
+ *  Override of CProtocolBase::Identify().
+ *  Called by the socket server to obtain a description of the SMS protocol.
+ *  
+ */
+void CSmsProtocol::Identify(TServerProtocolDesc *aDesc)const
+	{
+	LOGSMSPROT1("CSmsProtocol::Identify");
+
+	aDesc->iName=KSmsDatagram;
+	aDesc->iAddrFamily=KSMSAddrFamily;
+	aDesc->iSockType=KSockDatagram;
+	aDesc->iProtocol=KSMSDatagramProtocol;
+	aDesc->iVersion=TVersion(KSmsPrtMajorVersionNumber,KSmsPrtMinorVersionNumber,KSmsPrtBuildVersionNumber);
+	aDesc->iByteOrder=ELittleEndian;
+	aDesc->iServiceInfo=KSMSDatagramServiceInfo;
+	aDesc->iNamingServices=0;
+	aDesc->iSecurity=KSocketNoSecurity;
+	aDesc->iMessageSize=KSMSMaxDatagramSize;
+	aDesc->iServiceTypeInfo=0;
+	aDesc->iNumSockets=KSMSNumberSockets;
+	} // CProtocolBase::Identify
+
+
+/**
+ *  Override of CProtocolBase::NewHostResolverL().
+ *  Called by socket server to create a host resolver.
+ *  No host resolver service is provided by this SMS protocol.
+ *  
+ *  @leave Panics if called.
+ *  
+ */
+CHostResolvProvdBase *CSmsProtocol::NewHostResolverL()
+    {
+    // Ignore in code coverage - not intended to be used
+    BULLSEYE_OFF    
+    LOGSMSPROT1("CSmsProtocol::NewHostResolverL");
+    SmspPanic(ESmspCantCreateHostResolver);
+    return NULL;
+    BULLSEYE_RESTORE
+    }
+
+/**
+ *  Override of CProtocolBase::NewServiceResolverL().
+ *  Called by socket server to create a new service resolver.
+ *  Not supported by this protocol.
+ *  
+ *  @leave Panics if called.
+ *  
+ */
+CServiceResolvProvdBase *CSmsProtocol::NewServiceResolverL()
+    {
+    // Ignore in code coverage - not intended to be used
+    BULLSEYE_OFF    
+    LOGSMSPROT1("*CSmsProtocol::NewServiceResolverL");
+    SmspPanic(ESmspCantCreateServiceResolver);
+    return NULL;
+    BULLSEYE_RESTORE
+    }
+
+/**
+ *  Override of CProtocolBase::NewNetDatabaseL().
+ *  Called by socket server to create a new network database.
+ *  Not supported by this protocol.
+ *  
+ *  @leave Panics if called.
+ *  
+ */
+CNetDBProvdBase* CSmsProtocol::NewNetDatabaseL()
+    {
+    // Ignore in code coverage - not intended to be used
+    BULLSEYE_OFF    
+    LOGSMSPROT1("CSmsProtocol::NewNetDatabaseL");
+    SmspPanic(ESmspCantCreateNetDatabase);
+    return NULL;
+    BULLSEYE_RESTORE
+    }
+
+/**
+ *  Override of CProtocolBase::BindL().
+ *  Called by next protocol above wishing to bind to the SMS protocol.
+ *  Not supported by this protocol.
+ *  
+ *  @leave Panics if called.
+ *  
+ */
+void CSmsProtocol::BindL(CProtocolBase* /*aProtocol*/,TUint /*aId*/)
+    {
+    // Ignore in code coverage - not intended to be used
+    BULLSEYE_OFF    
+    LOGSMSPROT1("CSmsProtocol::BindL");
+    SmspPanic(ESmspCantBind);
+    BULLSEYE_RESTORE
+    }
+
+/**
+ *  Override of CProtocolBase::BindToL().
+ *  Called by socket server when a lower protocol must bind to the
+ *  SMS protocol.
+ *  Not supported by this protocol.
+ *  
+ *  @leave Panics if called.
+ *  
+ */
+void CSmsProtocol::BindToL(CProtocolBase* /*aProtocol*/)
+    {
+    // Ignore in code coverage - not intended to be used
+    BULLSEYE_OFF    
+    LOGSMSPROT1("CSmsProtocol::BindToL");
+    SmspPanic(ESmspCantBindTo);
+    BULLSEYE_RESTORE
+    }
+
+/**
+ *  Reads timeout value for send operation from configuration file
+ *  
+ *  @leave Leaves if configuration file cannot be read
+ *  @leave Leaves if value not greater than zero
+ */
+void CSmsProtocol::ReadConfigurableSettingsL()
+	{
+	CESockIniData* ini = NULL;
+	TRAPD(ret, ini=CESockIniData::NewL(_L("smswap.sms.esk")));
+	if(ret!=KErrNone)
+		{
+		LOGSMSPROT2("esk read failed, error code = [%d]", ret);
+		User::Leave(ret);
+		}
+
+	CleanupStack::PushL(ini);
+
+	TInt var(0);
+	if(ini->FindVar(_L("customTimeoutSettings"),_L("sendTryTimeout"),var))
+		{
+		if (var > 0)
+			{
+			LOGSMSPROT2("sendTryTimeout [%d]", var);
+			iSmsSettings.SetSendTryTimeout(var);
+			}
+		else
+			{
+			User::Leave(KErrArgument);
+			}
+		}
+
+	if(ini->FindVar(_L("customTimeoutSettings"),_L("bootTimerTimeout"),var))
+		{
+		if (var > 0)
+			{
+			LOGSMSPROT2("bootTimerTimeout [%d]", var);
+			iSmsSettings.SetBootTimerTimeout(var);
+			}
+		else
+			{
+			User::Leave(KErrArgument);
+			}
+		}
+
+	CleanupStack::PopAndDestroy(ini);
+	} // CSmsProtocol::ReadConfigurableSettingsL
+
+
+/**
+ *  Override of CProtocolBase::Send().
+ *  A down call from a protocol bound above to send a datagram.
+ *  Not supported by this protocol.
+ *  
+ *  @leave Panics if called.
+ *  
+ */
+TInt CSmsProtocol::Send(TDes8& /*aDes*/,TSockAddr* /*aTo*/,TSockAddr* /*aFrom*/,CProtocolBase* /*aSourceProtocol*/)
+    {
+    // Ignore in code coverage - not intended to be used
+    BULLSEYE_OFF    
+    LOGSMSPROT1("CSmsProtocol::Send");
+    SmspPanic(ESmspCantSend);
+    return KErrNotSupported;
+    BULLSEYE_RESTORE
+    }
+
+/**
+ *  Override of CProtocolBase::Process().
+ *  An up call from a protocol bound below to process a datagram.
+ *  Not supported by this protocol.
+ *  
+ *  @leave Panics if called.
+ *  
+ */
+void CSmsProtocol::Process(TDes8& /*aDes*/,TSockAddr* /*aFrom*/,TSockAddr* /*aTo*/,CProtocolBase* /*aSourceProtocol*/)
+    {
+    // Ignore in code coverage - not intended to be used
+    BULLSEYE_OFF    
+    LOGSMSPROT1("CSmsProtocol::Process");
+    SmspPanic(ESmspCantProcess);
+    BULLSEYE_RESTORE
+    }
+
+/**
+ *  Override of CProtocolBase::GetOption().
+ *  A down call from a protocol bound above to get a protocol option.
+ *  Not supported by this protocol.
+ *  
+ *  @leave Panics if called.
+ *  
+ */
+TInt CSmsProtocol::GetOption(TUint /*aLevel*/,TUint /*aName*/,TDes8 & /*aOption*/,CProtocolBase* /*aSourceProtocol*/)
+    {
+    // Ignore in code coverage - not intended to be used
+    BULLSEYE_OFF    
+    LOGSMSPROT1("CSmsProtocol::GetOption");
+    // SmspPanic(ESmspCantGetOption);
+    return KErrNotSupported;
+    BULLSEYE_RESTORE
+    }
+
+/**
+ *  Override of CProtocolBase::SetOption().
+ *  A down call from a protocol bound above to set a protocol option.
+ *  Not supported by this protocol.
+ *  
+ *  @leave Panics if called.
+ *  
+ */
+TInt CSmsProtocol::SetOption(TUint /*aLevel*/,TUint /*aName*/,const TDesC8& /*option*/,CProtocolBase* /*aSourceProtocol*/)
+    {
+    // Ignore in code coverage - not intended to be used
+    BULLSEYE_OFF    
+    LOGSMSPROT1("CSmsProtocol::SetOption");
+    //SmspPanic(ESmspCantSetOption);
+    return KErrNotSupported;
+    BULLSEYE_RESTORE
+    }
+
+/**
+ *  Override of CProtocolBase::Error().
+ *  An up call from a protocol bound below to indicate an error.
+ *  Not supported by this protocol.
+ *  
+ *  @leave Panics if called.
+ *  
+ */
+void CSmsProtocol::Error(TInt /*aError*/,CProtocolBase* /*aSourceProtocol*/)
+    {
+    // Ignore in code coverage - not intended to be used
+    BULLSEYE_OFF    
+    LOGSMSPROT1("CSmsProtocol::Error");
+    SmspPanic(ESmspCantError);
+    BULLSEYE_RESTORE
+    }
+
+/**
+ *  Adds an observer to the protocol's observer list.
+ *  Used by CSmsProvider and CWapSmsProtocol.
+ *  
+ *  @leave Leaves if not enough memory is available.
+ *  
+ */
+void CSmsProtocol::AddSmsMessageObserverL(MSmsMessageObserver& aObserver)
+    {
+    LOGSMSPROT2("CSmsProtocol::AddSmsMessageObserverL [aObserver=0x%08x]", &aObserver);
+    iSmsMessageObserverList.AppendL(&aObserver);
+    SetClosingDown(EFalse);
+    }
+
+/**
+ *  Binds an SMS observer to the protocol.
+ *  The protocol ensures there are no providers with duplicate addresses.
+ *  Used by CSmsProvider::SetLocalName(), and SMS WAP protocol.
+ *  
+ *  @param aObserver the observer.
+ *  @param aSmsAddr the local address of the observer.
+ *  @return KErrNone on success, or KErrAlreadyExists if a duplicate exists.
+ *  
+ */
+TInt CSmsProtocol::BindSmsMessageObserver(MSmsMessageObserver& aObserver,const TSmsAddr& aSmsAddr)
+	{
+	LOGSMSPROT2("CSmsProtocol::BindSmsMessageObserver 0x%08x", &aObserver);
+	__ASSERT_DEBUG(ObserverIsPresent(aObserver),SmspPanic(ESmspMessageObserverNotFound));
+	TInt ret=KErrNone;
+
+	if (!SmsAddrIsAlreadyUsed(&aObserver,aSmsAddr))
+		{
+		aObserver.SetLocalAddress(aSmsAddr);
+		OrderSmsMessageObserver(aObserver);
+
+		// If not in the powered-up state then the SAR store is closed. When the phone does power-up
+		// then anything waiting in the store will get processed
+		if(CheckPoweredUp() == KErrNone)
+			{
+			//
+			// check the SAR store for any complete messages.
+			// if there are any, send them to the observer
+			//
+			TRAP(ret, ProcessCompleteSmsMessagesL());
+			if(ret != KErrNone)
+				{
+				LOGSMSPROT2("WARNING! CSmsProtocol::ProcessCompleteSmsMessagesL left with %d", ret);
+				}
+			}
+		}
+	else
+		{
+		ret=KErrAlreadyExists;
+		}
+	return ret;
+	} // CSmsProvider::SetLocalName
+
+
+/**
+ *  Removes an observer from the observer list.
+ *  Observers should at least call this method in their destructors.
+ *  
+ */
+void CSmsProtocol::RemoveSmsMessageObserver(const MSmsMessageObserver& aObserver)
+    {
+    LOGSMSPROT2("CSmsProtocol::RemoveSmsMessageObserver 0x%08x", &aObserver);
+    __ASSERT_DEBUG(ObserverIsPresent(aObserver),SmspPanic(ESmspMessageObserverNotFound));
+    TInt index=ObserverIndex(aObserver);
+    iSmsMessageObserverList.Delete(index);
+    }
+
+/**
+ *  Handles a request from a SAP to send a SMS message.
+ *  Ensures there is a current connection to the modem and queues the message.
+ *  Completes with an error immediately if CheckPoweredUp() returns an error code
+ */
+void CSmsProtocol::SendSmsMessage(CSmsMessage* aSmsMessage,MSmsMessageObserver& aObserver,TUint aOptions)
+	{
+	LOGSMSPROT2("CSmsProtocol::SendSmsMessage [aObserver=0x%X]", &aObserver);
+	__ASSERT_DEBUG(ObserverIsPresent(aObserver), SmspPanic(ESmspMessageObserverNotFound));
+
+	// Ensure the modem is connected and initialized
+	const TInt err = CheckPoweredUp();
+
+	if (err != KErrNone)
+		{
+		// Nope, complete immediately
+		aObserver.MessageSendCompleted(err);
+		delete aSmsMessage;
+		}
+	else
+		{
+		iSendQueue->Queue(aSmsMessage, aObserver, aOptions);
+		}
+	}
+
+TInt CSmsProtocol::CheckPoweredUp() const
+    {
+    TInt err = KErrNone;
+    
+    if( iModemDetection == RPhone::EDetectedNotPresent || iState == EPoweredDown )
+        {
+        err = KErrDisconnected;
+        }
+    else if( iBackupRestoreSession->IsBackupOrRestoreInProgress() )
+        {
+        err = KErrAccessDenied;
+        }
+    else
+        {
+        err = iSmsPhoneInitialization->Initialized();
+        }
+    if( err != KErrNone )
+        {
+        LOGSMSPROT4("CSmsProtocol::CheckPoweredUp [err=%d, iModemDetection=%d, IsBackupOrRestoreInProgress=%d]", err, iModemDetection, iBackupRestoreSession->IsBackupOrRestoreInProgress());
+        }    
+    return err;
+    }
+
+/**
+ *  Cancels a previous request to send an SMS message.
+ *  Searches the send queue for the message.  If it is found at the
+ *  head of the queue the sending state machine is cancelled, which
+ *  in turn will callback to the protocol and delete the message.
+ *  If the message is elsewhere in the queue, it is simply removed
+ *  from the queue and the observer notified.
+ *  
+ *  @leave Panics in DEBUG if the message is not found in the queue.
+ *  
+ */
+void CSmsProtocol::CancelSendSmsMessage(MSmsMessageObserver& aObserver,TBool)
+	{
+	LOGSMSPROT2("CSmsProtocol::CancelSendSmsMessage 0x%08x", &aObserver);
+
+	__ASSERT_DEBUG(ObserverIsPresent(aObserver),SmspPanic(ESmspMessageObserverNotFound));
+
+	iSendQueue->CancelObserver(aObserver);
+	} // CSmsProtocol::CancelSendSmsMessage
+
+
+/**
+ *  Handles a request from a SAP to enumerate the SMS messages stored on the phone.
+ */
+void CSmsProtocol::EnumeratePhone(MSmsMessageObserver& aObserver)
+	{
+	LOGSMSPROT1("CSmsProtocol::EnumeratePhone");
+	__ASSERT_DEBUG(ObserverIsPresent(aObserver),SmspPanic(ESmspMessageObserverNotFound));
+
+	// Ensure the modem is connected and initialized
+	const TInt err = CheckPoweredUp();
+
+	if (err != KErrNone)
+		aObserver.EnumeratePhoneCompleted(err);
+	else
+		{
+		if (iPhoneEnumerationObserver!=NULL)
+			{
+			aObserver.EnumeratePhoneCompleted(KErrInUse);
+			}
+		else
+			{
+			iPhoneEnumerationObserver=&aObserver;
+			iSmsPhoneEnumeration->Start();
+			}
+		}
+	} // CSmsProtocol::EnumeratePhone
+
+
+/**
+ *  Cancels a previous request to enumerate the message on the phone memory.
+ *  
+ *  @leave Panics in DEBUG if the SAP is invalid.
+ *  
+ */
+void CSmsProtocol::CancelEnumeratePhone(MSmsMessageObserver& aObserver)
+	{
+	LOGSMSPROT1("CSmsProtocol::CancelEnumeratePhone");
+
+	__ASSERT_DEBUG(ObserverIsPresent(aObserver), SmspPanic(ESmspMessageObserverNotFound));
+	__ASSERT_DEBUG(iPhoneEnumerationObserver==NULL || &aObserver==iPhoneEnumerationObserver, SmspPanic(ESmspMessageWrongObserver));
+
+	if (iSmsPhoneEnumeration != NULL)
+		{
+		iSmsPhoneEnumeration->Cancel();
+		}
+
+	iReassemblyStore->DeleteEnumeratedSIMEntries();
+
+    (void) aObserver;
+	} // CSmsProtocol::CancelEnumeratePhone
+
+
+TInt CSmsProtocol::ExternalizeEnumeratedMessagesL(CSmsProvider& aProvider,TInt& aCount)
+	{
+	return iReassemblyStore->ExternalizeEnumeratedMessagesL(aProvider, aCount);
+	} // CSmsProtocol::ExternalizeEnumeratedMessagesL
+
+
+/**
+ *  Handles a request to write an SMS message to the phone's memory.
+ *  Completes with an error immediately if CheckPoweredUp() returns an error code
+ *  Otherwise the message is added to the tail of the write queue.
+ */
+void CSmsProtocol::WriteSmsMessage(CSmsMessage* aSmsMessage,MSmsMessageObserver& aObserver)
+	{
+	LOGSMSPROT1("CSmsProtocol::WriteSmsMessage");
+	__ASSERT_DEBUG(ObserverIsPresent(aObserver),SmspPanic(ESmspMessageObserverNotFound));
+
+	const TInt err = CheckPoweredUp();
+
+	if (err != KErrNone)
+		{
+		aObserver.MessageWriteCompleted(err);
+		delete aSmsMessage;
+		}
+	else
+		{
+		iWriteQueue->Queue(aSmsMessage, aObserver, NULL);
+		}
+	} // CSmsProtocol::WriteSmsMessage
+
+
+void CSmsProtocol::CancelWriteSmsMessage(MSmsMessageObserver& aObserver)
+	{
+	LOGSMSPROT1("CSmsProtocol::CancelWriteSmsMessage()");
+
+	if (iWriteQueue != NULL)
+		iWriteQueue->CancelObserver(aObserver);
+	} // CSmsProtocol::CancelWriteSmsMessage
+
+
+/**
+ *  Handles a request from a SAP to delete a message from the phone memory.
+ *  Completes with an error immediately if CheckPoweredUp() returns an error code
+ *  If the cached image of the phone's memory is not yet initialised, complete the
+ *  request with KErrNotReady.
+ *  Otherwise match the message in the phone image and queue the message for deletion.
+ *  
+ *  @note aSmsMessage is destroyed from memory on completion.
+ *  
+ */
+void CSmsProtocol::DeleteSmsMessage(CSmsMessage* aSmsMessage,MSmsMessageObserver& aObserver)
+	{
+	LOGSMSPROT1("CSmsProtocol::DeleteSmsMessage");
+	__ASSERT_DEBUG(ObserverIsPresent(aObserver),SmspPanic(ESmspMessageObserverNotFound));
+
+	// Ensure the modem is connected and initialized
+	const TInt err = CheckPoweredUp();
+
+	if (err != KErrNone)
+		{
+		// Not connected or backup running
+		aObserver.MessageDeleteCompleted(err);
+		}
+	else if (aSmsMessage->iSlotArray.Count()==0)
+		aObserver.MessageDeleteCompleted(KErrArgument);
+	else
+		DeletePDUs(aSmsMessage->iSlotArray,&aObserver);
+
+	delete aSmsMessage;
+	} // CSmsProtocol::DeleteSmsMessage
+
+
+/**
+ *  Cancels a previous request to delete a message from the phone memory.
+ *  
+ *  @leave Panics in DEBUG if the SAP is invalid.
+ *  
+ */
+void CSmsProtocol::CancelDeleteSmsMessage(MSmsMessageObserver& aObserver)
+	{
+	LOGSMSPROT1("CSmsProtocol::CancelDeleteSmsMessage");
+
+	__ASSERT_DEBUG(ObserverIsPresent(aObserver),SmspPanic(ESmspMessageObserverNotFound));
+
+	iDeleteQueue->CancelObserver(aObserver);
+	} // CSmsProtocol::CancelDeleteSmsMessage
+
+
+/**
+ *  Handles a request from a SAP to read the SMS parameters stored on the phone.
+ *  Completes with an error immediately if CheckPoweredUp() returns an error code
+ *  If TSY doesn't support retrieving of parameters, the request is completed
+ *  immediately with KErrNotSupported.
+ *  The request is completed with KErrNoMemory if creation of CSmsReadParams
+ *  object fails.
+ *  The request is completed with KErrInUse if another SAP is reading.
+ *  Otherwise, the reading process is started.
+ *  
+ */
+void CSmsProtocol::ReadSmsParameters(MSmsMessageObserver& aObserver)
+	{
+	LOGSMSPROT1("CSmsProtocol::ReadSmsParameters");
+	__ASSERT_DEBUG(ObserverIsPresent(aObserver),SmspPanic(ESmspMessageObserverNotFound));
+	TInt ret = CheckPoweredUp();
+
+	if (ret == KErrNone)
+		{
+		if(iMobileSmsCaps.iSmsControl & RMobileSmsMessaging::KCapsGetSmspList)
+			{
+			if (iSmsReadParams==NULL)
+				{
+				TRAP(ret,(iSmsReadParams=CSmsReadParams::NewL(*this,iSmsSettings,iSmsMessaging)));
+				}
+			else if (iSmsReadParams->IsActive())
+				{
+				ret = KErrInUse;
+				}
+			}
+		else
+			ret = KErrNotSupported;
+		}
+
+	if(ret != KErrNone)
+		aObserver.ReadSmsParamsCompleted(ret, NULL);
+	else
+		iSmsReadParams->Start(aObserver);
+	} // CSmsProtocol::ReadSmsParameters
+
+
+/**
+ *  Cancels a previous request to read SMS parameters.
+ *  
+ */
+void CSmsProtocol::CancelReadSmsParams()
+	{
+	LOGSMSPROT1("CSmsProtocol::CancelReadSmsParams");
+
+	if(iSmsReadParams != NULL)
+		iSmsReadParams->Cancel();
+	} // CSmsProtocol::CancelReadSmsParams
+
+
+/**
+ *  Handles a request to write an SMS parameters to the phone's memory.
+ *  Completes with an error immediately if CheckPoweredUp() returns an error code
+ *  If TSY doesn't support retrieving and writing of parameters, the request is completed
+ *  immediately with KErrNotSupported.
+ *  The request is completed with KErrInUse if another SAP is reading or writing.
+ *  The request is completed with KErrNoMemory if creation of CSmsReadParams or
+ *  CSmsWriteParams object fails.
+ *  Otherwise, the writing process is started.
+ *  
+ */
+void CSmsProtocol::WriteSmsParameters(CMobilePhoneSmspList* aMobilePhoneSmspList,MSmsMessageObserver& aObserver)
+	{
+	LOGSMSPROT1("CSmsProtocol::WriteSmsParameters");
+	__ASSERT_DEBUG(ObserverIsPresent(aObserver),SmspPanic(ESmspMessageObserverNotFound));
+
+	TInt ret = CheckPoweredUp();
+
+	if (ret == KErrNone)
+		{
+		if(iMobileSmsCaps.iSmsControl & RMobileSmsMessaging::KCapsGetSmspList && iMobileSmsCaps.iSmsControl & RMobileSmsMessaging::KCapsSetSmspList)
+			{
+			if (iSmsReadParams==NULL)
+				{
+				TRAP(ret,(iSmsReadParams=CSmsReadParams::NewL(*this,iSmsSettings,iSmsMessaging)));
+				}
+			else if (iSmsReadParams->IsActive())
+				ret=KErrInUse;
+			}
+		else
+			ret=KErrNotSupported;
+		}
+
+	if (ret==KErrNone)
+		{
+		if (iSmsWriteParams==NULL)
+			{
+			TRAP(ret,(iSmsWriteParams=CSmsWriteParams::NewL(*this,iSmsSettings,iSmsMessaging,*iSmsReadParams)));
+			}
+		else if (iSmsWriteParams->IsActive())
+			ret=KErrInUse;
+		}
+
+	if (ret==KErrNone)
+		iSmsWriteParams->Start(aObserver,aMobilePhoneSmspList);
+	else
+		{
+		aObserver.WriteSmsParamsCompleted(ret);
+		delete aMobilePhoneSmspList;
+		}
+	} // CSmsProtocol::WriteSmsParameters
+
+
+/**
+ *  Cancels a previous request to write SMS parameters.
+ *  
+ */
+void CSmsProtocol::CancelWriteSmsParams()
+	{
+	LOGSMSPROT1("CSmsProtocol::CancelWriteSmsParams");
+
+	if(iSmsWriteParams != NULL)
+		iSmsWriteParams->Cancel();
+	} // CSmsProtocol::CancelWriteSmsParams
+
+
+/**
+ *  Processes a received SMS message by matching it to an observer and
+ *  notifying the observer of the new message.
+ *  
+ *  If the message has been matched to a message previously sent by the protocol
+ *  (i.e. a status report from a previous submit), then the original message and address
+ *  are supplied.  Matching priority in this case is given to the original sender.
+ *  
+ *  If the message remains in phone or SIM memory, the message is sent to the "receive any"
+ *  observer, otherwise the match based on the message and address of the observer.
+ *  
+ *  @param aSmsMessage the received message
+ *  @param aOriginalSmsAddr pointer to the address of the sender of a previously sent
+ *  message matched to the received one (e.g. status report). Null if not matched.
+ *  @param aOriginalSmsMessage pointer to a message previously sent matched to the
+ *  received one (e.g. status report).	Null if not matched.
+ *  @param aDes user data for the deliver report acknowledging this message to the SC.
+ *  Filled in by the observer.
+ *  @return KErrNone if the observer handled the message successfully, otherwise an error.
+ *  
+ */
+TInt CSmsProtocol::ProcessMessageL(const CSmsMessage& aSmsMessage,const TSmsAddr* aOriginalSmsAddr,
+		const CSmsMessage* /*aOriginalSmsMessage*/,TDes& aDes)
+	{
+	LOGSMSPROT1("CSmsProtocol::ProcessMessage");
+
+	MSmsMessageObserver* observer=NULL;
+	if (aOriginalSmsAddr!=NULL)
+		{
+		// Status report and original message matched - send to original sender as priority
+		observer=MatchSmsAddressToObserver(*aOriginalSmsAddr);
+		if (observer==NULL)
+			{
+			// Sender no longer present or is read only - match on received message as usual
+			observer=MatchSmsMessageToObserver(aSmsMessage);
+			}
+		}
+	else if (iPhoneEnumerationObserver==NULL  ||  IsAppPortSMS(aSmsMessage ))
+		{
+		// Only match if not currently enumerating or if it is meant for an app port.
+		observer = MatchSmsMessageToObserver(aSmsMessage);
+		}
+
+	LOGSMSPROT2("CSmsProtocol::ProcessMessage [observer=0x%08x]",observer);
+	TInt ret=KErrNone;
+
+	if (observer!=NULL)
+		{
+		TBool isAppPortSms = IsAppPortSMS(aSmsMessage );
+
+		if(isAppPortSms && iBootTimer !=NULL && iBootTimer->IsActive() && observer->GetLocalAddress().SmsAddrFamily() == ESmsAddrRecvAny)
+			{
+			ret = KErrNotReady;
+			}
+		else
+			{
+			ret=observer->MessageReceived(aSmsMessage,aDes);
+			}
+
+		if(ret == KErrNone && (observer->ClientConfirmsMessage() == EFalse)  && observer->GetLocalAddress().SmsAddrFamily() != ESmsAddrRecvAny)
+		{
+			iReassemblyStore->DeleteMessageL(aSmsMessage, EFalse);
+			ret=KErrInUse;                
+			// used to signal to client that there is nothing to be done on reassembly store
+			// and code different from KErrNone will do - won't be propagated
+		}
+		else if(ret == KErrNotFound && observer->GetLocalAddress().SmsAddrFamily() != ESmsAddrRecvAny)
+			{
+			if ( iBootTimer && !iBootTimer->IsActive() && (aOriginalSmsAddr==NULL || aOriginalSmsAddr->SmsAddrFamily() != ESmsAddrRecvAny))
+ 				{
+				TSmsAddr addr;
+				addr.SetSmsAddrFamily(ESmsAddrRecvAny);
+				ret = ProcessMessageL(aSmsMessage, &addr, NULL, aDes);
+				}
+			}
+		}
+	else
+		{
+        ret=KErrNotReady; // Observers are not ready
+		}
+	return ret;
+	} // CSmsProtocol::ProcessMessageL
+
+
+/**
+ *  Deletes one or more PDUs from phone or SIM memory.
+ *  The PDUs are added to the deletion queue.  If this queue is empty, the deletion
+ *  state machine is started.
+ *  
+ *  @param aSlotArray
+ */
+void CSmsProtocol::DeletePDUs(const CArrayFix<TGsmSmsSlotEntry>& aSlotArray, MSmsMessageObserver* aObserver)
+	{
+	LOGSMSPROT3("CSmsProtocol::DeletePDUs [count=%d aObserver=0x%08X", aSlotArray.Count(), aObserver);
+	__ASSERT_DEBUG(aSlotArray.Count() != 0, SmspPanic(KSmspSlotArrayEmpty));
+
+	for(TInt i=0; i< aSlotArray.Count() ;i++)
+		{
+		LOGSMSPROT3("CSmsProtocol::DeletePDUs index: %d store %S", aSlotArray[i].iIndex, &aSlotArray[i].iStore);
+		}
+
+	if (iDeleteQueue != NULL && aSlotArray.Count() != 0)
+		{
+		iDeleteQueue->Queue(aSlotArray, aObserver);
+		}
+	} // CSmsProtocol::DeletePDUs
+
+/**
+ *  Called when the modem detection state has changed.
+ *  If a modem has connection has just been made, a number of event monitoring
+ *  state machines are restarted, and as is the bearer setting state machine.
+ *  If the the modem connection was lost, outstanding operations are cancelled.
+ *  
+ */
+void CSmsProtocol::ModemNotificationCompleted(TInt aStatus,
+											  RPhone::TModemDetection aNewState)
+	{
+	LOGSMSPROT3("CSmsProtocol::ModemNotificationCompleted(): aStatus=%d, aNewState=%d",
+				aStatus, aNewState);
+
+	TBool stateChanged = EFalse;
+
+	if (aStatus==KErrNone)
+		{
+		switch (iModemDetection)
+			{
+			//
+			// it goes from OFF to ON
+			//
+			case RPhone::EDetectedNotPresent:
+			case RPhone::EDetectedUnknown:
+				{
+				LOGSMSPROT1("RPhone::EDetectedNotPresent: [OFF -> ON]");
+				if (aNewState==RPhone::EDetectedPresent)
+					{
+					// There is a new modem connection
+					iModemDetection=aNewState;
+					stateChanged = ETrue;
+					}
+				break;
+				}
+			//
+			// it goes from ON to OFF
+			//
+			case RPhone::EDetectedPresent:
+				{
+				LOGSMSPROT1("RPhone::EDetectedPresent: [ON -> OFF]");
+				if (aNewState!=RPhone::EDetectedPresent)
+					{
+					// Ah, lost our modem - cancel outstanding operations
+					iModemDetection=aNewState;
+					stateChanged = ETrue;
+					}
+				break;
+				}
+			default:
+				{
+				__ASSERT_DEBUG(EFalse,SmspPanic(KSmspPanicUnknownModemDetection));
+				}
+			}
+
+		if (iModemDetection == RPhone::EDetectedPresent && !iBackupRestoreSession->IsBackupOrRestoreInProgress())
+			{
+			if (stateChanged || iState == EPoweredDown)
+				{
+				PowerUp();
+				}
+			}
+		else if (stateChanged || iState != EPoweredDown)
+			{
+			PowerDown();
+			}
+		}
+	} // CSmsProtocol::ModemNotificationCompleted
+
+
+void CSmsProtocol::DiskSpaceMonitorStateChange(TSmsDiskSpaceMonitorStatus aStatus)
+/**
+ * Called when the Disk Space Monitor state has changed.
+ */
+	{
+	LOGSMSPROT2("CSmsProtocol::DiskSpaceMonitorStateChange(): aStatus=%d", aStatus);
+
+	RProperty::Set(KUidPSSMSStackCategory, KUidPSSMSStackDiskSpaceMonitorKey, aStatus);
+	} // CSmsProtocol::DiskSpaceMonitorStateChange
+
+
+/**
+ *  Called when all message send requests have completed.
+ *  Increments the number of segmentation store accesses and purges the store
+ *  if it exceeds CSmsProtocol::KNumSARStoreAccessesBeforePurging.
+ */
+void CSmsProtocol::MessageSendCompleted(TInt aStatus)
+	{
+	LOGSMSPROT3("*** CSmsProtocol::MessageSendCompleted [aStatus=%d iNumSegmentationStoreAccesses=%d]", aStatus, iNumSegmentationStoreAccesses);
+    (void) aStatus;
+	iNumSegmentationStoreAccesses++;
+	if (iNumSegmentationStoreAccesses>=KNumSARStoreAccessesBeforePurging)
+		{
+		LOGSMSPROT1("iSegmentationStore->PurgeL Start");
+		TRAPD(ret, iSegmentationStore->PurgeL(iSmsSettings.KSegmentationLifetimeMultiplier(),EFalse));
+		if(ret!=KErrNone)
+			{
+			// we need to close the file because the function
+			// left with the file opened
+			// iSegmentationStore->CloseFile();
+			LOGSMSPROT2("WARNING! iSegmentationStore->PurgeL left with %d", ret);
+			}
+		iNumSegmentationStoreAccesses=0;
+		LOGSMSPROT2("iSegmentationStore->PurgeL End [ret=%d]", ret);
+		}
+	} // CSmsProtocol::KNumSARStoreAccessesBeforePurging
+
+
+/**
+ *  Called when the state machine for enumerating messages on the
+ *  phone has completed.  Notifies the SAP that made the request.
+ *  
+ */
+void CSmsProtocol::PhoneEnumerationCompleted(TInt aStatus)
+	{
+	LOGSMSPROT1("CSmsProtocol::PhoneEnumerationCompleted");
+	iPhoneEnumerationObserver->EnumeratePhoneCompleted(aStatus);
+	} // CSmsProtocol::PhoneEnumerationCompleted
+
+
+/**
+ *  Called by CProtocolBase::Close() to handle any delayed shutdown.
+ *  If there are messages in the deletion queue then the shut down flag
+ *  is set, otherwise CProtocolBase::CanClose() is called to finish closing.
+ *  
+ */
+void CSmsProtocol::CloseNow()
+	{
+	LOGSMSPROT1("CSmsProtocol::CloseNow");
+	if (iDeleteQueue != NULL && iDeleteQueue->IsActive())
+		SetClosingDown(ETrue);
+	else
+		CanClose();
+	} // CSmsProtocol::CloseNow
+
+
+/**
+ *  Private constructor.
+ *  
+ */
+CSmsProtocol::CSmsProtocol()
+	:iSmsMessageObserverList(8)
+	,iModemDetection(RPhone::EDetectedUnknown)
+	{
+	iSmsSettings.SetDeletePDUsFromSIM(EFalse);
+	iSmsSettings.SetDeletePDUsFromPhoneStores(EFalse);
+	iSmsSettings.SetDeletePDUsFromCombinedStores(EFalse);
+	iNext8BitPort=KMin8BitPortNumber;
+	iNext16BitPort=KMin16BitPortNumber;
+	} // CSmsProtocol::CSmsProtocol
+
+
+/**
+ *  Returns the index of an observer in the observer list.
+ *  
+ */
+TInt CSmsProtocol::ObserverIndex(const MSmsMessageObserver& aObserver) const
+	{
+	LOGSMSPROT1("CSmsProtocol::ObserverIndex()");
+
+	TInt count=iSmsMessageObserverList.Count();
+	TInt index=0;
+	for (; index<count; index++)
+		if (iSmsMessageObserverList[index]==&aObserver)
+			break;
+	return index;
+	} // CSmsProtocol::ObserverIndex
+
+
+/**
+ *  Checks if an SMS address type is a duplicate of an existing SAP / observer.
+ *  
+ */
+TBool CSmsProtocol::SmsAddrIsAlreadyUsed(const MSmsMessageObserver* aObserver,const TSmsAddr& aSmsAddr)const
+	{
+	LOGSMSPROT1("CSmsProtocol::SmsAddrIsAlreadyUsed()");
+
+	TBool isduplicate=EFalse;
+	TInt count=iSmsMessageObserverList.Count();
+	for (TInt i=0; (i<count) && (!isduplicate); i++)
+		isduplicate=(iSmsMessageObserverList[i]->SmsAddrIsDuplicate(aObserver,aSmsAddr));
+	return isduplicate;
+	} // CSmsProtocol::SmsAddrIsAlreadyUsed
+
+
+/**
+ *  A utility class for prioritizing the SMS protocol observers based
+ *  on their SMS address type.
+ *  A higher priority observer will be given the opportunity to
+ *  accept a received messages before one of a lower priority.
+ */
+class TKeySmsObserver : public TKeyArrayFix
+	{
+public:
+	TKeySmsObserver();
+	virtual TInt Compare(TInt aLeft,TInt aRight) const;
+	static TInt SmsAddressPriority(const TSmsAddr& aAddr);
+	};
+
+
+/**
+ *  Constructor
+ *  
+ */
+TKeySmsObserver::TKeySmsObserver()
+	:TKeyArrayFix(0,ECmpTInt)
+	{
+	iKeyOffset = 0;
+	} // TKeySmsObserver::TKeySmsObserver
+
+
+/**
+ *  Static method that returns the priority of a given SMS address.
+ *  
+ *  @leave Panics on an unknown address type.
+ *  
+ */
+TInt TKeySmsObserver::SmsAddressPriority(const TSmsAddr& aAddr)
+	{
+	TSmsAddrFamily fam = aAddr.SmsAddrFamily();
+
+	switch (fam)
+		{
+		case ESmsAddrEmail:
+			return 11;
+		case ESmsAddrApplication8BitPort:
+			return 10;
+		case ESmsAddrApplication16BitPort:
+			return 9;
+		case ESmsAddrMessageIndication:
+			return 8;
+		case ESmsAddrStatusReport:
+			return 7;
+		case ESmsAddrMatchIEI:
+			return 6;
+		case ESmsAddrMatchText:
+			return 5;
+		case ESmsAddrRecvAny:
+			return 4;
+		case ESmsAddrSendOnly:
+			return 3;
+		case ESmsAddrLocalOperation:
+			return 2;
+		case ESmsAddrUnbound:
+			return 1;
+		default:
+			SmspPanic(ESmspUnknownSmsAddressFamily);
+		};
+	return KErrNotFound;
+	} // TKeySmsObserver::SmsAddressPriority
+
+
+/**
+ *  Compares two observers.
+ *  Override of TKeyArrayFix::Compare() called on to help sort
+ *  the observer list based on their address types.
+ *  
+ */
+TInt TKeySmsObserver::Compare(TInt aLeft, TInt aRight) const
+	{
+	LOGSMSPROT3("TKeySmsObserver::Compare [left=%d, right=%d]", aLeft, aRight);
+
+	const TInt lhptr = -1; // Left higher priority than right
+	const TInt rhptl = 1; // Right higher priority than left
+
+	MSmsMessageObserver* left = *(MSmsMessageObserver**)At(aLeft);
+	MSmsMessageObserver* right = *(MSmsMessageObserver**)At(aRight);
+
+	const TSmsAddr& leftAddr = left->GetLocalAddress();
+	const TSmsAddr& rightAddr = right->GetLocalAddress();
+
+	TSmsAddrFamily leftFamily = leftAddr.SmsAddrFamily();
+
+
+	TInt leftPriority = SmsAddressPriority(leftAddr);
+	TInt rightPriority = SmsAddressPriority(rightAddr);
+
+	if (leftPriority > rightPriority)
+		return lhptr;
+	if (rightPriority > leftPriority)
+		return rhptl;
+
+	if (leftFamily == ESmsAddrMatchText)
+		{
+		// Longer strings are higher priority than shorter ones
+		TInt rightLen = rightAddr.TextMatch().Length();
+		TInt leftLen = leftAddr.TextMatch().Length();
+		if (leftLen > rightLen)
+			return lhptr;
+		if (rightLen > leftLen)
+			return rhptl;
+		}
+
+	return 0;
+	} // TKeyArrayFix::Compare
+
+
+/**
+ *  Re-orders the observer list using TKeySmsObserver to determine priorities.
+ *  
+ */
+void CSmsProtocol::OrderSmsMessageObserver(const MSmsMessageObserver& /*aObserver*/)
+	{
+	LOGSMSPROT1("CSmsProtocol::OrderSmsMessageObserver()");
+
+	TKeySmsObserver smsObsKey;
+#ifdef _DEBUG
+	TInt ret=iSmsMessageObserverList.Sort(smsObsKey);
+	__ASSERT_DEBUG(ret==KErrNone,SmspPanic(ESmspCorruptObserverList));
+#else
+    iSmsMessageObserverList.Sort(smsObsKey);
+#endif
+	} // CSmsProtocol::OrderSmsMessageObserver
+
+
+/**
+ *  Attempts to match an incoming message to a SAP / observer.  Starts with the
+ *  highest priority observer.
+ *  
+ */
+MSmsMessageObserver* CSmsProtocol::MatchSmsMessageToObserver(const CSmsMessage& aSmsMessage)
+	{
+	LOGSMSPROT1("CSmsProtocol::MatchSmsMessageToObserver()");
+
+	TInt count=iSmsMessageObserverList.Count();
+	for (TInt i=0;i<count;i++)
+		{
+		MSmsMessageObserver* obs = iSmsMessageObserverList[i];
+		if (IsMatch(obs->GetLocalAddress(),aSmsMessage))
+			return obs;
+		}
+	return NULL;
+	} // CSmsProtocol::MatchSmsMessageToObserver
+
+
+/**
+ *  Tries to match an SMS address to a SAP / observer.  Starts with the highest
+ *  priority observer.
+ *  
+ */
+MSmsMessageObserver* CSmsProtocol::MatchSmsAddressToObserver(const TSmsAddr& aAddr)
+	{
+	LOGSMSPROT1("CSmsProtocol::MatchSmsAddressToObserver()");
+
+	TInt count=iSmsMessageObserverList.Count();
+	for (TInt i=0;i<count;i++)
+		{
+		MSmsMessageObserver* obs = iSmsMessageObserverList[i];
+		if (obs->GetLocalAddress()==aAddr)
+			return obs;
+		}
+	return NULL;
+	} // CSmsProtocol::MatchSmsAddressToObserver
+
+
+/**
+ *  Static function checks if a message is matched to a given SMS address type.	Used by
+ *  MatchSmsMessageToObserver() to find a matching observer for the message.
+ *  
+ */
+TBool CSmsProtocol::IsMatch(const TSmsAddr& aSmsAddr, const CSmsMessage& aSmsMessage)
+	{
+	LOGSMSPROT1("CSmsProtocol::IsMatch()");
+
+	TSmsAddrFamily family = aSmsAddr.SmsAddrFamily();
+
+	switch(family)
+	{
+		case (ESmsAddrUnbound):
+		case (ESmsAddrSendOnly):
+		case(ESmsAddrLocalOperation):
+			return EFalse;
+
+		case(ESmsAddrApplication8BitPort ):
+			{
+			return (MatchApplicationPort(aSmsMessage,aSmsAddr.Port(),EFalse));
+			}
+
+		case (ESmsAddrApplication16BitPort ):
+			{
+			return(MatchApplicationPort(aSmsMessage,aSmsAddr.Port(),ETrue));
+			}
+
+		case (ESmsAddrMessageIndication):
+			{
+			if (MatchInformationElement(aSmsMessage,CSmsInformationElement::ESmsIEISpecialSMSMessageIndication))
+				return ETrue;
+			if (aSmsMessage.SmsPDU().DataCodingSchemePresent())
+				{
+				TSmsDataCodingScheme::TSmsDCSBits7To4 bits7to4 = aSmsMessage.SmsPDU().Bits7To4();
+				switch (bits7to4)
+					{
+					case TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationDiscardMessage:
+					case TSmsDataCodingScheme::ESmsDCSMessageWaitingIndication7Bit:
+					case TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationUCS2:
+						return ETrue;
+					default:
+						break;
+					}
+				}
+			// CPHS Implementation of message waiting indicator (CPHS Phase 2)
+			TGsmSmsTelNumber address;
+			aSmsMessage.ParsedToFromAddress(address);
+
+			//as far as I can see you can't get the npi from the address. (==0?)
+			//might want to compare the content of the tel number with the spec to make sure
+			//that we are dealing with a cphs message !
+
+			if((address.iTypeOfAddress.TON() == EGsmSmsTONAlphaNumeric)  &&
+				(address.iTelNumber.Length() == 4) &&
+					((address.iTelNumber[2] & 0x7E) == 0x10)  &&// x001 000x constant value
+						((address.iTelNumber[3] & 0x7E) == 0x00) )// x000 000x constant value
+						return ETrue; // This means that the SMS received is a Message Waiting indication
+			return EFalse;
+			}
+
+		case (ESmsAddrStatusReport):
+			{
+			LOGSMSPROT1("TSmsDataCodingScheme::ESmsDCSMessageWaitingIndicationDiscardMessage:");
+			if (aSmsMessage.Type() == CSmsPDU::ESmsStatusReport)
+				return ETrue;
+			}
+			break;
+		case (ESmsAddrMatchIEI):
+			{
+			return (MatchInformationElement(aSmsMessage,CSmsInformationElement::TSmsInformationElementIdentifier(aSmsAddr.IdentifierMatch())));
+			}
+		case (ESmsAddrMatchText):
+			{
+			TBuf<TSmsAddr::EMaxTextMatchLength> textMatch;
+			textMatch.Copy(aSmsAddr.TextMatch());
+			TBuf<TSmsAddr::EMaxTextMatchLength> smsMsgBuf;
+			TInt bufferLen = aSmsMessage.Buffer().Length();
+			bufferLen = Min(bufferLen,textMatch.Length());
+			aSmsMessage.Buffer().Extract(smsMsgBuf,0,bufferLen);
+			if (textMatch.CompareF(smsMsgBuf)==KErrNone)
+				return ETrue;
+			return EFalse;
+			}
+		case (ESmsAddrEmail):
+			{
+			if(aSmsMessage.IsEmailHeader())
+	 			return ETrue;
+			break;
+			}
+		case (ESmsAddrRecvAny):
+			return ETrue;
+		default:
+			return EFalse;
+
+		}
+	return EFalse;
+	} // CSmsProtocol::IsMatch
+
+/**
+ *  Static function checks if a message contains a given port.  Used by IsMatch()
+ *  to determine if an SMS address type matches an application port.
+ *  
+ */
+TBool CSmsProtocol::MatchApplicationPort(const CSmsMessage& aSmsMessage,TUint aPort,TBool a16Bit)
+	{
+	LOGSMSPROT1("CSmsProtocol::MatchApplicationPort");
+
+	if (!aSmsMessage.SmsPDU().UserDataPresent())
+		return EFalse;
+
+	const CSmsPDU& Pdu = aSmsMessage.SmsPDU();
+	TInt ToPort = 0;
+	TInt FromPort = 0;
+	TBool Is16BitPorts = 0;
+
+    Pdu.ApplicationPortAddressing(ToPort,FromPort,&Is16BitPorts);
+	if((TInt)aPort == ToPort && Is16BitPorts == a16Bit) return ETrue;
+
+	return EFalse;
+	} // CSmsProtocol::MatchApplicationPort
+
+
+/**
+ *  Static function checks if a message contains a given information element.  Used by IsMatch()
+ *  to determine if an SMS address type matches a message.
+ *  
+ */
+TBool CSmsProtocol::MatchInformationElement(const CSmsMessage& aSmsMessage, CSmsInformationElement::TSmsInformationElementIdentifier aIeVal)
+	{
+	LOGSMSPROT1("CSmsProtocol::MatchInformationElement");
+
+	if (!aSmsMessage.SmsPDU().UserDataPresent())
+		return EFalse;
+
+	TInt count=aSmsMessage.SmsPDU().UserData().NumInformationElements();
+	for (TInt i=0; i<count; i++)
+		{
+		TInt identifier=aSmsMessage.SmsPDU().UserData().InformationElement(i).Identifier();
+		if (identifier==aIeVal)
+			return ETrue;
+		}
+	return EFalse;
+	} // CSmsProtocol::MatchInformationElement
+
+
+/**
+ *  Searches the reassembly store for complete messages and tries to match
+ *  them to an observer.  If a match is found the message is passed to
+ *  the observer and deleted from the store, otherwise it's left in store.
+ *  Called when a new observer is added or a PDU has been received and
+ *  successfully processed.
+ *  
+ */
+void CSmsProtocol::ProcessCompleteSmsMessagesL()
+	{
+	LOGSMSPROT1("CSmsProtocol::ProcessCompleteSmsMessagesL");
+
+	if(iPhoneEnumerationObserver) return;
+
+	iReassemblyStore->ProcessCompleteSmsMessagesL(*this, iSmsPDURead->CurrentMessage());
+	} // CSmsProtocol::ProcessCompleteSmsMessagesL
+
+
+/**
+ *  Called when the state machine for processing a received PDU has completed.
+ *  The reassembly store access count is incremented and purged if it exceeds
+ *  CSmsProtocol::KNumSARStoreAccessesBeforePurging.
+ *  The completed entry is removed from the processing queue and if the queue is
+ *  not empty, and the processing state machinery is started for the next entry.
+ *  
+ */
+void CSmsProtocol::MessageReadedSuccessfully()
+	{
+	LOGSMSPROT1("CSmsProtocol::MessageReadedSuccessfully");
+	TRAPD(ret,ProcessCompleteSmsMessagesL());
+	if(ret!=KErrNone)
+		{
+		LOGSMSPROT2("WARNING! CSmsProtocol::ProcessCompleteSmsMessagesL left with %d", ret);
+		}
+
+	iNumReassemblyStoreAccesses++;
+	if(iNumReassemblyStoreAccesses>=KNumSARStoreAccessesBeforePurging)
+		{
+		TRAP(ret, iReassemblyStore->PurgeL(iSmsSettings.ReassemblyLifetime(),EFalse));
+
+		if(ret!=KErrNone)
+			{
+			LOGSMSPROT2("WARNING! iReassemblyStore->PurgeL left with %d", ret);
+			}
+
+		iNumReassemblyStoreAccesses=0;
+		}
+	if(CheckPoweredUp() == KErrNone )
+		iSmsPDURead->ResumeSmsReception();
+	} // CSmsProtocol::MessageReadedSuccessfully
+
+
+/**
+ *  method to delete sms from the reastore
+ */
+void CSmsProtocol::DeleteSMSFromReaStoreL(const CSmsMessage& aSmsMessage)
+	{
+	LOGSMSPROT1("CSmsProtocol::DeleteSMSFromReaStoreL entry");
+	if (aSmsMessage.Type() == CSmsPDU::ESmsStatusReport)
+	{
+		LOGSMSPROT1("CSmsProtocol::DeleteSMSFromReaStoreL it's SR");
+		return;
+	}
+
+	TSmsDataCodingScheme::TSmsClass  msgClass;
+
+	if (aSmsMessage.SmsPDU().DataCodingSchemePresent()	&&	aSmsMessage.SmsPDU().Class(msgClass))
+		{
+		if (msgClass == TSmsDataCodingScheme::ESmsClass0)
+			{
+			if (!aSmsMessage.IsComplete())
+				{
+				CIncompleteClass0MessageInfo& incompleteClass0MsgInfo = (CIncompleteClass0MessageInfo &) aSmsMessage.GetOperationsForNonIEL(ESmsIncompleteClass0MessageParameter);
+				// Retrieve incomplete class 0 message information & process
+				TInt startPos, endPos;
+				TBool isLastMessage;
+				incompleteClass0MsgInfo.GetIncompleteMessageInfoL(startPos, endPos, isLastMessage);
+				if (!isLastMessage)
+					{
+					/*
+					Only in this condition set incomplete message as forwarded
+					which internally will remove the PDUs from pre-allocated file.
+					*/
+					LOGSMSPROT1("CSmsProtocol::DeleteSMSFromReaStoreL Incomplete Message Not last segment");
+					iReassemblyStore->SetIncompleteMessageForwardedToClientL(aSmsMessage);
+					return;
+					}
+				}
+			}
+		}
+	iReassemblyStore->DeleteMessageL(aSmsMessage, ETrue);
+
+	LOGSMSPROT1("CSmsProtocol::DeleteSMSFromReaStoreL exit");
+	} // CSmsProtocol::DeleteSMSFromReaStoreL
+
+
+/**
+ *  Used to notify observer of the change in state of the modem connection.
+ *  Send only observers are not notified (why?).
+ */
+void CSmsProtocol::NotifyMessageObservers(TInt aStatus)
+	{
+	LOGSMSPROT1("CSmsProtocol::NotifyMessageObservers");
+
+	TInt count=iSmsMessageObserverList.Count();
+	LOGSMSPROT3("CSmsProtocol::NotifyMessageObservers [count=%d, aStatus=%d]",count, aStatus);
+	for (TInt index=0; index<count; index++)
+		{
+		MSmsMessageObserver* observer=iSmsMessageObserverList[index];
+		TSmsAddrFamily fam = observer->GetLocalAddress().SmsAddrFamily();
+	    LOGSMSPROT2("CSmsProtocol::NotifyMessageObservers [family=%d]", fam);
+		switch (fam)
+			{
+			case ESmsAddrMessageIndication:
+			case ESmsAddrStatusReport:
+			case ESmsAddrMatchIEI:
+			case ESmsAddrMatchText:
+			case ESmsAddrEmail:
+			case ESmsAddrRecvAny:
+			case ESmsAddrLocalOperation:
+			case ESmsAddrApplication8BitPort:
+	        case ESmsAddrApplication16BitPort:
+				{
+				observer->ModemNotificationCompleted(aStatus);
+				break;
+				}
+			case ESmsAddrSendOnly:
+			case ESmsAddrUnbound:
+				break;
+			default:
+				SmspPanic(ESmspPanicAddrFamilyNotAllowed);
+			}
+		}
+	} // CSmsProtocol::NotifyMessageObservers
+
+
+void CSmsProtocol::PowerUp()
+	{
+	LOGSMSPROT2("CSmsProtocol::PowerUp [iState=%d]", iState);
+	__ASSERT_DEBUG(iState == EPoweredDown, SmspPanic(KSmspPanicUnexpectedState));
+
+	if (iState == EPoweredDown)
+		{
+		TRAPD(err, DoPowerUpL());
+
+		if (err != KErrNone)
+			{
+			LOGSMSPROT3("WARNING: CSmsProtocol::DoPowerUpL left [err=%d iState=%d]", err, iState);
+			__ASSERT_DEBUG(iState == EPoweredDown, SmspPanic(KSmspPanicUnexpectedState));
+			PowerDown();
+			}
+		}
+	} // CSmsProtocol::PowerUp
+
+
+/**
+ *  Handles the event of the modem powering on (when it had been powered off).
+ *  Does the following...
+ *  - The TSY loaded
+ *  - ETEL resource handles initialised
+ *  - ETEL parameters set and retrieved
+ *  - A number of state machines started
+ *  
+ */
+void CSmsProtocol::DoPowerUpL()
+	{
+	LOGSMSPROT1("CSmsProtocol::DoPowerUpL");
+	__ASSERT_DEBUG(iModemDetection==RPhone::EDetectedPresent,SmspPanic(KSmspPhoneHasNotTurnedOn));
+
+	//Open the segmentation and reassembly stores
+
+	iReassemblyStore->OpenStoreL();
+	iSegmentationStore->OpenStoreL();
+	LOGSMSPROT1("CSmsProtocol::DoPowerUpL->PurgeL Start");
+	iReassemblyStore->PurgeL(iSmsSettings.ReassemblyLifetime(), ETrue);
+	LOGSMSPROT1("CSmsProtocol::DoPowerUpL->PurgeL End");
+	LOGSMSPROT1("CSmsProtocol::DoPowerUpL->PurgeL Start");
+	iSegmentationStore->PurgeL(iSmsSettings.KSegmentationLifetimeMultiplier(),EFalse);
+	LOGSMSPROT1("CSmsProtocol::DoPowerUpL->PurgeL End");
+
+	// Connect to ETEL and load the TSY
+	User::LeaveIfError(iTelServer.Connect());
+	User::LeaveIfError(iTelServer.LoadPhoneModule(iGsmTsyName));
+	LOGSMSPROT1("CSmsProtocol::DoPowerUpL  Connected to Etel");
+
+	// Find the phone corresponding to this TSY and open a number of handles on it
+	TInt numPhones;
+	User::LeaveIfError(iTelServer.EnumeratePhones(numPhones));
+	TInt i=0;
+	for (; i<numPhones; i++)
+		{
+		RTelServer::TPhoneInfo info;
+		User::LeaveIfError(iTelServer.GetPhoneInfo(i,info));
+		TName tsyName;
+		User::LeaveIfError(iTelServer.GetTsyName(i,tsyName));
+		if (tsyName.CompareF(iGsmTsyName)==KErrNone)
+			{
+			User::LeaveIfError(iGsmPhone.Open(iTelServer,info.iName));
+			User::LeaveIfError(iEnumerationPhone.Open(iTelServer,info.iName));
+			User::LeaveIfError(iWritePhone.Open(iTelServer,info.iName));
+			break;
+			}
+		}
+	__ASSERT_DEBUG(i<numPhones,SmspPanic(ESmspPhoneNotFound));
+	if (iTelServer.SetExtendedErrorGranularity(RTelServer::EErrorExtended)!=KErrNone)
+		User::LeaveIfError(iTelServer.SetExtendedErrorGranularity(RTelServer::EErrorBasic));
+	User::LeaveIfError(iSmsMessaging.Open(iGsmPhone));
+
+	LOGSMSPROT1("CSmsProtocol::DoPowerUpL  Opened TSY handles");
+
+	if (iSmsPhoneEnumeration == NULL)
+		iSmsPhoneEnumeration=CSmsPhoneEnumeration::NewL(*this, iSmsSettings, *iReassemblyStore, *iSegmentationStore, iEnumerationPhone, KSmsSessionPriority, *iSmsMonitorDiskSpace);
+
+	if (iWriteQueue == NULL)
+		iWriteQueue = CSmspWriteQueue::NewL(*this, iSmsSettings, iWritePhone,*iSegmentationStore, KSmsSessionPriority);
+
+	if (iDeleteQueue == NULL)
+		iDeleteQueue = CSmspDeleteQueue::NewL(*this,iSmsSettings,iSmsMessaging, KSmsSessionPriority);
+
+	// Start state machines
+	iSmsPhoneInitialization->Start();
+
+	LOGSMSPROT1("CSmsProtocol::DoPowerUpL  Started state machines");
+
+	NotifyMessageObservers(KIoctlSelectModemPresent);
+	LOGSMSPROT1("CSmsProtocol::DoPowerUpL  Notified message observers");
+
+
+	// Process any waiting messages
+	ProcessCompleteSmsMessagesL();
+
+	iState = EPoweredUp;
+	} // CSmsProtocol::DoPowerUpL
+
+
+/**
+ *  Handles the event of the modem powering off (when it had been powered on).
+ *  Does the following...
+ *  - State mechines cancelled
+ *  - Close TSY handles
+ *  - Disconnect from Etel
+ *  
+ *  This function will also be called if PowerUpL() leaves
+ */
+void CSmsProtocol::PowerDown()
+    {
+    LOGSMSPROT1("CSmsProtocol::PowerDown");
+    
+    iSetBearer->Cancel();
+    iReceiveMode->Cancel();
+    
+    iSendQueue->Cancel();
+    
+    iSmsPDURead->Cancel();
+    
+    iSmsMonitorDiskSpace->Cancel();
+    
+    delete iSmsPhoneEnumeration; //must be deleted because uses iSmsMessaging which is soon closed
+    iSmsPhoneEnumeration = NULL;
+    
+    iSmsPhoneInitialization->Cancel();
+    
+    if( iSmsReadParams != NULL )
+        {
+        iSmsReadParams->Cancel();
+        }
+    if( iSmsWriteParams != NULL )
+        {
+        iSmsWriteParams->Cancel();
+        }
+    
+    delete iWriteQueue; //must be deleted because uses iSmsMessaging which is soon closed
+    iWriteQueue = NULL;
+    
+    delete iDeleteQueue; //must be deleted because uses iSmsMessaging which is soon closed
+    iDeleteQueue = NULL;
+    
+    LOGSMSPROT1("CSmsProtocol::PowerDown  Cancelled state machines");
+    
+    NotifyMessageObservers(KIoctlSelectModemNotPresent);
+    LOGSMSPROT1("CSmsProtocol::PowerDown  Notified message observers");
+    
+    // Close TSY handles
+    iSmsMessaging.Close();
+    iGsmPhone.Close();
+    iEnumerationPhone.Close();
+    iWritePhone.Close();
+    LOGSMSPROT1("CSmsProtocol::PowerDown  Closed TSY handles");
+    
+    // Disconnect from Etel
+    iTelServer.Close();
+    LOGSMSPROT1("CSmsProtocol::PowerDown  Disconnected from Etel");
+    
+    iReassemblyStore->Close();
+    iSegmentationStore->Close();
+    
+    iState = EPoweredDown;
+    }
+
+void CSmsProtocol::CloseNowWrap()
+    {
+    // Ignore in code coverage - called when PDU delete queue is not 
+    // empty and SMS stack is closing down - can only get this situation
+    // when the PDU delete has been initiated by the SMS stack itself 
+    // (rather than the client) and the PDUs are still being deleted 
+    // when last client disconnects.
+    BULLSEYE_OFF
+    LOGSMSPROT1("CSmsProtocol::CloseNowWrap()");
+    
+    if( iDeleteQueue == NULL || !iDeleteQueue->IsActive() )
+        {
+        CloseNow();
+        }
+    BULLSEYE_RESTORE
+    }
+
+void CSmsProtocol::HandleBackupOrRestoreStartingL()
+    {
+    LOGSMSPROT2("CSmsProtocol::HandleBackupOrRestoreStartingL [ModemState=%d]",  iSmsModemNotification->ModemState());
+    PowerDown();
+    }
+
+void CSmsProtocol::HandleBackupOrRestoreCompleteL()
+    {
+    LOGSMSPROT2("CSmsProtocol::HandleBackupOrRestoreCompleteL [ModemState=%d]", iSmsModemNotification->ModemState());
+    
+    if (iModemDetection == RPhone::EDetectedPresent)
+        {
+        PowerUp();
+        }
+    }
+
+/**
+ *  Set the sap port number
+ */
+TBool CSmsProtocol::AllocateLocalAddress(TSmsAddr& aAddr)
+	{
+    LOGSMSPROT1("CSmsProtocol::AllocateLocalAddressL");
+
+	TBool found=EFalse;
+	TUint count=0,attempts=0;
+	TSmsAddr locAddr=aAddr;
+
+	if(locAddr.SmsAddrFamily() == ESmsAddrApplication8BitPort )
+		{
+		count =KMax8BitPortNumber-KMin8BitPortNumber+1;
+		}
+	else if(locAddr.SmsAddrFamily() == ESmsAddrApplication16BitPort )
+		{
+		count =KMax16BitPortNumber-KMin16BitPortNumber+1;
+		}
+
+	for(;!found && attempts < count; ++attempts)
+		{
+		if(locAddr.SmsAddrFamily() == ESmsAddrApplication8BitPort )
+			{
+			locAddr.SetPort(iNext8BitPort++);
+			if(iNext8BitPort > KMax8BitPortNumber)iNext8BitPort=KMin8BitPortNumber;
+			}
+		else if(locAddr.SmsAddrFamily() == ESmsAddrApplication16BitPort )
+			{
+			locAddr.SetPort(iNext16BitPort++);
+			if(iNext16BitPort > KMax16BitPortNumber)iNext8BitPort=KMin16BitPortNumber;
+			}
+		if(!SmsAddrIsAlreadyUsed(NULL,locAddr))found=ETrue;
+		}
+
+	if(found)
+		{
+		aAddr=locAddr;
+		}
+	return found;
+	} // CSmsProtocol::AllocateLocalAddress
+
+/**
+ *  Static method that returns the boolean value indicating whether the given
+ *  CSmsMessage is for application port.
+ *  This function is an utility function which determines the passed sms message
+ *  is for application port or not. This function is also used in CFacadeSmsReassemblyStore class.
+ *
+ *  @param aSmsMessage reference to CSmsMessage object.
+ *  
+ */
+TBool CSmsProtocol::IsAppPortSMS(const CSmsMessage& aSmsMessage)
+	{
+	LOGSMSPROT1("CSmsProtocol::IsAppPortSMS()");
+
+	TSmsAddr addr;
+	addr.SetSmsAddrFamily(ESmsAddrMatchIEI);
+	addr.SetIdentifierMatch(CSmsInformationElement::ESmsIEIApplicationPortAddressing8Bit);
+	if (IsMatch(addr,aSmsMessage))
+		{
+		return ETrue;
+		}
+
+	addr.SetSmsAddrFamily(ESmsAddrMatchIEI);
+	addr.SetIdentifierMatch(CSmsInformationElement::ESmsIEIApplicationPortAddressing16Bit);
+	if (IsMatch(addr,aSmsMessage))
+		{
+		return ETrue;
+		}
+
+	addr.SetSmsAddrFamily(ESmsAddrMatchText);
+	addr.SetTextMatch(_L8("//SCK"));
+	if (IsMatch(addr,aSmsMessage))
+		{
+		return ETrue;
+		}
+
+	return EFalse;
+	} // CSmsProtocol::IsAppPortSMS
+
+
+const RMobilePhone::TMobilePhoneNetworkInfoV1& CSmsProtocol::NetworkInfo() const
+	{
+	LOGSMSPROT1("CSmsProtocol::NetworkInfo()");
+
+	return iSmsPhoneInitialization->NetworkInfo();
+	} // CSmsProtocol::NetworkInfo
+
+
+TBool CSmsProtocol::NetworkInfoAvailable() const
+	{
+	LOGSMSPROT1("CSmsProtocol::NetworkInfoAvailable()");
+
+	return iSmsPhoneInitialization->NetworkInfoAvailable();
+	} // CSmsProtocol::NetworkInfoAvailable
+
+
+// implementation of CSmsProtocolBootTimer
+//
+
+/**
+ *  2 phase contructor
+ *  
+ *  @param aActive Reference to an CSmsProtocol object
+ */
+CSmsProtocolBootTimer* CSmsProtocolBootTimer::NewL(CSmsProtocol& aSmsProtocol)
+    {
+    LOGSMSPROT1("CSmsProtocolBootTimer::NewL");
+    
+    CSmsProtocolBootTimer* self = new(ELeave) CSmsProtocolBootTimer(aSmsProtocol);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+    }
+
+/**
+ *  D'tor
+ */
+CSmsProtocolBootTimer::~CSmsProtocolBootTimer()
+    {
+    Cancel();
+    }
+
+/**
+ *  Start a timeout specified in aTimeIntervalMicroSeconds32
+ */
+void CSmsProtocolBootTimer::Start(const TTimeIntervalMicroSeconds32& aTimeIntervalMicroSeconds32)
+	{
+	LOGSMSPROT1("CSmsProtocolBootTimer::Start");
+	After(aTimeIntervalMicroSeconds32);
+	}
+
+/**
+ *  C'tor
+ */
+CSmsProtocolBootTimer::CSmsProtocolBootTimer(CSmsProtocol& aSmsProtocol)
+: CTimer(KSmsSessionPriority), iSmsProtocol(aSmsProtocol)
+    {
+    CActiveScheduler::Add(this);
+    }
+
+/**
+ *  Timer completed - cancel the observer
+ */
+void CSmsProtocolBootTimer::RunL()
+    {
+    LOGSMSPROT2("CSmsProtocolBootTimer::RunL [iStatus=%d]", iStatus.Int() );
+    iSmsProtocol.MessageReadedSuccessfully();
+    }