--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/VirtualPhonebook/VPbkVCardEng/src/CVPbkVCardImporter.cpp Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,679 @@
+/*
+* Copyright (c) 2006-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: Importing the CParserProperty field from CParserVCard to
+* contact field.
+*
+*/
+
+#include "CVPbkVCardImporter.h"
+#include "CVPbkVCardPropertyParser.h"
+#include "CVPbkVCardAttributeHandler.h"
+#include "CVPbkVCardFieldTypeProperty.h"
+#include "CVPbkVCardContactFieldIterator.h"
+#include "CVPbkVCardData.h"
+#include "TVPbkVCardDataConverter.h"
+#include "CVPbkVCardContactFieldData.h"
+
+#include <MVPbkStoreContact.h>
+#include <MVPbkContactStore.h>
+#include <MVPbkContactCopyPolicy.h>
+#include <MVPbkContactFieldData.h>
+#include <MVPbkContactStoreProperties.h>
+#include <MVPbkContactAttribute.h>
+#include <MVPbkContactOperationBase.h>
+#include <CVPbkContactManager.h>
+#include <MVPbkStoreContactFieldCollection.h>
+
+// System includes
+#include <vcard.h>
+#include <bldvariant.hrh>
+#include <s32buf.h>
+
+#include <VPbkStoreUriLiterals.h>
+_LIT8( KPropXSelf, "X-SELF" );
+_LIT8( KPropXCategories, "X-CATEGORIES");
+
+CVPbkVCardImporter* CVPbkVCardImporter::NewL(
+ RPointerArray<MVPbkStoreContact>& aImportedContacts,
+ RReadStream& aSourceStream,
+ MVPbkContactStore& aTargetStore,
+ CVPbkVCardData& aData )
+ {
+ CVPbkVCardImporter* self = new (ELeave) CVPbkVCardImporter(
+ aImportedContacts, aTargetStore, aData);
+ CleanupStack::PushL( self );
+ self->ConstructL(aSourceStream);
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+CVPbkVCardImporter::CVPbkVCardImporter(
+ RPointerArray<MVPbkStoreContact>& aImportedContacts,
+ MVPbkContactStore& aTargetStore,
+ CVPbkVCardData& aData ) :
+ CActive( EPriorityStandard ),
+ iImportedContacts( aImportedContacts ),
+ iTargetStore( aTargetStore ),
+ iData( aData )
+ {
+ CActiveScheduler::Add( this );
+ }
+
+CVPbkVCardImporter::~CVPbkVCardImporter()
+ {
+ Cancel();
+ delete iAddCntContactFieldOperation;
+ delete iCntContact;
+ if (iCntModelStore)
+ {
+ iCntModelStore->Close(*this);
+ }
+ iSourceStream.Close();
+ delete iStreamBuffer;
+ delete iAddFieldOperation;
+ delete iAttributeHandler;
+ delete iContactFieldIterator;
+ delete iCurContact;
+ delete iPropertyParser;
+ delete iParser;
+ delete iGroupCardValue;
+
+ iErasableFields.Close();
+ }
+
+void CVPbkVCardImporter::ConstructL(RReadStream& aSourceStream)
+ {
+
+ // Get the source stream size
+ MStreamBuf* buf = aSourceStream.Source();
+ TInt streamSize = buf->SizeL();
+
+ // Read the source contents
+ iStreamBuffer = HBufC8::NewL(streamSize);
+ TPtr8 ptr(iStreamBuffer->Des());
+ aSourceStream.ReadL(ptr, streamSize);
+
+ // Create a new local stream
+ iSourceStream.Open(*iStreamBuffer);
+
+ iParser = CParserVCard::NewL();
+
+
+ iAttributeHandler = CVPbkVCardAttributeHandler::NewL();
+ iPropertyParser =
+ CVPbkVCardPropertyParser::NewL( iData, *iAttributeHandler );
+ iCopyPolicy = &iData.CopyPolicyL( iTargetStore.StoreProperties().Uri() );
+ if ( iTargetStore.StoreProperties().Uri().UriDes().CompareC(
+ KVPbkSimGlobalAdnURI()) == 0 )
+ {
+ iCntCopyPolicy = &iData.CopyPolicyL( iData.GetCntModelStoreL().StoreProperties().Uri() );
+ }
+ iOwnCard = EFalse;
+ // Construct an empty string to ensure that iGroupCardValue always exists
+ // See also GetGroupcardvalue()
+ iGroupCardValue = HBufC::NewL(0);
+ }
+
+void CVPbkVCardImporter::StartL()
+ {
+ iOwnCard = EFalse;
+ TRAPD( err, iParser->InternalizeL( iSourceStream ) );
+
+ if ( err != KErrEof ) // allow partial vcard data
+ {
+ User::LeaveIfError( err );
+ }
+
+ if ( !iParser->ArrayOfProperties( EFalse ) )
+ {
+ User::Leave( KErrNotFound );
+ }
+
+ // This function just starts the process asynchronously.
+ (KErrEof == err) ? StartAsync( EStop ) : StartAsync( EParseNext );
+ }
+
+void CVPbkVCardImporter::RunL()
+ {
+ if ( iStatus.Int() == KErrNone )
+ {
+ switch( iState )
+ {
+ case EParseNext:
+ {
+ if ( !iCurContact )
+ {
+ // If contact haven't not been created, create new one.
+ iCurContact = iTargetStore.CreateNewContactLC();
+ CleanupStack::Pop(); // iCurContact
+ if ( iCntCopyPolicy )
+ {
+ iCntModelStore = &iData.GetCntModelStoreL();
+ iCntModelStore->OpenL(*this);
+ break;
+ }
+ }
+ ParseNextL();
+ break;
+ }
+ case ESaveField:
+ {
+ SaveFieldL();
+ break;
+ }
+ case ESaveContact:
+ {
+ SaveContactL();
+ break;
+ }
+ case EStop:
+ {
+ iObserver->ContactsImportingCompleted();
+ break;
+ }
+ default:;
+ }
+ }
+ }
+
+TInt CVPbkVCardImporter::RunError( TInt aError )
+ {
+ HandleError( aError );
+ return KErrNone;
+ }
+
+void CVPbkVCardImporter::DoCancel()
+ {
+ }
+
+void CVPbkVCardImporter::SetObserver(
+ MVPbkImportOperationObserver& aObserver )
+ {
+ iObserver = &aObserver;
+ }
+
+CParserProperty* CVPbkVCardImporter::NextProperty()
+ {
+ // Get next property from parser array
+ CParserProperty* property = NULL;
+ TInt elementCount = iParser->ArrayOfProperties( EFalse )->Count();
+ if ( iArrayElementIndex < elementCount )
+ {
+ property =
+ iParser->ArrayOfProperties( EFalse )->At( iArrayElementIndex );
+ ++iArrayElementIndex;
+ }
+ return property;
+ }
+
+void CVPbkVCardImporter::ParseNextL()
+ {
+ delete iContactFieldIterator;
+ iContactFieldIterator = NULL;
+
+ CParserProperty* property = NextProperty();
+ if ( property )
+ {
+ if(property->Name().Compare(KPropXSelf())==0)
+ {
+ iOwnCard = ETrue;
+ }
+
+ if( property->Name().Compare(KPropXCategories())==0)
+ {
+ iGroupCard = ETrue;
+ CParserPropertyValue* value = property->Value();
+ // Get the HBufC property
+ CParserPropertyValueHBufC* hbufVal =
+ static_cast<CParserPropertyValueHBufC*>(value);
+ TPtrC normalVal = hbufVal->Value();
+ // Create a modifiable descriptor
+ if( iGroupCardValue )
+ {
+ delete iGroupCardValue;
+ iGroupCardValue = NULL;
+ }
+ iGroupCardValue = normalVal.AllocL();
+ }
+ // property is owned by iParser->ArrayOfProperties(), we are not
+ // responsible of deleting it.
+ iContactFieldIterator = iPropertyParser->ParseNextL( property );
+ iState = ESaveField;
+ }
+ else
+ {
+ // No properties anymore, all fields are added. Save contact.
+ iState = ESaveContact;
+ }
+ StartAsync( iState );
+ }
+
+TInt CVPbkVCardImporter::FindContactFieldL(
+ MVPbkStoreContact* aContact,
+ TInt aFieldTypeResId )
+ {
+ if ( aContact )
+ {
+ const MVPbkStoreContactFieldCollection& fields = aContact->Fields();
+ const TInt fieldCount = fields.FieldCount();
+
+ const TInt maxMatchPriority = 0;
+ iData.GetContactManager().FieldTypes().MaxMatchPriority();
+
+ for ( TInt matchPriority = 0;
+ matchPriority <= maxMatchPriority; ++matchPriority )
+ {
+ for ( TInt i = 0; i < fieldCount; ++i )
+ {
+ const MVPbkFieldType* fieldType =
+ fields.FieldAt(i).MatchFieldType(matchPriority);
+ if ( fieldType->FieldTypeResId() == aFieldTypeResId )
+ {
+ return i;
+ }
+ }
+ }
+ }
+
+ return KErrNotFound;
+ }
+
+void CVPbkVCardImporter::SaveFieldL()
+ {
+ if ( iContactFieldIterator->HasNext() )
+ {
+ // Get next field data
+ CVPbkVCardContactFieldData* data = iContactFieldIterator->NextLC();
+ // Save data asynchronously, if data is not saved e.g. empty field
+ // this is treated as synchronous function.
+ TBool saved = EFalse;
+ // SaveDataL may leave when constructing add field operation
+ // (e.g. for valid but unsupported in the current build field type)
+ // leave should be trapped and saving continue
+ TRAPD(err, saved = SaveDataL( *data ));
+ CleanupStack::PopAndDestroy( data );
+ if ( !saved )
+ {
+ // If data was not saved try to move next field.
+ if ( err == KErrNone )
+ {
+ StartAsync( ESaveField );
+ }
+ else
+ {
+ HandleFailedFieldAdditionL( err );
+ }
+ }
+ }
+ else
+ {
+ StartAsync( EParseNext );
+ }
+ }
+
+TBool CVPbkVCardImporter::SaveDataL( CVPbkVCardContactFieldData& aData )
+ {
+ // Data value type should be asked from aData
+ TBool isSaved ( ETrue );
+ TVPbkVCardDataConverter converter;
+ if ( aData.Uid() == TUid::Uid( KVersitPropertyHBufCUid ) ||
+ aData.Uid() == TUid::Uid( KVersitPropertyCDesCArrayUid ) )
+ {
+ const TDesC& value = converter.GetDesCData( aData );
+ SaveL( aData, value );
+ }
+ else if ( aData.Uid() == TUid::Uid( KVersitPropertyBinaryUid ) )
+ {
+ const TDesC8& value = converter.GetBinaryData( aData );
+ if ( value.Length() > 0 )
+ {
+ SaveL( aData, value );
+ }
+ else
+ {
+ isSaved = EFalse;
+ }
+ }
+ else if ( aData.Uid() == TUid::Uid( KVersitPropertyDateUid ) )
+ {
+ const TVersitDateTime* value = converter.GetDateTimeData( aData );
+ if ( value )
+ {
+ SaveL( aData, *value );
+ }
+ else
+ {
+ isSaved = EFalse;
+ }
+ }
+ else
+ {
+ // In case the UID is something else. Should not happen ever, because
+ // uids are defined by us.
+ isSaved = EFalse;
+ }
+
+ return isSaved;
+ }
+
+void CVPbkVCardImporter::SaveL(
+ CVPbkVCardContactFieldData& aData, const TVersitDateTime& aValue )
+ {
+ iAddFieldOperation = iCopyPolicy->AddFieldToContactL(
+ *iCurContact,
+ aData.FieldType(),
+ aValue.iDateTime,
+ NULL,
+ aData.Attribute(),
+ *this );
+ }
+
+void CVPbkVCardImporter::SaveL(
+ CVPbkVCardContactFieldData& aData, const TDesC& aValue )
+ {
+ if( iCntContact )
+ {
+ iAddCntContactFieldOperation = iCntCopyPolicy->AddFieldToContactL(
+ *iCntContact,
+ aData.FieldType(),
+ aValue,
+ NULL,
+ aData.Attribute(),
+ *this );
+ }
+
+ // If it is 'FN' vcard field,
+ // it can be overwriten by lastname subfield of 'N' vcard field
+ TInt fieldTypeResId = iContactFieldIterator->FindVCardFieldL(
+ EVPbkVersitNameFN,
+ EVPbkVersitSubFieldNone );
+ if ( fieldTypeResId != KErrNotFound )
+ {
+ if ( FindContactFieldL( iCurContact, fieldTypeResId ) ==
+ KErrNotFound )
+ {
+ iErasableFields.Append( fieldTypeResId );
+ }
+ }
+ else
+ {
+ fieldTypeResId = aData.FieldType().FieldTypeResId();
+ TInt id = iErasableFields.Find( fieldTypeResId );
+ if ( id != KErrNotFound )
+ {
+ TInt field = FindContactFieldL( iCurContact, fieldTypeResId );
+ if ( field != KErrNotFound )
+ {
+ iCurContact->RemoveField( field );
+ }
+ iErasableFields.Remove( id );
+ }
+ }
+
+ iAddFieldOperation = iCopyPolicy->AddFieldToContactL(
+ *iCurContact,
+ aData.FieldType(),
+ aValue,
+ NULL,
+ aData.Attribute(),
+ *this );
+ }
+
+void CVPbkVCardImporter::SaveL(
+ CVPbkVCardContactFieldData& aData, const TDesC8& aValue )
+ {
+ iAddFieldOperation = iCopyPolicy->AddFieldToContactL(
+ *iCurContact,
+ aData.FieldType(),
+ aValue,
+ NULL,
+ aData.Attribute(),
+ *this );
+ }
+
+void CVPbkVCardImporter::FieldAddedToContact(
+ MVPbkContactOperationBase& aOperation)
+ {
+ if (&aOperation == iAddFieldOperation)
+ {
+ delete iAddFieldOperation;
+ iAddFieldOperation = NULL;
+ StartAsync( ESaveField );
+ }
+ if (&aOperation == iAddCntContactFieldOperation)
+ {
+ delete iAddCntContactFieldOperation;
+ iAddCntContactFieldOperation = NULL;
+ }
+ }
+
+void CVPbkVCardImporter::FieldAddingFailed(
+ MVPbkContactOperationBase& aOperation,
+ TInt aError)
+ {
+ if (&aOperation == iAddFieldOperation)
+ {
+ delete iAddFieldOperation;
+ iAddFieldOperation = NULL;
+ TRAPD( error, HandleFailedFieldAdditionL( aError ) );
+ HandleError( error );
+ }
+ if (&aOperation == iAddCntContactFieldOperation)
+ {
+ delete iAddCntContactFieldOperation;
+ iAddCntContactFieldOperation = NULL;
+ }
+ }
+
+void CVPbkVCardImporter::FieldsCopiedToContact(
+ MVPbkContactOperationBase& aOperation)
+ {
+ if (&aOperation == iAddFieldOperation)
+ {
+ delete iAddFieldOperation;
+ iAddFieldOperation = NULL;
+
+ TRAPD( res, ContinueCopyingToNewContactL() );
+ HandleError( res );
+ }
+ if (&aOperation == iAddCntContactFieldOperation)
+ {
+ delete iAddCntContactFieldOperation;
+ iAddCntContactFieldOperation = NULL;
+ }
+ }
+
+void CVPbkVCardImporter::FieldsCopyFailed(
+ MVPbkContactOperationBase& aOperation,
+ TInt aError)
+ {
+ if (&aOperation == iAddFieldOperation)
+ {
+ delete iAddFieldOperation;
+ iAddFieldOperation = NULL;
+
+ HandleError( aError );
+ }
+ if (&aOperation == iAddCntContactFieldOperation)
+ {
+ delete iAddCntContactFieldOperation;
+ iAddCntContactFieldOperation = NULL;
+ }
+ }
+
+void CVPbkVCardImporter::SaveContactL()
+ {
+ if( iCntContact && iImportedContacts.Count() == 0 )
+ {
+ iAddCntContactFieldOperation = iCopyPolicy->CopyTitleFieldsL(
+ *iCntContact,
+ *iCurContact,
+ *this );
+ }
+
+ // We have looped through property array with all match priorities
+ // ==> all fields have been added
+ iImportedContacts.AppendL( iCurContact );
+ iCurContact = NULL;
+
+ // Remove empty fields and empty contacts
+ RemoveEmptyFieldsAndContacts();
+ iObserver->ContactsImported();
+ }
+
+void CVPbkVCardImporter::ContinueCopyingToNewContactL()
+ {
+ // Save same field again to the new contact
+ CVPbkVCardContactFieldData* data = iContactFieldIterator->CurrentLC();
+ TBool saved = SaveDataL( *data );
+ CleanupStack::PopAndDestroy( data );
+ if ( !saved )
+ {
+ // If data was not saved try to move next field.
+ StartAsync( ESaveField );
+ }
+ }
+
+void CVPbkVCardImporter::RemoveEmptyFieldsAndContacts()
+ {
+ TInt importedContactsCount = iImportedContacts.Count();
+ for ( TInt i = importedContactsCount - 1; i >= 0; --i )
+ {
+ MVPbkStoreContactFieldCollection& fields =
+ iImportedContacts[i]->Fields();
+ TInt fieldCount = fields.FieldCount();
+ while ( fieldCount-- > 0 )
+ {
+ MVPbkStoreContactField& field = fields.FieldAt( fieldCount );
+ if ( field.FieldData().IsEmpty() )
+ {
+ iImportedContacts[i]->RemoveField( fieldCount );
+ }
+ }
+
+ if ( fields.FieldCount() == 0 )
+ {
+ delete iImportedContacts[i];
+ iImportedContacts.Remove( i );
+ }
+ }
+ }
+
+void CVPbkVCardImporter::CopyContactTitlesL()
+ {
+ // If vcard was splitted to multiple contacts then copy
+ // title fields from the first imported contact to the other contacts.
+ iAddFieldOperation = iCopyPolicy->CopyTitleFieldsL(
+ *iImportedContacts[0],
+ *iCurContact,
+ *this );
+ }
+
+void CVPbkVCardImporter::HandleFailedFieldAdditionL( TInt aError )
+ {
+ if ( aError == KErrNotSupported )
+ {
+ // Target contact didn't support field or didn't have field type
+ // conversion for the field. Continue with next field.
+ StartAsync( ESaveField );
+ }
+ else if ( aError == KErrOverflow )
+ {
+ if( iCntContact && iImportedContacts.Count() == 0 )
+ {
+ iAddCntContactFieldOperation = iCopyPolicy->CopyTitleFieldsL(
+ *iCntContact,
+ *iCurContact,
+ *this );
+ }
+
+ // Target contact is full of that field -> Create a new contact
+ // and import field to that one.
+ iImportedContacts.AppendL( iCurContact );
+ iCurContact = NULL;
+ iCurContact = iTargetStore.CreateNewContactLC();
+ CleanupStack::Pop();
+ // Copy title fields to new contact first
+ CopyContactTitlesL();
+ }
+ else
+ {
+ // Some other error -> importing failed
+ iObserver->ContactImportingFailed( aError );
+ }
+ }
+
+void CVPbkVCardImporter::HandleError( TInt aError )
+ {
+ if ( aError != KErrNone )
+ {
+ iObserver->ContactImportingFailed( aError );
+ }
+ }
+
+void CVPbkVCardImporter::StartAsync( TState aNextState )
+ {
+ iState = aNextState;
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete( status, KErrNone );
+ SetActive();
+ }
+ TBool CVPbkVCardImporter::IsOwncard()
+ {
+ return iOwnCard;
+ }
+
+// ----------------------------------------------------------------------------
+// CVPbkVCardImporter::IsGroupcard
+// ----------------------------------------------------------------------------
+TBool CVPbkVCardImporter::IsGroupcard()
+ {
+ return iGroupCard;
+ }
+// ----------------------------------------------------------------------------
+// CVPbkVCardImporter::GetGroupcardvalue
+// ----------------------------------------------------------------------------
+
+TPtr CVPbkVCardImporter::GetGroupcardvalue()
+ {
+ return ( iGroupCardValue->Des());
+ }
+
+void CVPbkVCardImporter::StoreReady(MVPbkContactStore& aContactStore)
+ {
+ if (iCntContact)
+ {
+ delete iCntContact;
+ iCntContact = NULL;
+ }
+
+ iCntContact = aContactStore.CreateNewContactLC();
+ CleanupStack::Pop(); // iCntContact
+
+ ParseNextL();
+ }
+
+void CVPbkVCardImporter::StoreUnavailable(
+ MVPbkContactStore& /*aContactStore*/,
+ TInt /*aReason*/)
+ {
+ }
+
+void CVPbkVCardImporter::HandleStoreEventL(
+ MVPbkContactStore& /*aContactStore*/,
+ TVPbkContactStoreEvent /*aStoreEvent*/)
+ {
+ }
+
+// End of file