phonebookengines/contactsmodel/cntvcard/cntvcardimport.cpp
changeset 0 e686773b3f54
child 24 0ba2181d7c28
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/phonebookengines/contactsmodel/cntvcard/cntvcardimport.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,2316 @@
+// Copyright (c) 1997-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:
+//
+
+#include "cntvcardutils.h"
+
+// System includes
+#include <badesca.h>
+#include <conlist.h>
+#include <s32mem.h> 
+
+
+// User includes
+#include <cntfldst.h>
+#include <cntfield.h>
+#include <cntdef.h>
+#include <cntitem.h>
+
+
+// Constants
+const TInt KVCardImportAddressArrayGranularity = 4;
+const TInt KContactGivenName = 1;
+const TInt KContactFamilyName = 0;
+const TInt KContactAdditionalName = 2;
+const TInt KContactPrefixName = 3;
+const TInt KContactSuffixName = 4;
+const TInt KContactPostOffice = 0;
+const TInt KContactExtendedAddress = 1;
+const TInt KContactAddress = 2;
+const TInt KContactLocality = 3;
+const TInt KContactRegion = 4;
+const TInt KContactPostcode = 5;
+const TInt KContactCountry = 6;
+
+#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
+const TInt KContactMaxFieldNumber = 32;
+#endif
+
+/**
+ * Delete name fields from a contact
+ *
+ * @param aContact Contact item
+ */
+void CVCardToContactsAppConverter::DeleteNameFields(CContactItem& aContact)
+	{
+	const CContactItemFieldSet& fieldSet = aContact.CardFields();
+	//
+	DeleteField(aContact, fieldSet, KUidContactFieldGivenName, KUidContactFieldVCardMapUnusedN);
+	DeleteField(aContact, fieldSet, KUidContactFieldFamilyName, KUidContactFieldVCardMapUnusedN);
+	DeleteField(aContact, fieldSet, KUidContactFieldAdditionalName, KUidContactFieldVCardMapUnusedN);
+	DeleteField(aContact, fieldSet, KUidContactFieldPrefixName, KUidContactFieldVCardMapUnusedN);
+	DeleteField(aContact, fieldSet, KUidContactFieldSuffixName, KUidContactFieldVCardMapUnusedN);
+	}
+
+
+/**
+ * Delete a specific field from the contact card
+ *
+ * @param aContact The contact
+ * @param aFieldSet The contact's field set
+ * @param aFieldType The type of field to delete from the field set
+ * @param aMapping The additional mapping which the field must contain for it to be deleted
+ */
+void CVCardToContactsAppConverter::DeleteField(CContactItem& aContact, const CContactItemFieldSet& aFieldSet, TFieldType aFieldType, TUid aMapping)
+	{
+	const TInt pos = aFieldSet.Find(aFieldType, aMapping);
+	if	(pos != KErrNotFound)
+		aContact.RemoveField(pos);
+	}
+
+
+void CVCardToContactsAppConverter::MergeSpecifiedNameFieldL(CContactItem& aContact, TFieldType aFieldType, CVCardItemAndLabel& aNames, TInt aOption, TInt aNameIndex)
+/**
+ * Merge specific name fields from a contact
+ *
+ * @param aContact Contact item to add fields to
+ * @param aFieldType Field type of field to add (TFieldType)
+ * @param aNames An object containing the name and labels for 'N' property fields
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ * @param aNameIndex Index into aNames
+ */
+	{
+	CContactItemFieldSet& oldfieldset=aContact.CardFields();
+	const TInt pos = oldfieldset.Find(aFieldType, KUidContactFieldVCardMapUnusedN);
+	const TBool processWhitespace = (aOption & CContactVCardConverter::EConnectWhitespace);
+
+	// First check whether the field is present in the contact card
+	// Also verify that the array of address sub-values actually contains a specific
+	// value for the requested index.
+	if (aNames.ItemCount() > aNameIndex)
+		{
+		const TPtrC pValue = aNames.Item(aNameIndex);
+		const TInt length = pValue.Length();
+		if (processWhitespace)
+			{
+			TBool isSingleSpace = EFalse;
+			if (length == 1)
+				{
+				isSingleSpace = (pValue[0] == KContactVCardSpaceCharacter);
+				}
+			if	((pos != KErrNotFound) && (length || isSingleSpace))
+				{
+				// This means the PC side field is empty, so delete the corresponding device-side field.
+				aContact.RemoveField(pos);
+				}
+			if	(length && !isSingleSpace)
+				{
+				// This means the PC side field is unsupported, so ignore the corresponding contents.
+				TInt insertPos = 0;
+				SetNameFieldL(aNames, aContact, aOption, aNameIndex, aFieldType, insertPos);
+				}
+			}
+		else
+			{
+			if (pos != KErrNotFound)
+				{
+				// This means the PC side field is empty, so delete the corresponding device-side field.
+				aContact.RemoveField(pos);
+				}
+			if (length)
+				{
+				// This means the PC side field is not empty, so add the corresponding contents.
+				TInt insertPos = 0;
+				SetNameFieldL(aNames, aContact, aOption, aNameIndex, aFieldType, insertPos);
+				}
+			}
+		}
+	}
+
+
+void CVCardToContactsAppConverter::MergeNameFieldsL(CContactItem& aContact, CVCardItemAndLabel& aNames, TInt aOption, TBool aTreatAsPrn)
+/**
+ * Merge name fields from a contact
+ *
+ * @param aContact Contact item to add fields to
+ * @param aNames An object containing the name and labels for 'N' property fields
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ */
+	{
+	if(aTreatAsPrn)
+		{
+		MergeSpecifiedNameFieldL(aContact, KUidContactFieldGivenNamePronunciation,	aNames, aOption, KContactGivenName);
+		MergeSpecifiedNameFieldL(aContact, KUidContactFieldFamilyNamePronunciation,	aNames, aOption, KContactFamilyName);
+		}
+	else
+		{
+		MergeSpecifiedNameFieldL(aContact, KUidContactFieldPrefixName,		aNames, aOption, KContactPrefixName);
+		MergeSpecifiedNameFieldL(aContact, KUidContactFieldGivenName,		aNames, aOption, KContactGivenName);
+		MergeSpecifiedNameFieldL(aContact, KUidContactFieldAdditionalName,	aNames, aOption, KContactAdditionalName);
+		MergeSpecifiedNameFieldL(aContact, KUidContactFieldFamilyName,		aNames, aOption, KContactFamilyName);
+		MergeSpecifiedNameFieldL(aContact, KUidContactFieldSuffixName,		aNames, aOption, KContactSuffixName);
+		}
+	}
+
+
+void CVCardToContactsAppConverter::MergeSpecifiedAddressFieldL(CContactItem& aContact, const CVCardAddress& aAddress, const TUid& aFieldUid, const TUid& aMappingUid, TInt aAddressIndex, TInt aOption)
+/**
+ * Merge specific address fields from a contact
+ *
+ * @param aContact Contact item to add fields to
+ * @param aUid The Uid of the contact
+ * @param aFieldUid Contacts database Field ID
+ * @param aMappingUid VCard Mapping ID
+ * @param aAddress An object containing the name and labels for 'ADR' property fields
+ * @param aAddressIndex Index into aAddress
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ */
+	{
+	CContactItemFieldSet& oldfieldset = aContact.CardFields();
+	TInt pos = 0;
+	const TBool processWhitespace = (aOption & CContactVCardConverter::EConnectWhitespace);
+
+	if (aAddress.Mapping() == KNullUid)
+		{
+		TBool fieldFound = EFalse;
+		TInt startPos = KContactFieldSetSearchAll;
+
+		while(!fieldFound && !(pos == KErrNotFound))
+			{
+			pos = oldfieldset.FindNext(aMappingUid, startPos);
+			startPos = pos + 1;
+			if (pos != KErrNotFound )
+				{
+				CContactItemField& tempField = oldfieldset[pos];
+				const CContentType& tempContentType = tempField.ContentType();
+				TBool additionalMapFound = EFalse;
+				additionalMapFound |= tempContentType.ContainsFieldType(KUidContactFieldVCardMapHOME);
+				additionalMapFound |= tempContentType.ContainsFieldType(KUidContactFieldVCardMapWORK);
+				additionalMapFound |= tempContentType.ContainsFieldType(KUidContactFieldVCardMapPREF);
+				if (!additionalMapFound)
+					{
+					fieldFound = ETrue;
+					}
+				}
+			}
+		}
+	else
+		{
+		pos = oldfieldset.Find(aAddress.Mapping(), aMappingUid);
+		}
+
+	// First check whether the field is present in the contact card
+	// Also verify that the array of address sub-values actually contains a specific
+	// value for the requested index.
+	if (aAddress.ItemCount() > aAddressIndex)
+		{
+		const TPtrC pValue = aAddress.Item(aAddressIndex);
+		const TInt length = pValue.Length();
+		if (processWhitespace)
+			{
+			TBool isSingleSpace = EFalse;
+			if (length == 1)
+				{
+				isSingleSpace = (pValue[0] == KContactVCardSpaceCharacter);
+				}
+			if	((length || isSingleSpace) && (pos != KErrNotFound))
+				{
+				// This means the PC side field is empty, so delete the corresponding device-side field.
+				aContact.RemoveField(pos);
+				}
+			if	(length && !isSingleSpace)
+				{
+				TInt insertPos = 0;
+				SetAddressFieldL(aAddress, aContact, aOption, aAddressIndex, aFieldUid, insertPos, aMappingUid);
+				}
+			}
+		else
+			{
+			if (pos != KErrNotFound)
+				{
+				// This means the PC side field is empty, so delete the corresponding device-side field.
+				aContact.RemoveField(pos);
+				}
+			if (length)
+				{
+				// This means the PC side field is not empty, so add the corresponding contents.
+				TInt insertPos = 0;
+				SetAddressFieldL(aAddress, aContact, aOption, aAddressIndex, aFieldUid, insertPos, aMappingUid);
+				}
+			}
+		}
+	}
+
+
+void CVCardToContactsAppConverter::MergeAddressFieldsL(CContactItem& aContact, const CVCardAddress& aAddress, TInt aOption)
+/**
+ * Merge a specific field from the contact card
+ *
+ * @param aContact Contact item to add fields to
+ * @param aUid The Uid of the contact
+ * @param aAddresses Address of locally stored contact
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ */
+	{
+	MergeSpecifiedAddressFieldL(aContact, aAddress, KUidContactFieldPostOffice, KUidContactFieldVCardMapPOSTOFFICE, KContactPostOffice, aOption);
+	MergeSpecifiedAddressFieldL(aContact, aAddress, KUidContactFieldExtendedAddress, KUidContactFieldVCardMapEXTENDEDADR, KContactExtendedAddress, aOption);
+	MergeSpecifiedAddressFieldL(aContact, aAddress, KUidContactFieldAddress, KUidContactFieldVCardMapADR, KContactAddress, aOption);
+	MergeSpecifiedAddressFieldL(aContact, aAddress, KUidContactFieldLocality, KUidContactFieldVCardMapLOCALITY, KContactLocality, aOption);
+	MergeSpecifiedAddressFieldL(aContact, aAddress, KUidContactFieldRegion, KUidContactFieldVCardMapREGION, KContactRegion, aOption);
+	MergeSpecifiedAddressFieldL(aContact, aAddress, KUidContactFieldPostcode, KUidContactFieldVCardMapPOSTCODE, KContactPostcode, aOption);
+	MergeSpecifiedAddressFieldL(aContact, aAddress, KUidContactFieldCountry, KUidContactFieldVCardMapCOUNTRY, KContactCountry, aOption);
+	}
+
+
+TBool CVCardToContactsAppConverter::MergeVCardWithContactItemL(CContactItem &aContact, CParserVCard& aVCard, TUnknownPropertyBehaviour aUnknownPropertyBehaviour, TInt aOption)
+/**
+ * Merge a vCard with an existing contact item
+ *
+ * @param aContact Contact item to add fields to
+ * @param aVCard vCard parser object
+ * @param aUnknownPropertyBehaviour Specifies how extension properties are handled
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ * @return ETrue if contact item should be deleted, EFalse otherwise
+ */
+	{
+	TInt ii = 0;
+	TInt count = 0;
+	//
+	TBool deleteContact = ETrue;
+	iUnknownPropertyBehaviour = aUnknownPropertyBehaviour;
+	TTime lastModified;
+	GetVCardModifiedTimeL(aVCard, lastModified);
+
+	// We're performing a merge
+	SetImportType(ECntVCardImportTypeMerge);
+
+	// Get Name
+	CVCardItemAndLabel* names = GetContactNameLC(aVCard, aOption);
+	if	(names && names->ItemCount())
+		{
+		MergeNameFieldsL(aContact, *names, aOption);
+		deleteContact = EFalse;
+		}
+	CleanupStack::PopAndDestroy(names);
+	// Get Name pronunciation
+ 	names = GetContactNamePrnLC(aVCard, aOption);
+ 	if (names && names->ItemCount())
+ 		{
+ 		MergeNameFieldsL(aContact, *names, aOption, ETrue);
+ 		}
+ 	CleanupStack::PopAndDestroy(names);
+
+	// Create address container
+	RPointerArray<CVCardAddress> addresses(KVCardImportAddressArrayGranularity);
+	CleanupStack::PushL(TCleanupItem(CVCardItemAndLabel::CleanUpResetDestroyAndCloseArray, &addresses));
+
+	// Get addresses from the vCard. This actually only retrieves four types of addresses:
+	// HOME, WORK, PREF and now additionally, 'general' addresses
+	GetAddressesL(aVCard, aOption, addresses);
+
+	// Import each of the located address field into the contact card
+	count = addresses.Count();
+    for (ii=0; ii<count; ii++)
+		{
+		const CVCardAddress* address = addresses[ii];
+		MergeAddressFieldsL(aContact, *address, aOption);
+		deleteContact = EFalse;
+		}
+
+	// Finished with addresses now, so clean up
+	CleanupStack::PopAndDestroy(&addresses);
+
+	// Get Organization related information from the vCard. This actually only retrieves the Company and the Department Name
+	CDesCArrayFlat* orgList = new (ELeave)CDesCArrayFlat(4);
+	CleanupStack::PushL(orgList);
+	TInt orgCount = GetVCardPropertyAsArrayOfValuesL(aVCard, KVersitTokenORG, *orgList);
+	if(orgCount)
+		{
+		MergeOrgDetailsL(aContact,*orgList,aOption);
+		deleteContact = EFalse;
+		}
+	CleanupStack::PopAndDestroy(orgList); // orgList
+	
+	// Get Single Instance of Class Field from the vCard.
+	HBufC* singleClass = NULL;
+	singleClass = HBufC::NewLC(256);
+   	TPtr ptr(singleClass->Des());
+
+	TInt classCount = GetSingleInstanceL(aVCard, KVersitTokenClass, ptr);
+	if(classCount)
+		{
+		MergeSingleInstanceL(aContact,ptr,KUidContactFieldClass, KUidContactFieldVCardMapClass,aOption);
+		deleteContact = EFalse;
+		}
+	CleanupStack::PopAndDestroy(singleClass);
+
+	// Get other properties
+	CArrayPtr<CParserProperty>* arrayOfProperties = aVCard.ArrayOfProperties();
+	CleanupStack::PushL(TCleanupItem(CleanUpResetAndDestroy, arrayOfProperties));
+	count = arrayOfProperties->Count();
+
+	//Within this loop we store the content type of the last field updated.
+	//If the content type of the current field matches, we update fieldCount
+	//This holds the position of the field to update, to prevent us from
+	//overwriting the field we just updated.
+
+	TInt fieldCount = 0;
+	CContactItemField* oldField = NULL;
+	CContactItemField* newField = NULL;
+
+	for (ii = 0; ii < count; ii++)
+ 	  	{
+        if (((*arrayOfProperties)[ii]->Name() != KVersitTokenADR) && ((*arrayOfProperties)[ii]->Name() != KVersitTokenORG) && ((*arrayOfProperties)[ii]->Name() != KVersitTokenClass))
+		 {
+		  TBool unsupportedProperty=EFalse;
+		 
+			newField = GetVCardPropertyAsContactFieldLC((*arrayOfProperties)[ii], aOption,unsupportedProperty);
+			if (newField)
+				{
+				TInt ttnumber;
+				if (!oldField)
+					{
+					fieldCount = 1;
+					ttnumber = 1;
+					if (aOption & CContactVCardConverter::ETTFormat)
+						{
+						ttnumber = GetVCardPropertyTTNumber((*arrayOfProperties)[ii]);
+						}
+					}
+				else if (newField->ContentType().IsEqualForSyncUpdate(oldField->ContentType()))
+					{
+					ttnumber = ++fieldCount;
+					}
+				else
+					{
+					fieldCount = 1;
+					ttnumber = 1;
+					if (aOption & CContactVCardConverter::ETTFormat)
+						{
+						ttnumber = GetVCardPropertyTTNumber((*arrayOfProperties)[ii]);
+						}
+					}
+				if (oldField)
+					{
+					CleanupStack::Pop(); //newField
+					CleanupStack::PopAndDestroy(oldField);
+					oldField = NULL;
+					CleanupStack::PushL(newField);
+					}
+				oldField = newField;
+				aContact.CardFields().UpdateFieldSyncL(*newField, ttnumber);
+				if(newField->Storage()->IsFull())
+					{
+					deleteContact = EFalse;
+					}
+				newField = NULL;	
+				}
+			else if (unsupportedProperty)
+				{
+				CleanupStack::Pop();
+				deleteContact = EFalse;
+				}
+			else{
+				CleanupStack::Pop();
+				}
+			}
+    	}
+    //Remove all empty fields after merge
+    CContactItemFieldSet &fieldset = aContact.CardFields();
+    TInt i = 0;
+    for(; i < fieldset.Count(); ++i)
+    	{
+    	if( !fieldset[i].Storage()->IsFull() )
+    		{
+    		fieldset.Remove( i-- );
+    		}
+    	}
+
+	if (newField)
+		//coverity [dead_error_begin]
+		{	
+		CleanupStack::PopAndDestroy(newField);
+		newField = NULL;
+		}
+
+	if (oldField)
+		{
+		CleanupStack::PopAndDestroy(oldField);
+		oldField = NULL;
+		}
+	
+	if (lastModified != Time::NullTTime())
+		{
+    	aContact.SetLastModified(lastModified);
+		}
+    CleanupStack::PopAndDestroy(arrayOfProperties);
+	return(deleteContact);
+	}
+/**
+ * Set a name field. Only creates a field if the specified name text is not empty.
+ *
+ * @param aNames An object containing the name and labels for 'N' property fields
+ * @param aContact Contact item to add fields to
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ * @param aIndex Array position of field to use
+ * @param aFieldType Field type of field to add (TFieldType)
+ * @param aInsertPos Position in contact field set to add field
+*/
+void CVCardToContactsAppConverter::SetNameFieldL(const CVCardItemAndLabel& aNames, CContactItem& aContact, TInt aOption, TInt aIndex, TFieldType aFieldType, TInt& aInsertPos) const
+	{
+	const TInt count = aNames.ItemCount();
+	const TInt labelCount = aNames.LabelCount();
+	//
+	if	(aIndex >= 0 && aIndex < count)
+		{
+		const TPtrC pFieldText(aNames.Item(aIndex));
+		TBool addField = EFalse;
+
+		if (CContactVCardConverter::EConnectWhitespace & aOption)
+			{
+			addField = CContactVCardConverter::ContainsImportableData(pFieldText, CContactVCardConverter::EPropertyValueComposite, ImportType());
+			}
+		else
+			{
+			addField = (pFieldText.Length());
+			}
+		// Only add the field if it contains some data
+		if	(addField)
+			{
+			CContactItemField* contactItemField = CContactItemField::NewLC(KStorageTypeText, aFieldType);
+			contactItemField->SetMapping(KUidContactFieldVCardMapUnusedN);
+			if ((aOption & CContactVCardConverter::EIncludeX) && (aIndex >= 0 && aIndex < labelCount))
+				contactItemField->SetLabelL(aNames.Label(aIndex));
+			//
+			HBufC* encodedText = EncodeL(pFieldText, ETrue);
+			contactItemField->TextStorage()->SetText(encodedText); // takes ownership
+			
+			aContact.InsertFieldL(*contactItemField, aInsertPos++);
+			CleanupStack::Pop(contactItemField);
+			}
+		}
+	}
+
+HBufC* CVCardToContactsAppConverter::EncodeL(const TDesC& aText, TBool aTextTobeTruncated) const
+	{
+	const TUid KUidTextToEtextNoTrim={0x10281B4C};
+	
+	// Make a copy of aText and truncate if necessary.
+	TPtr truncText(const_cast<TUint16*>(aText.Ptr()),aText.Length());
+	
+	if(aTextTobeTruncated)
+		truncText.SetLength(aText.Length()>KCntMaxTextFieldLength ? KCntMaxTextFieldLength : aText.Length());
+	else
+		truncText.SetLength(aText.Length());
+			
+	HBufC8* text=HBufC8::NewLC(truncText.Length()*2);
+	TPtr8 ptr = text->Des();
+	TInt i;
+	for (i=0; i < truncText.Length(); i++)
+		{
+		ptr.Append(truncText[i] & 0x00FF);
+		ptr.Append((truncText[i] >> 8) & 0x00FF);
+		}
+	CCnaConverterList* convList=CCnaConverterList::NewLC(); 
+	CConverterBase* conv = convList->NewConverterL(KUidTextToEtextNoTrim); 
+	if (!conv)
+		{
+		CleanupStack::PopAndDestroy();          // convList 
+		User::Leave(KErrNotSupported);
+		}
+	CleanupStack::PushL(conv);
+	CBufFlat* decodeBuffer = CBufFlat::NewL(256); 
+	CleanupStack::PushL(decodeBuffer);
+	CBufFlat* encodedBuffer = CBufFlat::NewL(256); 
+	CleanupStack::PushL(encodedBuffer);
+	decodeBuffer->InsertL(0,ptr);
+	RBufReadStream readStream;
+	RBufWriteStream writeStream;
+	readStream.Open(*decodeBuffer);
+	writeStream.Open(*encodedBuffer);
+	conv->ConvertObjectL(readStream, writeStream); 
+	readStream.Close();
+	TInt size=encodedBuffer->Size();
+	HBufC* writeBuf=HBufC::NewLC(size); 
+	TPtr resulttext = writeBuf->Des();
+	for(i = 0; i < (size - 1); i += 2)
+		{
+		resulttext.Append((encodedBuffer->Ptr(0)[i + 1] << 8) | 
+		encodedBuffer->Ptr(0)[i]);
+		}
+
+	writeStream.CommitL();
+	writeStream.Close();
+	CleanupStack::Pop(); // writebuf
+	CleanupStack::PopAndDestroy(2); // buffers 
+	CleanupStack::PopAndDestroy(2); //conv+convList 
+	CleanupStack::PopAndDestroy();  //text
+	return writeBuf;
+	}
+
+/**
+ * Set name fields
+ *
+ * @param aNames An object containing the name and labels for 'N' property fields
+ * @param aContact Contact item to add fields to
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ * @param aTreatAsPronunciation If true, save name data in pronunciation fields, otherwise save as an actual name (the default)
+ */
+void CVCardToContactsAppConverter::SetNameFieldsL(const CVCardItemAndLabel& aNames, CContactItem& aContact, TInt aOption, TBool aTreatAsPronunciation) const
+	{
+	TInt insertPos=0;
+	if( aTreatAsPronunciation )
+		{
+		SetNameFieldL(aNames, aContact, aOption, KContactGivenName, KUidContactFieldGivenNamePronunciation, insertPos);
+		SetNameFieldL(aNames, aContact, aOption, KContactFamilyName, KUidContactFieldFamilyNamePronunciation, insertPos);
+		}
+	else
+		{
+		SetNameFieldL(aNames, aContact, aOption, KContactPrefixName, KUidContactFieldPrefixName, insertPos);
+		SetNameFieldL(aNames, aContact, aOption, KContactGivenName, KUidContactFieldGivenName, insertPos);
+		SetNameFieldL(aNames, aContact, aOption, KContactAdditionalName, KUidContactFieldAdditionalName, insertPos);
+		SetNameFieldL(aNames, aContact, aOption, KContactFamilyName, KUidContactFieldFamilyName, insertPos);
+		SetNameFieldL(aNames, aContact, aOption, KContactSuffixName, KUidContactFieldSuffixName, insertPos);
+		}
+	}
+
+
+
+void CVCardToContactsAppConverter::SetAddressFieldL(const CVCardAddress& aAddress, CContactItem& aContact, TInt aOption, TInt aIndex, TFieldType aFieldType, TInt& aInsertPos, TUid aMapping) const
+/**
+ * Set an address field
+ *
+ * @param aAddress An object containing the name and labels for 'ADR' property fields
+ * @param aContact Contact item to add fields to
+ * @param aOption Import preferences (available options defined in CContactVCardConverter::TOptions)
+ * @param aIndex Array position of field to use
+ * @param aFieldType Contact field type for address field
+ * @param aInsertPos Position in contact field set to add field
+ * @param aMapping vCard field mapping (eg. KUidContactFieldVCardMapPOSTCODE)
+ */
+	{
+	const TInt count = aAddress.ItemCount();
+	if	(aIndex >= 0 && aIndex < count)
+		{
+		const TPtrC pFieldText(aAddress.Item(aIndex));
+		TBool doInsert = ETrue; // By default we process the data, but if the TimeIS flag is set, then we need to check the content first.
+
+		if (CContactVCardConverter::EConnectWhitespace & aOption)
+			{
+			doInsert = (CContactVCardConverter::ContainsImportableData(pFieldText, CContactVCardConverter::EPropertyValueComposite, ImportType()));
+			}
+		if (doInsert)
+			{
+			CContentType* content = CContentType::NewL(aFieldType, aMapping);
+			CleanupStack::PushL(content);
+
+			if	(aAddress.Mapping() != KNullUid) // KNullUid corresponds to general address
+				{
+				content->AddFieldTypeL(aAddress.Mapping());
+				}
+
+			CContactItemField* contactItemField = CContactItemField::NewLC(KStorageTypeText, *content);
+			if ((aOption & CContactVCardConverter::EIncludeX) && (aIndex >= 0 && aIndex < aAddress.LabelCount()))
+				{
+				// get the correct label
+				TBuf<25> labelName(KContactVarVCardXDashEPOCCNTMODEL);
+				labelName.AppendFormat(KContactVarVCardLABELn, aIndex);
+				TInt position=KErrNotFound;
+				TInt err = aAddress.FindLabel(labelName, position);
+				if	(err==KErrNone && position!=KErrNotFound)
+					contactItemField->SetLabelL(aAddress.Label(position));
+				}
+			
+			HBufC* encodedText = EncodeL(pFieldText, ETrue);
+			contactItemField->TextStorage()->SetText(encodedText); // takes ownership
+			
+			// The contact takes ownership of the field.
+			aContact.InsertFieldL(*contactItemField, aInsertPos++);
+			CleanupStack::Pop(contactItemField);
+			CleanupStack::PopAndDestroy(content);
+			}
+		}
+	}
+
+
+void CVCardToContactsAppConverter::SetAddressFieldsL(const CVCardAddress& aAddress, CContactItem& aContact, TInt aOption) const
+/**
+ * Set the address fields
+ *
+ * @param aAddressses An object containing the name and labels for 'ADR' property fields
+ * @param aContact Contact item to add fields to
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ */
+	{
+	TInt insertPos = 0;
+	SetAddressFieldL(aAddress, aContact, aOption, KContactPostOffice, KUidContactFieldPostOffice, insertPos, KUidContactFieldVCardMapPOSTOFFICE);
+	SetAddressFieldL(aAddress, aContact, aOption, KContactExtendedAddress, KUidContactFieldExtendedAddress, insertPos, KUidContactFieldVCardMapEXTENDEDADR);
+	SetAddressFieldL(aAddress, aContact, aOption, KContactAddress, KUidContactFieldAddress, insertPos, KUidContactFieldVCardMapADR);
+	SetAddressFieldL(aAddress, aContact, aOption, KContactLocality, KUidContactFieldLocality, insertPos, KUidContactFieldVCardMapLOCALITY);
+	SetAddressFieldL(aAddress, aContact, aOption, KContactRegion, KUidContactFieldRegion, insertPos, KUidContactFieldVCardMapREGION);
+	SetAddressFieldL(aAddress, aContact, aOption, KContactPostcode, KUidContactFieldPostcode, insertPos, KUidContactFieldVCardMapPOSTCODE);
+	SetAddressFieldL(aAddress, aContact, aOption, KContactCountry, KUidContactFieldCountry, insertPos, KUidContactFieldVCardMapCOUNTRY);
+	}
+
+
+/**
+ * Convert aVCard into a ContactItem. This method leaves a CContactItem instance on the cleanup stack upon exit.
+ *
+ * @param aVCard					vCard parser object
+ * @param aAgentContact             Agent contact item. Note that this object is passed by reference but is not
+ *                                  left on the cleanup stack upon exit from this function. Clients shoul re-Push
+ *									this object if needed.
+ * @param aUnknownPropertyBehaviour Specifies how extension properties are handled
+ * @param aOption                   Import preferences (available options defined in CContactDatabase::TOptions)
+ *
+ * @return                          A CContactItem instance (on the cleanup stack) that has been constructed from
+ *                                  the vCard data.
+ */
+CContactItem* CVCardToContactsAppConverter::GetVCardAsContactItemLC(CParserVCard& aVCard, TUnknownPropertyBehaviour aUnknownPropertyBehaviour, TInt aOption)
+	{
+	TInt ii=0;
+	TInt count = 0;
+	//
+	iUnknownPropertyBehaviour = aUnknownPropertyBehaviour;
+	TTime lastModified;
+	TBuf<KUidStringLength> uidstring;
+	GetVCardModifiedTimeL(aVCard, lastModified);
+	GetVCardUidStringL(aVCard, uidstring);
+
+	//
+	CContactCard* mainContact = CContactCard::NewLC();
+	//
+	// We're performing an initial import
+	SetImportType(ECntVCardImportTypeFirstSync);
+
+	// Get Name
+	CVCardItemAndLabel* names = GetContactNameLC(aVCard, aOption);
+	if (names && names->ItemCount())
+		SetNameFieldsL(*names, *mainContact, aOption);
+	CleanupStack::PopAndDestroy(names);
+
+	// Get Name pronunciation
+	names = GetContactNamePrnLC(aVCard, aOption);
+	if (names && names->ItemCount())
+		{
+		SetNameFieldsL(*names, *mainContact, aOption, ETrue);
+		}
+	CleanupStack::PopAndDestroy(names);
+
+	// Create address container
+	RPointerArray<CVCardAddress> addresses(KVCardImportAddressArrayGranularity);
+	CleanupStack::PushL(TCleanupItem(CVCardItemAndLabel::CleanUpResetDestroyAndCloseArray, &addresses));
+
+	// Get addresses
+	GetAddressesL(aVCard, aOption, addresses);
+
+	// Import each address field into the contact card
+	count = addresses.Count();
+    for (ii=0; ii<count; ii++)
+		{
+		const CVCardAddress* address = addresses[ii];
+		SetAddressFieldsL(*address, *mainContact, aOption);
+		}
+
+	// Finished with addresses now, so clean up
+	CleanupStack::PopAndDestroy(&addresses);
+
+// Get Organization related information from the vCard. This actually only retrieves the Company and the Department Name
+	CDesCArrayFlat* orgList = new (ELeave)CDesCArrayFlat(4);
+	CleanupStack::PushL(orgList);
+	TInt orgCount = GetVCardPropertyAsArrayOfValuesL(aVCard, KVersitTokenORG, *orgList);
+	if(orgCount)
+		{
+		SetOrgDetailsL(*mainContact, *orgList, aOption);
+		}
+	CleanupStack::PopAndDestroy(orgList); // orgList
+
+// Get Single Instance of Class Field from the vCard.
+	HBufC* singleClass = NULL;
+	singleClass = HBufC::NewLC(256);
+	TPtr ptr(singleClass->Des());
+
+	TInt classCount = GetSingleInstanceL(aVCard, KVersitTokenClass, ptr);
+	if(classCount)
+		{
+		SetSingleInstanceL(*mainContact, ptr, KUidContactFieldClass, KUidContactFieldVCardMapClass,aOption);
+		}
+	CleanupStack::PopAndDestroy(singleClass);
+
+	// Get other properties
+    CArrayPtr<CParserProperty>* arrayOfProperties = aVCard.ArrayOfProperties();
+	CleanupStack::PushL(TCleanupItem(CleanUpResetAndDestroy,arrayOfProperties));
+	//
+	if	(arrayOfProperties)
+		{
+		count = arrayOfProperties->Count();
+		for (ii=0; ii<count; ii++)
+			{
+			CParserProperty* property = arrayOfProperties->At(ii);
+			// Address fields are handled in the above sections
+			if	((property->Name() != KVersitTokenADR) && (property->Name() != KVersitTokenORG) && (property->Name() != KVersitTokenClass))
+				{
+				// NOTE: This method can return a NULL object pushed onto the cleanup stack, so must
+				// always be popped!
+				TBool unsupportedProperty=EFalse;
+				CContactItemField* field = GetVCardPropertyAsContactFieldLC(property, aOption,unsupportedProperty);
+				if	(field)
+					{
+					mainContact->AddFieldL(*field);
+					}
+				CleanupStack::Pop(field);
+				}
+			}
+		// Email and Tel properties should only have a single Pref parameter
+		AdjustForPrefRule(*mainContact, KUidContactFieldEMail, KUidContactFieldVCardMapEMAILINTERNET);
+		AdjustForPrefRule(*mainContact, KUidContactFieldPhoneNumber, KUidContactFieldVCardMapTEL);
+		}
+	//
+    if	(lastModified != Time::NullTTime())
+    	{
+    	mainContact->SetLastModified(lastModified);
+    	}
+	//
+	mainContact->SetUidStringL(uidstring);
+	//
+    CleanupStack::PopAndDestroy(); // arrayOfProperties->ResetAndDestroy()
+	//
+	return mainContact;
+    }
+
+
+/**
+ * Extract the last modified date of the vCard.
+ * If there is no 'REV' property the last modified time is returned as as NULL TTime value.
+ *
+ * @param aVCard vCard parser object
+ * @param aLastModified Last modified time
+ */
+void CVCardToContactsAppConverter::GetVCardModifiedTimeL(CParserVCard& aVCard,TTime& aLastModified)
+	{
+	CArrayPtr<CParserProperty>* arrayOfRevisions=aVCard.PropertyL(KVersitTokenREV,TUid::Uid(KVersitPropertyDateTimeUid),EFalse);
+	if (arrayOfRevisions && arrayOfRevisions->Count())
+		{
+		CleanupStack::PushL(arrayOfRevisions);
+   		CParserPropertyValueDateTime* revision=(static_cast<CParserPropertyValueDateTime*>((*arrayOfRevisions)[0]->Value()));
+
+   		aLastModified=revision->Value()->iDateTime;
+		if (revision->Value()->iRelativeTime != TVersitDateTime::EIsUTC )
+			// The REV property isn't in UTC time, so let's (try to) convert it
+			{
+			CArrayPtr<CParserProperty>* arrayOfTimeZones=aVCard.PropertyL(KVersitTokenTZ, TUid::Uid(KVersitPropertyTimeZoneUid),EFalse);
+			if (arrayOfTimeZones && arrayOfTimeZones->Count())
+				// If we have the TZ property, adjust the machine local timestamp.
+				// If we don't have the TZ property, we'll just pretend that the REV
+				// property was already a UTC value.
+				{
+				CleanupStack::PushL(arrayOfTimeZones);
+				CParserPropertyValueTimeZone* timeZone =
+						static_cast<CParserPropertyValueTimeZone*> ((*arrayOfTimeZones)[0]->Value());
+				// Subtract the offset: UTC + Offset = Local => UTC = Local - Offset.
+				TTimeIntervalSeconds utcOffset = timeZone->Value().Int();
+				aLastModified -= utcOffset;
+				CleanupStack::PopAndDestroy(arrayOfTimeZones);
+				}
+			}
+		CleanupStack::PopAndDestroy(arrayOfRevisions);
+   		}
+   	else
+		{
+   		aLastModified=Time::NullTTime();
+		}
+    }
+
+
+/**
+ * Extract the vCard 'UID' property from the vCard.
+ *
+ * @param aVCard vCard parser object
+ * @param aUidString UID property value
+ */
+void CVCardToContactsAppConverter::GetVCardUidStringL(CParserVCard& aVCard,TDes& aUidString) const
+	{
+	const CArrayPtr<CParserProperty>* arrayOfProperties=aVCard.PropertyL(KVersitTokenUID,TUid::Uid(KVersitPropertyHBufCUid),EFalse);
+    if (arrayOfProperties)
+    	{
+    	TInt count=arrayOfProperties->Count();
+    	if (count)
+    		{
+    		CParserPropertyValueHBufC* uidstring=(STATIC_CAST(CParserPropertyValueHBufC*,(*arrayOfProperties)[0]->Value()));
+			if (uidstring->Value().Length() > KUidStringLength )
+				aUidString=uidstring->Value().Left(KUidStringLength) ; // truncate
+			else
+				aUidString=uidstring->Value();
+    		}
+    	delete arrayOfProperties;
+    	}
+    }
+
+
+/**
+ * Convert aVCardProperty into contact field.
+ *
+ * @param aProperty vCard property
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ * @param aUnsupportedProperty Return whether or not the field is supported by the PC PIM, only relevant when using the EConnectWhitespace flag
+ * @return Contact field or a NULL pointer (pushed onto the cleanup stack) in the case where
+ *         it wasn't possible to create a contact field for this vCard property.
+ */
+CContactItemField* CVCardToContactsAppConverter::GetVCardPropertyAsContactFieldLC(CParserProperty* aProperty,TInt aOption,TBool& aUnsupportedProperty)
+ 	{
+	TUid mappingUid;
+	TStorageType storageType;
+	CContentType* content=MapVCardPropertyToContentAndStorageTypeL(*aProperty,storageType);
+	CleanupStack::PushL(content);
+	mappingUid=content->Mapping();
+	TBool noConversion=EFalse;
+	aUnsupportedProperty=EFalse;
+
+	if (mappingUid==KUidContactFieldVCardMapNotRequired)
+		{
+		noConversion=ETrue;
+		}
+	else
+		{	/*Could preserve unknown non X- if VCard version no>2.1*/
+		switch (iUnknownPropertyBehaviour)
+			{
+			case EDiscardAllUnknownProperties:
+				if (mappingUid==KUidContactFieldVCardMapUnknownXDash)
+					noConversion=ETrue;
+					/* fall through */
+			case EDiscardNonXDashUnknownProperties:
+				if (mappingUid==KUidContactFieldVCardMapUnknown)
+					noConversion=ETrue;
+					/* fall through */
+			default:
+				break;
+			}
+		}
+
+	CContactItemField* contactItemField=NULL;
+	if (!noConversion)
+		{
+		TBool validImportableDataFound = ETrue;
+		contactItemField=CContactItemField::NewLC(storageType,*content);
+		if ((mappingUid==KUidContactFieldVCardMapUnknown) ||(mappingUid==KUidContactFieldVCardMapUnknownXDash))
+	    		{
+	    		TBool propertyTobeTruncated = PropertyTobeTruncated(aProperty->Name());
+	    		HBufC* encodedText = EncodeL(STATIC_CAST(CParserPropertyValueHBufC*,aProperty->Value())->Value(), propertyTobeTruncated);
+	    		contactItemField->TextStorage()->SetText(encodedText); // takes ownership
+				
+	    		contactItemField->SetHidden(ETrue);
+	    		}
+		else
+			{
+	    		switch (contactItemField->StorageType())
+	    			{
+	    			case KStorageTypeText:
+	    				{
+					TInt id = aProperty->Value()->Uid().iUid;
+					if(mappingUid == KUidContactFieldVCardMapORGPronunciation)
+						{ // this should be treated as an array instead of a single string
+						id = KVersitPropertyCDesCArrayUid;
+						}
+	    				switch (id)
+	    					{
+	    					case KVersitPropertyCDesCArrayUid:
+	    						{
+								TBool doConvert = ETrue;
+								 TBool pushed = EFalse;
+								CParserPropertyValueCDesCArray* propertyValueWrapper=NULL;
+								if(mappingUid == KUidContactFieldVCardMapORGPronunciation)
+									{ // Treat a SOUND with X-IRMC-ORG param as an array
+									const CParserPropertyValueHBufC* valueScalar = static_cast<CParserPropertyValueHBufC*>(aProperty->Value());
+									if(valueScalar)
+										{
+										propertyValueWrapper = valueScalar->TreatAsArrayPropertyLC(*aProperty);
+										pushed= ETrue;
+										}
+									}
+								else
+									{
+									propertyValueWrapper = static_cast<CParserPropertyValueCDesCArray*>(aProperty->Value());
+									}
+								CDesCArray* propertyValue = NULL;
+								if	(propertyValueWrapper)
+									{
+									propertyValue = propertyValueWrapper->Value();
+									}
+
+								if ((CContactVCardConverter::EConnectWhitespace & aOption) && propertyValue)
+									{
+									doConvert = TextArrayContainsImportableData(*propertyValue);
+									if (doConvert)
+										{
+										RemoveWhitespaceFromCompositePropertyL(*propertyValue);
+										}
+									}
+								if (doConvert && propertyValue)
+									{
+	   								TInt count = propertyValue->MdcaCount();
+								    HBufC *txt=HBufC::NewL(0);
+									CleanupStack::PushL(txt);
+									// concatenate the array
+								    for (TInt ii=0;ii<count;ii++)
+								    	{
+										TInt mdcaLen=propertyValue->MdcaPoint(ii).Size();
+										if (mdcaLen>0)
+											{
+								    			if (txt->Length()>0)
+												{
+												txt->Des().Append(TChar('\n'));
+												}
+											txt=txt->ReAllocL(txt->Length()+mdcaLen+1);	// +1 In case we add '\n'
+											CleanupStack::Pop();	// txt(old value)
+											CleanupStack::PushL(txt);
+											TPtrC temp(propertyValue->MdcaPoint(ii));
+											txt->Des().Append(temp);
+											}
+								    	}
+			   						TBool propertyTobeTruncated = PropertyTobeTruncated(aProperty->Name());
+			   						HBufC* encodedText = EncodeL(*txt, propertyTobeTruncated);
+			   						CleanupStack::PopAndDestroy(txt);
+			   						contactItemField->TextStorage()->SetText(encodedText); // takes ownership
+									}
+								else
+									{
+									validImportableDataFound = EFalse;
+									}
+								if(pushed)
+									{
+									CleanupStack::PopAndDestroy(propertyValueWrapper);
+									}
+	    						}
+			    				break;
+	   					case KVersitPropertyHBufCUid:
+							{
+							TBool doConvert = ETrue;
+
+							CParserPropertyValueHBufC* propertyValueWrapper = static_cast<CParserPropertyValueHBufC*>(aProperty->Value());
+							const TPtrC propertyValue(propertyValueWrapper->Value());
+
+							if (CContactVCardConverter::EConnectWhitespace & aOption)
+								{
+								if (propertyValue==KSingleSpacePropertyValue)
+									{
+									aUnsupportedProperty=ETrue;
+									}
+								doConvert = (CContactVCardConverter::ContainsImportableData(propertyValue, CContactVCardConverter::EPropertyValueSingle, ImportType()));
+								}
+							if (doConvert)
+								{
+								TBool propertyTobeTruncated = PropertyTobeTruncated(aProperty->Name());
+								HBufC* encodedText = EncodeL(propertyValue, propertyTobeTruncated);
+								contactItemField->TextStorage()->SetText(encodedText); // takes ownership
+								}
+							else
+								{
+								validImportableDataFound = EFalse;
+								}
+							}
+			    				break;
+		   				default:;
+	    					}
+	    				}
+		    			break;
+		    		case KStorageTypeDateTime:
+	    				{
+		    			switch (aProperty->Value()->Uid().iUid)
+		    				{
+		    				case KVersitPropertyDateTimeUid:
+		    					STATIC_CAST(CContactDateField*,contactItemField->Storage())->SetTime(STATIC_CAST(CParserPropertyValueDateTime*,aProperty->Value())->Value()->iDateTime);
+		    					break;
+						case KVersitPropertyDateUid:
+							STATIC_CAST(CContactDateField*,contactItemField->Storage())->SetTime(STATIC_CAST(CParserPropertyValueDate*,aProperty->Value())->Value()->iDateTime);
+							break;
+		    				default:
+			    				break;
+		    				}
+		    			}
+	    				break;
+		    		case KStorageTypeStore:
+		    			{
+		    			STATIC_CAST(CContactStoreField*,contactItemField->Storage())->SetThingL(STATIC_CAST(CParserPropertyValueBinary*,aProperty->Value())->Value());
+		    			}
+		    			break;
+		    		default:
+		    			break;
+		    		}
+	    		}
+		if (aOption & CContactVCardConverter::EIncludeX)
+			{
+			TBuf8<KContactMaxVCardPropertyNameLength> paramName;
+			paramName=KContactVCardXDashEPOCCNTMODEL;
+			paramName.Append(KContactVCardFIELDHIDDEN);
+			if (aProperty->Param(paramName))
+				contactItemField->SetHidden(ETrue);
+			paramName.Zero();
+			paramName=KContactVCardXDashEPOCCNTMODEL;
+			paramName.Append(KContactVCardFIELDREADONLY);
+			if (aProperty->Param(paramName))
+				contactItemField->SetReadOnly(ETrue);
+			paramName.Zero();
+			paramName=KContactVCardXDashEPOCCNTMODEL;
+			paramName.Append(KContactVCardFIELDLABEL);
+			if (aProperty->Param(paramName))
+				contactItemField->SetLabel(aProperty->Param(paramName)->ValueL());
+			}
+		CleanupStack::Pop(contactItemField);
+	// The field is only added to the contact card if it was found to contain
+	// legitimate importable data (i.e. has content that does not simply consist of LWSP characters).
+	// This is important, since TimeIS sync drivers can create vCard objects (pushed over to the device)
+	// that contain only space characters for their Versit 'Property Parameter Values'.
+		if (!validImportableDataFound)
+			{
+			delete contactItemField;
+			contactItemField = NULL;
+			}
+		}
+	CleanupStack::PopAndDestroy(content);
+	// We may be pushing a NULL pointer back onto the cleanup stack, but clients of this
+	// method understand this feature.
+	CleanupStack::PushL(contactItemField);
+	return(contactItemField);
+    }
+
+
+/**
+ * Find a vCard property parameter in a vCard property
+ *
+ * @param aVCardProperty vCard property
+ * @return Property parameter number
+ */
+TInt CVCardToContactsAppConverter::GetVCardPropertyTTNumber(CParserProperty* aVCardProperty)
+    {
+    TInt ii;
+	TBuf8<KContactMaxVCardPropertyNameLength> paramName;
+	for (ii=1;ii<=KContactMaxFieldNumber;ii++)
+		{
+		paramName.Format(_L8("%d"),ii);
+		if (aVCardProperty->Param(paramName))
+			{
+			return (ii);
+			}
+		}
+	return 1;	// Default to 1 if no number found
+	}
+
+
+/**
+ * Extract the contact name fields from the vCard 'N' property.
+ * This method takes values from the 'N' vCard property and returns the family name,
+ * given name, middle name, prefix and suffix.
+ *
+ * Only the first instance of the 'N' property is used.
+ *
+ * @param aVCard vCard parser object
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ * @return An instance of CVCardItemAndLabel which encapsulates the names and their associated
+ *         labels contained within the vCard or a NULL pointer pushed onto the cleanup stack
+ *         if it wasn't possible to construct the object.
+ */
+CVCardItemAndLabel* CVCardToContactsAppConverter::GetContactNameLC(CParserVCard& aVCard, TInt aOption)
+    {
+	CVCardItemAndLabel* names = NULL;
+
+	CArrayPtr<CParserProperty>* arrayOfProperties=aVCard.PropertyL(KVersitTokenN,TUid::Uid(KVersitPropertyCDesCArrayUid));
+  	if (arrayOfProperties && arrayOfProperties->Count())
+		{
+		CleanupStack::PushL(TCleanupItem(CleanUpResetAndDestroy,arrayOfProperties));
+		//
+		//
+		CParserProperty* property = arrayOfProperties->At(0);
+		CDesCArray& items = *static_cast<CParserPropertyValueCDesCArray*>(property->Value())->Value();
+		names = MakeNamesFromItemsL(items, aOption, property );
+		CleanupStack::PopAndDestroy(arrayOfProperties);
+    	}
+
+	// Clients of this method assume that something is pushed onto the Cleanup Stack, so
+	// this might potentially be NULL.
+	CleanupStack::PushL(names);
+	return names;
+    }
+
+
+
+/**
+ * Extract the contact name fields from the vCard 'N' property.
+ * This method takes values from the 'N' vCard property and returns the family name,
+ * given name, middle name, prefix and suffix.
+ *
+ * Only the first instance of the 'N' property is used.
+ *
+ * @param aVCard vCard parser object
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ * @return An instance of CVCardItemAndLabel which encapsulates the names and their associated
+ *         labels contained within the vCard or a NULL pointer pushed onto the cleanup stack
+ *         if it wasn't possible to construct the object.
+ */
+CVCardItemAndLabel* CVCardToContactsAppConverter::GetContactNamePrnLC(CParserVCard& aVCard, TInt aOption)
+	{
+	CVCardItemAndLabel* names = NULL;
+
+	CArrayPtr<CParserProperty>* arrayOfProperties=aVCard.PropertyL(KVersitTokenSOUND,TUid::Uid(KVersitPropertyHBufCUid), EFalse);
+
+	if (arrayOfProperties )
+		{
+		CleanupStack::PushL(arrayOfProperties);
+		TInt count = arrayOfProperties->Count();
+		const CParserProperty* property=NULL;
+		for (TInt index=0;index<count;index++)
+			{
+			property = arrayOfProperties->At(index);
+			if(property->Param(KVersitParam8NamePrn))
+				{
+				index=count;
+				}
+			else
+				{
+				property=NULL;
+				}
+			}
+		if (property) // property is the 1st SOUND property with an X-IRMC-N parameter
+			{
+			const CParserPropertyValueHBufC* valueScalar = static_cast<CParserPropertyValueHBufC*>(property->Value());
+			if(valueScalar)
+				{
+				CParserPropertyValueCDesCArray* valueArray = valueScalar->TreatAsArrayPropertyLC(*property);
+				names = MakeNamesFromItemsL( *valueArray->Value(), aOption, property );// valueArray will never be NULL
+				CleanupStack::PopAndDestroy(valueArray);
+				}
+			}
+		CleanupStack::PopAndDestroy(arrayOfProperties);
+    		}
+
+	// Clients of this method assume that something is pushed onto the Cleanup Stack, so
+	// this might potentially be NULL.
+	CleanupStack::PushL(names);
+	return names;
+	}
+
+CVCardItemAndLabel* CVCardToContactsAppConverter::MakeNamesFromItemsL(const CDesCArray& aItems, TInt aOption, const CParserProperty* aProperty )
+	{
+	CVCardItemAndLabel* names = CVCardItemAndLabel::NewLC();
+
+	const TInt fieldcount = aItems.Count();
+	//
+    	for(TInt ii=0; ii<fieldcount; ii++)
+    		{
+		const TPtrC pField(aItems.MdcaPoint(ii));
+    		names->AddItemL(pField);
+		if (aOption & CContactVCardConverter::EIncludeX)
+			{
+			TBuf8<KContactMaxVCardPropertyNameLength> paramName(KContactVCardXDashEPOCCNTMODEL);
+			paramName.AppendFormat(KContactVCardLABELn,ii);
+			//
+			if(aProperty->Param(paramName))
+				{
+				HBufC* value = aProperty->Param(paramName)->ValueL();
+				CleanupStack::PushL(value);
+				names->AddLabelL(*value);
+				CleanupStack::PopAndDestroy(value);
+				}
+    			}
+		}
+	CleanupStack::Pop(names);
+	return names;
+	}
+
+/**
+ * Extract specific address properties
+
+ * @param aProperties An array of vCard properties which should be searched
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ * @param aParamMustMatch A property parameter which must be found in the specified vCard property. If this
+ *                        has a NULL (KNullDesC) value then the property is treated as satisfying this condition
+ * @param aParamMustNotMatch1 A property parameter which must not be found in the specified vCard property. If this
+ *                        has a NULL (KNullDesC) value then the property is treated as satisfying this condition
+ * @param aParamMustNotMatch2 Another property parameter which must not be found in the specified vCard property. If this
+ *                        has a NULL (KNullDesC) value then the property is treated as satisfying this condition
+ * @param aMapping The address mapping which is being searched for (e.g. HOME, WORK, etc)
+ * @return An address object which contains the name and labels (optionally) located in aProperties for this particular mapping
+ */
+CVCardAddress* CVCardToContactsAppConverter::GetSpecifiedAddressLC(const CArrayPtr<CParserProperty>& aProperties, TInt aOption, const TDesC8& aParamMustMatch, const TDesC8& aParamMustNotMatch1, const TDesC8& aParamMustNotMatch2, TUid aMapping)
+	{
+	CVCardAddress* address = NULL;
+	const TInt propertyCount = aProperties.Count();
+	//
+	for (TInt ii=0; ii<propertyCount; ii++)
+		{
+		CParserProperty* property = aProperties[ii];
+		
+		// DEF084708, also get and compare for ADDR;TYPE=HOME etc in addition to ADDR;HOME. 
+		// The param to be matched (or not matched) can be found either as the param name (ADDR;HOME)
+		// or in the param value of param name - TYPE (case ADDR;TYPE=HOME)
+		CParserParam* paramType = property->Param(KVersitParam8Type);
+		if (
+			(property->Name() == KVersitTokenADR) &&
+			(property->Value()->Uid() == TUid::Uid(KVersitPropertyCDesCArrayUid)) &&
+			
+			(!aParamMustMatch.Length()     || property->Param(aParamMustMatch) != NULL ||
+			(paramType != NULL && paramType->Value().CompareF(aParamMustMatch) == 0)) &&
+			
+			(!aParamMustNotMatch1.Length() || (property->Param(aParamMustNotMatch1) == NULL &&
+			(paramType == NULL || paramType->Value().CompareF(aParamMustNotMatch1) != 0))) &&
+			
+			(!aParamMustNotMatch2.Length() || (property->Param(aParamMustNotMatch2) == NULL &&
+			(paramType == NULL || paramType->Value().CompareF(aParamMustNotMatch2) != 0)))
+			)
+			{
+			
+			CDesCArray& items = *static_cast<CParserPropertyValueCDesCArray*>(property->Value())->Value();
+			const TInt fieldcount = items.Count();
+
+			// Create the address
+			address = CVCardAddress::NewLC(aMapping);
+
+			for(TInt jj = 0; jj < fieldcount; jj++)
+    			{
+				const TPtrC pField(items.MdcaPoint(jj));
+    			address->AddItemL(pField);
+				//
+				if	(aOption & CContactVCardConverter::EIncludeX)
+					{
+					TBuf8<KContactMaxVCardPropertyNameLength> paramName(KContactVCardXDashEPOCCNTMODEL);
+					paramName.AppendFormat(KContactVCardLABELn, jj);
+					//
+					if	(property->Param(paramName))
+						{
+						HBufC* value = property->Param(paramName)->ValueL();
+						CleanupStack::PushL(value);
+						address->AddLabelL(*value);
+						CleanupStack::PopAndDestroy(value);
+						}
+    				}
+				}
+
+			// End for-loop now we've found the specified item
+			break;
+			}
+		}
+
+	// Have to push something to ensure cleanup stack is balanced
+	if	(!address)
+		CleanupStack::PushL((TAny*) NULL);
+	return address;
+	}
+
+
+/**
+ * Extract home and work address properties from the vCard
+ *
+ * @param aVCard vCard parser object
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ * @param aAddresses An array reference which contains any located address fields upon exit from this method
+ */
+void CVCardToContactsAppConverter::GetAddressesL(CParserVCard& aVCard, TInt aOption, RPointerArray<CVCardAddress>& aAddresses)
+    {
+	CArrayPtr<CParserProperty>* arrayOfProperties = aVCard.ArrayOfProperties(EFalse);
+	if	(arrayOfProperties)
+		{
+		// Find ADR;HOME
+		CVCardAddress* home = GetSpecifiedAddressLC(*arrayOfProperties,
+													aOption,
+													KVersitParam8Home, // Must be ADR;HOME and not ADR;HOME;WORK
+													KVersitParam8Work,
+													KNullDesC8,
+													KUidContactFieldVCardMapHOME
+													);
+		if	(home)
+			User::LeaveIfError(aAddresses.Append(home));
+		CleanupStack::Pop(home);
+
+		// Find ADR;WORK
+		CVCardAddress* work = GetSpecifiedAddressLC(*arrayOfProperties,
+													aOption,
+													KVersitParam8Work, // Must be ADR;WORK
+													KNullDesC8,
+													KNullDesC8,
+													KUidContactFieldVCardMapWORK
+													);
+		if	(work)
+			User::LeaveIfError(aAddresses.Append(work));
+		CleanupStack::Pop(work);
+
+		// Find ADR;PREF
+		CVCardAddress* pref = GetSpecifiedAddressLC(*arrayOfProperties,
+													aOption,
+													KVersitParam8Pref, // Must be ADR;PREF and not ADR;HOME or ADR;WORK
+													KVersitParam8Home,
+													KVersitParam8Work,
+													KUidContactFieldVCardMapPREF
+													);
+		if	(pref)
+			User::LeaveIfError(aAddresses.Append(pref));
+		CleanupStack::Pop(pref);
+
+		// Find general ADR: address
+		CVCardAddress* general = GetSpecifiedAddressLC(*arrayOfProperties,
+													aOption,
+													KNullDesC8, // Just has to be ADR
+													KVersitParam8Home,
+													KVersitParam8Work,
+													KNullUid
+													);
+		if	(general)
+			User::LeaveIfError(aAddresses.Append(general));
+		CleanupStack::Pop(general);
+		}
+	}
+
+
+
+/**
+ * Map vCard property to contacts field content and storage type
+ *
+ * @param aVCardProperty vCard property
+ * @param aStorageType Type of contact field storage (TStorageType)
+ * @return Content type for vCard property
+ */
+CContentType* CVCardToContactsAppConverter::MapVCardPropertyToContentAndStorageTypeL(const CParserProperty& aVCardProperty, TStorageType& aStorageType)
+    {
+	TUid mapping=KUidContactFieldNone;
+	TFieldType fieldType=KUidContactFieldNone;
+	TPtrC8 vpropNameConst = aVCardProperty.Name();
+    aStorageType=KStorageTypeStore;
+
+	switch (aVCardProperty.Value()->Uid().iUid)
+    	{
+    case KVersitPropertyCDesCArrayUid:
+    	{
+    	aStorageType=KStorageTypeText;
+    	if (vpropNameConst.CompareF(KVersitTokenN)==0)
+			{
+    		fieldType=KUidContactFieldFamilyName;
+			mapping=KUidContactFieldVCardMapUnusedN;
+			}
+    	else if (vpropNameConst.CompareF(KVersitTokenADR)==0)
+			{
+    		fieldType=KUidContactFieldAddress;
+			mapping=KUidContactFieldVCardMapADR;
+			}
+ 		else if (vpropNameConst.CompareF(KVersitTokenChildren) == 0)
+ 			{
+ 			mapping = KUidContactFieldVCardMapChildren;
+ 			fieldType = KUidContactFieldChildren;
+ 			}
+    	}
+    	break;
+    case KVersitPropertyDateTimeUid:
+    	aStorageType=KStorageTypeDateTime;
+    	if (vpropNameConst.CompareF(KVersitTokenREV)==0)
+    		mapping=KUidContactFieldVCardMapNotRequired;
+    	break;
+    case KVersitPropertyDateUid:
+    	aStorageType=KStorageTypeDateTime;
+    	if (vpropNameConst.CompareF(KVersitTokenBDAY)==0)
+			{
+    		mapping=KUidContactFieldVCardMapBDAY;
+			fieldType=KUidContactFieldBirthday;
+			}
+ 		else if (vpropNameConst.CompareF(KVersitTokenAnniversary) == 0)
+ 			{
+ 			mapping = KUidContactFieldVCardMapAnniversary;
+ 			fieldType = KUidContactFieldAnniversary;
+ 			}
+    	break;
+    case KVCardPropertyAgentUid:
+		aStorageType = KStorageTypeContactItemId ; 
+		if (vpropNameConst.CompareF(KVersitTokenAGENT) == 0)
+			{
+			mapping = KUidContactFieldVCardMapAGENT;
+			}
+    	break;
+
+    case KVersitPropertyTimeZoneUid:
+    	aStorageType=KStorageTypeStore;
+
+    	if(vpropNameConst.CompareF(KVersitTokenTZ) == 0)
+    		{
+    		mapping=KUidContactFieldVCardMapNotRequired;
+    		}
+    	break;
+//
+    default:	// aka case KVersitPropertyHBufCUid:
+    	aStorageType=KStorageTypeText;
+		mapping = KUidContactFieldVCardMapUnknown; // Initialize to something sensible
+		switch (vpropNameConst[0])
+			{
+		case 'B':
+		case 'b':
+			if (vpropNameConst.CompareF(KVersitTokenBDAY)==0)
+				{
+    			mapping=KUidContactFieldVCardMapBDAY;
+				fieldType=KUidContactFieldBirthday;
+				}
+			break;
+    	case 'E':
+    	case 'e':
+			if (vpropNameConst.CompareF(KVersitTokenEMAIL)==0)
+				{
+    			fieldType=KUidContactFieldEMail;
+    			mapping=KUidContactFieldVCardMapEMAILINTERNET;
+				}
+			break;
+    	case 'F':
+    	case 'f':
+			if (vpropNameConst.CompareF(KVersitTokenFN)==0)
+    			mapping=KUidContactFieldVCardMapUnusedFN;
+			break;
+    	case 'G':
+    	case 'g':
+			if (vpropNameConst.CompareF(KVersitTokenGEO)==0)
+				{
+				fieldType=KUidContactFieldGEO;
+    			mapping=KUidContactFieldVCardMapGEO;
+				}
+			break;
+    	case 'K':
+    	case 'k':
+			if (vpropNameConst.CompareF(KVersitTokenKEY)==0)
+				{
+				if(aVCardProperty.Value()->Uid().iUid == KVersitPropertyBinaryUid)
+					{					
+					aStorageType = KStorageTypeStore;
+			 		}
+    			mapping=KUidContactFieldVCardMapKEY;
+				}
+			break;
+    	case 'L':
+    	case 'l':
+			if (vpropNameConst.CompareF(KVersitTokenLABEL)==0)
+    			mapping=KUidContactFieldVCardMapLABEL;
+			else if (vpropNameConst.CompareF(KVersitTokenLOGO)==0)
+				{
+				aStorageType=KStorageTypeStore;
+    			mapping=KUidContactFieldVCardMapLOGO;
+				}
+    		break;
+    	case 'M':
+    	case 'm':
+			if  (vpropNameConst.CompareF(KVersitTokenMAILER)==0)
+    			mapping=KUidContactFieldVCardMapMAILER;
+			break;
+    	case 'N':
+    	case 'n':
+			if (vpropNameConst.CompareF(KVersitTokenNOTE)==0)
+				{
+				fieldType=KUidContactFieldNote;
+    				mapping=KUidContactFieldVCardMapNOTE;
+				}
+			break;
+    	case 'P':
+    	case 'p':
+			if (vpropNameConst.CompareF(KVersitTokenPHOTO)==0)
+				{
+    			mapping=KUidContactFieldVCardMapPHOTO;
+				aStorageType=KStorageTypeStore;
+				}
+			break;
+    	case 'R':
+    	case 'r':
+			if (vpropNameConst.CompareF(KVersitTokenROLE)==0)
+    			mapping=KUidContactFieldVCardMapROLE;
+			break;
+    	case 'S':
+    	case 's':
+			if (vpropNameConst.CompareF(KVersitTokenSOUND)==0)
+				{
+				if(aVCardProperty.Param(KVersitParam8CompanyPrn))
+					{
+					mapping = KUidContactFieldVCardMapORGPronunciation;
+					fieldType=KUidContactFieldCompanyNamePronunciation;
+					}
+				else if(aVCardProperty.Param(KVersitParam8NamePrn))
+					{// this is handled elsewhere
+					mapping = KUidContactFieldVCardMapNotRequired;
+					}
+				else // if we ever support any of the other pronunication extensions we'd have to add the checking here
+					{
+					mapping=KUidContactFieldVCardMapSOUND;
+					}
+				}
+			break;
+    	case 'T':
+    	case 't':    	
+			 if (vpropNameConst.CompareF(KVersitTokenTEL)==0)
+    			{
+    			fieldType=KUidContactFieldPhoneNumber;
+				mapping=KUidContactFieldVCardMapTEL;
+    			}
+			 else if (vpropNameConst.CompareF(KVersitTokenTITLE)==0)
+				{
+				fieldType=KUidContactFieldJobTitle;
+				mapping=KUidContactFieldVCardMapTITLE;
+				}
+			 else if (vpropNameConst.CompareF(KVersitTokenTZ)==0)
+				{
+				mapping=KUidContactFieldVCardMapNotRequired;
+				}
+			break;
+    	case 'U':
+    	case 'u':    	
+			if (vpropNameConst.CompareF(KVersitTokenURL)==0)
+				{
+    			mapping=KUidContactFieldVCardMapURL;
+				fieldType=KUidContactFieldUrl;
+				}
+			else if (vpropNameConst.CompareF(KVersitTokenUID)==0)
+				{
+				mapping=KUidContactFieldVCardMapNotRequired;
+				}
+			break;
+    	case 'V':
+    	case 'v':    	
+			if (vpropNameConst.CompareF(KVersitTokenVERSION)==0)
+				{
+    			mapping=KUidContactFieldVCardMapNotRequired;
+				}
+			break;
+    	case 'X':
+    	case 'x':    	
+			if (vpropNameConst.CompareF(KVersitTokenSECONDNAME)==0)
+				{
+				mapping=KUidContactFieldVCardMapSECONDNAME;
+				fieldType=KUidContactFieldSecondName;
+				}
+			else if (vpropNameConst.CompareF(KVersitTokenSIPID)==0)
+				{
+				mapping=KUidContactFieldVCardMapSIPID;
+				fieldType=KUidContactFieldSIPID;
+				}
+			else if (vpropNameConst.CompareF(KVersitTokenWVID)==0)
+				{
+				mapping=KUidContactFieldVCardMapWV;
+				fieldType=KUidContactFieldIMAddress;
+				}
+			else if (vpropNameConst.CompareF(KVersitTokenAssistant) == 0)
+				{
+				mapping = KUidContactFieldVCardMapAssistant;
+				fieldType = KUidContactFieldAssistant;
+				}
+			else if (vpropNameConst.CompareF(KVersitTokenAssistantTel) == 0)
+				{
+				mapping = KUidContactFieldVCardMapAssistantTel;
+				fieldType = KUidContactFieldPhoneNumber;
+				}
+			else if (vpropNameConst.CompareF(KVersitTokenAnniversary) == 0)
+				{
+				mapping = KUidContactFieldVCardMapAnniversary;
+				fieldType = KUidContactFieldAnniversary;
+				}
+			else if (vpropNameConst.CompareF(KVersitTokenSpouse) == 0)
+				{
+				mapping = KUidContactFieldVCardMapSpouse;
+				fieldType = KUidContactFieldSpouse;
+				}
+			else if (vpropNameConst.Length()>=2)
+    			{
+    			if (vpropNameConst.Left(2).CompareF(KVersitTokenXDash)==0)
+    				mapping=KUidContactFieldVCardMapUnknownXDash;
+				else
+ 					mapping=KUidContactFieldVCardMapUnknown;
+				}
+			break;
+    	default:
+			break; // Leave mapping set to KUidContactFieldVCardMapUnknown
+			};
+		};
+
+	CContentType* type=CContentType::NewL();
+	CleanupStack::PushL( type );
+	type->SetMapping(mapping);
+	if (mapping==KUidContactFieldVCardMapPHOTO || mapping==KUidContactFieldVCardMapLOGO)
+		{
+		type->AddFieldTypeL(KUidContactFieldPicture);
+        TFieldType bitmapFormat;
+        GetBitMapFormat(aVCardProperty, bitmapFormat);
+           
+        if (bitmapFormat.iUid!=KUidContactFieldNone.iUid)
+			{
+            type->AddFieldTypeL(bitmapFormat);
+			}
+		}
+	if(fieldType!=KUidContactFieldNone)
+		{
+		type->AddFieldTypeL(fieldType);
+		}
+
+	CArrayPtr<CParserParam>* paramArray = NULL ;
+	paramArray = aVCardProperty.ParamArray();
+
+	// parameters
+	if (IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Internet))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapINTERNET);
+		}
+	if  (IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Home))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapHOME);
+		}
+    if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Work))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapWORK);
+		}
+    if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Voice))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapVOICE);
+		}
+    if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Fax))
+        {
+        type->RemoveFieldType(KUidContactFieldPhoneNumber);
+        type->AddFieldTypeL(KUidContactFieldFax);
+        type->AddFieldTypeL(KUidContactFieldVCardMapFAX);
+        }
+    if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Pref))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapPREF);
+		}
+    if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Cell))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapCELL);
+		}
+    if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Pager))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapPAGER);
+		}
+    if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Bbs))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapBBS);
+		}
+    if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Modem))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapMODEM);
+		}
+    if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Car))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapCAR);
+		}
+    if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Isdn))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapISDN);
+		}
+    if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Video))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapVIDEO);
+		}
+	if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Msg))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapMSG);
+		}
+	if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8Dom))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapDOM);
+		}
+	if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8X509))
+		{
+    	type->AddFieldTypeL(KUidContactFieldVCardMapX509);
+		}
+	if 	(IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParam8PGP))
+		{
+    	type->AddFieldTypeL(KUidContactFieldVCardMapPGP);
+		}
+	if (IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParamPOC))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapPOC);
+		}
+	if (IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParamSWIS))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapSWIS);
+		}
+	if (IsParameterValuePresent(paramArray, KVersitTokenTYPE, KVersitParamVOIP))
+		{
+		type->AddFieldTypeL(KUidContactFieldVCardMapVOIP);
+		}
+	
+
+	CleanupStack::Pop(type);
+	return(type);
+    }
+
+/*
+ * Gets the bitmap format. This is done by looking for the name and value items in the parameter eg. TYPE=GIF
+ * the if construct assumes that this is  present in the vcf file. It is also possible to just have the format without
+ * the TYPE string and this is stored in the name part of the parameter so need to check through all supported formats
+ * to find if one is present, this is done in the else construct.
+ *
+ * @param aVCardProperty and aBitmapFormat
+ * @return void.
+ */   
+void CVCardToContactsAppConverter::GetBitMapFormat(const CParserProperty& aVCardProperty, TFieldType& aBitmapFormat)
+    {
+    aBitmapFormat.iUid=KUidContactFieldNone.iUid;
+   
+    CParserParam* param=aVCardProperty.Param(KVersitTokenTYPE);
+    if (param)
+        {
+        TFieldType bitmapFormat=MapVCardPhotoTypeToFieldType(param->Value());
+        if (bitmapFormat.iUid!=KUidContactFieldNone.iUid)
+            {
+            aBitmapFormat.iUid = bitmapFormat.iUid;
+            }
+        } //if
+    else
+        {   
+            const TInt KNumberOfBitmaps = 16;
+            //Set up table of bitmap formats
+            const TBufC8<5> bitmapString[] =
+            {
+                KVersitParam8Gif(),
+                KVersitParam8Jpeg(),
+                KVersitParam8Bmp(),
+                KVersitParam8Tiff(),
+                KVersitParam8Pict(),
+                KVersitParam8Cgm(),
+                KVersitParam8Wmf(),
+                KVersitParam8Ps(),
+                KVersitParam8Pdf(),
+                KVersitParam8Mpeg(),
+                KVersitParam8Mpeg2(),
+                KVersitParam8Avi(),
+                KVersitParam8Qtime(),   
+                KVersitParam8Dib(),
+                KVersitParam8Pmb(),
+                KVersitParam8Met()     
+            };
+           
+            // Loop through the table looking for a param whose name matches the bitmap format
+            for (TInt i=0; i < KNumberOfBitmaps - 1; ++i)
+                {
+                CParserParam* paramNameCheck = aVCardProperty.Param(bitmapString[i]);
+                if (paramNameCheck)
+                    {//ok found something
+                    TFieldType bitmapFormat=MapVCardPhotoTypeToFieldType(paramNameCheck->Name());
+                    aBitmapFormat.iUid = bitmapFormat.iUid;
+                    break;
+                    }
+                }   
+        } //else
+   
+    }
+
+TFieldType CVCardToContactsAppConverter::MapVCardPhotoTypeToFieldType(/*const CParserParam& aParserParam*/TPtrC8 aBitmapStringPtr)
+	{
+    if (aBitmapStringPtr.Length()<2)
+		{
+		return KUidContactFieldNone; //no bitmap type token are less than 2 characters long
+		}
+
+    TChar firstChar(aBitmapStringPtr[0]);
+	firstChar=firstChar.GetUpperCase();
+
+	switch (firstChar)
+		{
+	case 'G':
+		return KUidContactFieldVCardMapGIF;
+	case 'C':
+		return KUidContactFieldVCardMapCGM;
+	case 'W':
+		return KUidContactFieldVCardMapWMF;
+	case 'B':
+		return KUidContactFieldVCardMapBMP;
+	case 'D':
+		return KUidContactFieldVCardMapDIB;
+	case 'P':
+		{
+	    TChar secondChar(aBitmapStringPtr[1]);
+		switch (secondChar.GetUpperCase())
+			{
+		case 'S':
+			return KUidContactFieldVCardMapPS;
+		case 'M':
+			return KUidContactFieldVCardMapPMB;
+		case 'D':
+			return KUidContactFieldVCardMapPDF;
+		case 'I':
+			return KUidContactFieldVCardMapPICT;
+		default:
+			return KUidContactFieldNone;
+			}				
+		}
+	case 'T':
+		return KUidContactFieldVCardMapTIFF;
+	case 'J':
+		return KUidContactFieldVCardMapJPEG;
+	case 'M':
+        switch (aBitmapStringPtr.Length())
+			{
+		case 3:
+			return KUidContactFieldVCardMapMET;
+		case 4:
+			return KUidContactFieldVCardMapMPEG;
+		case 5:
+			return KUidContactFieldVCardMapMPEG2;
+		default:
+			return KUidContactFieldNone;
+			}
+	case 'A':
+		return KUidContactFieldVCardMapAVI;
+	case 'Q':
+		return KUidContactFieldVCardMapQTIME;
+	default:
+		return KUidContactFieldNone;
+		}
+	}
+
+
+/**
+ * Checks each field in an array to see if one or more contain importable data. Assuming one field within
+ * the array does, then the whole array should be imported.
+ *
+ * @param aArray The array of text fields to be checked for importable data
+ * @return Whether the array should be imported.
+ */
+TBool CVCardToContactsAppConverter::TextArrayContainsImportableData(const CDesCArray& aArray) const
+	{
+	// Text arrays are implicitly composite in nature
+	const TInt count = aArray.Count();
+	for(TInt i=0; i<count; i++)
+		{
+		const TPtrC pItem(aArray.MdcaPoint(i));
+		if	(CContactVCardConverter::ContainsImportableData(pItem, CContactVCardConverter::EPropertyValueComposite, ImportType()))
+			return ETrue;
+		}
+	//
+	return EFalse;
+	}
+
+/**
+ * Remove single space character entries from the specified composite property array and replace them
+ * with null values.
+ *
+ * The TimeIS sync engines use spaces and NULLs to indicate special behaviour. Space = supported
+ * but empty property. NULL = unsupported property.
+ *
+ * Contacts model fields do not support composite properties themselves. Instead, the following
+ * method is used to converted a composite (array) property to a non composite value:
+ *
+ * CContactTextField::SetStandardTextArray(...)
+ *
+ * This method simply concatenates all the array values into one non-composite value. A CRLF
+ * is added between each sub-field. Therefore, if a composite property reads thus:
+ *
+ * {"A","B"}
+ *
+ * contacts model will store the result as "A\r\n\B".
+ *
+ * In the case where a composite property from TimeIS contains a supported but empty field value,
+ * without special handling, the space character (implicit meaning: "supported but empty")
+ * will be interpreted literally and stored within the contacts model field as real data.
+ *
+ * For example: {"Symbian"," "}
+ *
+ * The implied meaning of this (in terms of PC sync) is:
+ *
+ * OrgName: Symbian
+ * OrgUnit: (a supported field of the PC PIM, but contains no data at this time).
+ *
+ * In the above example, without special processing, the resultant contacts model field would read thus:
+ *
+ * "Symbian\r\n "
+ *
+ * The trailing space would also be exported during any synchronisation, and therefore introduce
+ * unexpected data in the sync chain.
+ *
+ * This method simply ensures that single space characters are mapped back to their 'real' meaning,
+ * i.e. a NULL.
+ *
+ * @param aArray The composite property which needs fixing up
+ */
+void CVCardToContactsAppConverter::RemoveWhitespaceFromCompositePropertyL(CDesCArray& aArray)
+	{
+	const TInt count = aArray.Count();
+	for(TInt i=0; i<count; i++)
+		{
+		TPtrC pItem(aArray[i]);
+		if	(pItem == KContactVCardCompositeSupportedButEmptyFieldValue)
+			{
+			aArray.Delete(i);
+			aArray.InsertL(i, KContactVCardEmptyFieldValue);
+			}
+		}
+	}
+
+/**
+ * Get a Pointer to the First Instance of the specified Property's value in the VCard Object
+ *
+ * @param aVCard A vCard Object containing Array of Properties
+ * @param aToken A String with desired Property Name
+ * @param A buffer descriptor expected to contain the first instance of desired property Value on return
+ * @return Count of Class Properties found
+ */
+TInt CVCardToContactsAppConverter::GetSingleInstanceL(const CParserVCard& aVCard,const TDesC8& aToken, TDes& aClass)
+	{
+	CArrayPtr<CParserProperty>* arrayOfProp=aVCard.PropertyL(aToken, TUid::Uid(KVersitPropertyHBufCUid), EFalse);
+	if(arrayOfProp)
+		{
+		CleanupStack::PushL(arrayOfProp);
+		TInt propCount = arrayOfProp->Count();
+		CParserProperty* property = arrayOfProp->At(0);
+		CParserPropertyValueHBufC* propertyAsHBufC = static_cast<CParserPropertyValueHBufC*>(property->Value());
+		aClass = propertyAsHBufC->Value();
+		if( !aClass.Length() )
+			{
+			propCount = 0;
+			}
+		CleanupStack::PopAndDestroy(arrayOfProp);
+		return 	propCount;
+		}
+	return 0;
+	}
+
+/**
+ * Add a specific field into a contact
+ *
+ * @param aContact Contact item to add fields to
+ * @param aValue Reference to first Instance of the Property Value
+ * @param aFieldType Field type of field to add (TFieldType)
+ * @param aMapping vCard mapping Id of the field to add.
+ * @param aNames An object containing the name and labels for 'N' property fields
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ */
+void CVCardToContactsAppConverter::SetSingleInstanceL(CContactItem& aContact,const TDes& aValue,const TFieldType& aFieldType, const TUid& aMapping, TInt aOption)
+	{
+	//
+	TBool addField = EFalse;
+	if (CContactVCardConverter::EConnectWhitespace & aOption)
+		{
+		addField = CContactVCardConverter::ContainsImportableData(aValue, CContactVCardConverter::EPropertyValueSingle, ImportType());
+		}
+	else
+		{
+		addField = (aValue.Length());
+		}
+	// Only add the field if it contains some data
+	if	(addField)
+		{
+		CContactItemField* contactItemField = CContactItemField::NewLC(KStorageTypeText, aFieldType);
+		contactItemField->SetMapping(aMapping);
+		contactItemField->TextStorage()->SetStandardTextL(aValue);
+		aContact.AddFieldL(*contactItemField);
+		CleanupStack::Pop(contactItemField);
+		}
+	}
+
+/**
+ * Merge a specific field from a contact
+ *
+ * @param aContact Contact item to add fields to
+ * @param aValue Pointer to first Instance of the Property Value
+ * @param aFieldType Field type of field to add (TFieldType)
+ * @param aMapping vCard mapping Id of the field to add.
+ * @param aNames An object containing the name and labels for 'N' property fields
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ */
+void CVCardToContactsAppConverter::MergeSingleInstanceL(CContactItem& aContact, const TDes& aValue,const TFieldType& aFieldType, const TUid& aMapping, TInt aOption)
+	{
+	CContactItemFieldSet& oldfieldset = aContact.CardFields();
+	const TInt pos = oldfieldset.Find(aFieldType, aMapping);
+	const TBool processWhitespace = (aOption & CContactVCardConverter::EConnectWhitespace);
+
+	// First check whether the field is present in the contact card
+	// Also verify that the array of address sub-values actually contains a specific
+	// value for the requested index.
+	const TInt Klength = aValue.Length();
+	if (processWhitespace)
+		{
+		TBool isSingleSpace = EFalse;
+		if (Klength == 1)
+			{
+			isSingleSpace = (aValue[0] == KContactVCardSpaceCharacter);
+			}
+		if	((pos != KErrNotFound) && (Klength || isSingleSpace))
+			{
+			// This means the PC side field is empty, so delete the corresponding device-side field.
+			aContact.RemoveField(pos);
+			}
+		if	(Klength && !isSingleSpace)
+			{
+			// This means the PC side field is unsupported, so ignore the corresponding contents.
+			SetSingleInstanceL(aContact, aValue, aFieldType,aMapping,aOption);
+			}
+		}
+	else
+		{
+		if (pos != KErrNotFound)
+			{
+			// This means the PC side field is empty, so delete the corresponding device-side field.
+			aContact.RemoveField(pos);
+			}
+		if (Klength)
+			{
+			// This means the PC side field is not empty, so add the corresponding contents.
+			SetSingleInstanceL(aContact, aValue, aFieldType,aMapping,aOption);
+			}
+		}
+	}
+
+/**
+ * Get an Array containing Property's values from a VCard
+ *
+ * @param aVCard A vCard Object containing Array of Properties
+ * @param aToken A String with desired Property Name
+ * @param A Composite Descriptor array with desired vCard Property's Values on return
+ * @return Count of desired properties found.
+ */
+
+TInt CVCardToContactsAppConverter::GetVCardPropertyAsArrayOfValuesL(const CParserVCard& aVCard, const TDesC8& aToken, CDesCArray& aItems)
+	{
+	CArrayPtr<CParserProperty>* arrayOfProp =aVCard.PropertyL(aToken,TUid::Uid(KVersitPropertyCDesCArrayUid),EFalse);
+	TInt propCount = 0;
+	if(arrayOfProp)
+		{
+		CleanupStack::PushL(arrayOfProp);
+		propCount = arrayOfProp->Count();
+		CParserProperty* property = arrayOfProp->At(0);
+		CDesCArray& value = *static_cast<CParserPropertyValueCDesCArray*>(property->Value())->Value();
+		if(value.Count())
+			{
+			for(TInt i = 0;i < value.Count();i++)
+				{
+				aItems.AppendL(value.MdcaPoint(i));
+				}
+			}
+		else
+			{
+			propCount = 0;
+			}
+		CleanupStack::PopAndDestroy(arrayOfProp);
+		}
+
+	return propCount;
+	}
+
+/**
+ * Add Organization Information like Company Name and Department Name into contact
+ *
+ * @param aContact Contact item to add fields to
+ * @param aItems A CDesC Array containing the Property's value
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ */
+void CVCardToContactsAppConverter::SetOrgDetailsL(CContactItem& aContact,CDesCArray& aItems,const TInt aOption)
+	{
+	TInt orgCount = aItems.MdcaCount();
+	SetSpecificFieldL(aContact, aItems, KUidContactFieldCompanyName, KUidContactFieldVCardMapORG, aOption, 0, 1);
+	SetSpecificFieldL(aContact, aItems, KUidContactFieldDepartmentName,	KUidContactFieldVCardMapDepartment, aOption, 1, orgCount);
+	}
+
+/**
+ * Add a specific field from the Array of Property's values into contact
+ *
+ * @param aContact Contact item to add fields to
+ * @param aItems A CDesC Array containing the Property's values
+ * @param aFieldType Field type of field to add (TFieldType)
+ * @param aMapping vCardMapping Id of field to add
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ * @param aStartIndex Starting Index in the Property Value Array
+ * @param aEndIndex   Ending Index in the Property Value Array
+ */
+void CVCardToContactsAppConverter::SetSpecificFieldL(CContactItem& aContact,CDesCArray& aItems,const TUid& aFieldType,const TUid& aMapping,TInt aOption, TInt aStartIndex, TInt aEndIndex)
+	{
+	TBool doConvert = ETrue;
+	TInt ii = 0;
+
+	CDesCArrayFlat* orgList = new (ELeave)CDesCArrayFlat(4);
+	CleanupStack::PushL(orgList);
+
+    for (ii = aStartIndex;ii < aEndIndex;ii++)
+    	{
+    	orgList->AppendL(aItems.MdcaPoint(ii));
+    	}
+	if ((CContactVCardConverter::EConnectWhitespace & aOption) && orgList)
+		{
+		doConvert = TextArrayContainsImportableData(*orgList);
+		if (doConvert)
+			{
+			RemoveWhitespaceFromCompositePropertyL(*orgList);
+			}
+		}
+	if (doConvert)
+		{
+		CContactItemField* contactItemField = CContactItemField::NewLC(KStorageTypeText, aFieldType);
+		contactItemField->SetMapping(aMapping);
+		contactItemField->TextStorage()->SetStandardTextArray(orgList);
+		aContact.AddFieldL(*contactItemField);
+		CleanupStack::Pop(contactItemField);
+		}
+
+	CleanupStack::PopAndDestroy(orgList); // orgList
+}
+
+/**
+ * Merge Organization Information like Company Name and Department Name into contact
+ *
+ * @param aContact Contact item to add fields to
+ * @param aItems A CDesC Array containing the Property's value
+ * @param aFieldType Field type of field to add (TFieldType)
+ * @param aMapping vCardMapping Id of field to add
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ * @param aStartIndex Starting Index in the Property Value Array
+ * @param aEndIndex   Ending Index in the Property Value Array
+ */
+void CVCardToContactsAppConverter::MergeOrgDetailsL(CContactItem& aContact, CDesCArray& aItems, TInt aOption)
+	{
+	TInt orgCount = aItems.MdcaCount();
+	MergeSpecificFieldL(aContact, aItems, KUidContactFieldCompanyName,	KUidContactFieldVCardMapORG, aOption, 0, 1);
+	MergeSpecificFieldL(aContact, aItems, KUidContactFieldDepartmentName,	KUidContactFieldVCardMapDepartment, aOption, 1, orgCount);
+	}
+
+/**
+ * Merge specific Field from the array of Property's values into contact
+ *
+ * @param aContact Contact item to add fields to
+ * @param aItems A CDesC Array containing the Property's value
+ * @param aFieldType Field type of field to add (TFieldType)
+ * @param aMapping vCardMapping Id of field to add
+ * @param aOption Import preferences (available options defined in CContactDatabase::TOptions)
+ * @param aStartIndex Starting Index in the Property Value Array
+ * @param aEndIndex   Ending Index in the Property Value Array
+ */
+void CVCardToContactsAppConverter::MergeSpecificFieldL(CContactItem& aContact, CDesCArray& aItems, const TFieldType& aFieldType, const TUid& aMapping, TInt aOption, TInt aStartIndex, TInt aEndIndex)
+	{
+	CContactItemFieldSet& oldfieldset = aContact.CardFields();
+	const TInt pos = oldfieldset.Find(aFieldType, aMapping);
+	const TBool processWhitespace = (aOption & CContactVCardConverter::EConnectWhitespace);
+
+	// First check whether the field is present in the contact card
+	// Also verify that the array of address sub-values actually contains a specific
+	// value for the requested index.
+	
+	if(aItems.MdcaCount() > aStartIndex)
+		{	
+		const TPtrC pValue = aItems.MdcaPoint(aStartIndex);
+		const TInt Klength = pValue.Length();
+		if (processWhitespace)
+			{
+			TBool isSingleSpace = EFalse;
+			if (Klength == 1)
+				{
+				isSingleSpace = (pValue[0] == KContactVCardSpaceCharacter);
+				}
+			if	((pos != KErrNotFound) && (Klength || isSingleSpace))
+				{
+				// This means the PC side field is empty, so delete the corresponding device-side field.
+				aContact.RemoveField(pos);
+				}
+			if	(Klength && !isSingleSpace)
+				{
+				// This means the PC side field is unsupported, so ignore the corresponding contents.
+				SetSpecificFieldL(aContact, aItems, aFieldType,	aMapping, aOption, aStartIndex, aEndIndex);
+				}
+			}
+		else
+			{
+			if (pos != KErrNotFound)
+				{
+				// This means the PC side field is empty, so delete the corresponding device-side field.
+				aContact.RemoveField(pos);
+				}
+			if (Klength)
+				{
+				// This means the PC side field is not empty, so add the corresponding contents.
+				SetSpecificFieldL(aContact, aItems, aFieldType,	aMapping, aOption, aStartIndex, aEndIndex);
+				}
+			}
+		}
+	else if(pos != KErrNotFound)
+		{
+		aContact.RemoveField(pos);
+		}
+	}		
+
+/**
+ * Check if a specific field from vCard should be truncated or not.
+ *
+ * @param aPropertyName vCard property's name
+ *
+ * @return ETrue if the property must be truncated and EFalse otherwise
+ *
+ */
+TBool CVCardToContactsAppConverter::PropertyTobeTruncated(const TPtrC8& aPropertyName) const
+	{
+	//Test is the field is one that has to be truncated
+	if( aPropertyName == KVersitTokenN || aPropertyName == KVersitTokenORG || 
+		aPropertyName == KVersitTokenTEL || aPropertyName == KVersitTokenEMAIL )
+		return ETrue;
+	//	
+	return EFalse;
+	}
+
+/**
+ * Check if a specific parameter value exists in a parameter array.
+ *
+ * @param aParamArray Array of property parameters in which value has to be searched.
+ * @param aParamName A parameter name whose corresponding parameter value present in aParamArray has to be matched with aParamValue.
+ * @param aParamValue A parameter value which will be used to search.
+ * @return TBool ETrue if value is found in parameter array, otherwise EFalse.
+ */
+TBool CVCardToContactsAppConverter::IsParameterValuePresent(CArrayPtr<CParserParam>* aParamArray, const TDesC8& aParamName, const TDesC8& aParamValue)
+	{
+	if(!aParamArray)
+		{
+		return EFalse;
+		}
+	const TInt count = aParamArray->Count();
+	for (TInt ii = 0; ii < count; ii++)
+		{
+		if((*aParamArray)[ii]->Name().CompareF(aParamValue) == 0)
+			{
+			return ETrue;		
+			}
+		else if((*aParamArray)[ii]->Name().CompareF(aParamName) == 0)
+			{
+			if((*aParamArray)[ii]->Value().CompareF(aParamValue) == 0)
+				{
+				return ETrue;		
+				}	
+			}
+		}
+	return EFalse;	
+	}
+
+/**
+ * If there are multiple EMAIL and TEL properties in a vCard, then there should only be a single EMAIL or TEL property 
+ * with a PREF parameter. If more than one EMAIL or TEL properties contain a PREF parameter,then only the first property
+ * with the PREF parameter is stored and the other properties are stored with their other parameters but without the
+ * PREF parameter.
+ * 
+ * @param aMainContact, Contact item for the vCard
+ * @param aFieldType, the fieldtype in conjuction with the mapping is used to search for fields.
+ * @param aMapping, the mapping is used for searching a field i.e. EMAIL or TEL fields.
+ */
+
+void CVCardToContactsAppConverter::AdjustForPrefRule(CContactItem& aContact, TFieldType aFieldType, TUid aMapping)
+	{
+	TInt pos = 0;
+	TInt prefCount = 0;
+	CContactItemFieldSet& contactItemFieldSet = aContact.CardFields();
+	pos = contactItemFieldSet.FindNext(aFieldType, aMapping, pos);
+	while (pos != KErrNotFound)
+		{
+		CContactItemField& contactItemField = contactItemFieldSet[pos];
+		const CContentType& contentType = contactItemField.ContentType();
+		TBool pref = contentType.ContainsFieldType(KUidContactFieldVCardMapPREF);
+		if (pref)
+			{
+			++prefCount;
+			if (prefCount > 1)
+				{
+				contactItemField.RemoveFieldType(KUidContactFieldVCardMapPREF);
+				}
+			}
+		++pos;
+		pos = contactItemFieldSet.FindNext(aFieldType, aMapping, pos);
+		}
+	}