pimprotocols/phonebooksync/Server/SyncContactICCEntry.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 27 May 2010 12:45:19 +0300
changeset 37 fd64c38c277d
parent 0 e686773b3f54
permissions -rw-r--r--
Revision: 201019 Kit: 2010121

// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
// Implementation of the Phonebook Synchroniser internal ICC Entry
// representation class.
// 
//

/**
 @file
 @internalComponent
*/

#include "Phonebook.h"
#include "PhonebookManager.h"
#include "SyncContactICCEntry.h"
#include "phbksync.h"
#include "phbksyncsvr.h"
#include "phbksyncsess.h"
#include "phbksynclog.h"
#include "common.h"


/**
 *  Granularity of the arrays.
 */
const TInt KSyncArrayGranularity = 4;


/**
 *  Utility function to panic the server if needed.
 *
 *  @param aPanicCode  Phonebook Synchroniser Fault type 
 */
GLDEF_C void PhBkSyncPanic(TPhBkSyncPanic aPanicCode)
	{
	LOGCOMMON2(_L8("PhBkSync Fault %d"), aPanicCode);
	User::Panic(_L("PhBkSync Fault"), aPanicCode);
	} // PhBkSyncPanic


/**
 *  Factory method to create a CSyncContactICCEntry object.
 *
 *  @return Pointer to a new CSyncContactICCEntry object.
 */
CSyncContactICCEntry* CSyncContactICCEntry::NewL()
	{
	CSyncContactICCEntry*  ptr = new (ELeave) CSyncContactICCEntry();
	CleanupStack::PushL(ptr);
	ptr->ConstructL();
	CleanupStack::Pop(ptr);

	return ptr;
	} // CSyncContactICCEntry::NewL


/**
 *  Standard constructor.
 */
CSyncContactICCEntry::CSyncContactICCEntry()
  : iSlotNum(0),
    iTON(RMobilePhone::EUnknownNumber),
    iContactId(KNullContactId),
    iPhonebookUid(KUidIccGlobalAdnPhonebook),
    iIsHidden(EFalse),
    iTemplateId(KNullContactId)
	{
	// NOP
	} // CSyncContactICCEntry::CSyncContactICCEntry


/**
 *  Second phase constructor.
 */
void CSyncContactICCEntry::ConstructL()
	{
	iNumberList = new (ELeave) CArrayFixFlat<TSyncAdditionalNumber>(KSyncArrayGranularity);
	iGroupList = new (ELeave) CArrayFixFlat<TSyncEntryName>(KSyncArrayGranularity);
	iEmailList = new (ELeave) CArrayFixFlat<TSyncEntryName>(KSyncArrayGranularity);
	} //CSyncContactICCEntry::ConstructL


/**
 *  Standard destructor.
 */
CSyncContactICCEntry::~CSyncContactICCEntry()
	{
	delete iNumberList;
	delete iGroupList;
	delete iEmailList;
	} // CSyncContactICCEntry::~CSyncContactICCEntry


/**
 *  This method stores the streamed contents of the object into a CBufBase
 *  buffer.
 *
 *  @return Pointer to the allocated CBufFlat.
 */
CBufBase* CSyncContactICCEntry::StoreL()
	{
	CBufBase* buf=CBufFlat::NewL(KSyncArrayGranularity);
	CleanupStack::PushL(buf);

	RBufWriteStream  strm(*buf);
	strm << *this;
	strm.CommitL();
	CleanupStack::Pop(buf);

	return buf;
	} // CSyncContactICCEntry::StoreL


/**
 *  This method stores the streamed contents of the oject into a
 *  descriptor.
 *
 *  @param aDes  Descriptor in which to store the object.
 */
void CSyncContactICCEntry::StoreL(TDes8& aDes)
	{
	RDesWriteStream  strm(aDes);
	strm << *this;
	strm.CommitL();
	} // CSyncContactICCEntry::StoreL


/**
 *  This method retrieves the contents of a CSyncContactICCEntry from a
 *  descriptor.
 *
 * @param aBuf  Descriptor from which to read the CSyncContactICCEntry.
 */
