diff -r e8e63152f320 -r 2a9601315dfc javaextensions/pim/versit/src.s60/cpimcardpropertyconverter.cpp --- /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 +#include // parameter literals +#include +#include + +// ============================ 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(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(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(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(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(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(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(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(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* 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(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