diff -r 000000000000 -r dab8a81a92de omads/omadsextensions/adapters/sms/src/SmsDataStore.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omads/omadsextensions/adapters/sms/src/SmsDataStore.cpp Mon Nov 23 14:46:41 2009 +0200 @@ -0,0 +1,1362 @@ +/* +* Copyright (c) 2005-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: Part of SyncML Data Synchronization Plug In Adapter +* +*/ + + +#include +#include +#include +#include +#include +#include +#include "SmsDataStore.h" +#include "SmsDataProviderDefs.h" +#include "Logger.h" +#include "SMSAdapterMsvApi.h" +#include "VMessageParser.h" +#include "OMADSFolderObject.h" + +// This is used, when databuffer is not initialized +const TInt KDataBufferNotReady = -1; +// Size for internal CBufFlat, used to buffer SMS messages +const TInt KDataBufferSize = 1024; + +_LIT8(KSmsMimeType, "text/x-vMessage"); +_LIT8(KSmsMimeVersion, "1.2"); +_LIT8(KFolderMimeType, "application/vnd.omads-folder+xml"); +_LIT8(KFolderMimeVersion, "1.2"); + + +// ----------------------------------------------------------------------------- +// CSmsDataStore::CSmsDataStore +// C++ default constructor can NOT contain any code, that might leave. +// ----------------------------------------------------------------------------- +CSmsDataStore::CSmsDataStore(): + iHasHistory(EFalse), + iDataBaseOpened(EFalse), + iKey(TKeyArrayFix(_FOFF(TSnapshotItem, ItemId()), ECmpTInt)) + { + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::ConstructL +// Symbian 2nd phase constructor, can leave. +// ----------------------------------------------------------------------------- +void CSmsDataStore::ConstructL() + { + LOGGER_ENTERFN("CSmsDataStore::ConstructL"); + + iMsvApi = CSmsAdapterMsvApi::NewL(); + + // Item UID sets, used to transfer change info + iNewItems = new (ELeave) CNSmlDataItemUidSet; + iDeletedItems = new (ELeave) CNSmlDataItemUidSet; + iUpdatedItems = new (ELeave) CNSmlDataItemUidSet; + iMovedItems = new (ELeave) CNSmlDataItemUidSet; + iSoftDeletedItems = new (ELeave) CNSmlDataItemUidSet; + + iMessageParser = CVMessageParser::NewL(); + iFolderObjectParser = COMADSFolderObject::NewL(); + + LOGGER_LEAVEFN("CSmsDataStore::ConstructL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::NewLC +// Two-phased constructor. +// ----------------------------------------------------------------------------- +CSmsDataStore* CSmsDataStore::NewLC() + { + CSmsDataStore* self = new (ELeave) CSmsDataStore; + + CleanupStack::PushL(self); + self->ConstructL(); + + return self; + } + + +// ----------------------------------------------------------------------------- +// CSmsDataStore::~CSmsDataStore +// Destructor +// ----------------------------------------------------------------------------- +CSmsDataStore::~CSmsDataStore() + { + LOGGER_ENTERFN("CSmsDataStore::~CSmsDataStore()"); + + SAFEDELETE(iFolderObjectParser); + SAFEDELETE(iMessageParser); + + SAFEDELETE(iMsvApi); + SAFEDELETE(iChangeFinder); + + // UID sets + SAFEDELETE(iNewItems); + SAFEDELETE(iDeletedItems); + SAFEDELETE(iSoftDeletedItems); + SAFEDELETE(iUpdatedItems); + SAFEDELETE(iMovedItems); + + SAFEDELETE(iDataBuffer); + + LOGGER_LEAVEFN("CSmsDataStore::~CSmsDataStore()"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoOpenL +// Opens database. This operation is performed SYNCHRONOUSLY +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoOpenL(const TDesC& /*aStoreName*/, MSmlSyncRelationship& aContext, + TRequestStatus& aStatus) + { + LOGGER_ENTERFN("CSmsDataStore::DoOpenL"); + + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + if (iDataBaseOpened) + { + User::RequestComplete(iCallerStatus, KErrInUse); + LOGGER_WRITE("CSmsDataStore::DoOpenL failed with KErrInUse."); + return; + } + + *iContext = aContext; + + // Create ChangeFinder object + iChangeFinder = CChangeFinder::NewL(aContext, iKey, iHasHistory, KSmsDataProviderImplUid); + + RegisterSnapshotL(); + + iDataBaseOpened = ETrue; + iCurrentState = ESmsOpenAndWaiting; + User::RequestComplete(iCallerStatus, KErrNone); + + LOGGER_LEAVEFN("CSmsDataStore::DoOpenL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoCancelRequest +// Not supported, does nothing. +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoCancelRequest() + { + LOGGER_ENTERFN("CSmsDataStore::DoCancelRequestL"); + LOGGER_LEAVEFN("CSmsDataStore::DoCancelRequestL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoStoreName +// Returns the name of the DataStore +// ----------------------------------------------------------------------------- +const TDesC& CSmsDataStore::DoStoreName() const + { + LOGGER_ENTERFN("CSmsDataStore::DoStoreName"); + + if (iDataBaseOpened) + { + LOGGER_LEAVEFN("CSmsDataStore::DoStoreName"); + return KNSmlDefaultLocalDbName; + } + + LOGGER_LEAVEFN("CSmsDataStore::DoStoreName"); + return KNullDesC; + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoBeginTransactionL +// Transactions are not supported. +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoBeginTransactionL() + { + LOGGER_ENTERFN("CSmsDataStore::DoBeginTransactionL"); + LOGGER_WRITE("CSmsDataStore::DoBeginTransactionL leaved with KErrNotSupported.") + User::Leave(KErrNotSupported); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoCommitTransactionL +// Transactions are not supported. +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoCommitTransactionL(TRequestStatus& aStatus) + { + LOGGER_ENTERFN("CSmsDataStore::DoCommitTransactionL"); + LOGGER_WRITE("CSmsDataStore::DoCommitTransactionL failed with KErrNotSupported."); + + iCallerStatus = &aStatus; + User::RequestComplete(iCallerStatus, KErrNotSupported); + + LOGGER_LEAVEFN("CSmsDataStore::DoCommitTransactionL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoRevertTransaction +// Transactions are not supported. +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoRevertTransaction(TRequestStatus& aStatus) + { + LOGGER_ENTERFN("CSmsDataStore::DoRevertTransaction"); + iCallerStatus = &aStatus; + User::RequestComplete(iCallerStatus, KErrNone); + LOGGER_LEAVEFN("CSmsDataStore::DoRevertTransaction"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoBeginBatchL +// Batching is not supported. +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoBeginBatchL() + { + LOGGER_ENTERFN("CSmsDataStore::DoBeginBatchL"); + LOGGER_WRITE("CSmsDataStore::DoBeginBatchL leaved with KErrNotSupported."); + User::Leave(KErrNotSupported); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoCommitBatchL +// Batching is not supported +// ----------------------------------------------------------------------------- +// +void CSmsDataStore::DoCommitBatchL(RArray& /*aResultArray*/, TRequestStatus& aStatus) + { + LOGGER_ENTERFN("CSmsDataStore::DoCommitBatchL"); + LOGGER_WRITE("CSmsDataStore::DoCommitBatchL failed with KErrNotSupported"); + + iCallerStatus = &aStatus; + User::RequestComplete(iCallerStatus, KErrNotSupported); + + LOGGER_LEAVEFN("CSmsDataStore::DoCommitBatchL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoCancelBatch +// Batching is not supported +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoCancelBatch() + { + LOGGER_ENTERFN("CSmsDataStore::DoCancelBatch"); + LOGGER_LEAVEFN("CSmsDataStore::DoCancelBatch"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoSetRemoteStoreFormatL +// Not supported +// ----------------------------------------------------------------------------- +// +void CSmsDataStore::DoSetRemoteStoreFormatL(const CSmlDataStoreFormat& /*aServerDataStoreFormat*/) + { + LOGGER_ENTERFN("CSmsDataStore::DoSetRemoteStoreFormatL"); + LOGGER_LEAVEFN("CSmsDataStore::DoSetRemoteStoreFormatL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoSetRemoteMaxObjectSize +// Not supported +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoSetRemoteMaxObjectSize(TInt /*aServerMaxObjectSize*/) + { + LOGGER_ENTERFN("CSmsDataStore::DoSetRemoteMaxObjectSize"); + LOGGER_LEAVEFN("CSmsDataStore::DoSetRemoteMaxObjectSize"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoMaxObjectSize +// +// ----------------------------------------------------------------------------- +TInt CSmsDataStore::DoMaxObjectSize() const + { + LOGGER_ENTERFN("CSmsDataStore::DoMaxObjectSize"); + LOGGER_LEAVEFN("CSmsDataStore::DoMaxObjectSize"); + return 0; + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoOpenItemL +// Opens item in the DataStore, reads it (either completely or partially) +// to the temporary buffer where it can be later read to the remote database. +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoOpenItemL(TSmlDbItemUid aUid, TBool& aFieldChange, + TInt& aSize, TSmlDbItemUid& aParent, TDes8& aMimeType, + TDes8& aMimeVer, TRequestStatus& aStatus) + { + LOGGER_ENTERFN("CSmsDataStore::DoOpenItemL"); + + LOGGER_WRITE_1("Opening item %d.", aUid); + + // Store these for later use + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Check that we're in a proper state + if (iCurrentState != ESmsOpenAndWaiting) + { + LOGGER_WRITE_1("CSmsDataStore::DoOpenItemL, Incorrect state: %d", iCurrentState); + } + + // Allocate new buffer + SAFEDELETE(iDataBuffer); + iDataBuffer = CBufFlat::NewL(KDataBufferSize); + + TBool userFolderFound(EFalse); + TTime timeStamp; + TPtrC folderName; + userFolderFound = iMsvApi->FindUserFolderL(aUid, folderName, timeStamp); + if (userFolderFound) + { + iMimeType = EMessageFolder; + iParentId = KMsvMyFoldersEntryIdValue; + + iFolderObjectParser->SetName(folderName); + iFolderObjectParser->SetCreatedDate(timeStamp.DateTime()); + iFolderObjectParser->SetModifiedDate(timeStamp.DateTime()); + iFolderObjectParser->ExportFolderXmlL(*iDataBuffer); + } + else + { + iMimeType = ESmsMessage; + iMessageParser->ResetAll(); + + TBool unread; + TMsvId parent; + TRAPD(error, iMsvApi->RetrieveSML(aUid, parent, *iMessageParser, unread)); + if(error != KErrNone) + { + User::RequestComplete(iCallerStatus, KErrNotFound); + LOGGER_WRITE_1("RetrieveSML(aUid, &parser, flags) leaved with %d.", error); + return; + } + + iParentId = parent; + iMessageParser->ConstructMessageL(*iDataBuffer); + } + + // Adjust buffer + iDataBuffer->Compress(); + iReaderPosition = 0; + iCurrentState = ESmsItemOpen; + + // Return these + aFieldChange = EFalse; + aParent = iParentId; + aSize = iDataBuffer->Size(); + + if (iMimeType == EMessageFolder) + { + TInt targetLength = KFolderMimeType().Length(); + if (aMimeType.MaxLength() < targetLength) + targetLength = aMimeType.MaxLength(); + aMimeType.Copy(KFolderMimeType().Ptr(), targetLength); + + // Set mime version (do not exceed the allocated buffer) + targetLength = KFolderMimeVersion().Length(); + if (aMimeVer.MaxLength() < targetLength) + targetLength = aMimeVer.MaxLength(); + aMimeVer.Copy(KFolderMimeVersion().Ptr(), targetLength); + } + else // ESmsMessage + { + TInt targetLength = KSmsMimeType().Length(); + if (aMimeType.MaxLength() < targetLength) + targetLength = aMimeType.MaxLength(); + aMimeType.Copy(KSmsMimeType().Ptr(), targetLength); + + // Set mime version (do not exceed the allocated buffer) + targetLength = KSmsMimeVersion().Length(); + if (aMimeVer.MaxLength() < targetLength) + targetLength = aMimeVer.MaxLength(); + aMimeVer.Copy(KSmsMimeVersion().Ptr(), targetLength); + } + + // Signal we're complete + User::RequestComplete(iCallerStatus, KErrNone); + + LOGGER_LEAVEFN("CSmsDataStore::DoOpenItemL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoCreateItemL +// Create new item to the message store. +// Return the id number of the newly created item +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoCreateItemL(TSmlDbItemUid& aUid, TInt aSize, + TSmlDbItemUid aParent, const TDesC8& aMimeType, const TDesC8& /*aMimeVer*/, + TRequestStatus& aStatus) + { + LOGGER_ENTERFN("CSmsDataStore::DoCreateItemL"); + + // Store some variables for further use + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Ensure that we're in proper state + if (iCurrentState != ESmsOpenAndWaiting) + { + LOGGER_WRITE_1("Incorrect state: %d", iCurrentState); + } + + // Check MIME type + LOG(aMimeType); + if (aMimeType.Compare( KFolderMimeType() ) == 0) + { + iMimeType = EMessageFolder; + } + else if (aMimeType.Compare( KSmsMimeType() ) == 0) + { + iMimeType = ESmsMessage; + } + else + { + User::RequestComplete( iCallerStatus, KErrNotSupported ); + LOGGER_WRITE("Bad MIME type"); + return; + } + + LOGGER_WRITE_1( "Parent folder: %d", aParent); + if ((iMimeType == EMessageFolder && aParent != KMsvMyFoldersEntryIdValue) || + (iMimeType == ESmsMessage && !iMsvApi->ValidFolderL(aParent))) + { + User::RequestComplete( iCallerStatus, KErrNotSupported ); + LOGGER_WRITE( "Bad parent folder"); + return; + } + + // Ensure that we've got enough disk space for the item + if(iMsvApi->DiskSpaceBelowCriticalLevelL(aSize)) + { + User::RequestComplete(iCallerStatus, KErrDiskFull); + LOGGER_WRITE("Disk full"); + return; + } + + // Store uid values + iCreatedUid = &aUid; + iParentId = aParent; + + // Create message buffer, item will be written into this buffer + SAFEDELETE(iDataBuffer); + iDataBuffer = CBufFlat::NewL(KDataBufferSize); + iWriterPosition = 0; + iCurrentState = ESmsItemCreating; + + // Signal we're complete + User::RequestComplete( iCallerStatus, KErrNone ); + + LOGGER_LEAVEFN("CSmsDataStore::DoCreateItemL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoReplaceItemL +// Begin the replace operation, ensure that the item really exists +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoReplaceItemL(TSmlDbItemUid aUid, TInt aSize, TSmlDbItemUid aParent, + TBool /*aFieldChange*/, TRequestStatus& aStatus) + { + LOGGER_ENTERFN("CSmsDataStore::DoReplaceItemL"); + LOGGER_WRITE_1("Replacing item %d.", aUid); + LOGGER_WRITE_1("Parent folder: %d.", aParent); + + // Store some variables for further use + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Ensure proper state + if (iCurrentState != ESmsOpenAndWaiting) + { + LOGGER_WRITE_1("Incorrect state: %d", iCurrentState); + } + + // Ensure that we've got enough disk space for the item + if (iMsvApi->DiskSpaceBelowCriticalLevelL(aSize)) + { + User::RequestComplete(iCallerStatus, KErrDiskFull); + LOGGER_WRITE("Disk full"); + return; + } + + // Find entry + CMsvEntry* entry(NULL); + TRAPD(error, entry = iMsvApi->MsvSessionL()->GetEntryL(aUid)); + if (error != KErrNone) + { + User::RequestComplete(iCallerStatus, KErrNotFound); + LOGGER_WRITE("Item not found"); + return; + } + + // This is the representation of the actual message + TMsvEntry tEntry = entry->Entry(); + + // Not needed anymore + SAFEDELETE(entry); + + // Check entry type + if (tEntry.iType == KUidMsvFolderEntry) + { + iMimeType = EMessageFolder; + LOGGER_WRITE("Type: folder"); + } + else + { + iMimeType = ESmsMessage; + LOGGER_WRITE("Type: SMS message"); + } + + if ((iMimeType == EMessageFolder && aParent != KMsvMyFoldersEntryIdValue) || + (iMimeType == ESmsMessage && !iMsvApi->ValidFolderL(aParent) || + (aParent != tEntry.Parent()))) + { + User::RequestComplete(iCallerStatus, KErrNotSupported); + LOGGER_WRITE_1("Bad parent folder, message entry parent is %d", tEntry.Parent()); + return; + } + + // Store these for further use + iParentId = aParent; + iCurrentId = aUid; + + // Create temporary buffer for message data, item will be written here + SAFEDELETE(iDataBuffer); + iDataBuffer = CBufFlat::NewL(KDataBufferSize); + iWriterPosition = 0; + iCurrentState = ESmsItemUpdating; + + // Signal we're complete + User::RequestComplete(iCallerStatus, KErrNone); + + LOGGER_LEAVEFN("CSmsDataStore::DoReplaceItemL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoReadItemL +// Read specified amount of data from the temporary buffer +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoReadItemL(TDes8& aBuffer) + { + LOGGER_ENTERFN("CSmsDataStore::DoReadItemL"); + + // Check that we're in proper state + if (iCurrentState != ESmsItemOpen || !iDataBuffer) + { + LOGGER_WRITE("CSmsDataStore::DoReadItemL leaved with KErrNotReady."); + User::Leave(KErrNotReady); + } + + if (iReaderPosition == KDataBufferNotReady) + { + LOGGER_WRITE("CSmsDataStore::DoReadItemL leaved with KErrEof."); + User::Leave(KErrEof); + } + + // This is how much we've got left in the buffer + TInt left = iDataBuffer->Size() - iReaderPosition; + + // Make sure that there's something to read + if(left > 0) + { + // This is how much there's space in the destination buffer + TInt destSize = aBuffer.MaxSize(); + + // This is how much we can read + TInt toRead = destSize < left ? destSize : left; + + // Read the data from the buffer, then update the position + iDataBuffer->Read(iReaderPosition, aBuffer, toRead); + iReaderPosition += toRead; + } + else + { + iReaderPosition = KDataBufferNotReady; + LOGGER_WRITE("CSmsDataStore::DoReadItemL leaved with KErrEof."); + User::Leave(KErrEof); + } + + LOGGER_LEAVEFN("CSmsDataStore::DoReadItemL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoWriteItemL +// Write specified amount of data to the temporary buffer +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoWriteItemL(const TDesC8& aData) + { + LOGGER_ENTERFN("CSmsDataStore::DoWriteItemL"); + + // Ensure that we're in proper state + if ( iCurrentState != ESmsItemCreating && iCurrentState != ESmsItemUpdating ) + { + LOGGER_WRITE("CSmsDataStore::DoWriteItemL leaved with KErrNotReady."); + User::Leave( KErrNotReady ); + } + + // Calculate total size + TInt totalSize = aData.Size() + iDataBuffer->Size(); + + // Check that we have enough disk space to store this much data + if ( iMsvApi->DiskSpaceBelowCriticalLevelL( totalSize ) ) + { + LOGGER_WRITE("CSmsDataStore::DoWriteItemL leaved with KErrDiskFull."); + User::Leave(KErrDiskFull); + } + + // Add data to buffer + iDataBuffer->InsertL( iWriterPosition, aData ); + iWriterPosition += aData.Size(); + + LOGGER_LEAVEFN("CSmsDataStore::DoWriteItemL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoCommitItemL +// Commits item from temporary buffer to the message store +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoCommitItemL(TRequestStatus& aStatus) + { + LOGGER_ENTERFN("CSmsDataStore::DoCommitItemL"); + TInt error(KErrNone); + + // Store some variables + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Check that we're in proper state + if ((iCurrentState != ESmsItemCreating && iCurrentState != ESmsItemUpdating) || !iDataBuffer) + { + User::RequestComplete(iCallerStatus, KErrNotReady); + LOGGER_WRITE_1("Bad state: %d", iCurrentState); + return; + } + + iDataBuffer->Compress(); + TInt size = iDataBuffer->Size(); + + // Variable to hold the information whether SMS message is unread or not for Change Finder. + // For message folders this information is not relevant and value is EFalse by default. + TBool unread(EFalse); + + if ( iMimeType == ESmsMessage ) + { + // Reset parser + iMessageParser->ResetAll(); + + // This function returns the index, where the parsing ends (>=0) + // (the error codes are in the range below 0) + error = iMessageParser->ParseMessageL(iDataBuffer->Ptr(0)); + + if ( error >= 0 ) + { + unread = iMessageParser->iStatus.Compare(KVMsgStatusUnread) == 0 ? ETrue : EFalse; + + // Check the datastore state. We're either creating or updating an item. + if (iCurrentState == ESmsItemCreating) + { + TMsvId id; + TMsvId temporaryParent = iParentId; + // in message sending case, save message first to drafts folder + if ( iParentId == KMsvGlobalOutBoxIndexEntryId ) + { + temporaryParent = KMsvDraftEntryId; + } + + TRAP(error, iMsvApi->AddSML(*iMessageParser, temporaryParent, id)); + if ( error == KErrNone ) + { + *iCreatedUid = id; + iCurrentId = id; + } + else + { + LOGGER_WRITE_1("iMsvApi->AddSML leaved with %d.", error); + } + } + else // EItemUpdating + { + if ( iParentId == KMsvGlobalInBoxIndexEntryId ) + { + // For arrived message in Inbox only status is updated + TRAP(error, iMsvApi->UpdateSMStatusL( iCurrentId, *iMessageParser)); + } + else + { + TRAP(error, iMsvApi->ReplaceSML(iCurrentId, *iMessageParser)); + } + if(error != KErrNone) + { + LOGGER_WRITE_1("iMsvApi->ReplaceSML leaved with %d.", error); + } + } + } + else + { + LOGGER_WRITE_1("iMessageParser->ParseMessageL failed with %d.", error); + } + } // if (iMimeType == ESmsMessage) + + else // EMessageFolder + { + error = iFolderObjectParser->ImportFolderXml(iDataBuffer->Ptr(0)); + + if ( error == KErrNone ) + { + const TDesC& name = iFolderObjectParser->GetName(); + + if ( name.Length() > 0 ) + { + if ( iCurrentState == ESmsItemCreating ) + { + TMsvId id; + error = iMsvApi->AddUserFolderL( id, name ); + if ( error == KErrNone ) + { + *iCreatedUid = id; + iCurrentId = id; + } + else + { + LOGGER_WRITE_1("iMsvApi->AddFolderL failed with %d", error); + } + } + else // Updating + { + error = iMsvApi->UpdateUserFolderL( iCurrentId, name ); + if ( error != KErrNone ) + { + LOGGER_WRITE_1("iMsvApi->UpdateFolderL failed with %d", error); + } + } + } + else + { + LOGGER_WRITE("No folder name available"); + error = KErrArgument; + } + } + } + + // Send the message if the parent folder is outbox + if( iParentId == KMsvGlobalOutBoxIndexEntryId && + iMimeType == ESmsMessage && + iCurrentState == ESmsItemCreating && + error == KErrNone ) + { + LOGGER_WRITE("CSmsDataStore::DoCommitItemL, sending message."); + + TRAP( error, iMsvApi->MoveSML( iCurrentId, iParentId ) ); + if( error != KErrNone ) + { + LOGGER_WRITE_1("Moving to folder failed with %d", error); + iMsvApi->DeleteSML( iCurrentId ); + } + else + { + TRAP( error, iMsvApi->SendSML(iCurrentId) ); + if ( error != KErrNone ) + { + LOGGER_WRITE_1("iMsvApi->SendSML failed with %d.", error); + iMsvApi->DeleteSML( iCurrentId ); + } + } + } + + if ( error == KErrNone ) // Update Change Finder + { + CMsvSession* msvSession = iMsvApi->MsvSessionL(); + TMsvId service; + TMsvEntry msgEntry; + + // Inform ChangeFinder of added item + TSnapshotItem snapshotItem( iCurrentId, iParentId, unread ); + error = msvSession->GetEntry( iCurrentId, service, msgEntry ); + + if ( error == KErrNone ) + { + snapshotItem.SetLastChangedDate( msgEntry.iDate ); + if ( iMimeType == EMessageFolder ) + { + snapshotItem.SetFolderNameL( msgEntry.iDetails ); + } + + if ( iCurrentState == ESmsItemCreating ) + { + iChangeFinder->ItemAddedL( snapshotItem ); + } + else + { + iChangeFinder->ItemUpdatedL( snapshotItem ); + } + } + else + { + LOGGER_WRITE_1("CMsvSession::GetEntry failed with %d", error); + } + } + + // Reset and destroy write buffer, it's no longer needed + iWriterPosition = KDataBufferNotReady; + SAFEDELETE(iDataBuffer); + + // We'll be waiting for next event, signal we're done + iCurrentState = ESmsOpenAndWaiting; + User::RequestComplete(iCallerStatus, error); + + LOGGER_LEAVEFN("CSmsDataStore::DoCommitItemL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoCloseItem +// Closes open item in the data store +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoCloseItem() + { + LOGGER_ENTERFN("CSmsDataStore::DoCloseItem"); + + // Make sure that we're opened an item + if ( iCurrentState == ESmsItemOpen ) + { + // Reset read buffer + iReaderPosition = KDataBufferNotReady; + SAFEDELETE(iDataBuffer); + + // Start to wait for the next operation + iCurrentState = ESmsOpenAndWaiting; + } + else + { + LOGGER_WRITE_1("CSmsDataStore::DoCloseItem, invalid state %d.", iCurrentState); + } + + LOGGER_LEAVEFN("CSmsDataStore::DoCloseItem"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoMoveItemL +// Moves item from one folder to another in the message store +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoMoveItemL(TSmlDbItemUid aUid, TSmlDbItemUid aNewParent, TRequestStatus& aStatus) + { + LOGGER_ENTERFN("CSmsDataStore::DoMoveItemL"); + + LOGGER_WRITE_1("Moving item %d.", aUid); + + // Store some variables for further use + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Check that we're in proper state + if (iCurrentState != ESmsOpenAndWaiting) + { + LOGGER_WRITE_1("CSmsDataStore::DoMoveItemL, Incorrect state: %d", iCurrentState); + } + + TInt error_move(KErrNone); + TRAP(error_move, iMsvApi->MoveSML(aUid, aNewParent)); + if(error_move != KErrNone) + { + User::RequestComplete(iCallerStatus, error_move); + LOGGER_WRITE_1("iMsvApi->MoveSML leaved with %d.", error_move); + return; + } + + // Inform ChangeFinder of the moved item + TSnapshotItem snapshotItem(aUid, aNewParent); + iChangeFinder->ItemMovedL(snapshotItem); + + // Signal we're done + User::RequestComplete(iCallerStatus, KErrNone); + + LOGGER_LEAVEFN("CSmsDataStore::DoMoveItemL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoDeleteItemL +// Removes item from the message store +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoDeleteItemL(TSmlDbItemUid aUid, TRequestStatus& aStatus) + { + LOGGER_ENTERFN("CSmsDataStore::DoDeleteItemL"); + + // Store some variables for further use + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Check that we're in proper state + if (iCurrentState != ESmsOpenAndWaiting) + { + LOGGER_WRITE_1("CSmsDataStore::DoDeleteItemL, Incorrect state: %d", iCurrentState); + } + + TInt error(KErrNone); + + // Check if this is a user folder + TBool userFolder = iMsvApi->FindUserFolderL(aUid); + + if (userFolder) + { + LOGGER_WRITE_1("Delete user folder %d", aUid); + + // First delete SMS messages under the folder + CMsvEntrySelection* deletedItems = iMsvApi->CleanFolderGetMsvIdsL(aUid); + CleanupStack::PushL(deletedItems); + + for (TInt i = 0; i < deletedItems->Count(); i++) + { + TMsvId id = deletedItems->At(i); + TSnapshotItem item(id); + iChangeFinder->ItemDeletedL(item); + } + CleanupStack::PopAndDestroy(deletedItems); + + // Then delete the actual folder + // Note: folder is not deleted if it contains other message items (like MMS) + TRAP(error, iMsvApi->DeleteUserFolderL(aUid)); + } + else + { + LOGGER_WRITE_1("Delete SMS message %d", aUid); + TRAP(error, iMsvApi->DeleteSML(aUid)) + } + + if ( error != KErrNone ) + { + User::RequestComplete(iCallerStatus, error); + LOGGER_WRITE_1("iMsvApi function call leaved with %d", error); + return; + } + + // Inform ChangeFinder of the removed item + TSnapshotItem item(aUid); + iChangeFinder->ItemDeletedL(item); + + // Signal we're done + User::RequestComplete(iCallerStatus, KErrNone); + + LOGGER_LEAVEFN("CSmsDataStore::DoDeleteItemL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoSoftDeleteItemL +// Soft delete is not supported. +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoSoftDeleteItemL(TSmlDbItemUid /*aUid*/, TRequestStatus& aStatus) + { + LOGGER_ENTERFN("CSmsDataStore::DoSoftDeleteItemL"); + + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + User::RequestComplete(iCallerStatus, KErrNotSupported); + + LOGGER_LEAVEFN("CSmsDataStore::DoSoftDeleteItemL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoDeleteAllItemsL +// Deletes all items in the standard folders of message store +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoDeleteAllItemsL(TRequestStatus& aStatus) + { + LOGGER_ENTERFN("CSmsDataStore::DoDeleteAllItemsL"); + + // Store some variables for further use + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Check that we're in proper state + if (iCurrentState != ESmsOpenAndWaiting) + { + LOGGER_WRITE_1("CSmsDataStore::DoDeleteAllItemsL, Incorrect state: %d", iCurrentState); + } + + // Delete all messages in the standard folders (except outbox) + iMsvApi->CleanFolderL(KMsvGlobalInBoxIndexEntryId); + iMsvApi->CleanFolderL(KMsvDraftEntryId); + iMsvApi->CleanFolderL(KMsvSentEntryId); + + iMsvApi->CleanUserFoldersL(); + + iChangeFinder->ResetL(); + + User::RequestComplete(iCallerStatus, KErrNone); + + LOGGER_LEAVEFN("CSmsDataStore::DoDeleteAllItemsL"); + } + + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoHasSyncHistory +// This method returns ETrue if Data Store has history information. +// Slow-sync will be used if Data Store does not have history information. +// ----------------------------------------------------------------------------- +TBool CSmsDataStore::DoHasSyncHistory() const + { + LOGGER_WRITE_1("CSmsDataStore::DoHasSyncHistory return %d", (TInt)iHasHistory ); + + // iHasHistory is initialized in DoOpenL method + return iHasHistory; + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoAddedItems +// This method returns UIDs of added items. Those items are added after previous +// synchronization with current synchronization relationship. +// ----------------------------------------------------------------------------- +const MSmlDataItemUidSet& CSmsDataStore::DoAddedItems() const + { + LOGGER_ENTERFN("CSmsDataStore::DoAddedItems"); + + // Ensure that we're in a proper state + if (iCurrentState != ESmsOpenAndWaiting) + { + LOGGER_WRITE_1("CSmsDataStore::DoAddedItems, invalid state %d.", iCurrentState); + } + + TInt error(KErrNone); + + // Clear new-items array + iNewItems->Reset(); + + // Search for new items + TRAP( error, iChangeFinder->FindNewItemsL(*iNewItems) ); + if ( error != KErrNone ) + { + LOGGER_WRITE_1("CSmsDataStore::DoAddedItems, iChangeFinder->FindNewItemsL leaved with %d.", error); + } + + LOGGER_WRITE_1("New item count: %d.", iNewItems->ItemCount()); + LOGGER_LEAVEFN("CSmsDataStore::DoAddedItems"); + + return *iNewItems; + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoDeletedItems +// +// ----------------------------------------------------------------------------- +const MSmlDataItemUidSet& CSmsDataStore::DoDeletedItems() const + { + LOGGER_ENTERFN("CSmsDataStore::DoDeletedItemsL"); + + // Ensure that we're in a proper state + if (iCurrentState != ESmsOpenAndWaiting) + { + LOGGER_WRITE_1("CSmsDataStore::DoDeletedItems, invalid state %d.", iCurrentState); + } + + TInt error(KErrNone); + + // Clear deleted-items array + iDeletedItems->Reset(); + + // Search for deleted items + TRAP( error, iChangeFinder->FindDeletedItemsL(*iDeletedItems) ); + if ( error != KErrNone ) + { + LOGGER_WRITE_1("CSmsDataStore::DoDeletedItems, iChangeFinder->FindDeletedItemsL leaved with %d.", error); + } + + + LOGGER_WRITE_1("Deleted item count: %d.", iDeletedItems->ItemCount()); + LOGGER_LEAVEFN("CSmsDataStore::DoDeletedItemsL"); + return *iDeletedItems; + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoSoftDeletedItems +// Not directly supported, equals to "hard" delete +// ----------------------------------------------------------------------------- +const MSmlDataItemUidSet& CSmsDataStore::DoSoftDeletedItems() const + { + TRACE_FUNC; + + // Return empty array as a result + iSoftDeletedItems->Reset(); + return *iSoftDeletedItems; + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoModifiedItems +// Finds all modified items in the data store +// ----------------------------------------------------------------------------- +const MSmlDataItemUidSet& CSmsDataStore::DoModifiedItems() const + { + LOGGER_ENTERFN("CSmsDataStore::DoModifiedItems"); + + // Ensure that we're in a proper state + if (iCurrentState != ESmsOpenAndWaiting) + { + LOGGER_WRITE_1("CSmsDataStore::DoModifiedItems, invalid state %d.", iCurrentState); + } + + TInt error(KErrNone); + + // Clear updated-items array + iUpdatedItems->Reset(); + + // Search for updated items + TRAP( error, iChangeFinder->FindChangedItemsL(*iUpdatedItems) ) + if ( error != KErrNone ) + { + LOGGER_WRITE_1("CSmsDataStore::DoModifiedItems, iChangeFinder->FindChangedItemsL leaved with %d.", error); + } + else + { + TRAP( error, iChangeFinder->FindMovedItemsL(*iUpdatedItems) ); + if( error != KErrNone ) + { + LOGGER_WRITE_1("CSmsDataStore::DoModifiedItems, iChangeFinder->FindMovedItemsL leaved with %d.", error); + } + } + + LOGGER_WRITE_1("Modified item count: %d.", iUpdatedItems->ItemCount()); + LOGGER_LEAVEFN("CSmsDataStore::DoModifiedItems"); + return *iUpdatedItems; + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoMovedItems +// Moved items not supported (handled as replaced items) +// ----------------------------------------------------------------------------- +const MSmlDataItemUidSet& CSmsDataStore::DoMovedItems() const + { + TRACE_FUNC; + + // Clear moved-items array + iMovedItems->Reset(); + + return *iMovedItems; + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoResetChangeInfoL +// Resets change history in the data store. All content is considered +// new in the data store point of view. +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoResetChangeInfoL(TRequestStatus& aStatus) + { + LOGGER_ENTERFN("CSmsDataStore::DoResetChangeInfoL"); + + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Check that we're in proper state + if (iCurrentState != ESmsOpenAndWaiting) + { + LOGGER_WRITE_1("CSmsDataStore::DoResetChangeInfoL, invalid state %d.", iCurrentState); + } + + // Reset change info in ChangeFinder + iChangeFinder->ResetL(); + iHasHistory = EFalse; + + // Signal we're done + User::RequestComplete(iCallerStatus, KErrNone); + + LOGGER_LEAVEFN("CSmsDataStore::DoResetChangeInfoL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoCommitChangeInfoL +// Commits change info. These items are no longer reported, when change +// information is being queried. +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoCommitChangeInfoL(TRequestStatus& aStatus, const MSmlDataItemUidSet& aItems) + { + LOGGER_ENTERFN("CSmsDataStore::DoCommitChangeInfoL(MSmlDataItemUidSet)"); + LOGGER_WRITE_1("Item count: %d", aItems.ItemCount()); + + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Ensure that we're in a proper state + if (iCurrentState != ESmsOpenAndWaiting) + { + LOGGER_WRITE_1("CSmsDataStore::DoCommitChangeInfoL, invalid state %d.", iCurrentState); + } + + // Notify ChangeFinder + iChangeFinder->CommitChangesL(aItems); + iHasHistory = ETrue; + + // Signal we're done + User::RequestComplete(iCallerStatus, KErrNone); + + LOGGER_LEAVEFN("CSmsDataStore::DoCommitChangeInfoL"); + } + + +// ----------------------------------------------------------------------------- +// CSmsDataStore::DoCommitChangeInfoL +// Commits change info. There is no more nothing to report when change +// information is being queried. +// ----------------------------------------------------------------------------- +void CSmsDataStore::DoCommitChangeInfoL(TRequestStatus& aStatus) + { + LOGGER_ENTERFN("CSmsDataStore::DoCommitChangeInfoL"); + + iCallerStatus = &aStatus; + *iCallerStatus = KRequestPending; + + // Ensure that we're in a proper state + if (iCurrentState != ESmsOpenAndWaiting) + { + LOGGER_WRITE_1("CSmsDataStore::DoCommitChangeInfoL, invalid state %d.", iCurrentState); + } + + // Notify ChangeFinder + iChangeFinder->CommitChangesL(); + iHasHistory = ETrue; + + // Signal we're done + User::RequestComplete(iCallerStatus, KErrNone); + + LOGGER_LEAVEFN("CSmsDataStore::DoCommitChangeInfoL"); + } + + +// ----------------------------------------------------------------------------- +// CSmsDataStore::RegisterSnapshotL +// Sets Changefinder to compare against current message store content +// ----------------------------------------------------------------------------- +void CSmsDataStore::RegisterSnapshotL() const + { + LOGGER_ENTERFN("CSmsDataStore::RegisterSnapshotL"); + + CSnapshotArray* snapshot = new (ELeave) CSnapshotArray( KSnapshotGranularity ); + CleanupStack::PushL(snapshot); + + // Use only standard folders (outbox isn't synchronized) + LOGGER_WRITE( "KMsvGlobalInBoxIndexEntryId" ); + RegisterFolderL(snapshot, KMsvGlobalInBoxIndexEntryId); + LOGGER_WRITE( "KMsvDraftEntryId" ); + RegisterFolderL(snapshot, KMsvDraftEntryId); + LOGGER_WRITE( "KMsvSentEntryId" ); + RegisterFolderL(snapshot, KMsvSentEntryId); + LOGGER_WRITE( "KMsvGlobalOutBoxIndexEntryId" ); + RegisterFolderL(snapshot, KMsvGlobalOutBoxIndexEntryId); + RegisterUserFoldersL(snapshot); + + // Set new snapshot to compare against + iChangeFinder->SetNewSnapshot(snapshot); + + // Changefinder takes ownership of the snapshot + CleanupStack::Pop(); + + LOGGER_LEAVEFN("CSmsDataStore::RegisterSnapshotL"); + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::RegisterFolderL +// Adds a single folder into the snapshot array +// ----------------------------------------------------------------------------- +TInt CSmsDataStore::RegisterFolderL(CSnapshotArray* aSnapshot, const TMsvId& aId) const + { + LOGGER_ENTERFN("CSmsDataStore::RegisterFolderL"); + + CMsvSession* msvSession = iMsvApi->MsvSessionL(); + + // Get the folder + CMsvEntry* msvEntry = msvSession->GetEntryL(aId); + CleanupStack::PushL(msvEntry); + + // Find all of it's childs + CMsvEntrySelection* messages = msvEntry->ChildrenWithTypeL(KUidMsvMessageEntry); + CleanupStack::PopAndDestroy(); // msvEntry + CleanupStack::PushL(messages); + + TMsvId id; + TMsvEntry msg; + LOGGER_WRITE_1( "messages count %d", messages->Count() ); + for(TInt index=0; indexCount(); index++) + { + TInt result = msvSession->GetEntry(messages->At(index), id, msg); + User::LeaveIfError(result); + + // We're only interested about the SMS content + if(msg.iMtm == KUidMsgTypeSMS) + { + // Create snapshot item + TKeyArrayFix key(iKey); + TSnapshotItem item((TUint) msg.Id(), msg.Parent(), msg.Unread()); + + item.SetLastChangedDate(msg.iDate); + LOGGER_WRITE_1( "item id %d", msg.Id() ); + // Add to snapshot + aSnapshot->InsertIsqL(item, key); + } + else + { + LOGGER_WRITE("Wrong type"); + } + } + + CleanupStack::PopAndDestroy(); // messages + + LOGGER_LEAVEFN("CSmsDataStore::RegisterFolderL"); + + return KErrNone; + } + +// ----------------------------------------------------------------------------- +// CSmsDataStore::RegisterUserFoldersL +// Adds user folder messages into the snapshot array +// ----------------------------------------------------------------------------- +TInt CSmsDataStore::RegisterUserFoldersL(CSnapshotArray* aSnapshot) const + { + LOGGER_ENTERFN("CSmsDataStore::RegisterUserFoldersL"); + + CMsvSession* msvSession = iMsvApi->MsvSessionL(); + + // Get the folder + CMsvEntry* msvEntry = msvSession->GetEntryL(KMsvMyFoldersEntryIdValue); + CleanupStack::PushL(msvEntry); + + // Find all of it's childs + CMsvEntrySelection* folders = msvEntry->ChildrenWithTypeL( KUidMsvFolderEntry ); + CleanupStack::PopAndDestroy( msvEntry ); + CleanupStack::PushL( folders ); + LOGGER_WRITE_1("Folders: %d", folders->Count()); + for ( TInt index = 0; index < folders->Count(); index++ ) + { + TMsvId folderId = folders->At(index); + + if ( folderId != KMsvMyFoldersTemplatesFolderId ) + { + TMsvId service; + TMsvEntry folderEntry; + TInt result = msvSession->GetEntry(folderId, service, folderEntry); + User::LeaveIfError( result ); + + TKeyArrayFix key(iKey); + TBool unread(EFalse); + TSnapshotItem item( (TUint) folderId, folderEntry.Parent(), unread ); + item.SetLastChangedDate( folderEntry.iDate ); + item.SetFolderNameL( folderEntry.iDetails ); + + aSnapshot->InsertIsqL( item, key ); + + RegisterFolderL( aSnapshot, folderId ); + } + } + + CleanupStack::PopAndDestroy( folders ); + + // Register also SMS messages directly under My Folders + RegisterFolderL( aSnapshot, KMsvMyFoldersEntryIdValue ); + + LOGGER_LEAVEFN("CSmsDataStore::RegisterUserFoldersL"); + + return KErrNone; + } +