realtimenetprots/sipfw/ProfileAgent/Server/Src/SipProfileCacheItem.cpp
changeset 0 307788aac0a8
child 2 1e1cc61f56c3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/ProfileAgent/Server/Src/SipProfileCacheItem.cpp	Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,1312 @@
+// Copyright (c) 2008-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:
+// Name        : sipprofilecacheitem.cpp
+// Part of     : SIP Profile Server
+// implementation
+// Version     : 1.0
+//
+
+
+
+// INCLUDE FILES
+#include "SipProfileCacheItem.h"
+#include "SipProfileServerCore.h"
+#include "sipextendedconcreteprofileobserver.h"
+#include "SipProfileState.h"
+#include "SipProfileLog.h"
+#include "sipalrmigrationcontroller.h"
+#include <sipprofile.h>
+#include <cmmanager.h>
+#include<e32const.h>
+
+const TInt KSnapRetryCountThreshold = 3;
+const TUint32 KDefaultSNAPIdentifier = KMaxTUint32;
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::NewL
+// -----------------------------------------------------------------------------
+//
+CSIPProfileCacheItem*
+CSIPProfileCacheItem::NewL(CSIPProfileServerCore& aCore,
+    					   CSIPProfileState* aUnregistered)
+	{
+    CSIPProfileCacheItem* self =
+    	CSIPProfileCacheItem::NewLC(aCore, aUnregistered);
+    CleanupStack::Pop(self);
+    return self;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::NewLC
+// -----------------------------------------------------------------------------
+//
+CSIPProfileCacheItem*
+CSIPProfileCacheItem::NewLC(CSIPProfileServerCore& aCore,
+    						CSIPProfileState* aUnregistered)
+	{
+	CSIPProfileCacheItem* self =
+		new (ELeave) CSIPProfileCacheItem(aCore, aUnregistered);
+    CleanupStack::PushL(self);
+	self->ConstructL();
+    return self;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::CSIPProfileCacheItem
+// -----------------------------------------------------------------------------
+//
+CSIPProfileCacheItem::CSIPProfileCacheItem(CSIPProfileServerCore& aCore,
+									  	   CSIPProfileState* aUnregistered) :
+	iCacheState(ENormal),
+	iCurrentState(aUnregistered),
+	iServerCore(aCore),
+	iMigrationDisallowed(EFalse),
+	iDeltaTimer(0),
+	iDeltaTimerCallBack(DoNewIapFailed, this),
+	iSnapRetryCounter(0)
+#ifdef CPPUNIT_TEST
+    // Use array granularity 1, so each append allocates memory
+    , iObservers(1),
+    iUsers(1),
+    iObserversWaitedForPermission(1)
+#endif
+	{
+	iIsRfsInprogress = EFalse;
+	iDeltaTimerEntry.Set(iDeltaTimerCallBack);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::ConstructL()
+	{
+    iDeltaTimer = CDeltaTimer::NewL(CActive::EPriorityLow);
+	}
+
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::~CSIPProfileCacheItem
+// -----------------------------------------------------------------------------
+//
+CSIPProfileCacheItem::~CSIPProfileCacheItem()
+	{
+	if (iDeltaTimer)
+		{
+		iDeltaTimer->Cancel();
+		}
+	delete iDeltaTimer;
+
+	StopSnapMonitoring();
+
+	iObservers.Reset();
+	iObserversWaitedForPermission.Reset();
+	iUsers.Reset();
+	delete iQueuedProfile;
+	delete iProfile;
+	delete iOldProfile;
+	delete iProfileWithNewIAP;
+	delete iProfileWithOldIAP;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::IapAvailable
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::IapAvailable(TUint32 aSnapId, TUint32 aNewIapId)
+	{
+	iDeltaTimer->Cancel();
+
+	TRAPD(err, iCurrentState->IapAvailableL(*this, aSnapId, aNewIapId));
+	if (err != KErrNone)
+		{
+		iServerCore.HandleProfileError(*this, err);
+		}
+	}
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::MigrationIsAllowedL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::MigrationIsAllowedL(TUint32 aIapId)
+	{
+	iCurrentState->MigrationIsAllowedL(*this, aIapId);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::MigrationIsDisallowedL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::MigrationIsDisallowedL(TUint32 aIapId)
+	{
+	iCurrentState->MigrationIsDisallowedL(*this, aIapId);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ErrorOccurred
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::ErrorOccurred(TInt aError)
+	{
+	HandleError(aError);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::NoNewIapAvailable
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::NoNewIapAvailable()
+	{
+	iCurrentState->NoNewIapAvailable(*this);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::RefreshIAPsFailed
+// This is a fatal error, as profile no longer gets information of new IAPs.
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::RefreshIAPsFailed()
+	{
+	iProfile->SetLastRegistrationError(KErrNoMemory);
+	iCurrentState->RefreshIAPsFailed(*this);
+	SwitchToUnregisteredState();
+	PassAlrErrorToClient(KErrNoMemory, Profile().IapId());
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::SetProfile
+// Set iProfileId only once, then it never changes.
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::SetProfile(CSIPConcreteProfile* aProfile)
+	{
+	__ASSERT_ALWAYS(aProfile, User::Panic(_L("ProfileCacheItem:SetProfile"),
+										  KErrArgument));
+	delete iProfile;
+	iProfile = aProfile;
+
+	if (iProfileId == 0)
+		{
+		iProfileId = iProfile->Id();
+		}
+
+	CheckProfileEnabledState();
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::SetProfileId
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::SetProfileId(TUint aProfileId)
+	{
+	iProfileId = aProfileId;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ProfileId
+// -----------------------------------------------------------------------------
+//
+TUint CSIPProfileCacheItem::ProfileId() const
+	{
+	return iProfileId;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::Profile
+// Return the CSIPConcreteProfile that is most recently registered.
+// -----------------------------------------------------------------------------
+//
+CSIPConcreteProfile& CSIPProfileCacheItem::Profile()
+	{
+	__ASSERT_ALWAYS(iProfile,
+					User::Panic(_L("ProfileCacheItem:Profile"), KErrNotFound));
+	return *iProfile;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::Profile
+// -----------------------------------------------------------------------------
+//
+const CSIPConcreteProfile& CSIPProfileCacheItem::Profile() const
+	{
+	__ASSERT_ALWAYS(iProfile,
+					User::Panic(_L("ProfileCacheItem:ProfileC"), KErrNotFound));
+	return *iProfile;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::LatestProfile
+// Return the CSIPConcreteProfile that includes the most recent updates.
+// -----------------------------------------------------------------------------
+//
+CSIPConcreteProfile& CSIPProfileCacheItem::LatestProfile()
+	{
+	return iQueuedProfile ? *iQueuedProfile : Profile();
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ReferenceCount
+// -----------------------------------------------------------------------------
+//
+TUint CSIPProfileCacheItem::ReferenceCount() const
+	{
+	return iUsers.Count();
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::CacheOldProfile
+// If update is done before a previous update completed, it contains also the
+// earlier update's changes. Some states queue the update. If a new update
+// comes, it is stored and the previous discarded.
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::CacheOldProfile(CSIPConcreteProfile* aNewProfile,
+	const MSIPExtendedConcreteProfileObserver& aObserver)
+	{
+	__ASSERT_ALWAYS(aNewProfile && aNewProfile->Id() == ProfileId(),
+					User::Panic(_L("ProfileCacheItem:CacheOld"), KErrArgument));
+
+	if (iCurrentState->CanProfileBeUpdated(*this))
+		{
+		StoreProfileToUpdate(aNewProfile);
+		return ETrue;
+		}
+
+	delete iQueuedProfile;
+	iQueuedProfile = aNewProfile;
+	iQueuedObserver = &aObserver;
+	return EFalse;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ClearOldProfile
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::ClearOldProfile()
+	{
+	delete iOldProfile;
+	iOldProfile = NULL;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::HasProfileUpdate
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::HasProfileUpdate() const
+	{
+	return iOldProfile != NULL;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::UsedProfile
+// Return the CSIPConcreteProfile that most recently used profile agent to
+// register, deregister or update.
+//
+// iProfileWithNewIAP and iProfileWithOldIAP exist only during ALR migration,
+// and they never exist both at the same time.
+// iProfileWithNewIAP exists only in state CSIPProfileStateMigratingToNewIAP and
+// iProfileWithOldIAP exists only in state CSIPProfileStateUnregisteringOldIAP.
+//
+// iOldProfile exists during an update.
+// -----------------------------------------------------------------------------
+//
+CSIPConcreteProfile& CSIPProfileCacheItem::UsedProfile()
+	{
+	return iProfileWithNewIAP ? *iProfileWithNewIAP :
+		   iProfileWithOldIAP ? *iProfileWithOldIAP :
+		   iOldProfile ? *iOldProfile : Profile();
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::UsedProfile
+// -----------------------------------------------------------------------------
+//
+const CSIPConcreteProfile& CSIPProfileCacheItem::UsedProfile() const
+	{
+	return iProfileWithNewIAP ? *iProfileWithNewIAP :
+		   iProfileWithOldIAP ? *iProfileWithOldIAP :
+		   iOldProfile ? *iOldProfile : Profile();
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::AddObserverL
+// Don't add observer to iObserversWaitedForPermission. It has only observers
+// that were notified of a new IAP.
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::AddObserverL(
+	const MSIPExtendedConcreteProfileObserver& aObserver)
+	{
+	iObservers.AppendL(&aObserver);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::RemoveObserver
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::RemoveObserver(
+	const MSIPExtendedConcreteProfileObserver& aObserver)
+	{
+	TInt index = iObservers.Find(&aObserver);
+	if (index != KErrNotFound)
+		{
+		iObservers.Remove(index);
+		}
+
+	RemoveFromPendingObservers(aObserver);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::Observers
+// -----------------------------------------------------------------------------
+//
+const RPointerArray<MSIPExtendedConcreteProfileObserver>&
+CSIPProfileCacheItem::Observers() const
+	{
+	return iObservers;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::IsObserverOrUser
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::IsObserverOrUser(
+	const MSIPExtendedConcreteProfileObserver& aObserver) const
+	{
+	return (iObservers.Find(&aObserver) != KErrNotFound) || IsUser(aObserver);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::RemoveUser
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::RemoveUser(
+	const MSIPExtendedConcreteProfileObserver& aObserver)
+	{
+	TInt index = iUsers.Find(&aObserver);
+	if (index != KErrNotFound)
+		{
+		iUsers.Remove(index);
+		CheckProfileEnabledState();
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::RemoveAllUsers
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::RemoveAllUsers()
+	{
+	iUsers.Reset();
+    CheckProfileEnabledState();
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::IsUser
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::IsUser(
+	const MSIPExtendedConcreteProfileObserver& aObserver) const
+	{
+	return iUsers.Find(&aObserver) != KErrNotFound;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::MoveToUserL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::MoveToUserL(
+	const MSIPExtendedConcreteProfileObserver& aObserver)
+	{
+	iUsers.AppendL(&aObserver);
+
+	CheckProfileEnabledState();
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::IsActiveState
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::IsActiveState() const
+	{
+	return iCacheState == ENormal;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::HasAorL
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::HasAorL(const TDesC8& aAOR) const
+	{
+    TUriParser8 otherUriparser;
+    User::LeaveIfError(otherUriparser.Parse(aAOR));
+    TInt err = otherUriparser.Equivalent(iProfile->AORUri8());
+    if (err == KErrNoMemory)
+        {
+        User::Leave(err);
+        }
+    return err == KErrNone;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::StartRegisterL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::StartRegisterL(CSIPProfileState& aWaitForIAP,
+										  CSIPProfileState& aRegInProg,
+										  TBool aGetIap)
+	{
+	TUint32 snapId(0);
+		PROFILE_DEBUG3("ProfileCacheItem::StartRegisterL - SNAP ID", snapId)
+	if (aGetIap && IsSNAPConfigured(snapId))
+		{
+		PROFILE_DEBUG3("ProfileCacheItem::StartRegisterL - MONITOR SNAP", snapId)
+		MonitorSnapL(snapId, aWaitForIAP, aRegInProg);
+		}
+	else
+		{
+		PROFILE_DEBUG3("ProfileCacheItem::StartRegisterL - REGISTER", snapId)
+		iCurrentState->RegisterL(*this);
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::EnableL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::EnableL(
+	const MSIPExtendedConcreteProfileObserver& aObserver)
+	{
+	iCurrentState->EnableL(*this, aObserver);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::EnableSnapInUseL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::EnableSnapInUseL(
+	const MSIPExtendedConcreteProfileObserver& aObserver,
+	TUint32 aSnapId)
+	{
+	iCurrentState->EnableSnapInUseL(*this, aObserver, aSnapId);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::DisableL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::DisableL(
+	const MSIPExtendedConcreteProfileObserver& aObserver)
+	{
+	iCurrentState->DisableL(*this, aObserver);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::RemoveL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::RemoveL()
+	{
+	iCacheState = EToBeRemoved;
+	iCurrentState->RemoveL(*this);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ShutdownInitiated
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::ShutdownInitiated()
+	{
+	iIsShutdownInitiated = ETrue;
+	iCurrentState->ShutdownInitiated(*this);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::IsShutdownInitiated
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::IsShutdownInitiated() const
+	{
+	return iIsShutdownInitiated;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::RfsInprogress
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::RfsInprogress(TBool aStatus)
+    {
+    iIsRfsInprogress = aStatus;
+    iCurrentState->ShutdownInitiated(*this);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::IsRfsInprogress
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::IsRfsInprogress() const
+    {
+    return iIsRfsInprogress;
+    }
+
+// CSIPProfileCacheItem::CanBePermanentlyRemoved
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::CanBePermanentlyRemoved() const
+	{
+	return iCurrentState->CanBePermanentlyRemoved(*this);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::UpdateRegistrationL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::UpdateRegistrationL(
+	const MSIPExtendedConcreteProfileObserver& aObserver)
+	{
+	iCurrentState->UpdateRegistrationL(*this, aObserver);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::RegistrationStatusEvent
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::RegistrationStatusEventL(
+	CSIPConcreteProfile::TStatus aStatus,
+	TUint32 aStatusId)
+	{
+	UsedProfile().SetContextId(aStatusId);
+	iCurrentState->RegistrationStatusEventL(*this, aStatus);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ChangeStateL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::ChangeStateL(CSIPProfileState* aNewState)
+	{
+	CSIPConcreteProfile::TStatus newState = aNewState->Name();
+	PROFILE_DEBUG5("ProfileCacheItem::ChangeStateL id,old state,new state",
+				   ProfileId(),
+				   iCurrentState->Name(),
+				   newState)
+
+	TBool maySendRegStatusEvent = !iCurrentState->IsAlrState();
+	if (!aNewState->IsAlrState())
+		{
+		iProfile->SetStatus(newState);
+		}
+
+	iCurrentState = aNewState;
+	iCurrentState->EnterL(*this, maySendRegStatusEvent, iServerCore);
+
+	ResumeL();
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ResumeL
+// Don't resume if migrating. Resume is only used with SNAP.
+// If both a queued update and iMustRefreshIAPs exist, do update first.
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::ResumeL()
+	{
+	PROFILE_DEBUG3("ProfileCacheItem::ResumeL id", ProfileId())
+
+	TUint32 snapId(0);
+	if (!IAPMigrationInProgress())
+		{
+		PROFILE_DEBUG1("ProfileCacheItem::ResumeL SNAP used,not migrating")
+
+		if (iQueuedProfile && iCurrentState->CanProfileBeUpdated(*this))
+			{
+			ResumeQueuedUpdateL();
+			}
+		else if(IsSNAPConfigured(snapId))
+			{
+			PROFILE_DEBUG1("ProfileCacheItem::ResumeL don't resume now")
+
+			// HasProfileUpdate is checked in ShouldRefreshIAPs
+			if (iMustRefreshIAPs &&
+				iCurrentState->ShouldRefreshIAPs(*this) &&
+				iMigrationController)
+				{
+				iMustRefreshIAPs = EFalse;
+				PROFILE_DEBUG3("Refresh IAPs, snapId=", snapId)
+				iMigrationController->RefreshIapAvailabilityL(snapId);
+				}
+			}
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::SetIAPRefreshReminder
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::SetIAPRefreshReminder()
+	{
+	iMustRefreshIAPs = ETrue;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::NewIAPFailed
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::NewIAPFailed()
+	{
+	PROFILE_DEBUG1("ProfileCacheItem::NewIAPFailed")
+
+	iDeltaTimer->Remove(iDeltaTimerEntry);
+
+	const TInt KIapFailedDelay(1);
+
+	TTimeIntervalMicroSeconds32 interval(KIapFailedDelay);
+	iDeltaTimer->Queue(interval, iDeltaTimerEntry);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::SendUnregisteredStatusEventL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::SendUnregisteredStatusEventL()
+	{
+	iServerCore.SendUnregisteredStatusEventL(*this);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::HandleProfileError
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::HandleProfileError(TInt aError,
+	CSIPConcreteProfile& aProfile)
+	{
+	PROFILE_DEBUG3("ProfileCacheItem::HandleProfileError", aError)
+	iServerCore.SIPProfileErrorEvent(aProfile, aError);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::HandleError
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::HandleError(TInt aError)
+	{
+	PROFILE_DEBUG4("ProfileCacheItem::HandleError id,err", ProfileId(), aError)
+
+	if (iCurrentState->ErrorOccurred(*this, aError))
+		{
+		PROFILE_DEBUG1("ProfileCacheItem::HandleError go unregistered")
+
+		SwitchToUnregisteredState();
+
+		if (aError != KErrNone)
+			{
+			iProfile->SetLastRegistrationError(aError);
+			}
+		return ETrue;
+		}
+	return EFalse;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::Compare
+// During linear search operations the search term is always passed as the first
+// argument and the second argument is an element of the array being searched.
+//
+// As MSIPProfileAgentObserver calls can lead here, aSearched.iProfileId can be
+// a temp id, used in iOldProfile, iProfileWithNewIAP, iProfileWithOldIAP.
+// iQueuedProfile has the same profile id as current profile.
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::Compare(const CSIPProfileCacheItem& aSearched,
+									const CSIPProfileCacheItem& aArrayItem)
+	{
+	CSIPConcreteProfile* old    = aArrayItem.iOldProfile;
+	CSIPConcreteProfile* newIap = aArrayItem.iProfileWithNewIAP;
+	CSIPConcreteProfile* oldIap = aArrayItem.iProfileWithOldIAP;
+	return (aArrayItem.iProfileId  == aSearched.iProfileId) ||
+		   (old    && old->Id()    == aSearched.iProfileId) ||
+		   (newIap && newIap->Id() == aSearched.iProfileId) ||
+		   (oldIap && oldIap->Id() == aSearched.iProfileId);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ClientAllowsMigrationL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::ClientAllowsMigrationL(TUint32 aIapId,
+	const MSIPExtendedConcreteProfileObserver& aObserver)
+	{
+	iCurrentState->ClientAllowsMigrationL(*this, aIapId, aObserver);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ClientDisallowsMigrationL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::ClientDisallowsMigrationL(TUint32 aIapId,
+	const MSIPExtendedConcreteProfileObserver& aObserver)
+	{
+	iCurrentState->ClientDisallowsMigrationL(*this, aIapId, aObserver);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::SetClientPermission
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::SetClientPermission(TUint32 aIapId,
+	const MSIPExtendedConcreteProfileObserver* aObserver,
+	TBool aAllowMigration)
+	{
+	PROFILE_DEBUG5("ProfileCacheItem::SetClientPermission id,iap,allow",
+				   ProfileId(),
+				   aIapId,
+				   aAllowMigration)
+	PROFILE_DEBUG3("pending observers=", iObserversWaitedForPermission.Count())
+
+	if (!aAllowMigration)
+		{
+		iMigrationDisallowed = ETrue;
+		}
+	if (aObserver)
+		{
+		RemoveFromPendingObservers(*aObserver);
+		}
+
+	if (iObserversWaitedForPermission.Count() == 0 && iMigrationController)
+		{
+		PROFILE_DEBUG3("ProfileCacheItem::SetClientPermission allow",
+ 	    			   !iMigrationDisallowed)
+		iMigrationController->SetMigrationPermission(*this,
+													 !iMigrationDisallowed,
+													 aIapId);
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::IsSNAPConfigured
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::IsSNAPConfigured(TUint32& aSnapId) const
+	{
+	TBool Val = (UsedProfile().ExtensionParameter(KSIPSnapId, aSnapId) == KErrNone);
+
+	PROFILE_DEBUG3("Exceptional SNAP Entry verifier :", KDefaultSNAPIdentifier)
+	if(Val && aSnapId == KDefaultSNAPIdentifier)
+		{
+		PROFILE_DEBUG3("Snap ID Found to be :", aSnapId)
+		TRAPD(err, DefaultSNAPL(aSnapId));
+		if(err)
+			{
+				Val = EFalse;
+			}
+		}
+	PROFILE_DEBUG3("ProfileCacheItem::IsSNAPConfigured; return SNAP ID Value = ", aSnapId)
+	PROFILE_DEBUG3("ProfileCacheItem::IsSNAPConfigured; return Value = ", Val)
+	return Val;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::PassMigrationStartedToClientL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::PassMigrationStartedToClientL(TUint32 aSnapId,
+														 TUint32 aIapId)
+	{
+	iServerCore.MigrationStartedL(*this, aSnapId, aIapId);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::PassAlrErrorToClient
+// -----------------------------------------------------------------------------
+//
+TInt CSIPProfileCacheItem::PassAlrErrorToClient(TInt aError, TUint32 aIapId)
+	{
+	TUint32 snapId(0);
+	if (!IsSNAPConfigured(snapId))
+	    {
+	    return KErrNotFound;
+	    }
+	return iServerCore.PassAlrErrorToClient(*this, aError, snapId, aIapId);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::HandleNewIapL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::HandleNewIapL(TUint32 aSnapId,
+									     TUint32 aIapId,
+									     TBool aRegistrationExists,
+									     CSIPProfileState& aWaitForPermission)
+	{
+	PROFILE_DEBUG5("ProfileCacheItem::HandleNewIapL id,snap,iap",
+				   ProfileId(),
+				   aSnapId,
+				   aIapId)
+	PROFILE_DEBUG3("reg exists=", aRegistrationExists)
+
+	TUint32 snapId(0);
+	__ASSERT_ALWAYS(IsSNAPConfigured(snapId), User::Leave(KErrNotFound));
+	__ASSERT_ALWAYS(aSnapId == snapId, User::Leave(KErrArgument));
+
+	iMigrationDisallowed = EFalse;
+
+	// SetMigrationPermission can syncronously lead to MigrationIs(Dis)AllowedL
+	// so enter state first.
+	ChangeStateL(&aWaitForPermission);
+	if (aRegistrationExists)
+		{
+		// Don't wait (dis)allow to an earlier IAP
+		iObserversWaitedForPermission.Reset();
+
+		for (TInt i = 0; i < iObservers.Count(); ++i)
+	        {
+	        if (iObservers[i]->IapAvailableL(ProfileId(), aSnapId, aIapId))
+	        	{
+	        	iObserversWaitedForPermission.AppendL(iObservers[i]);
+	        	}
+	        }
+		PROFILE_DEBUG3("pending count=", iObserversWaitedForPermission.Count())
+		if (iObserversWaitedForPermission.Count() == 0)
+			{
+			iMigrationController->SetMigrationPermission(*this, ETrue, aIapId);
+			}
+		}
+	else
+		{
+		// Don't pass IAP-Available, MigrationStarted or MigrationCompleted to
+		// clients. This profile's clients are not asked for permission, but
+		// another profile with same SNAP can disallow migration.
+		__ASSERT_ALWAYS(!iProfileWithNewIAP, User::Leave(KErrNotFound));
+		iMigrationController->SetMigrationPermission(*this, ETrue, aIapId);
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::MonitorSnapL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::MonitorSnapL(TUint32 aSnapId,
+										CSIPProfileState& aWaitForIAP,
+										CSIPProfileState& aRegInProg)
+	{
+	if (iMigrationController && iMigrationController->SnapId() != aSnapId)
+		{
+		// Stop monitoring the old SNAP id
+		StopSnapMonitoring();
+		}
+
+	if (!iMigrationController)
+		{
+		iMigrationController = &iServerCore.MigrationControllerL(aSnapId);
+		TUint32 iapId = iMigrationController->AttachProfileL(*this);
+		if (iapId)
+			{
+			// Initial IAP obtained
+			aRegInProg.RegisterWithIapL(*this, iapId, aRegInProg);
+			}
+		else
+			{
+			// No IAP available yet
+			ChangeStateL(&aWaitForIAP);
+			}
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ProfileRegisteredL
+// If initial registration, don't pass MigrationCompleted.
+// -----------------------------------------------------------------------------
+//
+void
+CSIPProfileCacheItem::ProfileRegisteredL(TBool aMigrating)
+	{
+	TUint32 snapId(0);
+	if (IsSNAPConfigured(snapId))
+		{
+		__ASSERT_ALWAYS(iMigrationController != NULL,
+						User::Leave(KErrNotFound));
+
+		TInt err = iMigrationController->SetIapAcceptance(*this, ETrue);
+		if (err != KErrNone)
+			{
+			iServerCore.HandleProfileError(*this, err);
+			return;
+			}
+		if (aMigrating)
+			{
+			iServerCore.MigrationCompletedL(*this, snapId, Profile().IapId());
+			}
+		// Send notification of the updated IAP
+		iServerCore.SendProfileUpdatedEventL(*this, Profile());
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::RegistrationEnded
+// Can use the same profile id, as TerminateHandling cleared earlier profile
+// from Profile Agent.
+// If client uses SetClientPermission later, migration controller ignores it
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::RegistrationEnded()
+	{
+	PROFILE_DEBUG3("ProfileCacheItem::RegistrationEnded id", ProfileId())
+
+	// If this has already been done, does nothing.
+	iMigrationController->SetMigrationPermission(*this, ETrue);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::CheckProfileEnabledState
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::CheckProfileEnabledState()
+    {
+    UsedProfile().SetEnabled(iUsers.Count() > 0);
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::IsReferred
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::IsReferred() const
+	{
+	return ReferenceCount() > 0 || Profile().IsAutoRegistrationEnabled();
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ProceedUpdatingProfileL
+// If updating SNAP, de-register old SNAP's profile, then register new SNAP's
+// profile. CSIPProfileStateUnregistered::EnterL calls StartRegisterL, ending
+// old SNAP monitoring and starts monitoring new SNAP.
+// -----------------------------------------------------------------------------
+//
+void
+CSIPProfileCacheItem::ProceedUpdatingProfileL(CSIPProfileState& aUnregInProg)
+	{
+	if (HasProfileUpdate() && !IAPMigrationInProgress())
+		{
+		if (IsSnapIdUpdated(Profile()))
+			{
+			aUnregInProg.StartDeregisterL(*this, aUnregInProg);
+			}
+		else
+			{
+			if (aUnregInProg.DoUpdateL(Profile(), *iOldProfile))
+				{
+				ChangeStateL(&aUnregInProg);
+				}
+			else
+				{
+				ClearOldProfile();
+				// Update is complete, resume any pending action
+				ResumeL();
+				}
+			}
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::StopSnapMonitoring
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::StopSnapMonitoring()
+	{
+	if (iMigrationController)
+		{
+		iMigrationController->DetachProfile(*this);
+		iMigrationController = NULL;
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::CloneProfileL
+// Use a new profile id for the new IAP, so Profile Agent treats it as different
+// profile from the old IAP.
+// -----------------------------------------------------------------------------
+//
+CSIPConcreteProfile& CSIPProfileCacheItem::CloneProfileL(TUint aIapId)
+	{
+	PROFILE_DEBUG4("ProfileCacheItem::CloneProfileL id,iap",
+				   ProfileId(),
+				   aIapId)
+	__ASSERT_ALWAYS(!iProfileWithNewIAP, User::Leave(KErrAlreadyExists));
+
+	CSIPConcreteProfile* profile = Profile().CloneL();
+	CleanupStack::PushL(profile);
+	profile->SetId(iServerCore.GenerateProfileIdL());
+	profile->SetStorageId(Profile().StorageId());
+
+	// Use the same Contact user-part as the existing profile.
+	// CSIPConcreteProfile::CloneL generated a new one.
+	const TDesC8* user(NULL);
+	User::LeaveIfError(Profile().ExtensionParameter(
+		KSIPContactHeaderUser, user));
+	profile->SetExtensionParameterL(KSIPContactHeaderUser, *user);
+	CleanupStack::Pop(profile);
+	profile->SetIapId(aIapId);
+
+	iProfileWithNewIAP = profile;
+	return *iProfileWithNewIAP;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ClearMigrationProfiles
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::ClearMigrationProfiles()
+	{
+	delete iProfileWithNewIAP;
+	iProfileWithNewIAP = NULL;
+	delete iProfileWithOldIAP;
+	iProfileWithOldIAP = NULL;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::UseProfileWithNewIAP
+// The new IAP works. Prepare to de-register the old IAP.
+// -----------------------------------------------------------------------------
+//
+CSIPConcreteProfile& CSIPProfileCacheItem::UseProfileWithNewIAP()
+	{
+	__ASSERT_ALWAYS(!iProfileWithOldIAP,
+					User::Panic(KNullDesC, KErrAlreadyExists));
+	__ASSERT_ALWAYS(iProfileWithNewIAP != NULL,
+					User::Panic(KNullDesC, KErrNotFound));
+
+	PROFILE_DEBUG4("ProfileCacheItem::UseProfileWithNewIAP Swapping Id1, Id2",
+					iProfile->Id(), iProfileWithNewIAP->Id() )
+
+	iProfileWithNewIAP->SetStatus( CSIPConcreteProfile::ERegistered );
+
+	// Swap profile id's. Only the original id can be passed to clients.
+	TUint32 originalId( iProfile->Id() );
+	iProfile->SetId( iProfileWithNewIAP->Id() );
+	iProfileWithNewIAP->SetId( originalId );
+
+	iProfileWithOldIAP = iProfile;
+	iProfile = iProfileWithNewIAP;
+	iProfileWithNewIAP = NULL;
+
+	return *iProfileWithOldIAP;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::IAPMigrationInProgress
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::IAPMigrationInProgress() const
+	{
+	return iProfileWithNewIAP || iProfileWithOldIAP;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::StoreProfileToUpdate
+// -----------------------------------------------------------------------------
+//
+void
+CSIPProfileCacheItem::StoreProfileToUpdate(CSIPConcreteProfile* aNewProfile)
+	{
+	PROFILE_DEBUG3("ProfileCacheItem::StoreProfileToUpdate id", ProfileId())
+
+	if (!iOldProfile)
+		{
+		iOldProfile = iProfile;
+		iProfile = NULL;
+		}
+	SetProfile(aNewProfile);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ResumeQueuedUpdateL
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::ResumeQueuedUpdateL()
+	{
+	PROFILE_DEBUG3("ProfileCacheItem::ResumeQueuedUpdateL id", ProfileId())
+	__ASSERT_ALWAYS(iQueuedProfile != NULL && iQueuedObserver != NULL,
+				    User::Leave(KErrNotFound));
+	__ASSERT_ALWAYS(!IAPMigrationInProgress(), User::Leave(KErrNotReady));
+
+	CSIPConcreteProfile* profile = iQueuedProfile;
+	TUint32 snapId(0);
+	if (!IsSnapIdUpdated(*profile) && IsSNAPConfigured(snapId))
+		{
+		// Use the current IAP id
+		profile->SetIapId(UsedProfile().IapId());
+		}
+	const MSIPExtendedConcreteProfileObserver* obs = iQueuedObserver;
+	iQueuedProfile = NULL;
+	iQueuedObserver = NULL;
+	StoreProfileToUpdate(profile);
+
+	iServerCore.UpdateRegistrationL(ProfileId(), *obs);
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::IsSnapIdUpdated
+// -----------------------------------------------------------------------------
+//
+TBool
+CSIPProfileCacheItem::IsSnapIdUpdated(CSIPConcreteProfile& aNewProfile) const
+	{
+	TUint32 currentSnapId(0);
+	IsSNAPConfigured(currentSnapId);
+
+	TUint32 newSnapId(0);
+    TBool res(EFalse);
+	
+	res = (aNewProfile.ExtensionParameter(KSIPSnapId, newSnapId) == KErrNone &&
+			newSnapId != currentSnapId);
+	PROFILE_DEBUG3("Exceptional SNAP Entry verifier :", KDefaultSNAPIdentifier)
+	if(res && newSnapId == KDefaultSNAPIdentifier)
+		{
+		res=EFalse;
+		}
+	PROFILE_DEBUG3("CSIPProfileCacheItem::IsSnapIdUpdated CurrentSNAPID",currentSnapId)
+    PROFILE_DEBUG3("CSIPProfileCacheItem::IsSnapIdUpdated NewSNAPID",newSnapId)
+	return res;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::RemoveFromPendingObservers
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::RemoveFromPendingObservers(
+	const MSIPExtendedConcreteProfileObserver& aObserver)
+	{
+	TInt index = iObserversWaitedForPermission.Find(&aObserver);
+	if (index != KErrNotFound)
+		{
+		iObserversWaitedForPermission.Remove(index);
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::DoNewIapFailed
+// Ignore SetIapAcceptance return value, as already handling error (IAP failed).
+// -----------------------------------------------------------------------------
+//
+TInt CSIPProfileCacheItem::DoNewIapFailed(TAny* aPtr)
+	{
+	__ASSERT_DEBUG(aPtr, User::Panic(_L("ProfileCacheItem:DoNewIapFailed"),
+									 KErrArgument));
+	PROFILE_DEBUG1("ProfileCacheItem::DoNewIapFailed")
+
+	if ( !aPtr )
+		{
+		return KErrArgument;
+		}
+
+	CSIPProfileCacheItem* self = static_cast<CSIPProfileCacheItem*>(aPtr);
+	self->iMigrationController->ResetFlags();
+	self->iMigrationController->SetIapAcceptance(*self, EFalse);
+	return KErrNone;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::SwitchToUnregisteredState
+// Enter unregistered state. Don't use ChangeStateL to avoid loop where profile
+// would register again (if auto-registration on).
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::SwitchToUnregisteredState()
+	{
+	CSIPProfileState& unregistered = iServerCore.UnregisteredState();
+	iProfile->SetStatus(unregistered.Name());
+	iCurrentState = &unregistered;
+	SetSnapRetryCounter(0);
+
+	// No need to monitor SNAP anymore.
+	StopSnapMonitoring();
+	RemoveAllUsers();
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::SetSnapRetryCounter
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::SetSnapRetryCounter(TInt aCounter)
+	{
+	PROFILE_DEBUG3("CSIPProfileCacheItem::SetSnapRetryCounter counter",
+				   aCounter)
+	iSnapRetryCounter = aCounter;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::SnapRetryCounter
+// -----------------------------------------------------------------------------
+//
+TInt CSIPProfileCacheItem::SnapRetryCounter() const
+	{
+	PROFILE_DEBUG3("CSIPProfileCacheItem::SnapRetryCounter counter",
+				   iSnapRetryCounter)
+	return iSnapRetryCounter;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::SnapRetryCountReached
+// -----------------------------------------------------------------------------
+//
+TBool CSIPProfileCacheItem::SnapRetryCountReached() const
+	{
+	TBool reached = iSnapRetryCounter >= KSnapRetryCountThreshold;
+	PROFILE_DEBUG3("CSIPProfileCacheItem::SnapRetryCountReached reached",
+				   reached)
+	return reached;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::OfferedIapRejected
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::OfferedIapRejected()
+	{
+	PROFILE_DEBUG3("CSIPProfileCacheItem::OfferedIapRejected, status",
+				   iProfile->Status())
+
+	HandleError( KErrCancel );
+
+	// State is informed as ERegistrationInProgress to get registration
+	// error event event in client.
+	iServerCore.SendErrorEvent(
+		*this, CSIPConcreteProfile::ERegistrationInProgress, KErrCancel );
+	}
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::ResetShutdownvariable
+// -----------------------------------------------------------------------------
+//
+void CSIPProfileCacheItem::ResetShutdownvariable()
+    {    
+    iIsShutdownInitiated = EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPProfileCacheItem::DefaultSNAPL
+// This function will return the ID of the default SNAP.
+// -----------------------------------------------------------------------------
+//
+
+void CSIPProfileCacheItem::DefaultSNAPL(TUint32& aSnapId) const
+
+	{
+		RCmManager cmManager;
+		cmManager.OpenL();
+		CleanupClosePushL(cmManager);
+		TCmDefConnValue defConn;
+		cmManager.ReadDefConnL( defConn );
+		aSnapId = defConn.iId;	
+		PROFILE_DEBUG3("CSIPProfileCacheItem::DefaultSNAPL with Value: ", aSnapId)
+		CleanupStack::PopAndDestroy();
+	}