/*
* 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 <e32base.h>
#include <msvstd.h>
#include <msvapi.h>
#include <msvids.h>
#include <mtclreg.h>
#include <centralrepository.h>
#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<TInt>& /*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; index<messages->Count(); 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;
}