--- /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);
+ }
+ }