pimprotocols/pbap/server/pbapvcardexporterutil.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 14 Sep 2010 20:54:53 +0300
branchRCL_3
changeset 21 9da50d567e3c
parent 20 f4a778e096c2
permissions -rw-r--r--
Revision: 201033 Kit: 201035

// Copyright (c) 2006-2010 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:
// pbapvcardexporterimpl.cpp
// 
//

#include "pbapvcardexporterutil.h"

#include <cntitem.h>
#include <s32strm.h>
#include <vprop.h>
#include <vcard.h>
#include <centralrepository.h>

#ifdef SYMBIAN_ENABLE_SPLIT_HEADERS
#include "vcard3.h"
#include "cntdb_internal.h"
#endif
#include <vtoken.h>
#include "pbaplogeng.h"
#include "btaccesshostlog.h"

/* These constants are properly defined in telconfigcrkeys.h, however we 
are not allowed to include that from here.  As a temporary fix the constants 
from that file are re-defined here. */
const TUid KCRUidTelConfiguration = {0x102828B8};
const TUint32 KTelMatchDigits = 0x00000001;
/* And similarly this constant is defined in ccsdefs.h */
const TInt KDefaultGsmNumberMatchLength = 7;

//constants
_LIT8(KVersitTokenCALLDATETIME,"X-IRMC-CALL-DATETIME");
_LIT8(KVersitParamMISSED,"MISSED");
_LIT8(KVersitParamRECEIVED,"RECEIVED");
_LIT8(KVersitParamDIALED,"DIALED");	// US English spelling to conform with spec


/*static*/ CPbapVCardExporterUtil* CPbapVCardExporterUtil::NewL(CContactDatabase& aDatabase, 
																CPbapLogWrapper* aLogWrapper)
	{
	LOG_STATIC_FUNC
	CPbapVCardExporterUtil* self = new(ELeave) CPbapVCardExporterUtil(aDatabase, aLogWrapper);
	CleanupStack::PushL(self);
	self->ConstructL();
	CleanupStack::Pop(self);
	return self;
	}

CPbapVCardExporterUtil::CPbapVCardExporterUtil(CContactDatabase& aDatabase, CPbapLogWrapper* aLogWrapper)
: iDatabase(aDatabase), iLogWrapper(aLogWrapper)
	{
	LOG_FUNC
	}

void CPbapVCardExporterUtil::ConstructL()
	{
	LOG_FUNC
	CVersitTlsData::VersitTlsDataL();		
	User::LeaveIfError(iTzClient.Connect());
	
	// Read the amount of digits to be used in contact matching
	// The key is properly owned by PhoneApp, however we cannot include
	// that header file from here, so a temporary fix has been done to 
	// use locally defined versions.  If there is a problem here it is 
	// likely because these values have gone out of sync.
	CRepository* repository = CRepository::NewLC(KCRUidTelConfiguration);
    if ( repository->Get(KTelMatchDigits, iMatchDigitCount) == KErrNone )
        {
        // Min is 7
        iMatchDigitCount = Max(iMatchDigitCount, KDefaultGsmNumberMatchLength);
        }
    else
        {
        iMatchDigitCount = KDefaultGsmNumberMatchLength;
        }
	CleanupStack::PopAndDestroy(repository);
	}

CPbapVCardExporterUtil::~CPbapVCardExporterUtil()
	{
	LOG_FUNC
	iTzClient.Close();
	CVersitTlsData::CloseVersitTlsData();
	}
	
/**
 Export a contact as vCard.

 @param aContactId Contact item ID to export. If this value is set to KNullContactId an empty vCard
       containing only the mandatory properties defined in the PBAP specification will be exported
 @param aWriteStream Stream to externalize vCard data to
 @param aFormat Version of vCard specification 2.1 or 3.0
 @param aFilter Defines properties to be exported
 */
void CPbapVCardExporterUtil::ExportContactL(TContactItemId aContactId, 
											RWriteStream& aWriteStream,
											TVCardVersion aFormat, 
											TUint64 aFilter)
	{
	LOG_FUNC
	CContactIdArray* contactIdArray = CContactIdArray::NewLC();
	contactIdArray->AddL(aContactId);
	iDatabase.ExportSelectedContactsL(TUid::Uid(KUidPBAPVCardConvImpl), *contactIdArray, aWriteStream, 
										0, aFilter, NULL, aFormat, ETrue);
	CleanupStack::PopAndDestroy(contactIdArray);
	}


/**
 Export log engine event as a vCard.

 @param aEvent Log engine event to be exported
 @param aWriteStream Stream to externalize vCard data to
 @param aFormat Version of vCard specification 2.1 or 3.0
 @param aFilter Defines properties to be exported
 */
