--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javaextensions/pim/versit/src.s60/cpimcardpropertyconverter.cpp Mon May 03 12:27:20 2010 +0300
@@ -0,0 +1,1200 @@
+/*
+* 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: Converts properties PIM <-> vCard
+ *
+*/
+
+
+// CLASS HEADER
+#include "cpimcardpropertyconverter.h"
+
+// INTERNAL INCLUDES
+#include "pimcommon.h"
+#include "pimpanics.h"
+#include "pimversit.h"
+#include "cpimitem.h"
+#include "cpimvcardparser.h"
+#include "cpimcontactitem.h"
+#include "cpimparserproperty.h"
+#include "cpimcontactvalidator.h"
+#include "cpimvcardparserparamarray.h"
+#include "logger.h"
+
+// EXTERNAL INCLUDES
+#include <vcard.h>
+#include <cntdef.h> // parameter literals
+#include <tz.h>
+#include <tzconverter.h>
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CPIMCardPropertyConverter* CPIMCardPropertyConverter::NewL(
+ const CPIMContactValidator& aValidator)
+{
+ JELOG2(EPim);
+ CPIMCardPropertyConverter* self =
+ new(ELeave) CPIMCardPropertyConverter(aValidator);
+
+ return self;
+}
+
+// Destructor
+CPIMCardPropertyConverter::~CPIMCardPropertyConverter()
+{
+ JELOG2(EPim);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertFieldL
+// Inserts a Field from a PIM Contact Item to CParserVCard as a property.
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::ConvertFieldL(const CPIMItem& aItem, // item to read the field from
+ CParserVCard& aParser, // parser to insert the property to.
+ TPIMContactField aField) // field to convert
+{
+ JELOG2(EPim);
+ TInt valueCount = aItem.CountValuesL(aField);
+ for (TInt i = 0; i < valueCount; i++)
+ {
+ switch (aField)
+ {
+ case EPIMContactAddr:
+ {
+ ConvertAddressFieldL(aItem, aParser, aField, i);
+ break;
+ }
+ case EPIMContactBirthday:
+ case EPIMContactRevision:
+ case EPIMContactExtAnniversary:
+ {
+ ConvertDateFieldL(aItem, aParser, aField, i);
+ break;
+ }
+ case EPIMContactEmail:
+ case EPIMContactNote:
+ case EPIMContactTel:
+ case EPIMContactTitle:
+ case EPIMContactUrl:
+ case EPIMContactNickname:
+ case EPIMContactExtSip:
+ case EPIMContactExtDtmf:
+ case EPIMContactExtWvUserId:
+ case EPIMContactExtSpouse:
+ case EPIMContactExtChildren:
+ case EPIMContactExtAssistantName:
+ case EPIMContactExtVoip:
+ case EPIMContactExtPTT:
+ case EPIMContactExtSWIS:
+ // UID is required by VFX. Do not fix even though this is wrong
+ case EPIMContactUid:
+ {
+ ConvertStringFieldL(aItem, aParser, aField, i);
+ break;
+ }
+ case EPIMContactName:
+ {
+ ConvertNameFieldL(aItem, aParser, aField, i);
+ break;
+ }
+ case EPIMContactOrg:
+ case EPIMContactExtDepartment:
+ {
+ ConvertOrganisationalFieldsL(aItem, aParser, aField, i);
+ break;
+ }
+ case EPIMContactPhoto:
+ {
+ ConvertPhotoFieldL(aItem, aParser, aField, i);
+ break;
+ }
+ case EPIMContactClass:
+ {
+ ConvertClassFieldL(aItem, aParser, aField, i);
+ break;
+ }
+ // PIM API vCard parser does not support converting formatted names
+ // since the conversion is not unambiguous and an optional feature
+ // for vCard parsers based on IMC vCard specification. Also, PIM
+ // API internal specification version 4.3 does not allow
+ // Contact.FORMATTED_NAME to be a supported fields in S60 implementations
+ case EPIMContactFormattedName:
+ case EPIMContactFormattedAddr:
+ case EPIMContactPhotoUrl:
+ case EPIMContactPublicKey:
+ case EPIMContactPublicKeyString:
+ default:
+ {
+ __ASSERT_DEBUG(EFalse, User::Panic(KPIMPanicCategory,
+ EPIMPanicUnsupportedField));
+ return;
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertPropertyL
+// Inserts a proprety from a vCard to a PIM Contact Item as a field
+// -----------------------------------------------------------------------------
+//
+CParserVCard* CPIMCardPropertyConverter::ConvertPropertyL(
+ const CParserProperty& aProperty, // property to convert
+ CPIMContactItem& aItem) // item to insert the field to
+{
+ JELOG2(EPim);
+ TUid valueTypeUid = aProperty.Uid();
+ TInt valueType = valueTypeUid.iUid;
+ CParserVCard* retVal = NULL;
+
+ // The following, rather ugly, cast makes it possible for us to access
+ // the protected iArrayOfParams field.
+ const CPIMParserProperty& property =
+ static_cast<const CPIMParserProperty&>(aProperty);
+
+ // CLASS field is converted before others
+ if (aProperty.Name().CompareF(KVersitTokenClass) == 0)
+ {
+ ConvertClassPropertyL(property, aItem);
+ }
+ // If SOUND field holds parameter X-IRMC-N, it countains name reading fields
+ else if ((aProperty.Name().CompareF(KVersitTokenSOUND) == 0)
+ && (aProperty.Param(KVersitParam8NamePrn)))
+ {
+ ConvertNameReadingFieldL(property, aItem);
+ }
+ else
+ {
+ switch (valueType)
+ {
+ case KVersitPropertyBinaryUid:
+ {
+ ConvertPhotoPropertyL(property, aItem);
+ break;
+ }
+ case KVersitPropertyCDesCArrayUid:
+ {
+ // name and address arrays
+ ConvertCDesCArrayPropertyL(property, aItem);
+ break;
+ }
+ case KVersitPropertyDateUid:
+ case KVersitPropertyDateTimeUid:
+ {
+ // REV, BDAY, X-ANNIVERSARY
+ ConvertDatePropertyL(property, aItem);
+ break;
+ }
+ case KVersitPropertyHBufCUid:
+ {
+ ConvertStringPropertyL(property, aItem);
+ break;
+ }
+ case KVCardPropertyAgentUid:
+ {
+ retVal = ConvertAgentPropertyL(property);
+ }
+ default:
+ {
+ // don't support, don't care
+ }
+ }
+ }
+ return retVal;
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::CPIMCardPropertyConverter
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CPIMCardPropertyConverter::CPIMCardPropertyConverter(
+ const CPIMContactValidator& aValidator) :
+ iContactValidator(aValidator)
+{
+ JELOG2(EPim);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertAgentPropertyL
+// Converts an agent property.
+// -----------------------------------------------------------------------------
+//
+inline CParserVCard* CPIMCardPropertyConverter::ConvertAgentPropertyL(
+ const CPIMParserProperty& aProperty) // property to convert
+{
+ JELOG2(EPim);
+ CParserPropertyValueAgent* propertyValue =
+ static_cast<CParserPropertyValueAgent*>(aProperty.Value());
+ CParserVCard* value = propertyValue->Value();
+ return value;
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::AddParamHomeAndWorkL
+// Adds parameters "HOME" and "WORK" if necessary to given property parameter
+// array.
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::AddParamHomeAndWorkL(TPIMAttribute aAttributes, // checked if it contains AttrHome or AttrWork
+ CPIMVCardParserParamArray& aParamArray) // array to add the parameters to
+{
+ JELOG2(EPim);
+ if ((aAttributes & EPIMContactAttrHome) != 0)
+ {
+ AddParserParameterL(aParamArray, KVersitParam8Home());
+ }
+ if ((aAttributes & EPIMContactAttrWork) != 0)
+ {
+ AddParserParameterL(aParamArray, KVersitParam8Work());
+ }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertAddressFieldL
+// Converts an address field from a PIM Contact Item to CParserVCard.
+// The field is stored in the parser as a property.
+// The address values are stored in CParserPropertyValue
+// CParserProperty is created, given the value.
+// Parameters are added, and finally the property is added to parser.
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::ConvertAddressFieldL(const CPIMItem& aItem, // item to convert from
+ CParserVCard& aParser, // parsers to write to
+ TPIMContactField aField, // field to convert
+ TInt aIndex) // index to the field
+{
+ JELOG2(EPim);
+ // Add attributes if there are any
+ TPIMAttribute attributes = aItem.getAttributes(aField, aIndex);
+ CPIMVCardParserParamArray* paramArray =
+ new(ELeave) CPIMVCardParserParamArray(3);
+ CleanupStack::PushL(paramArray);
+ AddParamHomeAndWorkL(attributes, *paramArray);
+
+ const CDesCArray& itemAddrArray = aItem.GetStringArrayL(aField, aIndex);
+ // Copy the array
+ TInt elementCount = itemAddrArray.Count();
+ CDesCArrayFlat* addrArray = new(ELeave) CDesCArrayFlat(elementCount);
+ CleanupStack::PushL(addrArray);
+ for (TInt i = 0; i < elementCount; i++)
+ {
+ if (itemAddrArray[i].Compare(KPIMNullArrayElement) == 0)
+ {
+ addrArray->AppendL(KNullDesC);
+ }
+ else
+ {
+ addrArray->AppendL(itemAddrArray[i]);
+ }
+ }
+
+ CParserPropertyValue* propertyValue =
+ new(ELeave) CParserPropertyValueCDesCArray(addrArray);
+ // addrArray is now owned by propertyValue
+ CleanupStack::Pop(addrArray);
+ AddPropertyToParserL(propertyValue, KVersitTokenADR(), paramArray, aParser);
+ // The paramArray and propertyValue are popped by the previous function call
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertNameFieldL
+// Converts a Name field from a PIM Contact Item to CParserVCard.
+// The field is stored in the parser as a property.
+// The name values are stored in CParserPropertyValue
+// CParserProperty is created, given the value.
+// Parameters are added, and finally the property is added to parser.
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::ConvertNameFieldL(const CPIMItem& aItem, // item to convert from
+ CParserVCard& aParser, // parsers to write to
+ TPIMContactField aField, // field to convert
+ TInt aIndex) // index to the field
+{
+ JELOG2(EPim);
+ TBool readingFieldsPresent = EFalse;
+ const CDesCArray& itemNameArray = aItem.GetStringArrayL(aField, aIndex);
+ TInt elementCount = itemNameArray.Count();
+ CDesCArray* readingArray = new(ELeave) CDesCArrayFlat(2);
+ CleanupStack::PushL(readingArray);
+ CDesCArray* nameArray = new(ELeave) CDesCArrayFlat(elementCount);
+ CleanupStack::PushL(nameArray);
+
+ // Names should be ordered as follows:
+ // Family name, Given name, Middle name, Prefix, Suffix
+ // so check TPIMContactNameElement that it is in the right order
+ for (TInt i = 0; i < elementCount; i++)
+ {
+ // Skip extended name reading fields on here
+ if (i == EPIMContactExtFamilyNameReading || i
+ == EPIMContactExtGivenNameReading)
+ {
+ if (itemNameArray[i].Compare(KPIMNullArrayElement) != 0)
+ {
+ readingFieldsPresent = ETrue;
+ readingArray->AppendL(itemNameArray[TPIMContactNameElement(i)]);
+ }
+ else
+ {
+ readingArray->AppendL(KNullDesC);
+ }
+ }
+ // Replace null array elements with KNullDesC
+ else if (itemNameArray[i].Compare(KPIMNullArrayElement) == 0)
+ {
+ nameArray->AppendL(KNullDesC);
+ }
+ else
+ {
+ nameArray->AppendL(itemNameArray[TPIMContactNameElement(i)]);
+ }
+ }
+ CParserPropertyValue* propertyValue =
+ new(ELeave) CParserPropertyValueCDesCArray(nameArray);
+ // nameArray is now owned by propertyValue
+ CleanupStack::Pop(nameArray);
+ AddPropertyToParserL(propertyValue, KVersitTokenN(), NULL, aParser);
+ // The paramArray and propertyValue are popped by the previous function call
+
+ // Add name reading fields if they are present
+ if (readingFieldsPresent)
+ {
+ // Create parameter array
+ CPIMVCardParserParamArray* paramArray =
+ new(ELeave) CPIMVCardParserParamArray(1);
+ CleanupStack::PushL(paramArray);
+ // Create pronunciation parameter and add it to the parameter array
+ AddParserParameterL(*paramArray, KVersitParam8NamePrn());
+ // Create a new proprety value from the reading names array
+ CParserPropertyValue* readingPropValue =
+ new(ELeave) CParserPropertyValueCDesCArray(readingArray);
+ // nameArray is now owned by propertyValue
+ CleanupStack::Pop(paramArray);
+ CleanupStack::Pop(readingArray);
+ CleanupStack::PushL(paramArray);
+ AddPropertyToParserL(readingPropValue, KVersitTokenSOUND(), paramArray,
+ aParser);
+ // The paramArray and propertyValue are popped
+ // by the previous function call
+ }
+ else
+ {
+ // Clean the reading array
+ CleanupStack::PopAndDestroy(readingArray);
+ }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertCDesCArrayPropertyL
+// Converts name and address arrays from a vCard to a PIM Contact Item
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::ConvertCDesCArrayPropertyL(
+ const CPIMParserProperty& aProperty, // property to convert
+ CPIMContactItem& aItem) // item to insert the field to
+{
+ JELOG2(EPim);
+ TPIMField field = aProperty.MatchContactField();
+
+ if ((field != EPIMContactAddr) && (field != EPIMContactName) && (field
+ != EPIMContactOrg) && (field != EPIMContactExtChildren))
+ {
+ // unsupported properties are silently discarded
+ return;
+ }
+
+ CParserPropertyValueCDesCArray* propertyValue =
+ static_cast<CParserPropertyValueCDesCArray*>(aProperty.Value());
+ const CDesCArray* value = propertyValue->Value();
+
+ // In ORG field, the Organizational name is the first item and the second
+ // item is extended department name
+ if (field == EPIMContactOrg)
+ {
+ TInt valueCount = value->Count();
+ if (valueCount >= 1)
+ {
+ HBufC* orgValue = value->MdcaPoint(0).AllocLC();
+ aItem.AddStringL(field, KPIMAttrNone, orgValue);
+ CleanupStack::Pop(orgValue);
+ // Get department from the array
+ if (valueCount > 1)
+ {
+ HBufC* department = value->MdcaPoint(1).AllocLC();
+ aItem.AddStringL(EPIMContactExtDepartment, KPIMAttrNone,
+ department);
+ CleanupStack::Pop(department);
+ }
+ }
+ return;
+ }
+ // Children is imported as a CDesCArray so we have to convert it here
+ if (field == EPIMContactExtChildren && value->Count() >= 1)
+ {
+ // We are only interested about the first value
+ HBufC* children = value->MdcaPoint(0).AllocLC();
+ aItem.AddStringL(field, KPIMAttrNone, children);
+ CleanupStack::Pop(children);
+ return;
+ }
+
+ // Copy the array
+ TInt elementCount = value->Count();
+ CDesCArrayFlat* itemArray = new(ELeave) CDesCArrayFlat(elementCount);
+ CleanupStack::PushL(itemArray);
+ TInt i;
+ for (i = 0; i < elementCount; i++)
+ {
+ itemArray->AppendL((*value)[i]);
+ }
+
+ // If we need more elements, add nulls
+ TInt itemElementCount = iContactValidator.NumElementsL(field);
+ TPtrC nullArrayElement(KPIMNullArrayElement);
+ for (; i < itemElementCount; i++)
+ {
+ itemArray->AppendL(nullArrayElement);
+ }
+
+ TPIMAttribute attributes = KPIMAttrNone;
+ // Usually people only have one name. However, both PIM api and
+ // vCards allow two names: Formatted name is not supported anymore since
+ // converting it is not unambiguous and it must not be supported by the
+ // PIM API internal specification version 4.3. IMC's vCard specification
+ // states that Formatted name is an optional field for vCard parsers.
+ if (field == EPIMContactName && aItem.CountValuesL(EPIMContactName) > 0)
+ {
+ // we already have a name, so we just change the current one
+ // NOTE: There can be name reading fields before the name array
+ // elements are added so we have take care of it
+ const CDesCArray& nameArray = aItem.GetStringArrayL(EPIMContactName, 0);
+ TPtrC name(nameArray.MdcaPoint(EPIMContactExtFamilyNameReading));
+ if (name != KPIMNullArrayElement)
+ {
+ // Delete empty item and add existing item
+ itemArray->Delete(EPIMContactExtFamilyNameReading);
+ itemArray->InsertL(EPIMContactExtFamilyNameReading, name);
+ }
+ name.Set(nameArray.MdcaPoint(EPIMContactExtGivenNameReading));
+ if (name != KPIMNullArrayElement)
+ {
+ // Delete empty item and add existing item
+ itemArray->Delete(EPIMContactExtGivenNameReading);
+ itemArray->InsertL(EPIMContactExtGivenNameReading, name);
+ }
+
+ aItem.SetStringArrayL(EPIMContactName, 0, attributes, itemArray);
+ CleanupStack::Pop(); // itemArray now owned by aItem
+ return;
+ }
+ else
+ {
+ // address can have attributes
+ attributes = aProperty.MatchHomeAndWorkAttributes();
+ }
+ aItem.AddStringArrayL(field, attributes, itemArray);
+ CleanupStack::Pop(); // itemArray now owned by aItem
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertDateFieldL
+// Converts a date field from a PIM Contact Item to a CParserVCard.
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::ConvertDateFieldL(const CPIMItem& aItem, // item to convert from
+ CParserVCard& aParser, // parser to insert the property to.
+ TPIMContactField aField, // field to convert
+ TInt aIndex) // index to the field
+{
+ JELOG2(EPim);
+ TVersitDateTime* versitDateTime = NULL;
+ CParserPropertyValue* propertyValue = NULL;
+ TPtrC8 propertyName(KNullDesC8);
+
+ // Handle fields separately
+ switch (aField)
+ {
+ case EPIMContactExtAnniversary:
+ case EPIMContactBirthday:
+ {
+ const TPIMDate date = aItem.GetDateL(aField, aIndex);
+ // Convert times to local time since UTC time designator is not
+ // supported in anniversary and birthday fields
+ 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
+
+ versitDateTime
+ = new(ELeave) TVersitDateTime(date.DateTime(), TVersitDateTime::EIsMachineLocal);
+
+ // Set specific property name
+ if (aField == EPIMContactBirthday)
+ {
+ propertyName.Set(KVersitTokenBDAY);
+ }
+ else if (aField == EPIMContactExtAnniversary)
+ {
+ propertyName.Set(KVersitTokenAnniversary);
+ }
+ CleanupDeletePushL(versitDateTime);
+ // Create new date property value
+ propertyValue = new(ELeave) CParserPropertyValueDate(versitDateTime);
+ break;
+ }
+ case EPIMContactRevision:
+ {
+ TPIMDate date = aItem.LastModified();
+ versitDateTime
+ = new(ELeave) TVersitDateTime(date.DateTime(), TVersitDateTime::EIsUTC);
+ propertyName.Set(KVersitTokenREV);
+ CleanupDeletePushL(versitDateTime);
+ // Create new date and time property value
+ propertyValue
+ = new(ELeave) CParserPropertyValueDateTime(versitDateTime);
+ break;
+ }
+ default:
+ {
+ User::Panic(KPIMPanicCategory, EPIMPanicUnsupportedDateField);
+ break;
+ }
+ }
+ // versitDateTime is now owned by propertyValue
+ CleanupStack::Pop(versitDateTime);
+ AddPropertyToParserL(propertyValue, propertyName, NULL, aParser);
+ // The paramArray and propertyValue are popped by the previous function call
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertDatePropertyL
+// Converts a birthday from a vCard to a PIM Contact Item
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::ConvertDatePropertyL(
+ const CPIMParserProperty& aProperty, // property to convert
+ CPIMContactItem& aItem) // item to insert the field to
+{
+ JELOG2(EPim);
+ TPIMField field = aProperty.MatchContactField();
+ switch (field)
+ {
+ case EPIMContactExtAnniversary:
+ case EPIMContactBirthday:
+ case EPIMContactRevision:
+ {
+ // All date property values are equal (in some way)
+ CParserPropertyValueDateTime* value =
+ static_cast<CParserPropertyValueDateTime*>(aProperty.Value());
+ // Get versit date time object. Both date time properties
+ // return TVersitDateTime so we don't care about the actual object
+ const TVersitDateTime* vDateTime = value->Value();
+ // Add new date to PIM item
+ TPIMDate date(vDateTime->iDateTime);
+ aItem.AddDateL(field, KPIMAttrNone, date);
+ break;
+ }
+ default:
+ {
+ // Discard other fields
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertStringFieldL
+// Converts a string field from a PIM Item to vCard
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::ConvertStringFieldL(const CPIMItem& aItem, // item to convert from
+ CParserVCard& aParser, // parser to write to
+ TPIMContactField aField, // field to convert
+ TInt aIndex) // index to the value in the field
+{
+ JELOG2(EPim);
+ // We'll gather all property parameters (attributes) to an array
+ // which we give to the property in construction. It seems to be
+ // the only way to give a property multiple parameters of same type.
+ TPIMAttribute attributes = aItem.getAttributes(aField, aIndex);
+ // Assistant tel field is mapped for its own field in s60, so
+ // it must not be associated with the standard TEL field in vCards
+ if (aField == EPIMContactTel && (attributes & EPIMContactAttrAsst) != 0)
+ {
+ const TDesC& asstTel = aItem.GetStringL(aField, aIndex);
+ CParserPropertyValue* propertyValue = CParserPropertyValueHBufC::NewL(
+ asstTel);
+ AddPropertyToParserL(propertyValue, KPIMVersitTokenASSTTEL(), NULL,
+ aParser);
+ // Needed cleanup stack cleanup is done within the function
+ return;
+ }
+ CPIMVCardParserParamArray* paramArray =
+ new(ELeave) CPIMVCardParserParamArray(3);
+ CleanupStack::PushL(paramArray);
+
+ TPtrC8 propertyName; // mapped from field identifier
+
+ switch (aField)
+ {
+ case EPIMContactEmail:
+ {
+ propertyName.Set(KVersitTokenEMAIL);
+ AddParamHomeAndWorkL(attributes, *paramArray);
+ // Contacts Model and PIM support PREF attribute, how ever
+ // vCard specification does not. Thus we don't add it.
+ break;
+ }
+ case EPIMContactNote:
+ {
+ propertyName.Set(KVersitTokenNOTE);
+ break;
+ }
+ case EPIMContactTel:
+ {
+ propertyName.Set(KVersitTokenTEL);
+ if ((attributes & EPIMContactAttrFax) != 0)
+ {
+ AddParserParameterL(*paramArray, KVersitParam8Fax());
+ }
+ if ((attributes & EPIMContactAttrMobile) != 0)
+ {
+ AddParserParameterL(*paramArray, KVersitParam8Cell());
+ }
+ if ((attributes & EPIMContactAttrPager) != 0)
+ {
+ AddParserParameterL(*paramArray, KVersitParam8Pager());
+ }
+ if ((attributes & (EPIMContactAttrPager | EPIMContactAttrFax
+ | EPIMContactAttrSms | EPIMContactAttrAuto
+ | EPIMContactAttrExtVideoCall)) == 0)
+ {
+ AddParserParameterL(*paramArray, KVersitParam8Voice());
+ }
+ if ((attributes & (EPIMContactAttrPreferred)) != 0)
+ {
+ AddParserParameterL(*paramArray, KVersitParam8Pref());
+ }
+ if ((attributes & EPIMContactAttrAuto) != 0)
+ {
+ AddParserParameterL(*paramArray, KVersitParam8Car());
+ }
+ if ((attributes & EPIMContactAttrExtVideoCall) != 0)
+ {
+ AddParserParameterL(*paramArray, KVersitParam8Video());
+ }
+ // Contacts Model and PIM support SMS attribute, how ever
+ // vCard specification does not. Thus we ignore it.
+ // ATTR_OTHER is also ingored because Contacts Model doesn't
+ // provide anything where we could map ATTR_OTHER
+
+ // Add HOME or WORK after all other attributes
+ AddParamHomeAndWorkL(attributes, *paramArray);
+ break;
+ }
+ case EPIMContactTitle:
+ {
+ propertyName.Set(KVersitTokenTITLE);
+ break;
+ }
+ case EPIMContactUrl:
+ {
+ propertyName.Set(KVersitTokenURL);
+ AddParamHomeAndWorkL(attributes, *paramArray);
+ break;
+ }
+ case EPIMContactNickname:
+ {
+ propertyName.Set(KPIMVersitTokenNICKNAME);
+ break;
+ }
+ case EPIMContactExtDtmf:
+ {
+ propertyName.Set(KPIMVersitTokenDTMF);
+ break;
+ }
+ case EPIMContactExtWvUserId:
+ {
+ propertyName.Set(KPIMVersitTokenWVID);
+ break;
+ }
+ case EPIMContactExtSpouse:
+ {
+ propertyName.Set(KVersitTokenSpouse);
+ break;
+ }
+ case EPIMContactExtChildren:
+ {
+ propertyName.Set(KVersitTokenChildren);
+ break;
+ }
+ case EPIMContactExtAssistantName:
+ {
+ propertyName.Set(KVersitTokenAssistant);
+ break;
+ }
+ case EPIMContactExtVoip:
+ case EPIMContactExtSip:
+ case EPIMContactExtPTT:
+ case EPIMContactExtSWIS:
+ {
+ TPtrC8 paramName;
+ propertyName.Set(KPIMVersitTokenSIP);
+ // VOIP is mapped to a subfield of X-SIP
+ if (aField == EPIMContactExtVoip)
+ {
+ paramName.Set(KPIMVersitTokenVoip);
+ }
+ // PTT is mapped to a subfield of X-SIP
+ else if (aField == EPIMContactExtPTT)
+ {
+ paramName.Set(KPIMVersitTokenPoc);
+ }
+ // SWIS is mapped to a subfield of X-SIP
+ else if (aField == EPIMContactExtSWIS)
+ {
+ paramName.Set(KPIMVersitTokenSwis);
+ }
+ if (aField != EPIMContactExtSip)
+ {
+ AddParserParameterL(*paramArray, paramName);
+ }
+
+ AddParamHomeAndWorkL(attributes, *paramArray);
+ // Contacts Model and PIM support PREF attribute, how ever
+ // vCard specification does not. Thus we don't add it.
+ break;
+ }
+ case EPIMContactUid:
+ {
+ propertyName.Set(KVersitTokenUID);
+ break;
+ }
+ default:
+ {
+ User::Panic(KPIMPanicCategory, EPIMPanicUnsupportedStringField);
+ }
+ }
+
+ const TDesC& pimStringValue = aItem.GetStringL(aField, aIndex);
+
+ CParserPropertyValue* propertyValue = CParserPropertyValueHBufC::NewL(
+ pimStringValue);
+ AddPropertyToParserL(propertyValue, propertyName, paramArray, aParser);
+ // The paramArray and propertyValue are popped by the previous function call
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::AddParserParameterL
+// Adds new parser parameter to the parameter array
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::AddParserParameterL(
+ CPIMVCardParserParamArray& aArrayOfParams, const TPtrC8 aParamName)
+{
+ JELOG2(EPim);
+ // Create a new parameter from the name
+ CParserParam* newParam = CParserParam::NewL(aParamName, KNullDesC8);
+ CleanupStack::PushL(newParam);
+ // Add parameter to the param array
+ aArrayOfParams.AppendL(newParam);
+ // newParam is now owned by the parameter array
+ CleanupStack::Pop(newParam);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertStringPropertyL
+// Converts a string property from a vCard to a PIM Contact Item
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::ConvertStringPropertyL(
+ const CPIMParserProperty& aProperty, // property to convert
+ CPIMContactItem& aItem) // item to insert the field to
+{
+ JELOG2(EPim);
+ TPIMField field = aProperty.MatchContactField();
+ TPIMAttribute attributes = KPIMAttrNone;
+
+ if (field == KErrNotFound)
+ {
+ return;
+ }
+
+ CParserPropertyValueHBufC* propertyValue =
+ static_cast<CParserPropertyValueHBufC*>(aProperty.Value());
+ HBufC* value = propertyValue->TakeValueOwnership();
+ CleanupStack::PushL(value);
+
+ switch (field)
+ {
+ case EPIMContactUrl:
+ case EPIMContactEmail:
+ // vCard EMAIL does not support PREF
+ {
+ attributes = aProperty.MatchHomeAndWorkAttributes();
+ break;
+ }
+ case EPIMContactTel:
+ {
+ // Assistant phone is not an attribute in TEL field
+ // it must be handled separately
+ if (aProperty.Name().CompareF(KPIMVersitTokenASSTTEL) == 0)
+ {
+ attributes = EPIMContactAttrAsst;
+ }
+ else
+ {
+ attributes = aProperty.MatchAllAttributes();
+ }
+ break;
+ }
+ case EPIMContactExtVoip:
+ {
+ // VOIP field can have parameters HOME or WORK
+ attributes = aProperty.MatchHomeAndWorkAttributes();
+ break;
+ }
+ default:
+ {
+ // no attributes
+ }
+ }
+ aItem.AddStringL(field, attributes, value);
+ CleanupStack::Pop(value);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertPhotoFieldL
+// Converts a photo field from a PIM Contact Item to a vCard
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::ConvertPhotoFieldL(const CPIMItem& aItem, // item to convert from
+ CParserVCard& aParser, // parser to write to
+ TPIMContactField aField, // field to convert
+ TInt aIndex) // index to the field
+{
+ JELOG2(EPim);
+ const CPIMByteArray& byteArray = aItem.GetBinaryRawL(aField, aIndex);
+
+ const TUint8& byteRef = byteArray.At(0);
+ const TUint8* bytePtr = &byteRef;
+ TPtrC8 data(bytePtr, byteArray.Count());
+
+ CParserPropertyValue* propertyValue =
+ CParserPropertyValueBinary::NewL(data);
+ AddPropertyToParserL(propertyValue, KVersitTokenPHOTO(), NULL, aParser);
+ // The paramArray and propertyValue are popped by the previous function call
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertPhotoPropertyL
+// Converts a photo field from a vCard to a PIM Contact Item
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::ConvertPhotoPropertyL(
+ const CPIMParserProperty& aProperty, // property to convert
+ CPIMContactItem& aItem) // item to insert the field to
+{
+ JELOG2(EPim);
+ if (aProperty.Name().CompareF(KVersitTokenPHOTO) != 0)
+ {
+ // Unsupported binary property, silently discarded
+ return;
+ }
+
+ CParserPropertyValueBinary* propertyValue =
+ static_cast<CParserPropertyValueBinary*>(aProperty.Value());
+ const CBufSeg* value = propertyValue->Value();
+
+ TInt binarySize = value->Size();
+ CPIMByteArray* byteArray = new(ELeave) CPIMByteArray(binarySize);
+ CleanupStack::PushL(byteArray);
+ byteArray->ResizeL(binarySize);
+ TUint8& byteRef = byteArray->At(0);
+ TUint8* bytePtr = &byteRef;
+
+ value->Read(0, static_cast<TAny*>(bytePtr), binarySize);
+
+ aItem.AddBinaryRawL(EPIMContactPhoto, KPIMAttrNone, byteArray);
+ CleanupStack::Pop(byteArray); // byteArray now owned by aItem
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertClassFieldL
+// Converts a CLASS field from a PIM Contact Item to a vCard
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::ConvertClassFieldL(const CPIMItem& aItem,
+ CParserVCard& aParser, TPIMContactField aField, TInt aIndex)
+{
+ JELOG2(EPim);
+ TInt classIntValue = aItem.getInt(aField, aIndex);
+ TPtrC classStringValue(KPIMClassStringConfidential());
+ switch (classIntValue)
+ {
+ case EPIMContactClassConfidential:
+ {
+ classStringValue.Set(KPIMClassStringConfidential());
+ break;
+ }
+ case EPIMContactClassPrivate:
+ {
+ classStringValue.Set(KPIMClassStringPrivate());
+ break;
+ }
+ case EPIMContactClassPublic:
+ {
+ classStringValue.Set(KPIMClassStringPublic());
+ break;
+ }
+ default:
+ {
+ __ASSERT_DEBUG(EFalse, User::Invariant());
+ break;
+ }
+ }
+ CParserPropertyValue* propertyValue = CParserPropertyValueHBufC::NewL(
+ classStringValue);
+ AddPropertyToParserL(propertyValue, KVersitTokenClass(), NULL, aParser);
+ // The paramArray and propertyValue are popped by the previous function call
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertClassPropertyL
+// Converts CLASS property to a PIM Event item.
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::ConvertClassPropertyL(
+ const CPIMParserProperty& aProperty, CPIMContactItem& aItem)
+{
+ JELOG2(EPim);
+ CParserPropertyValueHBufC* propertyValue =
+ static_cast<CParserPropertyValueHBufC*>(aProperty.Value());
+
+ const TPtrC classStringPtr = propertyValue->Value();
+ TInt classInt = KErrCorrupt;
+
+ if (classStringPtr.CompareF(KPIMClassStringPublic) == 0)
+ {
+ classInt = EPIMContactClassPublic;
+ }
+ else if (classStringPtr.CompareF(KPIMClassStringPrivate) == 0)
+ {
+ classInt = EPIMContactClassPrivate;
+ }
+ else if (classStringPtr.CompareF(KPIMClassStringConfidential) == 0)
+ {
+ classInt = EPIMContactClassConfidential;
+ }
+ // else the class value in the originating vCalendar is flawed - ignore
+
+ if (classInt != KErrCorrupt)
+ {
+ aItem.addInt(EPIMContactClass, KPIMAttrNone, classInt);
+ }
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertOrganisationalFieldsL
+// Converts organisational fields from PIM item to CParserVCard
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::ConvertOrganisationalFieldsL(
+ const CPIMItem& aItem, CParserVCard& aParser, TPIMContactField /*aField*/,
+ TInt /*aIndex*/)
+{
+ JELOG2(EPim);
+ // Check that the field is not converted twice (e.g one of the
+ // organisational fields have been already converted and caused
+ // other field to be converted also
+ CArrayPtr<CParserProperty>* props = aParser.ArrayOfProperties(EFalse);
+ if (props)
+ {
+ TInt propCount = props->Count();
+ for (TInt i = 0; i < propCount; i++)
+ {
+ const CParserProperty* property = props->At(i);
+ if (property->Name().CompareF(KVersitTokenORG) == 0)
+ {
+ return;
+ }
+ }
+ }
+
+ // Create array from organisation and department fields
+ CDesCArray* orgArray = new(ELeave) CDesCArrayFlat(2);
+ CleanupStack::PushL(orgArray);
+ if (aItem.CountValuesL(EPIMContactOrg) > 0)
+ {
+ const TDesC& org = aItem.GetStringL(EPIMContactOrg, 0);
+ orgArray->AppendL(org);
+ }
+ else
+ {
+ orgArray->AppendL(KNullDesC);
+ }
+ // Department field is after organisational unit
+ if (aItem.CountValuesL(EPIMContactExtDepartment) > 0)
+ {
+ const TDesC& dep = aItem.GetStringL(EPIMContactExtDepartment, 0);
+ orgArray->AppendL(dep);
+ }
+ else
+ {
+ orgArray->AppendL(KNullDesC);
+ }
+
+ CParserPropertyValue* propertyValue =
+ new(ELeave) CParserPropertyValueCDesCArray(orgArray);
+ CleanupStack::Pop(orgArray); // orgArray now owned by propertyValue
+ AddPropertyToParserL(propertyValue, KVersitTokenORG(), NULL, aParser);
+ // The paramArray and propertyValue are popped by the previous function call
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::ConvertNameReadingFieldL
+// Converts name reading fields from vCard to PIM item
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::ConvertNameReadingFieldL(
+ const CPIMParserProperty& aProperty, CPIMContactItem& aItem)
+{
+ JELOG2(EPim);
+ TInt nameCount = iContactValidator.NumElementsL(EPIMContactName);
+
+ // Name reading fields come in a HBufC property value although they
+ // are in an array property value and SHOULD come in as an array.
+ // So, we have to generate an array property from the HBufC proprety
+ CParserPropertyValueHBufC* propertyValue =
+ static_cast<CParserPropertyValueHBufC*>(aProperty.Value());
+ HBufC* value = propertyValue->TakeValueOwnership();
+ CleanupStack::PushL(value);
+ // PIM parser to access protected methods
+ CPIMVCardParser* parser = CPIMVCardParser::NewLC();
+ CDesCArray* readingValues = parser->MakePropertyValueCDesCArrayL(
+ value->Des());
+ CleanupStack::PopAndDestroy(2, value); // parser
+ CleanupStack::PushL(readingValues);
+
+ // Array for the new name elements
+ CDesCArray* newNameArray = new(ELeave) CDesCArrayFlat(nameCount);
+ CleanupStack::PushL(newNameArray);
+ // Old elements exist
+ if (aItem.CountValuesL(EPIMContactName) > 0)
+ {
+ const CDesCArray& nameArray = aItem.GetStringArrayL(EPIMContactName, 0);
+ for (TInt i = 0; i < nameCount; i++)
+ {
+ TPtrC element(nameArray.MdcaPoint(i));
+ newNameArray->AppendL(element);
+ }
+ // Add array elements. If the array count is larger than zero
+ // it indicates that at least the Last name reading field is present
+ if (readingValues->Count() > 0)
+ {
+ // Remove old value and add new
+ newNameArray->Delete(EPIMContactExtFamilyNameReading);
+ newNameArray->InsertL(EPIMContactExtFamilyNameReading,
+ readingValues->MdcaPoint(0));
+ }
+ // If the array count is larger than one it indicates that
+ // the First name reading is also present
+ if (readingValues->Count() > 1)
+ {
+ newNameArray->Delete(EPIMContactExtGivenNameReading);
+ newNameArray->InsertL(EPIMContactExtGivenNameReading,
+ readingValues->MdcaPoint(1));
+ }
+
+ // Set new string array for the contact name field
+ aItem.SetStringArrayL(EPIMContactName, 0, KPIMAttrNone, newNameArray);
+ }
+ // No old name array
+ else
+ {
+ // Create a new array and append name reading values to it
+ for (TInt i = 0; i < nameCount; i++)
+ {
+ newNameArray->AppendL(KPIMNullArrayElement);
+ }
+ // Add array elements. If the array count is larger than zero
+ // it indicates that at least the Last name reading field is present
+ if (readingValues->Count() > 0)
+ {
+ // Remove old value and add new
+ newNameArray->Delete(EPIMContactExtFamilyNameReading);
+ newNameArray->InsertL(EPIMContactExtFamilyNameReading,
+ readingValues->MdcaPoint(0));
+ }
+ // If the array count is larger than one it indicates that
+ // the First name reading is also present
+ if (readingValues->Count() > 1)
+ {
+ newNameArray->Delete(EPIMContactExtGivenNameReading);
+ newNameArray->InsertL(EPIMContactExtGivenNameReading,
+ readingValues->MdcaPoint(1));
+ }
+ // Add new string array for the cotnact name field
+ aItem.AddStringArrayL(EPIMContactName, KPIMAttrNone, newNameArray);
+ }
+
+ CleanupStack::Pop(newNameArray);
+ CleanupStack::PopAndDestroy(readingValues);
+}
+
+// -----------------------------------------------------------------------------
+// CPIMCardPropertyConverter::AddPropertyToParserL
+// adds a new property value to the parser. NOTE that the property value
+// -----------------------------------------------------------------------------
+//
+void CPIMCardPropertyConverter::AddPropertyToParserL(
+ CParserPropertyValue* aPropertyValue, const TDesC8& aPropertyName,
+ CPIMVCardParserParamArray* aArrayOfParams, CParserVCard& aParser)
+{
+ JELOG2(EPim);
+ // Add property value to the cleanup stack. It should not be added
+ // before this call. This function is an exception and reduces much code
+ CleanupStack::PushL(aPropertyValue);
+ // Create a new parser property from the property value, its name and
+ // array of parameters. If there are no parameters, the aArrayOfParams
+ // should be NULL and the parser property will be generated without params
+ CParserProperty* property = CParserProperty::NewL(*aPropertyValue,
+ aPropertyName, aArrayOfParams);
+ // property takes ownership of the property value
+ CleanupStack::Pop(aPropertyValue);
+ // Pop aArrayOfParams if it is not NULL
+ if (aArrayOfParams)
+ {
+ CleanupStack::Pop(aArrayOfParams);
+ }
+ // NOTE: property MUST not be pushed to the cleanup stack since the
+ // AddPropertyL pushes it right away to the cleanup stack. So, we must not
+ // push it here to avoid duplicate stack pointers
+ aParser.AddPropertyL(property);
+ // Property is now owned by the parser but we do not have to pop it
+}
+
+// End of file