/*
* 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 <mmsconst.h>
#include <centralrepository.h>
#include <mmscodecclient.h>
#include <sysutil.h>
#include <MmsEngineInternalCRKeys.h>
#include "mmsdatastore.h"
#include "omadsfolderobject.h"
#include "mmsadaptermsvapi.h"
#include "mmsdataproviderdefs.h"
#include "logger.h"
_LIT8( KMmsMimeType, "application/vnd.wap.mms-message" );
_LIT8( KMmsMimeVersion, "1.2" );
_LIT8( KFolderMimeType, "application/vnd.omads-folder+xml" );
_LIT8( KFolderMimeVersion, "1.2" );
const TInt KDataBufferSize = 1024;
const TUint KMMS_Flag_Read = 0x01;
// -----------------------------------------------------------------------------
// CMmsDataStore::CMmsDataStore
// C++ default constructor can NOT contain any code, that might leave.
// -----------------------------------------------------------------------------
CMmsDataStore::CMmsDataStore():
iHasHistory(EFalse),
iDataBaseOpened(EFalse),
iKey(TKeyArrayFix(_FOFF(TSnapshotItem, ItemId()), ECmpTInt))
{
}
// -----------------------------------------------------------------------------
// CMmsDataStore::ConstructL
// Symbian 2nd phase constructor, can leave.
// -----------------------------------------------------------------------------
void CMmsDataStore::ConstructL(CMsvSession &aMsvSession)
{
LOGGER_ENTERFN("CMmsDataStore::ConstructL");
iMsvSession = &aMsvSession;
// Waiter object to be used with CodecClient
iMsvWait = CMsvOperationActiveSchedulerWait::NewLC();
CleanupStack::Pop( iMsvWait );
iCodecClient = CMmsCodecClient::NewL( *iMsvSession );
iMsvApi = CMmsAdapterMsvApi::NewL( *iMsvSession );
// 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;
iFolderObjectParser = COMADSFolderObject::NewL();
LOGGER_LEAVEFN("CMmsDataStore::ConstructL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
CMmsDataStore* CMmsDataStore::NewL( CMsvSession &aMsvSession)
{
CMmsDataStore* self = new (ELeave) CMmsDataStore;
CleanupStack::PushL( self );
self->ConstructL( aMsvSession );
CleanupStack::Pop( self );
return self;
}
// -----------------------------------------------------------------------------
// CMmsDataStore::~CMmsDataStore
// Destructor
// -----------------------------------------------------------------------------
CMmsDataStore::~CMmsDataStore()
{
LOGGER_ENTERFN("CMmsDataStore::~CMmsDataStore()");
delete iDataBuffer;
delete iChangeFinder;
delete iFolderObjectParser;
delete iNewItems;
delete iDeletedItems;
delete iUpdatedItems;
delete iMovedItems;
delete iSoftDeletedItems;
delete iMsvApi;
delete iCodecClient;
delete iMsvWait;
LOGGER_LEAVEFN("CMmsDataStore::~CMmsDataStore()");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoOpenL
// Opens database. This operation is performed SYNCHRONOUSLY
// -----------------------------------------------------------------------------
void CMmsDataStore::DoOpenL( const TDesC& /*aStoreName*/,
MSmlSyncRelationship& aContext, TRequestStatus& aStatus )
{
LOGGER_ENTERFN("CMmsDataStore::DoOpenL");
iCallerStatus = &aStatus;
*iCallerStatus = KRequestPending;
if ( iDataBaseOpened )
{
User::RequestComplete( iCallerStatus, KErrInUse );
LOGGER_WRITE("CMmsDataStore::DoOpenL failed with KErrInUse.");
return;
}
*iContext = aContext;
// Create ChangeFinder object
if ( iChangeFinder )
{
delete iChangeFinder;
iChangeFinder = NULL;
}
iChangeFinder = CChangeFinder::NewL( aContext, iKey, iHasHistory, KMmsDataProviderImplUid );
// Set current snapshot, this will be compared against the old one
RegisterSnapshotL();
iDataBaseOpened = ETrue;
iCurrentState = EMmsOpenAndWaiting;
User::RequestComplete( iCallerStatus, KErrNone );
LOGGER_LEAVEFN("CMmsDataStore::DoOpenL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoCancelRequest
// Not supported, does nothing.
// -----------------------------------------------------------------------------
void CMmsDataStore::DoCancelRequest()
{
LOGGER_ENTERFN("CMmsDataStore::DoCancelRequestL");
LOGGER_LEAVEFN("CMmsDataStore::DoCancelRequestL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoStoreName
// Returns the name of the DataStore
// -----------------------------------------------------------------------------
const TDesC& CMmsDataStore::DoStoreName() const
{
LOGGER_ENTERFN("CMmsDataStore::DoStoreName");
if ( iDataBaseOpened )
{
LOGGER_LEAVEFN( "CMmsDataStore::DoStoreName" );
LOGGER_MSG_EC( "Database name: %S", &KNSmlDefaultLocalDbName );
return KNSmlDefaultLocalDbName;
}
LOGGER_LEAVEFN( "CMmsDataStore::DoStoreName" );
return KNullDesC;
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoBeginTransactionL
// Transactions are not supported.
// -----------------------------------------------------------------------------
void CMmsDataStore::DoBeginTransactionL()
{
LOGGER_ENTERFN("CMmsDataStore::DoBeginTransactionL");
LOGGER_WRITE( "CMmsDataStore::DoBeginTransactionL leaved with KErrNotSupported." );
User::Leave( KErrNotSupported );
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoCommitTransactionL
// Transactions are not supported.
// -----------------------------------------------------------------------------
void CMmsDataStore::DoCommitTransactionL( TRequestStatus& aStatus )
{
LOGGER_ENTERFN( "CMmsDataStore::DoCommitTransactionL" );
LOGGER_WRITE( "CMmsDataStore::DoCommitTransactionL failed with KErrNotSupported." );
iCallerStatus = &aStatus;
User::RequestComplete( iCallerStatus, KErrNotSupported );
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoRevertTransaction
// Transactions are not supported.
// -----------------------------------------------------------------------------
void CMmsDataStore::DoRevertTransaction( TRequestStatus& aStatus )
{
LOGGER_ENTERFN( "CMmsDataStore::DoRevertTransaction" );
iCallerStatus = &aStatus;
User::RequestComplete( iCallerStatus, KErrNotSupported );
LOGGER_LEAVEFN( "CMmsDataStore::DoRevertTransaction" );
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoBeginBatchL
// Batching is not supported.
// -----------------------------------------------------------------------------
void CMmsDataStore::DoBeginBatchL()
{
LOGGER_ENTERFN( "CMmsDataStore::DoBeginBatchL" );
LOGGER_WRITE( "CMmsDataStore::DoBeginBatchL leaved with KErrNotSupported." );
User::Leave( KErrNotSupported );
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoCommitBatchL
// Batching is not supported
// -----------------------------------------------------------------------------
//
void CMmsDataStore::DoCommitBatchL( RArray<TInt>& /*aResultArray*/, TRequestStatus& aStatus )
{
LOGGER_ENTERFN( "CMmsDataStore::DoCommitBatchL" );
LOGGER_WRITE( "CMmsDataStore::DoCommitBatchL failed with KErrNotSupported" );
iCallerStatus = &aStatus;
User::RequestComplete( iCallerStatus, KErrNotSupported );
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoCancelBatch
// Batching is not supported
// -----------------------------------------------------------------------------
void CMmsDataStore::DoCancelBatch()
{
LOGGER_ENTERFN( "CMmsDataStore::DoCancelBatch" );
LOGGER_LEAVEFN( "CMmsDataStore::DoCancelBatch" );
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoSetRemoteStoreFormatL
// Not supported
// -----------------------------------------------------------------------------
//
void CMmsDataStore::DoSetRemoteStoreFormatL( const CSmlDataStoreFormat& /*aServerDataStoreFormat*/ )
{
LOGGER_ENTERFN("CMmsDataStore::DoSetRemoteStoreFormatL");
LOGGER_LEAVEFN("CMmsDataStore::DoSetRemoteStoreFormatL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoSetRemoteMaxObjectSize
// Not supported
// -----------------------------------------------------------------------------
void CMmsDataStore::DoSetRemoteMaxObjectSize( TInt /*aServerMaxObjectSize*/ )
{
LOGGER_ENTERFN("CMmsDataStore::DoSetRemoteMaxObjectSize");
LOGGER_LEAVEFN("CMmsDataStore::DoSetRemoteMaxObjectSize");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoMaxObjectSize
// Reads the maximum MMS Message size from the central repository
// -----------------------------------------------------------------------------
TInt CMmsDataStore::DoMaxObjectSize() const
{
LOGGER_ENTERFN( "CMmsDataStore::DoMaxObjectSize" );
CRepository* repository( NULL );
TInt error( KErrNone );
TInt maxSendSize( 0 );
// Create central repository instance
TRAP( error, repository = CRepository::NewL( KCRUidMmsEngine ) );
if ( error == KErrNone )
{
// Obtain the size from the central repository.
// In the case of error we'll set the value to zero ("anything goes").
error = repository->Get( KMmsEngineMaximumSendSize, maxSendSize );
if ( error != KErrNone )
{
maxSendSize = 0;
}
delete repository;
}
else
{
LOGGER_MSG_EC( "CRepository::NewL leaved with %d", error );
}
LOGGER_LEAVEFN( "CMmsDataStore::DoMaxObjectSize" );
return maxSendSize;
}
// -----------------------------------------------------------------------------
// CMmsDataStore::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 CMmsDataStore::DoOpenItemL( TSmlDbItemUid aUid, TBool& aFieldChange,
TInt& aSize, TSmlDbItemUid& aParent, TDes8& aMimeType,
TDes8& aMimeVer, TRequestStatus& aStatus )
{
LOGGER_ENTERFN( "CMmsDataStore::DoOpenItemL" );
LOGGER_MSG_EC( "Opening item %d.", aUid );
// Store these for later use
iCallerStatus = &aStatus;
*iCallerStatus = KRequestPending;
// Check that we're in a proper state
if ( iCurrentState != EMmsOpenAndWaiting )
{
LOGGER_MSG_EC( "CMmsDataStore::DoOpenItemL, invalid state %d.", iCurrentState );
User::RequestComplete( iCallerStatus, KErrNotReady );
return;
}
TBool userFolderFound( EFalse );
TTime timeStamp;
TPtrC folderName;
userFolderFound = iMsvApi->FindUserFolderL( aUid, folderName, timeStamp );
if ( userFolderFound )
{
// Allocate new buffer
SAFEDELETE( iDataBuffer );
iDataBuffer = CBufFlat::NewL( KDataBufferSize );
iFolderObjectParser->SetName( folderName );
iFolderObjectParser->SetCreatedDate( timeStamp.DateTime() );
iFolderObjectParser->SetModifiedDate( timeStamp.DateTime() );
iFolderObjectParser->ExportFolderXmlL( *iDataBuffer );
iParentId = KMsvMyFoldersEntryIdValue;
iCurrentState = EFolderOpen;
iReadPosition = 0;
aSize = iDataBuffer->Size();
}
else // Open MMS message
{
TInt error( KErrNone );
CMsvEntry* entry( NULL );
TRAP( error, entry = iMsvSession->GetEntryL(aUid) );
if ( error != KErrNone )
{
User::RequestComplete( iCallerStatus, KErrNotFound );
LOGGER_MSG_EC("iMsvSession->GetEntryL failed with %d.", error);
return;
}
TMsvEntry messageEntry = entry->Entry();
SAFEDELETE( entry );
iCurrentId = aUid;
iParentId = messageEntry.Parent();
iReadCounter = 0;
// Check whether we need to send the whole item
if ( iChangeFinder->UpdatePartialL( aUid ) )
{
LOGGER_WRITE("EMmsItemOpenFieldUpdate");
aSize = 1;
iCurrentState = EMmsItemOpenFieldUpdate;
}
else
{
// Read the whole item from the message store to the buffer
TUint32 flags( 0 );
TRAP( error, iCodecClient->InitializeChunkedRetrievingL(
iCurrentId,
iParentId,
flags,
iUnread,
aSize,
iMsvWait->iStatus) );
if ( error != KErrNone )
{
User::RequestComplete( iCallerStatus, error );
LOGGER_MSG_EC("iCodecClient->InitializeChunkedRetrievingL failed with %d.", error);
return;
}
// Wait until the message has been processed
iMsvWait->Start();
if ( iMsvWait->iStatus != KErrNone )
{
User::RequestComplete( iCallerStatus, iMsvWait->iStatus.Int() );
LOGGER_MSG_EC( "iCodecClient->InitializeChunkedRetrievingL failed with %d",
iMsvWait->iStatus.Int() );
return;
}
aSize++; // Status byte will be added also, reserve one additional byte for that.
iCurrentState = EMmsItemOpen;
}
} // Open MMS message
aParent = iParentId;
aFieldChange = iCurrentState == EMmsItemOpenFieldUpdate ? ETrue : EFalse;
if ( iCurrentState == EFolderOpen ) // Message folder
{
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 // EMmsMessage
{
TInt targetLength = KMmsMimeType().Length();
if ( aMimeType.MaxLength() < targetLength )
{
targetLength = aMimeType.MaxLength();
}
aMimeType.Copy( KMmsMimeType().Ptr(), targetLength );
// Set mime version (do not exceed the allocated buffer)
targetLength = KMmsMimeVersion().Length();
if ( aMimeVer.MaxLength() < targetLength )
{
targetLength = aMimeVer.MaxLength();
}
aMimeVer.Copy( KMmsMimeVersion().Ptr(), targetLength );
}
LOGGER_WRITE_1("aSize: %d", aSize);
// Signal we're complete
User::RequestComplete( iCallerStatus, KErrNone );
LOGGER_LEAVEFN("CMmsDataStore::DoOpenItemL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoCreateItemL
// Create new item to the message store.
// Return the id number of the newly created item
// -----------------------------------------------------------------------------
void CMmsDataStore::DoCreateItemL( TSmlDbItemUid& aUid, TInt aSize, TSmlDbItemUid aParent,
const TDesC8& aMimeType, const TDesC8& /*aMimeVer*/, TRequestStatus& aStatus )
{
LOGGER_ENTERFN( "CMmsDataStore::DoCreateItemL" );
LOGGER_MSG_EC( "Parent folder: %d.", aParent );
// Store some variables for further use
iCallerStatus = &aStatus;
*iCallerStatus = KRequestPending;
// Ensure that we're in proper state
if ( iCurrentState != EMmsOpenAndWaiting )
{
LOGGER_MSG_EC( "Invalid state %d.", iCurrentState );
}
TBool createFolder( EFalse );
LOG( aMimeType );
if ( aMimeType.Compare( KFolderMimeType() ) == 0 )
{
createFolder = ETrue;
}
else if ( aMimeType.Compare( KMmsMimeType() ) != 0 )
{
User::RequestComplete( iCallerStatus, KErrNotSupported );
LOGGER_WRITE("Bad MIME type");
return;
}
// Ensure that we've got enough disk space for the item
if ( iCodecClient->DiskSpaceBelowCriticalLevelL( aSize ) )
{
User::RequestComplete( iCallerStatus, KErrDiskFull );
LOGGER_WRITE( "Disk full" );
return;
}
if( createFolder )
{
if ( aParent != KMsvMyFoldersEntryIdValue )
{
User::RequestComplete( iCallerStatus, KErrNotSupported );
LOGGER_WRITE( "Bad parent folder" );
return;
}
SAFEDELETE( iDataBuffer );
iDataBuffer = CBufFlat::NewL( KDataBufferSize );
iCurrentState = EFolderCreating;
iCreatedUid = &aUid;
iWrittenDataLength = 0;
}
else
{
// There is some problems on chunked data adding, so get all data to internal buffer
iCreatedUid = &aUid;
iCurrentState = EMmsItemCreating;
iWriteCounter = 0;
iWrittenDataLength = 0;
if ( iDataBuffer )
{
iDataBuffer->ResizeL( aSize );
}
else
{
iDataBuffer = CBufFlat::NewL( KDataBufferSize );
iDataBuffer->ResizeL( aSize );
}
}
iParentId = aParent;
// Signal we're complete
User::RequestComplete( iCallerStatus, KErrNone );
LOGGER_LEAVEFN("CMmsDataStore::DoCreateItemL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoReplaceItemL
// Begin the replace operation, ensure that the item really exists
// -----------------------------------------------------------------------------
void CMmsDataStore::DoReplaceItemL( TSmlDbItemUid aUid, TInt aSize, TSmlDbItemUid aParent,
TBool /*aFieldChange*/, TRequestStatus& aStatus )
{
LOGGER_ENTERFN("CMmsDataStore::DoReplaceItemL");
LOGGER_MSG_EC("Replacing item %d.", aUid);
LOGGER_MSG_EC("Parent folder: %d.", aParent);
// Store some variables for further use
iCallerStatus = &aStatus;
*iCallerStatus = KRequestPending;
// Ensure proper state
if ( iCurrentState != EMmsOpenAndWaiting )
{
LOGGER_MSG_EC("Invalid state %d.", iCurrentState);
}
// Ensure that we've got enough disk space for the item
if ( iCodecClient->DiskSpaceBelowCriticalLevelL( aSize ) )
{
User::RequestComplete( iCallerStatus, KErrDiskFull );
LOGGER_WRITE("Disk full");
return;
}
// Find entry
CMsvEntry* entry(NULL);
TRAPD( err, entry = iMsvSession->GetEntryL( aUid ) );
if ( err != KErrNone )
{
User::RequestComplete( iCallerStatus, KErrNotFound );
LOGGER_MSG_EC("CMsvSession::GetEntryL failed with %d.", err)
return;
}
TMsvEntry tEntry = entry->Entry();
delete entry;
// Check entry type
TBool updateFolder(EFalse);
if ( tEntry.iType == KUidMsvFolderEntry )
{
updateFolder = ETrue;
LOGGER_WRITE("Type: folder");
}
if ( ( updateFolder && aParent != KMsvMyFoldersEntryIdValue )
|| ( !updateFolder && !iMsvApi->ValidFolderL( aParent )
|| ( aParent != tEntry.Parent() ) ) )
{
User::RequestComplete( iCallerStatus, KErrNotSupported );
LOGGER_MSG_EC("Bad parent folder, message entry parent is %d", tEntry.Parent());
return;
}
// Store these for further use
iParentId = aParent;
iCurrentId = aUid;
if ( updateFolder )
{
SAFEDELETE( iDataBuffer );
iDataBuffer = CBufFlat::NewL( KDataBufferSize );
iCurrentState = EFolderUpdating;
iWrittenDataLength = 0;
}
else
{
iCurrentState = EMmsItemUpdating;
iWriteCounter = 0;
iWrittenDataLength = 0;
if ( iDataBuffer )
{
iDataBuffer->ResizeL( aSize );
}
else
{
iDataBuffer = CBufFlat::NewL( KDataBufferSize );
iDataBuffer->ResizeL( aSize );
}
}
// Signal we're complete
User::RequestComplete( iCallerStatus, KErrNone );
LOGGER_LEAVEFN("CMmsDataStore::DoReplaceItemL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoReadItemL
// Read specified amount of data from the temporary buffer
// -----------------------------------------------------------------------------
void CMmsDataStore::DoReadItemL( TDes8& aBuffer )
{
LOGGER_ENTERFN("CMmsDataStore::DoReadItemL");
if ( iCurrentState == EFolderOpen )
{
// This is how much we've got left in the buffer
TInt left = iDataBuffer->Size() - iReadPosition;
// 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( iReadPosition, aBuffer, toRead );
iReadPosition += toRead;
}
else
{
LOGGER_WRITE("All data read");
User::Leave( KErrEof );
}
}
else if ( iCurrentState == EMmsItemOpenFieldUpdate )
{
if ( iReadCounter++ == 0 )
{
TUint8 status = ResolveStatusBits( iUnread );
aBuffer.Append( &status, 1 );
}
else
{
LOGGER_WRITE("Field update done");
User::Leave( KErrEof );
}
}
else if ( iCurrentState == EMmsItemOpen )
{
if ( iReadCounter++ == 0 )
{
TUint8 status = ResolveStatusBits( iUnread );
aBuffer.Append( &status, 1 );
iReadPosition = 0;
iLastDataChunk = EFalse;
iReadAllData = EFalse;
}
else if ( iReadAllData )
{
User::Leave( KErrEof );
}
TInt error = ReadDataRecursively( aBuffer );
if ( error != KErrNone )
{
User::Leave( error );
}
}
else
{
LOGGER_MSG_EC("CMmsDataStore::DoReadItemL: bad state %d", iCurrentState);
User::Leave( KErrNotReady );
}
LOGGER_LEAVEFN("CMmsDataStore::DoReadItemL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoWriteItemL
// Write specified amount of data to the temporary buffer
// -----------------------------------------------------------------------------
void CMmsDataStore::DoWriteItemL( const TDesC8& aData )
{
LOGGER_ENTERFN("CMmsDataStore::DoWriteItemL");
LOGGER_MSG_EC("%d",iWriteCounter);
TInt dataLength = aData.Length();
LOGGER_MSG_EC("Data length: %d", dataLength);
if ( !( dataLength > 0 ) ) // Should never happen...
{
LOGGER_WRITE("Error: no data");
User::Leave( KErrArgument );
}
if ( iCodecClient->DiskSpaceBelowCriticalLevelL( dataLength ) )
{
LOGGER_WRITE("Error: disk full");
User::Leave( KErrDiskFull );
}
TInt error( KErrNone );
if ( iCurrentState == EFolderCreating || iCurrentState == EFolderUpdating )
{
// Add data to buffer
iDataBuffer->InsertL( iWrittenDataLength, aData );
iWrittenDataLength += aData.Size();
}
else if ( iCurrentState == EMmsItemCreating )
{
if ( iWriteCounter++ == 0 )
{
iUnread = aData[0] & KMMS_Flag_Read ? EFalse : ETrue;
if ( dataLength > 1 )
{
TPtrC8 data = aData.Mid(1);
iDataBuffer->Write( iWrittenDataLength, data );
iWrittenDataLength += data.Length();
}
}
else
{
TPtrC8 data = aData.Mid(0);
iDataBuffer->Write( iWrittenDataLength, data );
iWrittenDataLength += dataLength;
}
}
else if ( iCurrentState == EMmsItemUpdating )
{
if ( iWriteCounter++ == 0 )
{
iUnread = aData[0] & KMMS_Flag_Read ? EFalse : ETrue;
if ( dataLength > 1 )
{
TPtrC8 data = aData.Mid(1);
iDataBuffer->Write( iWrittenDataLength, data );
iWrittenDataLength += data.Length();
}
else // just status update
{
UpdateMmsStatusL( iCurrentId, iUnread );
LOGGER_MSG_EC("Message status updated: %d", iUnread);
}
}
else
{
TPtrC8 data = aData.Mid(0);
iDataBuffer->Write( iWrittenDataLength, data );
iWrittenDataLength += dataLength;
}
}
else
{
LOGGER_MSG_EC("Wrong state %d", iCurrentState);
User::Leave( KErrNotReady );
}
if ( error != KErrNone )
{
LOGGER_MSG_EC("iCodecClient->NextDataPart() failed with %d", error);
User::Leave( error );
}
LOGGER_LEAVEFN("CMmsDataStore::DoWriteItemL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoCommitItemL
// Commits item from temporary buffer to the message store
// -----------------------------------------------------------------------------
void CMmsDataStore::DoCommitItemL( TRequestStatus& aStatus )
{
LOGGER_ENTERFN("CMmsDataStore::DoCommitItemL");
// Store some variables
iCallerStatus = &aStatus;
*iCallerStatus = KRequestPending;
TInt error(KErrNone);
if ( iCurrentState == EFolderCreating || iCurrentState == EFolderUpdating )
{
error = iFolderObjectParser->ImportFolderXml( iDataBuffer->Ptr(0) );
if ( error != KErrNone )
{
User::RequestComplete( iCallerStatus, error );
LOGGER_MSG_EC("ImportFolderXml failed with %d", error);
return;
}
const TDesC& name = iFolderObjectParser->GetName();
if ( name.Length() <= 0 )
{
User::RequestComplete( iCallerStatus, KErrNotSupported );
LOGGER_WRITE("Folder name is empty");
return;
}
if ( iCurrentState == EFolderCreating )
{
TMsvId id;
error = iMsvApi->AddUserFolderL( id, name );
if ( error == KErrNone )
{
*iCreatedUid = id;
iCurrentId = id;
}
else
{
LOGGER_MSG_EC("iMsvApi->AddFolderL failed with %d", error);
}
}
else
{
error = iMsvApi->UpdateUserFolderL( iCurrentId, name );
if ( error != KErrNone )
{
LOGGER_MSG_EC("iMsvApi->UpdateFolderL failed with %d", error);
}
}
}
else if ( iCurrentState == EMmsItemCreating )
{
LOGGER_WRITE("Create MMS item");
TMsvId newId(0);
TUint32 flags(0);
error = iCodecClient->CreateNewMessageEntryL( iParentId, newId );
if ( !error )
{
iCodecClient->AddMML( *iDataBuffer, iParentId, flags, iUnread, newId, iMsvWait->iStatus );
// Wait until the message has been processed
iMsvWait->Start();
error = iMsvWait->iStatus.Int();
LOGGER_WRITE_1("error: %d", error);
LOGGER_WRITE_1("AddMML newId: %d", newId);
*iCreatedUid = newId;
iCurrentId = newId;
}
}
else if ( iCurrentState == EMmsItemUpdating )
{
if ( iWrittenDataLength > 0 ) // if no data then just field update
{
TUint32 flags(0);
iCodecClient->ReplaceMML( iCurrentId, *iDataBuffer, flags, iUnread, iMsvWait->iStatus );
iMsvWait->Start();
error = iMsvWait->iStatus.Int();
}
else
{
UpdateMmsStatusL( iCurrentId, iUnread );
}
}
else
{
User::RequestComplete( iCallerStatus, KErrNotSupported );
LOGGER_MSG_EC("Bad state: %d", iCurrentState);
return;
}
delete iDataBuffer;
iDataBuffer = NULL;
if ( error == KErrNone ) // Update Change Finder
{
TMsvId service;
TMsvEntry msgEntry;
// Inform ChangeFinder of added item
TSnapshotItem snapshotItem( iCurrentId, iParentId, iUnread );
error = iMsvSession->GetEntry( iCurrentId, service, msgEntry );
if ( error == KErrNone )
{
snapshotItem.SetLastChangedDate( msgEntry.iDate );
if ( iCurrentState == EFolderCreating || iCurrentState == EFolderUpdating )
{
snapshotItem.SetFolderNameL( msgEntry.iDetails );
}
if ( iCurrentState == EFolderCreating || iCurrentState == EMmsItemCreating )
{
iChangeFinder->ItemAddedL( snapshotItem );
}
else
{
iChangeFinder->ItemUpdatedL( snapshotItem );
}
}
else
{
LOGGER_MSG_EC( "CMsvSession::GetEntry failed with %d", error );
}
}
// Send message if parent folder is Outbox
if ( iParentId == KMsvGlobalOutBoxIndexEntryId &&
iCurrentState == EMmsItemCreating &&
error == KErrNone )
{
LOGGER_WRITE("Sending message...");
iCodecClient->SendMML( iCurrentId, iMsvWait->iStatus );
iMsvWait->Start();
error = iMsvWait->iStatus.Int();
}
LOGGER_WRITE_1("error: %d", error);
// We'll be waiting for next event, signal we're done
iCurrentState = EMmsOpenAndWaiting;
User::RequestComplete( iCallerStatus, error );
LOGGER_LEAVEFN("CMmsDataStore::DoCommitItemL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoCloseItem
// Closes open item in the data store
// -----------------------------------------------------------------------------
void CMmsDataStore::DoCloseItem()
{
LOGGER_ENTERFN("CMmsDataStore::DoCloseItem");
SAFEDELETE(iDataBuffer);
if ( iCurrentState == EFolderOpen )
{
iCurrentState = EMmsOpenAndWaiting;
}
else if ( iCurrentState == EMmsItemOpen )
{
iCodecClient->ReleaseData();
iCurrentState = EMmsOpenAndWaiting;
}
else if ( iCurrentState == EMmsItemOpenFieldUpdate )
{
iCurrentState = EMmsOpenAndWaiting;
}
else
{
LOGGER_MSG_EC("Invalid state %d.", iCurrentState);
}
LOGGER_LEAVEFN("CMmsDataStore::DoCloseItem");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoMoveItemL
// Moves item from one folder to another in the message store
// -----------------------------------------------------------------------------
void CMmsDataStore::DoMoveItemL( TSmlDbItemUid aUid,
TSmlDbItemUid aNewParent, TRequestStatus& aStatus )
{
LOGGER_ENTERFN("CMmsDataStore::DoMoveItemL");
LOGGER_MSG_EC("Moving item %d.", aUid);
// Store some variables for further use
iCallerStatus = &aStatus;
*iCallerStatus = KRequestPending;
// Check that we're in proper state
if ( iCurrentState != EMmsOpenAndWaiting )
{
LOGGER_MSG_EC("CMmsDataStore::DoMoveItemL, invalid state %d.", iCurrentState);
}
// Ensure that we have this item in the message store
if ( !MmsItemExists( aUid ) )
{
User::RequestComplete( iCallerStatus, KErrNotSupported );
LOGGER_WRITE("MMS item not found");
return;
}
iCodecClient->MoveMML( aUid, aNewParent, iMsvWait->iStatus );
iMsvWait->Start();
// Inform ChangeFinder of the moved item
TMsvId service;
TMsvEntry msgEntry;
User::LeaveIfError( iMsvSession->GetEntry( aUid, service, msgEntry ) );
TBool unread = msgEntry.Unread();
TSnapshotItem snapshotItem( aUid, aNewParent, unread );
iChangeFinder->ItemMovedL( snapshotItem );
// Signal we're done
User::RequestComplete( iCallerStatus, KErrNone );
LOGGER_LEAVEFN("CMmsDataStore::DoMoveItemL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoDeleteItemL
// Removes item from the message store
// -----------------------------------------------------------------------------
void CMmsDataStore::DoDeleteItemL( TSmlDbItemUid aUid, TRequestStatus& aStatus )
{
LOGGER_ENTERFN("CMmsDataStore::DoDeleteItemL");
LOGGER_MSG_EC("Deleting item %d.", aUid);
// Store some variables for further use
iCallerStatus = &aStatus;
*iCallerStatus = KRequestPending;
TInt error(KErrNone);
// Check that we're in proper state
if ( iCurrentState != EMmsOpenAndWaiting )
{
LOGGER_MSG_EC("CMmsDataStore::DoDeleteItemL, invalid state %d.", iCurrentState);
}
// Check if this is a user folder
if ( iMsvApi->FindUserFolderL( aUid ) )
{
LOGGER_WRITE("Folder");
error = DeleteAllMessagesInFolderL( aUid );
if ( error != KErrNone )
{
User::RequestComplete( iCallerStatus, error );
LOGGER_MSG_EC("Deleting MMS messages in folder failed with %d", error);
return;
}
error = iMsvApi->DeleteUserFolderL(aUid);
if ( error != KErrNone )
{
// Note: folder is not deleted if contains other message items (like MMS)
// In this case DeleteUserFolderL returns KErrInUse.
LOGGER_MSG_EC("Deleting folder failed with %d", error);
}
}
else if ( MmsItemExists( aUid ) )
{
// Tell CodecClient to delete this message
error = iCodecClient->DeleteMM( aUid );
if ( error != KErrNone )
{
User::RequestComplete( iCallerStatus, error );
LOGGER_MSG_EC("CMmsCodecClient::DeleteMM failed with %d", error);
return;
}
// Inform ChangeFinder of the removed item
iChangeFinder->ItemDeletedL( aUid );
}
else
{
User::RequestComplete( iCallerStatus, KErrNotFound );
LOGGER_MSG_EC("Item %d is not folder or MMS message", aUid);
return;
}
LOGGER_WRITE_1("complete error: %d", error);
// Signal we're done
User::RequestComplete( iCallerStatus, error );
LOGGER_LEAVEFN("CMmsDataStore::DoDeleteItemL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoSoftDeleteItemL
// Soft delete isn't supported.
// -----------------------------------------------------------------------------
void CMmsDataStore::DoSoftDeleteItemL( TSmlDbItemUid /*aUid*/, TRequestStatus& aStatus )
{
LOGGER_ENTERFN("CMmsDataStore::DoSoftDeleteItemL");
// Store some variables for further use
iCallerStatus = &aStatus;
*iCallerStatus = KRequestPending;
// Signal we're done
User::RequestComplete( iCallerStatus, KErrNotSupported );
LOGGER_LEAVEFN("CMmsDataStore::DoSoftDeleteItemL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoDeleteAllItemsL
// Deletes all items in the standard folders of message store
// -----------------------------------------------------------------------------
void CMmsDataStore::DoDeleteAllItemsL( TRequestStatus& aStatus )
{
LOGGER_ENTERFN("CMmsDataStore::DoDeleteAllItemsL");
// Store some variables for further use
iCallerStatus = &aStatus;
*iCallerStatus = KRequestPending;
// Check that we're in proper state
if ( iCurrentState != EMmsOpenAndWaiting )
{
LOGGER_MSG_EC("CMmsDataStore::DoDeleteAllItemsL, invalid state %d.", iCurrentState);
}
TInt error(KErrNone);
TInt result(KErrNone);
// Delete all messages in the standard folders (except outbox)
error = DeleteAllMessagesInFolderL( KMsvGlobalInBoxIndexEntryId );
if ( error != KErrNone )
{
result = error;
}
error = DeleteAllMessagesInFolderL( KMsvDraftEntryId );
if ( error != KErrNone )
{
result = error;
}
error = DeleteAllMessagesInFolderL( KMsvSentEntryId );
if ( error != KErrNone )
{
result = error;
}
error = CleanUserFoldersL();
if ( error != KErrNone )
{
result = error;
}
iChangeFinder->ResetL();
User::RequestComplete( iCallerStatus, result );
LOGGER_LEAVEFN("CMmsDataStore::DoDeleteAllItemsL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DeleteAllMessagesInFolderL
// Deletes all items in the specified folder in message store
// -----------------------------------------------------------------------------
TInt CMmsDataStore::DeleteAllMessagesInFolderL( TMsvId aId )
{
LOGGER_ENTERFN("CMmsDataStore::DeleteAllMessagesInFolderL");
LOGGER_MSG_EC("Folder: %d", aId);
TInt error(KErrNone);
// Get the root folder
CMsvEntry* msvEntry = iMsvSession->GetEntryL(aId);
CleanupStack::PushL(msvEntry);
// Find all of it's childs
CMsvEntrySelection* messages = msvEntry->ChildrenWithTypeL(KUidMsvMessageEntry);
CleanupStack::PopAndDestroy(msvEntry);
CleanupStack::PushL(messages);
TMsvId service;
TMsvEntry msg;
TMsvId id;
// We are only interested of the MM content
for ( TInt index=0; index < messages->Count(); index++ )
{
id = messages->At( index );
LOGGER_MSG_EC("Message item %d:", id);
error = iMsvSession->GetEntry( id, service, msg );
if ( error != KErrNone )
{
LOGGER_MSG_EC("GetEntry failed with %d", error);
break;
}
if ( msg.iMtm == KUidMsgTypeMultimedia )
{
error = iCodecClient->DeleteMM( id );
if ( error != KErrNone )
{
LOGGER_MSG_EC("DeleteMM failed with %d", error);
break;
}
// Update Change Finder
iChangeFinder->ItemDeletedL( id );
LOGGER_WRITE("MMS message deleted");
}
}
CleanupStack::PopAndDestroy(messages);
LOGGER_LEAVEFN("CMmsDataStore::DeleteAllMessagesInFolderL");
return error;
}
// -----------------------------------------------------------------------------
// CMmsDataStore::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 CMmsDataStore::DoHasSyncHistory() const
{
LOGGER_ENTERFN("CMmsDataStore::DoHasSyncHistory");
LOGGER_LEAVEFN("CMmsDataStore::DoHasSyncHistory");
// iHasHistory is initialized in DoOpenL method
return iHasHistory;
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoAddedItems
// This method returns UIDs of added items. Those items are added after previous
// synchronization with current synchronization relationship.
// -----------------------------------------------------------------------------
const MSmlDataItemUidSet& CMmsDataStore::DoAddedItems() const
{
LOGGER_ENTERFN("CMmsDataStore::DoAddedItems");
// Ensure that we're in a proper state
if ( iCurrentState != EMmsOpenAndWaiting )
{
LOGGER_MSG_EC("CMmsDataStore::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_MSG_EC("CMmsDataStore::DoAddedItems, iChangeFinder->FindNewItemsL leaved with %d.", error);
}
LOGGER_MSG_EC("New item count: %d.", iNewItems->ItemCount());
LOGGER_LEAVEFN("CMmsDataStore::DoAddedItems");
return *iNewItems;
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoDeletedItems
//
// -----------------------------------------------------------------------------
const MSmlDataItemUidSet& CMmsDataStore::DoDeletedItems() const
{
LOGGER_ENTERFN("CMmsDataStore::DoDeletedItemsL");
// Ensure that we're in a proper state
if ( iCurrentState != EMmsOpenAndWaiting )
{
LOGGER_MSG_EC("CMmsDataStore::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_MSG_EC("CMmsDataStore::DoDeletedItems, iChangeFinder->FindDeletedItemsL leaved with %d.", error);
}
LOGGER_MSG_EC("Deleted item count: %d.", iDeletedItems->ItemCount());
LOGGER_LEAVEFN("CMmsDataStore::DoDeletedItemsL");
return *iDeletedItems;
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoSoftDeletedItems
// Not directly supported, equals to "hard" delete
// -----------------------------------------------------------------------------
const MSmlDataItemUidSet& CMmsDataStore::DoSoftDeletedItems() const
{
LOGGER_ENTERFN("CMmsDataStore::DoSoftDeletedItems");
LOGGER_LEAVEFN("CMmsDataStore::DoSoftDeletedItems");
iSoftDeletedItems->Reset();
return *iSoftDeletedItems;
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoModifiedItems
// Finds all modified items in the data store
// -----------------------------------------------------------------------------
const MSmlDataItemUidSet& CMmsDataStore::DoModifiedItems() const
{
LOGGER_ENTERFN("CMmsDataStore::DoModifiedItems");
// Ensure that we're in a proper state
if ( iCurrentState != EMmsOpenAndWaiting )
{
LOGGER_MSG_EC("CMmsDataStore::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_MSG_EC("CMmsDataStore::DoModifiedItems, iChangeFinder->FindChangedItemsL leaved with %d.", error);
}
LOGGER_MSG_EC("Modified item count: %d.", iUpdatedItems->ItemCount());
LOGGER_LEAVEFN("CMmsDataStore::DoModifiedItems");
return *iUpdatedItems;
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoMovedItems
// Finds all moved items in the data store
// -----------------------------------------------------------------------------
const MSmlDataItemUidSet& CMmsDataStore::DoMovedItems() const
{
LOGGER_ENTERFN("CMmsDataStore::DoMovedItems");
// Ensure that we're in a proper state
if ( iCurrentState != EMmsOpenAndWaiting )
{
LOGGER_MSG_EC("CMmsDataStore::DoMovedItems, invalid state %d.", iCurrentState);
}
TInt error(KErrNone);
// Clear moved-items array
iMovedItems->Reset();
// Search for moved items
TRAP( error, iChangeFinder->FindMovedItemsL( *iMovedItems ) );
if ( error != KErrNone )
{
LOGGER_MSG_EC("CMmsDataStore::DoMovedItems, iChangeFinder->FindMovedItemsL leaved with %d.", error);
}
LOGGER_MSG_EC("Moved item count: %d.", iMovedItems->ItemCount());
LOGGER_LEAVEFN("CMmsDataStore::DoMovedItems");
return *iMovedItems;
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoResetChangeInfoL
// Resets change history in the data store. All content is considered
// new in the data store point of view.
// -----------------------------------------------------------------------------
void CMmsDataStore::DoResetChangeInfoL( TRequestStatus& aStatus )
{
LOGGER_ENTERFN("CMmsDataStore::DoResetChangeInfoL");
iCallerStatus = &aStatus;
*iCallerStatus = KRequestPending;
// Check that we're in proper state
if ( iCurrentState != EMmsOpenAndWaiting )
{
LOGGER_MSG_EC("CMmsDataStore::DoResetChangeInfoL, invalid state %d.", iCurrentState);
}
// Reset change info in ChangeFinder
iChangeFinder->ResetL();
iHasHistory = EFalse;
// Signal we're done
User::RequestComplete( iCallerStatus, KErrNone );
LOGGER_LEAVEFN("CMmsDataStore::DoResetChangeInfoL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoCommitChangeInfoL
// Commits change info. These items are no longer reported, when change
// information is being queried.
// -----------------------------------------------------------------------------
void CMmsDataStore::DoCommitChangeInfoL( TRequestStatus& aStatus, const MSmlDataItemUidSet& aItems )
{
LOGGER_ENTERFN("CMmsDataStore::DoCommitChangeInfoL");
iCallerStatus = &aStatus;
*iCallerStatus = KRequestPending;
// Ensure that we're in a proper state
if ( iCurrentState != EMmsOpenAndWaiting )
{
LOGGER_MSG_EC("CMmsDataStore::DoCommitChangeInfoL, invalid state %d.", iCurrentState);
}
// Notify ChangeFinder
iChangeFinder->CommitChangesL(aItems);
iHasHistory = ETrue;
// Signal we're done
User::RequestComplete(iCallerStatus, KErrNone);
LOGGER_LEAVEFN("CMmsDataStore::DoCommitChangeInfoL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::DoCommitChangeInfoL
// Commits change info. There is no more nothing to report when change
// information is being queried.
// -----------------------------------------------------------------------------
void CMmsDataStore::DoCommitChangeInfoL(TRequestStatus& aStatus)
{
LOGGER_ENTERFN("CMmsDataStore::DoCommitChangeInfoL");
iCallerStatus = &aStatus;
*iCallerStatus = KRequestPending;
// Ensure that we're in a proper state
if ( iCurrentState != EMmsOpenAndWaiting )
{
LOGGER_MSG_EC("CMmsDataStore::DoCommitChangeInfoL, invalid state %d.", iCurrentState);
}
// Notify ChangeFinder
iChangeFinder->CommitChangesL();
iHasHistory = ETrue;
// Signal we're done
User::RequestComplete( iCallerStatus, KErrNone );
LOGGER_LEAVEFN("CMmsDataStore::DoCommitChangeInfoL");
}
// -----------------------------------------------------------------------------
// CMmsDataStore::RegisterSnapshotL
// Sets Changefinder to compare against current message store content
// -----------------------------------------------------------------------------
void CMmsDataStore::RegisterSnapshotL() const
{
CSnapshotArray* snapshot = new (ELeave) CSnapshotArray( KSnapshotGranularity );
CleanupStack::PushL(snapshot);
// Use only standard folders (except outbox)
RegisterFolderL(snapshot, KMsvGlobalInBoxIndexEntryId);
RegisterFolderL(snapshot, KMsvDraftEntryId);
RegisterFolderL(snapshot, KMsvSentEntryId);
RegisterFolderL(snapshot, KMsvGlobalOutBoxIndexEntryId);
RegisterUserFoldersL(snapshot);
// Set new snapshot to compare against
iChangeFinder->SetNewSnapshot(snapshot);
// Changefinder takes ownership of the snapshot
CleanupStack::Pop(snapshot);
}
// -----------------------------------------------------------------------------
// CMmsDataStore::RegisterFolderL
// Adds a single folder into the snapshot array
// -----------------------------------------------------------------------------
TInt CMmsDataStore::RegisterFolderL(CSnapshotArray* aSnapshot, const TMsvId& aId) const
{
// Get the root folder
CMsvEntry* msvEntry = iMsvSession->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;
// We are only interested of the MM content
for ( TInt index=0; index<messages->Count(); index++ )
{
TInt result = iMsvSession->GetEntry( messages->At( index ), id, msg );
User::LeaveIfError( result );
// We're only interested about the multimedia content
if ( msg.iMtm == KUidMsgTypeMultimedia )
{
// Create snapshot item
TKeyArrayFix key(iKey);
TSnapshotItem item( (TUint) msg.Id() );
item.SetLastChangedDate( msg.iDate );
item.SetParentId( msg.Parent() );
item.SetUnread( msg.Unread() ? ETrue : EFalse );
// Add to snapshot
aSnapshot->InsertIsqL( item, key );
}
}
CleanupStack::PopAndDestroy( messages );
return KErrNone;
}
// -----------------------------------------------------------------------------
// CMmsDataStore::MmsItemExists
// Returns ETrue if MMS item exists in the message store, otherwise EFalse
// -----------------------------------------------------------------------------
TBool CMmsDataStore::MmsItemExists( TMsvId aUid )
{
CMsvEntry* entry(NULL);
// Try to open this item
TRAPD( error, entry = iMsvSession->GetEntryL( aUid ) );
if ( error != KErrNone )
{
return EFalse;
}
TMsvEntry tEntry = entry->Entry();
TBool result(EFalse);
if ( tEntry.iType == KUidMsvMessageEntry && tEntry.iMtm == KUidMsgTypeMultimedia )
{
result = ETrue;
}
delete entry;
return result;
}
// -----------------------------------------------------------------------------
// CMmsDataStore::ResolveStatusBits
// Creates status bit field according to TMsvEntry parameter
// -----------------------------------------------------------------------------
TUint8 CMmsDataStore::ResolveStatusBits(TBool aUnread)
{
// Reset the status byte, then find the correct flags
TUint8 data(0);
// Set status according to the Read/Unread information iCurrentEntry
if ( aUnread )
{
// Status unset
data &= (~KMMS_Flag_Read);
}
else
{
// Status set
data |= KMMS_Flag_Read;
}
return data;
}
// -----------------------------------------------------------------------------
// CMmsDataStore::ReadDataRecursively
// Write specified amount of data to the temporary buffer
// -----------------------------------------------------------------------------
TInt CMmsDataStore::ReadDataRecursively( TDes8& aBuffer )
{
LOGGER_ENTERFN("CMmsDataStore::ReadDataRecursively");
TInt error(KErrNone);
TInt freeBuffer = aBuffer.MaxLength() - aBuffer.Length();
if ( freeBuffer == 0 )
{
LOGGER_WRITE("Destination buffer filled.");
return KErrNone;
}
if ( iReadPosition == 0 )
{
if ( iLastDataChunk )
{
LOGGER_WRITE("All MMS data read");
iReadAllData = ETrue;
return KErrNone;
}
else
{
error = iCodecClient->GetNextDataPart( iReadDataChunk, iLastDataChunk );
if ( error != KErrNone )
{
LOGGER_MSG_EC("iCodecClient->GetNextDataPart failed with %d", error);
return error;
}
else
{
LOGGER_MSG_EC("iCodecClient->GetNextDataPart succeeded, length %d", iReadDataChunk.Length());
}
}
}
TInt left = iReadDataChunk.Length() - iReadPosition;
if ( freeBuffer < left )
{
TPtrC8 data = iReadDataChunk.Mid(iReadPosition, freeBuffer);
aBuffer.Append(data);
iReadPosition += freeBuffer;
return KErrNone;
}
else
{
if ( left > 0 )
{
TPtrC8 data = iReadDataChunk.Mid(iReadPosition, left);
aBuffer.Append(data);
}
error = iCodecClient->ReleaseData();
if ( error != KErrNone )
{
return error;
}
iReadPosition = 0;
return ReadDataRecursively( aBuffer );
}
}
// -----------------------------------------------------------------------------
// CMmsDataStore::UpdateMmsStatusL
// Updates MMS message status
// -----------------------------------------------------------------------------
void CMmsDataStore::UpdateMmsStatusL( TMsvId aId, TBool aUnread )
{
CMsvEntry* msvEntry = iMsvSession->GetEntryL( aId );
const TMsvEntry& oldEntry = msvEntry->Entry();
TMsvEntry newEntry( oldEntry );
newEntry.SetUnread( aUnread );
CleanupStack::PushL( msvEntry );
msvEntry->ChangeL( newEntry );
CleanupStack::PopAndDestroy( msvEntry );
}
// -----------------------------------------------------------------------------
// CMmsDataStore::RegisterUserFoldersL
// Adds user folder messages into the snapshot array
// -----------------------------------------------------------------------------
TInt CMmsDataStore::RegisterUserFoldersL( CSnapshotArray* aSnapshot ) const
{
LOGGER_ENTERFN("CMmsDataStore::RegisterUserFoldersL");
// Get the folder
CMsvEntry* msvEntry = iMsvSession->GetEntryL( KMsvMyFoldersEntryIdValue );
CleanupStack::PushL(msvEntry);
// Find all of it's childs
CMsvEntrySelection* folders = msvEntry->ChildrenWithTypeL( KUidMsvFolderEntry );
CleanupStack::PopAndDestroy( msvEntry );
CleanupStack::PushL( folders );
for ( TInt index = 0; index < folders->Count(); index++ )
{
TMsvId folderId = folders->At(index);
if ( folderId != KMsvMyFoldersTemplatesFolderId )
{
TMsvId service;
TMsvEntry folderEntry;
TInt result = iMsvSession->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 MMS messages directly under My Folders
RegisterFolderL( aSnapshot, KMsvMyFoldersEntryIdValue );
LOGGER_LEAVEFN("CMmsDataStore::RegisterUserFoldersL");
return KErrNone;
}
// -----------------------------------------------------------------------------
// CMmsDataStore::CleanUserFoldersL
// Cleans all user folders from MMS messages
// -----------------------------------------------------------------------------
TInt CMmsDataStore::CleanUserFoldersL()
{
LOGGER_ENTERFN("CMmsDataStore::CleanUserFoldersL");
// Get the folder
CMsvEntry* msvEntry = iMsvSession->GetEntryL( KMsvMyFoldersEntryIdValue );
CleanupStack::PushL(msvEntry);
// Find all of it's childs
CMsvEntrySelection* folders = msvEntry->ChildrenWithTypeL( KUidMsvFolderEntry );
CleanupStack::PopAndDestroy( msvEntry );
CleanupStack::PushL( folders );
TInt error(KErrNone);
TInt result(KErrNone);
for ( TInt index = 0; index < folders->Count(); index++ )
{
TMsvId folderId = folders->At(index);
if ( folderId != KMsvMyFoldersTemplatesFolderId )
{
error = DeleteAllMessagesInFolderL(folderId);
if ( error != KErrNone )
{
LOGGER_MSG_EC("Deleting messages in folder failed with %d", error);
result = error;
}
error = iMsvApi->DeleteUserFolderL( folderId );
if ( error != KErrNone && error != KErrInUse )
{
// Note: folder is not deleted if contains other message items (like MMS)
// In this case DeleteUserFolderL returns KErrInUse.
LOGGER_MSG_EC("iMsvApi->DeleteUserFolderL failed with %d", error);
result = error;
}
}
}
CleanupStack::PopAndDestroy( folders );
// Delete all messages directly under My Folders
DeleteAllMessagesInFolderL( KMsvMyFoldersEntryIdValue );
LOGGER_LEAVEFN("CSmsDataStore::CleanUserFoldersL");
return result;
}