void CPbapVCardExporterUtil::ExportCallHistoryL(const CLogEvent& aLogEvent, 
												RWriteStream& aWriteStream,
												TVCardVersion aFormat, 
												TUint64 aFilter)
	{
	LOG_FUNC
	TContactItemId contactId = aLogEvent.Contact();	
	
	if (contactId == KNullContactId && aLogEvent.RemoteParty() != KNullDesC)
		{
		// The S60 phonebook uses the remote party for the name, so if there isn't a name
		// there won't be a contact, so we only look up the contact if there is a Remote Party
		contactId = FindContactIdFromNumberL(aLogEvent.Number());
		}
	
	if (ContactExistsL(contactId))
		{
		// store the log event, format and filter parameters to use in the callback
		// from the contacts vCard converter
		iLogEvent = &aLogEvent;
		iLogEventContactId = contactId;
		iFormat = aFormat;
		iFilter = aFilter;
	
		CContactIdArray* contactIdArray = CContactIdArray::NewLC();
		contactIdArray->AddL(contactId);
		iDatabase.ExportSelectedContactsL(TUid::Uid(KUidPBAPVCardConvImpl), *contactIdArray, aWriteStream, 0, aFilter, this, aFormat, EFalse);
		CleanupStack::PopAndDestroy(contactIdArray);
		}
	else
		{
		//no associated contact so only export properties which map to log entry fields
		CParserVCard* vCard = CreateVCardParserLC(aFormat);
		vCard->SetDefaultCharSet(Versit::EUTF8CharSet);

		// N property mandated by vCard 2.1 and 3.0 specifications
		vCard->AddPropertyL(EmptyNamePropertyL());
		
		// FN property mandated by vCard 3.0 specification
		if (aFormat==EPBAPVCard30)
			{
			//add empty FN property
			vCard->AddPropertyL(DesPropertyL(KVersitTokenFN, KNullDesC));
			}

		// add mandatory TEL property using number from call log
		vCard->AddPropertyL(DesPropertyL(KVersitTokenTEL, aLogEvent.Number()));

		// add the X-IRMC-CALL-DATETIME property
		if (aFilter == SymbianPBAP::KPbapAttributeAll || aFilter&SymbianPBAP::KPbapAttributeMaskCallDateTime)
			{
			vCard->AddPropertyL(CallDateTimePropertyL(aLogEvent, aFormat));
			}

		vCard->ExternalizeL(aWriteStream);
		CleanupStack::PopAndDestroy(vCard);
		}
	}

TContactItemId CPbapVCardExporterUtil::FindContactIdFromNumberL(const TDesC& aNumber)
	{
	TContactItemId ret = KNullContactId;
	CContactIdArray* contactIdArray = iDatabase.MatchPhoneNumberL(aNumber, iMatchDigitCount);
	if (contactIdArray->Count() > 0)
		{
		ret = (*contactIdArray)[0];
		}
	delete contactIdArray;
	return ret;
	}

/**
Writes a vCard to the stream containing only the mandatory properties defined in the PBAP specification
with all properties set to empty (null) values
*/
void CPbapVCardExporterUtil::ExportEmptyVCardL(RWriteStream& aWriteStream, TVCardVersion aFormat)
	{
	LOG_FUNC
	CParserVCard* vCard = CreateVCardParserLC(aFormat);
	vCard->SetDefaultCharSet(Versit::EUTF8CharSet);
	
	vCard->AddPropertyL(EmptyNamePropertyL());

	if (aFormat == EPBAPVCard30)
		{
		vCard->AddPropertyL(DesPropertyL(KVersitTokenFN, KNullDesC));
		}

	vCard->AddPropertyL(DesPropertyL(KVersitTokenTEL, KNullDesC));

	vCard->ExternalizeL(aWriteStream);
	CleanupStack::PopAndDestroy(vCard);
	}

/**
PBAP clients are supposed to provide any information regarding the contact item represented by aContactId.
This information should be in form of standard vCard property, all such properties should be appended to the array aPropertyList.
*/
void CPbapVCardExporterUtil::AddIntraContactPropertiesL(const TContactItemId& aContactId, 
														CArrayPtr<CParserProperty>* aPropertyList)
	{
	LOG_FUNC
	if(iLogEvent && iLogEventContactId == aContactId)
		{
		CParserProperty* property;

 		// add mandatory TEL property using number from log event
		property = DesPropertyL(KVersitTokenTEL, iLogEvent->Number());
		CleanupStack::PushL(property);
		aPropertyList->AppendL(property);
		CleanupStack::Pop(property); //ownership passed
		
		// add X-IRMC-CALL-DATETIME property
		if (iFilter == SymbianPBAP::KPbapAttributeAll || iFilter&SymbianPBAP::KPbapAttributeMaskCallDateTime)
			{
			property = CallDateTimePropertyL(*iLogEvent, iFormat);
			CleanupStack::PushL(property);  
			aPropertyList->AppendL(property);
			CleanupStack::Pop(property); //ownership passed
			}
							
		iLogEvent = NULL;
		}		
	}
	
