--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/emailservices/emailstore/message_store/server/src/bufferedmessagecreator.cpp Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,540 @@
+/*
+* Copyright (c) 2006 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:
+*
+*/
+
+#include "bufferedmessagecreator.h"
+
+#include "ContainerStoreContentManager.h"
+#include "ContainerStoreUtils.h"
+#include "ContainerStoreEncryption.h"
+#include "messagestoreutils.h"
+
+
+/**
+ *
+ */
+/*public static*/
+CBufferedMessageCreator* CBufferedMessageCreator::NewL(
+ CContainerStore& aStore )
+ {
+ CBufferedMessageCreator* self = new (ELeave) CBufferedMessageCreator();
+
+ CleanupStack::PushL( self );
+ self->ConstructL( aStore );
+ CleanupStack::Pop( self );
+
+ return self;
+ }
+
+
+/**
+ *
+ */
+/*public*/ TBool CBufferedMessageCreator::EnqueueL(
+ CContainerStore& aStore,
+ TMsgStoreCreateContainerCmdParams& aParams,
+ const RBuf8& aProperties )
+ {
+ TBool doEnqueue = EFalse;
+
+ if ( ( aParams.iType & EMsgStoreContainerMask ) == EMsgStoreMessageBits
+ && EFalse == aStore.IsEncryptionEnabled() )
+ {
+ if ( EFalse == iIsBatchInsert )
+ {
+ //if not in batch-mode: a message container; discard current
+ //message; start buffering.
+ ResetL( aStore );
+ }
+
+ //in batch mode containers will be queued until the batch operation is
+ //marked as complete.
+
+ aStore.AllocateIdsBlockL( iIds );
+ doEnqueue = ETrue;
+ iInProgress = ETrue;
+ }
+ else if ( ( aParams.iType & EMsgStoreContainerMask ) == EMsgStorePartBits
+ && IsContainerBuffered( aParams.iParentId ) )
+ {
+ //a part container that belongs to a buffered message container; keep
+ //buffering.
+ doEnqueue = ETrue;
+ }
+
+ if ( doEnqueue )
+ {
+ AddRequestL( aStore, aParams, aProperties );
+ }
+
+ return doEnqueue;
+ }
+
+/**
+ *
+ */
+/*private*/ void CBufferedMessageCreator::AddRequestL(
+ CContainerStore& aStore,
+ TMsgStoreCreateContainerCmdParams& aParams,
+ const RBuf8& aProperties )
+ {
+ aParams.iId = GetNextContainerIdL( aStore );
+ aParams.iId |= aParams.iType;
+
+ ContainerDescriptor* part = new (ELeave) ContainerDescriptor(
+ aParams, aProperties );
+ iContainers.AppendL( part );
+ }
+
+/**
+ *
+ */
+/*public*/ TBool CBufferedMessageCreator::IsContainerBuffered(
+ TMsgStoreId aId ) const
+ {
+ TBool belongsToCurrentMessage = EFalse;
+
+ if ( iInProgress )
+ {
+ //the buffering has started, now check the buffered containers.
+
+ TInt count = iContainers.Count();
+ for ( TInt i = 0; i < count; i++ )
+ {
+ ContainerDescriptor& container = *iContainers[i];
+
+ if ( container.iParams.iId == aId )
+ {
+ //the parent container has been buffered thus the current
+ //container must be buffered too.
+ belongsToCurrentMessage = ETrue;
+ break;
+ }
+ }
+ }
+
+ return belongsToCurrentMessage;
+ }
+
+/**
+ *
+ */
+/*public*/
+void CBufferedMessageCreator::CommitMessageL(
+ CContainerStore& aStore,
+ MContainerStoreObserver* aObserver )
+ {
+ //in batch mode commits are postponed until the batch job is marked as
+ //complete.
+ if ( EFalse == iIsBatchInsert )
+ {
+ iInProgress = EFalse;
+ CommitMessagesL( aStore, aObserver );
+ }
+ }
+
+/**
+ *
+ */
+/*public*/
+void CBufferedMessageCreator::AppendContentL(
+ CContainerStore& aStore,
+ TMsgStoreId aId,
+ RBuf8& aContentBuf )
+ {
+ TFileName filePath;
+ GetUncommittedContentPath( aStore, aId, filePath );
+
+ RFs& rfs = aStore.StoreUtils().FileSystem();
+
+ //prepare the file handle.
+ RFile file;
+ TInt err = file.Open( rfs, filePath, EFileShareAny | EFileWrite );
+ if ( KErrNotFound == err )
+ {
+ User::LeaveIfError( file.Create(
+ rfs, filePath, EFileShareAny | EFileWrite ) );
+ }
+ else if ( KErrNone != err )
+ {
+ User::Leave( err );
+ }
+ CleanupClosePushL( file );
+
+ //now append the content.
+ TInt pos = 0;
+ User::LeaveIfError( file.Seek( ESeekEnd, pos ) );
+ User::LeaveIfError( file.Write( aContentBuf ) );
+
+ CleanupStack::PopAndDestroy( &file );
+ }
+
+/**
+ *
+ */
+/*public*/ void CBufferedMessageCreator::PrependContentL(
+ CContainerStore& aStore,
+ TMsgStoreId aId,
+ RBuf8& aContentBuf )
+ {
+ if ( aContentBuf.Length() )
+ {
+ TFileName sourcePath;
+ GetUncommittedContentPath( aStore, aId, sourcePath );
+
+ if ( BaflUtils::FileExists(
+ aStore.StoreUtils().FileSystem(), sourcePath ) )
+ {
+ TFileName targetPath( sourcePath );
+ _LIT( KTmpExtension, ".tmp" );
+ targetPath.Append( KTmpExtension );
+
+ MessageStoreUtils::PrependBufferAndMoveFileL(
+ aStore.StoreUtils().FileSystem(), aStore.StoreUtils(),
+ sourcePath, targetPath, aContentBuf );
+ }
+ else
+ {
+ AppendContentL( aStore, aId, aContentBuf );
+ }
+ }
+ }
+
+/**
+ *
+ */
+/*public*/ void CBufferedMessageCreator::ReplaceContentL(
+ CContainerStore& aStore,
+ TMsgStoreId aId,
+ RBuf8& aContentBuf )
+ {
+ TFileName filePath;
+ GetUncommittedContentPath( aStore, aId, filePath );
+
+ RFile file;
+ User::LeaveIfError( file.Replace(
+ aStore.StoreUtils().FileSystem(), filePath,
+ EFileShareAny | EFileWrite ) );
+ CleanupClosePushL( file );
+
+ User::LeaveIfError( file.Write( aContentBuf ) );
+
+ CleanupStack::PopAndDestroy( &file );
+ }
+
+/**
+ *
+ */
+/*public*/ void CBufferedMessageCreator::ReplaceContentL(
+ CContainerStore& aStore,
+ TMsgStoreId aId,
+ RFile& aFile )
+ {
+ TFileName filePath;
+ GetUncommittedContentPath( aStore, aId, filePath );
+
+ MessageStoreUtils::ReplaceFileWithFileL(
+ aStore.StoreUtils().FileSystem(), aStore.StoreUtils(), aFile, filePath );
+ }
+
+/**
+ *
+ */
+/*private*/
+TContainerId CBufferedMessageCreator::GetNextContainerIdL(
+ CContainerStore& aStore )
+ {
+ if ( iIds.Count() == 0 )
+ {
+ aStore.AllocateIdsBlockL( iIds, 1 );
+ }
+
+ TContainerId id = iIds[0];
+ iIds.Remove( 0 );
+
+ return id;
+ }
+
+/**
+ *
+ */
+/*private*/ void CBufferedMessageCreator::GetUncommittedContentPath(
+ CContainerStore& aStore,
+ TMsgStoreId aId,
+ TFileName& aFilePath )
+ {
+ aFilePath = aStore.PrivatePath();
+ aFilePath.Append( KUncommittedDirName );
+
+ if ( KMsgStoreInvalidId != aId )
+ {
+ aFilePath.AppendNum( aId );
+ }
+ }
+
+/**
+ *
+ */
+/*private*/ void CBufferedMessageCreator::ConstructL( CContainerStore& aStore )
+ {
+ TFileName filePath;
+ GetUncommittedContentPath( aStore, KMsgStoreInvalidId, filePath );
+
+ RFs& rfs = aStore.StoreUtils().FileSystem();
+ TInt err = rfs.MkDirAll( filePath );
+
+ if ( KErrAlreadyExists != err && KErrNone != err )
+ {
+ User::Leave( err );
+ }
+ }
+
+/**
+ *
+ */
+/*private*/ CBufferedMessageCreator::CBufferedMessageCreator()
+ {
+ }
+
+/**
+ *
+ */
+/*public virtual*/
+CBufferedMessageCreator::~CBufferedMessageCreator()
+ {
+ iContainers.ResetAndDestroy();
+ iIds.Close();
+ }
+
+/**
+ *
+ */
+/*public*/ void CBufferedMessageCreator::ResetL( CContainerStore& aStore )
+ {
+ iInProgress = EFalse;
+ iIsBatchInsert = EFalse;
+
+ iContainers.ResetAndDestroy();
+ iIds.Close();
+
+ //then delete all of the uncommitted content files.
+ TFileName filePath;
+ GetUncommittedContentPath( aStore, KMsgStoreInvalidId, filePath );
+
+ CDir* dirList;
+ RFs& rfs = aStore.StoreUtils().FileSystem();
+
+ User::LeaveIfError(
+ rfs.GetDir( filePath, KEntryAttMaskSupported, ESortByName, dirList ) );
+ CleanupStack::PushL( dirList );
+
+ TPath fullName;
+ TInt count = dirList->Count();
+ for ( TInt i = 0; i < count; i++ )
+ {
+ fullName = filePath;
+ fullName.Append( (*dirList)[i].iName );
+
+ //error code intentionally ignored, there's nothing to do with it.
+ rfs.Delete( fullName );
+ }
+
+ CleanupStack::PopAndDestroy( dirList );
+ }
+
+/**
+ *
+ */
+/*public*/ void CBufferedMessageCreator::AbandonMessageL(
+ CContainerStore& aStore,
+ TMsgStoreId aId )
+ {
+ if ( iIsBatchInsert )
+ {
+ //unless there is a good need to support this (not aware of one at the
+ //moment) in case the batch insert mode is being used do not support
+ //abandoning individual messages; while in batch insert mode abandoning
+ //of all of the buffered messages can be achieved by starting a new
+ //batch job (BeginBatchInsertL) and immediately finishing it
+ //(FinishBatchInsertL).
+ User::Leave( KErrNotSupported );
+ }
+
+ if ( iInProgress )
+ {
+ if ( iContainers.Count() )
+ {
+ //the message container is the first in the buffer.
+ ContainerDescriptor& container = *iContainers[0];
+
+ if ( aId == container.iParams.iId )
+ {
+ ResetL( aStore );
+ }
+ }
+ }
+ }
+
+/**
+ *
+ */
+/*public*/
+void CBufferedMessageCreator::BeginBatchInsertL( CContainerStore& aStore )
+ {
+ ResetL( aStore );
+ iIsBatchInsert = ETrue;
+ }
+
+/**
+ *
+ */
+/*public*/
+void CBufferedMessageCreator::FinishBatchInsertL(
+ CContainerStore& aStore,
+ MContainerStoreObserver* aObserver )
+ {
+ iInProgress = EFalse;
+ iIsBatchInsert = EFalse;
+
+ CommitMessagesL( aStore, aObserver );
+ }
+
+
+/**
+ *
+ */
+/*private*/
+void CBufferedMessageCreator::CommitMessagesL(
+ CContainerStore& aStore,
+ MContainerStoreObserver* aObserver )
+ {
+ TRAPD( err, CommitMessagesImplL( aStore, aObserver ) );
+ ResetL( aStore );
+ User::LeaveIfError( err );
+ }
+
+/**
+ *
+ */
+/*private*/
+void CBufferedMessageCreator::CommitMessagesImplL(
+ CContainerStore& aStore,
+ MContainerStoreObserver* aObserver )
+ {
+ aStore.BeginDatabaseTransactionLC();
+
+ TInt msgIdx = -1;
+
+ TInt count = iContainers.Count();
+ for ( TInt i = 0; i < count; i++ )
+ {
+ ContainerDescriptor& part = *iContainers[i];
+
+ if ( EMsgStoreMessageBits
+ == ( part.iParams.iType & EMsgStoreContainerMask ) )
+ {
+ //current part is a message.
+
+ if ( -1 == msgIdx )
+ {
+ //starting now, just remember the message index for later.
+ msgIdx = i;
+ }
+ else
+ {
+ //got to the next message, it is time to commit the current
+ //one.
+ ContainerDescriptor& part = *iContainers[msgIdx];
+ aStore.CommitContainerL(
+ part.iParams.iId, part.iParams.iParentId,
+ part.iParams.iMailBoxId, aObserver );
+
+ msgIdx = i;
+ }
+ }
+
+ aStore.CreateContainerL(
+ part.iParams.iType,
+ part.iParams.iParentId,
+ part.iParams.iGrandparentId,
+ part.iProperties,
+ part.iParams.iId );
+
+ //commit the message last so the event notifications are the same as
+ //before the buffering (adding child parts to uncommitted message
+ //does not trigger notifications).
+ if ( msgIdx != i )
+ {
+ aStore.CommitContainerL(
+ part.iParams.iId, part.iParams.iParentId,
+ part.iParams.iMailBoxId, aObserver );
+ }
+ }
+
+ //now commit the last message.
+ if ( -1 != msgIdx )
+ {
+ ContainerDescriptor& part = *iContainers[msgIdx];
+ aStore.CommitContainerL(
+ part.iParams.iId, part.iParams.iParentId,
+ part.iParams.iMailBoxId, aObserver );
+ }
+
+ //pops the rollback item.
+ aStore.CommitDatabaseTransactionL();
+
+ //now that the containers are committed the content files can be
+ //"committed" too.
+ RFs& rfs = aStore.StoreUtils().FileSystem();
+
+ for ( TInt i = 0; i < count; i++ )
+ {
+ ContainerDescriptor& part = *iContainers[i];
+
+ TFileName filePath;
+ GetUncommittedContentPath( aStore, part.iParams.iId, filePath );
+
+ if ( BaflUtils::FileExists( rfs, filePath ) )
+ {
+ aStore.ContentManager().TransferContentFile(
+ part.iParams.iId, filePath );
+ }
+ }
+ }
+
+
+////////////////////////////////////////////////////////////
+// PartDescriptor //
+////////////////////////////////////////////////////////////
+
+/**
+ *
+ */
+CBufferedMessageCreator::ContainerDescriptor::ContainerDescriptor(
+ TMsgStoreCreateContainerCmdParams& aParams,
+ const RBuf8& aProperties )
+ : iParams( aParams )
+ {
+ iProperties.Assign( aProperties );
+ }
+
+/**
+ *
+ */
+CBufferedMessageCreator::ContainerDescriptor::~ContainerDescriptor()
+ {
+ iProperties.Close();
+ }