void CSyncContactICCEntry::RestoreL(const TDesC8& aBuf)
	{
	RDesReadStream  strm(aBuf);
	strm >> *this;
	} // CSyncContactICCEntry::RestoreL


/**
 *  This method internalises the contents of a CSyncContactICCEntry from
 *  a stream.
 *
 *  @param aStream  The read stream containing a CSyncContactICCEntry.
 */
void CSyncContactICCEntry::InternalizeL(RReadStream& aStream)
	{
	aStream >> iName;
	aStream >> iSecondName;
	aStream >> iNumber;
	TInt count(aStream.ReadInt32L());	// list of additional numbers 
	TInt i(0);
	for(i=0; i<count; ++i)
		{
		TSyncAdditionalNumber addNumber;
		aStream >> addNumber;
		iNumberList->AppendL(addNumber);
		}
	count = aStream.ReadInt32L();		// group list
	for(i=0; i<count; ++i)
		{
		TSyncEntryName group;
		aStream >> group;
		iGroupList->AppendL(group);
		}
	count = aStream.ReadInt32L();		// email list
	for(i=0; i<count; ++i)
		{
		TSyncEntryName email;
		aStream >> email;
		iEmailList->AppendL(email);
		}
	iSlotNum = aStream.ReadInt32L();
	iTON = static_cast<RMobilePhone::TMobileTON>(aStream.ReadUint32L());
	iContactId = aStream.ReadInt32L();
	iPhonebookUid = TUid::Uid(aStream.ReadInt32L());
	iIsHidden = static_cast<TBool>(aStream.ReadInt32L());
	iTemplateId = aStream.ReadInt32L();
	} // CSyncContactICCEntry::InternalizeL


/**
 *  This method externalizes the contents of a CSyncContactICCEntry into
 *  a stream.
 *
 *  @param aStream  The write stream that will contain a CSyncContactICCEntry.
 */
void CSyncContactICCEntry::ExternalizeL(RWriteStream& aStream) const
	{
	aStream << iName;
	aStream << iSecondName;
	aStream << iNumber;
	TInt count(iNumberList->Count());	// list of additional numbers
	TInt i(0);
	aStream.WriteInt32L(count);
	for(i=0; i<count; ++i)
		aStream << iNumberList->At(i);
	count = iGroupList->Count();		// group list
	aStream.WriteInt32L(count);
	for(i=0; i<count; ++i)
		aStream << iGroupList->At(i);
	count = iEmailList->Count();		// email list
	aStream.WriteInt32L(count);
	for(i=0; i<count; ++i)
		aStream << iEmailList->At(i);
	aStream.WriteInt32L(iSlotNum); 
	aStream.WriteUint32L(iTON);
	aStream.WriteInt32L(iContactId);
	aStream.WriteInt32L(iPhonebookUid.iUid);
	aStream.WriteInt32L(iIsHidden);
	aStream.WriteInt32L(iTemplateId);
	} // CSyncContactICCEntry::ExternalizeL


/**
 *  Initialise the class members from data taken from a CContactICCEntry.
 *
 *  @param aContactItem  Contacts ICC entry 
 *
 *  @return TInt KErrNotSupported if a non-supported field supplied in field set, KErrOverflow for an overflow, 
 *          othewise KErrNone
 */
