phonebookengines/VirtualPhonebook/VPbkSimStore/src/CContact.cpp
branchRCL_3
changeset 63 f4a778e096c2
child 64 c1e8ba0c2b16
child 85 38bb213f60ba
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/VirtualPhonebook/VPbkSimStore/src/CContact.cpp	Wed Sep 01 12:29:52 2010 +0100
@@ -0,0 +1,722 @@
+/*
+* Copyright (c) 2002-2007 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:  A contact adapter between VPbk framework and VPbkSimStoreImpl
+*
+*/
+
+
+// INCLUDES
+#include "CContact.h"
+
+#include "CContactStore.h"
+#include "CFieldTypeMappings.h"
+#include "CViewContact.h"
+#include "MVPbkContactObserver.h"
+#include "CSupportedFieldTypes.h"
+#include "CContactOperationCallback.h"
+#include "VPbkSimStoreError.h"
+
+#include <CVPbkAsyncOperation.h>
+#include <CVPbkContactLinkArray.h>
+#include <CVPbkSimContact.h>
+#include <CVPbkSimCntField.h>
+#include <featmgr.h>
+#include <MVPbkSimCntStore.h>
+#include <MVPbkContactViewBase.h>
+#include <MVPbkContactStoreProperties.h>
+#include <RVPbkStreamedIntArray.h>
+#include <TVPbkSimStoreProperty.h>
+#include <VPbkSimCntFieldTypes.hrh>
+#include <MVPbkSimStoreOperation.h>
+#include <VPbkError.h>
+#include <MVPbkStoreContactProperties.h>
+
+namespace {
+
+// MODULE DATA STRUCTURES
+enum TContactFlags
+    {
+    KNewContact = 1
+    };
+
+const TInt KDefinedAnrFieldTypeCount = 3;   // count of defined additional number types
+
+// ============================= LOCAL FUNCTIONS ===============================
+
+MVPbkContactObserver::TContactOp ConvertContactOperation(
+    MVPbkSimContactObserver::TEvent aEvent )
+    {
+    MVPbkContactObserver::TContactOp op = 
+        MVPbkContactObserver::EContactOperationUnknown;
+    switch ( aEvent )
+        {
+        case MVPbkSimContactObserver::EDelete:
+            {
+            op = MVPbkContactObserver::EContactDelete;
+            break;
+            }
+        case MVPbkSimContactObserver::ESave:
+            {
+            op = MVPbkContactObserver::EContactCommit;
+            break;
+            }
+        default:
+            {
+            op = MVPbkContactObserver::EContactOperationUnknown;
+            break;
+            }
+        }
+    return op;
+    }
+
+TInt MaxNumberOfFieldsInContact( TVPbkSimCntFieldType aType,
+        TVPbkUSimStoreProperty& aUsimProp )
+    {
+    TInt result = 0;
+    switch ( aType )
+        {
+        case EVPbkSimReading: // FALLTHROUGH
+        case EVPbkSimNickName: // FALLTHROUGH
+        case EVPbkSimName:
+            {
+            ++result; // only one name field can exist
+            break;
+            }
+        case EVPbkSimEMailAddress:
+            {
+            if (aUsimProp.iMaxNumOfEmails != KVPbkSimStorePropertyUndefined)
+                {
+                result = aUsimProp.iMaxNumOfEmails;
+                }
+            break;
+            }
+        case EVPbkSimGsmNumber: // FALLTHROUGH
+        case EVPbkSimAdditionalNumberLast:    // the EVPbkSimAdditionalNumber
+            {
+            ++result; // always at least one number
+            if ( aUsimProp.iMaxNumOfAnrs != KVPbkSimStorePropertyUndefined )
+                {
+                if ( !FeatureManager::FeatureSupported(
+                             KFeatureIdFfTdClmcontactreplicationfromphonebooktousimcard ) )
+                    {
+                    result += aUsimProp.iMaxNumOfAnrs;
+                    }
+                else
+                    {
+                    if ( aUsimProp.iMaxNumOfAnrs - KDefinedAnrFieldTypeCount > 0 )
+                        {
+                        result += (aUsimProp.iMaxNumOfAnrs - KDefinedAnrFieldTypeCount);
+                        }
+                    }
+                }
+            break;
+            }
+        case EVPbkSimAdditionalNumber1:
+            result = aUsimProp.iMaxNumOfAnrs >= 1 ? 1 : 0;   // according the max number of anrs.
+            break;
+        case EVPbkSimAdditionalNumber2:
+            result = aUsimProp.iMaxNumOfAnrs >= 2 ? 1 : 0;
+            break;
+        case EVPbkSimAdditionalNumber3:
+            result = aUsimProp.iMaxNumOfAnrs >= 3 ? 1 : 0;	
+            break;
+        default:
+            {
+            // Do nothing
+            break;
+            }
+        }
+    return result;
+    }
+}
+
+namespace VPbkSimStore {
+
+_LIT( KEmptyData, "+" );    //the empty data, modifiy this string to keep its a special string.
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CContact::CContact
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+inline CContact::CContact( CContactStore& aParentStore ) 
+:   iParentStore( aParentStore )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+inline void CContact::ConstructL( CVPbkSimContact& aSimContact, 
+    TBool aIsNewContact )
+    {
+    if ( aIsNewContact )
+        {
+        iFlags.Set( KNewContact );
+        }
+    if( FeatureManager::FeatureSupported( 
+                        KFeatureIdFfTdClmcontactreplicationfromphonebooktousimcard ) )
+        {
+        RemoveAllEmptyFields( aSimContact );    //  remove the empty contacts where added before save.
+        }
+    iFields.SetContact( *this, aSimContact );
+    iAsyncOp = new( ELeave ) VPbkEngUtils::CVPbkAsyncOperation;
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CContact* CContact::NewL( CContactStore& aParentStore,
+    CVPbkSimContact* aSimContact, TBool aIsNewContact )
+    {
+    CContact* self = new ( ELeave ) CContact( aParentStore );
+    CleanupStack::PushL(self);
+    self->ConstructL( *aSimContact, aIsNewContact );
+    CleanupStack::Pop( self );
+    // Take ownership after construction
+    self->iSimContact = aSimContact;
+    return self;
+    }
+
+// Destructor
+CContact::~CContact()
+    {
+    delete iStoreOperation;
+    delete iAsyncOp;
+    delete iSimContact;
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::RemoveAllEmptyFields
+// -----------------------------------------------------------------------------
+//
+void CContact::RemoveAllEmptyFields( CVPbkSimContact& aSimContact )
+    {
+    TInt i = aSimContact.FieldCount() - 1 ;
+    while( i >= 0 )
+        {
+		CVPbkSimCntField& cntField = aSimContact.FieldAt( i );
+		TVPbkSimCntFieldType simCntType = cntField.Type();
+        if( simCntType ==  EVPbkSimGsmNumber
+		    || simCntType == EVPbkSimAdditionalNumber1
+			|| simCntType == EVPbkSimAdditionalNumber2
+			|| simCntType == EVPbkSimAdditionalNumber3
+			|| simCntType == EVPbkSimAdditionalNumberLast )
+        	{
+			if( cntField. Data().Compare( KEmptyData ) == 0 )
+				{
+				aSimContact.DeleteField( i );
+				}
+        	}
+        i --;
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::FillWithEmptyFieldsL
+// -----------------------------------------------------------------------------
+//
+void CContact::FillWithEmptyFieldsL() const
+    {
+    RPointerArray<CVPbkSimCntField> & contactFieldArray = iSimContact->FieldArray();
+    TInt i = contactFieldArray.Count() - 1 ;
+	while( i >= 0 ) // remove all empty content.
+		{
+		CVPbkSimCntField& cntField = iSimContact->FieldAt( i );
+		TVPbkSimCntFieldType type = cntField.Type();
+		if( cntField. Data().Length() == 0 )
+			{
+			iSimContact->DeleteField( i );
+			}
+		i --;
+		}
+	
+    if( contactFieldArray.Count() == 0 )  // no un-empty fields.
+        {
+        return;
+        }
+    CVPbkSimContact::TFieldLookup lookupAdnNumber = 
+                       iSimContact->FindField( EVPbkSimAdditionalNumber );  
+    if( lookupAdnNumber.EndOfLookup())  // if there is no additional number in the contact then no need to add placeholder
+    	{
+		return;
+    	}
+    RPointerArray<CVPbkSimCntField> tempFieldArray;
+    CleanupClosePushL( tempFieldArray );
+    // mappings 
+    CFieldTypeMappings & mappings = iParentStore.FieldTypeMappings();
+    // supported types.
+    const CSupportedFieldTypes& supportedTypes = iParentStore.SupportedFieldTypes();
+
+    // check all supported field types in the fields list. If not exist created new.
+    // if data length is 0, set data to empty data.
+    for( int i = 0; i < supportedTypes.FieldTypeCount(); i ++ )
+        {
+        const MVPbkFieldType& fieldType = supportedTypes.FieldTypeAt( i );
+        TVPbkSimCntFieldType simCntType = mappings.Match( fieldType );
+        if( simCntType ==  EVPbkSimGsmNumber
+		    || simCntType == EVPbkSimAdditionalNumber1
+			|| simCntType == EVPbkSimAdditionalNumber2
+			|| simCntType == EVPbkSimAdditionalNumber3
+			|| simCntType == EVPbkSimAdditionalNumberLast )
+            {
+            CVPbkSimCntField * field = NULL;
+            CVPbkSimContact::TFieldLookup lookup = 
+                   iSimContact->FindField( simCntType );
+
+            if( lookup.EndOfLookup() )
+                {
+                field= iSimContact->CreateFieldLC( simCntType );
+                field->SetDataL( KEmptyData );
+                tempFieldArray.Append( field );
+                CleanupStack::Pop();
+                }
+             else
+                {
+                field = contactFieldArray[lookup.Index()];
+                if( field->Data().Length() == 0 )
+                    {
+                    field->SetDataL( KEmptyData );
+                    }
+                if( simCntType == EVPbkSimAdditionalNumber1 
+                    || simCntType == EVPbkSimAdditionalNumber2
+                    || simCntType == EVPbkSimAdditionalNumber3 )
+                    {
+                    contactFieldArray.Remove( lookup.Index() );
+                    tempFieldArray.AppendL( field );
+                    }
+                }
+            }
+        }
+    TInt j = contactFieldArray.Count() - 1;
+    while( j >= 0 )  //  EVPbkSimAdditionalNumberLast type field will append at last.
+        {
+        if( contactFieldArray[j]->Type() == EVPbkSimAdditionalNumberLast )
+            {
+            tempFieldArray.AppendL( contactFieldArray[ j ] );
+            contactFieldArray.Remove( j );
+            }
+        j --;
+        }
+    for( int i = 0; i < tempFieldArray.Count(); i ++ )
+        {
+        contactFieldArray.AppendL( tempFieldArray[i]);
+        }
+    tempFieldArray.Reset();
+    CleanupStack::Pop();
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::ParentObject
+// -----------------------------------------------------------------------------
+//
+MVPbkObjectHierarchy& CContact::ParentObject() const
+    {
+    return iParentStore;
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::ConstFields
+// -----------------------------------------------------------------------------
+//
+const MVPbkStoreContactFieldCollection& CContact::Fields() const
+    {
+    return iFields;
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::IsSame
+// -----------------------------------------------------------------------------
+//
+TBool CContact::IsSame( const MVPbkStoreContact& aOtherContact ) const
+    {
+    if ( &ParentStore() == &aOtherContact.ParentStore() )
+        {
+        const CContact& otherCnt = static_cast<const CContact&>( aOtherContact );
+        return otherCnt.SimContact().SimIndex() == iSimContact->SimIndex();
+        }
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::CreateLinkLC
+// -----------------------------------------------------------------------------
+//
+MVPbkContactLink* CContact::CreateLinkLC() const
+    {
+    return iParentStore.CreateLinkLC( iSimContact->SimIndex() );
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::DeleteL
+// -----------------------------------------------------------------------------
+//
+void CContact::DeleteL( MVPbkContactObserver& aObserver ) const
+    {
+    if ( iStoreOperation )
+        {
+        User::Leave( KErrInUse );
+        }
+            
+    // From the client point of view the MVPbkStoreContact is constant but
+    // implementation needs a non const contact.
+    RVPbkStreamedIntArray indexArray;
+    CleanupClosePushL( indexArray );
+    indexArray.AppendIntL(iSimContact->SimIndex() );
+    iStoreOperation = iParentStore.NativeStore().DeleteL( indexArray, 
+        const_cast<CContact&>(*this));
+    iObserver = &aObserver;
+    CleanupStack::PopAndDestroy(); // indexArray 
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::MatchContactStore
+// -----------------------------------------------------------------------------
+//    
+TBool CContact::MatchContactStore(const TDesC& aContactStoreUri) const
+    {
+    return iParentStore.MatchContactStore(aContactStoreUri);
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::MatchContactStoreDomain
+// -----------------------------------------------------------------------------
+//    
+TBool CContact::MatchContactStoreDomain(const TDesC& aContactStoreDomain) const
+    {
+    return iParentStore.MatchContactStoreDomain(aContactStoreDomain);
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::CreateBookmarkLC
+// -----------------------------------------------------------------------------
+//
+MVPbkContactBookmark* CContact::CreateBookmarkLC() const
+    {
+    return iParentStore.CreateBookmarkLC( iSimContact->SimIndex() );
+    }
+    
+// -----------------------------------------------------------------------------
+// CContact::ParentStore
+// -----------------------------------------------------------------------------
+//
+MVPbkContactStore& CContact::ParentStore() const
+    {
+    return iParentStore;
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::Fields
+// -----------------------------------------------------------------------------
+//
+MVPbkStoreContactFieldCollection& CContact::Fields()
+    {
+    return iFields;
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::CreateFieldLC
+// -----------------------------------------------------------------------------
+//
+MVPbkStoreContactField* CContact::CreateFieldLC(
+    const MVPbkFieldType& aFieldType ) const
+    {
+    if ( !iParentStore.SupportedFieldTypes().ContainsSame( aFieldType ) )
+        {
+        // According to contact API the function must leave if 
+        // the type is invalid
+        User::Leave( KErrNotSupported );
+        }
+    TVPbkSimCntFieldType simType = 
+        iParentStore.FieldTypeMappings().Match( aFieldType );
+    
+    __ASSERT_DEBUG( simType != EVPbkSimUnknownType,
+        VPbkSimStore::Panic( ESimFieldTypeNotFound ) );
+
+    if ( simType == EVPbkSimGsmNumber || 
+         simType == EVPbkSimAdditionalNumberLast )  //the same field type as EVPbkSimGsmNumber
+        {
+        // EVPbkSimGsmNumber and EVPbkSimAdditionalNumber maps to same
+        // VPbk field type. A sim contact can have only one EVPbkSimGsmNumber
+        // field type and possibly many EVPbkSimAdditionalNumber types 
+        // depending on the USIM store.
+        // However, if SIM card doesn't support additional number it is allowed
+        // to create as many EVPbkSimGsmNumber fields as client wants. This
+        // is needed to enable temporary contacts that holds multiple numbers.
+        CVPbkSimContact::TFieldLookup lookup = 
+            iSimContact->FindField( EVPbkSimGsmNumber );
+        if ( lookup.EndOfLookup() || 
+             !( iParentStore.SimStoreCapabilities() & 
+                VPbkSimStoreImpl::KAdditionalNumUsed ))
+            {
+            simType = EVPbkSimGsmNumber;
+            }
+        else
+            {
+            simType = EVPbkSimAdditionalNumberLast; 
+            }
+        }
+
+    CVPbkSimCntField* field = iSimContact->CreateFieldLC( simType );
+    TContactNewField* fieldWrapper = new( ELeave ) TContactNewField( field );
+    fieldWrapper->SetParentContact( const_cast<CContact&>( *this ) );
+    CleanupStack::Pop( field );
+    CleanupDeletePushL( fieldWrapper );
+    return fieldWrapper;
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::AddFieldL
+// -----------------------------------------------------------------------------
+//
+TInt CContact::AddFieldL( MVPbkStoreContactField* aField )
+    {
+    __ASSERT_ALWAYS( aField, VPbkError::Panic( VPbkError::ENullContactField ) );
+    // Test that the client gives this contact's field and doesn't pass
+    // an existing field of this contact as  a new one
+    __ASSERT_ALWAYS( &aField->ParentContact() == this &&
+        aField != iFields.FieldPointer(), 
+        VPbkError::Panic( VPbkError::EInvalidContactField ) );
+    
+    // Now the wrapper is casted back
+    TContactNewField* fieldWrapper = static_cast<TContactNewField*>( aField );
+    // Takes ownership of the field from the wrapper
+    CVPbkSimCntField* field = fieldWrapper->SimField();
+    CleanupStack::PushL( field );
+    // Add sim field to sim contact. Contact owns the field now.
+    iSimContact->AddFieldL( field );
+    CleanupStack::Pop( field );
+    // After this the function must not leave because client has created
+    // the fieldWrapper with CreateFieldLC and it's in the CleanupStack
+    // Client pops the fieldWrapper after this function
+    delete fieldWrapper;
+    // The field is appended to the array -> return the last field index.
+    return iSimContact->FieldCount() - 1;
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::RemoveField
+// -----------------------------------------------------------------------------
+//
+void CContact::RemoveField( TInt aIndex )
+    {
+    __ASSERT_ALWAYS( aIndex >= 0 && aIndex < iFields.FieldCount(), 
+        VPbkError::Panic(VPbkError::EInvalidFieldIndex) );
+    __ASSERT_ALWAYS( !iParentStore.StoreProperties().ReadOnly(),
+        VPbkError::Panic(VPbkError::EInvalidAccessToReadOnlyContact ) );
+
+    iSimContact->DeleteField( aIndex );
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::RemoveAllFields
+// -----------------------------------------------------------------------------
+//
+void CContact::RemoveAllFields()
+    {
+    __ASSERT_ALWAYS( !iParentStore.StoreProperties().ReadOnly(),
+        VPbkError::Panic(VPbkError::EInvalidAccessToReadOnlyContact ) );
+
+    iSimContact->DeleteAllFields();
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::LockL
+// -----------------------------------------------------------------------------
+//
+void CContact::LockL( MVPbkContactObserver& aObserver ) const
+    {
+    MVPbkContactObserver::TContactOpResult opResult;
+    opResult.iExtension = NULL;
+    opResult.iOpCode = MVPbkContactObserver::EContactLock;
+    opResult.iStoreContact = NULL;
+    
+    CContactOperationCallback* callBack = 
+        new( ELeave ) CContactOperationCallback( opResult, aObserver, 
+        KErrNone );
+    CleanupStack::PushL( callBack );
+    iAsyncOp->CallbackL( callBack );
+    CleanupStack::Pop( callBack );
+    iLocked = ETrue;
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::CommitL
+// -----------------------------------------------------------------------------
+//
+void CContact::CommitL( MVPbkContactObserver& aObserver ) const
+    {
+    if ( iLocked || iFlags.IsSet( KNewContact ))
+        {
+        if ( iStoreOperation )
+            {
+            User::Leave( KErrInUse );
+            }
+        // From the client point of view the MVPbkStoreContact is constant but
+        // implementation needs a non const contact.
+        if( FeatureManager::FeatureSupported( KFeatureIdFfTdClmcontactreplicationfromphonebooktousimcard ) )
+            {
+            FillWithEmptyFieldsL();
+            }
+        iStoreOperation = iSimContact->SaveL( const_cast<CContact&>( *this ));
+        iObserver = &aObserver;
+        }
+    else
+        {
+        // Virtual Phonebook API demands that contact must be locked before
+        // CommitL. Sim Store has to behave according to that and 
+        // complete with KErrAccessDenied.
+        MVPbkContactObserver::TContactOpResult opResult;
+        opResult.iExtension = NULL;
+        opResult.iOpCode = MVPbkContactObserver::EContactCommit;
+        opResult.iStoreContact = NULL;
+        CContactOperationCallback* callBack = 
+            new( ELeave ) CContactOperationCallback( 
+            opResult, aObserver, KErrAccessDenied );
+        CleanupStack::PushL( callBack );
+        iAsyncOp->CallbackL( callBack );
+        CleanupStack::Pop( callBack );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::GroupsJoinedLC
+// -----------------------------------------------------------------------------
+//
+MVPbkContactLinkArray* CContact::GroupsJoinedLC() const
+    {
+    return CVPbkContactLinkArray::NewLC();
+    }
+   
+// -----------------------------------------------------------------------------
+// CContact::Group
+// -----------------------------------------------------------------------------
+//
+MVPbkContactGroup* CContact::Group()
+    {
+    return NULL;
+    }    
+
+// -----------------------------------------------------------------------------
+// CContact::MaxNumberOfFieldL
+// -----------------------------------------------------------------------------
+//
+TInt CContact::MaxNumberOfFieldL( const MVPbkFieldType& aType ) const
+    {
+    TInt res = 0;
+    TVPbkSimCntFieldType nativeType = 
+        iParentStore.FieldTypeMappings().Match( aType );
+    if ( nativeType != EVPbkSimUnknownType )
+        {
+        TVPbkUSimStoreProperty usimProp;
+        User::LeaveIfError(iParentStore.NativeStore().GetUSimStoreProperties( 
+            usimProp ));
+        res = MaxNumberOfFieldsInContact( nativeType, usimProp );
+        }
+    return res;
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::ContactEventComplete
+// -----------------------------------------------------------------------------
+//
+void CContact::ContactEventComplete( TEvent aEvent, 
+    CVPbkSimContact* /*aContact*/ )
+    {
+    __ASSERT_DEBUG( iObserver, Panic(EPreCond_CContact_ContactEventComplete));
+    
+    delete iStoreOperation;
+    iStoreOperation = NULL;
+    
+    MVPbkContactObserver::TContactOpResult vpbkOpResult;
+    vpbkOpResult.iStoreContact = NULL;
+    vpbkOpResult.iExtension = NULL;
+    vpbkOpResult.iOpCode = ConvertContactOperation( aEvent );
+    
+    MVPbkContactObserver* observer = iObserver;
+    ResetContactOperationState();
+    
+    // remove filled placeholder fields.
+    if( vpbkOpResult.iOpCode == MVPbkContactObserver::EContactCommit )
+    	{
+		RemoveAllEmptyFields( *iSimContact );
+    	}
+    observer->ContactOperationCompleted( vpbkOpResult );
+    }
+
+// -----------------------------------------------------------------------------
+// CContact::ContactEventError
+// -----------------------------------------------------------------------------
+//
+void CContact::ContactEventError( TEvent aEvent, 
+    CVPbkSimContact* /*aContact*/, TInt aError )
+    {
+    __ASSERT_DEBUG( iObserver, Panic(EPreCond_CContact_ContactEventError));
+    
+    delete iStoreOperation;
+    iStoreOperation = NULL;
+    
+    MVPbkContactObserver* observer = iObserver;
+    ResetContactOperationState();
+    MVPbkContactObserver::TContactOp op = ConvertContactOperation( aEvent );
+    
+    // remove filled placeholder fields.
+    if( op == MVPbkContactObserver::EContactCommit )
+    	{
+		RemoveAllEmptyFields( *iSimContact );
+    	}
+    observer->ContactOperationFailed( op, aError, EFalse );
+    } 
+
+// -----------------------------------------------------------------------------
+// CContact::ResetContactOperationState
+// -----------------------------------------------------------------------------
+//
+void CContact::ResetContactOperationState()
+    {
+    iObserver = NULL;
+    }
+
+TAny* CContact::StoreContactExtension(TUid aExtensionUid)
+{
+    
+    if( aExtensionUid == KMVPbkStoreContactExtension2Uid )
+		return static_cast<MVPbkStoreContact2*>( this );
+    return NULL;
+}
+
+
+	
+MVPbkStoreContactProperties* CContact::PropertiesL() const
+    {
+    //sim  store doesn't support any of MVPbkStoreContactProperties functions
+    return NULL;
+    }
+
+void CContact::SetAsOwnL( MVPbkContactObserver& /*aObserver*/ ) const
+	{
+	// own link is not supported in sim store    
+	User::Leave( KErrNotSupported );
+	}
+
+} // namespace VPbkSimStore
+
+// end of file
+