// Copyright (c) 2007-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:
//
#include "cntsyncchecker.h"
#include "cntsyncphonedata.h"
#include <cntdef.h>
#include <cntdb.h>
#include "cntsyncdata.h"
#include <centralrepository.h> // CRepository.
#include <e32property.h>
#include <phbksync.h>
//---------------------------------------------------
CContactSyncPhonebookData* CContactSyncPhonebookData::NewL(TUint32& aCRKey, CRepository* aRepository)
{
TUid temp;
temp.iUid = 0;
CContactSyncPhonebookData* self = new(ELeave) CContactSyncPhonebookData(temp, aRepository);
self->InternaliseFromCRL(aCRKey);
return self;
}
CContactSyncPhonebookData* CContactSyncPhonebookData::NewLC(TUid aPhonebookUid, CRepository* aRepository)
{
CContactSyncPhonebookData* self = new(ELeave) CContactSyncPhonebookData(aPhonebookUid, aRepository);
CleanupStack::PushL(self);
return self;
}
CContactSyncPhonebookData::CContactSyncPhonebookData(TUid aPhonebookUid, CRepository* aRepository)
: iPhonebookUid(aPhonebookUid), iPhonebookTemplateId(KNullContactId), iPhonebookGroupId(KNullContactId), iRepository(aRepository)
{
}
const TDesC& CContactSyncPhonebookData::TemplateLabel()
{
_LIT(KPhbkTemplateADN,"SIM Card Contacts ADN"); // should be in a resource file for localisation really ;)
_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");
/* Some Contacts test code used to set group names
_LIT(KGlobalAdnGroupName,"Global Adn Group");
_LIT(KGlobalSdnGroupName,"Global Sdn Group");
_LIT(KGlobalLdnGroupName,"Global Lnd Group");
_LIT(KUsimAppAdnGroupName,"Usim App Adn Group");
*/
switch (iPhonebookUid.iUid)
{
case KUidIccGlobalAdnPhonebookValue:
return KPhbkTemplateADN;
case KUidIccGlobalSdnPhonebookValue:
return KPhbkTemplateSDN;
case KUidIccGlobalLndPhonebookValue:
return KPhbkTemplateLND;
case KUidUsimAppAdnPhonebookValue:
return KPhbkTemplateUSimApp;
case KUidIccGlobalFdnPhonebookValue:
return KPhbkTemplateFDN;
default:
break;
}
return KPhbkTemplateNotSpecified;
}
CContactSyncPhonebookData::~CContactSyncPhonebookData()
{
delete iIccTemplate;
iStatusArray.Close();
iPhonebookContacts.ResetAndDestroy();
}
void CContactSyncPhonebookData::AddPhonebookContactL(const TDesC& aName, const TDesC& aNumber)
{
iPhonebookContacts.AppendL(CPhonebookContact::NewLC(aName, aNumber, iRepository));
CleanupStack::Pop(); // CPhonebookContact
}
TInt CContactSyncPhonebookData::SynchronisePhonebook(CContactDatabase& aDb, TInt aCompletionError, TInt aLeaveError)
{
TInt error(KErrNone);
__ASSERT_DEBUG(iIsSynchronised == EFalse, User::Invariant());
if ((aCompletionError == KErrNone) && (aLeaveError == KErrNone))
{
// Validate any template ID remembered from previous test
if ((iPhonebookTemplateId != KNullContactId) && // if value has not been set
(iPhonebookTemplateId != KGoldenTemplateId) ) // internally initialised value by cntmodel
{
TRAP(error, ValidateTemplateIdAndLabelL(aDb));
if (error)
{
if (error != KErrNotFound)
{
return error;
}
iPhonebookTemplateId = KNullContactId;
}
}
// Need to create a new template?
if ((iPhonebookTemplateId == KNullContactId) || // if value has not been set
(iPhonebookTemplateId == KGoldenTemplateId)) // internally initialised value by cntmodel
{
if (iIccTemplate)
{
delete iIccTemplate;
iIccTemplate = NULL;
}
TRAP(error, CreateTemplateIdL(aDb)); // First create Template ID
if (error == KErrNone)
{
// cache template
TRAP(error, iIccTemplate = aDb.ReadContactL(iPhonebookTemplateId));
}
if (error)
{
return error;
}
}
// Validate any group ID remembered from previouzs test
if ((iPhonebookGroupId != KNullContactId) && // if value has not been set
(iPhonebookGroupId != KGoldenTemplateId) ) // internally initialised value by cntmodel
{
TRAP(error, ValidateGroupIdAndTemplateL(aDb));
if (error)
{
if (error != KErrNotFound)
{
return error;
}
iPhonebookGroupId = KNullContactId;
}
}
if ((iPhonebookGroupId == KNullContactId) || // if value has not been set
(iPhonebookGroupId == KGoldenTemplateId) ) // internally initialised value by cntmodel
{
// Now create group ID for this phonebook
TRAP(error, CreateGroupIdL(aDb));
}
if (error == KErrNone && iPhonebookContacts.Count() > 0)
{
TRAP(error, SynchroniseContactsL(aDb));
}
if (error)
{
return error;
}
// successfully synchronised
iIsSynchronised = ETrue;
}
CompleteNotificationRequest(aCompletionError);
iSynchronisedLeaveCode = aLeaveError;
// simulated synchronisation completed
return KErrNone;
}
void CContactSyncPhonebookData::ValidateTemplateIdAndLabelL(CContactDatabase& aDb)
{
CContactItem* item = aDb.ReadContactLC(iPhonebookTemplateId);
// The following test confirms if a template ID relates to this phonebook's
// template by checking the label employed.
if ((item->Type() != KUidContactCardTemplate) ||
(static_cast<CContactCardTemplate*>(item)->GetTemplateLabelL() != TemplateLabel()))
{
iPhonebookTemplateId = KNullContactId;
}
CleanupStack::PopAndDestroy(item);
}
void CContactSyncPhonebookData::ValidateGroupIdAndTemplateL(CContactDatabase& aDb)
{
CContactGroup* group = static_cast<CContactGroup*> (aDb.ReadContactL(iPhonebookGroupId));
CleanupStack::PushL(group);
// check that contact id refers to a group
if (group->Type() == KUidContactGroup)
{
// Retrieve the first entry in the group, and check that entry's template ID
CContactIdArray* itemList = group->ItemsContainedLC();
if (itemList->Count() > 0)
{
CContactItem* groupItem = aDb.ReadContactLC((*itemList)[0]);
if (groupItem)
{
if (groupItem->TemplateRefId() != iPhonebookTemplateId)
{
// wrong group
iPhonebookGroupId = KNullContactId;
}
CleanupStack::PopAndDestroy(groupItem);
}
}
CleanupStack::PopAndDestroy(itemList);
}
else
{
// id is not really a group
iPhonebookGroupId = KNullContactId;
}
CleanupStack::PopAndDestroy(group);
}
/**
Create Template UID for the phonebook.
(Beware - can leave partially created Template)
@param aDb Handle to the contacts database.
*/
void CContactSyncPhonebookData::CreateTemplateIdL(CContactDatabase &aDb)
{
__ASSERT_DEBUG((iPhonebookTemplateId == KNullContactId || iPhonebookTemplateId == KGoldenTemplateId), User::Invariant());
// First check if there is an existing template in the contact database for this phonebook
CContactIdArray* idList = aDb.GetCardTemplateIdListL();
if (idList)
{
CleanupStack::PushL(idList);
const TInt idListCount = idList->Count();
if (idListCount > 0)
{
TInt i;
for (i = 0; i < idListCount; i++)
{
CContactCardTemplate* item = static_cast<CContactCardTemplate*> (aDb.ReadContactLC((*idList)[i]));
if (item->GetTemplateLabelL() == TemplateLabel())
{
iPhonebookTemplateId = (*idList)[i];
i = idListCount; // force loop to exit
}
CleanupStack::PopAndDestroy(item);
}
}
CleanupStack::PopAndDestroy(idList);
}
// If no suitable template been found create a new one
if (iPhonebookTemplateId == KNullContactId ||
iPhonebookTemplateId == KGoldenTemplateId)
{
// "Creating template for this phonebook"
CContactItem* newTemplate = aDb.CreateContactCardTemplateLC(TemplateLabel());
TContactItemId templateId = newTemplate->Id();
CleanupStack::PopAndDestroy(newTemplate);
// Remove all the unnecessary fields
newTemplate = aDb.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->SetLabelL(_L("Name"));
name->SetMapping(KUidContactFieldVCardMapUnusedN);
newTemplate->AddFieldL(*name);
CleanupStack::Pop(name);
// Add second name field
CContactItemField* secondName = CContactItemField::NewLC(KStorageTypeText, KUidContactFieldSecondName);
secondName->SetLabelL(_L("Additional Name"));
secondName->SetMapping(KUidContactFieldVCardMapSECONDNAME);
secondName->SetUserFlags(EContactCategoryHome);
newTemplate->AddFieldL(*secondName);
CleanupStack::Pop(secondName);
// Add default number field
CContactItemField* number = CContactItemField::NewLC(KStorageTypeText, KUidContactFieldPhoneNumber);
number->SetLabelL(_L("Phone Number"));
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->SetLabelL(_L("Slot"));
slotnum->SetMapping(KUidContactFieldVCardMapNotRequired);
newTemplate->AddFieldL(*slotnum);
CleanupStack::Pop(slotnum);
// Add Phonebook type field
CContactItemField* phonebook = CContactItemField::NewLC(KStorageTypeText, KUidContactFieldICCPhonebook);
phonebook->SetLabelL(_L("Phonebook UID"));
phonebook->SetMapping(KUidContactFieldVCardMapNotRequired);
newTemplate->AddFieldL(*phonebook);
CleanupStack::Pop(phonebook);
// presume this is a 3G ICC so there are additional fields for ADN and USIM App phonebooks
if((iPhonebookUid.iUid == KUidIccGlobalAdnPhonebookValue) ||
(iPhonebookUid.iUid == KUidUsimAppAdnPhonebookValue))
{
// Add e-mail field
CContactItemField* emailField = CContactItemField::NewLC(KStorageTypeText, KUidContactFieldEMail);
emailField->SetLabelL(_L("Email"));
emailField->SetMapping(KUidContactFieldVCardMapEMAILINTERNET);
emailField->AddFieldTypeL(KUidContactFieldVCardMapWORK);
emailField->SetUserFlags(EContactCategoryOther);
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->SetLabelL(_L("Group"));
group->SetMapping(KUidContactFieldVCardMapUnusedN);
newTemplate->AddFieldL(*group);
CleanupStack::Pop(group);
}
// Now that we know nothing as left, assign member variables (this avoids member variables being left in a bad state in the event of a leave).
iPhonebookTemplateId = templateId;
aDb.CommitContactL(*newTemplate);
CleanupStack::PopAndDestroy(2); // newTemplate plus locked record
}
}
/**
Create Group UID for the phonebook.
@param aDb Handle to the contacts database.
*/
void CContactSyncPhonebookData::CreateGroupIdL(CContactDatabase &aDb)
{
__ASSERT_DEBUG((iPhonebookGroupId == KNullContactId ||
iPhonebookGroupId == KGoldenTemplateId), User::Invariant());
// First check if there is an existing group in the contact database for this phonebook
CContactIdArray* idList = aDb.GetGroupIdListL();
if (idList)
{
CleanupStack::PushL(idList);
const TInt idListCount = idList->Count();
if (idListCount > 0)
{
TInt i;
for (i = 0; i < idListCount; i++)
{
// Retrieve the first entry in each group, and check that entry's template ID
CContactGroup* group = static_cast<CContactGroup*> (aDb.ReadContactLC((*idList)[i]));
CContactIdArray* itemList = group->ItemsContainedLC();
if (itemList->Count() > 0)
{
CContactItem* groupItem = aDb.ReadContactLC((*itemList)[0]);
if (groupItem->TemplateRefId() == iPhonebookTemplateId)
{
iPhonebookGroupId = (*idList)[i];
i = idListCount; // force exit from loop
}
CleanupStack::PopAndDestroy(groupItem);
}
CleanupStack::PopAndDestroy(2, group); // itemList, group
}
}
CleanupStack::PopAndDestroy(idList);
}
// If no suitable group has been found create a new one
if (iPhonebookGroupId==KNullContactId ||
iPhonebookGroupId==KGoldenTemplateId)
{
CContactItem* group = aDb.CreateContactGroupLC(KNullDesC);
iPhonebookGroupId = group->Id();
CleanupStack::PopAndDestroy(group);
}
}
void CContactSyncPhonebookData::SynchroniseContactsL(CContactDatabase &aDb)
{
const TInt nContacts = iPhonebookContacts.Count();
// simple version of phonebook sync
for (TInt idx = 0; idx < nContacts; ++idx)
{
CContactICCEntry* item = CContactICCEntry::NewL(*iIccTemplate);
CleanupStack::PushL(item);
CContactItemFieldSet& fieldSet = item->CardFields();
// add name text
TInt pos = fieldSet.Find(KUidContactFieldFamilyName);
if (pos != KErrNotFound)
{
fieldSet[pos].TextStorage()->SetTextL(*iPhonebookContacts[idx]->Name());
}
// add phone number
pos = fieldSet.Find(KUidContactFieldPhoneNumber);
if (pos != KErrNotFound)
{
fieldSet[pos].TextStorage()->SetTextL(*iPhonebookContacts[idx]->Number());
}
// ICC Phonebook slot
pos = fieldSet.Find(KUidContactFieldICCSlot);
if (pos != KErrNotFound)
{
TBuf16<20> numberBuffer;
numberBuffer.Format(_L("%d"), idx + 1);
fieldSet[pos].TextStorage()->SetTextL(numberBuffer);
}
TContactItemId id = aDb.AddNewContactL(*item);
CleanupStack::PopAndDestroy(item);
// debug print fields
CContactItem* contact = aDb.ReadContactLC(id);
CContactItemFieldSet& contactFields = contact->CardFields();
const TInt fieldCount = contactFields.Count();
for (TInt i=0; i < fieldCount; i++)
{
CContactItemField &field = contactFields[i];
if (field.StorageType() == KStorageTypeText)
{
TPtrC fieldText = field.TextStorage()->Text();
TPtrC labelText = field.Label();
RDebug::Print(_L("--Field(%d) %S: %S \n\r"), i, &labelText, &fieldText);
}
}
CleanupStack::PopAndDestroy(contact);
}
if (nContacts)
{
aDb.CompactL();
}
}
void CContactSyncPhonebookData::ResetSynchronised(TBool aResetTemplateAndGroupIds)
{
if (aResetTemplateAndGroupIds)
{
iPhonebookTemplateId = KNullContactId;
iPhonebookGroupId = KNullContactId;
}
// tell observers that synchronisation state has changed
CompleteNotificationRequest(KErrNone);
// not synchronised
iIsSynchronised = EFalse;
iSynchronisedLeaveCode = KErrNone;
}
TInt CContactSyncPhonebookData::StoreNotificationRequest(TInt aStatus)
{
// aStatus = KRequestPending;
iNotificationPending++;
return iStatusArray.Append(aStatus);
}
void CContactSyncPhonebookData::CompleteNotificationRequest(TInt aError)
{
const TInt count = iStatusArray.Count();
for (TInt k = count; k > 0; --k)
{
iNotificationPending--;
RProperty::Set(
SyncNotification::KPropertyCategory,
iPhonebookUid.iUid,
aError);
}
iErrorCode = aError;
iStatusArray.Reset();
}
void CContactSyncPhonebookData::CancelNotificationRequestL()
{
const TInt count = iStatusArray.Count();
RProperty property;
for (TInt k = count; k > 0; --k)
{
iNotificationPending--;
User::LeaveIfError(property.Attach(SyncNotification::KPropertyCategory,iPhonebookUid.iUid));
property.Cancel();
}
iStatusArray.Reset();
}
TInt CContactSyncPhonebookData::NotificationPendingCount()
{
return iStatusArray.Count();
}
void CContactSyncPhonebookData::SetTemplateId(TInt aPhonebookTemplateId)
{
iPhonebookTemplateId = aPhonebookTemplateId;
}
void CContactSyncPhonebookData::SetGroupId(TInt aPhonebookGroupId)
{
iPhonebookGroupId = aPhonebookGroupId;
}
const TUid& CContactSyncPhonebookData::PhonebookUid()
{
return iPhonebookUid;
}
TInt CContactSyncPhonebookData::TemplateId()
{
return iPhonebookTemplateId;
}
TInt CContactSyncPhonebookData::GroupId()
{
return iPhonebookGroupId;
}
void CContactSyncPhonebookData::SetSynchronisedLeaveCode(TInt aLeaveError)
{
iSynchronisedLeaveCode = aLeaveError;
}
void CContactSyncPhonebookData::SetSynchronised(TInt aSynchronised)
{
iIsSynchronised = aSynchronised;
}
TBool CContactSyncPhonebookData::IsSynchronisedL()
{
User::LeaveIfError(iSynchronisedLeaveCode);
return iIsSynchronised;
}
TBool CContactSyncPhonebookData::SynchroniseRequired()
{
return !iIsSynchronised;
}
void CContactSyncPhonebookData::InternaliseFromCRL(TUint32& aCRKey)
{
TInt temp;
CContactSyncStaticRepository::ReadIntFromCentralRepositoryL(aCRKey, temp, *iRepository);
iPhonebookUid.iUid = temp;
CContactSyncStaticRepository::ReadIntFromCentralRepositoryL(aCRKey, temp, *iRepository);
iPhonebookTemplateId = temp;
CContactSyncStaticRepository::ReadIntFromCentralRepositoryL(aCRKey, temp, *iRepository);
iPhonebookGroupId = temp;
CContactSyncStaticRepository::ReadIntFromCentralRepositoryL(aCRKey, iIsSynchronised, *iRepository);
CContactSyncStaticRepository::ReadIntFromCentralRepositoryL(aCRKey, iNotificationPending, *iRepository);
CContactSyncStaticRepository::ReadIntFromCentralRepositoryL(aCRKey, iErrorCode, *iRepository);
CContactSyncStaticRepository::ReadIntFromCentralRepositoryL(aCRKey, iSynchronisedLeaveCode, *iRepository);
TInt notificationVectorSize = 0;
CContactSyncStaticRepository::ReadIntFromCentralRepositoryL(aCRKey, notificationVectorSize, *iRepository);
for (TInt i = 0 ; i < notificationVectorSize ; i++)
{
TInt notification;
CContactSyncStaticRepository::ReadIntFromCentralRepositoryL(aCRKey, notification, *iRepository);
iStatusArray.Append(notification);
}
TInt numberOfPhonebookContacts = 0;
CContactSyncStaticRepository::ReadIntFromCentralRepositoryL(aCRKey, numberOfPhonebookContacts, *iRepository);
aCRKey+=10 - iStatusArray.Count();
for (TInt i2 = 0 ; i2 < numberOfPhonebookContacts ; i2++)
{
CPhonebookContact* temp;
temp = CPhonebookContact::NewL(aCRKey, iRepository);
iPhonebookContacts.Append(temp);
}
aCRKey+=10;
}
void CContactSyncPhonebookData::ExternaliseToCRL(TUint32& aCRKey)
{
TInt temp = iPhonebookUid.iUid;
//TRAP(Err, iRepository->Set(aCRKey++, temp));
CContactSyncStaticRepository::WriteIntToCentralRepositoryL(aCRKey, temp, *iRepository);
temp = iPhonebookTemplateId;
CContactSyncStaticRepository::WriteIntToCentralRepositoryL(aCRKey, temp, *iRepository);
temp = iPhonebookGroupId;
CContactSyncStaticRepository::WriteIntToCentralRepositoryL(aCRKey, temp, *iRepository);
CContactSyncStaticRepository::WriteIntToCentralRepositoryL(aCRKey, iIsSynchronised, *iRepository);
CContactSyncStaticRepository::WriteIntToCentralRepositoryL(aCRKey, iNotificationPending, *iRepository);
CContactSyncStaticRepository::WriteIntToCentralRepositoryL(aCRKey, iErrorCode, *iRepository);
CContactSyncStaticRepository::WriteIntToCentralRepositoryL(aCRKey, iSynchronisedLeaveCode, *iRepository);
CContactSyncStaticRepository::WriteIntToCentralRepositoryL(aCRKey, iStatusArray.Count(), *iRepository);
for (TInt i = 0 ; i < iStatusArray.Count() ; i++)
{
TInt notification(iStatusArray[i]);
CContactSyncStaticRepository::WriteIntToCentralRepositoryL(aCRKey, notification, *iRepository);
}
CContactSyncStaticRepository::WriteIntToCentralRepositoryL(aCRKey, iPhonebookContacts.Count(), *iRepository);
aCRKey+=10 - iStatusArray.Count();
for (TInt i2 = 0 ; i2 < iPhonebookContacts.Count() ; i2++)
{
CPhonebookContact* temp = iPhonebookContacts[i2];
temp->WriteToCRL(aCRKey);
}
aCRKey+=10;
}
TInt CContactSyncPhonebookData::ErrorCode()
{
return iErrorCode;
}