emailservices/emailstore/message_store/server/src/ContainerStoreContentManager.cpp
changeset 0 8466d47a6819
child 13 0396474f30f5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/emailservices/emailstore/message_store/server/src/ContainerStoreContentManager.cpp	Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,1442 @@
+/*
+* 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:  Container store content manager implementation.
+*
+*/
+
+
+
+// ========
+// INCLUDES
+// ========
+
+#include <bautils.h>
+#include <s32mem.h>
+#include <e32math.h>
+ 
+#include "ContainerStoreContentManager.h"
+#include "ContainerStoreUtils.h"
+#include "ContainerStoreEncryption.h"
+#include "ContainerStoreDefs.h"
+#include "messagestoreutils.h"
+
+
+// =========
+// CONSTANTS
+// =========
+
+// The heap buffer size for read operations.
+const TUint KReadBufferSize = 4096;
+
+// The heap buffer size for write operations.
+const TUint KWriteBufferSize = 4096;
+
+//cmail
+// The heap buffer size for non-encrypted operations.
+// must be less than or equal to KReadBufferSize and KWriteBufferSize
+const TUint KNormalBlockSize = 4096;
+
+//~cmail
+// The minimum data size passed into and out of the encryption/decryption functions.  This is also
+// the pad length.  This constant will be adjusted to an even multiple of the block size returned
+// by the encryption functionality.
+const TUint KMinimumBlockSize = 128;
+
+
+#define KFILE_MODE_READ  (EFileRead | EFileShareAny)
+#define KFILE_MODE_WRITE (EFileWrite | EFileShareAny)
+
+// 82187 - Need to exclude the vommit code from the search
+_LIT( KSmartForwardTag, ":::" );
+_LIT( KSmartForwardTagNoAttach, "::::" );
+
+// =============
+// LOCAL CLASSES
+// =============
+
+class CBufferedReader : public CBase
+    {
+    public:
+        
+        static CBufferedReader* NewLC( RFile& aFile, TInt aBufferSize, TInt aBlockSize );
+        
+        virtual ~CBufferedReader();
+            
+        TPtrC8 NextBlockL();
+        
+        // NextBlockL should be called, and the data consumed, before AtEofL is called.
+        TBool AtEofL();
+        
+    private:
+
+        CBufferedReader( RFile& aFile, TInt aBlockSize );
+    
+        void ConstructL( TInt aBufferSize );
+
+        void ReadMoreDataL();
+            
+        RFile&     iFile;
+        const TInt iBlockSize;
+        TInt       iBufferSize;
+        TInt       iBufferPosition;
+        RBuf8      iBuffer;        
+        
+    }; // end class CBufferedReader
+
+class CBufferedWriter : public CBase
+    {
+    public:
+        
+        static CBufferedWriter* NewLC( RFile& aFile, TInt aBufferSize, TInt aBlockSize );
+            
+        virtual ~CBufferedWriter();
+        
+        TPtr8 NextBlockBufferL();
+        
+        void TruncateLastBlockL( TInt aTruncationAmount );
+
+        void FlushL();
+        
+    private:
+        
+        CBufferedWriter( RFile& aFile, TInt aBlockSize );
+    
+        void ConstructL( TInt aBlocksToBuffer );
+            
+        RFile&     iFile;
+        const TInt iBlockSize;
+        RBuf8      iBuffer;        
+    
+    }; // end class CBufferedWriter
+
+// ======================
+// METHOD IMPLEMENTATIONS
+// ======================
+
+// ==========================================================================
+// FUNCTION: NewL
+// ==========================================================================
+CContainerStoreContentManager* CContainerStoreContentManager::NewL( CContainerStoreUtils&      aUtils,
+                                                                    CContainerStoreEncryption& aEncryption )
+    {
+    CContainerStoreContentManager* self = new(ELeave) CContainerStoreContentManager( aUtils, aEncryption );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    CleanupStack::Pop( self );
+    return self;
+    } // end NewL
+
+// ==========================================================================
+// FUNCTION: Constructor
+// ==========================================================================
+CContainerStoreContentManager::CContainerStoreContentManager( CContainerStoreUtils&      aUtils,
+                                                              CContainerStoreEncryption& aEncryption ) :
+    iUtils( aUtils ),
+    iEncryption( aEncryption ),
+    iFs( aUtils.FileSystem() )
+    {
+    __LOG_CONSTRUCT( "msg", "CContainerStoreContentManager" )
+    _LIT( KFormatString, "%ST1" );    
+    iTemporaryFilename.Format( KFormatString, &iUtils.PrivatePath() );
+    
+    _LIT( KEncryptDecryptTempFileFormatString, "%ST2" );    
+    iEncryptDecryptTempFilename.Format( KEncryptDecryptTempFileFormatString, &iUtils.PrivatePath() );
+
+    } // end constructor
+
+// ==========================================================================
+// FUNCTION: ConstructL
+// ==========================================================================
+void CContainerStoreContentManager::ConstructL()    
+    {
+    CleanupTemporaryFile();
+    CreateContentSubdirectoriesL();
+    } // end ConstructL
+    
+// ==========================================================================
+// FUNCTION: Destructor
+// ==========================================================================
+CContainerStoreContentManager::~CContainerStoreContentManager()
+    {
+    __LOG_DESTRUCT
+    } // end destructor
+
+// ==========================================================================
+// FUNCTION: CleanupTemporaryFile
+// ==========================================================================
+void CContainerStoreContentManager::WipeContentFiles( RFs& aFs )
+    {
+    TFileName privatePath;
+    TFileName directoryNameWithWildcard;
+    
+    aFs.PrivatePath( privatePath );
+
+    for( TInt i = 0; i < KNumberOfContentSubdirectories; i++ )
+        {
+        _LIT( KFormatString, "%SC%i\\*" );
+        directoryNameWithWildcard.Format( KFormatString, &privatePath, i );    
+        BaflUtils::DeleteFile( aFs, directoryNameWithWildcard );
+        } // end for        
+    }
+    
+// ==========================================================================
+// FUNCTION: CleanupTemporaryFile
+// ==========================================================================
+void CContainerStoreContentManager::CleanupTemporaryFile()
+    {
+	BaflUtils::DeleteFile( iUtils.FileSystem(), iTemporaryFilename );    
+    } // end CleanupTemporaryFile
+    
+// ==========================================================================
+// FUNCTION: CreateContentSubdirectoriesL
+// ==========================================================================
+void CContainerStoreContentManager::CreateContentSubdirectoriesL()
+    {
+    TFileName directoryName;
+    
+    for( TInt i = 0; i < KNumberOfContentSubdirectories; i++ )
+        {
+        _LIT( KFormatString, "%SC%i\\" );
+        directoryName.Format( KFormatString, &iUtils.PrivatePath(), i );    
+        BaflUtils::EnsurePathExistsL( iUtils.FileSystem(), directoryName );
+        } // end for        
+    } // end CreateContentSubdirectoriesL
+        
+// ==========================================================================
+// FUNCTION: UpdateBlockSizeL
+// ==========================================================================
+void CContainerStoreContentManager::UpdateBlockSizeL( TBool isEncrypted )
+    {
+    TInt actualBlockSize = 0;
+    
+    if ( isEncrypted )
+        {
+        actualBlockSize = iEncryption.BlockSizeL();
+        
+        if( actualBlockSize < KMinimumBlockSize )
+            {
+            // The minimum block size is already a multiple of the actual block size.
+            iBlockSize = KMinimumBlockSize;
+            }
+        else
+            {
+            // Round up to the next multiple of the block size.
+            iBlockSize = KMinimumBlockSize + actualBlockSize - (KMinimumBlockSize % actualBlockSize);
+            } // end if
+        }
+    else
+        {
+        iBlockSize = KNormalBlockSize;
+        }
+    
+    } // end UpdateBlockSizeL
+        
+// ==========================================================================
+// FUNCTION: ContentLengthL
+// ==========================================================================
+TUint CContainerStoreContentManager::ContentLengthL( TContainerId aId, TBool aIsEncrypted )
+    {
+    TUint returnValue = 0;
+    
+	TFileName contentFilename;	
+	ContentFilename( aId, contentFilename );
+
+    // Open the content file.
+	RFile file;
+	TInt result = file.Open( iFs, contentFilename, KFILE_MODE_READ );
+
+    if( result == KErrNone )
+        {  
+        CleanupClosePushL( file );
+              
+    	TInt fileSize;
+    	User::LeaveIfError( file.Size( fileSize ) );
+        
+        if ( !aIsEncrypted )
+            {
+            returnValue = fileSize;
+            }
+        else
+            {
+            UpdateBlockSizeL( aIsEncrypted );
+            
+            RBuf8 encryptedBuffer;
+            encryptedBuffer.CreateL( iBlockSize );
+            CleanupClosePushL( encryptedBuffer );
+            
+            RBuf8 plaintextBuffer;
+            plaintextBuffer.CreateL( iBlockSize );
+            CleanupClosePushL( plaintextBuffer );
+        	
+        	// Read the last block.
+    
+        	TInt seekPosition = fileSize - iBlockSize;
+            User::LeaveIfError( file.Seek( ESeekCurrent, seekPosition ) ); 
+        	
+            User::LeaveIfError( file.Read( encryptedBuffer, iBlockSize ) );
+        	
+        	// Decrypt the last block.
+            
+        	iEncryption.DecryptL( encryptedBuffer, plaintextBuffer );
+        	iEncryption.RemovePaddingL( plaintextBuffer );
+        	
+            // The content length is the file size minus the number of pad bytes in the final block.    	    
+            returnValue = fileSize - iBlockSize + plaintextBuffer.Size();
+            
+            CleanupStack::PopAndDestroy( &plaintextBuffer );        
+            CleanupStack::PopAndDestroy( &encryptedBuffer );        
+            }
+        
+        CleanupStack::PopAndDestroy( &file );        
+        }
+    // If no content file exists then treat it as content length 0.
+    else if( result != KErrNotFound )
+        {
+        User::Leave( result );
+        } // end if
+
+    return returnValue;
+    
+    } // end ContentLengthL
+
+// ==========================================================================
+// FUNCTION: CopyContentL
+// ==========================================================================
+void CContainerStoreContentManager::CopyContentL( TContainerId aOldId, TContainerId aNewId )
+	{
+	iEncryption.CheckForAuthenticationL();
+	
+	TFileName oldContentFilename;	
+	ContentFilename( aOldId, oldContentFilename );
+
+	RFile file;
+	TInt result = file.Open( iFs, oldContentFilename, KFILE_MODE_READ );
+	
+	if( result == KErrNone )
+	    {
+    	TInt fileSize;
+    	User::LeaveIfError( file.Size( fileSize ) );
+    	file.Close();
+    	
+    	iUtils.LeaveIfLowDiskSpaceL( fileSize );
+    	
+    	TFileName newContentFilename;	
+    	ContentFilename( aNewId, newContentFilename );
+        
+        // Just copy the content file.  No encryption/decryption is required.
+        User::LeaveIfError( BaflUtils::CopyFile( iFs, oldContentFilename, newContentFilename ) );        
+        iCopiedContentFiles.AppendL( aNewId );
+	    }
+    // It is valid not to have a content file, so don't leave in that case.
+    else if( result != KErrNotFound )
+        {
+        User::Leave( result );        
+        } // end if
+	
+	} // end CopyContentL
+
+
+// ==========================================================================
+// FUNCTION: EncryptAndWriteNextBlockL
+// ==========================================================================
+TBool CContainerStoreContentManager::EncryptAndWriteNextBlockL( CBufferedWriter& aBufferedWriter, 
+                                                                const TDesC8&    aPlaintextBlock )
+    {
+    __LOG_ENTER_SUPPRESS( "EncryptAndWriteNextBlockL" )
+       
+    TBool lastBlock = EFalse;
+    
+    TPtr8 nextBlock = aBufferedWriter.NextBlockBufferL();    
+    
+    if( aPlaintextBlock.Length() == iBlockSize )
+        {    
+        iEncryption.EncryptL( aPlaintextBlock, nextBlock );
+        }
+    else
+        {
+        __LOG_WRITE_INFO( "writing last block" )
+        
+        lastBlock = ETrue;
+        
+        // Add PKCS5-stype padding to pad to the block size.
+                
+        RBuf8 paddedBuffer;
+        paddedBuffer.CreateL( iBlockSize );
+        CleanupClosePushL( paddedBuffer );
+        
+        paddedBuffer.Copy( aPlaintextBlock );
+        
+        iEncryption.AddPaddingL( paddedBuffer, iBlockSize );                       
+        
+        iEncryption.EncryptL( paddedBuffer, nextBlock );        
+        
+        CleanupStack::PopAndDestroy( &paddedBuffer );
+        } // end if
+    
+    return lastBlock;        
+    
+    } // end EncryptAndWriteNextBlockL
+
+// ==========================================================================
+// FUNCTION: ReadNextBlockL
+// ==========================================================================
+TBool CContainerStoreContentManager::ReadNextBlockL( CBufferedReader& aReader,
+                                                     TDes8&           aPlaintextBlock,
+                                                     TBool            aIsContentEncrypted )
+    {    
+    TPtrC8 nextBlock = aReader.NextBlockL();
+    
+    if ( aIsContentEncrypted )
+        {
+        iEncryption.DecryptL( nextBlock, aPlaintextBlock );    
+        }
+    else
+        {
+        aPlaintextBlock.Copy( nextBlock );
+        }
+        
+    // If this is the last block in the file then remove the pad bytes
+    TBool done = aReader.AtEofL();
+    if( done && aIsContentEncrypted )   
+        {
+        iEncryption.RemovePaddingL( aPlaintextBlock );
+        } // end if
+        
+    return done;        
+          
+    } // end ReadNextBlockL
+
+// ==========================================================================
+// FUNCTION: ReplaceContentL
+// ==========================================================================
+void CContainerStoreContentManager::ReplaceContentL( TContainerId  aId, 
+                                				     const TDesC8& aContent,
+                                                     TBool         aIsContentEncrypted )
+    {
+    __LOG_ENTER( "ReplaceContentL" )
+    
+    if( aContent.Length() == 0 )
+        {
+        TRAP_IGNORE( RemoveContentL( aId ) );
+        }
+    else
+        {                
+        UpdateBlockSizeL( aIsContentEncrypted );
+           
+       	iUtils.LeaveIfLowDiskSpaceL( aContent.Length() + iBlockSize );  // worst case size
+     
+        // Open the temporary output file.
+        RFile outFile;
+        User::LeaveIfError( outFile.Replace( iFs, iTemporaryFilename, EFileWrite ) );
+        CleanupClosePushL( outFile );
+        
+        TInt result   = KErrNone;            
+        
+        if ( aIsContentEncrypted )
+            {
+            CBufferedWriter* writer = CBufferedWriter::NewLC( outFile, KWriteBufferSize, iBlockSize );
+    
+            // Write content blocks to the file until there is no more content.  If the content is
+            // exactly a multiple of the block size, then add one extra loop with zero length
+            // content, to add the expected final pad characters.
+            TInt position = 0;
+            TBool done    = EFalse;    
+            TInt writeLength = 0;
+            while( !done && (result == KErrNone) )
+                {
+                writeLength = iBlockSize;
+                if( writeLength > aContent.Length() - position )
+                    {
+                    writeLength = aContent.Length() - position;
+                    } // end if
+                
+                TRAP( result, done = EncryptAndWriteNextBlockL( *writer, aContent.Mid( position, writeLength ) ) );
+                position += writeLength;
+                } // end while
+            
+            writer->FlushL();
+
+            CleanupStack::PopAndDestroy( writer );
+            }
+        else
+            {
+            //The content is not encrypted, just do a simple write
+            outFile.Write( aContent );
+            result = outFile.Flush();
+            }
+        CleanupStack::PopAndDestroy( &outFile );        
+        
+        // Commit the temporary file if the result is OK.  Otherwise, clean it up.
+        CommitTemporaryFileL( result, aId );
+        
+        } // end if
+        
+    __LOG_EXIT        
+    } // end ReplaceContentL
+
+// ==========================================================================
+// FUNCTION: ReplaceContentL
+// ==========================================================================
+void CContainerStoreContentManager::ReplaceContentL( TContainerId aId, 
+							                         RFile&       aContentFile,
+                                                     TBool        aEncryptContent )
+    {
+    __LOG_ENTER( "ReplaceContentL" )
+    
+	TInt fileSize;
+	User::LeaveIfError( aContentFile.Size( fileSize ) );
+	
+    TInt  result   = KErrNone;
+    
+    if( fileSize == 0 )
+        {
+        TRAP_IGNORE( RemoveContentL( aId ) );
+        }
+    else
+        {                	
+        UpdateBlockSizeL( aEncryptContent );
+        
+       	iUtils.LeaveIfLowDiskSpaceL( fileSize + iBlockSize );  // worst case size
+
+        RFile outFile;
+        User::LeaveIfError( outFile.Replace( iFs, iTemporaryFilename, EFileWrite ) );
+        CleanupClosePushL( outFile );
+
+        CBufferedReader* reader = CBufferedReader::NewLC( aContentFile, KReadBufferSize, iBlockSize );
+        
+        if ( aEncryptContent )
+            {
+        
+            CBufferedWriter* writer = CBufferedWriter::NewLC( outFile, KWriteBufferSize, iBlockSize );
+    
+            TBool done     = EFalse;
+            
+            // Write content to the file until there is no more content.  If the content is
+            // exactly a multiple of the block size, then add one extra loop with zero length
+            // content, to add the expected final pad characters.
+            while( !done && (result == KErrNone) )
+                {
+                TRAP( result, TPtrC8 plaintextBuffer = reader->NextBlockL();
+                              done = EncryptAndWriteNextBlockL( *writer, plaintextBuffer ) );
+                }  // end while
+    
+            writer->FlushL();
+    
+            CleanupStack::PopAndDestroy( writer );        
+            }
+        else
+            {
+            //encryption not on, so replace the content
+            TBool done = EFalse;
+            while( !done  )
+                {
+                TPtrC8 plaintextBuffer = reader->NextBlockL();
+                outFile.Write( plaintextBuffer );
+                if ( plaintextBuffer.Length() < iBlockSize )
+                    {
+                    done = ETrue;
+                    }
+                }  // end while
+            }
+        
+        CleanupStack::PopAndDestroy( reader );        
+        CleanupStack::PopAndDestroy( &outFile );
+        
+        // Commit the temporary file if the result is OK.  Otherwise, clean it up.
+        CommitTemporaryFileL( result, aId );
+        
+        } // end if
+    
+    __LOG_EXIT
+    } // end ReplaceContentL
+  
+/**
+ *
+ */
+TInt CContainerStoreContentManager::TransferContentFile(
+    TContainerId aId, 
+    const TDesC& aContentPath )
+    {
+    __LOG_ENTER( "TransferContentFile" )
+    
+    TFileName contentFilename;  
+    ContentFilename( aId, contentFilename );
+    
+    TInt err = iFs.Rename( aContentPath, contentFilename ); 
+    
+    __LOG_EXIT
+    return err;
+    }
+
+            
+// ==========================================================================
+// FUNCTION: AppendContentL
+// ==========================================================================
+void CContainerStoreContentManager::AppendContentL( TContainerId  aId, 
+					                                const TDesC8& aContent,
+                                                    TBool         aIsContentEncrypted )
+    {
+    __LOG_ENTER( "AppendContentL" )
+    
+    if( aContent.Length() > 0 )
+        {
+    	TFileName contentFilename;	
+    	ContentFilename( aId, contentFilename );
+	
+    	// Open the content file.
+        RFile inFile;
+        TInt result = inFile.Open( iFs, contentFilename, KFILE_MODE_READ );
+        
+        if( result == KErrNone )
+            {
+            CleanupClosePushL( inFile );
+
+        	TInt fileSize;
+        	User::LeaveIfError( inFile.Size( fileSize ) );
+
+            UpdateBlockSizeL( aIsContentEncrypted );        
+
+           	iUtils.LeaveIfLowDiskSpaceL( fileSize + aContent.Length() + iBlockSize ); // worst case size
+
+            CleanupStack::PopAndDestroy( &inFile );            
+            
+            // Copy the existing content file to the temporary content file.    
+            User::LeaveIfError( BaflUtils::CopyFile( iFs, contentFilename, iTemporaryFilename ) );
+            
+            // Open the temporary content file. 
+            RFile outFile;
+            User::LeaveIfError( outFile.Open( iFs, iTemporaryFilename, EFileRead | EFileWrite ) );
+            CleanupClosePushL( outFile );
+            
+            if ( aIsContentEncrypted )
+                {
+                RBuf8 plaintextBlock;
+                plaintextBlock.CreateL( iBlockSize );
+                CleanupClosePushL( plaintextBlock );
+    
+                // Read the content of the final block (padding removed).
+            	TInt seekPosition = fileSize - iBlockSize;
+            	User::LeaveIfError( outFile.Seek( ESeekStart, seekPosition ) );
+            	
+                CBufferedReader* reader = CBufferedReader::NewLC( outFile, iBlockSize, iBlockSize );
+    
+                ReadNextBlockL( *reader, plaintextBlock );
+                
+                CleanupStack::PopAndDestroy( reader );   
+    
+                // Reposition the file pointer at the start of the final block for writing.
+            	User::LeaveIfError( outFile.Seek( ESeekStart, seekPosition ) );
+    
+                CBufferedWriter* writer = CBufferedWriter::NewLC( outFile, KWriteBufferSize, iBlockSize );
+                
+                // Add the start of the buffer to be appended to the remaining plaintext from the
+                // existing file.
+                TInt position   = iBlockSize - plaintextBlock.Length();
+                if( position > aContent.Length() )
+                    {
+                    position = aContent.Length();
+                    } // end if       
+                if ( position > 0 )
+                    {
+                    plaintextBlock.Append( aContent.Right( position ) );
+                    }
+                
+                TBool done = EFalse;
+                
+                TRAP( result, done = EncryptAndWriteNextBlockL( *writer, plaintextBlock ) );
+    
+                // Write the remaining content to the file until there is no more content.  If the
+                // content is exactly a multiple of the block size, then add one extra loop with
+                // zero length content, to add the expected final pad characters.
+                TInt writeLength = 0;
+                while( !done && (result == KErrNone) )
+                    {
+                    writeLength = iBlockSize;
+                    if( writeLength > aContent.Length() - position )
+                        {
+                        writeLength = aContent.Length() - position;
+                        } // end if
+                
+                    TRAP( result, done = EncryptAndWriteNextBlockL( *writer, aContent.Mid( position, writeLength ) ) );
+                    position += writeLength;
+                    } // end while
+                
+                writer->FlushL();
+    
+                CleanupStack::PopAndDestroy( writer );   
+                CleanupStack::PopAndDestroy( &plaintextBlock );   
+                }
+            else
+                {
+                //content is not encrypted
+                TInt seekPosition = 0;
+                User::LeaveIfError( outFile.Seek( ESeekEnd, seekPosition ) );
+                outFile.Write( aContent );
+                User::LeaveIfError( outFile.Flush() );
+                }
+            CleanupStack::PopAndDestroy( &outFile );   
+            
+            // Commit the temporary file if the result is OK.  Otherwise, clean it up.
+            CommitTemporaryFileL( result, aId );                   
+            }
+        else if( result == KErrNotFound )    
+            {
+            ReplaceContentL( aId, aContent, aIsContentEncrypted );
+            }
+        else
+            {
+            User::LeaveIfError( result );
+            } // end if
+
+        } // end if
+    
+    __LOG_EXIT    
+    } // end AppendContentL
+
+
+// ==========================================================================
+// FUNCTION: PrependContentL
+// ==========================================================================
+void CContainerStoreContentManager::PrependContentL(
+    TContainerId  aId, 
+    const TDesC8& aContent,
+    TBool aIsContentEncrypted )
+    {
+    __LOG_ENTER( "PrependContentL" )
+    
+    if ( aIsContentEncrypted )
+        {
+        User::Leave( KErrNotSupported );
+        }
+        
+    if ( aContent.Length() > 0 )
+        {
+        TFileName contentFilename;  
+        ContentFilename( aId, contentFilename );
+    
+        if ( BaflUtils::FileExists( iFs, contentFilename ) )
+            {
+            TRAPD( err, MessageStoreUtils::PrependBufferAndCopyFileL(
+                iFs, iUtils, contentFilename, iTemporaryFilename, aContent ) );
+      
+            //Commit the temporary file if the result is OK.
+            //Otherwise, clean it up.
+            CommitTemporaryFileL( err, aId );                   
+            }
+        else
+            {
+            ReplaceContentL( aId, aContent, aIsContentEncrypted );
+            }
+        }
+    
+    __LOG_EXIT    
+    } //PrependContentL
+
+
+// ==========================================================================
+// FUNCTION: RemoveContent
+// ==========================================================================
+void CContainerStoreContentManager::RemoveContentL( TContainerId aId )
+    {   
+    __LOG_ENTER( "RemoveContentL" )
+     
+	TFileName contentFilename;
+	ContentFilename( aId, contentFilename );
+    
+	TInt rc = BaflUtils::DeleteFile( iUtils.FileSystem(), contentFilename );
+    if ( rc != KErrNone && rc != KErrNotFound )
+        {
+        User::Leave( rc );
+        }
+	
+	__LOG_EXIT
+    } // end RemoveContent
+
+// ==========================================================================
+// FUNCTION: FetchContentL
+// ==========================================================================
+void CContainerStoreContentManager::FetchContentL( TContainerId aId,					
+                                				   TDes8&       aContent,
+                                                   TBool        aIsContentEncrypted, 
+                                				   TUint        aStartPosition )
+    {  
+    __LOG_ENTER( "FetchContentL" )
+      
+	aContent.SetLength( 0 );
+	
+	TFileName contentFilename;	
+	ContentFilename( aId, contentFilename );
+	
+	// Open the content file.
+    RFile inFile;
+    TInt result = inFile.Open( iFs, contentFilename, KFILE_MODE_READ );
+    
+    if( result == KErrNone )
+        {
+        CleanupClosePushL( inFile );
+
+    	TInt fileSize;
+    	User::LeaveIfError( inFile.Size( fileSize ) );
+        
+        if( aStartPosition < fileSize )
+            {
+            
+            if ( aIsContentEncrypted )
+                {
+                UpdateBlockSizeL( aIsContentEncrypted );
+                
+                RBuf8 plaintextBlock;
+                plaintextBlock.CreateL( iBlockSize );
+                CleanupClosePushL( plaintextBlock );
+    
+                // Calculate the position of the first block to read.
+                TInt seekPosition = aStartPosition - (aStartPosition % iBlockSize);
+    
+                // Seek to the calculated position.
+                User::LeaveIfError( inFile.Seek( ESeekStart, seekPosition ) );            
+                
+                CBufferedReader* reader = CBufferedReader::NewLC( inFile, KReadBufferSize, iBlockSize );
+                
+                // Calculate the position within the plaintext buffer to start copying.
+                TInt copyStart = aStartPosition - seekPosition;
+    
+                // Keep reading until the output buffer is full, or until the end of the content file is reached.
+                TBool done = EFalse;
+                while( (aContent.Length() < aContent.MaxLength()) && !done )
+                    {
+                    // Read and decrypt the next block from the content file.
+                    done = ReadNextBlockL( *reader, plaintextBlock );
+    
+                    // Copy the data from the plaintext buffer to the output buffer.
+                    TInt copyLength = plaintextBlock.Length() - copyStart;                
+                    if( aContent.Length() + copyLength > aContent.MaxLength() )
+                        {
+                        copyLength = aContent.MaxLength() - aContent.Length();
+                        } // end if
+                    aContent.Append( plaintextBlock.Mid( copyStart, copyLength ) );
+    
+                    // All copies (except possibly the first one) start at 0.
+                    copyStart = 0;                
+                                    
+                    } // end while
+    
+                CleanupStack::PopAndDestroy( reader );   
+                CleanupStack::PopAndDestroy( &plaintextBlock );   
+                }
+            else
+                {
+                //content is not encrypted
+                TInt seekPosition = aStartPosition;
+                
+                // Seek to the calculated position.
+                User::LeaveIfError( inFile.Seek( ESeekStart, seekPosition ) );
+                inFile.Read( aContent );
+                }
+            } // end if        
+
+        CleanupStack::PopAndDestroy( &inFile );   
+        }
+    else if( result != KErrNotFound )
+        {
+        User::LeaveIfError( result );
+        } // end if
+
+    __LOG_EXIT
+    } // end FetchContentL
+    
+// ==========================================================================
+// FUNCTION: FetchContentL
+// ==========================================================================
+void CContainerStoreContentManager::FetchContentL( TContainerId aId,
+					                               RFile&       aDestinationFile,
+                                                   TBool        aIsContentEncrypted )
+    {
+    __LOG_ENTER( "FetchContentL" )
+    
+	TFileName contentFilename;	
+	ContentFilename( aId, contentFilename );
+    
+	// Open the content file.
+    RFile inFile;
+    TInt result = inFile.Open( iFs, contentFilename, KFILE_MODE_READ );
+    
+    if( result == KErrNone )
+        {
+        CleanupClosePushL( inFile );
+
+    	TInt fileSize;
+    	User::LeaveIfError( inFile.Size( fileSize ) );
+
+       	iUtils.LeaveIfLowDiskSpaceL( fileSize );  // worst case size
+        
+        UpdateBlockSizeL( aIsContentEncrypted );
+        
+        CBufferedReader* reader = CBufferedReader::NewLC( inFile, KReadBufferSize, iBlockSize );
+        
+        if ( aIsContentEncrypted )
+            {
+            
+            CBufferedWriter* writer = CBufferedWriter::NewLC( aDestinationFile, KWriteBufferSize, iBlockSize );
+            
+            // Read blocks from the content file and write them to the destination file,
+            // until the end of the content file is reached.
+            TBool done = EFalse;
+            while( !done )
+                {
+                TPtr8 writeBuffer = writer->NextBlockBufferL();
+                
+                if( ReadNextBlockL( *reader, writeBuffer ) )
+                    {
+                    done = ETrue;
+                    
+                    writer->TruncateLastBlockL( iBlockSize - writeBuffer.Length() );
+                    } // end if
+    
+                } // end while
+    
+            writer->FlushL();
+    
+            CleanupStack::PopAndDestroy( writer );   
+            }
+        else
+            {
+            //content is not encrypted, just copy the file
+            //encryption not on, so just copy the file
+            TBool done = EFalse;
+            while( !done )
+                {
+                TPtrC8 buf = reader->NextBlockL();
+                aDestinationFile.Write( buf );
+                if ( buf.Length() < iBlockSize )
+                    {
+                    done = ETrue;
+                    } // end if
+                } // end while
+                User::LeaveIfError( aDestinationFile.Flush() );
+            }
+            
+        CleanupStack::PopAndDestroy( reader );   
+        CleanupStack::PopAndDestroy( &inFile );   
+        }
+    else if( result != KErrNotFound )
+        {
+        User::LeaveIfError( result );
+        } // end if
+
+    __LOG_EXIT
+    } // end FetchContentL
+							
+// ==========================================================================
+// FUNCTION: OpenContentFileL
+// ==========================================================================
+void CContainerStoreContentManager::OpenContentFileL( TContainerId aId, RFs& aFs, RFile& aFile, TBool aIsContentEncrypted  )
+    {
+    __LOG_ENTER( "OpenContentFileL" )
+    
+    if ( aIsContentEncrypted )
+        {
+        User::Leave( KErrNotSupported );
+        }
+    
+    TFileName contentFilename;  
+    ContentFilename( aId, contentFilename );
+    
+    TInt rc = aFile.Open( aFs, contentFilename, KFILE_MODE_READ );
+    if ( rc != KErrNone )
+        {
+        __LOG_WRITE8_FORMAT1_ERROR( "Failed to open content file. err=%d", rc)
+        User::Leave( rc );
+        }
+    
+    __LOG_EXIT
+    }
+
+// ==========================================================================
+// FUNCTION: ContentFilename
+// ==========================================================================
+void CContainerStoreContentManager::ContentFilename( TContainerId aId, TDes& aFilename )
+	{
+	_LIT( KFormatString, "%SC%i\\%x" );
+	
+	// Content files are now stored in a folder hierarchy rather than a flat directory,
+	// to avoid a single directory with thousands of files.
+	//
+	// Content filenames are of the form C:\\private\\x\\Cy\\z", where:
+	//
+	// x = UID of server executable
+	// y = a number between 0 and KNumberOfContentSubdirectories-1
+	// z = the ID of the container with the type bits masked out (in hex)	
+	
+	TUint32 filename = aId & ~KContainerTypeMask;
+	TUint32 path     = filename % KNumberOfContentSubdirectories;
+	aFilename.Format( KFormatString, &iUtils.PrivatePath(), path, filename );
+	
+	} // end ContentFilename
+	
+// ==========================================================================
+// FUNCTION: CommitTemporaryFileL
+// ==========================================================================
+void CContainerStoreContentManager::CommitTemporaryFileL( TInt aResult, TContainerId aContainerId )
+    {
+    if( aResult != KErrNone )
+        {
+        CleanupTemporaryFile();
+        User::Leave( aResult );
+        } // end if
+    
+    TFileName contentFilename;
+    ContentFilename( aContainerId, contentFilename );
+    
+    // Delete the existing file, if necessary.
+    TInt rc = BaflUtils::DeleteFile( iUtils.FileSystem(), contentFilename );
+    
+    if ( rc == KErrInUse )
+        {
+        RFile inFile;
+        User::LeaveIfError( inFile.Open( iFs, iTemporaryFilename, KFILE_MODE_READ ) );
+        CleanupClosePushL( inFile );                                                               //+inFile
+        
+        CBufferedReader* reader = CBufferedReader::NewLC( inFile, KReadBufferSize, iBlockSize );    //+reader
+        
+        RFile outFile;
+        User::LeaveIfError( outFile.Open( iFs, contentFilename, KFILE_MODE_WRITE ) );
+        CleanupClosePushL( outFile );                                                              //+outFile
+        
+        //the client may still have the content file open, in this case, we can not delete it nor can we rename the temp file to it
+        //the only thing we can do is to copy the content of the temp file to it.
+        TBool done = EFalse;
+        while( !done )
+            {
+            TPtrC8 buf = reader->NextBlockL();
+            outFile.Write( buf );
+            if ( buf.Length() < iBlockSize )
+                {
+                done = ETrue;
+                } // end if
+            } // end while
+        User::LeaveIfError( outFile.Flush() );
+        
+        CleanupStack::PopAndDestroy( &outFile );
+        CleanupStack::PopAndDestroy( reader );
+        CleanupStack::PopAndDestroy( &inFile );
+        }
+    else
+        {
+        // Rename the temporary file to the new name.
+        User::LeaveIfError( BaflUtils::RenameFile( iUtils.FileSystem(), iTemporaryFilename, contentFilename ) );    
+        }
+    } // end CommitTemporaryFileL	        	
+
+// ==========================================================================
+// FUNCTION: SearchContentL
+// ==========================================================================
+TBool CContainerStoreContentManager::SearchContentL( TContainerId aContainerId, 
+                                                     const TDesC& aSearchString,
+                                                     TDes8&       aSearchBuffer,
+                                                     TBool        aIsContentEncrypted )
+    {    
+    __LOG_ENTER_SUPPRESS( "SearchContentL" )
+    
+    __LOG_WRITE_FORMAT1_INFO( "id=%x", aContainerId )
+    
+    TBool found = EFalse;
+    
+	TFileName contentFilename;	
+	ContentFilename( aContainerId, contentFilename );
+	
+	// Open the content file.
+    RFile inFile;
+    TInt result = inFile.Open( iFs, contentFilename, KFILE_MODE_READ );
+    
+    if( result == KErrNone )
+        {
+        CleanupClosePushL( inFile );
+
+        if ( aIsContentEncrypted )
+            {
+            UpdateBlockSizeL( aIsContentEncrypted );
+            }
+        else
+            {
+            //we can only search half of the size of the buffer at a time
+            iBlockSize = KNormalBlockSize / 2;
+            }
+        
+        CBufferedReader* reader = CBufferedReader::NewLC( inFile, KReadBufferSize, iBlockSize );
+
+        TUint16* unicodePointer = reinterpret_cast<TUint16*>(const_cast<TUint8*>(aSearchBuffer.Ptr()));
+        TPtr16   unicodeBuffer( unicodePointer, 0, aSearchBuffer.MaxLength() / 2 ); 
+        
+        RBuf8 plaintextBlock;
+        plaintextBlock.CreateL( iBlockSize );
+        CleanupClosePushL( plaintextBlock );
+        
+        const TUint16* sourcePtr16 = reinterpret_cast<const TUint16*>( plaintextBlock.Ptr() );        
+
+        //  Loop until the search string is found or the end of file is reached.            
+        TBool done = EFalse;
+        while( !found && !done )
+            {            
+            // Read and decrypt the next block.
+            done = ReadNextBlockL( *reader, plaintextBlock, aIsContentEncrypted );
+
+            // Create a 16-bit overlay to the plain text block.
+            TPtrC16 sourceBuffer( sourcePtr16, plaintextBlock.Length() / 2 );
+
+            // Convert the 16-bit text to uppercase and copy to the end of the unicode buffer.
+            TUint16* destinationPointer = unicodePointer + unicodeBuffer.Length();
+            TPtr16   destinationBuffer( destinationPointer, 0, plaintextBlock.Length() ); 
+
+            destinationBuffer.Copy( sourceBuffer );
+
+            unicodeBuffer.SetLength( unicodeBuffer.Length() + destinationBuffer.Length() );            
+
+            // If the end of file has been reached or the unicode buffer is full then search the
+            // unicode buffer for the search string.
+            if( done || unicodeBuffer.MaxLength() - unicodeBuffer.Length() < iBlockSize )
+                {
+                
+                // 82187 - need to skip the vomit code 
+                if ( done )
+                	{
+                	TInt index = FindVomitCode( unicodeBuffer );
+                	if ( index > 0 )
+                		{
+                		unicodeBuffer.SetLength( index );
+                		}
+                	}
+                
+                // Search for the string in the unicode buffer.                
+                TInt rc = unicodeBuffer.MatchC( aSearchString );
+                if( rc != KErrNotFound )
+                    {
+                    __LOG_WRITE8_FORMAT1_INFO( "found in %i", aContainerId )
+                    found = ETrue;
+                    }
+                else
+                    {
+                    // Copy the end of this buffer to the start of the next buffer, in case the search
+                    // string spans the boundary of the buffers.
+                    unicodeBuffer.Copy( unicodeBuffer.Right(aSearchString.Length()-1) ); 
+                    } // end if
+                    
+                } // end if
+
+            } // end while
+
+        CleanupStack::PopAndDestroy( &plaintextBlock );   
+        CleanupStack::PopAndDestroy( reader );   
+        CleanupStack::PopAndDestroy( &inFile );   
+        } // end if
+
+    __LOG_WRITE_FORMAT1_INFO( "found=%i", found )
+    
+    return found;
+  
+    } // end SearchContentL
+
+
+// ==========================================================================
+// FUNCTION: EncryptL
+// ==========================================================================
+void CContainerStoreContentManager::EncryptL( TContainerId aId )
+    {
+    RFile file;
+    User::LeaveIfError( file.Replace( iFs, iEncryptDecryptTempFilename, EFileWrite ) );
+    CleanupClosePushL( file );
+    
+    //fetch the content that was NOT encrypted
+    FetchContentL( aId, file, EFalse );
+
+    //reposition the file to the begining so that it can be read by ReplaceContent
+    TInt pos = 0;
+    file.Seek( ESeekStart, pos );
+    
+    //replace and encrypt the content 
+    ReplaceContentL( aId, file, ETrue );
+    
+    CleanupStack::PopAndDestroy( &file );
+    
+    BaflUtils::DeleteFile( iFs, iEncryptDecryptTempFilename );    
+    }
+
+// ==========================================================================
+// FUNCTION: DecryptL
+// ==========================================================================
+void CContainerStoreContentManager::DecryptL( TContainerId aId )
+    {
+    RFile file;
+    User::LeaveIfError( file.Replace( iFs, iEncryptDecryptTempFilename, EFileWrite ) );
+    CleanupClosePushL( file );
+    
+    //fetch the content that was encrypted
+    FetchContentL( aId, file, ETrue );
+    
+    //reposition the file to the begining so that it can be read by ReplaceContent
+    TInt pos = 0;
+    file.Seek( ESeekStart, pos );
+    
+    //replace the content with decrypted buffer
+    ReplaceContentL( aId, file, EFalse );
+    
+    CleanupStack::PopAndDestroy( &file );
+    
+    BaflUtils::DeleteFile( iFs, iEncryptDecryptTempFilename );    
+    }
+
+
+TInt CContainerStoreContentManager::FindVomitCode( TPtr16& aBody )
+{
+	__LOG_ENTER_SUPPRESS("FindVomitCode");
+	//Search backward for the end of the key
+	//Ignore whitespace
+	TInt idx = aBody.Length()-1;
+	while ( idx >= 0 && TChar(aBody[idx]).IsSpace() ) 
+		{
+		idx--;
+		}
+	
+	int end = idx+1;
+	if ( end - KSmartForwardTag().Length() < 0 )
+		{
+	    return KErrNotFound;
+		}
+	
+	const TDesC16& p = aBody.Mid(end-KSmartForwardTag().Length() );
+	
+	if ( p.Find(KSmartForwardTag) == KErrNotFound )
+		{
+		return KErrNotFound; //No key at end of message
+		}
+		
+	// point to the last character before the end tag
+	idx = end - KSmartForwardTag().Length() - 1;
+	if (idx < 0)
+		{
+	    return KErrNotFound;
+		}
+
+	// : 67030 [USER-10 CRASH]
+	// Turns out that the server is allowed to set the attachments
+	// list bit map to empty, causing the last part of the key
+	// to be 4 colons in a row instead of three.
+	// Check if the tail is 4 :
+	if (end-KSmartForwardTagNoAttach().Length() >= 0)
+	{
+		const TDesC16& p2 = aBody.Mid( end-KSmartForwardTagNoAttach().Length() );
+		if ( p2.Find( KSmartForwardTagNoAttach ) != KErrNotFound )
+		{
+			idx--;
+		}
+	}
+	
+	// Replace the end tag with something so we can't find it
+	TInt repIdx = idx+1;
+	for ( TInt i = repIdx ; i < aBody.Length() ; i++ ) 
+	{
+		if ( aBody[i] == ':') 
+			{
+			_LIT(KStar,"*");
+			aBody.Replace( i, 1, KStar );
+			}
+		else
+			{
+			break;
+			}
+	}
+	
+	// Now search backward for beginning of key
+    //TInt bodyLen = aBody.Length();
+	while ( idx >= 0 )
+	{
+		const TDesC16& tmp = aBody.Mid(idx);
+		int loc = tmp.Find( KSmartForwardTag );
+		if ( loc != KErrNotFound )
+			{
+			break;
+			}
+		idx--;
+	}
+	
+	// Put the colons back in
+	for ( TInt i = repIdx ; i < aBody.Length() ; i++ )
+	{
+		if ( aBody[i] == '*' ) 
+			{
+			_LIT(KColon,":");
+			aBody.Replace( i, 1, KColon);
+			}
+		else 
+			{
+			break;
+			}
+	}
+	if ( idx == 0 ) 
+		{
+		return KErrNotFound;
+		}
+		
+	__LOG_WRITE_FORMAT1_INFO( "Vomit code found! index=%d", idx );
+	return idx;
+}
+
+
+/**
+ * Must be called before doing multiple calls to the CopyContentL. 
+ */
+void CContainerStoreContentManager::StartCopyTransaction()
+    {
+    iCopiedContentFiles.Reset();
+    }
+
+
+/**
+ * If a failure is detected deletes the newly copied content files.
+ */
+void CContainerStoreContentManager::RollbackCopyTransaction()
+    {
+    TInt count = iCopiedContentFiles.Count();
+
+    TFileName contentFilename;
+    for ( TInt i = 0; i < count; i++ )
+        {
+        ContentFilename( iCopiedContentFiles[i], contentFilename );
+        iFs.Delete( contentFilename );
+        }
+    }
+
+
+// ---------------
+// CBufferedReader
+// ---------------
+
+CBufferedReader* CBufferedReader::NewLC( RFile& aFile, TInt aBufferSize, TInt aBlockSize )
+    {
+    CBufferedReader* self = new(ELeave) CBufferedReader( aFile, aBlockSize );
+    CleanupStack::PushL( self );
+    self->ConstructL( aBufferSize );
+    return self;
+    }
+
+CBufferedReader::CBufferedReader( RFile& aFile, TInt aBlockSize ) :
+    iFile( aFile ),
+    iBlockSize( aBlockSize )
+    {
+    }
+
+void CBufferedReader::ConstructL( TInt aBufferSize )
+    {
+    // Make sure the buffer size is an even multiple of the block size.
+    iBufferSize = aBufferSize - (aBufferSize % iBlockSize );     
+    iBuffer.CreateL( iBufferSize );
+    }
+
+CBufferedReader::~CBufferedReader()
+    {
+    iBuffer.Close();
+    }
+    
+TPtrC8 CBufferedReader::NextBlockL()
+    {
+    TInt remainingBufferData = iBuffer.Length() - iBufferPosition;
+    
+    if( remainingBufferData == 0 )
+        {
+        ReadMoreDataL();
+        remainingBufferData = iBuffer.Length(); 
+        } // end if
+        
+    TInt length = iBlockSize;
+                                
+    if( length > remainingBufferData )
+        {
+        length = remainingBufferData;
+        } // end if
+        
+    TPtrC8 returnValue = iBuffer.Mid( iBufferPosition, length );
+    
+    iBufferPosition += length;
+    
+    return returnValue;
+    }
+
+TBool CBufferedReader::AtEofL()
+    {
+    if( iBufferPosition >= iBuffer.Length() )
+        {
+        ReadMoreDataL();
+        } // end if
+    
+    return( iBuffer.Length() == 0 );
+    }
+
+void CBufferedReader::ReadMoreDataL()
+    {
+    iBuffer.SetLength( 0 );
+    iBufferPosition = 0;
+    
+    // Read more data.
+    User::LeaveIfError( iFile.Read( iBuffer, iBufferSize ) );            
+    }                     
+            
+// ---------------
+// CBufferedWriter
+// ---------------
+
+CBufferedWriter* CBufferedWriter::NewLC( RFile& aFile, TInt aBufferSize, TInt aBlockSize )
+    {
+    CBufferedWriter* self = new(ELeave) CBufferedWriter( aFile, aBlockSize );
+    CleanupStack::PushL( self );
+    self->ConstructL( aBufferSize );
+    return self;
+    }
+    
+CBufferedWriter::CBufferedWriter( RFile& aFile, TInt aBlockSize ) :
+    iFile( aFile ),
+    iBlockSize( aBlockSize )
+    {
+    }
+
+void CBufferedWriter::ConstructL( TInt aBufferSize )
+    {
+    // Make sure the buffer size is an even multiple of the block size.
+    iBuffer.CreateL( aBufferSize - (aBufferSize % iBlockSize ) );           
+    }
+    
+CBufferedWriter::~CBufferedWriter()
+    {
+    iBuffer.Close();
+    }
+
+TPtr8 CBufferedWriter::NextBlockBufferL()
+    {
+    if( iBuffer.Length() + iBlockSize > iBuffer.MaxLength() )
+        {
+        FlushL();
+        } // end if
+        
+    iBuffer.SetLength( iBuffer.Length() + iBlockSize );
+    return iBuffer.RightTPtr( iBlockSize );                
+    }
+
+void CBufferedWriter::TruncateLastBlockL( TInt aTruncationAmount )
+    {
+    iBuffer.SetLength( iBuffer.Length() - aTruncationAmount );
+    }
+
+void CBufferedWriter::FlushL()
+    {
+    User::LeaveIfError( iFile.Write( iBuffer ) );
+    iBuffer.SetLength( 0 );
+    }