void CSyncContactICCEntry::InitialiseFromContactICCEntryL(const CContactICCEntry& aContactItem)
	{
	//
	// Clear the fields to start with...
	//
	Reset();

	TInt retrievedFields(0); // Number of fields retrieved from aContactItem field set 
	iContactId = aContactItem.Id(); // get Contact UID
	CContactItemFieldSet& fieldSet = aContactItem.CardFields();

	TInt index(0), firstPhoneNumIndex(0);
	// get default phone number field from aContacItem
	firstPhoneNumIndex = fieldSet.Find(KUidContactFieldPhoneNumber);
	if(firstPhoneNumIndex != KErrNotFound)
		{
		++retrievedFields;
		const CContactItemField& field = fieldSet[firstPhoneNumIndex];
		if(field.TextStorage()->Text().Length() > RMobilePhone::KMaxMobileTelNumberSize)
			{
			User::Leave(KErrOverflow);
			}

		TPtrC number(field.TextStorage()->Text());
		iNumber.Copy(number);

		//
		// Set the TON/NPI for that number as International if the number contains
		// the '+' prefix, otherwise set it to unknown.
		//
		if (TLex(iNumber).Get() == '+')
			{
			iTON = RMobilePhone::EInternationalNumber;
			}
		else
			{
			iTON = RMobilePhone::EUnknownNumber;
			}

		// Check whether this entry is hidden 
		if(const_cast<CContactICCEntry&>(aContactItem).IsHidden())
			iIsHidden = ETrue;

		// Retrieve family name
		if((index = fieldSet.Find(KUidContactFieldFamilyName)) != KErrNotFound)
			{
			++retrievedFields;
			// get given name field from aContactItem
			if(field.TextStorage()->Text().Length() > CSyncContactICCEntry::KMaxPhBkNameSize)
				{
				User::Leave(KErrOverflow);
				}
			iName.Copy(fieldSet[index].TextStorage()->Text());
			} // name is not a compulsory field, so do not return an error if not found

		// retrieve second name
		if((index = fieldSet.Find(KUidContactFieldSecondName)) != KErrNotFound)
			{
			++retrievedFields;
			// get given name field from aContactItem
			if(field.TextStorage()->Text().Length() > CSyncContactICCEntry::KMaxPhBkNameSize)
				{
				User::Leave(KErrOverflow);
				}
			iSecondName.Copy(fieldSet[index].TextStorage()->Text());
			} // name is not a compulsory field, so do not return an error if not found

		// get slot number field from aContactItem
		index = fieldSet.Find(KUidContactFieldICCSlot);
		if(index!=KErrNotFound) // index field provided
			{
			++retrievedFields;
			TPtrC tempPtr(NULL,0);
			tempPtr.Set(fieldSet[index].TextStorage()->Text());
			TLex lex(tempPtr);
			TInt slot;
			TInt ret(lex.Val(slot));
			if (ret == KErrNone) // index field value supplied 
				{
				iSlotNum = slot;
				}
			else
				iSlotNum = KSyncIndexNotSupplied; // index field provided as template field, so no actual values supplied
			}
		else
			{
			// all fields supplied but slot field not found so it must be a new entry
			iSlotNum = KSyncIndexNotSupplied; // Set index to KSyncIndexNotSupplied
			}

		// handle the a phonebook UID field if present (it should always be as it is in the template)...
		index = fieldSet.Find(KUidContactFieldICCPhonebook);
		if(index!=KErrNotFound) // index field provided
			{
			++retrievedFields;
			TPtrC tempPtr(NULL,0);
			tempPtr.Set(fieldSet[index].TextStorage()->Text());
			TLex lex(tempPtr);
			TInt phonebook;
			TInt ret(lex.Val(phonebook));
			if (ret == KErrNone) // index field value supplied 
				{
				iPhonebookUid.iUid = phonebook;
				}
			else
				{
				iPhonebookUid = KUidIccGlobalAdnPhonebook;
				}
			}
		else
			{
			iPhonebookUid = KUidIccGlobalAdnPhonebook;
			}

		// now get list of additional phone numbers from CContactICCEntry 		
		index = firstPhoneNumIndex;  // skip the default phone number which has been read in early
		while((index = fieldSet.FindNext(KUidContactFieldPhoneNumber,index+1)) != KErrNotFound)
			{
			// get additional phone number field from aContacItem
			++retrievedFields;
			const CContactItemField& field = fieldSet[index];
			if(field.TextStorage()->Text().Length() > RMobilePhone::KMaxMobileTelNumberSize)
				{
				User::Leave(KErrOverflow);
				}

			TPtrC number(field.TextStorage()->Text());
			CSyncContactICCEntry::TSyncAdditionalNumber addNumber;
			addNumber.iNumber.Copy(number);

			//
			// Set the TON/NPI for that number as International if the number contains
			// the '+' prefix, otherwise set it to unknown.
			//
			if (TLex(addNumber.iNumber).Get() == '+')
				{
				addNumber.iTON = RMobilePhone::EInternationalNumber;
				}
			else
				{
				addNumber.iTON = RMobilePhone::EUnknownNumber;
				}

            //-- assign alpha string to the additional number according to additional field types
			const CContentType&  cntType = field.ContentType();
		    
		    //
		    // Assume HOME by default. Please note that this will be used as default 
		    // value if something other than HOME or WORK is supplied.
		    //
			if (cntType.ContainsFieldType(KUidContactFieldVCardMapWORK)) 
				{
				addNumber.iNumberString.Append(KVersitParamWork);
				}
			else
				{
				addNumber.iNumberString.Append(KVersitParamHome);
				}

		    //
		    // Try to locate other tags (FAX, CELL, etc)...
			//
			if (cntType.ContainsFieldType(KUidContactFieldVCardMapMSG))
				{
				addNumber.iNumberString.Append(KVersitParamMsg);
				}
			else if (cntType.ContainsFieldType(KUidContactFieldVCardMapVOICE))
				{
				addNumber.iNumberString.Append(KVersitParamVoice);
				}
			else if (cntType.ContainsFieldType(KUidContactFieldVCardMapFAX))
				{
				addNumber.iNumberString.Append(KVersitParamFax);
				}
			else if (cntType.ContainsFieldType(KUidContactFieldVCardMapPREF))
				{
				addNumber.iNumberString.Append(KVersitParamPref);
				}
			else if (cntType.ContainsFieldType(KUidContactFieldVCardMapCELL))
				{
				addNumber.iNumberString.Append(KVersitParamCell);
				}
			else if (cntType.ContainsFieldType(KUidContactFieldVCardMapPAGER))
				{
				addNumber.iNumberString.Append(KVersitParamPager);
				}
			else if (cntType.ContainsFieldType(KUidContactFieldVCardMapBBS))
				{
				addNumber.iNumberString.Append(KVersitParamBbs);
				}
			else if (cntType.ContainsFieldType(KUidContactFieldVCardMapMODEM))
				{
				addNumber.iNumberString.Append(KVersitParamModem);
				}
			else if (cntType.ContainsFieldType(KUidContactFieldVCardMapCAR))
				{
				addNumber.iNumberString.Append(KVersitParamCar);
				}
			else if (cntType.ContainsFieldType(KUidContactFieldVCardMapISDN))
				{
				addNumber.iNumberString.Append(KVersitParamIsdn);
				}
			else if (cntType.ContainsFieldType(KUidContactFieldVCardMapVIDEO))
				{
				addNumber.iNumberString.Append(KVersitParamVideo);
				}

			// finally append additional number to additional number list
			iNumberList->AppendL(addNumber);
			}

		// get all e-mail fields 
		index = -1;
		while((index = fieldSet.FindNext(KUidContactFieldEMail,index+1)) != KErrNotFound)
			{
			++retrievedFields;
			// get e-mail field from aContactItem
			if(field.TextStorage()->Text().Length() > CSyncContactICCEntry::KMaxPhBkNameSize)
				{
				User::Leave(KErrOverflow);
				}

			CSyncContactICCEntry::TSyncEntryName name;
			name.Copy(fieldSet[index].TextStorage()->Text());
			iEmailList->AppendL(name);
			} // e-mail is not a compulsory field, so do not return an error if not found

		// get all groups that this entry belongs to 
		index = -1; // following was originally commented out (JJ)	
		while((index = fieldSet.FindNext(KUidContactFieldICCGroup, index+1)) != KErrNotFound)
			{
			++retrievedFields;
			// get group field from aContactItem
			if(field.TextStorage()->Text().Length() > CSyncContactICCEntry::KMaxPhBkNameSize)
				{
				User::Leave(KErrOverflow);
				}

			CSyncContactICCEntry::TSyncEntryName name;
			name.Copy(fieldSet[index].TextStorage()->Text());
			iGroupList->AppendL(name);
			} // group is not a compulsory field, so do not return an error if not foun

		// For new entries phonebook type is not supplied, so always extract Template ID
		iTemplateId = aContactItem.TemplateRefId();
		}			

	//
	// Check that all expected fields were retrieved...
	//
	if (fieldSet.Count() != retrievedFields)
		{
#ifdef _DEBUG
		//
		// At least one field has was not supported. Log all the field types!
		//
		LOGCOMMON1(_L8("CSyncContactICCEntry: Unsupported field found!"));
		for (TInt field = 0;  field < fieldSet.Count();  field++)
			{
			LOGCOMMON2(_L8("CSyncContactICCEntry:   Field[%d]:"), field);
			for (TInt type = 0;  type < fieldSet[field].ContentType().FieldTypeCount();  type++)
				{
				LOGCOMMON3(_L8("CSyncContactICCEntry:     Type[%d]=0x%08x"), type,
				           fieldSet[field].ContentType().FieldType(type));
				}
			}
#endif

		User::Leave(KErrNotSupported);
		}
	} // CSyncContactICCEntry::InitialiseFromContactICCEntryL




