--- a/qtmobility/plugins/contacts/symbiansim/src/cntsimstoreprivate.cpp Fri Jun 11 14:26:25 2010 +0300
+++ b/qtmobility/plugins/contacts/symbiansim/src/cntsimstoreprivate.cpp Wed Jun 23 19:08:38 2010 +0300
@@ -67,13 +67,26 @@
m_state(InactiveState),
m_engine(engine),
m_simStore(simStore),
- m_storeName(storeName),
- m_readOnlyAccess(false),
- m_storeInfoPckg(m_storeInfo),
- m_listener(0)
+ m_listener(0),
+ m_extraDetailsChecked(false)
{
CActiveScheduler::Add(this);
m_managerUri = engine.managerUri();
+
+ // Initialize store info
+ m_storeInfo.m_storeName = storeName;
+ m_storeInfo.m_totalEntries = -1;
+ m_storeInfo.m_usedEntries = -1;
+ m_storeInfo.m_readOnlyAccess = false;
+ m_storeInfo.m_numberSupported = true; // allways supported
+ m_storeInfo.m_nameSupported = true; // allways supported
+ m_storeInfo.m_secondNameSupported = false;
+ m_storeInfo.m_additionalNumberSupported = false;
+ m_storeInfo.m_emailSupported = false;
+
+ // SDN store is allways read only
+ if (m_storeInfo.m_storeName == KParameterValueSimStoreNameSdn)
+ m_storeInfo.m_readOnlyAccess = true;
}
void CntSimStorePrivate::ConstructL()
@@ -81,10 +94,6 @@
TBuf<RMobilePhoneBookStore::KMaxPBIDSize> storeName;
convertStoreNameL(storeName);
- // SDN store is always read only
- if (m_storeName == KParameterValueSimStoreNameSdn)
- m_readOnlyAccess = true;
-
// Open etel server
User::LeaveIfError(m_etelServer.Connect());
User::LeaveIfError(m_etelServer.LoadPhoneModule(KMmTsyModuleName));
@@ -94,26 +103,13 @@
User::LeaveIfError(m_etelServer.GetPhoneInfo(0, info));
User::LeaveIfError(m_etelPhone.Open(m_etelServer, info.iName));
- // open Etel store
+ // Open Etel store
User::LeaveIfError(m_etelStore.Open(m_etelPhone, storeName));
+
+ // Update store info
+ updateStoreInfoL();
- //check what information can be saved to the Etel store
- TRequestStatus requestStatus;
- m_etelStore.GetInfo(requestStatus, (TDes8&)m_storeInfoPckg);
- User::WaitForRequest(requestStatus);
- PbkPrintToLog(_L("CntSymbianSimEngine::getEtelStoreInfoL() - GetInfo err = %d"),
- requestStatus.Int());
- User::LeaveIfError(requestStatus.Int());
-
- PbkPrintToLog(_L("CntSymbianSimEngine::getEtelStoreInfoL() - TotalEntries = %d"),
- m_storeInfo.iTotalEntries);
- PbkPrintToLog(_L("CntSymbianSimEngine::getEtelStoreInfoL() - UsedEntries = %d"),
- m_storeInfo.iUsedEntries);
- PbkPrintToLog(_L("CntSymbianSimEngine::getEtelStoreInfoL() - MaxNumLength = %d"),
- m_storeInfo.iMaxNumLength);
- PbkPrintToLog(_L("CntSymbianSimEngine::getEtelStoreInfoL() - MaxTextLength = %d"),
- m_storeInfo.iMaxTextLength);
-
+ // Start listening for events
m_listener = new (ELeave) CntSimStoreEventListener(m_engine, m_etelStore);
m_listener->start();
}
@@ -133,15 +129,15 @@
User::Leave(KErrArgument);
}
- if (m_storeName.isEmpty()) {
+ if (m_storeInfo.m_storeName.isEmpty()) {
// Default to ADN store
- m_storeName = (QLatin1String) KParameterValueSimStoreNameAdn;
+ m_storeInfo.m_storeName = (QLatin1String) KParameterValueSimStoreNameAdn;
storeName.Copy(KETelIccAdnPhoneBook);
- } else if (m_storeName == KParameterValueSimStoreNameFdn) {
+ } else if (m_storeInfo.m_storeName == KParameterValueSimStoreNameFdn) {
storeName.Copy(KETelIccFdnPhoneBook);
- } else if (m_storeName == KParameterValueSimStoreNameAdn) {
+ } else if (m_storeInfo.m_storeName == KParameterValueSimStoreNameAdn) {
storeName.Copy(KETelIccAdnPhoneBook);
- } else if (m_storeName == KParameterValueSimStoreNameSdn) {
+ } else if (m_storeInfo.m_storeName == KParameterValueSimStoreNameSdn) {
storeName.Copy(KETelIccSdnPhoneBook);
}
@@ -233,8 +229,8 @@
// start reading
m_buffer.Zero();
- m_buffer.ReAlloc(KOneSimContactBufferSize*m_storeInfo.iTotalEntries);
- m_etelStore.Read(iStatus, 1, m_storeInfo.iTotalEntries, m_buffer);
+ m_buffer.ReAlloc(KOneSimContactBufferSize*m_storeInfo.m_totalEntries);
+ m_etelStore.Read(iStatus, 1, m_storeInfo.m_totalEntries, m_buffer);
SetActive();
m_state = ReadReservedSlotsState;
@@ -271,7 +267,7 @@
{
QList<QContact> contacts = decodeSimContactsL(m_buffer);
- // set sync target and set type as read only
+ // set sync target and read only access constraint and display label
QList<QContact>::iterator i;
for (i = contacts.begin(); i != contacts.end(); ++i) {
QContactSyncTarget syncTarget;
@@ -281,6 +277,7 @@
QContactType contactType = i->detail(QContactType::DefinitionName);
m_engine.setReadOnlyAccessConstraint(&contactType);
i->saveDetail(&contactType);
+ m_engine.updateDisplayLabel(*i);
}
emit m_simStore.readComplete(contacts, QContactManager::NoError);
@@ -417,7 +414,7 @@
QString number = lastNumber.number();
number.insert(0, "+");
lastNumber.setNumber(number);
- if (m_readOnlyAccess)
+ if (m_storeInfo.m_readOnlyAccess)
m_engine.setReadOnlyAccessConstraint(&lastNumber);
currentContact.saveDetail(&lastNumber);
}
@@ -441,7 +438,7 @@
QContactName name;
QString nameString = QString::fromUtf16(bufPtr.Ptr(), bufPtr.Length());
name.setCustomLabel(nameString);
- if (m_readOnlyAccess)
+ if (m_storeInfo.m_readOnlyAccess)
m_engine.setReadOnlyAccessConstraint(&name);
currentContact.saveDetail(&name);
QContactManager::Error error(QContactManager::NoError);
@@ -456,7 +453,7 @@
QContactNickname nickName;
QString name = QString::fromUtf16(bufPtr.Ptr(), bufPtr.Length());
nickName.setNickname(name);
- if (m_readOnlyAccess)
+ if (m_storeInfo.m_readOnlyAccess)
m_engine.setReadOnlyAccessConstraint(&nickName);
currentContact.saveDetail(&nickName);
}
@@ -468,7 +465,7 @@
QContactPhoneNumber phoneNumber;
QString number = QString::fromUtf16(bufPtr.Ptr(), bufPtr.Length());
phoneNumber.setNumber(number);
- if (m_readOnlyAccess)
+ if (m_storeInfo.m_readOnlyAccess)
m_engine.setReadOnlyAccessConstraint(&phoneNumber);
currentContact.saveDetail(&phoneNumber);
}
@@ -486,7 +483,7 @@
QContactEmailAddress email;
QString emailAddress = QString::fromUtf16(bufPtr.Ptr(), bufPtr.Length());
email.setEmailAddress(emailAddress);
- if (m_readOnlyAccess)
+ if (m_storeInfo.m_readOnlyAccess)
m_engine.setReadOnlyAccessConstraint(&email);
currentContact.saveDetail(&email);
}
@@ -531,46 +528,42 @@
*/
void CntSimStorePrivate::encodeSimContactL(QContact* contact, TDes8& rawData) const
{
- // TODO: get detail definition schema and verify (unique)
-
// Keep track of the count of phone numbers added
int phoneNumberCount(0);
- int emailCount(0);
+ // Create buffer
CPhoneBookBuffer* pbBuffer = new(ELeave) CPhoneBookBuffer();
CleanupStack::PushL(pbBuffer);
pbBuffer->Set(&rawData);
User::LeaveIfError(pbBuffer->AddNewEntryTag());
- foreach(QContactDetail detail, contact->details()) {
+ // Loop through details
+ foreach(QContactDetail detail, contact->details())
+ {
QString definitionName = detail.definitionName();
+
+ // NOTE: If the detail is too long let the etel store return
+ // an error about it. We could check the maximum lenghts for each
+ // detail but then we would need to read it before every write operation
+ // bacause it seems to change depending on how full the sim card is.
- if (definitionName == QContactName::DefinitionName) {
- // Name
+ // Name
+ if (definitionName == QContactName::DefinitionName)
+ {
QContactName nameDetail = static_cast<QContactName>(detail);
- // Trim to the max possible length
- QString name = nameDetail.customLabel().left(m_storeInfo.iMaxTextLength);
- if (name.isEmpty()) {
- name = "Unnamed";
- }
- putTagAndValueL(
- pbBuffer,
- RMobilePhoneBookStore::ETagPBText,
- name);
- // Replace detail value with the trimmed one
- nameDetail.setCustomLabel(name);
- contact->saveDetail(&nameDetail);
- } else if (definitionName == QContactPhoneNumber::DefinitionName
-#ifndef SYMBIANSIM_BACKEND_PHONEBOOKINFOV1
- && (phoneNumberCount == 0
- || phoneNumberCount <= m_storeInfo.iMaxAdditionalNumbers)) {
-#else
- && phoneNumberCount == 0) {
-#endif
- // Phone number
+ QString name = nameDetail.customLabel();
+ putTagAndValueL(pbBuffer, RMobilePhoneBookStore::ETagPBText, name);
+ }
+ // Phone number
+ else if (definitionName == QContactPhoneNumber::DefinitionName)
+ {
+ if (m_storeInfo.m_additionalNumberSupported == false && phoneNumberCount>0)
+ User::Leave(KErrNotSupported);
+
phoneNumberCount++;
- QContactPhoneNumber numberDetail = static_cast<QContactPhoneNumber>(detail);
- QString number = numberDetail.number();
+ QString number = static_cast<QContactPhoneNumber>(detail).number();
+ if (number.isEmpty())
+ continue;
// Verify the number only contains legal digits
foreach (const QChar character, number) {
@@ -585,58 +578,48 @@
}
}
- // TODO: check if the number is empty (do we have a test case for that?)
-
- // Verify the number length
- PbkPrintToLog(_L("CntSymbianSimEngine::encodeSimContactL() - phone number length = %d"),
- numberDetail.number().length());
- if (numberDetail.number().length() > m_storeInfo.iMaxNumLength) {
- User::Leave(KErrTooBig);
- }
-
if (phoneNumberCount > 1) {
// Mark the beginning of an additional number
User::LeaveIfError(pbBuffer->AddNewNumberTag());
}
// The number itself
- putTagAndValueL(
- pbBuffer,
- RMobilePhoneBookStore::ETagPBNumber,
- number);
-#ifndef SYMBIANSIM_BACKEND_PHONEBOOKINFOV1
- // Phonebook info version 1 does not support nick name or e-mail
- } else if (definitionName == QContactNickname::DefinitionName
- && m_storeInfo.iMaxSecondNames > 0) {
- // nickname
- QContactNickname nicknameDetail = static_cast<QContactNickname>(detail);
- // Trim to the max possible length;
- QString nickname = nicknameDetail.nickname().left(m_storeInfo.iMaxTextLengthSecondName);
- putTagAndValueL(
- pbBuffer,
- RMobilePhoneBookStore::ETagPBSecondName,
- nickname);
- // Replace detail value with the trimmed one
- nicknameDetail.setNickname(nickname);
- contact->saveDetail(&nicknameDetail);
- } else if (definitionName == QContactEmailAddress::DefinitionName
- && emailCount < m_storeInfo.iMaxEmailAddr) {
- emailCount++;
- QContactEmailAddress emailDetail = static_cast<QContactEmailAddress>(detail);
- if (emailDetail.emailAddress().length() > m_storeInfo.iMaxTextLengthEmailAddr) {
- User::Leave(KErrTooBig);
- }
- putTagAndValueL(
- pbBuffer,
- RMobilePhoneBookStore::ETagPBEmailAddress,
- emailDetail.emailAddress());
-#endif
+ putTagAndValueL(pbBuffer, RMobilePhoneBookStore::ETagPBNumber, number);
+ }
+ // Nickname
+ else if (definitionName == QContactNickname::DefinitionName)
+ {
+ if (m_storeInfo.m_secondNameSupported == false)
+ User::Leave(KErrNotSupported);
+
+ QString nickname = static_cast<QContactNickname>(detail).nickname();
+ if (nickname.isEmpty())
+ continue;
+
+ putTagAndValueL(pbBuffer, RMobilePhoneBookStore::ETagPBSecondName, nickname);
+ }
+ // email
+ else if (definitionName == QContactEmailAddress::DefinitionName)
+ {
+ if (m_storeInfo.m_emailSupported == false)
+ User::Leave(KErrNotSupported);
+
+ QString email = static_cast<QContactEmailAddress>(detail).emailAddress();
+ if (email.isEmpty())
+ continue;
+
+ putTagAndValueL(pbBuffer, RMobilePhoneBookStore::ETagPBEmailAddress, email);
+ }
// These are ignored in the conversion
- } else if (definitionName == QContactSyncTarget::DefinitionName
+ else if (definitionName == QContactSyncTarget::DefinitionName
|| definitionName == QContactDisplayLabel::DefinitionName
- || definitionName == QContactType::DefinitionName) {
+ || definitionName == QContactType::DefinitionName)
+ {
// Do nothing
- } else {
+ }
+ else
+ {
+ // Unknown detail
User::Leave(KErrArgument);
}
}
@@ -675,3 +658,154 @@
CleanupStack::PopAndDestroy(pbBuffer);
return reservedSlots;
}
+
+void CntSimStorePrivate::writeL(QContact *contact)
+{
+ if (IsActive())
+ User::Leave(KErrLocked);
+
+ // get index
+ int index = KErrNotFound;
+ if (contact->id().managerUri() == m_managerUri &&
+ contact->localId() > 0) {
+ index = contact->localId();
+ }
+
+ // encode
+ m_buffer.Zero();
+ m_buffer.ReAlloc(KOneSimContactBufferSize);
+ encodeSimContactL(contact, m_buffer);
+
+ // write
+ TRequestStatus status;
+ m_etelStore.Write(status, m_buffer, index);
+ User::WaitForRequest(status);
+ User::LeaveIfError(status.Int());
+
+ // update id
+ QContactId id;
+ id.setLocalId(index);
+ id.setManagerUri(m_managerUri);
+ contact->setId(id);
+}
+
+void CntSimStorePrivate::removeL(int index)
+{
+ if (IsActive())
+ User::Leave(KErrLocked);
+
+ // NOTE:
+ // If index points to an empty slot and running in hardware the
+ // delete operation will not return any error.
+
+ TRequestStatus status;
+ m_etelStore.Delete(status, index);
+ User::WaitForRequest(status);
+ User::LeaveIfError(status.Int());
+}
+
+void CntSimStorePrivate::updateStoreInfoL()
+{
+#ifdef SYMBIANSIM_BACKEND_PHONEBOOKINFOV1
+ RMobilePhoneBookStore::TMobilePhoneBookInfoV1 info;
+ RMobilePhoneBookStore::TMobilePhoneBookInfoV1Pckg infoPckg(info);
+#else
+ RMobilePhoneBookStore::TMobilePhoneBookInfoV5 info;
+ RMobilePhoneBookStore::TMobilePhoneBookInfoV5Pckg infoPckg(info);
+#endif
+
+ // Get info
+ TRequestStatus status;
+ m_etelStore.GetInfo(status, infoPckg);
+ User::WaitForRequest(status);
+ User::LeaveIfError(status.Int());
+
+ // Update entry counts
+ m_storeInfo.m_totalEntries = info.iTotalEntries;
+ m_storeInfo.m_usedEntries = info.iUsedEntries;
+
+#ifdef SYMBIANSIM_BACKEND_TEST_EXTRADETAILS
+ // Check if store supports the extra details
+ //
+ // NOTE:
+ // We cannot rely on TMobilePhoneBookInfoV5 to check if we support
+ // these details. For example iMaxSecondNames is allways -1 even if the sim
+ // card supports a second name.
+ //
+ // There is an API for checking these but it's Nokia internal so we must
+ // do it this way - by checking if saving these details is possible.
+
+ // Have we checked these already?
+ if (m_extraDetailsChecked == false)
+ {
+ // Cannot test extra details if sim card is full
+ if (m_storeInfo.m_usedEntries == m_storeInfo.m_totalEntries)
+ return;
+
+ // Cancel store event listener temporarily
+ if (m_listener)
+ m_listener->Cancel();
+
+ // Test writing nickname
+ QContact contact;
+ QContactNickname nick;
+ nick.setNickname("simbackend test");
+ contact.saveDetail(&nick);
+ TRAPD(err, {
+ m_storeInfo.m_secondNameSupported = true; // enable to pass encodeSimContactL()
+ writeL(&contact);
+ removeL(contact.localId());
+ } );
+ if (err)
+ m_storeInfo.m_secondNameSupported = false;
+
+ // Test writing additional number
+ contact = QContact();
+ QContactPhoneNumber num1;
+ num1.setNumber("1111111111");
+ contact.saveDetail(&num1);
+ QContactPhoneNumber num2;
+ num2.setNumber("2222222222");
+ contact.saveDetail(&num2);
+ TRAP(err, {
+ m_storeInfo.m_additionalNumberSupported = true; // enable to pass encodeSimContactL()
+ writeL(&contact);
+ removeL(contact.localId());
+ } );
+ if (err)
+ m_storeInfo.m_additionalNumberSupported = false;
+
+ // Test writing email
+ contact = QContact();
+ QContactEmailAddress email;
+ email.setEmailAddress("simbackend@test.com");
+ contact.saveDetail(&email);
+ TRAP(err, {
+ m_storeInfo.m_emailSupported = true; // enable to pass encodeSimContactL()
+ writeL(&contact);
+ removeL(contact.localId());
+ } );
+ if (err)
+ m_storeInfo.m_emailSupported = false;
+
+ // Start store event listener again
+ if (m_listener)
+ m_listener->start();
+
+ m_extraDetailsChecked = true;
+ }
+#endif
+
+ /*
+ qDebug() << "Store info:"
+ << "\nStore name :" << m_storeInfo.m_storeName
+ << "\nTotal entries :" << m_storeInfo.m_totalEntries
+ << "\nUsed entries :" << m_storeInfo.m_usedEntries
+ << "\nRead only access :" << m_storeInfo.m_readOnlyAccess
+ << "\nNumber supported :" << m_storeInfo.m_numberSupported
+ << "\nName supported :" << m_storeInfo.m_nameSupported
+ << "\nSecond name supported :" << m_storeInfo.m_secondNameSupported
+ << "\nAdditional name supported :" << m_storeInfo.m_additionalNumberSupported
+ << "\nEmail supported :" << m_storeInfo.m_emailSupported;
+ */
+}