javaextensions/pim/cntadapter/src.s60/cpimcontactitemadapter.cpp
changeset 21 2a9601315dfc
child 64 0ea12c182930
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javaextensions/pim/cntadapter/src.s60/cpimcontactitemadapter.cpp	Mon May 03 12:27:20 2010 +0300
@@ -0,0 +1,1467 @@
+/*
+* Copyright (c) 2008 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:  Handles conversion between PIM API Contact Items and Contacts
+ *                Model Contact Cards
+ *
+*/
+
+
+// CLASS HEADER
+#include "cpimcontactitemadapter.h"
+
+// INTERNAL INCLUDES
+#include "cpimcontactcategorymanager.h"
+#include "pimpanics.h"
+#include "mpimcontactitem.h"
+#include "mpimitemdata.h"
+#include "cpimimagescaler.h"
+#include "cpimcontactfieldinfo.h"
+#include "logger.h"
+
+// EXTERNAL INCLUDES
+#include <cntitem.h> // CContactCard etc.
+#include <cntfldst.h> // CContactTextField etc.
+#include <tz.h>
+#include <tzconverter.h>
+
+
+
+// UNNAMED LOCAL NAMESPACE
+namespace
+{
+// Phonebook maps Syncronisation field values with specified
+// hard-coded string values. At the time implementing, the header
+// was not exported so it is necessary to define own constants
+// with same values
+_LIT(KPIMContactClassPrivate, "private");
+_LIT(KPIMContactClassPublic, "public");
+_LIT(KPIMContactClassConfidential, "none");
+}
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CPIMContactItemAdapter* CPIMContactItemAdapter::NewL(
+    CPIMContactCategoryManager& aCategoryManager)
+{
+    JELOG2(EPim);
+    CPIMContactItemAdapter* self =
+        new(ELeave) CPIMContactItemAdapter(aCategoryManager);
+
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+
+    return self;
+}
+
+// destructor
+CPIMContactItemAdapter::~CPIMContactItemAdapter()
+{
+    JELOG2(EPim);
+    delete iImageScaler;
+    delete iFieldInfo;
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::CardL
+// Converts from a PIM item data to a Contacts Model contact card.
+// Returns: A contact card with the same information as given in
+//          the parameter item. The ownership of the card is
+//          transferred to the caller.
+// -----------------------------------------------------------------------------
+//
+CContactCard* CPIMContactItemAdapter::CardL(const MPIMContactItem& aItem)
+{
+    JELOG2(EPim);
+    CContactCard* card = CContactCard::NewLC();
+    const MPIMItemData& item = aItem.ItemData();
+    __ASSERT_DEBUG((aItem.ContactItemIdL() == 0), User::Panic(
+                       KPIMPanicCategory, EPIMPanicInvalidItemID));
+    CArrayFix<TPIMField>* fields = item.FieldsLC();
+
+    TInt fieldCount = fields->Count();
+    for (TInt i = 0; i < fieldCount; i++)
+    {
+        ConvertFieldL(aItem, *card,
+                      static_cast<TPIMContactField>(fields->At(i)));
+    }
+
+    // Set default values if not present in PIM item
+    if (item.CountValues(EPIMContactClass) == 0)
+    {
+        CContentType* type = CContentType::NewL(KUidContactFieldClass,
+                                                KUidContactFieldVCardMapClass);
+        CleanupStack::PushL(type);
+
+        // Add value to the contact field
+        CContactItemField* field = CContactItemField::NewLC(KStorageTypeText,
+                                   *type);
+        field->SetUserFlags(EContactCategoryNone);
+        CContactTextField* textField = field->TextStorage();
+        textField->SetTextL(KPIMContactClassPrivate());
+        card->AddFieldL(*field);
+
+        CleanupStack::Pop(field);
+        CleanupStack::PopAndDestroy(type);
+    }
+
+    CleanupStack::PopAndDestroy(fields);
+    CleanupStack::Pop(card);
+    return card;
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::FillItemL
+// Converts from a Contacts Model contact card to the PIM representation.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::FillItemL(MPIMContactItem& aItem, // Item data container to fill with the data
+                                       const CContactCard& aCard) // Contact Card to convert
+{
+    JELOG2(EPim);
+    // convert fields
+    CContactItemFieldSet& fieldSet = aCard.CardFields();
+    TInt fieldCount = fieldSet.Count();
+    for (TInt i = 0; i < fieldCount; i++)
+    {
+        ConvertFieldL(fieldSet[i], aItem);
+    }
+    // convert categories
+    MPIMItemData& item = aItem.ItemData();
+    CContactIdArray* groupArray = aCard.GroupsJoinedLC();
+    TInt groupCount = groupArray->Count();
+    for (TInt i = 0; i < groupCount; i++)
+    {
+        HBufC* label = iCategoryManager.GroupLabelL((*groupArray)[i]);
+        CleanupStack::PushL(label);
+        // Add item to this category if it doesn't belong to it already
+        if (item.FindCategory(*label) == KErrNotFound)
+        {
+            item.AddNewCategoryL(*label);
+        }
+        CleanupStack::PopAndDestroy(label);
+    }
+    CleanupStack::PopAndDestroy(groupArray);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::UpdateCardL
+// Updates the data in the Contacts Model contact card to match
+// the data in the PIM item data container.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::UpdateCardL(const MPIMContactItem& aItem, // Item from which the data is read
+        CContactCard& aCard) // The card which is updated
+{
+    JELOG2(EPim);
+    CleanCard(aCard);
+    const MPIMItemData& itemData = aItem.ItemData();
+    // Get fields
+    CArrayFix<TPIMField>* fields = itemData.FieldsLC();
+    TInt fieldCount = fields->Count();
+    for (TInt i = 0; i < fieldCount; i++)
+    {
+        ConvertFieldL(aItem, aCard, (TPIMContactField)(fields->At(i)));
+    }
+    CleanupStack::PopAndDestroy(); // fields
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::UpdateCategoriesL
+// Updates the category information in the database.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::UpdateCategoriesL(const MPIMContactItem& aItem, // Item containing the new categories
+        const CContactCard& aCard) // Item to update
+{
+    JELOG2(EPim);
+    const CDesCArray& pimCategories = aItem.ItemData().Categories();
+    const TInt pimCategoryCount = pimCategories.Count();
+    TBool* newCategoryTable = new(ELeave) TBool[pimCategoryCount];
+    CleanupArrayDeletePushL(newCategoryTable);
+    TInt i = 0;
+    for (i = 0; i < pimCategoryCount; i++)
+    {
+        newCategoryTable[i] = ETrue;
+    }
+
+    CContactIdArray* cardCategories = aCard.GroupsJoinedLC();
+    TContactItemId id = aItem.ContactItemIdL();
+
+    // first remove extra groups
+    const TInt cardCategoryCount = cardCategories->Count();
+    for (i = 0; i < cardCategoryCount; i++)
+    {
+        TContactItemId groupId = (*cardCategories)[i];
+        HBufC* groupLabel = iCategoryManager.GroupLabelL(groupId);
+        TInt pos;
+        TInt found = pimCategories.Find(*groupLabel, pos, ECmpNormal);
+        delete groupLabel;
+        if (found != 0)
+        {
+            // removed group
+            iCategoryManager.RemoveFromGroupL(id, groupId);
+        }
+        else
+        {
+            // old group
+            newCategoryTable[pos] = EFalse;
+        }
+    }
+    // then add new categories
+    for (i = 0; i < pimCategoryCount; i++)
+    {
+        if (newCategoryTable[i])
+        {
+            TPtrC category = pimCategories[i];
+            iCategoryManager.AddToGroupL(id, category);
+        }
+    }
+    CleanupStack::PopAndDestroy(2); // cardCategories, newCategoryTable
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::ContactsModelFieldType
+// Other items were commented in the header
+// -----------------------------------------------------------------------------
+//
+CArrayFix<TInt>* CPIMContactItemAdapter::ContactsModelFieldTypeL(
+    TPIMContactField aContactField) const
+{
+    JELOG2(EPim);
+    return iFieldInfo->MatchPIMFieldL(aContactField);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::CPIMContactItemAdapter
+// C++ constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CPIMContactItemAdapter::CPIMContactItemAdapter(
+    CPIMContactCategoryManager& aCategoryManager) :
+        iCategoryManager(aCategoryManager)
+{
+    JELOG2(EPim);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+inline void CPIMContactItemAdapter::ConstructL()
+{
+    JELOG2(EPim);
+    iFieldInfo = CPIMContactFieldInfo::NewL();
+    iImageScaler = CPIMImageScaler::NewL();
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::CleanCardL
+// Deletes all the supported fields from the contact card.
+// Those fields which are not supported are left as is.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::CleanCard(CContactCard& aCard)
+{
+    JELOG2(EPim);
+    // convert fields
+    CContactItemFieldSet& fieldSet = aCard.CardFields();
+    TInt fieldCount = fieldSet.Count();
+    for (TInt i = 0; i < fieldCount; i++)
+    {
+        if (IsSupportedField(fieldSet[i]))
+        {
+            // as the field is removed, the array shrinks
+            aCard.RemoveField(i--);
+            fieldCount--;
+        }
+    }
+}
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::IsSupportedFieldL
+// Checks if we support this particular contact field.
+// Returns:     ETrue if the field is supported
+//              EFalse otherwise
+// -----------------------------------------------------------------------------
+//
+TBool CPIMContactItemAdapter::IsSupportedField(CContactItemField& aField)
+{
+    JELOG2(EPim);
+    const CContentType& type = aField.ContentType();
+    if (type.FieldTypeCount() == 0)
+    {
+        // we don't support unknown types
+        return EFalse;
+    }
+
+    TFieldType fieldTypeUid = type.FieldType(0);
+    TInt fieldType = fieldTypeUid.iUid;
+    switch (fieldType)
+    {
+    case KUidContactFieldAddressValue:
+    {
+        // Label addresses are also stored in the database using
+        // KUidContactFieldAddressValue, but we don't support them
+        if (type.ContainsFieldType(KUidContactFieldVCardMapADR))
+        {
+            return ETrue;
+        }
+        else
+        {
+            return EFalse;
+        }
+    }
+    case KUidContactFieldPictureValue:
+    {
+        // Thumbnails are supported while pictures are not
+        if (type.ContainsFieldType(KUidContactFieldVCardMapPHOTO))
+        {
+            return ETrue;
+        }
+        else
+        {
+            return EFalse;
+        }
+    }
+    case KUidContactFieldSIPIDValue:
+    case KUidContactFieldFamilyNameValue:
+    case KUidContactFieldGivenNameValue:
+    case KUidContactFieldSecondNameValue:
+    case KUidContactFieldFamilyNamePronunciationValue:
+    case KUidContactFieldGivenNamePronunciationValue:
+    case KUidContactFieldAdditionalNameValue:
+    case KUidContactFieldPrefixNameValue:
+    case KUidContactFieldSuffixNameValue:
+    case KUidContactFieldPhoneNumberValue:
+    case KUidContactFieldFaxValue:
+    case KUidContactFieldEMailValue:
+    case KUidContactFieldUrlValue:
+    case KUidContactFieldPostOfficeValue:
+    case KUidContactFieldExtendedAddressValue:
+    case KUidContactFieldPostCodeValue:
+    case KUidContactFieldLocalityValue:
+    case KUidContactFieldRegionValue:
+    case KUidContactFieldCountryValue:
+    case KUidContactFieldCompanyNameValue:
+    case KUidContactFieldNoteValue:
+    case KUidContactFieldBirthdayValue:
+    case KUidContactFieldJobTitleValue:
+    case KUidContactFieldDTMFValue:
+    case KUidContactFieldIMAddressValue:
+    case KUidContactFieldDepartmentNameValue:
+    case KUidContactFieldAssistantValue:
+    case KUidContactFieldChildrenValue:
+    case KUidContactFieldSpouseValue:
+    case KUidContactFieldAnniversaryValue:
+    case KUidContactFieldClassValue:
+    {
+        return ETrue;
+    }
+    default:
+    {
+        return EFalse;
+    }
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::ConvertFieldL
+// Converts a field from a PIM Item to a Contact Card.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::ConvertFieldL(const MPIMContactItem& aItem, // item to read the field from
+        CContactCard& aCard, // card to write the field to
+        TPIMContactField aField) // field to convert
+{
+    JELOG2(EPim);
+    const MPIMItemData& itemData = aItem.ItemData();
+
+    // These are indexes in PIM Item address values
+    TInt plainAddressIndex = KErrNotFound;
+    TInt homeAddressIndex = KErrNotFound;
+    TInt workAddressIndex = KErrNotFound;
+    if (aField == EPIMContactAddr)
+    {
+        AddressAttributesL(itemData, plainAddressIndex, homeAddressIndex,
+                           workAddressIndex);
+        ConvertAddressFieldL(itemData, aCard, aField, plainAddressIndex,
+                             KPIMAttrNone);
+        ConvertAddressFieldL(itemData, aCard, aField, homeAddressIndex,
+                             EPIMContactAttrHome);
+        ConvertAddressFieldL(itemData, aCard, aField, workAddressIndex,
+                             EPIMContactAttrWork);
+        return;
+    }
+
+    TInt valueCount = itemData.CountValues(aField);
+    for (TInt i = 0; i < valueCount; i++)
+    {
+        switch (aField)
+        {
+        case EPIMContactUid:
+        case EPIMContactRevision:
+        {
+            // uid and revision fields are totally ignored
+            break;
+        }
+        case EPIMContactBirthday:
+        case EPIMContactExtAnniversary:
+        {
+            ConvertDateFieldL(itemData, aCard, aField, i);
+            break;
+        }
+        case EPIMContactEmail:
+        case EPIMContactNickname:
+        case EPIMContactNote:
+        case EPIMContactOrg:
+        case EPIMContactTel:
+        case EPIMContactTitle:
+        case EPIMContactUrl:
+        case EPIMContactExtSip:
+        case EPIMContactExtDtmf:
+        case EPIMContactExtWvUserId:
+        case EPIMContactExtDepartment:
+        case EPIMContactExtAssistantName:
+        case EPIMContactExtChildren:
+        case EPIMContactExtSpouse:
+        case EPIMContactExtVoip:
+        case EPIMContactExtPTT:
+        case EPIMContactExtSWIS:
+        {
+            ConvertStringFieldL(itemData, aCard, aField, i);
+            break;
+        }
+        case EPIMContactName:
+        {
+            ConvertNameFieldL(itemData, aCard, aField, i);
+            break;
+        }
+        case EPIMContactPhoto:
+        {
+            ConvertPhotoFieldL(itemData, aCard, aField, i);
+            break;
+        }
+        case EPIMContactClass:
+        {
+            ConvertClassFieldL(itemData, aCard, aField, i);
+            break;
+        }
+        case EPIMContactFormattedName:
+        case EPIMContactFormattedAddr:
+        case EPIMContactPhotoUrl:
+        case EPIMContactPublicKey:
+        case EPIMContactPublicKeyString:
+        default:
+        {
+            __ASSERT_DEBUG(EFalse, User::Panic(KPIMPanicCategory,
+                                               EPIMPanicUnsupportedField));
+            return;
+        }
+        }
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::ConvertFieldL
+// Converts a field from a Contact Card to a PIM Item.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::ConvertFieldL(const CContactItemField& aField, // field to read data from
+        MPIMContactItem& aItem) // field to write the data to
+{
+    JELOG2(EPim);
+    TStorageType type = aField.StorageType();
+    switch (type)
+    {
+    case KStorageTypeText:
+    {
+        ConvertTextFieldL(aField, aItem);
+        break;
+    }
+    case KStorageTypeStore:
+    {
+        ConvertStoreFieldL(aField, aItem);
+        break;
+    }
+    case KStorageTypeContactItemId:
+    {
+        break;
+    }
+    case KStorageTypeDateTime:
+    {
+        ConvertDateFieldL(aField, aItem);
+        break;
+    }
+    default:
+    {
+        __ASSERT_DEBUG(EFalse, User::Panic(KPIMPanicCategory,
+                                           EPIMPanicUnsupportedField));
+    }
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::ConvertTextFieldL
+// Converts a text field from a Contact Card to a PIM Item.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::ConvertTextFieldL(const CContactItemField& aField, // field to read data from
+        MPIMContactItem& aItem) // field to write the data to
+{
+    JELOG2(EPim);
+    MPIMItemData& itemData = aItem.ItemData();
+    CContactTextField* textField = aField.TextStorage();
+    const CContentType& type = aField.ContentType();
+
+    // Check that can we handle this field
+    if (!(textField->IsFull()) || (type.FieldTypeCount() == 0))
+    {
+        return;
+    }
+
+    TPtrC text = textField->Text();
+    TFieldType fieldTypeUid = type.FieldType(0);
+    TPIMAttribute attributes = KPIMAttrNone;
+
+    TPIMField field = iFieldInfo->MatchContactField(fieldTypeUid.iUid);
+    // Check which field we must handle
+    switch (field)
+    {
+    case EPIMContactName:
+    {
+        TPIMContactNameElement
+        nameElement =
+            static_cast<TPIMContactNameElement>(iFieldInfo->MatchContactArrayElement(
+                                                    fieldTypeUid.iUid));
+        AddNameFieldToItemL(text, aItem, nameElement, aField.Label());
+        break;
+    }
+    case EPIMContactAddr:
+    {
+        TPIMContactAddrElement
+        addrElement =
+            static_cast<TPIMContactAddrElement>(iFieldInfo->MatchContactArrayElement(
+                                                    fieldTypeUid.iUid));
+        attributes = iFieldInfo->FieldAttributes(aField.ContentType());
+
+        // Label addresses are also stored in the database using
+        // KUidContactFieldAddressValue, but we don't support them
+        if (fieldTypeUid.iUid == KUidContactFieldAddressValue)
+        {
+            if (type.ContainsFieldType(KUidContactFieldVCardMapADR))
+            {
+                AddAddressFieldToItemL(text, aItem, EPIMContactAddrStreet,
+                                       attributes, aField.Label());
+            }
+        }
+        else
+        {
+            AddAddressFieldToItemL(text, aItem, addrElement, attributes,
+                                   aField.Label());
+        }
+        break;
+    }
+    case EPIMContactClass:
+    {
+        AddClassFieldToItemL(itemData, text, aField.Label());
+        break;
+    }
+    case EPIMContactExtSip:
+    case EPIMContactExtVoip:
+    case EPIMContactExtPTT:
+    case EPIMContactExtSWIS:
+    {
+        // SIPID value can hold PoC (Push-To-Talk) Share view, SIP
+        // and VOIP (Voice Over IP) fields inside it.
+        // Apply internal attributes
+        CArrayFix<TUid>* attrs = new(ELeave) CArrayFixFlat<TUid> (3);
+        CleanupStack::PushL(attrs);
+        iFieldInfo->GetFieldInternalAttributesL(type, *attrs);
+        // VOIP (Internet telephone) field
+        if (type.ContainsFieldType(KUidContactFieldVCardMapVOIP))
+        {
+            attributes = iFieldInfo->FieldAttributes(type);
+            field = EPIMContactExtVoip;
+        }
+        else if (type.ContainsFieldType(KUidContactFieldVCardMapPOC))
+        {
+            field = EPIMContactExtPTT;
+        }
+        else if (type.ContainsFieldType(KUidContactFieldVCardMapSWIS))
+        {
+            field = EPIMContactExtSWIS;
+        }
+        else
+        {
+            field = EPIMContactExtSip;
+        }
+        // Add field, attributes, internal attributes and label to the item
+        // Note that internal attributes are popped from the cleanup stack
+        // inside the following function and there is no need to pop after it
+        AddStringFieldWithLabelL(itemData, field, attributes, attrs, text,
+                                 aField.Label());
+        break;
+    }
+    case EPIMContactEmail:
+    case EPIMContactNickname:
+    case EPIMContactNote:
+    case EPIMContactOrg:
+    case EPIMContactTel:
+    case EPIMContactTitle:
+    case EPIMContactUrl:
+    case EPIMContactExtDtmf:
+    case EPIMContactExtWvUserId:
+    case EPIMContactExtDepartment:
+    case EPIMContactExtAssistantName:
+    case EPIMContactExtChildren:
+    case EPIMContactExtSpouse:
+    {
+        // Get internal attributes from the content type
+        CArrayFix<TUid>* attrs = new(ELeave) CArrayFixFlat<TUid> (3);
+        CleanupStack::PushL(attrs);
+        iFieldInfo->GetFieldInternalAttributesL(type, *attrs);
+        // Add attributes. FAX is special so it must be handled separately
+        attributes = iFieldInfo->FieldAttributes(aField.ContentType());
+        if (fieldTypeUid.iUid == KUidContactFieldFaxValue)
+        {
+            attributes |= EPIMContactAttrFax;
+        }
+        // Add field, attributes, internal attributes and label to the item
+        // Note that internal attributes are popped from the cleanup stack
+        // inside the following function and there is no need to pop after it
+        AddStringFieldWithLabelL(itemData, field, attributes, attrs, text,
+                                 aField.Label());
+        break;
+    }
+    default:
+    {
+        // The field is not supported so we don't know what to do with it
+        // and it is ignored. NOTE that contacts are opened first before
+        // writing those to the contact database to ensure that unsupported
+        // fields will still be included the to item and no data will be lost
+        break;
+    }
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::AddStringFieldWithLabelL
+// Adds a string field to the item, and optionally sets the fields label.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::AddStringFieldWithLabelL(MPIMItemData& aItem,
+        TPIMField aField, TPIMAttribute aAttributes,
+        CArrayFix<TUid>* aInternalAttributes, const TPtrC aValue,
+        const TPtrC aLabel)
+{
+    JELOG2(EPim);
+    TInt valueCount = aItem.CountValues(aField);
+    TPIMFieldData fieldData(aField, aAttributes, aValue.AllocLC());
+
+    // Add data to the item
+    aItem.AddValueL(fieldData);
+    CleanupStack::Pop(); // aValue.AlloclC()
+    // Apply internal attributes
+    aItem.SetInternalAttributesL(aField, valueCount, aInternalAttributes);
+    // aItem now owns aInternalAttributes
+    CleanupStack::Pop(aInternalAttributes);
+
+    // Set preferred index if it is set to this field value index
+    // Only one value index of this field can have preferred index set
+    // so we have to remove all existing preferred indexes. This has to
+    // be done to SMS attribute also. There cannot be more than one
+    // preferred SMS number in the S60 Phonebook
+    if (aAttributes & EPIMContactAttrPreferred || aAttributes
+            & EPIMContactAttrSms)
+    {
+        // Clear "preferred index" attribute from all other values
+        // except this one (previously added one)
+        for (TInt i = 0; i < valueCount; i++)
+        {
+            TPIMAttribute attributes = aItem.AttributesL(aField, i);
+            // Clear attributes from preferred index
+            if (aAttributes & EPIMContactAttrPreferred)
+            {
+                attributes &= ~EPIMContactAttrPreferred;
+            }
+            if (aAttributes & EPIMContactAttrSms)
+            {
+                attributes &= ~EPIMContactAttrSms;
+            }
+            aItem.SetAttributesL(aField, i, attributes);
+        }
+    }
+
+    // Add label if necessary
+    if (aLabel.Length() > 0)
+    {
+        aItem.SetLabelL(aField, valueCount, 0, aLabel);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::ConvertDateFieldL
+// Converts a date field from a Contact Card to a PIM Item.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::ConvertDateFieldL(const CContactItemField& aField, // field to read data from
+        MPIMContactItem& aItem) // field to write the data to
+{
+    JELOG2(EPim);
+    MPIMItemData& itemData = aItem.ItemData();
+    CContactDateField* dateField = aField.DateTimeStorage();
+    if (!(dateField->IsFull()))
+    {
+        // if date is not set, we don't read it
+        return;
+    }
+    TTime time = dateField->Time();
+    const CContentType& type = aField.ContentType();
+
+    TPIMField field(0);
+    // Check the field type
+    if (type.ContainsFieldType(KUidContactFieldBirthday))
+    {
+        field = EPIMContactBirthday;
+    }
+    else if (type.ContainsFieldType(KUidContactFieldAnniversary))
+    {
+        field = EPIMContactExtAnniversary;
+    }
+
+    // Anniversary and Birthday are only dates so we are not interested
+    // in which is the time in these fields. This is because Phonebook
+    // doesn't take into account what time is used within these fields
+    // Time conversion between UTC and local time is not needed here
+    // because Phonebook handles only dates and PIM API times are in UTC
+    // format causing this date to be set to the start of the UTC date time
+    // and the date is shown correctly when midlet accesses it on the Java-side
+    TDateTime temp(time.DateTime());
+    temp.SetHour(0);
+    temp.SetSecond(0);
+    temp.SetMinute(0);
+    temp.SetMicroSecond(0);
+
+    // Count values and add new data
+    TInt valueCount = itemData.CountValues(field);
+    TPIMFieldData fieldData(field, KPIMAttrNone, TPIMDate(temp));
+    itemData.AddValueL(fieldData);
+
+    // Set label
+    if (aField.Label().Length() > 0)
+    {
+        itemData.SetLabelL(field, valueCount, 0, aField.Label());
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::ConvertStoreFieldL
+// Converts a store field from a Contact Card to a PIM Item.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::ConvertStoreFieldL(
+    const CContactItemField& aField, // field to read data from
+    MPIMContactItem& aItem) // field to write the data to
+{
+    JELOG2(EPim);
+    CContactStoreField* storeField = aField.StoreStorage();
+    if (!(storeField->IsFull()))
+    {
+        return;
+    }
+    const CContentType& type = aField.ContentType();
+    if (type.ContainsFieldType(KUidContactFieldPicture))
+    {
+        // We don't care about other store fields
+        MPIMItemData& itemData = aItem.ItemData();
+        HBufC8* data = storeField->Thing();
+        if (data)
+        {
+            TInt dataLength = data->Length();
+            CPIMByteArray* byteArray = new(ELeave) CPIMByteArray(dataLength);
+            CleanupStack::PushL(byteArray);
+            byteArray->AppendL(data->Ptr(), dataLength);
+            TPIMFieldData fieldData(EPIMContactPhoto, KPIMAttrNone, byteArray);
+            itemData.AddValueL(fieldData);
+            CleanupStack::Pop(); // byteArray
+        }
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::AddNameFieldToItemL
+// Adds a name field to a PIM Item
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::AddNameFieldToItemL(TPtrC aText, // text to add
+        MPIMContactItem& aItem, // item to add to
+        TPIMContactNameElement aElement, // element to add
+        TPtrC aLabel) // label of the field
+{
+    JELOG2(EPim);
+    MPIMItemData& itemData = aItem.ItemData();
+    // 7 for array granularity
+    CDesCArrayFlat* nameArray = new(ELeave) CDesC16ArrayFlat(7);
+    CleanupStack::PushL(nameArray);
+    // do we already have a name field in the item
+    TInt nameCount = itemData.CountValues(EPIMContactName);
+    if (nameCount > 0)
+    {
+        const TPIMFieldData fieldData = itemData.ValueL(EPIMContactName, 0);
+        const CDesCArray& oldNameArray = fieldData.StringArrayValue();
+        TInt elementCount = oldNameArray.Count();
+
+        for (TInt i = 0; i < elementCount; i++)
+        {
+            TPtrC16 oldName = oldNameArray[i];
+            nameArray->AppendL(oldName);
+        }
+        // don't trust that item data has correct amount of elements
+        for (TInt i = elementCount; i < EPIMContactNameNumElements; i++)
+        {
+            nameArray->AppendL(KPIMNullArrayElement());
+        }
+        // Add new element
+        nameArray->Delete(aElement);
+        nameArray->InsertL(aElement, aText);
+        TPIMFieldData newFieldData(EPIMContactName, KPIMAttrNone, nameArray);
+        itemData.SetValueL(newFieldData);
+    }
+    else
+    {
+        for (TInt i = 0; i < EPIMContactNameNumElements; i++)
+        {
+            nameArray->AppendL(KPIMNullArrayElement());
+        }
+        // Add new element
+        nameArray->Delete(aElement);
+        nameArray->InsertL(aElement, aText);
+        TPIMFieldData newFieldData(EPIMContactName, KPIMAttrNone, nameArray);
+        itemData.AddValueL(newFieldData);
+    }
+    // Name array is now owned by the item
+    CleanupStack::Pop(nameArray);
+    // Add label if it exists
+    if (aLabel.Length() > 0)
+    {
+        itemData.SetLabelL(EPIMContactName, 0, aElement, aLabel);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::AddAddressFieldToItemL
+// Adds an address field to a PIM Item
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::AddAddressFieldToItemL(TPtrC aText, // text to add
+        MPIMContactItem& aItem, // item to add to
+        TPIMContactAddrElement aElement, // element to add
+        TPIMAttribute aAttributes, // attributes of the address
+        TPtrC aLabel) // label
+{
+    JELOG2(EPim);
+    MPIMItemData& itemData = aItem.ItemData();
+    // 7 for array granularity
+    CDesCArrayFlat* addrArray = new(ELeave) CDesC16ArrayFlat(7);
+    CleanupStack::PushL(addrArray);
+    // do we already have an address field in the item with the same attributes
+    TInt addrCount = itemData.CountValues(EPIMContactAddr);
+    TBool notFound = ETrue;
+    TInt index = -1;
+    for (TInt i = 0; (notFound) && (i < addrCount); i++)
+    {
+        if (itemData.AttributesL(EPIMContactAddr, i) == aAttributes)
+        {
+            const TPIMFieldData fieldData = itemData.ValueL(EPIMContactAddr, i);
+            const CDesCArray& oldAddrArray = fieldData.StringArrayValue();
+            TInt elementCount = oldAddrArray.Count();
+            for (TInt j = 0; j < elementCount; j++)
+            {
+                TPtrC oldAddr = oldAddrArray[j];
+                addrArray->AppendL(oldAddr);
+            }
+            for (TInt j = elementCount; j < EPIMContactAddrNumElements; j++)
+            {
+                addrArray->AppendL(KPIMNullArrayElement());
+            }
+            notFound = EFalse;
+            addrArray->Delete(aElement);
+            addrArray->InsertL(aElement, aText);
+            TPIMFieldData newFieldData(EPIMContactAddr, aAttributes, addrArray);
+            newFieldData.SetIndex(i);
+            itemData.SetValueL(newFieldData);
+            index = i;
+        }
+    }
+    if (notFound)
+    {
+        for (TInt i = 0; i < EPIMContactAddrNumElements; i++)
+        {
+            addrArray->AppendL(KPIMNullArrayElement);
+        }
+        addrArray->Delete(aElement);
+        addrArray->InsertL(aElement, aText);
+        TPIMFieldData fieldData(EPIMContactAddr, aAttributes, addrArray);
+        itemData.AddValueL(fieldData);
+    }
+    // Array is now owned by the item
+    CleanupStack::Pop(addrArray);
+
+    // Add label if it exists
+    if (aLabel.Length() > 0)
+    {
+        // If the index is -1, it indicates that we are
+        // adding new string array at the end of the others
+        // so the index should be same as addrCount
+        index = (index == -1) ? addrCount : index;
+        itemData.SetLabelL(EPIMContactAddr, index, aElement, aLabel);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::ConvertAddressFieldL
+// Converts an address field from a PIM Item to a Contact Card.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::ConvertAddressFieldL(const MPIMItemData& aItem, // item to convert from
+        CContactCard& aCard, // card to write to
+        TPIMContactField aField, // field to convert
+        TInt aIndex, // index to the field
+        TPIMAttribute aAttributes) // attributes of the field
+{
+    JELOG2(EPim);
+    if (aIndex == KErrNotFound)
+    {
+        return;
+    }
+    const TPIMFieldData fieldData = aItem.ValueL(aField, aIndex);
+    const CDesCArray& addrArray = fieldData.StringArrayValue();
+    EContactFieldCategory category = EContactCategoryNone;
+    if (aAttributes == EPIMContactAttrHome)
+    {
+        category = EContactCategoryHome;
+    }
+    if (aAttributes == EPIMContactAttrWork)
+    {
+        category = EContactCategoryWork;
+    }
+
+    TInt addrCount = addrArray.Count();
+    for (TInt i = 0; i < addrCount; i++)
+    {
+        if (addrArray[i].Compare(KPIMNullArrayElement()) == 0)
+        {
+            // we don't add null elements
+            continue;
+        }
+
+        EnsureValidAddrElemLengthL(TPIMContactAddrElement(i), addrArray[i]);
+
+        CContentType* type = iFieldInfo->AddressContentTypeL(
+                                 static_cast<TPIMContactAddrElement>(i), category);
+        CleanupStack::PushL(type);
+
+        CContactItemField* field = CContactItemField::NewLC(KStorageTypeText,
+                                   *type);
+
+        // Add label to the field
+        TPIMContactAddrElement element = TPIMContactAddrElement(i);
+        const TPtrC label = aItem.LabelL(aField, aIndex, element);
+        if (label.Compare(KPIMNullArrayElement) != 0)
+        {
+            field->SetLabelL(label);
+        }
+        field->SetUserFlags(category);
+        // we don't store any label, Contacts Model should use default template
+        CContactTextField* textField = field->TextStorage();
+        textField->SetTextL(addrArray[i]);
+        // Card takes the ownership of the field
+        aCard.AddFieldL(*field);
+        CleanupStack::Pop(field);
+        CleanupStack::PopAndDestroy(type);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::ConvertNameFieldL
+// Converts an address field from a PIM Item to a Contact Card.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::ConvertNameFieldL(const MPIMItemData& aItem, // item to convert from
+        CContactCard& aCard, // card to write to
+        TPIMContactField aField, // field to convert
+        TInt aIndex) // index to the field
+{
+    JELOG2(EPim);
+    const TPIMFieldData fieldData = aItem.ValueL(aField, aIndex);
+    const CDesCArray& nameArray = fieldData.StringArrayValue();
+    EContactFieldCategory category = EContactCategoryHome;
+
+    TInt nameCount = nameArray.Count();
+    for (TInt i = 0; i < nameCount; i++)
+    {
+        if (nameArray[i].Compare(KPIMNullArrayElement()) == 0)
+        {
+            // we don't add null elements
+            continue;
+        }
+
+        EnsureValidNameElemLengthL(TPIMContactNameElement(i), nameArray[i]);
+
+        CContentType* type = iFieldInfo->NameContentTypeL(
+                                 static_cast<TPIMContactNameElement>(i));
+        CleanupStack::PushL(type);
+
+        CContactItemField* field = CContactItemField::NewLC(KStorageTypeText,
+                                   *type);
+
+        // Add label to the field. aIndex should be 0 in this case because
+        // there are only one string array in the name field
+        TPIMContactNameElement element = TPIMContactNameElement(i);
+        const TPtrC label = aItem.LabelL(aField, aIndex, element);
+        if (label.Compare(KPIMNullArrayElement) != 0)
+        {
+            field->SetLabelL(label);
+        }
+        field->SetUserFlags(category);
+        // we don't store any label, Contacts Model should use default template
+        CContactTextField* textField = field->TextStorage();
+        textField->SetTextL(nameArray[i]);
+        // Card takes ownership of the field
+        aCard.AddFieldL(*field);
+        CleanupStack::Pop(field);
+        CleanupStack::PopAndDestroy(type);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::ConvertDateFieldL
+// Converts a date field from a PIM Item to a Contact Card.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::ConvertDateFieldL(const MPIMItemData& aItem, // item to convert from
+        CContactCard& aCard, // card to write to
+        TPIMContactField aField, // field to convert
+        TInt aIndex) // index to the field
+{
+    JELOG2(EPim);
+    const TPIMFieldData fieldData = aItem.ValueL(aField, aIndex);
+    const TPIMDate& date = fieldData.DateValue();
+    CContentType* type = NULL;
+
+    switch (aField)
+    {
+    case EPIMContactBirthday:
+    {
+        type = CContentType::NewL(KUidContactFieldBirthday,
+                                  KUidContactFieldVCardMapBDAY);
+        CleanupStack::PushL(type);
+        break;
+    }
+    case EPIMContactExtAnniversary:
+    {
+        type = CContentType::NewL(KUidContactFieldAnniversary,
+                                  KUidContactFieldVCardMapAnniversary);
+        CleanupStack::PushL(type);
+        break;
+    }
+    default:
+    {
+        User::Panic(KPIMPanicCategory, EPIMPanicUnsupportedDateField);
+        break;
+    }
+    }
+    CContactItemField* field = CContactItemField::NewLC(KStorageTypeDateTime,
+                               *type);
+    // set label if set in pim item
+    const TPtrC label = aItem.LabelL(aField, aIndex, 0);
+    if (label.Compare(KPIMNullArrayElement) != 0)
+    {
+        field->SetLabelL(label);
+    }
+
+    field->SetUserFlags(EContactCategoryOther);
+    CContactDateField* dateField = field->DateTimeStorage();
+
+    // PIM API stores dates as UTC time. Phonebook instead expects that dates
+    // are stored as in local time format in the Contacts Model database
+    RTz tzServer;
+    User::LeaveIfError(tzServer.Connect());
+    CleanupClosePushL(tzServer);
+
+    // Create timezone converter
+    CTzConverter* converter = CTzConverter::NewL(tzServer);
+    CleanupStack::PushL(converter);
+
+    TTime localTime(date);
+    User::LeaveIfError(converter->ConvertToLocalTime(localTime));
+    CleanupStack::PopAndDestroy(2); // converter, tzServer
+
+    // Anniversary and Birthday are only dates so we are not interested
+    // in which is the time in these fields. This is because Phonebook
+    // doesn't take into account what time is used within these fields
+    TDateTime temp(localTime.DateTime());
+    temp.SetHour(0);
+    temp.SetMinute(0);
+    temp.SetSecond(0);
+    temp.SetMicroSecond(0);
+
+    dateField->SetTime(TTime(temp));
+    // Card takes ownership of the field
+    aCard.AddFieldL(*field);
+    CleanupStack::Pop(field);
+    CleanupStack::PopAndDestroy(type);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::ConvertStringFieldL
+// Converts a string field from a PIM Item to a Contact Card.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::ConvertStringFieldL(const MPIMItemData& aItem, // item to convert from
+        CContactCard& aCard, // card to write to
+        TPIMContactField aField, // field to convert
+        TInt aIndex) // index to the field
+{
+    JELOG2(EPim);
+    const CArrayFix<TUid>& attrs = aItem.InternalAttributesL(aField, aIndex);
+    const TPIMFieldData fieldData = aItem.ValueL(aField, aIndex);
+    const TDesC& string = fieldData.StringValue();
+    TPIMAttribute attributes = fieldData.Attributes();
+    EContactFieldCategory category = EContactCategoryNone;
+
+    EnsureValidStringValueLengthL(aField, string);
+
+    if ((attributes & EPIMContactAttrHome) != 0)
+    {
+        category = EContactCategoryHome;
+    }
+    if ((attributes & EPIMContactAttrWork) != 0)
+    {
+        category = EContactCategoryWork;
+    }
+    CContentType* type = iFieldInfo->StringFieldContentTypeL(aField,
+                         attributes, category);
+    CleanupStack::PushL(type);
+    // Apply internal attributes if any
+    TInt interalAttrCount = attrs.Count();
+    for (TInt i = 0; i < interalAttrCount; i++)
+    {
+        TFieldType fieldType = attrs.At(i);
+        // Check to avoid duplicate field types in the content type
+        // this may be possible when unrecognized fields are added to
+        // internal attribute list (e.g incorrectly generated ContentType)
+        if (!type->ContainsFieldType(fieldType))
+        {
+            type->AddFieldTypeL(fieldType);
+        }
+    }
+    // Create new contact item field which is a text storage
+    CContactItemField* field =
+        CContactItemField::NewLC(KStorageTypeText, *type);
+    // set label if set in pim item
+    const TPtrC label = aItem.LabelL(aField, aIndex, 0);
+    if (label.Compare(KPIMNullArrayElement) != 0)
+    {
+        field->SetLabelL(label);
+    }
+
+    field->SetUserFlags(category);
+    CContactTextField* textField = field->TextStorage();
+    textField->SetTextL(string);
+    // Card takes ownership of the field
+    aCard.AddFieldL(*field);
+    CleanupStack::Pop(field);
+    CleanupStack::PopAndDestroy(type);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::ConvertPhotoFieldL
+// Converts a photo field from a PIM Item to a Contact Card.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::ConvertPhotoFieldL(const MPIMItemData& aItem, // item to convert from
+        CContactCard& aCard, // card to write to
+        TPIMContactField aField, // field to convert
+        TInt aIndex) // index to the field
+{
+    JELOG2(EPim);
+    const TPIMFieldData fieldData = aItem.ValueL(aField, aIndex);
+    const CPIMByteArray& byteArray = fieldData.BinaryValue();
+    EContactFieldCategory category = EContactCategoryNone;
+    CContentType* type = CContentType::NewL(KUidContactFieldPicture,
+                                            KUidContactFieldVCardMapPHOTO);
+    CleanupStack::PushL(type);
+
+    CContactItemField* field = CContactItemField::NewLC(KStorageTypeStore,
+                               *type);
+    field->SetUserFlags(category);
+
+    const TUint8& byteRef = byteArray.At(0);
+    const TUint8* bytePtr = &byteRef;
+    TPtrC8 data(bytePtr, byteArray.Count());
+
+    HBufC8* thumbNail = iImageScaler->ScaleL(data);
+    CleanupStack::PushL(thumbNail);
+
+    CContactStoreField* storeField = field->StoreStorage();
+    storeField->SetThingL(*thumbNail);
+    CleanupStack::PopAndDestroy(); // thumbNail
+    // Card takes ownership of the field
+    aCard.AddFieldL(*field);
+    CleanupStack::Pop(field);
+    CleanupStack::PopAndDestroy(type);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::ConvertClassFieldL
+// Converts a CLASS field from a PIM Item to a Contact Card.
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::ConvertClassFieldL(const MPIMItemData& aItemData,
+        CContactCard& aCard, TPIMContactField aField, TInt aIndex)
+{
+    JELOG2(EPim);
+    TPtrC classValueDes(KPIMContactClassPrivate());
+    const TPIMFieldData fieldData = aItemData.ValueL(aField, aIndex);
+    const TInt classValue = fieldData.IntegerValue();
+    CContentType* type = CContentType::NewL(KUidContactFieldClass,
+                                            KUidContactFieldVCardMapClass);
+    CleanupStack::PushL(type);
+
+    switch (classValue)
+    {
+    case EPIMContactClassPrivate:
+    {
+        classValueDes.Set(KPIMContactClassPrivate());
+        break;
+    }
+    case EPIMContactClassPublic:
+    {
+        classValueDes.Set(KPIMContactClassPublic());
+        break;
+    }
+    case EPIMContactClassConfidential:
+    {
+        classValueDes.Set(KPIMContactClassConfidential());
+        break;
+    }
+    default:
+    {
+        __ASSERT_DEBUG(EFalse, User::Invariant());
+        break; // For a happy compiler
+    }
+    }
+    // Add value to the contact field
+    CContactItemField* field =
+        CContactItemField::NewLC(KStorageTypeText, *type);
+    field->SetUserFlags(EContactCategoryNone);
+
+    // Set label if any
+    const TPtrC label = aItemData.LabelL(aField, aIndex, 0);
+    if (label.Compare(KPIMNullArrayElement) != 0)
+    {
+        field->SetLabelL(label);
+    }
+
+    CContactTextField* textField = field->TextStorage();
+    textField->SetTextL(classValueDes);
+    // Card takes ownership of the field
+    aCard.AddFieldL(*field);
+    CleanupStack::Pop(field);
+    CleanupStack::PopAndDestroy(type);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::ConvertClassFieldL
+// Converts a CLASS field from a Contact Card to PIM item
+// -----------------------------------------------------------------------------
+//
+void CPIMContactItemAdapter::AddClassFieldToItemL(MPIMItemData& aItemData,
+        TPtrC& aClassDesValue, TPtrC aLabel)
+{
+    JELOG2(EPim);
+    // Syncronisation is private for default
+    TPIMContactClassValue classValue = EPIMContactClassPrivate;
+    TInt valueCount = aItemData.CountValues(EPIMContactClass);
+
+    if (aClassDesValue.Compare(KPIMContactClassPublic()) == 0)
+    {
+        classValue = EPIMContactClassPublic;
+    }
+    else if (aClassDesValue.Compare(KPIMContactClassPrivate()) == 0)
+    {
+        classValue = EPIMContactClassPrivate;
+    }
+    else if (aClassDesValue.Compare(KPIMContactClassConfidential()) == 0)
+    {
+        classValue = EPIMContactClassConfidential;
+    }
+    TPIMFieldData fieldData(EPIMContactClass, EPIMFieldInt, KPIMAttrNone,
+                            classValue);
+    aItemData.AddValueL(fieldData);
+    // Label if any
+    if (aLabel.Length() > 0)
+    {
+        aItemData.SetLabelL(EPIMContactClass, valueCount, 0, aLabel);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::AddressAttributesL
+// Checks the optimal attributes for the addresses
+// -----------------------------------------------------------------------------
+void CPIMContactItemAdapter::AddressAttributesL(const MPIMItemData& aItem,
+        TInt& aPlainAddressIndex, TInt& aHomeAddressIndex, TInt& aWorkAddressIndex)
+{
+    JELOG2(EPim);
+    aPlainAddressIndex = KErrNotFound;
+    aHomeAddressIndex = KErrNotFound;
+    aWorkAddressIndex = KErrNotFound;
+    TInt addressCount = aItem.CountValues(EPIMContactAddr);
+
+    // first pass - find zero and single attribute values if exist
+    TInt i = 0;
+    for (; i < addressCount; i++)
+    {
+        if (aItem.AttributesL(EPIMContactAddr, i) == KPIMAttrNone)
+        {
+            aPlainAddressIndex = i;
+        }
+        else if (aItem.AttributesL(EPIMContactAddr, i) == EPIMContactAttrHome)
+        {
+            aHomeAddressIndex = i;
+        }
+        else if (aItem.AttributesL(EPIMContactAddr, i) == EPIMContactAttrWork)
+        {
+            aWorkAddressIndex = i;
+        }
+    }
+
+    // second pass - fill in the rest
+    for (i = 0; i < addressCount; i++)
+    {
+        if ((aPlainAddressIndex != i) && (aHomeAddressIndex != i)
+                && (aWorkAddressIndex != i))
+        {
+            // this index has not been used yet
+            if (KErrNotFound == aWorkAddressIndex)
+            {
+                aWorkAddressIndex = i;
+            }
+            else if (KErrNotFound == aHomeAddressIndex)
+            {
+                aHomeAddressIndex = i;
+            }
+            else if (KErrNotFound == aPlainAddressIndex)
+            {
+                aPlainAddressIndex = i;
+            }
+            else
+            {
+                // all indexes are filled
+                break; // out of the for loop
+            }
+        }
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::EnsureValidStringValueLengthL
+// -----------------------------------------------------------------------------
+void CPIMContactItemAdapter::EnsureValidStringValueLengthL(
+    TPIMContactField aField, const TDesC& aValue)
+{
+    JELOG2(EPim);
+    const TInt* maxLengthArr = NULL;
+    TInt offset = 0;
+    TInt arrLen = 0;
+
+    if (aField >= KContactExtStringMaxLengthOffset)
+    {
+        maxLengthArr = KContactExtStringMaxLengths;
+        offset = KContactExtStringMaxLengthOffset;
+        arrLen = KContactExtStringMaxLengthsLen;
+    }
+    else
+    {
+        maxLengthArr = KContactStringMaxLengths;
+        offset = KContactStringMaxLengthsOffset;
+        arrLen = KContactStringMaxLengthsLen;
+    }
+
+    TInt index = aField - offset;
+
+    __ASSERT_ALWAYS((index >= 0), User::Invariant());
+    __ASSERT_ALWAYS((index < arrLen), User::Invariant());
+
+    TInt maxLen = maxLengthArr[index];
+    if ((maxLen > 0) && (aValue.Length() > maxLen))
+    {
+        User::Leave(KErrTooBig);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::EnsureValidAddrElemLengthL
+// -----------------------------------------------------------------------------
+void CPIMContactItemAdapter::EnsureValidAddrElemLengthL(
+    TPIMContactAddrElement aElemIndex, const TDesC& aElemValue)
+{
+    JELOG2(EPim);
+    __ASSERT_DEBUG((aElemIndex >= 0), User::Invariant());
+
+    __ASSERT_DEBUG((aElemIndex < EPIMContactAddrNumElements), User::Invariant());
+
+    __ASSERT_DEBUG(
+        (KContactAddrElemMaxLengths[aElemIndex] != KErrNotSupported),
+        User::Invariant());
+
+    if ((KContactAddrElemMaxLengths[aElemIndex] != KErrNotSupported)
+            && (aElemValue.Length() > KContactAddrElemMaxLengths[aElemIndex]))
+    {
+        User::Leave(KErrTooBig);
+    }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMContactItemAdapter::EnsureValidNameElemLengthL
+// -----------------------------------------------------------------------------
+void CPIMContactItemAdapter::EnsureValidNameElemLengthL(
+    TPIMContactNameElement aElemIndex, const TDesC& aElemValue)
+{
+    JELOG2(EPim);
+    __ASSERT_DEBUG((aElemIndex >= 0), User::Invariant());
+
+    __ASSERT_DEBUG((aElemIndex < EPIMContactNameNumElements), User::Invariant());
+
+    __ASSERT_DEBUG(
+        (KContactNameElemMaxLengths[aElemIndex] != KErrNotSupported),
+        User::Invariant());
+
+    if ((KContactNameElemMaxLengths[aElemIndex] != KErrNotSupported)
+            && (aElemValue.Length() > KContactNameElemMaxLengths[aElemIndex]))
+    {
+        User::Leave(KErrTooBig);
+    }
+}
+
+// End of File