/**
 *  This method resets all attributes.
 */
void CSyncContactICCEntry::Reset()
	{
	// reset all variables
	iSlotNum      = 0; 
	iTON          = RMobilePhone::EUnknownNumber;
	iContactId    = KNullContactId;
	iPhonebookUid = KUidIccGlobalAdnPhonebook; 
	iIsHidden     = EFalse; 
	iTemplateId   = KNullContactId;
	iName.Zero();
	iSecondName.Zero();
	iNumber.Zero();

	// reset all lists
	iNumberList->Reset();
	iGroupList->Reset();	
	iEmailList->Reset();
	} // CSyncContactICCEntry::Reset


#ifdef _DEBUG
/**
 *  Logs the contact entry for debugging purposes.
 */
void CSyncContactICCEntry::LogSyncContactICCEntry() const
	{
	//
	// Log the basic fields...
	//
	TBuf8<KMaxPhBkNameSize>  fieldIn8bit;
	TBuf8<RMobilePhone::KMaxMobileTelNumberSize>  numberIn8bit;

	fieldIn8bit.Copy(iName);
	LOGCOMMON2(_L8("ICCEntry: Name=\"%S\""), &fieldIn8bit);

	fieldIn8bit.Copy(iSecondName);
	LOGCOMMON2(_L8("ICCEntry: Second Name=\"%S\""), &fieldIn8bit);

	numberIn8bit.Copy(iNumber);
	LOGCOMMON2(_L8("ICCEntry: Number=\"%S\""), &numberIn8bit);

	LOGCOMMON2(_L8("ICCEntry: SlotNum=%d"), iSlotNum);

	LOGCOMMON2(_L8("ICCEntry: TypeOfNum=%d"), iTON);

	LOGCOMMON2(_L8("ICCEntry: ContactID=0x%08x"), iContactId);

	LOGCOMMON2(_L8("ICCEntry: PhonebookUID=0x%08x"), iPhonebookUid.iUid);

	LOGCOMMON2(_L8("ICCEntry: IsHidden=%d"), iIsHidden);

	LOGCOMMON2(_L8("ICCEntry: TemplateId=%d"), iTemplateId);

	//
	// Log the number list...
	//
	TInt  listCount(iNumberList->Count());
	TInt  index;

	for (index = 0;  index < listCount;  index++)
		{
		numberIn8bit.Copy(iNumberList->At(index).iNumber);
		fieldIn8bit.Copy(iNumberList->At(index).iNumberString);
		LOGCOMMON4(_L8("ICCEntry: NumberList[%d] \"%S\" \"%S\""),
				   index, &numberIn8bit, &fieldIn8bit);
		}

	//
	// Log the group list...
	//
	listCount = iGroupList->Count();

	for (index = 0;  index < listCount;  index++)
		{
		fieldIn8bit.Copy(iGroupList->At(index));
		LOGCOMMON3(_L8("ICCEntry: GroupList[%d]=\"%S\""), index, &fieldIn8bit);
		}

	//
	// Log the email list...
	//
	listCount = iEmailList->Count();

	for (index = 0;  index < listCount;  index++)
		{
		fieldIn8bit.Copy(iEmailList->At(index));
		LOGCOMMON3(_L8("ICCEntry: EmailList[%d]=\"%S\""), index, &fieldIn8bit);
		}
	} // CSyncContactICCEntry::LogSyncContactICCEntry
