diff -r 000000000000 -r e686773b3f54 phonebookengines/contactsmodel/cntvcard/cntvcardimport.cpp --- /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 +#include +#include + + +// User includes +#include +#include +#include +#include + + +// 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 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; iiDes()); + + TInt classCount = GetSingleInstanceL(aVCard, KVersitTokenClass, ptr); + if(classCount) + { + MergeSingleInstanceL(aContact,ptr,KUidContactFieldClass, KUidContactFieldVCardMapClass,aOption); + deleteContact = EFalse; + } + CleanupStack::PopAndDestroy(singleClass); + + // Get other properties + CArrayPtr* 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(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 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 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; iiDes()); + + TInt classCount = GetSingleInstanceL(aVCard, KVersitTokenClass, ptr); + if(classCount) + { + SetSingleInstanceL(*mainContact, ptr, KUidContactFieldClass, KUidContactFieldVCardMapClass,aOption); + } + CleanupStack::PopAndDestroy(singleClass); + + // Get other properties + CArrayPtr* arrayOfProperties = aVCard.ArrayOfProperties(); + CleanupStack::PushL(TCleanupItem(CleanUpResetAndDestroy,arrayOfProperties)); + // + if (arrayOfProperties) + { + count = arrayOfProperties->Count(); + for (ii=0; iiAt(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* arrayOfRevisions=aVCard.PropertyL(KVersitTokenREV,TUid::Uid(KVersitPropertyDateTimeUid),EFalse); + if (arrayOfRevisions && arrayOfRevisions->Count()) + { + CleanupStack::PushL(arrayOfRevisions); + CParserPropertyValueDateTime* revision=(static_cast((*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* 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 ((*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* 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(aProperty->Value()); + if(valueScalar) + { + propertyValueWrapper = valueScalar->TreatAsArrayPropertyLC(*aProperty); + pushed= ETrue; + } + } + else + { + propertyValueWrapper = static_cast(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;iiMdcaPoint(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(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 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 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* 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(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* 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;indexAt(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(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; iiAddItemL(pField); + if (aOption & CContactVCardConverter::EIncludeX) + { + TBuf8 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& 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; iiParam(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(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 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& aAddresses) + { + CArrayPtr* 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* 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* 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(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* 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(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* 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); + } + }