--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/emailservices/emailstore/message_store/server/src/ContainerStore.cpp Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,2516 @@
+/*
+* 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 implementation.
+*
+*/
+
+
+
+// ========
+// INCLUDES
+// ========
+
+#include <bautils.h>
+
+#include "MsgStoreTypes.h"
+#include "ContainerStore.h"
+#include "ContainerStoreContainersTable.h"
+#include "ContainerStoreContentManager.h"
+#include "ContainerStoreDefs.h"
+#include "ContainerStoreDeleteHandler.h"
+#include "ContainerStoreEncryption.h"
+#include "ContainerStoreGeneralTable.h"
+#include "ContainerStoreAccountTable.h"
+#include "ContainerStoreSortingTable.h"
+#include "ContainerStoreUtils.h"
+#include "MsgStoreSortResultRowSet.h"
+#include "PropertiesSerializer.h"
+#include "ContainerStoreSearchHandler.h"
+#include "ContainerStoreSearchResultTable.h"
+#include "MessageStoreEncryptHandler.h"
+#include "ContainerStoreMRUAddressTable.h"
+#include "MsgStorePropertyKeys.h"
+
+// =========
+// CONSTANTS
+// =========
+
+_LIT8( KNullDes, "" );
+
+// The maximum recursion depth for the recursive copy function.
+const TUint KMaxRecursionDepth = 40;
+
+// Priorities, in descending order.
+const TInt KSearchPriorityOffset = 0;
+const TInt KEncryptPriorityOffset = -1;
+const TInt KDeletePriorityOffset = -2;
+const TInt KCompactionPriorityOffset = -3;
+
+void RMsgStoreSortableFields::Close()
+ {
+ iSubject.Close();
+ iFrom.Close();
+ iTo.Close();
+ }
+
+// ======================
+// METHOD IMPLEMENTATIONS
+// ======================
+
+// ==========================================================================
+// FUNCTION: NewL
+// ==========================================================================
+CContainerStore* CContainerStore::NewL( const TDesC& aDbFilename,
+ TDriveNumber aDriveNumber,
+ MCustomBehaviorProvider& aCustomBehaviorProvider,
+ MBackgroundOperationsObserver& aBackgroundOperationsObserver,
+ TInt aBasePriority )
+ {
+ CContainerStore* self = new( ELeave ) CContainerStore( aCustomBehaviorProvider,
+ aBasePriority );
+ CleanupStack::PushL( self );
+ self->ConstructL( aDbFilename, aBackgroundOperationsObserver, aDriveNumber );
+ CleanupStack::Pop( self );
+ return self;
+ } // end NewL
+
+// ==========================================================================
+// FUNCTION: Constructor
+// ==========================================================================
+CContainerStore::CContainerStore( MCustomBehaviorProvider& aCustomBehaviorProvider,
+ TInt aBasePriority ) :
+ iCustomBehaviorProvider( aCustomBehaviorProvider ),
+ iBasePriority( aBasePriority ),
+ iNextSortSessionId( 0 )
+ {
+ __LOG_CONSTRUCT( "msg", "CContainerStore" )
+ } // end Constructor
+
+// ==========================================================================
+// FUNCTION: ConstructL
+// ==========================================================================
+void CContainerStore::ConstructL( const TDesC& aDbFilename,
+ MBackgroundOperationsObserver& aBackgroundOperationsObserver,
+ TDriveNumber aDriveNumber )
+ {
+ __LOG_ENTER( "ConstructL" )
+
+ TUint quickPropertiesLength;
+
+ iCustomBehaviorProvider.LengthsL( iCountsLength, quickPropertiesLength );
+
+ iQuickProperties.CreateL( quickPropertiesLength );
+
+ iTotalCountsDelta.CreateL( iCountsLength );
+
+ iDeleteHandler = CDeleteHandler::NewL( *this,
+ aBackgroundOperationsObserver,
+ iBasePriority + KDeletePriorityOffset );
+
+ iUtils = CContainerStoreUtils::NewL( aDriveNumber,
+ iBasePriority + KCompactionPriorityOffset,
+ aDbFilename,
+ *iDeleteHandler );
+
+ iEncryption = CContainerStoreEncryption::NewL();
+
+ // Open an existing database.
+ TRAPD( err, iUtils->OpenDatabaseL(); OpenTablesL() );
+
+ switch( err )
+ {
+ case KErrNone:
+
+ // Success! Nothing else to do.
+ break;
+
+ case KErrPathNotFound: // private path does not yet exist
+ case KErrNotFound: // file not found, table not found
+ case KErrEof: // something is wrong with the file
+ case KErrCorrupt: // schema version mismatch
+
+ __LOG_WRITE8_FORMAT1_ERROR( "open failed (%i), recreating database", err );
+
+ CloseTables();
+ iUtils->CloseDatabaseL();
+
+ // Unable to open the database. Create a new database.
+ iUtils->CreateDatabaseL();
+ CreateTablesL();
+ break;
+
+ default:
+
+ // Something unexpected has occurred.
+ __LOG_WRITE8_FORMAT1_ERROR( "unable to open database (%i)", err );
+ User::Leave( err );
+ break;
+
+ }; // end switch
+
+ iEncryptHandler = CMessageStoreEncryptHandler::NewL( *iGeneralTable, *iUtils, iBasePriority + KEncryptPriorityOffset );
+ iEncryptHandler->AddEncryptableTableL( this );
+ iEncryptHandler->AddEncryptableTableL( iAccountTable );
+ iEncryptHandler->AddEncryptableTableL( iSortingTable );
+ iEncryptHandler->AddEncryptableTableL( iMruAddressTable );
+ iEncryptHandler->StartL();
+
+ iEncryption->SetAuthenticationRequired( iGeneralTable->IsAuthenticateRequiredL() );
+ iEncryption->SetEncryptionFlag( iGeneralTable->IsEncryptionOnL() );
+
+ //Initialize the MRU address list
+ //It leaves if the DB is not authenticated, so trap it and ignore it
+ TRAP_IGNORE( iMruAddressTable->InitializeIfNeededL() );
+
+ iContentManager = CContainerStoreContentManager::NewL( *iUtils, *iEncryption );
+
+ // Cleanup any uncommitted containers.
+ MarkUncommittedContainersForDeleteL();
+
+ // Start the background delete operation.
+ iDeleteHandler->Start();
+
+ // Read the total counts.
+ iTotalCounts.CreateL( iCountsLength );
+
+ __LOG_EXIT
+ } // end ConstructL
+
+// ==========================================================================
+// FUNCTION: Destructor
+// ==========================================================================
+CContainerStore::~CContainerStore()
+ {
+ delete iDeleteHandler;
+
+ for ( int i = 0 ; i < iSortSessions.Count() ; i++ )
+ {
+ delete iSortSessions[i].iResultRowSet;
+ }
+ iSortSessions.Close();
+
+ CloseTables();
+
+ if ( iUtils )
+ {
+ TRAP_IGNORE( iUtils->CloseDatabaseL() );
+ }
+
+ delete iEncryptHandler;
+
+ delete iContentManager;
+
+ delete iEncryption;
+
+ delete iUtils;
+
+ iObservers.Close();
+
+ iHierarchy.Close();
+
+ iQuickProperties.Close();
+
+ iTotalCountsDelta.Close();
+
+ iTotalCounts.Close();
+
+ __LOG_DESTRUCT
+ } // end destructor
+
+// ==========================================================================
+// FUNCTION: WipeEverything
+// ==========================================================================
+TInt CContainerStore::WipeEverything( const TDesC& aDbFilename,
+ TDriveNumber aDriveNumber )
+ {
+ RFs fs;
+ TInt result = fs.Connect();
+ if( result == KErrNone )
+ {
+ fs.SetSessionToPrivate( aDriveNumber );
+
+ // Wipe the database file.
+ BaflUtils::DeleteFile( fs, aDbFilename );
+
+ // Wipe the content files.
+ CContainerStoreContentManager::WipeContentFiles( fs );
+
+ fs.Close();
+
+ } // end if
+
+ return result;
+
+ } // end WipeEverything
+
+// ==========================================================================
+// FUNCTION: CreateTablesL
+// ==========================================================================
+void CContainerStore::CreateTablesL()
+ {
+ __LOG_ENTER( "CreateTablesL" )
+
+ iUtils->BeginDatabaseTransactionLC();
+
+ delete iGeneralTable;
+ iGeneralTable = NULL;
+
+ iGeneralTable = CContainerStoreGeneralTable::CreateL( *iUtils );
+
+ delete iAccountTable;
+ iAccountTable = NULL;
+
+ iAccountTable = CContainerStoreAccountTable::CreateL( *iUtils, *iEncryption, iCustomBehaviorProvider );
+
+ delete iContainersTable;
+ iContainersTable = NULL;
+
+ iContainersTable = CContainerStoreContainersTable::CreateL( *iUtils, iCustomBehaviorProvider, iCountsLength, *iEncryption );
+
+ delete iSortingTable;
+ iSortingTable = NULL;
+
+ iSortingTable = CContainerStoreSortingTable::CreateL( *iUtils, *iEncryption, *this );
+
+ delete iSearchResultTable;
+ iSearchResultTable = NULL;
+
+ iSearchResultTable = CContainerStoreSearchResultTable::CreateL( *iUtils );
+
+ delete iMruAddressTable;
+ iMruAddressTable = NULL;
+
+ iMruAddressTable = CContainerStoreMruAddressTable::CreateL( *iUtils, *iEncryption, *iGeneralTable, *iAccountTable );
+
+ iUtils->CommitDatabaseTransactionL();
+
+ __LOG_EXIT
+ } // end CreateTablesL
+
+// ==========================================================================
+// FUNCTION: OpenTablesL
+// ==========================================================================
+void CContainerStore::OpenTablesL()
+ {
+ __LOG_ENTER( "OpenTablesL" )
+
+ delete iGeneralTable;
+ iGeneralTable = NULL;
+
+ iGeneralTable = CContainerStoreGeneralTable::OpenL( *iUtils );
+
+ delete iAccountTable;
+ iAccountTable = NULL;
+
+ iAccountTable = CContainerStoreAccountTable::OpenL( *iUtils, *iEncryption, iCustomBehaviorProvider );
+
+ delete iContainersTable;
+ iContainersTable = NULL;
+
+ iContainersTable = CContainerStoreContainersTable::OpenL( *iUtils, iCustomBehaviorProvider, iCountsLength, *iEncryption );
+
+ delete iSortingTable;
+ iSortingTable = NULL;
+
+ iSortingTable = CContainerStoreSortingTable::OpenL( *iUtils, *iEncryption, *this );
+
+ delete iSearchResultTable;
+ iSearchResultTable = NULL;
+
+ iSearchResultTable = CContainerStoreSearchResultTable::OpenL( *iUtils );
+
+ delete iMruAddressTable;
+ iMruAddressTable = NULL;
+
+ iMruAddressTable = CContainerStoreMruAddressTable::OpenL( *iUtils, *iEncryption, *iGeneralTable, *iAccountTable );
+
+ __LOG_EXIT
+ } // end OpenTablesL
+
+// ==========================================================================
+// FUNCTION: CloseTables
+// ==========================================================================
+void CContainerStore::CloseTables()
+ {
+ __LOG_ENTER( "CloseTables" )
+
+ delete iAccountTable;
+ iAccountTable = NULL;
+
+ delete iGeneralTable;
+ iGeneralTable = NULL;
+
+ delete iContainersTable;
+ iContainersTable = NULL;
+
+ delete iSortingTable;
+ iSortingTable = NULL;
+
+ delete iSearchResultTable;
+ iSearchResultTable = NULL;
+
+ delete iMruAddressTable;
+ iMruAddressTable = NULL;
+
+ __LOG_EXIT
+ } // end CloseTables
+
+// ==========================================================================
+// FUNCTION: ObserveL
+// ==========================================================================
+void CContainerStore::ObserveL( MContainerStoreObserver* aObserver )
+ {
+ __LOG_ENTER( "ObserverL" )
+
+ iObservers.AppendL( aObserver );
+
+ __LOG_EXIT
+ } // end ObserveL
+
+// ==========================================================================
+// FUNCTION: StopObserving
+// ==========================================================================
+void CContainerStore::StopObserving( MContainerStoreObserver* aObserver )
+ {
+ __LOG_ENTER( "StopObserving" )
+
+ TBool found = EFalse;
+
+ TInt index = 0;
+
+ while( !found && index < iObservers.Count() )
+ {
+ if( iObservers[index] == aObserver )
+ {
+ found = ETrue;
+ iObservers.Remove( index );
+ }
+ else
+ {
+ index++;
+ } // end if
+
+ } // end while
+
+ __LOG_EXIT
+ } // end StopObservingL
+
+// ==========================================================================
+// FUNCTION: NotifyObservers
+// ==========================================================================
+void CContainerStore::NotifyObservers( MContainerStoreObserver::TOperation aOperation,
+ const RArray<TContainerId>& aHierarchy,
+ const TDesC8& aQuickProperties,
+ MContainerStoreObserver* aDoNotNotify,
+ TContainerId aOtherId )
+ {
+ __LOG_ENTER_SUPPRESS( "NotifyObservers" )
+ if ( aHierarchy.Count() > 1 )
+ {
+ __LOG_WRITE8_FORMAT4_INFO( "op=%i id=%x pid=%x otherid=%x", aOperation, aHierarchy[0], aHierarchy[1], aOtherId );
+ }
+
+ // if aDoNotNotify is NULL or if the operation was for an uncommitted object then suppress this
+ // notification entirely.
+
+ if( aDoNotNotify && aHierarchy[aHierarchy.Count()-1] != KUncommittedContainers )
+ {
+ for( TInt index = 0; index < iObservers.Count(); index++ )
+ {
+ if( iObservers[index] != aDoNotNotify )
+ {
+ __LOG_WRITE8_FORMAT1_INFO( "Notifying observer %i", index );
+ iObservers[index]->ContainerModified( aOperation, aHierarchy, aOtherId, aQuickProperties );
+ } // end if
+
+ } // end for
+ } // end if
+
+ __LOG_EXIT
+ } // end NotifyObservers
+
+// ==========================================================================
+// FUNCTION: NotifyObservers
+// ==========================================================================
+void CContainerStore::NotifyObservers( TBool aAuthenticated )
+ {
+ __LOG_ENTER_SUPPRESS( "NotifyObservers" )
+ __LOG_WRITE8_FORMAT1_INFO( "authenticated=%i", aAuthenticated )
+
+ for( TInt index = 0; index < iObservers.Count(); index++ )
+ {
+ iObservers[index]->AuthenticationChanged( aAuthenticated );
+ } // end for
+
+ __LOG_EXIT
+ } // end NotifyObservers
+
+void CContainerStore::NotifyObservers( MContainerStoreObserver::TOperation aOperation,
+ TInt32 aOwnerId,
+ const TDesC8& aName,
+ const TDesC8& aNewName,
+ TContainerId aMailboxId,
+ MContainerStoreObserver* aDoNotNotify )
+ {
+ __LOG_ENTER_SUPPRESS( "NotifyObservers" )
+ __LOG_WRITE8_FORMAT4_INFO( "op=%i id=%x name=%S newName=%S", aOperation, aOwnerId, &aName, &aNewName );
+
+ if( aDoNotNotify )
+ {
+ for( TInt index = 0; index < iObservers.Count(); index++ )
+ {
+ if( iObservers[index] != aDoNotNotify )
+ {
+ __LOG_WRITE8_FORMAT1_INFO( "Notifying observer %i", index );
+ iObservers[index]->AccountModified( aOperation, aOwnerId, aName, aNewName, aMailboxId );
+ }
+ } // end for
+ }
+
+ __LOG_EXIT
+ }
+
+// ==========================================================================
+// FUNCTION: CreatePredefinedContainerIfNeededL
+// ==========================================================================
+void CContainerStore::CreatePredefinedContainerIfNeededL( TContainerId aId,
+ TContainerId aType,
+ TContainerId aParentId,
+ const TDesC8& aProperties )
+ {
+ __LOG_ENTER_SUPPRESS( "CreatePredefinedContainerIfNeededL" )
+ __LOG_WRITE8_FORMAT3_INFO( "id=%x type=%x pid=%x", aId, aType, aParentId )
+
+ TRAPD( result, iContainersTable->SeekL( aId ) );
+
+ if( result == KErrNotFound )
+ {
+ aId = aId | aType;
+
+ iUtils->BeginDatabaseTransactionLC();
+ iContainersTable->CreateContainerL( aId, aParentId, aProperties, iQuickProperties );
+ iUtils->CommitDatabaseTransactionL();
+
+ } // end if
+
+ __LOG_EXIT
+ } // end CreatePredefinedContainerIfNeededL
+
+// ==========================================================================
+// FUNCTION: Authenticated
+// ==========================================================================
+TBool CContainerStore::Authenticated()
+ {
+ return iEncryption->Authenticated();
+ } // end Authenticated
+
+// ==========================================================================
+// FUNCTION: AuthenticateL
+// ==========================================================================
+TBool CContainerStore::AuthenticateL( const TDesC& aPassword )
+ {
+ __LOG_ENTER( "AuthenticateL" )
+
+ CContainerStoreUtils::LeaveIfFalse( iEncryption->IsAuthenticationRequired(), KErrNotSupported );
+
+ RBuf8 buffer;
+ CleanupClosePushL( buffer );
+
+ iGeneralTable->GetAuthenticationDataL( buffer );
+
+ TBool oldAuthenticated = iEncryption->Authenticated();
+
+ TBool returnValue = iEncryption->AuthenticateL( aPassword, buffer );
+
+ TBool newAuthenticated = iEncryption->Authenticated();
+
+ CleanupStack::PopAndDestroy( &buffer );
+
+ if( oldAuthenticated != newAuthenticated )
+ {
+ NotifyObservers( newAuthenticated );
+ } // end if
+
+ __LOG_EXIT8_FORMAT1( "returnValue=%i", returnValue )
+ return returnValue;
+
+ } // end AuthenticateL
+
+// ==========================================================================
+// FUNCTION: ClearAuthentication
+// ==========================================================================
+void CContainerStore::ClearAuthentication()
+ {
+ __LOG_ENTER( "ClearAuthentication" )
+
+ TBool oldAuthenticated = iEncryption->Authenticated();
+
+ iEncryption->ClearAuthentication();
+
+ if( oldAuthenticated )
+ {
+ NotifyObservers( EFalse );
+ } // end if
+
+ __LOG_EXIT
+ } // end ClearAuthenticationL
+
+// ==========================================================================
+// FUNCTION: HasPasswordL
+// ==========================================================================
+TBool CContainerStore::HasPasswordL()
+ {
+ return iGeneralTable->AuthenticationDataPresentL();
+ } // end HasPasswordL
+
+
+
+// ==========================================================================
+// FUNCTION: SetPasswordL
+// ==========================================================================
+void CContainerStore::SetPasswordL( const TDesC& aPassword )
+ {
+ __LOG_ENTER( "SetPasswordL" )
+
+ if ( iGeneralTable->AuthenticationDataPresentL() )
+ {
+ User::Leave( KErrAlreadyExists );
+ }
+
+ RBuf8 buffer;
+ CleanupClosePushL( buffer );
+
+ iEncryption->CreateAuthenticationBufferL( aPassword, buffer );
+
+ iUtils->BeginDatabaseTransactionLC();
+ iGeneralTable->SetAuthenticationDataL( buffer );
+
+ //Enable the authentication required flag.
+ //From this point on, authentication is required
+ iGeneralTable->SetAuthenticationRequiredL( ETrue );
+ iEncryption->SetAuthenticationRequired( ETrue );
+
+ iUtils->CommitDatabaseTransactionL();
+
+ CleanupStack::PopAndDestroy( &buffer );
+
+ NotifyObservers( ETrue );
+
+ __LOG_EXIT
+ } // end SetPasswordL
+
+// ==========================================================================
+// FUNCTION: ChangePasswordL
+// ==========================================================================
+TBool CContainerStore::ChangePasswordL( const TDesC& aOldPassword, const TDesC& aNewPassword )
+ {
+ __LOG_ENTER( "ChangePasswordL" )
+
+ CContainerStoreUtils::LeaveIfFalse( iEncryption->IsAuthenticationRequired(), KErrNotSupported );
+
+ RBuf8 buffer;
+ CleanupClosePushL( buffer );
+
+ TBool oldAuthenticated = iEncryption->Authenticated();
+
+ iGeneralTable->GetAuthenticationDataL( buffer );
+
+ TBool oldPasswordOk = iEncryption->AuthenticateL( aOldPassword, buffer );
+
+ if( oldPasswordOk )
+ {
+ buffer.Close();
+
+ iEncryption->CreateAuthenticationBufferL( aNewPassword, buffer );
+
+ iUtils->BeginDatabaseTransactionLC();
+ iGeneralTable->SetAuthenticationDataL( buffer );
+ iUtils->CommitDatabaseTransactionL();
+
+ } // end if
+
+ CleanupStack::PopAndDestroy( &buffer );
+
+ if( oldAuthenticated != iEncryption->Authenticated() )
+ {
+ NotifyObservers( iEncryption->Authenticated() );
+ } // end if
+
+ __LOG_EXIT8_FORMAT1( "oldPasswordOk=%i", oldPasswordOk )
+ return oldPasswordOk;
+
+ } // end ChangePasswordL
+
+// ==========================================================================
+// FUNCTION: EnableEncryptionL
+// ==========================================================================
+void CContainerStore::EnableEncryptionL()
+ {
+ __LOG_ENTER( "EnableEncryptionL" );
+
+ //leave if password has not been set, or
+ // client has not authenticated with the store yet
+ if ( !iGeneralTable->AuthenticationDataPresentL() ||
+ !iEncryption->Authenticated() )
+ {
+ User::Leave( KErrNotReady );
+ }
+ //leave if authentication is already on
+ else if ( iGeneralTable->IsEncryptionOnL() )
+ {
+ User::Leave( KErrAlreadyExists );
+ }
+
+ iUtils->BeginDatabaseTransactionLC();
+
+ iGeneralTable->SetEncryptionFlagL( ETrue );
+ iEncryption->SetEncryptionFlag( ETrue );
+
+ iEncryptHandler->EncryptL();
+
+ iUtils->CommitDatabaseTransactionL();
+
+ __LOG_EXIT
+ }
+
+// ==========================================================================
+// FUNCTION: DisableEncryptionL
+// ==========================================================================
+void CContainerStore::DisableEncryptionL()
+ {
+ __LOG_ENTER( "DisableEncryptionL" );
+
+ //leave if password has not been set, or
+ // client has not authenticated with the store yet
+ if ( !iGeneralTable->AuthenticationDataPresentL() ||
+ !iEncryption->Authenticated() )
+ {
+ User::Leave( KErrNotReady );
+ }
+ //leave if authenticaion is NOT on
+ else if ( !iGeneralTable->IsEncryptionOnL() )
+ {
+ User::Leave( KErrAlreadyExists );
+ }
+
+ iUtils->BeginDatabaseTransactionLC();
+
+ iGeneralTable->SetEncryptionFlagL( EFalse );
+ iEncryption->SetEncryptionFlag( EFalse );
+
+ iEncryptHandler->DecryptL();
+
+ iUtils->CommitDatabaseTransactionL();
+
+ __LOG_EXIT
+ }
+
+// ==========================================================================
+// FUNCTION: CreateAccountL
+// ==========================================================================
+TContainerId CContainerStore::CreateAccountL( TInt32 aOwnerId, const TDesC& aName, MContainerStoreObserver* aDoNotNotify, const TDesC8& aProperties )
+ {
+ __LOG_ENTER_SUPPRESS( "CreateAccountL" );
+ __LOG_WRITE_FORMAT2_INFO( "ownerId=%i name=%S", aOwnerId, &aName );
+
+ //convert name to 8 bits
+ TPtrC8 name8;
+ const TUint8* valuePtr8 = reinterpret_cast<const TUint8*>( aName.Ptr() );
+ name8.Set( valuePtr8, aName.Length() * 2 );
+
+ TContainerId mailboxId = KMsgStoreInvalidId;
+
+ TRAPD(err, mailboxId = iAccountTable->FindAccountL( aOwnerId, name8 ) )
+ if ( err == KErrNone )
+ {
+ User::Leave( KErrAlreadyExists );
+ }
+ else if ( err != KErrNotFound )
+ {
+ User::Leave( err );
+ }
+
+ iUtils->BeginDatabaseTransactionLC();
+
+ mailboxId = CreateContainerL( EMsgStoreMailBoxBits, KMsgStoreRootMailBoxId, KMsgStoreInvalidId, aProperties );
+
+ iAccountTable->AddAccountL( mailboxId, aOwnerId, name8 );
+
+ iMruAddressTable->AddMailboxL( mailboxId );
+
+ CommitContainerL( mailboxId, KMsgStoreRootMailBoxId, mailboxId, NULL );
+
+ //create system folders, do not leave
+ TRAP_IGNORE( CreateSystemFoldersL( mailboxId ) );
+
+ iUtils->CommitDatabaseTransactionL();
+
+ NotifyObservers( MContainerStoreObserver::EAdd, aOwnerId, name8, KNullDesC8, mailboxId, aDoNotNotify );
+
+ return mailboxId;
+ }
+
+// ==========================================================================
+// FUNCTION: OpenAccountL
+// ==========================================================================
+TContainerId CContainerStore::OpenAccountL( TInt32 aOwnerId, const TDesC& aName, RBuf8& aProperties )
+ {
+ __LOG_ENTER_SUPPRESS( "OpenAccountL" );
+ __LOG_WRITE_FORMAT2_INFO( "ownerId=%i name=%S", aOwnerId, &aName );
+
+ //convert name to 8 bits
+ TPtrC8 name8;
+ const TUint8* valuePtr8 = reinterpret_cast<const TUint8*>( aName.Ptr() );
+ name8.Set( valuePtr8, aName.Length() * 2 );
+
+ TContainerId mailboxId = iAccountTable->FindAccountL( aOwnerId, name8 );
+
+ TContainerId parentId = KMsgStoreRootMailBoxId;
+ FetchPropertiesL( mailboxId, parentId, KMsgStoreInvalidId, aProperties );
+
+ return mailboxId;
+ }
+
+// ==========================================================================
+// FUNCTION: RenameAccountL
+// ==========================================================================
+void CContainerStore::RenameAccountL( TInt32 aOwnerId, const TDesC& aOldName, const TDesC& aNewName, MContainerStoreObserver* aDoNotNotify )
+ {
+ __LOG_ENTER_SUPPRESS( "RenameAccountL" );
+ __LOG_WRITE_FORMAT3_INFO( "ownerId=%i oldName=%S newName=%S", aOwnerId, &aOldName, &aNewName );
+
+ //convert names to 8 bits
+ TPtrC8 oldName8;
+ const TUint8* oldValPtr8 = reinterpret_cast<const TUint8*>( aOldName.Ptr() );
+ oldName8.Set( oldValPtr8, aOldName.Length() * 2 );
+
+ TPtrC8 newName8;
+ const TUint8* newValPtr8 = reinterpret_cast<const TUint8*>( aNewName.Ptr() );
+ newName8.Set( newValPtr8, aNewName.Length() * 2 );
+
+ iAccountTable->RenameAccountL( aOwnerId, oldName8, newName8 );
+
+ TContainerId mailboxId = iAccountTable->FindAccountL( aOwnerId, newName8 );
+
+ NotifyObservers( MContainerStoreObserver::ERenameAccount, aOwnerId, oldName8, newName8, mailboxId, aDoNotNotify );
+ }
+
+// ==========================================================================
+// FUNCTION: DeleteAccountL
+// ==========================================================================
+void CContainerStore::DeleteAccountL( TInt32 aOwnerId, const TDesC& aName, MContainerStoreObserver* aDoNotNotify )
+ {
+ __LOG_ENTER_SUPPRESS( "DeleteAccountL" );
+ __LOG_WRITE_FORMAT2_INFO( "ownerId=%i name=%S", aOwnerId, &aName );
+
+ //convert name to 8 bits
+ TPtrC8 name8;
+ const TUint8* valuePtr8 = reinterpret_cast<const TUint8*>( aName.Ptr() );
+ name8.Set( valuePtr8, aName.Length() * 2 );
+
+ TContainerId mailboxId = iAccountTable->FindAccountL( aOwnerId, name8 );
+
+ iUtils->BeginDatabaseTransactionLC();
+
+ //NOTE: must delete it from container table BEFORE deleting it from account table
+ //otherwise accountTable->UpdateTotalCounts() will leave.
+ DeleteContainerL( mailboxId, KMsgStoreInvalidId, KMsgStoreInvalidId, mailboxId, NULL );
+ iAccountTable->DeleteAccountL( aOwnerId, name8 );
+
+ iMruAddressTable->DeleteMailboxL( mailboxId );
+
+ iUtils->CommitDatabaseTransactionL();
+
+ NotifyObservers( MContainerStoreObserver::EDelete, aOwnerId, name8, KNullDesC8, mailboxId, aDoNotNotify );
+ }
+
+// ==========================================================================
+// FUNCTION: ListAccountsL
+// ==========================================================================
+void CContainerStore::ListAccountsL( TDes8& aBuf )
+ {
+ iAccountTable->AccountsL( aBuf );
+ }
+
+
+// ==========================================================================
+// FUNCTION: CreateContainerL
+// ==========================================================================
+TContainerId CContainerStore::CreateContainerL(
+ TContainerId aType,
+ TContainerId aParentId,
+ TContainerId aGrandparentId,
+ const TDesC8& aProperties,
+ TContainerId aId /*= KMsgStoreInvalidId*/ )
+ {
+ __LOG_ENTER_SUPPRESS( "CreateContainerL" );
+ __LOG_WRITE8_FORMAT3_INFO( "type=%x pid=%x gpid=%x", aType, aParentId, aGrandparentId )
+
+ iContainersTable->HierarchyL( aParentId, iHierarchy );
+ ValidateParentL( aGrandparentId, iHierarchy, EFalse ); // allow parent or grandparent to be uncommitted.
+
+ //check if we are already in a DB Transaction
+ TBool weStartedDBTransaction = EFalse;
+ if ( !iUtils->InTransaction() )
+ {
+ iUtils->BeginDatabaseTransactionLC();
+ weStartedDBTransaction = ETrue;
+ }
+
+ TContainerId id;
+ if ( KMsgStoreInvalidId == aId )
+ {
+ id = iGeneralTable->AssignNextIdL();
+ id = id | aType;
+ }
+ else
+ {
+ id = aId;
+ }
+
+ // Add a row to the containers table.
+ iContainersTable->CreateContainerL( id, KUncommittedContainers, aProperties, iQuickProperties );
+
+ if ( weStartedDBTransaction )
+ {
+ iUtils->CommitDatabaseTransactionL();
+ }
+
+ __LOG_EXIT8_FORMAT1( "id=%x", id );
+ return id;
+
+ } // end CreateContainerL
+
+
+/**
+ *
+ */
+void CContainerStore::AllocateIdsBlockL(
+ RArray<TContainerId>& aIds, TInt aBlockSize /*= 4*/ )
+ {
+ //check if we are already in a DB Transaction
+ TBool weStartedDBTransaction = EFalse;
+ if ( !iUtils->InTransaction() )
+ {
+ iUtils->BeginDatabaseTransactionLC();
+ weStartedDBTransaction = ETrue;
+ }
+
+ for ( TInt i = 0; i < aBlockSize; i++ )
+ {
+ TContainerId id = iGeneralTable->AssignNextIdL();
+ aIds.AppendL( id );
+ }
+
+ if ( weStartedDBTransaction )
+ {
+ iUtils->CommitDatabaseTransactionL();
+ }
+ }
+
+// ==========================================================================
+// FUNCTION: AbandonContainerL
+// ==========================================================================
+void CContainerStore::AbandonContainerL( TContainerId aId )
+ {
+ __LOG_ENTER_SUPPRESS( "AbandonContainerL" )
+ __LOG_WRITE8_FORMAT1_INFO( "id=%x", aId )
+
+ iContainersTable->SeekL( aId, iHierarchy );
+ ValidateParentL( KUncommittedContainers, iHierarchy );
+
+ DoAbandonContainerL( aId );
+
+ __LOG_EXIT
+ } // end AbandonContainerL
+
+// ==========================================================================
+// FUNCTION: DoAbandonContainerL
+// ==========================================================================
+void CContainerStore::DoAbandonContainerL( TContainerId aId )
+ {
+ iContainersTable->SeekL( aId );
+
+ iUtils->BeginDatabaseTransactionLC();
+ iContainersTable->MoveL( KToBeDeletedContainers, iTotalCountsDelta );
+ iUtils->CommitDatabaseTransactionL();
+
+ // No need to update the total counts since uncommitted containers do not
+ // affect the total counts.
+
+ } // end AbandonContainerL
+
+// ==========================================================================
+// FUNCTION: MarkUncommittedContainersForDeleteL
+// ==========================================================================
+void CContainerStore::MarkUncommittedContainersForDeleteL()
+ {
+ __LOG_ENTER( "MarkUncommittedContainersForDeleteL" )
+
+ RArray<TContainerId> children;
+ CleanupClosePushL( children );
+
+ // Abandon all of the uncommitted containers.
+ iContainersTable->ListChildrenL( children, KUncommittedContainers );
+
+ for( TInt i = 0; i < children.Count(); i++ )
+ {
+ __LOG_WRITE8_FORMAT1_INFO( "abandoning %x", children[i] )
+ TRAP_IGNORE( DoAbandonContainerL( children[i] ) );
+ } // end for
+
+ CleanupStack::PopAndDestroy( &children );
+
+ __LOG_EXIT
+ } // end MarkUncommittedContainersForDeleteL
+
+// ==========================================================================
+// FUNCTION: CommitContainerL
+// ==========================================================================
+void CContainerStore::CommitContainerL( TContainerId aId,
+ TContainerId aParentId,
+ TContainerId aMailBoxId,
+ MContainerStoreObserver* aObserver,
+ TContainerId aCopiedFromOriginalMsgId )
+ {
+ __LOG_ENTER_SUPPRESS( "CommitContainerL" )
+ __LOG_WRITE8_FORMAT2_INFO( "id=%x parentId=%x", aId, aParentId )
+
+ iContainersTable->SeekL( aId, iHierarchy );
+ ValidateParentL( KUncommittedContainers, iHierarchy );
+
+ iContainersTable->QuickPropertiesL( iQuickProperties );
+
+ //get the total counts for the mailbox
+ iAccountTable->TotalCountsL( aMailBoxId, iTotalCounts );
+
+ //check if we are already in a DB Transaction
+ TBool weStartedDBTransaction = EFalse;
+ if ( !iUtils->InTransaction() )
+ {
+ iUtils->BeginDatabaseTransactionLC();
+ weStartedDBTransaction = ETrue;
+ }
+
+ // Move the message.
+ iContainersTable->MoveL( aParentId, iTotalCountsDelta );
+
+ // Update the total counts.
+ iCustomBehaviorProvider.IncrementParentCounts( iTotalCounts, iTotalCountsDelta );
+ iAccountTable->UpdateTotalCountsL( aMailBoxId, iTotalCounts );
+
+ //update the sorting table if this container is a message
+ if ( ( aId & EMsgStoreContainerMask ) == EMsgStoreMessageBits )
+ {
+ RMsgStoreSortableFields sortableFields;
+ CleanupClosePushL( sortableFields );
+
+ GetSortableFieldsL( aId, sortableFields );
+ iSortingTable->AddMessageL( aId, aParentId, aMailBoxId, sortableFields );
+
+ CleanupStack::PopAndDestroy( &sortableFields );
+ }
+
+ if ( weStartedDBTransaction )
+ {
+ iUtils->CommitDatabaseTransactionL();
+ }
+
+ iContainersTable->HierarchyL( aId, iHierarchy );
+
+ NotifyObservers( MContainerStoreObserver::EAdd, iHierarchy, iQuickProperties, aObserver, aCopiedFromOriginalMsgId );
+
+ __LOG_EXIT
+ } // end CommitContainerL
+
+// ==========================================================================
+// FUNCTION: DeleteContainerL
+// ==========================================================================
+void CContainerStore::DeleteContainerL( TContainerId aId,
+ TContainerId aParentId,
+ TContainerId aGrandparentId,
+ TContainerId aMailBoxId,
+ MContainerStoreObserver* aObserver )
+ {
+ __LOG_ENTER_SUPPRESS( "DeleteContainerL" )
+ __LOG_WRITE8_FORMAT3_INFO( "id=%x pid=%x gpid=%x", aId, aParentId, aGrandparentId )
+
+ if( aId < KLowestUserCreatedContainerId )
+ {
+ __LOG_WRITE_ERROR( "Attempted to delete predefined container" )
+ User::Leave( KErrArgument );
+ } // end if
+
+ // Check for authentication, even though no encryption/decryption will be performed.
+ iEncryption->CheckForAuthenticationL();
+
+ iContainersTable->SeekL( aId, iHierarchy );
+
+ ValidateParentAndGrandparentL( aParentId, aGrandparentId, iHierarchy );
+
+ iContainersTable->QuickPropertiesL( iQuickProperties );
+
+ //get the current total counts for the mailbox
+ iAccountTable->TotalCountsL( aMailBoxId, iTotalCounts );
+ //check if we are already in a DB Transaction
+ TBool weStartedDBTransaction = EFalse;
+ if ( !iUtils->InTransaction() )
+ {
+ iUtils->BeginDatabaseTransactionLC();
+ weStartedDBTransaction = ETrue;
+ }
+
+ // Move the message to the ToBeDeletedContainers folder
+ iContainersTable->MoveL( KToBeDeletedContainers, iTotalCountsDelta );
+
+ // Update the total counts.
+ iCustomBehaviorProvider.IncrementParentCounts( iTotalCounts, iTotalCountsDelta );
+ iAccountTable->UpdateTotalCountsL( aMailBoxId, iTotalCounts );
+
+ //update the sorting table if necessary
+ TMsgStoreId type = aId & EMsgStoreContainerMask;
+ if ( type == EMsgStoreMessageBits )
+ {
+ //need to get the size
+ TRAP_IGNORE( iSortingTable->DeleteMessageL( aId ) );
+ }
+ else if ( type == EMsgStoreFolderBits )
+ {
+ //need to get the size
+ TRAP_IGNORE( iSortingTable->DeleteMessagesByFolderIdL( aId ) );
+ }
+ else if ( type == EMsgStoreMailBoxBits )
+ {
+ //need to get the size
+ TRAP_IGNORE( iSortingTable->DeleteMessagesByMailBoxIdL( aId ) );
+ }
+
+ if ( weStartedDBTransaction )
+ {
+ iUtils->CommitDatabaseTransactionL();
+ }
+
+ iDeleteHandler->Start();
+
+ // Only send a notification for the parent object.
+ NotifyObservers( MContainerStoreObserver::EDelete, iHierarchy, iQuickProperties, aObserver );
+
+ __LOG_EXIT
+ } // end DeleteContainerL
+
+// ==========================================================================
+// FUNCTION: MoveContainerL
+// ==========================================================================
+void CContainerStore::MoveContainerL( TContainerId aId,
+ TContainerId aOldParentId,
+ TContainerId aNewParentId,
+ MContainerStoreObserver* aObserver )
+ {
+ __LOG_ENTER_SUPPRESS( "MoveContainerL" )
+ __LOG_WRITE8_FORMAT3_INFO( "%x from %x to %x", aId, aOldParentId, aNewParentId )
+
+ if( aId < KLowestUserCreatedContainerId )
+ {
+ __LOG_WRITE_ERROR( "Attempted to move predefined container" )
+ User::Leave( KErrArgument );
+ } // end if
+
+ // Check for authentication, even though no encryption/decryption will be performed.
+ iEncryption->CheckForAuthenticationL();
+
+ iContainersTable->HierarchyL( aNewParentId, iHierarchy );
+
+ iContainersTable->SeekL( aId, iHierarchy );
+ ValidateParentL( aOldParentId, iHierarchy );
+
+ iContainersTable->QuickPropertiesL( iQuickProperties );
+
+ iUtils->BeginDatabaseTransactionLC();
+
+ iContainersTable->MoveL( aNewParentId, iTotalCountsDelta );
+
+ //update the sorting table if necessary
+ if ( ( aId & EMsgStoreContainerMask ) == EMsgStoreMessageBits )
+ {
+ iSortingTable->UpdateMessageFolderL( aId, aNewParentId );
+ }
+
+ // No need to update the total counts since moves don't affect the total counts except in the
+ // case of Commit and Delete, which are not handled by this function.
+
+ iUtils->CommitDatabaseTransactionL();
+
+ NotifyObservers( MContainerStoreObserver::EMove, iHierarchy, iQuickProperties, aObserver, aNewParentId );
+
+ __LOG_EXIT
+ } // end MoveContainerL
+
+// ==========================================================================
+// FUNCTION: CopyContainerL
+// ==========================================================================
+TContainerId CContainerStore::CopyContainerL( TContainerId aId,
+ TContainerId aSourceId,
+ TContainerId aSourceParentId,
+ TContainerId aDestinationId,
+ TContainerId aDestinationParentId,
+ TContainerId aMailBoxId,
+ MContainerStoreObserver* aObserver )
+ {
+ __LOG_ENTER_SUPPRESS( "CopyContainerL" )
+ __LOG_WRITE8_FORMAT3_INFO( "id=%x source=%x destination=%x", aId, aSourceId, aDestinationId )
+
+ // Verify the hierarchy of the destination.
+ iContainersTable->HierarchyL( aDestinationId, iHierarchy );
+ ValidateParentL( aDestinationParentId, iHierarchy );
+
+ // Verify the hierarchy of the source.
+ iContainersTable->HierarchyL( aId, iHierarchy );
+ ValidateParentAndGrandparentL( aSourceId, aSourceParentId, iHierarchy );
+
+ iUtils->BeginDatabaseTransactionLC();
+ iContentManager->StartCopyTransaction();
+
+ TContainerId newId = 0;
+ TRAPD( err, newId = RecursiveCopyL( 0, aId, KUncommittedContainers ) );
+ if ( KErrNone == err )
+ {
+ iUtils->CommitDatabaseTransactionL();
+
+ //Per Gypsy UI's request, when copying messages, we now send the original message id
+ // in the aOtherId field of the notification ( MotificationNotify() ).
+ if ( ( aId & EMsgStoreContainerMask ) == EMsgStoreMessageBits )
+ {
+ CommitContainerL( newId, aDestinationId, aMailBoxId, aObserver, aId );
+ }
+ else
+ {
+ CommitContainerL( newId, aDestinationId, aMailBoxId, aObserver );
+ }
+ }
+ else
+ {
+ iContentManager->RollbackCopyTransaction();
+
+ //will automatically rollback the transaction.
+ CleanupStack::PopAndDestroy( iUtils );
+
+ //if there was a rollback and the recover call detected recovering is
+ //necessary (happens in one of the unit tests) then all of the open
+ //tables will be closed; so reopening the tables is necessary; not
+ //confident enough whether this is not a very specific case so making
+ //this change only here; technically tables must always be reopened
+ //after a call to Recover because they could definitely get closed
+ //although the documentation doesn't say anything.
+
+ CloseTables();
+ OpenTablesL();
+
+ User::Leave( err );
+ }
+
+ __LOG_EXIT8_FORMAT1( "id=%x", newId )
+ return newId;
+
+ } // end CopyContainerL
+
+// ==========================================================================
+// FUNCTION: RecursiveCopyL
+//
+// Recursion notes:
+//
+// Each recursive call pushes these variables on the stack:
+//
+// children (RArray has 8 32-bit values, actual elements are allocated from the heap)
+// newId
+// aDepth
+// aId
+// aDestinationId
+//
+// This is approximately 48 bytes per invocation (plus any additional runtime overhead like
+// return addresses, etc.). Assuming 80 bytes per invocation, and an 8K Symbian stack, a
+// recursion depth of up to 100 should be acceptable.
+// ==========================================================================
+TContainerId CContainerStore::RecursiveCopyL( TUint aDepth,
+ TContainerId aId,
+ TContainerId aDestinationId )
+ {
+ __LOG_ENTER_SUPPRESS( "RecursiveCopyL" )
+
+ if( aDepth > KMaxRecursionDepth )
+ {
+ __LOG_WRITE_ERROR( "Maximum recursion depth exceeded" );
+ User::Leave( KErrOverflow );
+ } // end if
+
+ iContainersTable->SeekL( aId );
+
+ // Generate a new ID, with the same type as the entry being copied.
+ TContainerId newId = iGeneralTable->AssignNextIdL() | (aId & KContainerTypeMask);
+
+ // Copy current row.
+ iContainersTable->CopyL( newId, aDestinationId, iQuickProperties );
+
+ // Copy content and children.
+ RArray<TContainerId> children;
+ CleanupClosePushL( children );
+
+ TRAPD( result, iContentManager->CopyContentL( aId, newId );
+
+ iContainersTable->ListChildrenL( children, aId );
+
+ for( TInt i = 0; i < children.Count(); i++ )
+ {
+ RecursiveCopyL( aDepth+1, children[i], newId );
+ }
+ );
+
+ User::LeaveIfError( result );
+
+ CleanupStack::PopAndDestroy( &children );
+
+ return newId;
+
+ } // end RecursiveCopyL
+
+// ==========================================================================
+// FUNCTION: ChildrenCountsL
+// ==========================================================================
+void CContainerStore::ChildrenCountsL( TContainerId aId, TDes8& aCounts )
+ {
+ __LOG_ENTER_SUPPRESS( "ChildrenCountsL" )
+ __LOG_WRITE8_FORMAT1_INFO( "id=%x", aId )
+
+ iContainersTable->SeekL( aId, iHierarchy );
+ iContainersTable->ChildrenCountsL( aCounts );
+
+ __LOG_EXIT
+ } // end ChildrenCountsL
+
+// ==========================================================================
+// FUNCTION: TotalCountsL
+// ==========================================================================
+void CContainerStore::TotalCountsL( TContainerId aMailBoxId, TDes8& aCounts )
+ {
+ __LOG_ENTER( "TotalCountsL" )
+
+ iAccountTable->TotalCountsL( aMailBoxId, aCounts );
+
+ __LOG_EXIT
+ } // end TotalCountsL
+
+// ==========================================================================
+// FUNCTION: UpdatePropertiesL
+// ==========================================================================
+void CContainerStore::UpdatePropertiesL( TContainerId aId,
+ TContainerId aParentId,
+ TContainerId aMailBoxId,
+ const TDesC8& aProperties,
+ MContainerStoreObserver* aObserver )
+ {
+ __LOG_ENTER_SUPPRESS( "UpdatePropertiesL" )
+ __LOG_WRITE8_FORMAT2_INFO( "id=%x pid=%x", aId, aParentId )
+
+ iContainersTable->SeekL( aId, iHierarchy );
+ ValidateParentL( aParentId, iHierarchy );
+
+ //gets the total counts for the mailbox
+ iAccountTable->TotalCountsL( aMailBoxId, iTotalCounts );
+
+ iUtils->BeginDatabaseTransactionLC();
+
+ TContainerId realParentId;
+
+ // Update the properties.
+ iContainersTable->UpdatePropertiesL( aProperties, iQuickProperties, iTotalCountsDelta, realParentId );
+
+ // Update the total counts if the parent is not uncommitted.
+ if( realParentId != KUncommittedContainers )
+ {
+ iCustomBehaviorProvider.IncrementParentCounts( iTotalCounts, iTotalCountsDelta );
+ iAccountTable->UpdateTotalCountsL( aMailBoxId, iTotalCounts );
+ }
+
+ //update the sorting table if necessary
+ if ( ( aId & EMsgStoreContainerMask ) == EMsgStoreMessageBits )
+ {
+ RMsgStoreSortableFields sortableFields;
+ CleanupClosePushL( sortableFields );
+
+ GetSortableFieldsL( aId, sortableFields );
+ //need to get the size
+ TRAPD( err, iSortingTable->UpdateMessageL( aId, sortableFields ) );
+ if ( err != KErrNone && err != KErrNotFound )
+ {
+ //if err==KErrNotFound, it just means that the message has been created
+ // but not committed yet, in this case, the message will be added to the
+ // sorting table when it is committed. So ignore KErrNotFound
+ User::Leave( err );
+ }
+
+ CleanupStack::PopAndDestroy( &sortableFields );
+ }
+
+ iUtils->CommitDatabaseTransactionL();
+
+ NotifyObservers( MContainerStoreObserver::EUpdateProperties, iHierarchy, iQuickProperties, aObserver );
+
+ __LOG_EXIT
+ } // end UpdatePropertiesL
+
+// ==========================================================================
+// FUNCTION: UpdatePropertyL
+// ==========================================================================
+void CContainerStore::UpdatePropertyL( TContainerId aId,
+ TContainerId aParentId,
+ TContainerId aMailBoxId,
+ const TDesC8& aName,
+ TUint8 aType,
+ const TDesC8& aValue,
+ MContainerStoreObserver* aObserver )
+ {
+ __LOG_ENTER_SUPPRESS( "UpdatePropertyL" )
+ __LOG_WRITE8_FORMAT4_INFO( "id=%x pid=%x name=%S type=%i", aId, aParentId, &aName, aType )
+
+ iContainersTable->SeekL( aId, iHierarchy );
+ ValidateParentL( aParentId, iHierarchy );
+
+ //gets the total counts for the mailbox
+ iAccountTable->TotalCountsL( aMailBoxId, iTotalCounts );
+
+ iUtils->BeginDatabaseTransactionLC();
+
+ TContainerId realParentId;
+
+ // Update the property.
+ iContainersTable->UpdatePropertyL( aName, aType, aValue, iQuickProperties, iTotalCountsDelta, realParentId );
+
+ // Update the total counts.
+ if( realParentId != KUncommittedContainers )
+ {
+ iCustomBehaviorProvider.IncrementParentCounts( iTotalCounts, iTotalCountsDelta );
+ iAccountTable->UpdateTotalCountsL( aMailBoxId, iTotalCounts );
+ }
+
+ //update the sorting table if necessary
+ if ( ( aId & EMsgStoreContainerMask ) == EMsgStoreMessageBits )
+ {
+ RMsgStoreSortableFields sortableFields;
+ CleanupClosePushL( sortableFields );
+
+ GetSortableFieldsL( aId, sortableFields );
+ //need to get the size
+ TRAPD( err, iSortingTable->UpdateMessageL( aId, sortableFields ) );
+ if ( err != KErrNone && err != KErrNotFound )
+ {
+ //if err==KErrNotFound, it just means that the message has been created
+ // but not committed yet, in this case, the message will be added to the
+ // sorting table when it is committed. So ignore KErrNotFound
+ User::Leave( err );
+ }
+
+ CleanupStack::PopAndDestroy( &sortableFields );
+ }
+
+ iUtils->CommitDatabaseTransactionL();
+
+ NotifyObservers( MContainerStoreObserver::EUpdateProperties, iHierarchy, iQuickProperties, aObserver );
+
+ __LOG_EXIT
+ } // end UpdatePropertyL
+
+// ==========================================================================
+// FUNCTION: ReplaceContentL
+// ==========================================================================
+void CContainerStore::ReplaceContentL( TContainerId aId,
+ TContainerId aParentId,
+ const TDesC8& aContent,
+ MContainerStoreObserver* aObserver )
+ {
+ __LOG_ENTER_SUPPRESS( "ReplaceContentL" )
+ __LOG_WRITE8_FORMAT2_INFO( "id=%x pid=%x", aId, aParentId )
+
+ iContainersTable->HierarchyL( aId, iHierarchy );
+ ValidateParentL( aParentId, iHierarchy, EFalse );
+
+ TBool isRowEncrypted = iContainersTable->IsEncrypted();
+
+ iContentManager->ReplaceContentL( aId, aContent, isRowEncrypted );
+
+ NotifyObservers( MContainerStoreObserver::EUpdateContent, iHierarchy, KNullDes, aObserver );
+
+ __LOG_EXIT
+ } // end ReplaceContentL
+
+// ==========================================================================
+// FUNCTION: ReplaceContentL
+// ==========================================================================
+void CContainerStore::ReplaceContentL( TContainerId aId,
+ TContainerId aParentId,
+ RFile& aContentFile,
+ MContainerStoreObserver* aObserver )
+ {
+ __LOG_ENTER_SUPPRESS( "ReplaceContentL" )
+ __LOG_WRITE8_FORMAT2_INFO( "id=%x pid=%x", aId, aParentId )
+
+ iContainersTable->HierarchyL( aId, iHierarchy );
+ ValidateParentL( aParentId, iHierarchy, EFalse );
+
+ TBool isRowEncrypted = iContainersTable->IsEncrypted();
+
+ iContentManager->ReplaceContentL( aId, aContentFile, isRowEncrypted );
+
+ NotifyObservers( MContainerStoreObserver::EUpdateContent, iHierarchy, KNullDes, aObserver );
+
+ __LOG_EXIT
+ } // end ReplaceContentL
+
+// ==========================================================================
+// FUNCTION: AppendContentL
+// ==========================================================================
+void CContainerStore::AppendContentL( TContainerId aId, TContainerId aParentId, const TDesC8& aContent, MContainerStoreObserver* aObserver )
+ {
+ __LOG_ENTER_SUPPRESS( "AppendContentL" )
+ __LOG_WRITE8_FORMAT2_INFO( "id=%x pid=%x", aId, aParentId )
+
+ iContainersTable->HierarchyL( aId, iHierarchy );
+ ValidateParentL( aParentId, iHierarchy, EFalse );
+
+ TBool isRowEncrypted = iContainersTable->IsEncrypted();
+
+ iContentManager->AppendContentL( aId, aContent, isRowEncrypted );
+
+ NotifyObservers( MContainerStoreObserver::EUpdateContent, iHierarchy, KNullDes, aObserver );
+
+ __LOG_EXIT
+ } // end AppendContentL
+
+// ==========================================================================
+// FUNCTION: PrependContentL
+// ==========================================================================
+void CContainerStore::PrependContentL(
+ TContainerId aId,
+ TContainerId aParentId,
+ const TDesC8& aContent,
+ MContainerStoreObserver* aObserver )
+ {
+ __LOG_ENTER_SUPPRESS( "PrependContentL" )
+ __LOG_WRITE8_FORMAT2_INFO( "id=%x pid=%x", aId, aParentId )
+
+ iContainersTable->HierarchyL( aId, iHierarchy );
+ ValidateParentL( aParentId, iHierarchy, EFalse );
+
+ TBool isRowEncrypted = iContainersTable->IsEncrypted();
+
+ iContentManager->PrependContentL( aId, aContent, isRowEncrypted );
+
+ NotifyObservers( MContainerStoreObserver::EUpdateContent, iHierarchy, KNullDes, aObserver );
+
+ __LOG_EXIT
+ } // end PrependContentL
+
+// ==========================================================================
+// FUNCTION: RemoveContentL
+// ==========================================================================
+void CContainerStore::RemoveContentL( TContainerId aId, TContainerId aParentId, MContainerStoreObserver* aObserver )
+ {
+ __LOG_ENTER_SUPPRESS( "RemoveContentL" )
+ __LOG_WRITE8_FORMAT2_INFO( "id=%x pid=%x", aId, aParentId )
+
+ iContainersTable->HierarchyL( aId, iHierarchy );
+ ValidateParentL( aParentId, iHierarchy, EFalse );
+
+ iContentManager->RemoveContentL( aId );
+
+ NotifyObservers( MContainerStoreObserver::ERemoveContent, iHierarchy, KNullDes, aObserver );
+
+ __LOG_EXIT
+ } // end RemoveContentL
+
+// ==========================================================================
+// FUNCTION: FetchPropertiesL
+// ==========================================================================
+void CContainerStore::FetchPropertiesL( TContainerId aId,
+ TContainerId& aParentId,
+ TContainerId aGrandparentId,
+ RBuf8& aProperties,
+ TContainerId aMailboxId )
+ {
+ __LOG_ENTER_SUPPRESS( "FetchPropertiesL" )
+ __LOG_WRITE8_FORMAT3_INFO( "id=%x pid=%x gpid=%x", aId, aParentId, aGrandparentId )
+
+ iContainersTable->SeekL( aId, iHierarchy );
+ ValidateParentAndGrandparentL( aParentId, aGrandparentId, iHierarchy );
+
+ //check the mailbox id if specified
+ if ( aMailboxId != KContainerInvalidId )
+ {
+ if ( iHierarchy.Find( aMailboxId ) < 0 )
+ {
+ User::Leave( KErrNotFound );
+ }
+ }
+
+ if( iHierarchy.Count() > 1 )
+ {
+ aParentId = iHierarchy[1];
+ } // end if
+
+ iContainersTable->PropertiesL( aProperties );
+
+ __LOG_EXIT
+ } // end FetchPropertiesL
+
+// ==========================================================================
+// FUNCTION: FastFetchPropertiesL
+// ==========================================================================
+void CContainerStore::FastFetchPropertiesL( TContainerId aId,
+ TBool aQuickProperties,
+ TContainerId& aParentId,
+ RBuf8& aProperties )
+ {
+ __LOG_ENTER_SUPPRESS( "FastFetchPropertiesL" )
+ __LOG_WRITE8_FORMAT2_DEBUG3( "id=%x pid=%x", aId, aParentId )
+
+ iContainersTable->SeekL( aId );
+
+ aParentId = iContainersTable->ParentId();
+
+ if( aQuickProperties )
+ {
+ iContainersTable->QuickPropertiesL( aProperties );
+ }
+ else
+ {
+ iContainersTable->PropertiesL( aProperties );
+ } // end if
+
+ } // end FastFetchPropertiesL
+
+// ==========================================================================
+// FUNCTION: FetchContentL
+// ==========================================================================
+void CContainerStore::FetchContentL( TContainerId aId,
+ TContainerId aParentId,
+ TDes8& aContent,
+ TUint aStartPosition )
+ {
+ __LOG_ENTER_SUPPRESS( "FetchContentL(1)" )
+ __LOG_WRITE8_FORMAT3_INFO( "id=%x pid=%x spos=%i", aId, aParentId, aStartPosition )
+
+ // Make sure that the message has not been deleted, otherwise generate KErrNotFound.
+ iContainersTable->HierarchyL( aId, iHierarchy );
+ ValidateParentL( aParentId, iHierarchy );
+
+ TBool isRowEncrypted = iContainersTable->IsEncrypted();
+
+ iContentManager->FetchContentL( aId, aContent, isRowEncrypted, aStartPosition );
+
+ __LOG_EXIT
+ } // end FetchContentL
+
+// ==========================================================================
+// FUNCTION: FetchContentL
+// ==========================================================================
+void CContainerStore::FetchContentL( TContainerId aId,
+ TContainerId aParentId,
+ RFile& aDestinationFile )
+ {
+ __LOG_ENTER_SUPPRESS( "FetchContentL(2)" )
+ __LOG_WRITE8_FORMAT2_INFO( "id=%x pid=%x", aId, aParentId )
+
+ // Make sure that the message has not been deleted, otherwise generate KErrNotFound.
+ iContainersTable->HierarchyL( aId, iHierarchy );
+ ValidateParentL( aParentId, iHierarchy );
+
+ TBool isRowEncrypted = iContainersTable->IsEncrypted();
+
+ iContentManager->FetchContentL( aId, aDestinationFile, isRowEncrypted );
+
+ __LOG_EXIT
+ } // end FetchContentL
+
+// ==========================================================================
+// FUNCTION: ContentLengthL
+// ==========================================================================
+TUint CContainerStore::ContentLengthL( TContainerId aId,
+ TContainerId aParentId )
+ {
+ __LOG_ENTER_SUPPRESS( "ContentLengthL" )
+ __LOG_WRITE8_FORMAT2_INFO( "id=%x pid=%x", aId, aParentId )
+
+ // Make sure that the message has not been deleted, otherwise generate KErrNotFound.
+ iContainersTable->HierarchyL( aId, iHierarchy );
+ ValidateParentL( aParentId, iHierarchy );
+
+ TBool isRowEncrypted = iContainersTable->IsEncrypted();
+
+ TUint returnValue = iContentManager->ContentLengthL( aId, isRowEncrypted );
+
+ __LOG_EXIT8_FORMAT1( "length=%i", returnValue )
+ return returnValue;
+ } // end ContentLengthL
+
+
+// ==========================================================================
+// FUNCTION: OpenContentFileL
+// ==========================================================================
+void CContainerStore::OpenContentFileL( TContainerId aId, TContainerId aParentId, RFs& aFs, RFile& aFile )
+ {
+ __LOG_ENTER_SUPPRESS( "OpenContentFileL" )
+ __LOG_WRITE8_FORMAT2_INFO( "id=%x pid=%x", aId, aParentId )
+
+ // Make sure that the message has not been deleted, otherwise generate KErrNotFound.
+ iContainersTable->HierarchyL( aId, iHierarchy );
+ ValidateParentL( aParentId, iHierarchy );
+
+ TBool isRowEncrypted = iContainersTable->IsEncrypted();
+
+ iContentManager->OpenContentFileL( aId, aFs, aFile, isRowEncrypted );
+ }
+
+// ==========================================================================
+// FUNCTION: ListChildrenL
+// ==========================================================================
+void CContainerStore::ListChildrenL( RArray<TContainerId>& aChildren, TContainerId aId, TContainerId aParentId, TContainerId aType, TBool aRecursive )
+ {
+ __LOG_ENTER_SUPPRESS( "ListChildrenL" )
+ __LOG_WRITE8_FORMAT2_INFO( "id=%x pid=%x", aId, aParentId )
+
+ iContainersTable->HierarchyL( aId, iHierarchy );
+ ValidateParentL( aParentId, iHierarchy );
+
+ iContainersTable->ListChildrenL( aChildren, aId, aType, aRecursive );
+
+ __LOG_EXIT
+ } // end ListChildrenL
+
+// ==========================================================================
+// FUNCTION: FirstChildL
+// ==========================================================================
+TContainerId CContainerStore::FirstChildL( TContainerId aId )
+ {
+ __LOG_ENTER_SUPPRESS( "FirstChildL" )
+ __LOG_WRITE8_FORMAT1_INFO( "id=%x", aId )
+
+ const TUint bufSize = 60;
+ TBuf<bufSize> queryString;
+
+ _LIT( KEquals, "=" );
+
+ queryString.Copy( KContainersTableParentIdCol );
+ queryString.Append( KEquals );
+ queryString.AppendNum( aId );
+
+ TContainerId returnValue = iContainersTable->FindL( queryString );
+
+ __LOG_EXIT
+ return returnValue;
+
+ } // end FirstChildL
+
+TContainerId CContainerStore::FirstChildL( TContainerId aId, TBool& aIsChildEncrypted )
+ {
+ TContainerId firstChildId = FirstChildL( aId );
+
+ if( firstChildId != KContainerInvalidId )
+ {
+ aIsChildEncrypted = iContainersTable->IsEncrypted();
+ } // end if
+ return firstChildId;
+ }
+
+// ==========================================================================
+// FUNCTION: FirstChildL
+// ==========================================================================
+void CContainerStore::FirstChildL( TContainerId aId, TContainerId& aFirstChildId, TDbBookmark& aBookmark )
+ {
+ aFirstChildId = FirstChildL( aId );
+
+ if( aFirstChildId != KContainerInvalidId )
+ {
+ aBookmark = iContainersTable->Bookmark();
+ } // end if
+
+ } // end FirstChildL
+
+// ==========================================================================
+// FUNCTION: SearchL
+// ==========================================================================
+CContainerStoreSearchHandler* CContainerStore::SearchL( TContainerId aType,
+ TMsgStoreSearchCmdParams& aCmdParam,
+ RPointerArray<HBufC>& aSearchStrings,
+ RArray<TContainerId>& aFolderIds,
+ RPointerArray<HBufC8>& aPropertyNames,
+ MContainerStoreSearchClient& aSearchClient )
+ {
+ __LOG_ENTER_SUPPRESS( "SearchL" )
+
+ CContainerStoreSearchHandler* handler = new(ELeave) CContainerStoreSearchHandler( *this,
+ *iContentManager,
+ *iSearchResultTable,
+ *iSortingTable,
+ aType,
+ aSearchClient,
+ iBasePriority + KSearchPriorityOffset );
+ CleanupStack::PushL( handler );
+ handler->ConstructL( aSearchStrings, aCmdParam, aFolderIds, aPropertyNames );
+ CleanupStack::Pop( handler );
+
+ return handler;
+
+ } // end SearchL
+
+// ==========================================================================
+// FUNCTION: StartSortingL
+// ==========================================================================
+TContainerId CContainerStore::StartSortingL( TMsgStoreSortCriteria& aSortCriteria,
+ RPointerArray<HBufC8>& aPropertyNames,
+ TBool aInMemorySort )
+ {
+ __LOG_ENTER_SUPPRESS( "StartSortingL" )
+ __LOG_WRITE_FORMAT4_INFO( "folder=%x sortField=%d order=%d, aInMemorySort=%d", aSortCriteria.iFolderId, aSortCriteria.iSortBy, aSortCriteria.iSortOrder, aInMemorySort )
+
+ CMsgStoreSortResultRowSet* resultRowSet = iSortingTable->SortL( aSortCriteria, aInMemorySort );
+ CleanupStack::PushL( resultRowSet );
+
+ //the property names will be used by GetSortedRows, and only the properties specified in aPropertyNames
+ //will be returned to the client
+ resultRowSet->SetPropertyNamesL( aPropertyNames );
+
+ //the "subject prefixes to be ignored" is used when sorting subjects
+ //subject prefixes like: "RE:", "FW:" will be ignored
+ //resultRowSet->SetSubjectPrefixToIgnoreL( aSubjectPrefixToIgnore );
+
+ TSortSession session;
+
+ session.iSessionId = iNextSortSessionId++;
+ session.iResultRowSet = resultRowSet ;
+
+ iSortSessions.Append( session );
+
+ CleanupStack::Pop( resultRowSet );
+
+ return session.iSessionId;
+ }
+
+// ==========================================================================
+// FUNCTION: EndSortingL
+// ==========================================================================
+void CContainerStore::EndSortingL( TContainerId aSessionId )
+ {
+ __LOG_ENTER_SUPPRESS( "EndSortingL" )
+ __LOG_WRITE_FORMAT1_INFO( "session=%d", aSessionId )
+
+ //find the session;
+ TUint index = FindSortingSessionL( aSessionId );
+ if ( index < iSortSessions.Count() )
+ {
+ delete iSortSessions[index].iResultRowSet;
+ iSortSessions.Remove(index);
+ }
+ }
+
+// ==========================================================================
+// FUNCTION: GetSortedRowsL
+// ==========================================================================
+TBool CContainerStore::GetSortedRowsL( TMsgStoreGetSortedRowsCmdParams aParams, RBuf8& aPropertiesBuf, const TDesC& aStartWith )
+ {
+ __LOG_ENTER_SUPPRESS( "GetSortedRowsL" )
+ __LOG_WRITE_FORMAT4_INFO( "session=%d from msg=%x direction=%d rows=%d", aParams.iSortSessionId,
+ aParams.iStartingMessageId,
+ aParams.iDirection,
+ aParams.iRowsToRetrieve );
+
+ iUtils->SuspendCompactionLC();
+
+ //find the session;
+ TUint index = FindSortingSessionL( aParams.iSortSessionId );
+ CMsgStoreSortResultRowSet* rowSet = NULL;
+ if ( index < iSortSessions.Count() )
+ {
+ rowSet = iSortSessions[index].iResultRowSet;
+ }
+ else
+ {
+ User::Leave( KErrNotFound );
+ }
+
+
+ const RPointerArray<HBufC8>& propertyNames = rowSet->PropertyNames();
+
+ TMsgStoreId msgId;
+ TPckg<TContainerId> idPckg( msgId );
+
+ TContainerId folderId = rowSet->FolderId();
+ TPckg<TContainerId> folderIdPckg( folderId );
+
+ TUint32 length32;
+ TPckg<TUint32> length32Pckg( length32 );
+
+ const TUint overhead = idPckg.Length() + folderIdPckg.Length() + length32Pckg.Length();
+
+ TMsgStoreIteratorDirection direction = aParams.iDirection;
+ TUint rowsToGet = aParams.iRowsToRetrieve;
+
+ TBool hasMore = ETrue;
+ TInt err = KErrNone;
+
+ RBuf8 curPropertiesBuf;
+ CleanupClosePushL( curPropertiesBuf );
+
+ //position the starting point (put the cursor to the desired place)
+ if ( aStartWith == KNullDesC )
+ {
+ if ( aParams.iStartingMessageId == KMsgStoreSortResultTop )
+ {
+ rowSet->ToTopL();
+ }
+ else if ( aParams.iStartingMessageId == KMsgStoreSortResultBottom )
+ {
+ rowSet->ToEndL();
+ }
+ else
+ {
+ rowSet->GotoL( aParams.iStartingMessageId );
+ }
+ }
+ else
+ {
+ rowSet->GotoL( aStartWith, direction );
+ }
+
+ //for "Group" support in UI
+ //check if we need to skip the current group
+ if ( aParams.iSkipCurrentGroup )
+ {
+ TUint itemsInGroup;
+ hasMore = rowSet->SkipCurrentGroupL( direction, itemsInGroup );
+ }
+
+ //start retrieving rows
+ for ( TUint i = 0 ; hasMore && i < rowsToGet ; i++ )
+ {
+ if ( direction == EMsgStoreIteratorForward )
+ {
+ TRAP( err, msgId = rowSet->NextL() );
+ }
+ else
+ {
+ TRAP( err, msgId = rowSet->PreviousL() );
+ }
+
+ if ( err == KErrOverflow || err == KErrUnderflow )
+ {
+ hasMore = EFalse;
+ }
+ else if ( err != KErrNone )
+ {
+ User::Leave( err );
+ }
+ else
+ {
+ //got a valid row, get it's properties
+ curPropertiesBuf.SetLength( 0 );
+
+ FastFetchPropertiesL( msgId, EFalse, folderId, curPropertiesBuf );
+
+ //filter out the properties that are not specified in the propertyNames
+ if( propertyNames.Count() > 0 )
+ {
+ // Remove the properties that are not needed.
+ TPropertiesSerializer serializer( curPropertiesBuf );
+ TBool moreProperties = serializer.First();
+ while( moreProperties )
+ {
+ TBool found = EFalse;
+ for( TInt i = 0; !found && (i < propertyNames.Count()); i++ )
+ {
+ found = (propertyNames[i]->Compare( serializer.Name() ) == 0);
+ } // end for
+ if( found )
+ {
+ moreProperties = serializer.Next();
+ }
+ else
+ {
+ moreProperties = serializer.RemovePropertyL();
+ } // end if
+ } // end while
+ } // end if
+
+ aPropertiesBuf.ReAllocL( aPropertiesBuf.Length() + curPropertiesBuf.Length() + overhead ); //msgId + parentId + length32 = 12 bytes
+
+ aPropertiesBuf.Append( idPckg );
+ aPropertiesBuf.Append( folderIdPckg );
+
+ length32 = curPropertiesBuf.Length();
+ aPropertiesBuf.Append( length32Pckg );
+
+ aPropertiesBuf.Append( curPropertiesBuf );
+ }
+ }
+
+ CleanupStack::PopAndDestroy( &curPropertiesBuf );
+
+ //check if there are more rows left
+ if ( hasMore )
+ {
+ if ( direction == EMsgStoreIteratorForward )
+ {
+ hasMore = rowSet->HasMoreNextL();
+ }
+ else
+ {
+ hasMore = rowSet->HasMorePreviousL();
+ }
+ }
+
+ iUtils->ResumeCompaction();
+
+ return hasMore;
+
+ }
+
+// ==========================================================================
+// FUNCTION: IteratorGroupCountL
+// ==========================================================================
+TInt CContainerStore::IteratorGroupCountL( TContainerId aSessionId, RArray<TUint>& aItemsInGroup )
+ {
+ //find the session;
+ TUint index = FindSortingSessionL( aSessionId );
+ CMsgStoreSortResultRowSet* rowSet = NULL;
+ if ( index < iSortSessions.Count() )
+ {
+ rowSet = iSortSessions[index].iResultRowSet;
+ }
+ else
+ {
+ User::Leave( KErrNotFound );
+ }
+ return rowSet->GroupCountL( aItemsInGroup );
+ }
+
+// ==========================================================================
+// FUNCTION: SortedIdsAndFlagsL
+// ==========================================================================
+void CContainerStore::SortedIdsAndFlagsL( TContainerId aSessionId, RArray<TContainerId>& aIdArray, RArray<TUint32>& aFlagArray )
+ {
+ __LOG_ENTER_SUPPRESS( "SortedIdsAndFlagsL" )
+ //find the session;
+ TUint index = FindSortingSessionL( aSessionId );
+ CMsgStoreSortResultRowSet* rowSet = NULL;
+ if ( index < iSortSessions.Count() )
+ {
+ rowSet = iSortSessions[index].iResultRowSet;
+ }
+ else
+ {
+ User::Leave( KErrNotFound );
+ }
+ TContainerId folderId = rowSet->FolderId();
+
+ __LOG_WRITE_INFO("Before Calling SortedIdsL()")
+ rowSet->SortedIdsL( aIdArray );
+ __LOG_WRITE_INFO("After Calling SortedIdsL()")
+
+ TPckgBuf<TUint32> flagsPckg;
+
+ for ( TInt i = 0 ; i < aIdArray.Count() ; i++ )
+ {
+ iContainersTable->SeekL( aIdArray[i] );
+ iContainersTable->QuickPropertiesL( iQuickProperties );
+
+ TPropertiesSerializer serializer( iQuickProperties );
+
+ if ( !serializer.Find( KMsgStorePropertyFlags ) )
+ {
+ User::Leave( KErrCorrupt );
+ }
+
+ flagsPckg.Copy( serializer.Value() );
+ aFlagArray.Append( flagsPckg() );
+ }
+
+ __LOG_WRITE_INFO("After Getting all flags")
+
+ }
+
+
+// ==========================================================================
+// FUNCTION: SortedIndexOfL
+// ==========================================================================
+TInt CContainerStore::SortedIndexOfL( TContainerId aSessionId, TContainerId aMessageId )
+ {
+ //find the session;
+ TUint index = FindSortingSessionL( aSessionId );
+ CMsgStoreSortResultRowSet* rowSet = NULL;
+ if ( index < iSortSessions.Count() )
+ {
+ rowSet = iSortSessions[index].iResultRowSet;
+ }
+ else
+ {
+ User::Leave( KErrNotFound );
+ }
+ return rowSet->IndexOfL( aMessageId );
+ }
+
+// ==========================================================================
+// FUNCTION: SortedIdsL
+// ==========================================================================
+void CContainerStore::SortedIdsL( TContainerId aSessionId, RArray<TContainerId>& aIdArray )
+ {
+ //find the session;
+ TUint index = FindSortingSessionL( aSessionId );
+ CMsgStoreSortResultRowSet* rowSet = NULL;
+ if ( index < iSortSessions.Count() )
+ {
+ rowSet = iSortSessions[index].iResultRowSet;
+ }
+ else
+ {
+ User::Leave( KErrNotFound );
+ }
+ rowSet->SortedIdsL( aIdArray );
+ }
+
+// ==========================================================================
+// FUNCTION: SortedIdsAndGroupCountL
+// ==========================================================================
+void CContainerStore::SortedIdsAndGroupCountL( TContainerId aSessionId,
+ RArray<TContainerId>& aIdArray,
+ RArray<TUint>& aItemsInGroup )
+ {
+ //find the session;
+ TUint index = FindSortingSessionL( aSessionId );
+ CMsgStoreSortResultRowSet* rowSet = NULL;
+ if ( index < iSortSessions.Count() )
+ {
+ rowSet = iSortSessions[index].iResultRowSet;
+ }
+ else
+ {
+ User::Leave( KErrNotFound );
+ }
+ rowSet->SortedIdsAndGroupCountL( aIdArray, aItemsInGroup );
+ }
+
+// ==========================================================================
+// FUNCTION: FindSortingSessionL
+// ==========================================================================
+TUint CContainerStore::FindSortingSessionL( TContainerId aSessionId )
+ {
+ __LOG_ENTER_SUPPRESS( "FindSortingSessionL" )
+
+ TBool found = EFalse;
+ TUint i = 0;
+ for ( ; !found && i < iSortSessions.Count() ; i++ )
+ {
+ if ( iSortSessions[i].iSessionId == aSessionId )
+ {
+ found = ETrue;
+ break;
+ }
+ }
+
+ if ( !found )
+ {
+ __LOG_WRITE_ERROR( "ERR: session not found!" )
+ User::Leave( KErrNotFound );
+ }
+
+ return i;
+ }
+
+// ==========================================================================
+// FUNCTION: SetMaxMruCountL
+// ==========================================================================
+void CContainerStore::SetMaxMruCountL( TInt aMaxCount )
+ {
+ iMruAddressTable->SetMaxMruCountL( aMaxCount );
+ }
+
+// ==========================================================================
+// FUNCTION: SetMruAddressListL
+// ==========================================================================
+void CContainerStore::SetMruAddressListL( TContainerId aMailboxId, RPointerArray<CMruAddress>& aMruAddressArray )
+ {
+ iMruAddressTable->SetMruAddressListL( aMailboxId, aMruAddressArray );
+ }
+
+// ==========================================================================
+// FUNCTION: MruAddressListL
+// ==========================================================================
+const RPointerArray<CMruAddress>& CContainerStore::MruAddressListL( TContainerId aMailboxId )
+ {
+ return iMruAddressTable->MruAddressListL( aMailboxId );
+ }
+
+// ==========================================================================
+// FUNCTION: EncryptFirstL
+// ==========================================================================
+TBool CContainerStore::EncryptFirstL( TDbBookmark& aNextRow )
+ {
+ __LOG_ENTER( "EncryptFirstL" )
+
+ TBool hasMore = iContainersTable->EncryptFirstL( aNextRow );
+
+ __LOG_EXIT
+
+ return hasMore;
+ }
+
+// ==========================================================================
+// FUNCTION: EncryptNextL
+// ==========================================================================
+TBool CContainerStore::EncryptNextL( TDbBookmark& aNextRow )
+ {
+ __LOG_ENTER( "EncryptNextL" )
+
+ TContainerId containerId = KContainerInvalidId;
+
+ TBool hasMore = iContainersTable->EncryptNextL( aNextRow, containerId );
+
+ if ( containerId != KContainerInvalidId )
+ {
+ TRAP_IGNORE( iContentManager->EncryptL( containerId ) );
+ }
+
+ __LOG_EXIT
+
+ return hasMore;
+ }
+
+// ==========================================================================
+// FUNCTION: EncryptNextL
+// ==========================================================================
+TBool CContainerStore::DecryptFirstL( TDbBookmark& aNextRow )
+ {
+ __LOG_ENTER( "DecryptFirstL" )
+
+ TBool hasMore = iContainersTable->DecryptFirstL( aNextRow );
+
+ __LOG_EXIT
+
+ return hasMore;
+ }
+
+// ==========================================================================
+// FUNCTION: EncryptNextL
+// ==========================================================================
+TBool CContainerStore::DecryptNextL( TDbBookmark& aNextRow )
+ {
+ __LOG_ENTER( "DecryptNextL" )
+
+ TContainerId containerId = KContainerInvalidId;
+
+ TBool hasMore = iContainersTable->DecryptNextL( aNextRow, containerId );
+
+ if ( containerId != KContainerInvalidId )
+ {
+ TRAP_IGNORE( iContentManager->DecryptL( containerId ) );
+ }
+
+ __LOG_EXIT
+
+ return hasMore;
+ }
+
+// ==========================================================================
+// FUNCTION: ValidateParentL
+// ==========================================================================
+void CContainerStore::ValidateParentL( TContainerId aParentId,
+ const RArray<TContainerId>& aHierarchy,
+ TBool aStrictComparison )
+ {
+ __LOG_ENTER_SUPPRESS( "ValidateParentL" )
+
+ TBool matches = (aParentId == KContainerInvalidId) ||
+ ((aHierarchy.Count() > 1) &&
+ (aHierarchy[1] == aParentId) ||
+ ((aHierarchy[1] == KUncommittedContainers) && !aStrictComparison ));
+
+ if( !matches )
+ {
+ __LOG_WRITE_ERROR( "parent does not match" )
+
+ User::Leave( KErrNotFound );
+ } // end if
+
+ } // end ValidateParentL
+
+// ==========================================================================
+// FUNCTION: ValidateParentAndGrandparentL
+// ==========================================================================
+void CContainerStore::ValidateParentAndGrandparentL( TContainerId aParentId,
+ TContainerId aGrandparentId,
+ const RArray<TContainerId>& aHierarchy,
+ TBool aStrictComparison )
+ {
+ __LOG_ENTER_SUPPRESS( "ValidateParentAndGrandparentL" )
+
+ ValidateParentL( aParentId, aHierarchy, aStrictComparison );
+
+ TBool matches = (aGrandparentId == KContainerInvalidId) ||
+ ((aHierarchy.Count() == 2) &&
+ ((aHierarchy[1] == KUncommittedContainers) && !aStrictComparison )) ||
+ ((aHierarchy.Count() > 2) &&
+ ((aHierarchy[2] == aGrandparentId) ||
+ ((aHierarchy[2] == KUncommittedContainers) && !aStrictComparison )));
+
+ if( !matches )
+ {
+ __LOG_WRITE_ERROR( "grandparent does not match" )
+
+ User::Leave( KErrNotFound );
+ } // end if
+
+ } // end ValidateParentAndGrandparentL
+
+// ==========================================================================
+// FUNCTION: DeleteIndividualContainerL
+// ==========================================================================
+TBool CContainerStore::DeleteIndividualContainerL( TDbBookmark aBookmark )
+ {
+ __LOG_ENTER( "DeleteIndividualContainerL" )
+
+ TBool result = ETrue;
+
+ TContainerId id = iContainersTable->GotoL( aBookmark );
+
+ TRAPD( err, iContentManager->RemoveContentL( id ) );
+ if ( err == KErrInUse )
+ {
+ __LOG_WRITE_INFO("Content file still open, mark for delete again.")
+ iUtils->BeginDatabaseTransactionLC();
+ iContainersTable->MarkAsDeleteRetryL();
+ iUtils->CommitDatabaseTransactionL();
+ result = EFalse;
+ }
+ else
+ {
+ iUtils->BeginDatabaseTransactionLC();
+ iContainersTable->DeleteL();
+ iUtils->CommitDatabaseTransactionL();
+ }
+
+ __LOG_EXIT
+
+ return result;
+ } // end DeleteIndividualContainerL
+
+// ==========================================================================
+// FUNCTION: SuspendCompaction
+// ==========================================================================
+void CContainerStore::SuspendCompactionLC()
+ {
+ iUtils->SuspendCompactionLC();
+ } // end SuspendCompaction
+
+// ==========================================================================
+// FUNCTION: ResumeCompaction
+// ==========================================================================
+void CContainerStore::ResumeCompaction()
+ {
+ iUtils->ResumeCompaction();
+ } // end ResumeCompaction
+
+// ==========================================================================
+// FUNCTION: GetSortableFieldsL
+// ==========================================================================
+void CContainerStore::GetSortableFieldsL( TContainerId aMessageId, RMsgStoreSortableFields& aSortableFields )
+ {
+ RBuf8 propertiesBuf;
+ CleanupClosePushL( propertiesBuf );
+
+ iContainersTable->SeekL( aMessageId );
+
+ iContainersTable->PropertiesL( propertiesBuf );
+
+ iCustomBehaviorProvider.SortableFieldsL( iQuickProperties, propertiesBuf, aSortableFields );
+
+ CleanupStack::PopAndDestroy( &propertiesBuf );
+
+ //need to get the size
+ if ( aSortableFields.iSizeOnServer == 0 )
+ {
+ //get the size on client
+ //first get the proerty size of the message itself
+ TUint size = iContainersTable->PropertiesSizeL( aMessageId );
+
+ RArray<TContainerId> children;
+ CleanupClosePushL( children );
+
+ // Abandon all of the uncommitted containers.
+ iContainersTable->ListChildrenL( children, aMessageId ); //non-recursive, assuming the UI will not build an recursive attachment.
+ for ( int i = 0 ; i < children.Count() ; i++ )
+ {
+ //get the property size
+ size += iContainersTable->PropertiesSizeL( children[i] );
+ TBool isRowEncrypted = iContainersTable->IsEncrypted();
+ //get the content size
+ size += iContentManager->ContentLengthL( children[i], isRowEncrypted );
+ }
+
+ CleanupStack::PopAndDestroy( &children );
+
+ aSortableFields.iSizeOnClient = size;
+ }
+ }
+
+
+// ==========================================================================
+// FUNCTION: CreateSystemFoldersL
+// ==========================================================================
+void CContainerStore::CreateSystemFoldersL( TContainerId aMailboxId )
+ {
+ TPckg<TBool> boolPckg( ETrue );
+ TPckg<TUint> intPckg( aMailboxId );
+ TInt totalLength = TPropertiesSerializer::EFixedOverhead;
+ totalLength += KMsgStorePropertyFolderType().Length() + intPckg.Length() + TPropertiesSerializer::EPerNodeOverhead;
+ totalLength += KMsgStorePropertyLocal().Length() + boolPckg.Length() + TPropertiesSerializer::EPerNodeOverhead;
+
+ RBuf8 properties;
+ properties.Create( totalLength );
+ CleanupClosePushL( properties );
+
+ for ( TUint32 i = EMsgStoreInbox; i <= EMsgStoreDeleted; i++ )
+ {
+ properties.SetLength( 0 );
+ TPropertiesSerializer serializer( properties );
+
+ TPckg<TUint> typePkg( i );
+ serializer.AddPropertyL( KMsgStorePropertyFolderType, EMsgStoreTypeUint32, typePkg );
+
+ TBool isLocal = ( i == EMsgStoreDeleted );
+ TPckg<TBool> isLocalPkg( isLocal );
+ serializer.AddPropertyL( KMsgStorePropertyLocal, EMsgStoreTypeBool, isLocalPkg );
+
+ TContainerId folderId = CreateContainerL( EMsgStoreFolderBits, aMailboxId, KMsgStoreInvalidId, properties );
+
+ CommitContainerL( folderId, aMailboxId, aMailboxId, NULL );
+ }
+
+ CleanupStack::PopAndDestroy( &properties );
+ }
+
+// ==========================================================================
+// FUNCTION: GetSortableFields
+// ==========================================================================
+void CContainerStore::MessageUpdate( TContainerId aMessageId,
+ TContainerId aFolderId,
+ TMsgStoreOperation aOperation,
+ TUint aFieldsChanged,
+ const TDesC& aFrom,
+ const TDesC& aTo,
+ const TDesC& aSubject,
+ TInt64 aDate)
+ {
+ for ( TInt i = 0 ; i < iSortSessions.Count() ; i++ )
+ {
+ iSortSessions[i].iResultRowSet->MessageUpdate( aMessageId, aFolderId, aOperation, aFieldsChanged, aFrom, aTo, aSubject, aDate );
+ }
+ }
+
+// ==========================================================================
+// FUNCTION: FolderDeleted
+// ==========================================================================
+void CContainerStore::FolderDeleted( TContainerId aFolderId )
+ {
+ for ( TInt i = 0 ; i < iSortSessions.Count() ; i++ )
+ {
+ iSortSessions[i].iResultRowSet->FolderDeleted( aFolderId );
+ }
+ }
+
+// ==========================================================================
+// FUNCTION: MailBoxDeleted
+// ==========================================================================
+void CContainerStore::MailBoxDeleted( TContainerId aMailBoxId )
+ {
+ for ( TInt i = 0 ; i < iSortSessions.Count() ; i++ )
+ {
+ iSortSessions[i].iResultRowSet->MailBoxDeleted( aMailBoxId );
+ }
+ }
+
+/**
+ *
+ */
+/*public*/ CContainerStoreUtils& CContainerStore::StoreUtils()
+ {
+ return *iUtils;
+ }
+
+/**
+ *
+ */
+/*public*/ CContainerStoreContentManager& CContainerStore::ContentManager()
+ {
+ //guaranteed that cannot be NULL by ConstructL.
+ return *iContentManager;
+ }
+
+/**
+ *
+ */
+/*public*/ TBool CContainerStore::IsEncryptionEnabled()
+ {
+ return iEncryption->IsEncryptionOn();
+ }
+
+/**
+ *
+ */
+/*public*/
+void CContainerStore::BeginDatabaseTransactionLC()
+ {
+ iUtils->BeginDatabaseTransactionLC();
+ }
+
+/**
+ *
+ */
+/*public*/
+void CContainerStore::CommitDatabaseTransactionL()
+ {
+ iUtils->CommitDatabaseTransactionL();
+ }
+
+/**
+ *
+ */
+/*public*/ const TDesC& CContainerStore::PrivatePath()
+ {
+ return iUtils->PrivatePath();
+ }
+
+// ---------------
+// DEBUG FUNCTIONS
+// ---------------
+
+#ifdef _DEBUG
+
+void CContainerStore::SimulateLowDiskSpace( TInt aLatency )
+ {
+ iUtils->SimulateLowDiskSpace( aLatency );
+ }
+
+TInt CContainerStore::GetEncryptionStateL()
+ {
+ return iGeneralTable->EncryptionStateL();
+ }
+
+#endif
+