#endif


/**
 *  This method internalizes the contents of TSyncAdditionalNumber from
 *  a stream.
 *
 *  @param aStream  The read stream containing TSyncAdditionalNumber.
 */
void CSyncContactICCEntry::TSyncAdditionalNumber::InternalizeL(RReadStream& aStream)
	{
	aStream >> iNumber;
	aStream >> iNumberString;
	iTON = static_cast<RMobilePhone::TMobileTON>(aStream.ReadUint32L());
	} // CSyncContactICCEntry::TSyncAdditionalNumber::InternalizeL


/**
 *  This method externalizes the contents of TSyncAdditionalNumber into
 *  a stream.
 *
 *  @param aStream  The write stream that will contain TSyncAdditionalNumber.
 */
void CSyncContactICCEntry::TSyncAdditionalNumber::ExternalizeL(RWriteStream& aStream) const
	{
	aStream << iNumber;
	aStream << iNumberString;
	aStream.WriteUint32L(iTON);
	} // CSyncContactICCEntry::TSyncAdditionalNumber::ExternalizeL


/**
 *  Standard constructor.
 */
TContactFieldFormat::TContactFieldFormat(TInt aLength, TInt aCount,
										 TBool aDisplayed)
  : iLength(aLength),
    iCount(aCount),
    iDisplayed(aDisplayed)
	{
	// NOP
	} // TContactFieldFormat::TContactFieldFormat


