pimprotocols/phonebooksync/Server/WriteContactToICC.cpp
changeset 0 e686773b3f54
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pimprotocols/phonebooksync/Server/WriteContactToICC.cpp	Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,548 @@
+// 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:
+// Contains method implementations for the Active Object used to write a
+// Contact to the ICC.
+// 
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include "common.h"
+#include "Phonebook.h"
+#include "PhonebookManager.h"
+#include "SyncContactICCEntry.h"
+#include "phbksynclog.h"
+#include "phbksyncsvr.h"
+#include "SyncEngineSession.h"
+#include "SyncEngineServer.h"
+#include "phbksyncsess.h"
+#include "WriteContactToICC.h"
+
+
+/**
+ *  Static factory method used to create a CWriteContactToICC object.
+ *
+ *  @param aBufferSize        Size of ICC Entry buffer passed in the request.
+ *  @param aSession           Handle to the engine session.
+ *  @param aPhonebookManager  Pointer to the Phonebook Manager which stores all
+ *                            the phonebook parameters.
+ *  @param aPhone             Handle to the phone object.
+ *  @param aPhonebookUid      Phonebook UID for the contact to be deleted from.
+ *  @param aClientMessage     Handle to the engine message request.
+ *
+ *  @return  Pointer to the created CWriteContactToICC object, or NULL.
+ */
+CWriteContactToICC* CWriteContactToICC::NewL(CSyncEngineSession& aSession,
+											 TInt aBufferSize,
+											 CPhoneBookManager& aPhonebookManager,
+											 RMobilePhone& aPhone,
+											 TUid aPhonebookUid,
+											 const RMessage2& aClientMessage)
+	{
+	CWriteContactToICC*  self = new(ELeave) CWriteContactToICC(aSession,
+															   aPhonebookManager,
+															   aPhone,
+															   aPhonebookUid,
+															   aClientMessage);
+	CleanupStack::PushL(self);
+	self->ConstructL(aBufferSize); 
+	CleanupStack::Pop(self);
+
+	return self;
+	} // CWriteContactToICC::NewL
+
+
+/**
+ *  Standard constructor.
+ *
+ *  @param aSession           Handle to the engine session.
+ *  @param aPhonebookManager  Pointer to the Phonebook Manager which stores all
+ *                            the phonebook parameters.
+ *  @param aPhone             Handle to the phone object.
+ *  @param aPhonebookUid      Phonebook UID for the contact to be deleted from.
+ *  @param aClientMessage     Handle to the engine message request.
+ */
+CWriteContactToICC::CWriteContactToICC(CSyncEngineSession& aSession,
+									   CPhoneBookManager& aPhonebookManager,
+									   RMobilePhone& aPhone,
+									   TUid aPhonebookUid,
+									   const RMessage2& aClientMessage)
+  : CActive(EPriorityNormal),
+	iSession(aSession),
+	iPhonebookManager(aPhonebookManager),
+	iPhone(aPhone),
+	iPhonebookUid(aPhonebookUid),
+	iClientMessage(aClientMessage),
+	iIccEntryBuf(NULL),
+	iIccEntryPtr(NULL, 0),
+	iPhonebookDataPtr(NULL,0),
+	iIccWriteState(EPBSyncIccWriteIdle),
+	iIsUsedSlot(EFalse)
+	{
+	// NOP
+	} // CWriteContactToICC::CWriteContactToICC
+
+
+/**
+ *  Standard destructor. This will cancel any pending active requests and
+ *  free any allocated memory.
+ */
+CWriteContactToICC::~CWriteContactToICC()
+	{
+	LOGACTIVE1(_L8("~CWriteContactToICC()"));
+
+	Cancel();
+
+	delete iPhonebookBuffer;
+	delete iIccEntry;
+	delete iIccEntryBuf;
+	delete iPhonebookData;
+	} // CWriteContactToICC::~CWriteContactToICC
+
+
+/**
+ *  Second phase constructor.
+ */
+void CWriteContactToICC::ConstructL(TInt aBufferSize)
+	{
+	//
+	// Create the phonebook buffer for writing to the ICC...
+	//
+	iPhonebookBuffer = new(ELeave) CPhoneBookBuffer();
+
+	//
+	// Create the ICC Entry and phonebook buffer...
+	//
+	iIccEntry = CSyncContactICCEntry::NewL();
+
+	iIccEntryBuf = CBufFlat::NewL(1);
+	iIccEntryBuf->ResizeL(aBufferSize); 
+	iIccEntryPtr.Set(iIccEntryBuf->Ptr(0));
+	iPhonebookData = HBufC8::NewL(KPBDataClientHeap); // Create client buffer to store write data 
+	iPhonebookDataPtr.Set(const_cast<unsigned char*>(iPhonebookData->Ptr()), 0, KPBDataClientHeap);
+	iPhonebookBuffer->Set(&iPhonebookDataPtr); // Set iPBBuffer to point to the phonebook data buffer
+
+	//
+	// Get the PhBkStore & PhBkInfo for later use...
+	//
+	User::LeaveIfError(iPhonebookManager.GetPhoneBookStore(iPhonebookUid, iPhone, iPhonebookStore));
+	User::LeaveIfError(iPhonebookManager.GetPhoneBookInfo(iPhonebookUid, iPhBkInfoV5));
+
+	//
+	// Read the ICC Entry streamed buffer...
+	//
+	iClientMessage.ReadL(3, iIccEntryPtr);
+
+	CActiveScheduler::Add(this);
+	} // CWriteContactToICC::ConstructL
+
+
+/** 
+ *  Method to write to ICC after checking slot is empty and memory is available.
+ */
+void CWriteContactToICC::DoIccWriteL()
+	{
+	LOGACTIVE1(_L8("CWriteContactToICC::DoIccWriteL()"));
+
+	//
+	// Check that we are not in use!
+	//
+	if (iIccWriteState != EPBSyncIccWriteIdle)
+		{
+		PhBkSyncPanic(EPhBkSyncPanicDoIccWriteError);
+		}
+
+	//
+	// Restore streamed contact data...
+	//
+	iIccEntry->RestoreL(iIccEntryPtr);
+	iIccEntry->iPhonebookUid = iPhonebookUid;
+
+#ifdef _DEBUG
+	iIccEntry->LogSyncContactICCEntry();
+#endif
+
+	//
+	// Determine if the requested write is to add a new entry, edit an
+	// existing entry, or move an existing entry from one slot to another.
+	//
+	if (iIccEntry->iContactId == KNullContactId ||
+	    iIccEntry->iContactId == KGoldenTemplateId)
+		{
+		iTypeOfWrite = CWriteContactToICC::EWriteAddNew;
+		}
+	else
+		{
+		User::LeaveIfError(iPhonebookManager.GetSlotNumFromContactId(iPhonebookUid,
+		 															 iIccEntry->iContactId,
+		 															 iOldSlot));
+
+		if (iOldSlot != iIccEntry->iSlotNum)
+			{
+			iTypeOfWrite = CWriteContactToICC::EWriteEditSlotNumber;
+			}
+		else
+			{
+			iTypeOfWrite = CWriteContactToICC::EWriteEdit;
+			}
+		}
+
+	//
+	// Check if a destination slot is specified and if that slot is already used...
+	//
+	if (iIccEntry->iSlotNum != KSyncIndexNotSupplied)
+		{
+		TContactItemId  tempId;
+		TInt  result;
+		
+		result = iPhonebookManager.GetContactIdFromSlotNum(iIccEntry->iPhonebookUid,
+														   iIccEntry->iSlotNum,
+														   tempId);
+		if (result != KErrNotFound)
+			{
+			iIsUsedSlot = ETrue;
+			}
+		}
+
+	//
+	// This is an entry requiring an empty slot...
+	//
+	if (iIccEntry->iSlotNum == KSyncIndexNotSupplied)
+		{
+		TInt  result;
+
+		result = iPhonebookManager.GetFirstEmptySlot(iIccEntry->iPhonebookUid,
+													 iIccEntry->iSlotNum);
+
+		if (result != KErrNone)
+			{
+			//
+			// No empty slots exist...
+			//
+			LOGACTIVE1(_L8("CWriteContactToICC::DoIccWriteL(): No empty slots found."));
+			iSession.Server().CompleteWriteContactToICC(KErrNoMemory);
+			return;
+			}
+		}
+
+	//
+	// Encode ICC entry into TLV format...
+	//
+	TRAPD(ret, EncodeICCEntryL());
+	if (ret != KErrNone)
+		{
+		//
+		// Complete client request with the error...
+		//
+		iSession.Server().CompleteWriteContactToICC(ret);
+		return;
+		}
+	
+	//
+	// Write the entry to the ICC...
+	//
+	iPhonebookStore.Write(iStatus, iPhonebookDataPtr, iIccEntry->iSlotNum);
+	iIccWriteState = EPBSyncIccWriteWaitForIccWrite;
+	SetActive();
+	
+	LOGACTIVETIMESTAMP();
+	} // CWriteContactToICC::DoIccWriteL
+
+
+/**
+ *  Encodes the iIccEnty into the TLV format used by the ETel server. 
+ */
+void CWriteContactToICC::EncodeICCEntryL()
+	{
+	//
+	// First add new entry tag...
+	//
+	User::LeaveIfError(iPhonebookBuffer->AddNewEntryTag());
+
+	TInt i;
+
+	// Get first representation of name
+	// convert text into TLV format and append it to allocated buffer
+	User::LeaveIfError(iPhonebookBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBText, iIccEntry->iName));
+
+	// Get second representation of name
+	// convert text into TLV format and append it to allocated buffer
+	User::LeaveIfError(iPhonebookBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBSecondName, iIccEntry->iSecondName));
+
+	// Get default number and its TON 
+	// First convert number into TLV format and append it to allocated buffer
+	User::LeaveIfError(iPhonebookBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBNumber, iIccEntry->iNumber));
+		
+	// convert type into TLV format and append it to allocated buffer
+	User::LeaveIfError(iPhonebookBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBTonNpi, ConvertTonNpiByte(iIccEntry->iTON)));
+
+	// Get list of additional numbers 
+	TInt count = iIccEntry->iNumberList->Count();
+	for(i=0; i < count; ++i)
+		{
+		CSyncContactICCEntry::TSyncAdditionalNumber additionalNumber;
+		additionalNumber = iIccEntry->iNumberList->At(i);
+
+		// Mark the beginning of an additional number 
+		User::LeaveIfError(iPhonebookBuffer->AddNewNumberTag());
+
+		// convert text into TLV format and append it to allocated buffer
+		if (iPhBkInfoV5.iMaxTextLengthAdditionalNumber > 0)
+			{
+			User::LeaveIfError(iPhonebookBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBText, additionalNumber.iNumberString));
+			}
+	
+		// First convert number into TLV format and append it to allocated buffer
+		User::LeaveIfError(iPhonebookBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBNumber, additionalNumber.iNumber));
+			
+		// convert type into TLV format and append it to allocated buffer
+		User::LeaveIfError(iPhonebookBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBTonNpi, ConvertTonNpiByte(additionalNumber.iTON)));
+	}
+
+	// Get list of groups 
+	count = iIccEntry->iGroupList->Count();
+	for(i=0; i < count; ++i)
+		{
+		CSyncContactICCEntry::TSyncEntryName group(iIccEntry->iGroupList->At(i));
+		// convert group into TLV format and append it to allocated buffer
+		User::LeaveIfError(iPhonebookBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBGroupName, group));
+		}
+
+	// Get list of e-mails
+	count = iIccEntry->iEmailList->Count();
+	for(i=0; i < count; ++i)
+		{
+		CSyncContactICCEntry::TSyncEntryName email;
+		email.Append(iIccEntry->iEmailList->At(i));
+		// convert e-mail into TLV format and append it to allocated buffer
+		User::LeaveIfError(iPhonebookBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBEmailAddress, email));
+		}
+
+	// Append hidden entry info here - this can only be added when V2 format is being used
+	if (iSession.Server().IsV2Tsy())
+		{
+		User::LeaveIfError(iPhonebookBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBHiddenInfo,(TUint8)iIccEntry->iIsHidden));
+		}
+	} // CWriteContactToICC::EncodeICCEntryL
+
+
+/** 
+ *  Standard Active Object RunL() method to process the write request.
+ */
+void CWriteContactToICC::RunL()
+	{
+	LOGACTIVE2(_L8("CWriteContactToICC::RunL(): iStatus=%d"), iStatus.Int());
+	LOGACTIVETIMESTAMP();
+	
+	switch (iIccWriteState)
+		{
+		case EPBSyncIccWriteWaitForIccWrite:
+			{
+			if (iStatus.Int() == KErrNone)
+				{
+				//
+				// Update server's look-up table...
+				//
+				User::LeaveIfError(iPhonebookManager.UpdateEntryInTable(iPhonebookUid, iIccEntry->iSlotNum,
+																		KNullContactId, ESlotUsedAvailable));
+
+				if (iTypeOfWrite != EWriteAddNew)
+					{
+					// If this is a new entry the ID will be set by the contact model
+					// If this is an edit the ID needs to be set here
+					User::LeaveIfError(iPhonebookManager.UpdateEntryInTable(iPhonebookUid, iIccEntry->iSlotNum, iIccEntry->iContactId));
+					}
+
+				// Are we editing slot number and need to remove entry at old slot?
+				if (iTypeOfWrite == EWriteEditSlotNumber  &&
+					iOldSlot != KErrNotFound)
+					{
+					// Decrement the number of used entries for the phonebook
+					User::LeaveIfError(iPhonebookManager.AdjustPhoneBookInfoUsedEntries(iIccEntry->iPhonebookUid, -1));
+						
+					iIccWriteState = EPBSyncIccWriteDeleteOldSlot;//need to delete entry at old slot
+					iPhonebookStore.Delete(iStatus, iOldSlot);
+					SetActive();
+					}
+				else
+					{
+					iIccWriteState = EPBSyncIccWriteIdle;
+					// If the entry is written to an unused slot increment the number of entries for the phonebook 
+
+					if (!iIsUsedSlot)
+						{
+						User::LeaveIfError(iPhonebookManager.AdjustPhoneBookInfoUsedEntries(iIccEntry->iPhonebookUid, 1));
+						}
+						
+					iSession.Server().CompleteWriteContactToICC(iStatus.Int());
+					}
+				}
+			else
+				{
+				iIccWriteState = EPBSyncIccWriteIdle;
+				iSession.Server().CompleteWriteContactToICC(iStatus.Int()); 
+				}
+			}
+			break;
+
+		case EPBSyncIccWriteDeleteOldSlot:
+			{
+			//
+			// The client has requested to change the slot number of an entry
+			// after the entry has been written at the new slot.
+			//
+			// Update the look up table even if the delete was not successful
+			// (It would be very bad to have 2 entries with the same UID on
+			// the table).
+			//
+			User::LeaveIfError(iPhonebookManager.UpdateEntryInTable(iPhonebookUid, iOldSlot,
+																	KNullContactId, ESlotEmpty));
+
+			//
+			// If the entry is written to an unused slot increment the number
+			// of entries for the phonebook...
+			//
+			if (iIsUsedSlot == EFalse)
+				{
+				User::LeaveIfError(iPhonebookManager.AdjustPhoneBookInfoUsedEntries(iIccEntry->iPhonebookUid, 1));
+				}
+	
+			iIccWriteState = EPBSyncIccWriteIdle;
+			iSession.Server().CompleteWriteContactToICC(iStatus.Int()); 
+			}
+			break;
+
+		case EPBSyncIccWriteWaitForCancel:
+			{
+			iIccWriteState = EPBSyncIccWriteIdle;
+			iSession.Server().CompleteWriteContactToICC(iStatus.Int());
+			}
+			break;
+
+		default:
+			{
+			PhBkSyncPanic(EPhBkSyncPanicDoIccWriteError);
+			}
+			break;
+		}
+	} // CWriteContactToICC::RunL
+
+
+/** 
+ *  Standard Active Object DoCancel method called when the objects Cancel()
+ *  method is called.
+ */
+void CWriteContactToICC::DoCancel()
+	{
+ 	if (iIccWriteState == EPBSyncIccWriteWaitForIccWrite)
+		{
+ 		iPhonebookStore.CancelAsyncRequest(EMobilePhoneBookStoreWrite);
+ 		iIccWriteState = EPBSyncIccWriteWaitForCancel;
+		}
+	else if(iIccWriteState == EPBSyncIccWriteDeleteOldSlot)
+		{
+		//
+		// Don't change the state here. We will still need to update the look
+		// up table if the entry is not deleted from the ICC in order not to
+		// have 2 entries with the same UID.
+		//
+		iPhonebookStore.CancelAsyncRequest(EMobilePhoneStoreDelete);
+		}
+	} // CWriteContactToICC::DoCancel
+
+
+/**
+ *  Standard Active Object RunError method called when the objects RunL()
+ *  method leaves.
+ *
+ *  Hopefully this method should never be called.
+ *
+ *  @param aError  Leave code from the RunL().
+ *
+ *  @return  KErrNone is returned although the server will panic first.
+ */
+TInt CWriteContactToICC::RunError(TInt aError)
+	{
+#ifdef _DEBUG
+	LOGACTIVE2(_L8("CWriteContactToICC::RunError(%d)"), aError);
+#else
+	(void) aError;
+#endif
+
+	PhBkSyncPanic(EPhBkSyncPanicUnexpectedLeave);
+
+	return KErrNone;	
+	} // CWriteContactToICC::RunError
+
+
+/**
+ *  Convert a ETel TON to an ICC TON value.
+ *
+ *  @param aTon  Should be an ETSI Type-Of-Number field.
+ *
+ *  @return The equivalent RMobilePhone::TMobileTON value for aValue
+ */
+TUint8 CWriteContactToICC::ConvertTonNpiByte(RMobilePhone::TMobileTON aTon) 
+	{
+	TUint8  result(0x81);
+	
+	//
+	// The below 'magic numbers' come from the ETSI 03.40
+	// specification for Address Fields (section 9.1.2.5)
+	//
+	switch (aTon)
+		{
+		case RMobilePhone::EUnknownNumber:
+			{	
+			result = 0x81;
+			}
+			break;
+
+		case RMobilePhone::EInternationalNumber:
+			{	
+			result = 0x91;
+			}
+			break;
+
+		case RMobilePhone::ENationalNumber:
+			{	
+			result = 0xA1;
+			}
+			break;
+
+		case RMobilePhone::ENetworkSpecificNumber:
+			{	
+			result = 0xB1;
+			}
+			break;
+
+		case RMobilePhone::ESubscriberNumber:
+			{	
+			result = 0xC1;
+			}
+			break;
+
+		default:
+			{
+			result = 0x81;
+			}
+			break;
+		}	
+
+	return result;
+	} // CWriteContactToICC::ConvertTonNpiByte
+