--- a/qtmobility/plugins/contacts/symbiansim/src/cntsimstoreprivate.cpp Fri Apr 16 15:51:22 2010 +0300
+++ b/qtmobility/plugins/contacts/symbiansim/src/cntsimstoreprivate.cpp Mon May 03 13:18:40 2010 +0300
@@ -42,12 +42,14 @@
#include "cntsimstoreprivate.h"
#include "cntsymbiansimtransformerror.h"
#include "cntsimstore.h"
+#include "cntsimstoreeventlistener.h"
#include <mmtsy_names.h>
#include <qtcontacts.h>
-
+#include <qcontactchangeset.h>
+#include <QDebug>
-const int KOneSimContactBufferSize = 512;
+const TInt KOneSimContactBufferSize = 512;
const TInt KDataClientBuf = 128;
const TInt KEtsiTonPosition = 0x70;
@@ -66,7 +68,9 @@
m_engine(engine),
m_simStore(simStore),
m_storeName(storeName),
- m_storeInfoPckg(m_storeInfo)
+ m_readOnlyAccess(false),
+ m_storeInfoPckg(m_storeInfo),
+ m_listener(0)
{
CActiveScheduler::Add(this);
m_managerUri = engine.managerUri();
@@ -77,6 +81,10 @@
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));
@@ -104,16 +112,19 @@
PbkPrintToLog(_L("CntSymbianSimEngine::getEtelStoreInfoL() - MaxNumLength = %d"),
m_storeInfo.iMaxNumLength);
PbkPrintToLog(_L("CntSymbianSimEngine::getEtelStoreInfoL() - MaxTextLength = %d"),
- m_storeInfo.iMaxTextLength);
+ m_storeInfo.iMaxTextLength);
+
+ m_listener = new (ELeave) CntSimStoreEventListener(m_engine, m_etelStore);
+ m_listener->start();
}
CntSimStorePrivate::~CntSimStorePrivate()
{
Cancel();
- m_buffer.Close();
+ delete m_listener;
m_etelStore.Close();
m_etelPhone.Close();
- m_etelServer.Close();
+ m_etelServer.Close();
}
void CntSimStorePrivate::convertStoreNameL(TDes &storeName)
@@ -140,23 +151,12 @@
}
}
-QContactManager::Error CntSimStorePrivate::getInfo()
+bool CntSimStorePrivate::read(int index, int numSlots, QContactManager::Error *error)
{
- if (IsActive())
- return QContactManager::LockedError;
-
- // start get info request
- m_etelStore.GetInfo(iStatus, (TDes8&)m_storeInfoPckg);
- SetActive();
- m_state = GetInfoState;
-
- return QContactManager::NoError;
-}
-
-QContactManager::Error CntSimStorePrivate::read(int index, int numSlots)
-{
- if (IsActive())
- return QContactManager::LockedError;
+ if (IsActive()) {
+ *error = QContactManager::LockedError;
+ return false;
+ }
// start reading
m_buffer.Zero();
@@ -165,29 +165,35 @@
SetActive();
m_state = ReadState;
- return QContactManager::NoError;
+ *error = QContactManager::NoError;
+ return true;
}
-QContactManager::Error CntSimStorePrivate::write(const QContact &contact)
+bool CntSimStorePrivate::write(const QContact &contact, QContactManager::Error *error)
{
- if (IsActive())
- return QContactManager::LockedError;
+ if (IsActive()) {
+ *error = QContactManager::LockedError;
+ return false;
+ }
// get index
m_writeIndex = KErrNotFound;
if (contact.id().managerUri() == m_managerUri &&
contact.localId() > 0) {
- m_writeIndex = contact.localId();
+ m_writeIndex = contact.localId();
+
+ // TODO: check that the contact exist in the sim
}
// encode
m_buffer.Zero();
m_buffer.ReAlloc(KOneSimContactBufferSize);
- TRAPD(err, m_convertedContact = encodeSimContactL(&contact, m_buffer));
+ m_convertedContact = QContact(contact);
+
+ TRAPD(err, encodeSimContactL(&m_convertedContact, m_buffer));
if (err != KErrNone) {
- QContactManager::Error qtError;
- CntSymbianSimTransformError::transformError(err, qtError);
- return qtError;
+ CntSymbianSimTransformError::transformError(err, error);
+ return false;
}
// start writing
@@ -195,13 +201,16 @@
SetActive();
m_state = WriteState;
- return QContactManager::NoError;
+ *error = QContactManager::NoError;
+ return true;
}
-QContactManager::Error CntSimStorePrivate::remove(int index)
+bool CntSimStorePrivate::remove(int index, QContactManager::Error *error)
{
- if (IsActive())
- return QContactManager::LockedError;
+ if (IsActive()) {
+ *error = QContactManager::LockedError;
+ return false;
+ }
// NOTE:
// If index points to an empty slot and running in hardware the
@@ -211,41 +220,65 @@
SetActive();
m_state = DeleteState;
- return QContactManager::NoError;
+ *error = QContactManager::NoError;
+ return true;
+}
+
+bool CntSimStorePrivate::getReservedSlots(QContactManager::Error *error)
+{
+ if (IsActive()) {
+ *error = QContactManager::LockedError;
+ return false;
+ }
+
+ // start reading
+ m_buffer.Zero();
+ m_buffer.ReAlloc(KOneSimContactBufferSize*m_storeInfo.iTotalEntries);
+ m_etelStore.Read(iStatus, 1, m_storeInfo.iTotalEntries, m_buffer);
+ SetActive();
+ m_state = ReadReservedSlotsState;
+
+ *error = QContactManager::NoError;
+ return true;
}
void CntSimStorePrivate::DoCancel()
{
- if (m_state == GetInfoState)
- m_etelStore.CancelAsyncRequest(EMobilePhoneStoreGetInfo);
if (m_state == ReadState)
m_etelStore.CancelAsyncRequest(EMobilePhoneStoreRead);
if (m_state == WriteState)
m_etelStore.CancelAsyncRequest(EMobilePhoneStoreWrite);
if (m_state == DeleteState)
m_etelStore.CancelAsyncRequest(EMobilePhoneStoreDelete);
+ if (m_state == ReadReservedSlotsState)
+ m_etelStore.CancelAsyncRequest(EMobilePhoneStoreRead);
m_state = InactiveState;
}
void CntSimStorePrivate::RunL()
{
+ //qDebug() << "CntSimStorePrivate::RunL()" << m_state << iStatus.Int();
+
+ m_asyncError = iStatus.Int();
User::LeaveIfError(iStatus.Int());
// NOTE: It is assumed that emitting signals is queued
switch (m_state)
{
- case GetInfoState:
- {
- emit m_simStore.getInfoComplete(m_storeInfo, QContactManager::NoError);
- }
- break;
-
case ReadState:
{
QList<QContact> contacts = decodeSimContactsL(m_buffer);
- m_buffer.Zero();
+
+ // set sync target
+ QList<QContact>::iterator i;
+ for (i = contacts.begin(); i != contacts.end(); ++i) {
+ QContactSyncTarget syncTarget;
+ syncTarget.setSyncTarget(KSimSyncTarget);
+ i->saveDetail(&syncTarget);
+ }
+
emit m_simStore.readComplete(contacts, QContactManager::NoError);
}
break;
@@ -259,10 +292,12 @@
m_convertedContact.setId(contactId);
// set sync target
- QContactSyncTarget syncTarget;
- syncTarget.setSyncTarget(KSimSyncTarget);
- m_convertedContact.saveDetail(&syncTarget);
-
+ if(m_convertedContact.detail(QContactSyncTarget::DefinitionName).isEmpty()) {
+ QContactSyncTarget syncTarget = m_convertedContact.detail(QContactSyncTarget::DefinitionName);
+ syncTarget.setSyncTarget(KSimSyncTarget);
+ m_convertedContact.saveDetail(&syncTarget);
+ }
+
emit m_simStore.writeComplete(m_convertedContact, QContactManager::NoError);
}
break;
@@ -273,6 +308,13 @@
}
break;
+ case ReadReservedSlotsState:
+ {
+ QList<int> reservedSlots = decodeReservedSlotsL(m_buffer);
+ emit m_simStore.getReservedSlotsComplete(reservedSlots, QContactManager::NoError);
+ }
+ break;
+
default:
{
User::Leave(KErrUnknown);
@@ -285,22 +327,19 @@
TInt CntSimStorePrivate::RunError(TInt aError)
{
QContactManager::Error qtError = QContactManager::NoError;
- CntSymbianSimTransformError::transformError(aError, qtError);
+ CntSymbianSimTransformError::transformError(aError, &qtError);
// NOTE: It is assumed that emitting signals is queued
- if (m_state == GetInfoState) {
- RMobilePhoneBookStore::TMobilePhoneBookInfoV5 emptyInfo;
- emit m_simStore.getInfoComplete(emptyInfo, qtError);
- } else if (m_state == ReadState) {
- QList<QContact> emptyList;
- emit m_simStore.readComplete(emptyList, qtError);
- } else if (m_state == WriteState) {
+ if (m_state == ReadState)
+ emit m_simStore.readComplete(QList<QContact>(), qtError);
+ else if (m_state == WriteState)
emit m_simStore.writeComplete(m_convertedContact, qtError);
- } else if (m_state == DeleteState) {
+ else if (m_state == DeleteState)
emit m_simStore.removeComplete(qtError);
- }
-
+ else if (m_state == ReadReservedSlotsState)
+ emit m_simStore.getReservedSlotsComplete(QList<int>(), qtError);
+
m_state = InactiveState;
return KErrNone;
@@ -368,6 +407,8 @@
QString number = lastNumber.number();
number.insert(0, "+");
lastNumber.setNumber(number);
+ if (m_readOnlyAccess)
+ m_engine.setReadOnlyAccessConstraint(&lastNumber);
currentContact.saveDetail(&lastNumber);
}
}
@@ -390,9 +431,11 @@
QContactName name;
QString nameString = QString::fromUtf16(bufPtr.Ptr(), bufPtr.Length());
name.setCustomLabel(nameString);
+ if (m_readOnlyAccess)
+ m_engine.setReadOnlyAccessConstraint(&name);
currentContact.saveDetail(&name);
QContactManager::Error error(QContactManager::NoError);
- currentContact = m_engine.setContactDisplayLabel(m_engine.synthesizedDisplayLabel(currentContact, error), currentContact);
+ m_engine.setContactDisplayLabel(¤tContact, m_engine.synthesizedDisplayLabel(currentContact, &error));
}
}
break;
@@ -403,6 +446,8 @@
QContactNickname nickName;
QString name = QString::fromUtf16(bufPtr.Ptr(), bufPtr.Length());
nickName.setNickname(name);
+ if (m_readOnlyAccess)
+ m_engine.setReadOnlyAccessConstraint(&nickName);
currentContact.saveDetail(&nickName);
}
break;
@@ -411,9 +456,10 @@
{
if (pbBuffer->GetValue(bufPtr) == KErrNone) {
QContactPhoneNumber phoneNumber;
- phoneNumber.setSubTypes( QContactPhoneNumber::SubTypeMobile );
QString number = QString::fromUtf16(bufPtr.Ptr(), bufPtr.Length());
phoneNumber.setNumber(number);
+ if (m_readOnlyAccess)
+ m_engine.setReadOnlyAccessConstraint(&phoneNumber);
currentContact.saveDetail(&phoneNumber);
}
break;
@@ -430,6 +476,8 @@
QContactEmailAddress email;
QString emailAddress = QString::fromUtf16(bufPtr.Ptr(), bufPtr.Length());
email.setEmailAddress(emailAddress);
+ if (m_readOnlyAccess)
+ m_engine.setReadOnlyAccessConstraint(&email);
currentContact.saveDetail(&email);
}
break;
@@ -473,129 +521,150 @@
*
* \param contact QContact to be converted
* \param rawData Contact in TLV format on return.
- * \return QContact containing actually saved information.
*/
-QContact CntSimStorePrivate::encodeSimContactL(const QContact* contact, TDes8& rawData) const
+void CntSimStorePrivate::encodeSimContactL(QContact* contact, TDes8& rawData) const
{
- PbkPrintToLog(_L("CntSymbianSimEngine::encodeSimContactL() - IN"));
- QContact convertedContact;
+ // TODO: get detail definition schema and verify (unique)
+
+ // Keep track of the count of phone numbers added
+ int phoneNumberCount(0);
+ int emailCount(0);
+
CPhoneBookBuffer* pbBuffer = new(ELeave) CPhoneBookBuffer();
CleanupStack::PushL(pbBuffer);
pbBuffer->Set(&rawData);
-
- //add new enty tag
User::LeaveIfError(pbBuffer->AddNewEntryTag());
- //add name
- QString name;
- QList<QContactDetail> nameDetails = contact->details(QContactName::DefinitionName);
- if (nameDetails.count() == 0) {
- // TODO: should we leave name empty?
- name.append("Unnamed");
- }
- else {
- QContactName nameDetail = static_cast<QContactName>(nameDetails.at(0));
- name.append(nameDetail.customLabel());
- if (name.isNull()) {
- // TODO: should we leave name empty?
- name.append("Unnamed)");
- }
- }
- name = name.left(m_storeInfo.iMaxTextLength); //trim to the max possible length
- TPtrC nameValue(reinterpret_cast<const TUint16*>(name.utf16()));
- User::LeaveIfError(pbBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBText, nameValue));
+ foreach(QContactDetail detail, contact->details()) {
+ QString definitionName = detail.definitionName();
+
+ if (definitionName == QContactName::DefinitionName) {
+ // Name
+ 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
+ phoneNumberCount++;
+ QContactPhoneNumber numberDetail = static_cast<QContactPhoneNumber>(detail);
+ QString number = numberDetail.number();
+
+ // Verify the number only contains legal digits
+ foreach (const QChar character, number) {
+ if(!character.isDigit()) {
+ if(character != QChar('+')
+ && character != QChar('*')
+ && character != QChar('#')
+ && character != QChar('p')
+ && character != QChar('w')) {
+ User::Leave(KErrArgument);
+ }
+ }
+ }
+
+ // TODO: check if the number is empty (do we have a test case for that?)
- QContactName convertedNameDetail;
- convertedNameDetail.setCustomLabel(name);
- convertedContact.saveDetail(&convertedNameDetail);
+ // 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());
+ }
- //add nickname
- if (m_storeInfo.iMaxSecondNames > 0) {
- QString nickname;
- QList<QContactDetail> nicknameDetails = contact->details(QContactNickname::DefinitionName);
- if (nicknameDetails.count() > 0) {
- QContactNickname nicknameDetail = static_cast<QContactNickname>(nicknameDetails.at(0));
- nickname = nicknameDetail.nickname();
- nickname = nickname.left(m_storeInfo.iMaxTextLengthSecondName); //trim to the max possible length
- TPtrC nicknameValue(reinterpret_cast<const TUint16*>(nickname.utf16()));
- User::LeaveIfError(pbBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBSecondName, nicknameValue));
-
- QContactNickname convertedNicknameDetail;
- convertedNicknameDetail.setNickname(nickname);
- convertedContact.saveDetail(&convertedNicknameDetail);
+ // 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
+ // These are ignored in the conversion
+ } else if (definitionName == QContactSyncTarget::DefinitionName
+ || definitionName == QContactDisplayLabel::DefinitionName
+ || definitionName == QContactType::DefinitionName) {
+ // Do nothing
+ } else {
+ User::Leave(KErrArgument);
}
}
-
- //add phone number
- QList<QContactDetail> phoneNumberDetails = contact->details(QContactPhoneNumber::DefinitionName);
- if (phoneNumberDetails.count() > 0) {
- PbkPrintToLog(_L("CntSymbianSimEngine::encodeSimContactL() - add phone number"));
- QContactPhoneNumber phoneNumberDetail = static_cast<QContactPhoneNumber>(phoneNumberDetails.at(0));
- QString number = phoneNumberDetail.number();
- foreach (const QChar character, number) {
- if(!character.isDigit()) {
- if(character != QChar('+')
- && character != QChar('*')
- && character != QChar('#')
- && character != QChar('p')
- && character != QChar('w')) {
- User::Leave(KErrArgument);
- }
- }
- }
- PbkPrintToLog(_L("CntSymbianSimEngine::encodeSimContactL() - phone number length = %d"),
- phoneNumberDetail.number().length());
- if (phoneNumberDetail.number().length() > m_storeInfo.iMaxNumLength) {
- User::Leave(KErrTooBig);
- }
- TPtrC phoneNumberValue(reinterpret_cast<const TUint16*>(phoneNumberDetail.number().utf16()));
- PbkPrintToLog(_L("CntSymbianSimEngine::encodeSimContactL() - number = %S"), &phoneNumberValue);
- User::LeaveIfError(pbBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBNumber, phoneNumberValue));
-
- QContactPhoneNumber convertedPhoneNumberDetail;
- convertedPhoneNumberDetail.setNumber(phoneNumberDetail.number());
- convertedContact.saveDetail(&convertedPhoneNumberDetail);
- }
+ CleanupStack::PopAndDestroy(pbBuffer);
+}
- //add additional numbers
- if (m_storeInfo.iMaxAdditionalNumbers > 0) {
- //one number is saved already
- for (int i = 1; i < phoneNumberDetails.count() && i-1 < m_storeInfo.iMaxAdditionalNumbers; ++i) {
- QContactPhoneNumber phoneNumberDetail = static_cast<QContactPhoneNumber>(phoneNumberDetails.at(i));
- if (phoneNumberDetail.number().length() > m_storeInfo.iMaxNumLengthAdditionalNumber) {
- User::Leave(KErrTooBig);
- }
- //mark the beginning of an additional number
- User::LeaveIfError(pbBuffer->AddNewNumberTag());
- //add number itself
- TPtrC phoneNumberValue(reinterpret_cast<const TUint16*>(phoneNumberDetail.number().utf16()));
- User::LeaveIfError(pbBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBNumber, phoneNumberValue));
-
- QContactPhoneNumber convertedPhoneNumberDetail;
- convertedPhoneNumberDetail.setNumber(phoneNumberDetail.number());
- convertedContact.saveDetail(&convertedPhoneNumberDetail);
- }
- }
-
- //add e-mails
- if (m_storeInfo.iMaxEmailAddr > 0) {
- QList<QContactDetail> emailDetails = contact->details(QContactEmailAddress::DefinitionName);
- for (int i = 0; i < emailDetails.count() && i < m_storeInfo.iMaxEmailAddr; ++i) {
- QContactEmailAddress emailDetail = static_cast<QContactEmailAddress>(emailDetails.at(i));
- TPtrC emailValue(reinterpret_cast<const TUint16*>(emailDetail.emailAddress().utf16()));
- if (emailValue.Length() > m_storeInfo.iMaxTextLengthEmailAddr) {
- User::Leave(KErrTooBig);
- }
- User::LeaveIfError(pbBuffer->PutTagAndValue(RMobilePhoneBookStore::ETagPBEmailAddress, emailValue));
-
- QContactEmailAddress convertedEmailDetail;
- convertedEmailDetail.setEmailAddress(emailDetail.emailAddress());
- convertedContact.saveDetail(&convertedEmailDetail);
- }
- }
-
- CleanupStack::PopAndDestroy(pbBuffer);
- PbkPrintToLog(_L("CntSymbianSimEngine::encodeSimContactL() - OUT"));
- return convertedContact;
+void CntSimStorePrivate::putTagAndValueL(CPhoneBookBuffer* pbBuffer, TUint8 tag, QString data) const
+{
+ TPtrC value(reinterpret_cast<const TUint16*>(data.utf16()));
+ User::LeaveIfError(pbBuffer->PutTagAndValue(tag, value));
}
+QList<int> CntSimStorePrivate::decodeReservedSlotsL(TDes8& rawData) const
+{
+ QList<int> reservedSlots;
+
+ TUint8 tagValue(0);
+ CPhoneBookBuffer::TPhBkTagType dataType;
+
+ CPhoneBookBuffer* pbBuffer = new (ELeave) CPhoneBookBuffer();
+ CleanupStack::PushL(pbBuffer);
+ pbBuffer->Set(&rawData);
+ pbBuffer->StartRead();
+
+ while (pbBuffer->GetTagAndType(tagValue, dataType) == KErrNone)
+ {
+ if (tagValue == RMobilePhoneBookStore::ETagPBAdnIndex)
+ {
+ TUint16 index;
+ if (pbBuffer->GetValue(index) == KErrNone)
+ reservedSlots.append(index);
+ } else
+ pbBuffer->SkipValue(dataType);
+ } //while
+
+ CleanupStack::PopAndDestroy(pbBuffer);
+ return reservedSlots;
+}