/**
 *  The old PhBkSyncServerThread Server Thread. This thread is no longer
 *  supported.
 */
EXPORT_C TInt PhBkSyncServerThread(TAny*)
	{
	return KErrNotSupported;
	} // PhBkSyncServerThread


/**
 *  This method returns the Phonebook Synchroniser API extension number
 *  of the class.
 *
 *  @return An integer that will indicate the version of the type.
 */
EXPORT_C TInt RPhoneBookSession::TContactFieldsV1::ExtensionId() const
	{
	return iExtensionId;
	} // RPhoneBookSession::TContactFieldsV1::ExtensionId()


/**
 *  Standard constructor.
 */
EXPORT_C RPhoneBookSession::TContactFieldsV1::TContactFieldsV1()
  : iNameField(0, 0, EFalse),
    iNumberField(0,0,EFalse),
    iIccSlotField(0,0,EFalse), 
    iExtensionId(KPhBkSyncTContactFieldsV1)
	{
	// NOP
	} // RPhoneBookSession::TContactFieldsV1::TContactFieldsV1


/**
 *  Standard constructor.
 */
EXPORT_C RPhoneBookSession::TContactFieldsV2::TContactFieldsV2()
  : TContactFieldsV1(),
    iAdditionalNumString(0, 0, EFalse),
    iGroupField(0,0,EFalse), 
    iEmailField(0,0,EFalse),
    iPhonebook(KUidIccGlobalAdnPhonebook)
	{
	iExtensionId = KPhBkSyncTContactFieldsV2;
	} // RPhoneBookSession::TContactFieldsV2::TContactFieldsV2()


/**
 *  Standard constructor.
 */
EXPORT_C RPhoneBookSession::TContactFieldsV3::TContactFieldsV3()
  : TContactFieldsV2(),
    iAdditionalNumAlphaString(0, 0, EFalse),
    iSecondNameField(0,0,EFalse)
	{
	iExtensionId = KPhBkSyncTContactFieldsV3;
	} // RPhoneBookSession::TContactFieldsV3::TContactFieldsV3()