TBool CPbapVCardExporterUtil::ContactExistsL(TContactItemId aContactId)
	{
	LOG_FUNC
	TBool exists = EFalse;
	if (aContactId != KNullContactId)
		{
		CContactItem* contactItem=NULL;
		TRAPD(error, contactItem=iDatabase.ReadMinimalContactL(aContactId));
		if (error==KErrNone)
			{
			if (contactItem && (contactItem->Type()== KUidContactCard || contactItem->Type()== KUidContactOwnCard))
				{
				// the contact item exists in the pb phone book
				exists = ETrue;
				delete contactItem;	
				}
			}
		else if (error != KErrNotFound && error!=KErrNotReady)
			{
			User::Leave(error);			
			}
		}
	return exists;		
	}

CParserVCard* CPbapVCardExporterUtil::CreateVCardParserLC(TVCardVersion aFormat)
	{
	LOG_FUNC
	CParserVCard* parser=NULL;
	switch (aFormat)
		{
		case EPBAPVCard21:
			parser=CParserVCard::NewL(); //create vCard 2.1 parser
			break;
		case EPBAPVCard30:
			parser=CParserVCard3::NewL(); //create vCard 3.0 parser
			break;
		default:
			User::Leave(KErrNotSupported);
			break;
		}
	CleanupStack::PushL(parser);
	
	return parser;
	}

CParserProperty* CPbapVCardExporterUtil::EmptyNamePropertyL()
	{
	LOG_FUNC
	CDesCArrayFlat* desArray =new (ELeave) CDesCArrayFlat(4);
	CleanupStack::PushL(desArray);
	desArray->AppendL(KNullDesC);
	CParserPropertyValue* value = new(ELeave) CParserPropertyValueCDesCArray(desArray);
	CleanupStack::Pop(desArray); //ownership passed
	CleanupStack::PushL(value);
	CParserGroupedProperty* property = CParserGroupedProperty::NewL(*value, KVersitTokenN, NULL, NULL);
	CleanupStack::Pop(value); //ownership passed
	return property;
	}

		
CParserProperty* CPbapVCardExporterUtil::DesPropertyL(const TDesC8& aToken, const TDesC& aDes)
	{
	LOG_FUNC
	CParserPropertyValue* value = CParserPropertyValueHBufC::NewL(aDes);	
	CleanupStack::PushL(value);
	CParserGroupedProperty* property = CParserGroupedProperty::NewL(*value, aToken, NULL, NULL);
	CleanupStack::Pop(value); //ownership passed
	return property;
	}
		
CParserProperty* CPbapVCardExporterUtil::CallDateTimePropertyL(const CLogEvent& aLogEvent, TVCardVersion aFormat)
	{
	LOG_FUNC
	TTime localTime = aLogEvent.Time();
	TVersitDateTime::TRelativeTime relativeTime = TVersitDateTime::EIsUTC;
	if (iTzClient.ConvertToLocalTime(localTime) == KErrNone)
		{
		relativeTime = TVersitDateTime::EIsMachineLocal;
		}

	TVersitDateTime* dateTime= new(ELeave) TVersitDateTime(localTime.DateTime(), relativeTime);
	CleanupStack::PushL(dateTime);
	CParserPropertyValueDateTime* value = new(ELeave) CParserPropertyValueDateTime(dateTime);
	CleanupStack::Pop(dateTime); //ownership passed
	CleanupStack::PushL(value);
	CParserGroupedProperty* property = CParserGroupedProperty::NewL(*value, KVersitTokenCALLDATETIME, NULL, NULL);
	CleanupStack::Pop(value); //ownership passed
	CleanupStack::PushL(property);

	TPtrC8 paramValue(ParameterValueFromEventL(aLogEvent));
	
	if (paramValue.Length())
		{
		CParserParam* param;
		if (aFormat == EPBAPVCard30)
			{
			//nameless parameters not allowed for vCard 3.0, so add "TYPE" parameter name
			param= CParserParam::NewL(KVersitTokenTYPE, paramValue);
			}
		else
			{
			param= CParserParam::NewL(paramValue, KNullDesC);
			}
		CleanupStack::PushL(param);
		property->AddParamL(param);
		CleanupStack::Pop(param); //ownership passed
		}
		
	CleanupStack::Pop(property);
	return property;
	}


TPtrC8 CPbapVCardExporterUtil::ParameterValueFromEventL(const CLogEvent& aLogEvent)
	{
	LOG_FUNC
	if (iLogWrapper)
		{		
		TLogString logString;
		User::LeaveIfError(iLogWrapper->GetString(logString, R_LOG_DIR_MISSED));
		if (aLogEvent.Direction()==logString)
			{
			return KVersitParamMISSED();
			}
		User::LeaveIfError(iLogWrapper->GetString(logString, R_LOG_DIR_IN));
		if (aLogEvent.Direction()==logString)
			{
			return KVersitParamRECEIVED();
			}
		User::LeaveIfError(iLogWrapper->GetString(logString, R_LOG_DIR_OUT));
		if (aLogEvent.Direction()==logString)
			{
			return KVersitParamDIALED();
			}
		}
	//unknown log type, just set parameter value to empty string	
	return KNullDesC8();
	}