--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/pimprotocols/phonebooksync/Server/SyncEngineServer.cpp Tue Feb 02 10:12:17 2010 +0200
@@ -0,0 +1,2143 @@
+// 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 Background Sync Engine server. The engine provides
+// the ability to perform Phonebook Sync's long running operations (e.g. Sync,
+// write contact and delete contact).
+//
+//
+
+/**
+ @file
+ @internalComponent
+*/
+
+#include <connect/sbdefs.h>
+#include <commsdattypesv1_1.h>
+#include <cdblen.h>
+
+#include "common.h"
+#include "PhonebookManager.h"
+#include "SyncContactICCEntry.h"
+#include "phbksynclog.h"
+#include "SyncEngineServer.h"
+#include "SyncEngineSession.h"
+#include "SyncContactsWithICC.h"
+#include "WriteContactToICC.h"
+#include "DeleteContactFromICC.h"
+
+
+using namespace CommsDat;
+
+
+/**
+ * Number of retries for connecting to Etel.
+ */
+const TInt KMaxConnectToEtelRetries = 3;
+
+
+//
+// Teleplate names. Should be in a resource file for localisation really!
+//
+_LIT(KPhbkTemplateADN, "SIM Card Contacts ADN");
+_LIT(KPhbkTemplateSDN, "SIM Card Contacts SDN");
+_LIT(KPhbkTemplateLND, "SIM Card Contacts LND");
+_LIT(KPhbkTemplateUSimApp, "SIM Card Contacts USIMAPP");
+_LIT(KPhbkTemplateFDN, "SIM Card Contacts FDN");
+_LIT(KPhbkTemplateNotSpecified, "SIM Card Contacts Name Not Specified");
+
+
+//
+// Constants for encoding contacts...
+//
+_LIT(KEngineInternationalPrefix,"+");
+
+
+//
+// Definition of iPolicy dictating the capability checking for phbksyncsvr...
+//
+const TUint iEngineRangeCount = 10;
+
+const TInt CSyncEngineServer::iRanges[iEngineRangeCount] =
+ {
+ 0, //range is 0
+ 1, //range is 1-3 inclusive
+ 4, //range is 4-5 inclusive
+ 6, //range is 6
+ 7, //range is 7-13 inclusive
+ 14, //range is 14
+ 15, //range is 15-16 inclusive
+ 17, //range is 17-24 inclusive
+ 25, //range is 25 inclusive
+ 26, //range is 26-KMaxTInt inclusive
+ };
+
+const TUint8 CSyncEngineServer::iElementsIndex[iEngineRangeCount] =
+ {
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ CPolicyServer::ENotSupported,
+ };
+
+const CPolicyServer::TPolicyElement CSyncEngineServer::iElements[] =
+ {
+ { _INIT_SECURITY_POLICY_C2( ECapabilityReadUserData, ECapabilityWriteUserData), CPolicyServer::EFailClient}, // policy 0: range 0 - 0
+ { _INIT_SECURITY_POLICY_C1( ECapability_None), CPolicyServer::EFailClient}, // policy 1: range 1 - 3
+ { _INIT_SECURITY_POLICY_C1( ECapabilityWriteUserData), CPolicyServer::EFailClient}, // policy 2: range 4 - 5
+ { _INIT_SECURITY_POLICY_C1( ECapabilityReadUserData), CPolicyServer::EFailClient}, // policy 3: range 6 - 6
+ { _INIT_SECURITY_POLICY_C1( ECapability_None), CPolicyServer::EFailClient}, // policy 4: range 7 - 13
+ { _INIT_SECURITY_POLICY_C2( ECapabilityReadUserData, ECapabilityWriteUserData), CPolicyServer::EFailClient}, // policy 5: range 14 - 14
+ { _INIT_SECURITY_POLICY_C1( ECapabilityWriteUserData), CPolicyServer::EFailClient}, // policy 6: range 15 - 16
+ { _INIT_SECURITY_POLICY_C1( ECapability_None), CPolicyServer::EFailClient}, // policy 7: range 17 - 24
+#ifdef _DEBUG
+ { _INIT_SECURITY_POLICY_C1( ECapability_None), CPolicyServer::EFailClient}, // policy 8: range 25
+#else
+ { _INIT_SECURITY_POLICY_FAIL}, // policy 8: range 25
+#endif
+ };
+
+const CPolicyServer::TPolicy CSyncEngineServer::iPolicy =
+ {
+ CPolicyServer::EAlwaysPass ,
+ iEngineRangeCount,
+ iRanges,
+ iElementsIndex,
+ iElements
+ };
+
+
+/**
+ * Static factory method used to create a CSyncEngineServer object.
+ *
+ * @param aPhoneBookManager Reference to the front-end servers's phonebook
+ * manager.
+ *
+ * @return Pointer to the created CSyncEngineServer object, or NULL.
+ */
+CSyncEngineServer* CSyncEngineServer::NewL(CPhoneBookManager& aPhoneBookManager)
+ {
+ LOGENGINE1(_L8("NewL()"));
+
+ CSyncEngineServer* self = new (ELeave) CSyncEngineServer(aPhoneBookManager);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+
+ return self;
+ } // CSyncEngineServer::NewL
+
+
+/**
+ * Standard constructor.
+ *
+ * @param aPhoneBookManager Reference to the front-end servers's phonebook
+ * manager.
+ */
+CSyncEngineServer::CSyncEngineServer(CPhoneBookManager& aPhoneBookManager)
+ : CPolicyServer(EPriorityNormal, iPolicy, ESharableSessions),
+ iICCCaps(RMobilePhone::KCapsSimAccessSupported),
+ iPhoneBookSyncEngineStarter(NULL),
+ iConnectedSession(NULL),
+ iPhonebookManager(aPhoneBookManager),
+ iSyncContactsWithICC(NULL),
+ iWriteContactToICC(NULL),
+ iDeleteContactFromICC(NULL)
+ {
+ __DECLARE_NAME(_L("CSyncEngineServer"));
+ } // CSyncEngineServer::CSyncEngineServer
+
+
+/**
+ * Second phase constructor. Ensures the server is created and ready to run.
+ */
+void CSyncEngineServer::ConstructL()
+ {
+ StartL(PHBKSYNC_ENGINE_NAME);
+ } // CSyncEngineServer::ConstructL
+
+
+/**
+ * Destructor.
+ */
+CSyncEngineServer::~CSyncEngineServer()
+ {
+ //
+ // Stop the engine from starting if it has initiated a startup.
+ //
+ delete iPhoneBookSyncEngineStarter;
+ iPhoneBookSyncEngineStarter = NULL;
+
+ //
+ // Unconfigure the engine if needed...
+ //
+ TRAP_IGNORE(UnconfigureEngineL());
+
+ delete iSyncContactsWithICC;
+ delete iWriteContactToICC;
+ delete iDeleteContactFromICC;
+ } // CSyncEngineServer::~CSyncEngineServer
+
+
+/**
+ * Configures the engine for use. This includes opening the ETel handles,
+ * connecting to the contacts database and opening the phonebook stores.
+ */
+void CSyncEngineServer::ConfigureEngineL()
+ {
+ LOGENGINE1(_L8("CSyncEngineServer::ConfigureEngineL()"));
+
+ //
+ // Connect to ETel...
+ //
+ TInt etelErr(KErrNone), retryCount;
+
+ for (retryCount = 0; retryCount < KMaxConnectToEtelRetries; retryCount++)
+ {
+ TRAP(etelErr, ConnectToEtelL()); //This can leave due to a denied access
+ //to CommDb or Etel
+ if (etelErr == KErrNone)
+ {
+ break;
+ }
+
+ if (retryCount < KMaxConnectToEtelRetries - 1)
+ {
+ User::After(1000000);
+ }
+ }
+ User::LeaveIfError(etelErr);
+
+ //
+ // Open the Contacts DB...
+ //
+ TInt dbErr(KErrNone);
+
+ for (retryCount = 0; retryCount < KMaxDbAccessRetryCount; retryCount++)
+ {
+ TRAP(dbErr, iDb = CContactDatabase::OpenL()); // First try to open existing database
+
+ if (dbErr == KErrNotFound)
+ {
+ TRAP(dbErr, iDb = CContactDatabase::CreateL()); // Database does not exist so create and open new one
+ }
+
+ if (dbErr == KErrNone)
+ {
+ break;
+ }
+
+ if (retryCount < KMaxDbAccessRetryCount - 1)
+ {
+ User::After(1000000);
+ }
+ }
+ User::LeaveIfError(dbErr);
+
+ //
+ // Setup the phonebook parameters, read the settings from the INI
+ // file and create the phonebook group IDs...
+ //
+ if (iPhone.GetIccAccessCaps(iICCCaps) != KErrNone) // Get type of ICC that is being used
+ {
+ iICCCaps = RMobilePhone::KCapsSimAccessSupported; // set default value
+ }
+
+ CreatePhoneBookIdsL();
+ } // CSyncEngineServer::ConfigureEngineL
+
+
+/**
+ * Unconfigures the engine ready to shutdown.
+ */
+void CSyncEngineServer::UnconfigureEngineL()
+ {
+ LOGENGINE1(_L8("CSyncEngineServer::UnconfigureEngineL()"));
+
+ iPhonebookManager.ClosePhoneBookStores();
+
+ delete iDb;
+ iDb = NULL;
+
+ iPhone.Close();
+ iEtelServer.Close();
+ } // CSyncEngineServer::UnconfigureEngineL
+
+
+/**
+ * Create a Template ID for the specified phonebook.
+ *
+ * @param aPhonebookUid UID of the phonebook to create an ID for.
+ * @param aICCCaps The capabilities of the phone.
+ */
+void CSyncEngineServer::CreateTemplateIdL(TUid aPhonebookUid,
+ TUint32 aICCCaps)
+ {
+ LOGENGINE2(_L8("CreateTemplateIdL(0x%08x)"), aPhonebookUid);
+
+ TContactItemId templateId(KNullContactId);
+
+ //
+ // Check if there is an existing template in the contact database for
+ // this phonebook...
+ //
+ CContactIdArray* idList = iDb->GetCardTemplateIdListL();
+ CleanupStack::PushL(idList);
+
+ if (idList != NULL && idList->Count() > 0)
+ {
+ TInt idCount = idList->Count();
+
+ for (TInt index = 0; index < idCount; index++)
+ {
+ CContactCardTemplate* item = static_cast<CContactCardTemplate*> (iDb->ReadContactLC((*idList)[index]));
+
+ if ((aPhonebookUid == KUidIccGlobalAdnPhonebook &&
+ item->GetTemplateLabelL() == KPhbkTemplateADN) ||
+ (aPhonebookUid == KUidIccGlobalSdnPhonebook &&
+ item->GetTemplateLabelL() == KPhbkTemplateSDN) ||
+ (aPhonebookUid == KUidIccGlobalLndPhonebook &&
+ item->GetTemplateLabelL() == KPhbkTemplateLND) ||
+ (aPhonebookUid == KUidUsimAppAdnPhonebook &&
+ item->GetTemplateLabelL() == KPhbkTemplateUSimApp) ||
+ (aPhonebookUid == KUidIccGlobalFdnPhonebook &&
+ item->GetTemplateLabelL() == KPhbkTemplateFDN))
+ {
+ templateId = (*idList)[index];
+
+ User::LeaveIfError(iPhonebookManager.SetTemplateId(aPhonebookUid,
+ templateId));
+
+ index = idCount; // to terminate loop
+ }
+ CleanupStack::PopAndDestroy(item);
+ }
+ }
+ CleanupStack::PopAndDestroy(idList);
+
+ //
+ // If no suitable template been found create a new one...
+ //
+ if (templateId == KNullContactId)
+ {
+ LOGENGINE2(_L8("CreateTemplateIdL(0x%08x): Creating template."),
+ aPhonebookUid);
+
+ CContactItem* newTemplate;
+
+ if (aPhonebookUid == KUidIccGlobalAdnPhonebook)
+ {
+ newTemplate = iDb->CreateContactCardTemplateLC(KPhbkTemplateADN);
+ }
+ else if (aPhonebookUid == KUidIccGlobalSdnPhonebook)
+ {
+ newTemplate = iDb->CreateContactCardTemplateLC(KPhbkTemplateSDN);
+ }
+ else if (aPhonebookUid == KUidIccGlobalLndPhonebook)
+ {
+ newTemplate = iDb->CreateContactCardTemplateLC(KPhbkTemplateLND);
+ }
+ else if (aPhonebookUid == KUidUsimAppAdnPhonebook)
+ {
+ newTemplate = iDb->CreateContactCardTemplateLC(KPhbkTemplateUSimApp);
+ }
+ else if (aPhonebookUid == KUidIccGlobalFdnPhonebook)
+ {
+ newTemplate = iDb->CreateContactCardTemplateLC(KPhbkTemplateFDN);
+ }
+ else
+ {
+ newTemplate = iDb->CreateContactCardTemplateLC(KPhbkTemplateNotSpecified);
+ }
+
+ templateId = newTemplate->Id();
+ CleanupStack::PopAndDestroy(newTemplate);
+
+ //
+ // Remove all the unnecessary fields...
+ //
+ newTemplate = iDb->OpenContactLX(templateId);
+ CleanupStack::PushL(newTemplate);
+ const TInt fieldCount = newTemplate->CardFields().Count();
+ for(TInt i=fieldCount-1;i>=0;i--)
+ {
+ newTemplate->RemoveField(i);
+ }
+
+ //
+ // Add default name field...
+ //
+ CContactItemField* name = CContactItemField::NewLC(KStorageTypeText,KUidContactFieldFamilyName);
+ name->SetMapping(KUidContactFieldVCardMapUnusedN);
+ newTemplate->AddFieldL(*name);
+ CleanupStack::Pop(name);
+
+ //
+ // Add second name field...
+ //
+ CContactItemField* secondName = CContactItemField::NewLC(KStorageTypeText,KUidContactFieldSecondName);
+ secondName->SetMapping(KUidContactFieldVCardMapSECONDNAME);
+ secondName->SetUserFlags(EContactCategoryHome);
+ newTemplate->AddFieldL(*secondName);
+ CleanupStack::Pop(secondName);
+
+ //
+ // Add default number field...
+ //
+ CContactItemField* number = CContactItemField::NewLC(KStorageTypeText,KUidContactFieldPhoneNumber);
+ number->SetMapping(KUidContactFieldVCardMapTEL);
+ number->AddFieldTypeL(KUidContactFieldVCardMapWORK);
+ number->AddFieldTypeL(KUidContactFieldVCardMapVOICE);
+ number->AddFieldTypeL(KUidContactFieldVCardMapCELL);
+ newTemplate->AddFieldL(*number);
+ CleanupStack::Pop(number);
+
+ //
+ // Add Slot Number field...
+ //
+ CContactItemField* slotnum = CContactItemField::NewLC(KStorageTypeText,KUidContactFieldICCSlot);
+ slotnum->SetMapping(KUidContactFieldVCardMapNotRequired);
+ newTemplate->AddFieldL(*slotnum);
+ CleanupStack::Pop(slotnum);
+
+ //
+ // Add Phonebook type field...
+ //
+ CContactItemField* phonebook = CContactItemField::NewLC(KStorageTypeText,KUidContactFieldICCPhonebook);
+ phonebook->SetMapping(KUidContactFieldVCardMapNotRequired);
+ newTemplate->AddFieldL(*phonebook);
+ CleanupStack::Pop(phonebook);
+
+ //
+ // 3G ICC so there are additional fields for ADN and USIM App
+ // phonebooks.
+ //
+ if (aICCCaps & RMobilePhone::KCapsUSimAccessSupported)
+ {
+ if (aPhonebookUid == KUidIccGlobalAdnPhonebook ||
+ aPhonebookUid == KUidUsimAppAdnPhonebook)
+ {
+ //
+ // Add e-mail field...
+ //
+ CContactItemField* emailField = CContactItemField::NewLC(KStorageTypeText,KUidContactFieldEMail);
+ emailField->SetMapping(KUidContactFieldVCardMapUnusedN);
+ newTemplate->AddFieldL(*emailField);
+ CleanupStack::Pop(emailField);
+
+ //
+ // Add group field - this is different from contacts group.
+ // This field indicates group that this ICC entry belongs to.
+ // User can add this entry to a number of groups on ICC i.e.
+ // business, private, etc.
+ //
+ CContactItemField* group = CContactItemField::NewLC(KStorageTypeText,KUidContactFieldICCGroup);
+ group->SetMapping(KUidContactFieldVCardMapUnusedN);
+ newTemplate->AddFieldL(*group);
+ CleanupStack::Pop(group);
+ }
+ }
+
+ //
+ // Store the new Template ID...
+ //
+ User::LeaveIfError(iPhonebookManager.SetTemplateId(aPhonebookUid, templateId));
+
+ iDb->CommitContactL(*newTemplate);
+ CleanupStack::PopAndDestroy(2); // newTemplate plus locked record
+ }
+ } // CSyncEngineServer::CreateTemplateIdL
+
+
+/**
+ * Create a Group ID for the specified phonebook.
+ *
+ * @param aPhonebookUid UID of the phonebook to create an ID for.
+ */
+void CSyncEngineServer::CreateGroupIdL(TUid aPhonebookUid)
+ {
+ LOGENGINE2(_L8("CreateGroupIdL(0x%08x)"), aPhonebookUid);
+
+ TContactItemId groupId(KNullContactId);
+
+ //
+ // Check if there is an existing group in the contact database for this
+ // phonebook...
+ //
+ CContactIdArray* idList = iDb->GetGroupIdListL();
+ CleanupStack::PushL(idList);
+
+ if (idList != NULL && idList->Count() > 0)
+ {
+ LOGENGINE2(_L8("CreateGroupIdL(0x%08x): Creating template."),
+ aPhonebookUid);
+
+ TInt idCount = idList->Count();
+
+ for (TInt index = 0; index < idCount; index++)
+ {
+ //
+ // Retrieve the first entry in each group, obtain that entry's
+ // template ID and check the template label to confirm if it
+ // relates to this phonebook.
+ //
+ CContactGroup* group = static_cast<CContactGroup*> (iDb->ReadContactLC((*idList)[index]));
+ CContactIdArray* itemList = group->ItemsContainedLC();
+
+ if (itemList->Count() > 0)
+ {
+ CContactItem* groupItem = iDb->ReadContactLC((*itemList)[0]);
+ TContactItemId templateId = groupItem->TemplateRefId();
+ if (templateId != KNullContactId)
+ {
+ CContactCardTemplate* tempItem = static_cast<CContactCardTemplate*> (iDb->ReadContactLC(templateId));
+
+ TPtrC templateLabel;
+ TRAPD(errorCheck, templateLabel.Set(tempItem->GetTemplateLabelL()));
+
+ // Check if the first item in the group uses a template with a label then check to see if the
+ // label matches one of the Phonebook template labels
+ if(errorCheck != KErrNotFound)
+ {
+ if( (aPhonebookUid == KUidIccGlobalAdnPhonebook && templateLabel == KPhbkTemplateADN) ||
+ (aPhonebookUid == KUidIccGlobalSdnPhonebook && templateLabel == KPhbkTemplateSDN) ||
+ (aPhonebookUid == KUidIccGlobalLndPhonebook && templateLabel == KPhbkTemplateLND) ||
+ (aPhonebookUid == KUidIccGlobalFdnPhonebook && templateLabel == KPhbkTemplateFDN) ||
+ (aPhonebookUid == KUidUsimAppAdnPhonebook && templateLabel == KPhbkTemplateUSimApp))
+ {
+ groupId = (*idList)[index];
+ User::LeaveIfError(iPhonebookManager.SetGroupId(aPhonebookUid,groupId));
+ index = idCount; // to terminate loop
+ }
+ }
+ CleanupStack::PopAndDestroy(tempItem);
+ }
+ CleanupStack::PopAndDestroy(groupItem);
+ }
+ CleanupStack::PopAndDestroy(2, group); // itemList, group
+ }
+ }
+
+ //
+ // If no suitable group has been found create a new one...
+ //
+ if (groupId == KNullContactId)
+ {
+ //
+ // Store the new group ID...
+ //
+ CContactItem* group = iDb->CreateContactGroupLC(KNullDesC);
+ groupId = group->Id();
+
+ User::LeaveIfError(iPhonebookManager.SetGroupId(aPhonebookUid, groupId));
+ CleanupStack::PopAndDestroy(group);
+ }
+
+ CleanupStack::PopAndDestroy(idList);
+ } // CSyncEngineServer::CreateGroupIdL
+
+
+/**
+ * Create the template ID and group ID for all supported phonebooks. These
+ * IDs are to be used with the entries that reside on a particular phonebook.
+ */
+void CSyncEngineServer::CreatePhoneBookIdsL()
+ {
+ LOGENGINE1(_L8("CreatePhoneBookIdsL()"));
+
+ //
+ // Ensure each phonebook has its templates created...
+ //
+ TInt phonebookUidCount(iPhonebookManager.GetPhonebookCount());
+
+ for (TInt index = 0; index < phonebookUidCount; index++)
+ {
+ TUid phonebookUid;
+
+ User::LeaveIfError(iPhonebookManager.GetPhonebookUid(index,
+ phonebookUid));
+
+ LOGENGINE2(_L8("CreatePhoneBookIdsL: Phonebook=0x%08x"), phonebookUid);
+
+ //
+ // Get the template ID...
+ //
+ TContactItemId templateId;
+
+ User::LeaveIfError(iPhonebookManager.GetTemplateId(phonebookUid,
+ templateId));
+
+ //
+ // Validate any template ID already provided in INI file
+ //
+ if (templateId != KNullContactId)
+ {
+ CContactItem* item(NULL);
+
+ TRAPD(err, item = iDb->ReadContactL(templateId));
+ CleanupStack::PushL(item);
+
+ if (err == KErrNotFound)
+ {
+ User::LeaveIfError(iPhonebookManager.SetTemplateId(phonebookUid,
+ KNullContactId));
+ templateId = KNullContactId;
+ }
+ else if (err != KErrNone)
+ {
+ User::Leave(err);
+ }
+ else if (item == NULL || item->Type() != KUidContactCardTemplate)
+ {
+ User::LeaveIfError(iPhonebookManager.SetTemplateId(phonebookUid,
+ KNullContactId));
+ templateId = KNullContactId;
+ }
+ else
+ {
+ TPtrC label = static_cast<CContactCardTemplate*>(item)->GetTemplateLabelL();
+
+ //
+ // The following test confirms if a template ID relates to this
+ // phonebook's template by checking the label employed.
+ //
+ if (!((phonebookUid == KUidIccGlobalAdnPhonebook && label == KPhbkTemplateADN) ||
+ (phonebookUid == KUidIccGlobalSdnPhonebook && label == KPhbkTemplateSDN) ||
+ (phonebookUid == KUidIccGlobalLndPhonebook && label == KPhbkTemplateLND) ||
+ (phonebookUid == KUidUsimAppAdnPhonebook && label == KPhbkTemplateUSimApp) ||
+ (phonebookUid == KUidIccGlobalFdnPhonebook && label == KPhbkTemplateFDN)))
+ {
+ User::LeaveIfError(iPhonebookManager.SetTemplateId(phonebookUid,
+ KNullContactId));
+ templateId = KNullContactId;
+ }
+ }
+
+ CleanupStack::PopAndDestroy(item);
+ }
+
+ //
+ // If we don't have a template ID, then create a template...
+ //
+ if (templateId == KNullContactId)
+ {
+ CreateTemplateIdL(phonebookUid, iICCCaps);
+ }
+
+ //
+ // Get the group ID...
+ //
+ TContactItemId groupId;
+
+ User::LeaveIfError(iPhonebookManager.GetGroupId(phonebookUid, groupId));
+
+ //
+ // Validate any group ID already provided in INI file
+ //
+ if (groupId != KNullContactId)
+ {
+ CContactItem* item = NULL;
+ TRAPD(err, item = iDb->ReadContactL(groupId));
+ CleanupStack::PushL(item);
+
+ if (err == KErrNotFound)
+ {
+ User::LeaveIfError(iPhonebookManager.SetGroupId(phonebookUid,
+ KNullContactId));
+ groupId = KNullContactId;
+ }
+ else if (err != KErrNone)
+ {
+ User::Leave(err);
+ }
+ else if (item == NULL || item->Type() != KUidContactGroup)
+ {
+ User::LeaveIfError(iPhonebookManager.SetGroupId(phonebookUid,
+ KNullContactId));
+ groupId = KNullContactId;
+ }
+ else
+ {
+ //
+ // The following test is a simplistic method to determine
+ // if the group ID represents a phonebook group - as
+ // employed by LPD for Linnea. It does not attempt to check
+ // if it relates to the correct type of phonebook.
+ //
+ if (static_cast<CContactGroup*>(item)->GetGroupLabelL() != KNullDesC)
+ {
+ User::LeaveIfError(iPhonebookManager.SetGroupId(phonebookUid,
+ KNullContactId));
+ groupId = KNullContactId;
+ }
+ }
+ CleanupStack::PopAndDestroy(item);
+ }
+
+ if (groupId == KNullContactId)
+ {
+ CreateGroupIdL(phonebookUid);
+ }
+ }
+ } // CSyncEngineServer::CreatePhoneBookIdsL
+
+
+/**
+ * Removes all the contact entries for a phonebook. This is called when a
+ * sync request is made on an unsupported phonebook so that it can be
+ * cleared.
+ *
+ * @param aPhonebookUid UID of the ICC phonebook to perform the operation on.
+ */
+void CSyncEngineServer::RemoveAllContactsForPhoneBookL(TUid aPhonebookUid)
+ {
+ LOGENGINE2(_L8("RemoveAllContactsForPhoneBookL(0x%08x)"), aPhonebookUid);
+
+ //
+ // Get the Group ID to search for entries. If no ID exists then the
+ // database does not contain any entries.
+ //
+ TContactItemId groupId;
+
+ User::LeaveIfError(iPhonebookManager.GetGroupId(aPhonebookUid, groupId));
+
+ //
+ // Delete all entries for this group ID...
+ //
+ if (groupId != KNullContactId && groupId != KGoldenTemplateId)
+ {
+ CContactItem* group = iDb->ReadContactLC(groupId);
+ const CContactIdArray* members = static_cast<CContactGroup*>(group)->ItemsContained();
+ const TInt count = members->Count();
+
+ for (TInt item = 0; item < count; item++)
+ {
+ iDb->DeleteContactL((*members)[item]);
+ }
+
+ CleanupStack::PopAndDestroy(group);
+
+ //
+ // Compress the database if needed and we are finished!
+ //
+ if (iDb->CompressRequired())
+ {
+ TRAP_IGNORE(iDb->CompactL());
+ }
+ }
+ } // CSyncEngineServer::RemoveAllContactsForPhoneBookL
+
+
+/**
+ * This method synchronises the specified phonebook. The synchronisation is
+ * done by creating an instance of the CSyncContactsWithICC Active Object
+ * class and then starting it.
+ *
+ * @param aMessage A reference to the front-end server request.
+ * @param aPhonebookUid UID of the ICC phonebook to perform the operation on.
+ */
+void CSyncEngineServer::DoSynchronisationL(const RMessage2& aMessage,
+ TUid aPhonebookUid)
+ {
+ LOGENGINE2(_L8("DoSynchronisationL(0x%08x)"), aPhonebookUid);
+
+ //
+ // Set the cache state to unsynchronised to start with.
+ //
+ TInt result;
+
+ result = iPhonebookManager.SetSyncState(aPhonebookUid,
+ RPhoneBookSession::EUnsynchronised);
+ if (result != KErrNone)
+ {
+ iConnectedSession->CompleteRequest(aMessage, result);
+ return;
+ }
+
+ //
+ // Has the PhBkInfo structure been received yet? If not then this
+ // phonebook is not usable...
+ //
+ TInt phBkInfoRetrievedResult;
+
+ result = iPhonebookManager.GetPhBkInfoRetrievedResult(aPhonebookUid,
+ phBkInfoRetrievedResult);
+ if (result != KErrNone)
+ {
+ iPhonebookManager.SetLastSyncError(aPhonebookUid, result);
+ iPhonebookManager.SetSyncState(aPhonebookUid, RPhoneBookSession::EErrorDuringSync);
+
+ iConnectedSession->CompleteRequest(aMessage, result);
+ return;
+ }
+
+ if (phBkInfoRetrievedResult != KErrNone)
+ {
+ //
+ // The phonebook has been found to not exist, and a sync has been
+ // requested, so remove all entries from the database.
+ //
+ RemoveAllContactsForPhoneBookL(aPhonebookUid);
+
+ iPhonebookManager.SetLastSyncError(aPhonebookUid, phBkInfoRetrievedResult);
+ iPhonebookManager.SetSyncState(aPhonebookUid, RPhoneBookSession::EErrorDuringSync);
+
+ iConnectedSession->CompleteRequest(aMessage, phBkInfoRetrievedResult);
+ return;
+ }
+
+ //
+ // Check that the phone store was opened...
+ //
+ RMobilePhoneBookStore phonebookStore;
+
+ result = iPhonebookManager.GetPhoneBookStore(aPhonebookUid, iPhone,
+ phonebookStore);
+ if (result != KErrNone)
+ {
+ iPhonebookManager.SetLastSyncError(aPhonebookUid, result);
+ iPhonebookManager.SetSyncState(aPhonebookUid, RPhoneBookSession::EErrorDuringSync);
+
+ iConnectedSession->CompleteRequest(aMessage, result);
+ return;
+ }
+
+ if (phonebookStore.SubSessionHandle() == 0)
+ {
+ //
+ // The phonebook is not supported and a sync has been
+ // requested, so remove all entries from the database.
+ //
+ RemoveAllContactsForPhoneBookL(aPhonebookUid);
+
+ iPhonebookManager.SetLastSyncError(aPhonebookUid, KErrNotSupported);
+ iPhonebookManager.SetSyncState(aPhonebookUid, RPhoneBookSession::EErrorDuringSync);
+
+ iConnectedSession->CompleteRequest(aMessage, KErrNotSupported);
+ return;
+ }
+
+ //
+ // Ensure there is no left sync in progress (there should not be!)...
+ //
+ if (iSyncContactsWithICC != NULL)
+ {
+ iPhonebookManager.SetLastSyncError(aPhonebookUid, KErrServerBusy);
+ iPhonebookManager.SetSyncState(aPhonebookUid, RPhoneBookSession::EErrorDuringSync);
+
+ iConnectedSession->CompleteRequest(aMessage, KErrServerBusy);
+ return;
+ }
+
+ //
+ // Create the Active Object that will perform the sync...
+ //
+ iSyncContactsWithICC = CSyncContactsWithICC::NewL(*iConnectedSession,
+ iPhonebookManager,
+ *iDb,
+ iPhone,
+ aPhonebookUid,
+ aMessage);
+
+ //
+ // Start reading phonebook entries and populating Contacts DB...
+ //
+ TRAPD(error, iSyncContactsWithICC->SyncContactsWithICCL());
+ if (error != KErrNone)
+ {
+ CompleteDoSync(error);
+ }
+ } // CSyncEngineServer::DoSynchronisationL
+
+
+/**
+ * Delete an entry specified by aContactId from the ICC phonebook store
+ * specified. It performs the opperation by creating a CDeleteContactFromICC
+ * Active Object and starting it.
+ *
+ * @param aMessage A reference to the front-end server request.
+ * @param aPhonebookUid UID of the phonebook containing the entry.
+ * @param aContactId ID of the contact to delete.
+ */
+void CSyncEngineServer::DeleteCntFromICCL(const RMessage2& aMessage,
+ TUid aPhonebookUid,
+ TContactItemId aContactId)
+ {
+ LOGENGINE2(_L8("DeleteCntFromICCL(0%d)"), aContactId);
+
+ //
+ // This request can only proceed if the cache is valid...
+ //
+ RPhoneBookSession::TSyncState syncState;
+ TInt result;
+
+ result = iPhonebookManager.GetSyncState(aPhonebookUid, syncState);
+ if (result != KErrNone)
+ {
+ iConnectedSession->CompleteRequest(aMessage, result);
+ return;
+ }
+
+ if (syncState != RPhoneBookSession::ECacheValid)
+ {
+ iConnectedSession->CompleteRequest(aMessage, KErrNotReady);
+ return;
+ }
+
+ //
+ // Check that ICC is not locked, blocked OR pin protected...
+ //
+ if (iPhonebookManager.IsPin1Valid() == EFalse)
+ {
+ iConnectedSession->CompleteRequest(aMessage, KErrAccessDenied);
+ return;
+ }
+
+ //
+ // If this is a USIM App ADN phonebook then check that USIM PIN is valid...
+ //
+ if (aPhonebookUid == KUidUsimAppAdnPhonebook &&
+ iPhonebookManager.IsUsimAppPinValid() == EFalse)
+ {
+ iConnectedSession->CompleteRequest(aMessage, KErrAccessDenied);
+ return;
+ }
+
+ //
+ // If this is the FDN phonebook then check that PIN2 is valid...
+ //
+ if (aPhonebookUid == KUidIccGlobalFdnPhonebook &&
+ iPhonebookManager.IsPin2Valid() == EFalse)
+ {
+ iConnectedSession->CompleteRequest(aMessage, KErrAccessDenied);
+ return;
+ }
+
+ //
+ // Now create and run the Active Object which will process this
+ // delete request...
+ //
+ if (iDeleteContactFromICC != NULL)
+ {
+ iConnectedSession->CompleteRequest(aMessage, KErrServerBusy);
+ return;
+ }
+
+ iDeleteContactFromICC = CDeleteContactFromICC::NewL(*iConnectedSession,
+ iPhonebookManager,
+ *iDb,
+ iPhone,
+ aPhonebookUid,
+ aMessage);
+ iDeleteContactFromICC->DoIccDelete(aContactId);
+ } // CSyncEngineServer::DeleteCntFromICCL
+
+
+/**
+ * Completes an outstanding Delete-from-ICC request. It is called by the
+ * active object CPhoneBookDoIccDelete class when it has finished its task.
+ * The functin completes the front-end server's DeleteContact request.
+ *
+ * @param aRetVal Complete-request error code.
+ */
+void CSyncEngineServer::CompleteDoIccDelete(TInt aRetVal)
+ {
+ LOGENGINE2(_L8("CompleteDoIccDelete(%d)"), aRetVal);
+
+ //
+ // Complete the session request and delete the Active Object...
+ //
+ iConnectedSession->CompleteRequest(iDeleteContactFromICC->ClientMessage(),
+ aRetVal);
+
+ delete iDeleteContactFromICC;
+ iDeleteContactFromICC = NULL;
+ } // CSyncEngineServer::CompleteDoIccDelete
+
+
+/**
+ * Write an entry to the ICC phonebook store. This is performed by creating an
+ * Active Object to request the write via ETel. The PIN1 and PIN2 (if FDN)
+ * must be valid to perform such a request.
+ *
+ * @param aMessage A reference to the front-end server request.
+ * @param aTemplateId ID of the template to use.
+ * @param aBufferSize Size of the streamed ICC buffer.
+ */
+void CSyncEngineServer::WriteCntToICCL(const RMessage2& aMessage,
+ TContactItemId aTemplateId,
+ TInt aBufferSize)
+ {
+ LOGENGINE3(_L8("CSyncEngineServer::WriteCntToICCL(): %d 0x%08x %d"),
+ aTemplateId, aBufferSize);
+
+ //
+ // Is the ICC still in usable state for this phonebook?
+ //
+ TUid phonebookUid = iPhonebookManager.GetPhonebookUidFromTemplateId(aTemplateId);
+
+ if (iPhonebookManager.IsPin1Valid() == EFalse ||
+ (phonebookUid == KUidUsimAppAdnPhonebook &&
+ iPhonebookManager.IsUsimAppPinValid() == EFalse) ||
+ (phonebookUid == KUidIccGlobalFdnPhonebook &&
+ iPhonebookManager.IsPin2Valid() == EFalse))
+ {
+ iConnectedSession->CompleteRequest(aMessage, KErrAccessDenied);
+ return;
+ }
+
+ //
+ // Create the Active Object which will process this Write request...
+ //
+ if (iWriteContactToICC != NULL)
+ {
+ iConnectedSession->CompleteRequest(aMessage, KErrServerBusy);
+ return;
+ }
+
+ iWriteContactToICC = CWriteContactToICC::NewL(*iConnectedSession,
+ aBufferSize,
+ iPhonebookManager,
+ iPhone,
+ phonebookUid,
+ aMessage);
+
+ //
+ // Setup the Active Object and begin...
+ //
+ TRAPD(error, iWriteContactToICC->DoIccWriteL());
+ if (error != KErrNone)
+ {
+ CompleteWriteContactToICC(error);
+ }
+ } // CSyncEngineServer::WriteCntToICCL
+
+
+/**
+ * Complete an outstanding Write-to-ICC request. It is called by the Active
+ * Object CWriteContactToICC class when it has finished its task. The ICC
+ * slot number is written back to the front-end address space and the
+ * request is completed.
+ *
+ * @param aRetVal Complete-request error code.
+ */
+void CSyncEngineServer::CompleteWriteContactToICC(TInt aRetVal)
+ {
+ LOGENGINE2(_L8("CompleteWriteContactToICC(%d)"), aRetVal);
+
+ if (aRetVal == KErrNone)
+ {
+ TPckg<TInt> indexPckg(iWriteContactToICC->SlotNum());
+ TPckg<TUid> phonebookUidPckg(iWriteContactToICC->PhonebookUid());
+
+ TRAPD(err1, iWriteContactToICC->ClientMessage().WriteL(1, indexPckg));
+ TRAPD(err2, iWriteContactToICC->ClientMessage().WriteL(2, phonebookUidPckg));
+
+ __ASSERT_ALWAYS(err1 == KErrNone && err2 == KErrNone,
+ PhBkSyncPanic(EPhBkSyncPanicBadDescriptor));
+ }
+
+ //
+ // Complete the session request and delete the Active Object...
+ //
+ iConnectedSession->CompleteRequest(iWriteContactToICC->ClientMessage(),
+ aRetVal);
+
+ delete iWriteContactToICC;
+ iWriteContactToICC = NULL;
+ } // CSyncEngineServer::CompleteWriteContactToICC
+
+
+/**
+ * Cancel a previous synchronisation request.
+ *
+ * @param aPhonebookUid UID of the ICC phonebook to cancel the sync request.
+ *
+ * @return KErrNone if the request was cancelled, otherwise returns an error.
+ */
+TInt CSyncEngineServer::DoSynchronisationCancelL(TUid aPhonebookUid)
+ {
+ LOGENGINE1(_L8("CSyncEngineServer::DoSynchronisationCancelL()"));
+
+ if (iSyncContactsWithICC != NULL &&
+ iSyncContactsWithICC->PhonebookUid() == aPhonebookUid)
+ {
+ //
+ // Cancel the Active Object which is used to sync the ICC.
+ // We call DoCancel() rather than Cancel() for two reasons:
+ //
+ // 1) It allows the cancel to be asynchronous, which is important
+ // for TSY requests that may take a long time.
+ //
+ // 2) It ensures the RunL is called which will call the complete
+ // function and hence pass the request completion to the client.
+ //
+ iSyncContactsWithICC->DoCancel();
+ }
+
+ return(KErrNone);
+ } // CSyncEngineServer::DoSynchronisationCancelL
+
+
+/**
+ * Cancel a previous delete request.
+ *
+ * @param aPhonebookUid UID of the ICC phonebook to cancel the delete request.
+ *
+ * @return KErrNone if the request was cancelled, otherwise returns an error.
+ */
+TInt CSyncEngineServer::DeleteCntFromICCCancelL(TUid aPhonebookUid)
+ {
+ LOGENGINE2(_L8("DeleteCntFromICCCancelL(0x%08x)"), aPhonebookUid);
+
+ if (iDeleteContactFromICC != NULL &&
+ iDeleteContactFromICC->PhonebookUid() == aPhonebookUid)
+ {
+ //
+ // Cancel the Active Object which is used to delete the ICC entry.
+ // We call DoCancel() rather than Cancel() for two reasons:
+ //
+ // 1) It allows the cancel to be asynchronous, which is important
+ // for TSY requests that may take a long time.
+ //
+ // 2) It ensures the RunL is called which will call the complete
+ // function and hence pass the request completion to the client.
+ //
+ iDeleteContactFromICC->DoCancel();
+ }
+
+ return(KErrNone);
+ } // CSyncEngineServer::DeleteCntFromICCCancelL
+
+
+/**
+ * Cancel a previous write request.
+ *
+ * @param aPhonebookUid UID of the ICC phonebook to cancel the write request.
+ *
+ * @return KErrNone if the request was cancelled, otherwise returns an error.
+ */
+TInt CSyncEngineServer::WriteCntToICCCancelL(TUid aPhonebookUid)
+ {
+ LOGENGINE2(_L8("WriteCntToICCCancelL(0x%08x)"), aPhonebookUid);
+
+ if (iWriteContactToICC != NULL &&
+ iWriteContactToICC->PhonebookUid() == aPhonebookUid)
+ {
+ //
+ // Cancel the Active Object which is used to write the ICC entry.
+ // We call DoCancel() rather than Cancel() for two reasons:
+ //
+ // 1) It allows the cancel to be asynchronous, which is important
+ // for TSY requests that may take a long time.
+ //
+ // 2) It ensures the RunL is called which will call the complete
+ // function and hence pass the request completion to the client.
+ //
+ iWriteContactToICC->DoCancel();
+ }
+
+ return(KErrNone);
+ } // CSyncEngineServer::WriteCntToICCCancelL
+
+
+/**
+ * Connect to the ETel Sever, obtains the name of the currently selected TSY
+ * and then load the TSY.
+ *
+ * @return KErrNone if connected successfully, otherwise return error.
+ */
+void CSyncEngineServer::ConnectToEtelL()
+ {
+ LOGENGINE1(_L8("ConnectToEtelL()"));
+
+ //
+ // Obtain the name of the currently selected TSY...
+ //
+#ifdef SYMBIAN_NON_SEAMLESS_NETWORK_BEARER_MOBILITY
+ CMDBSession* db = CMDBSession::NewLC(KCDVersion1_2);
+#else
+ CMDBSession* db = CMDBSession::NewLC(KCDVersion1_1);
+#endif
+
+ CMDBField<TUint32>* globalSettingField = new(ELeave) CMDBField<TUint32>(KCDTIdModemPhoneServicesSMS);
+ CleanupStack::PushL(globalSettingField);
+
+ globalSettingField->SetRecordId(1);
+ globalSettingField->LoadL(*db);
+ TUint32 modemId = *globalSettingField;
+
+ CMDBField<TDesC>* tsyField = new(ELeave) CMDBField<TDesC>(KCDTIdTsyName);
+ CleanupStack::PushL(tsyField);
+
+ tsyField->SetRecordId(modemId);
+ TRAPD(err, tsyField->LoadL(*db));
+ if (err != KErrNone)
+ {
+ LOGENGINE1(_L8("Unable to get default TSY"));
+ }
+ User::LeaveIfError(err);
+
+ TBuf<KCommsDbSvrMaxFieldLength> tsyName;
+ tsyName = *tsyField;
+
+ CleanupStack::PopAndDestroy(3, db); // db, tsyField & globalSettingField
+
+ TInt ret(iEtelServer.Connect()); // First connect to the ETel server
+ if(ret==KErrNone)
+ {
+ LOGENGINE1(_L8("Loading TSY")); // Now load the TSY
+ ret=iEtelServer.LoadPhoneModule(tsyName);
+ RTelServer::TPhoneInfo phoneInfo;
+ if(ret==KErrNone)
+ {
+ // Determine if TSY supports V2 functionality
+ // in event of a problem here assume that it does not
+ ret = iEtelServer.IsSupportedByModule(tsyName, KETelExtMultimodeV2, iIsV2Tsy);
+ if (ret != KErrNone)
+ {
+ iIsV2Tsy = EFalse;
+ }
+
+ TInt phoneIndex(0);
+ iEtelServer.EnumeratePhones(phoneIndex); // Get total number of phones supported by all currently loaded TSY modules
+ while(phoneIndex-->0)
+ {
+ TName searchTsyName;
+ // Check whether this phone belongs to loaded TSY
+ if((iEtelServer.GetTsyName(phoneIndex,searchTsyName)==KErrNone) && (searchTsyName.CompareF(tsyName)==KErrNone))
+ break;
+ }
+ iEtelServer.GetPhoneInfo(phoneIndex,phoneInfo); // Get information associated with specified phone
+
+ LOGENGINE1(_L8("Open the phone"));
+ ret = iPhone.Open(iEtelServer,phoneInfo.iName); // Open and intialise the phone
+ if (ret!=KErrNone)
+ {
+ LOGENGINE2(_L8("Open phone failed (ret=%d)"), ret);
+ }
+
+ ret = iEtelServer.SetExtendedErrorGranularity(RTelServer::EErrorExtended);
+ if (ret!=KErrNone)
+ {
+ LOGENGINE2(_L8("Cannot request Extended Errors (ret=%d)"), ret);
+ }
+ }
+ else
+ {
+ LOGENGINE2(_L8("Could not load the TSY (ret=%d)"), ret);
+ }
+ }
+ else
+ {
+ LOGENGINE2(_L8("Could not connect to ETel (ret=%d)"), ret);
+ }
+
+ User::LeaveIfError(ret);
+ } // CSyncEngineServer::ConnectToEtelL
+
+
+/**
+ * Append additional field types according to textual alpha tags.
+ * The field will contain next types:
+ * TEL {HOME|WORK} {VOICE|CELL|FAX|....}
+ *
+ * @param aTextTag String that is supposed to contain tags.
+ * @param aCurrField Pointer to the contact item field to which optional
+ * types will be added.
+ */
+void CSyncEngineServer::AssignAlphaTagsToFieldTypeL(const TDesC16 &aTextTag,
+ CContactItemField* aCurrField)
+{
+ //
+ // Exit immediately if there is no field pointer value...
+ //
+ if (aCurrField == NULL)
+ {
+ return;
+ }
+
+ TFieldType alphaTagUID(KUidContactFieldVCardMapHOME); // Assume HOME by default
+
+ CSyncContactICCEntry::TSyncEntryName textTag(aTextTag);
+ textTag.UpperCase(); // convert text tag(s) to upper case, because later we will use KVersitParam* constants from "cntdef.h"
+
+ //-- try to find out the main type of the phone (WORK/HOME). Assume HOME by default
+ if(textTag.Find(KVersitParamWork) >= 0)
+ alphaTagUID = KUidContactFieldVCardMapWORK; //-- found WORK tag, assume the work phone.
+
+ if (!aCurrField->ContentType().ContainsFieldType(alphaTagUID))
+ {
+ aCurrField->AddFieldTypeL(alphaTagUID); //-- append field type WORK/HOME
+ }
+
+ //-- now try to find more additional tags VOICE/FAX/CELL etc. Assume nothing by default.
+ alphaTagUID = TUid::Null();
+
+ if (textTag.Find(KVersitParamMsg) >= 0)
+ {
+ alphaTagUID = KUidContactFieldVCardMapMSG;
+ }
+ else if (textTag.Find(KVersitParamVoice) >= 0)
+ {
+ alphaTagUID = KUidContactFieldVCardMapVOICE;
+ }
+ else if (textTag.Find(KVersitParamFax) >= 0)
+ {
+ alphaTagUID = KUidContactFieldVCardMapFAX;
+ }
+ else if (textTag.Find(KVersitParamPref) >= 0)
+ {
+ alphaTagUID = KUidContactFieldVCardMapPREF;
+ }
+ else if (textTag.Find(KVersitParamCell) >= 0)
+ {
+ alphaTagUID = KUidContactFieldVCardMapCELL;
+ }
+ else if (textTag.Find(KVersitParamPager) >= 0)
+ {
+ alphaTagUID = KUidContactFieldVCardMapPAGER;
+ }
+ else if (textTag.Find(KVersitParamBbs) >= 0)
+ {
+ alphaTagUID = KUidContactFieldVCardMapBBS;
+ }
+ else if (textTag.Find(KVersitParamModem) >= 0)
+ {
+ alphaTagUID = KUidContactFieldVCardMapMODEM;
+ }
+ else if (textTag.Find(KVersitParamCar) >= 0)
+ {
+ alphaTagUID = KUidContactFieldVCardMapCAR;
+ }
+ else if (textTag.Find(KVersitParamIsdn) >= 0)
+ {
+ alphaTagUID = KUidContactFieldVCardMapISDN;
+ }
+ else if (textTag.Find(KVersitParamVideo) >= 0)
+ {
+ alphaTagUID = KUidContactFieldVCardMapVIDEO;
+ }
+
+ if (alphaTagUID != TUid::Null())
+ {
+ //
+ // Append additional field type...
+ //
+ if (!aCurrField->ContentType().ContainsFieldType(alphaTagUID))
+ {
+ aCurrField->AddFieldTypeL(alphaTagUID);
+ }
+ }
+ } // CSyncEngineServer::AssignAlphaTagsToFieldTypeL
+
+
+/**
+ * Decide whether the entry needs to be added to the contacts database or
+ * the existing one needs to be updated by comparing it to the one already
+ * stored in the database.
+ *
+ * Work out the write action required for this entry.
+ *
+ * There are 3 possibilities when searching for this item in the lookup table:
+ * 1 - item is not found - needs to be added
+ * 2 - item is found and identical - no action required
+ * 3 - item is found and different - needs to be updated
+ *
+ *
+ * Create an CContactICCEntry using the data provided by aContactItem and then
+ * write the entry to the Contacts Database.
+ *
+ * If it is a new entry then create an CContactICCEntry using the data provided
+ * by aContactItem and then write to the Contacts Database. Otherwise edit the
+ * existing ICC contact item and commit the changes to the database.
+ *
+ * If the entry is hidden it will be stored in the contacts database, but the
+ * server will also set the contact item's hidden attribute.
+ *
+ * This means that the item will not be displayed if the view definition
+ * excludes hidden fields.
+ *
+ * @param aICCEntry Phonebook Server internal format for ICC Entry
+ *
+ * @return Contacts ID if operation was successful, otherwise a NULL ID.
+ */
+TContactItemId CSyncEngineServer::WriteICCContactToDBL(CSyncContactICCEntry& aICCEntry)
+ {
+ LOGENGINE2(_L8("WriteICCContactToDBL(): 0x%08x"), aICCEntry.iPhonebookUid);
+
+ //
+ // Check if the ID does not yet exist, or is identical, to see what needs
+ // to be done.
+ //
+ TInt result;
+
+ result = iPhonebookManager.GetContactIdFromSlotNum(aICCEntry.iPhonebookUid,
+ aICCEntry.iSlotNum,
+ aICCEntry.iContactId);
+ if (result != KErrNone && result != KErrNotFound)
+ {
+ User::Leave(result);
+ }
+
+ if (result == KErrNotFound)
+ {
+ //
+ // The contact doesn't exist, we will continue and add it...
+ //
+ LOGENGINE2(_L8("WriteICCContactToDBL(): Slot %d add"), aICCEntry.iSlotNum);
+ aICCEntry.iContactId = KNullContactId;
+ }
+ else if (EntriesIdenticalL(aICCEntry, aICCEntry.iContactId))
+ {
+ //
+ // The contact exists, and is identical so there is nothing to do. We
+ // can return now...
+ //
+ LOGENGINE2(_L8("WriteICCContactToDBL(): Slot %d nothing to do"), aICCEntry.iSlotNum);
+
+ return aICCEntry.iContactId;
+ }
+ else
+ {
+ //
+ // The entry needs to be updated. In this case, we will delete it now and then
+ // continue and add it again (which is easier than clearing out all the fields
+ // and lists etc.)...
+ //
+ LOGENGINE2(_L8("WriteICCContactToDBL(): Slot %d delete and add"), aICCEntry.iSlotNum);
+
+ iDb->DeleteContactL(aICCEntry.iContactId);
+ aICCEntry.iContactId = KNullContactId;
+ }
+
+ //
+ // Get the template and group IDs...
+ //
+ TContactItemId templateId;
+ TContactItemId groupId;
+
+ User::LeaveIfError(iPhonebookManager.GetTemplateId(aICCEntry.iPhonebookUid, templateId));
+ User::LeaveIfError(iPhonebookManager.GetGroupId(aICCEntry.iPhonebookUid, groupId));
+
+ //
+ // Create template for ICC contacts items...
+ //
+ CContactItem* iccTemplate = iDb->ReadContactL(templateId);
+ CleanupStack::PushL(iccTemplate);
+
+ CContactICCEntry* item = CContactICCEntry::NewL(*iccTemplate);
+ CleanupStack::PopAndDestroy(iccTemplate);
+ CleanupStack::PushL(item);
+
+ //
+ // Create phone number field(s)
+ //
+
+ // Default number
+ if (aICCEntry.iNumber.Length() != 0)
+ {
+ TBuf<RMobilePhone::KMaxMobileTelNumberSize> number;
+ if ((aICCEntry.iTON==RMobilePhone::EInternationalNumber) && (aICCEntry.iNumber[0] != KEngineInternationalPrefix()[0]))
+ {
+ number.Append(KEngineInternationalPrefix); // Append '+' prefix if International Number
+ }
+ number.Append(aICCEntry.iNumber);
+ AddTextFieldToIccContactL(KStorageTypeText, KUidContactFieldPhoneNumber, KUidContactFieldVCardMapTEL, number, item, 0);
+ }
+
+ // Check whether this is hidden entry and set its hidden attributes
+ if (aICCEntry.iIsHidden)
+ {
+ item->SetHidden(ETrue);
+ }
+
+ // Additional numbers
+ TInt count(aICCEntry.iNumberList->Count());
+ for (TInt i=0; i<count; ++i)
+ {
+ CSyncContactICCEntry::TSyncAdditionalNumber additionalNum(aICCEntry.iNumberList->At(i));
+
+ // Actual number
+ TBuf<RMobilePhone::KMaxMobileTelNumberSize> number;
+ if((additionalNum.iTON==RMobilePhone::EInternationalNumber) && (additionalNum.iNumber[0] != KEngineInternationalPrefix()[0]))
+ {
+ number.Append(KEngineInternationalPrefix); // Append '+' prefix if International Number
+ }
+ number.Append(additionalNum.iNumber);
+
+ //-- add or modify existing text field in CContactICCEntry* item fieldset
+ CContactItemField *pCurrField =
+ AddTextFieldToIccContactL(KStorageTypeText,
+ KUidContactFieldPhoneNumber,
+ KUidContactFieldVCardMapTEL,
+ number,
+ item,
+ i + 1); // Here, 1 is used to distinguish the
+ // default number and additional number.
+ // The reason is that they share the
+ // same field type (see comments in
+ // method AddTextFieldToIccContactL).
+
+
+ //-- append additional field type to the current field if any.
+ //-- this field type is obtained from additional number alpha tag
+ if(pCurrField)
+ {
+ AssignAlphaTagsToFieldTypeL(additionalNum.iNumberString, pCurrField);
+ }
+ }
+
+ // Create name field
+ if (aICCEntry.iName.Length() > 0)
+ {
+ AddTextFieldToIccContactL(KStorageTypeText, KUidContactFieldFamilyName, KUidContactFieldVCardMapUnusedN, aICCEntry.iName, item, 0);
+ }
+
+ // Create second name field
+ if (aICCEntry.iSecondName.Length() > 0)
+ {
+ AddTextFieldToIccContactL(KStorageTypeText, KUidContactFieldSecondName, KUidContactFieldVCardMapSECONDNAME, aICCEntry.iSecondName, item, 0);
+ }
+
+ // Create group field(s)
+ count = aICCEntry.iGroupList->Count();
+ for(TInt i=0; i<count; ++i)
+ {
+ CSyncContactICCEntry::TSyncEntryName groupField;
+ groupField.Copy(aICCEntry.iGroupList->At(i));
+ AddTextFieldToIccContactL(KStorageTypeText, KUidContactFieldICCGroup, KUidContactFieldVCardMapUnusedN, groupField, item, i);
+ }
+
+ // Create e-mail field(s)
+ count = aICCEntry.iEmailList->Count();
+ for(TInt i=0; i<count; ++i)
+ {
+ CSyncContactICCEntry::TSyncEntryName emailField;
+ emailField.Copy(aICCEntry.iEmailList->At(i));
+ AddTextFieldToIccContactL(KStorageTypeText, KUidContactFieldEMail, KUidContactFieldVCardMapEMAILINTERNET, emailField, item, i);
+ }
+
+ // Create slot number field
+ TBuf<KTemplateFieldLength> buf;
+ buf.AppendNum(aICCEntry.iSlotNum);
+ AddTextFieldToIccContactL(KStorageTypeText, KUidContactFieldICCSlot, KUidContactFieldVCardMapNotRequired, buf, item, 0);
+
+ // Create phonebook type field
+ buf.FillZ();
+ buf.Zero();
+
+ buf.AppendNum(aICCEntry.iPhonebookUid.iUid);
+ AddTextFieldToIccContactL(KStorageTypeText, KUidContactFieldICCPhonebook, KUidContactFieldVCardMapNotRequired, buf, item, 0);
+
+ //
+ // Write the contact to the database...
+ //
+ LOGENGINE1(_L8("WriteICCContactToDBL(): Adding contact to database"));
+
+ iDb->DatabaseBeginL(EFalse); // Start the transaction
+ iIsInTransaction = ETrue;
+
+ aICCEntry.iContactId = iDb->doAddNewContactL(*item, EFalse, ETrue); // Add that new contact to Contact DB
+ CleanupStack::PopAndDestroy(item);
+
+ // Add the contact to the correct group now because during
+ // synchronisation the contacts model can't do it since the
+ // plug-in won't have a connection to the server (and therefore know
+ // which group to add it to).
+ iDb->AddContactToGroupL(aICCEntry.iContactId, groupId, ETrue);
+ CommitIccTransactionL();
+
+ return aICCEntry.iContactId;
+ } // CSyncEngineServer::WriteICCContactToDBL
+
+
+/**
+ * Checks if an ICC entry is the same as one in the database.
+ *
+ * @param aICCEntry CSyncContactICCEntry reference.
+ * @param aId TContactItemId reference.
+ *
+ * @return Boolean stating if entries match.
+ */
+TBool CSyncEngineServer::EntriesIdenticalL(CSyncContactICCEntry& aICCEntry,
+ TContactItemId& aId)
+ {
+ LOGENGINE3(_L8("EntriesIdenticalL(): 0x%08x %d"), aICCEntry.iPhonebookUid,
+ aId);
+
+ //
+ // Get the entry from the contacts database...
+ //
+ CContactItem* contactEntry=iDb->ReadContactLC(aId);
+ CContactItemFieldSet& fieldSet = contactEntry->CardFields();
+
+ // Note: We have already matched the slot number field.
+
+ // Check if the same amount of information is provided.
+ // This will reduce time for comparison when there is a lot of additional
+ // information but a small mismatch in the number of additional fields.
+ TInt index;
+
+ // Obtain number count
+ TInt iccNumCount(aICCEntry.iNumberList->Count() + 1); // first phone number is not in additional number list
+ TInt contactNumCount(0);
+ index = -1;
+ while((index = fieldSet.FindNext(KUidContactFieldPhoneNumber, index+1)) != KErrNotFound)
+ {
+ contactNumCount++;
+ }
+
+ // Obtain group count
+ TInt iccGrpCount(aICCEntry.iGroupList->Count());
+ TInt contactGrpCount(0);
+ index = -1;
+ while((index = fieldSet.FindNext(KUidContactFieldICCGroup, index+1)) != KErrNotFound)
+ {
+ const CContactItemField& testField = fieldSet[index];
+ TPtrC testFieldPtr(testField.TextStorage()->Text());
+ if (testFieldPtr.Length() > 0) // entry for SDN & LND will have group field but it will be empty
+ {
+ contactGrpCount++;
+ }
+ }
+
+ // Obtain email count
+ TInt iccEmailCount(aICCEntry.iEmailList->Count());
+ TInt contactEmailCount(0);
+ index = -1;
+ while((index = fieldSet.FindNext(KUidContactFieldEMail, index+1)) != KErrNotFound)
+ {
+ const CContactItemField& testField = fieldSet[index];
+ TPtrC testFieldPtr(testField.TextStorage()->Text());
+ if (testFieldPtr.Length() > 0) // entry for SDN & LND will have email field but it will be empty
+ {
+ contactEmailCount++;
+ }
+ }
+
+ // Test field counts and exit if these don't match
+ if( (contactNumCount != iccNumCount) ||
+ (contactGrpCount != iccGrpCount) ||
+ (contactEmailCount != iccEmailCount) ||
+ (contactNumCount < 1))
+ {
+ CleanupStack::PopAndDestroy(contactEntry);
+ return EFalse;
+ }
+
+ // Detailed test of first representation of name
+ TInt loop(0);
+ TBool contentMatch(ETrue);
+
+ index = fieldSet.Find(KUidContactFieldFamilyName); // start with family name
+ if (index != KErrNotFound)
+ {
+ const CContactItemField& testField1 = fieldSet[index];
+ TPtrC testFieldPtr1(testField1.TextStorage()->Text());
+ if (testFieldPtr1.Compare(aICCEntry.iName) != 0)
+ {
+ contentMatch = EFalse;
+ }
+ }
+ else if (aICCEntry.iName.Length() > 0)
+ {
+ contentMatch = EFalse;
+ }
+
+ // Detailed test of second representation of name
+ if (contentMatch)
+ {
+ index = fieldSet.Find(KUidContactFieldSecondName); // get second name
+ if (index != KErrNotFound)
+ {
+ const CContactItemField& testField1 = fieldSet[index];
+ TPtrC testFieldPtr1(testField1.TextStorage()->Text());
+ if (testFieldPtr1.Compare(aICCEntry.iSecondName) != 0)
+ {
+ contentMatch = EFalse;
+ }
+ }
+ else if (aICCEntry.iSecondName.Length() > 0)
+ {
+ contentMatch = EFalse;
+ }
+ }
+
+ if (contentMatch)
+ {
+ // Detailed test of phone number information
+ // Note: the first phone number is stored separately from additional numbers
+ // and as a result this loop treats it differently. The loop counter
+ // is adjusted to allow for this number not being in the additional number list
+ index = fieldSet.Find(KUidContactFieldPhoneNumber);
+ for (loop = 0;
+ (loop < iccNumCount) && (index != KErrNotFound) && contentMatch;
+ loop++)
+ {
+ const CContactItemField& testField2 = fieldSet[index];
+ TBuf<RMobilePhone::KMaxMobileTelNumberSize> testFieldPtr2 = testField2.TextStorage()->Text();
+ TBool isInternationalCntNumber(EFalse);
+
+ if (testFieldPtr2.Find(KEngineInternationalPrefix)!=KErrNotFound)
+ {
+ testFieldPtr2 = testFieldPtr2.Mid(1);
+ isInternationalCntNumber = ETrue;
+ }
+
+ // retrieving the number from the ICC entry
+ TBool isInternationalICCNumber;
+ TBuf<RMobilePhone::KMaxMobileTelNumberSize> testFieldPtr5;
+ if (loop == 0) // first phone number is stored separately
+ {
+ testFieldPtr5 = aICCEntry.iNumber;
+ isInternationalICCNumber = (aICCEntry.iTON==RMobilePhone::EInternationalNumber);
+ }
+ else
+ {
+ testFieldPtr5 = aICCEntry.iNumberList->At(loop - 1).iNumber;
+ isInternationalICCNumber = (aICCEntry.iNumberList->At(loop - 1).iTON==RMobilePhone::EInternationalNumber);
+ }
+
+ // Does the ICC number contain a prefix? (apparently, some TSYs are designed to keep it)
+ if (testFieldPtr5.Find(KEngineInternationalPrefix)!=KErrNotFound)
+ {
+ // If it does, strip it
+ testFieldPtr5 = testFieldPtr5.Mid(1);
+ // Also implies that it is international too, regardless of the aICCEntry.iTON flag value
+ isInternationalICCNumber = ETrue;
+ }
+
+ // comparing the numbers
+ if ( (isInternationalCntNumber!=isInternationalICCNumber) ||
+ (testFieldPtr2.Compare(testFieldPtr5) != 0) )
+ {
+ contentMatch = EFalse;
+ }
+ index = fieldSet.FindNext(KUidContactFieldPhoneNumber, index+1); // get next additional number
+ }
+
+ if (contentMatch)
+ {
+ // Detailed test of group information
+ index = fieldSet.Find(KUidContactFieldICCGroup);
+ for ( loop = 0;
+ (loop < iccGrpCount) && (index != KErrNotFound) && contentMatch;
+ loop++)
+ {
+ const CContactItemField& testField3 = fieldSet[index];
+ TPtrC testFieldPtr3(testField3.TextStorage()->Text());
+
+ // Ignore blank group entries...
+ if (testFieldPtr3.Length() == 0)
+ {
+ index = fieldSet.FindNext(KUidContactFieldICCGroup, index+1);
+ loop--;
+ continue;
+ }
+
+ if (testFieldPtr3.Compare(aICCEntry.iGroupList->At(loop)) != 0)
+ {
+ contentMatch = EFalse;
+ }
+ index = fieldSet.FindNext(KUidContactFieldICCGroup, index+1);
+ }
+
+ if (contentMatch)
+ {
+ // Detailed test of Email information
+ index = fieldSet.Find(KUidContactFieldEMail);
+ for (loop = 0;
+ (loop < iccEmailCount) && (index != KErrNotFound) && contentMatch;
+ loop++)
+ {
+ const CContactItemField& testField4 = fieldSet[index];
+ TPtrC testFieldPtr4(testField4.TextStorage()->Text());
+
+ // Ignore blank email entries...
+ if (testFieldPtr4.Length() == 0)
+ {
+ index = fieldSet.FindNext(KUidContactFieldEMail, index+1);
+ loop--;
+ continue;
+ }
+
+ if (testFieldPtr4.Compare(aICCEntry.iEmailList->At(loop)) != 0)
+ {
+ contentMatch = EFalse;
+ }
+ index = fieldSet.FindNext(KUidContactFieldEMail, index+1);
+ }
+ }
+ }
+ }
+
+ // Cleanup and return result
+ CleanupStack::PopAndDestroy(contactEntry);
+
+ return contentMatch;
+ } // CSyncEngineServer::EntriesIdenticalL
+
+
+/**
+ * Commit the current transaction.
+ */
+void CSyncEngineServer::CommitIccTransactionL()
+ {
+ if (iIsInTransaction)
+ {
+ LOGENGINE1(_L8("Commit Icc Transaction"));
+ iDb->DatabaseCommitL(EFalse);
+ iIsInTransaction = EFalse;
+ }
+ } // CSyncEngineServer::CommitIccTransactionL
+
+
+/**
+ * Rollback the current transaction.
+ */
+void CSyncEngineServer::RollbackIccTransaction()
+ {
+ if (iIsInTransaction)
+ {
+ LOGENGINE1(_L8("Rollback Icc Transaction"));
+
+ //
+ // Transaction must be rolled back if a failure occurs otherwise
+ // Contacts Database will become corrupt...
+ //
+ iDb->DatabaseRollback();
+
+ //
+ // Check whether database is damaged and needs to be recovered. This
+ // should never happen...
+ //
+ if (iDb->IsDamaged())
+ {
+ TRAPD(recoverErr, iDb->RecoverL());
+ if (recoverErr == KErrDiskFull)
+ {
+ //
+ // The disk is full, compact the database and check for
+ // damage again. Not much else we can do!
+ //
+ TRAPD(compactErr, iDb->CompactL());
+
+ if (compactErr != KErrNone && iDb->IsDamaged())
+ {
+ TRAPD(recoverErr2, iDb->RecoverL());
+ if (recoverErr2 == KErrDiskFull)
+ {
+ TRAP_IGNORE(iDb->CompactL());
+ }
+ }
+ }
+ }
+
+ //
+ // We're no longer in a transaction...
+ //
+ iIsInTransaction = EFalse;
+ }
+ } // CSyncEngineServer::RollbackIccTransaction
+
+
+/**
+ * Add a new text field (aField) to the CContactICCEntry supplied by aIccEntry.
+ *
+ * @param aType Field Storage type
+ * @param aFieldType Field type
+ * @param aMapping Mapping for the field's content type
+ * @param aField Field data
+ * @param aIccEntry CContactICCEntry item
+ * @param aCount Identifies which instance of field is to be used. Actually
+ * it is an index of an object in one of vectors from
+ * CSyncContactICCEntry class.
+ *
+ * @return Pointer to the current (modified or added) field in
+ * aIccEntry fieldset so that it is possible to get access
+ * to this field later. Can be NULL.
+ */
+CContactItemField* CSyncEngineServer::AddTextFieldToIccContactL(TStorageType aType,
+ TFieldType aFieldType,
+ TUid aMapping,
+ TDesC& aField,
+ CContactICCEntry* aIccEntry,
+ TInt aCount)
+ {
+ CContactItemFieldSet& fieldSet = aIccEntry->CardFields();
+ TInt pos(KErrNotFound);
+ for (TInt i = 0; i <= aCount; i++)
+ {
+ // "pos+1" below provides a new start position for the FindNext.
+ pos = fieldSet.FindNext(aFieldType, pos + 1);
+ if (pos == KErrNotFound)
+ break;
+ }
+
+ CContactItemField *pCurrField = NULL; // pointer to the current field in fieldset
+
+ if (pos!=KErrNotFound) // Field already present. Note, Contacts model reads all fields
+ // in template and adds them as empty fields in ICC item
+ {
+ // If the "aCount" identified instance field already exists in the "fieldSet",
+ // then update it.
+
+ CContactItemField& field=fieldSet[pos];
+ field.TextStorage()->SetTextL(aField);
+
+ pCurrField = &field;
+ }
+ else
+ {
+ // If there is no field in the "fieldSet" whose type is the given "aFieldType",
+ // then create a new field and add it into the "fieldSet".
+ // Or
+ // If the "aCount" identified instance field does not exist in the "fieldSet",
+ // then create a new field and add it into the "fieldSet".
+
+ CContactItemField* field=CContactItemField::NewLC(aType, aFieldType);
+ field->SetMapping(aMapping);
+ field->AddFieldTypeL(aFieldType); // Appends a field type to the field's content type
+ field->TextStorage()->SetTextL(aField);
+ aIccEntry->AddFieldL(*field);
+ CleanupStack::Pop(field); // No need to destroy it since contact item takes ownership of field
+
+ pCurrField = field;
+ }
+
+ return pCurrField;
+ } // CSyncEngineServer::AddTextFieldToIccContactL
+
+
+/**
+ * Create a new client session.
+ */
+CSession2* CSyncEngineServer::NewSessionL(const TVersion& /*aVersion*/,
+ const RMessage2& /*aMessage*/) const
+ {
+ LOGENGINE1(_L8("CSyncEngineServer::NewSessionL"));
+
+ //
+ // Only one session connection is allowed!!!
+ //
+ if (iConnectedSession != NULL)
+ {
+ User::Leave(KErrPermissionDenied);
+ }
+
+ return new(ELeave) CSyncEngineSession();
+ } // CSyncEngineServer::NewSessionL
+
+
+/**
+ * Called when a new session is being created.
+ *
+ * @param aSession Server side session.
+ */
+void CSyncEngineServer::AddSessionL(CSyncEngineSession* aSession)
+ {
+ LOGENGINE1(_L8("CSyncEngineServer::AddSession"));
+
+ //
+ // Store the session pointer...
+ //
+ iConnectedSession = aSession;
+
+ //
+ // Queue an Active Object to configure the engine straight after this
+ // session is created.
+ //
+ if (iPhoneBookSyncEngineStarter == NULL)
+ {
+ iPhoneBookSyncEngineStarter = new (ELeave) CPhoneBookSyncEngineStarter(*this);
+ iPhoneBookSyncEngineStarter->Call();
+ }
+ } // CSyncEngineServer::AddSessionL
+
+
+/**
+ * Called when a session is being destroyed.
+ */
+void CSyncEngineServer::DropSession(CSyncEngineSession* /*aSession*/)
+ {
+ LOGENGINE1(_L8("CSyncEngineServer::DropSession"));
+
+ iConnectedSession = NULL;
+ TRAP_IGNORE(UnconfigureEngineL());
+
+ CActiveScheduler::Stop();
+ } // CSyncEngineServer::DropSession
+
+
+/**
+ * Standard Active Object RunError() method, called when the RunL() method
+ * leaves, which will be when the CPhoneBookSession::ServiceL() leaves.
+ *
+ * Find the current message and complete it before restarting the server.
+ *
+ * @param aError Leave code from CPhoneBookSession::ServiceL().
+ *
+ * @return KErrNone
+ */
+TInt CSyncEngineServer::RunError(TInt aError)
+ {
+ LOGENGINE2(_L8("CSyncEngineServer::RunError %d"),aError);
+
+ //
+ // Complete the request with the available error code.
+ //
+ if (Message().IsNull() == EFalse)
+ {
+ Message().Complete(aError);
+ }
+
+ //
+ // The leave will result in an early return from CServer::RunL(), skipping
+ // the call to request another message. So do that now in order to keep the
+ // server running.
+ //
+ ReStart();
+
+ return KErrNone;
+ } // CSyncEngineServer::RunError
+
+
+/**
+ * This method begins the completion of a synchronisation operation. It is
+ * called when the CSyncContactsWithICC Active Object has finished its task.
+ *
+ * @param aRetVal Complete-request error code.
+ */
+void CSyncEngineServer::CompleteDoSync(TInt aRetVal)
+ {
+ TUid phonebookUid = iSyncContactsWithICC->PhonebookUid();
+
+ LOGENGINE3(_L8("CompleteDoSync(%d): 0x%08x"), aRetVal, phonebookUid);
+
+ //
+ // Store the result of the synchronisation operation...
+ //
+ if (aRetVal == KErrNone)
+ {
+ iPhonebookManager.SetLastSyncError(phonebookUid, KErrNone);
+ iPhonebookManager.SetSyncState(phonebookUid,
+ RPhoneBookSession::ECacheValid);
+ }
+ else if (aRetVal == KErrCancel)
+ {
+ iPhonebookManager.SetLastSyncError(phonebookUid, KErrCancel);
+ iPhonebookManager.SetSyncState(iSyncContactsWithICC->PhonebookUid(),
+ RPhoneBookSession::EUnsynchronised);
+ }
+ else
+ {
+ iPhonebookManager.SetLastSyncError(phonebookUid, aRetVal);
+ iPhonebookManager.SetSyncState(phonebookUid,
+ RPhoneBookSession::EErrorDuringSync);
+ }
+
+ //
+ // For debug purposes print out the new Look Up Table for this phonebook...
+ //
+#ifdef _DEBUG
+ iPhonebookManager.LogLookUpTable(iSyncContactsWithICC->PhonebookUid());
+#endif
+
+ //
+ // Complete this request and release the Active Object's memory...
+ //
+ iConnectedSession->CompleteRequest(iSyncContactsWithICC->ClientMessage(),
+ aRetVal);
+
+ delete iSyncContactsWithICC;
+ iSyncContactsWithICC = NULL;
+ } // CSyncEngineServer::CompleteDoSync
+
+
+/**
+ * Create and install the active scheduler.
+ */
+CSyncEngineScheduler* CSyncEngineScheduler::New()
+ {
+ LOGENGINE1(_L8("CSyncEngineScheduler::New()"));
+
+ CSyncEngineScheduler* scheduler = new CSyncEngineScheduler;
+
+ if (scheduler != NULL)
+ {
+ CSyncEngineScheduler::Install(scheduler);
+ }
+
+ return scheduler;
+ } // CSyncEngineScheduler::New
+
+
+/**
+ * Called if any RunL() method leaves.
+ */
+void CSyncEngineScheduler::Error(TInt aError) const
+ {
+#ifdef _DEBUG
+ LOGENGINE2(_L8("CSyncEngineScheduler::Error(%d)"), aError);
+#else
+ (void) aError;
+#endif
+
+ PhBkSyncPanic(EPhBkSyncPanicUnexpectedLeave);
+ } // CSyncEngineScheduler::Error
+
+
+/**
+ * Standard constructor.
+ *
+ * @param aEngine Reference to the engine.
+ */
+CPhoneBookSyncEngineStarter::CPhoneBookSyncEngineStarter(CSyncEngineServer& aEngine)
+ : CAsyncOneShot(EPriorityHigh),
+ iEngine(aEngine)
+ {
+ // NOP
+ } // CPhoneBookSyncEngineStarter::CPhoneBookSyncEngineStarter
+
+
+/**
+ * RunL() for the starter object. This configures the engine fully or
+ * shuts it down.
+ */
+void CPhoneBookSyncEngineStarter::RunL()
+ {
+ LOGENGINE2(_L8("CPhoneBookSyncEngineStarter::RunL(): iStatus=%d."), iStatus.Int());
+
+ //
+ // Configure the engine...
+ //
+ TRAPD(configErr, iEngine.ConfigureEngineL());
+ if (configErr != KErrNone)
+ {
+ LOGENGINE2(_L8("ConfigureEngineL() failed with error %d."), configErr);
+
+ //
+ // Shutdown the engine in this case, so it can be restarted later.
+ //
+ TRAP_IGNORE(iEngine.UnconfigureEngineL());
+ CActiveScheduler::Stop();
+ }
+ } // CPhoneBookSyncEngineStarter::RunL
+