emailservices/emailstore/message_store/server/src/bufferedmessagecreator.cpp
changeset 0 8466d47a6819
child 12 f5907b1a1053
child 20 ecc8def7944a
--- /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();
+    }