--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/emailservices/emailstore/message_store/server/src/ContainerStoreSearchHandler.cpp Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,506 @@
+/*
+* 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 search handler implementation.
+*
+*/
+
+
+
+// ========
+// INCLUDES
+// ========
+
+#include "ContainerStoreSearchHandler.h"
+#include "ContainerStore.h"
+#include "ContainerStoreDefs.h"
+#include "ContainerStoreContentManager.h"
+#include "ContainerStoreSearchResultTable.h"
+#include "MsgStoreSortResultRowSet.h"
+#include "PropertiesSerializer.h"
+//<cmail>
+#include "MsgStorePropertyKeys.h"
+//</cmail>
+
+// =========
+// CONSTANTS
+// =========
+
+// The heap buffer size for search operations.
+//WMT: This size needs to be >= KNormalBlockSize defined in ContainerStoreContentManager.cpp
+const TUint KSearchBufferSize = 4096;
+
+// ======================
+// METHOD IMPLEMENTATIONS
+// ======================
+
+// ==========================================================================
+// FUNCTION: Constructor
+// ==========================================================================
+CContainerStoreSearchHandler::CContainerStoreSearchHandler( CContainerStore& aContainerStore,
+ CContainerStoreContentManager& aContentManager,
+ CContainerStoreSearchResultTable& aSearchResultTable,
+ CContainerStoreSortingTable& aSortingTable,
+ TContainerId aType,
+ MContainerStoreSearchClient& aClient,
+ TInt aPriority ) :
+ CActive( aPriority ),
+ iContainerStore( aContainerStore ),
+ iContentManager( aContentManager ),
+ iSearchResultTable( aSearchResultTable ),
+ iSortingTable( aSortingTable ),
+ iClient( aClient ),
+ iType( aType ),
+ iSortResultSet( NULL ),
+ iIsNewSearch( ETrue )
+ {
+ __LOG_CONSTRUCT( "msg", "CContainerStoreSearchHandler" )
+
+ CActiveScheduler::Add(this);
+ } // end constructor
+
+// ==========================================================================
+// FUNCTION: ConstructL
+// ==========================================================================
+void CContainerStoreSearchHandler::ConstructL( RPointerArray<HBufC>& aSearchStrings,
+ TMsgStoreSearchCmdParams& aCmdParam,
+ RArray<TContainerId>& aFolderIds,
+ RPointerArray<HBufC8>& aPropertyNames )
+ {
+ __LOG_ENTER( "ConstructL" )
+
+ CreateSearchPatternL( aSearchStrings, iSearchStrings );
+
+ TInt maxSSLength = 0;
+ for ( TInt i = 0 ; i < aSearchStrings.Count() ; i++ )
+ {
+ if ( aSearchStrings[i]->Length() > maxSSLength )
+ {
+ maxSSLength = aSearchStrings[i]->Length();
+ }
+ }
+
+ iSearchBuffer.CreateL( KSearchBufferSize + maxSSLength * 2 );
+
+ InitializeL( aCmdParam, aFolderIds, aPropertyNames );
+
+ iSearchResultTable.DeleteAllL();
+
+ __LOG_EXIT
+ } // end ConstructL
+
+// ==========================================================================
+// FUNCTION: Destructor
+// ==========================================================================
+CContainerStoreSearchHandler::~CContainerStoreSearchHandler()
+ {
+ __LOG_DESTRUCT
+
+ Cancel();
+ TRAP_IGNORE( iSearchResultTable.DeleteAllL() );
+
+// iSearchIds.Reset();
+ iSearchBuffer.Close();
+ iFolderIds.Close();
+ iSearchStrings.ResetAndDestroy();
+ iPropertyNames.ResetAndDestroy();
+ delete iSortResultSet;
+ iPropertyBuf.Close();
+ } // end destructor
+
+// ==========================================================================
+// FUNCTION: StartL
+// ==========================================================================
+void CContainerStoreSearchHandler::StartL()
+ {
+ __LOG_ENTER( "StartL" )
+
+ iCurFolderIdIndex = -1;
+
+ SortNextFolderL( );
+
+ DoNextSearchL();
+
+ __LOG_EXIT
+ } // end StartL
+
+// ==========================================================================
+// FUNCTION: IsSameSearchCriteriaL
+// ==========================================================================
+TBool CContainerStoreSearchHandler::IsSameSearchCriteriaL( RPointerArray<HBufC>& aSearchStrings )
+ {
+ //
+ RPointerArray<HBufC> newSearchPatterns;
+
+ CreateSearchPatternL( aSearchStrings, newSearchPatterns );
+
+ TBool isSame = newSearchPatterns.Count() == iSearchStrings.Count();
+
+ if ( isSame )
+ {
+ for ( TInt i = 0 ; i < iSearchStrings.Count() ; i++ )
+ {
+ isSame = newSearchPatterns[i]->CompareC( *(iSearchStrings[i]) ) == 0;
+ if ( !isSame )
+ {
+ break;
+ }
+ }
+ }
+
+ newSearchPatterns.ResetAndDestroy();
+
+ return isSame;
+ }
+
+// ==========================================================================
+// FUNCTION: RestartL
+// ==========================================================================
+void CContainerStoreSearchHandler::RestartL( TMsgStoreSearchCmdParams& aCmdParam,
+ RArray<TContainerId>& aFolderIds,
+ RPointerArray<HBufC8>& aPropertyNames )
+ {
+ InitializeL( aCmdParam, aFolderIds, aPropertyNames );
+ iIsNewSearch = EFalse;
+ StartL();
+ }
+
+// ==========================================================================
+// FUNCTION: DoNextSearchL
+// ==========================================================================
+void CContainerStoreSearchHandler::DoNextSearchL()
+ {
+ __LOG_ENTER_SUPPRESS( "DoNextSearch" )
+
+ TContainerId messageId = KContainerInvalidId;
+
+ if ( iSortResultSet->HasMoreNextL() )
+ {
+ messageId = iSortResultSet->NextL();
+ }
+ else
+ {
+ while ( SortNextFolderL() )
+ {
+ if ( iSortResultSet->HasMoreNextL() )
+ {
+ messageId = iSortResultSet->NextL();
+ break;
+ }
+ }
+ }
+
+ if( messageId != KContainerInvalidId )
+ {
+ TBool found = EFalse;
+
+ TRAP_IGNORE( found = SearchL( messageId ) );
+
+ if( found )
+ {
+ // Remove the properties that are not needed.
+ TPropertiesSerializer serializer( iPropertyBuf );
+ TBool moreProperties = serializer.First();
+ while( moreProperties )
+ {
+ TBool found = EFalse;
+ for( TInt i = 0; !found && (i < iPropertyNames.Count()); i++ )
+ {
+ found = (iPropertyNames[i]->Compare( serializer.Name() ) == 0);
+ } // end for
+ if( found )
+ {
+ moreProperties = serializer.Next();
+ }
+ else
+ {
+ moreProperties = serializer.RemovePropertyL();
+ } // end if
+ } // end while
+
+
+ iClient.MatchFound( messageId, iSortResultSet->FolderId(), iPropertyBuf );
+ } // end if
+
+ // Schedule next search (yield, in case higher priority active objects have something to do).
+ SetActive();
+ TRequestStatus* status = &iStatus;
+ User::RequestComplete( status, KErrNone );
+ }
+ else
+ {
+ // Done!
+ __LOG_WRITE_INFO( "Search complete" )
+ iClient.SearchComplete( KErrNone );
+ } // end if
+
+ } // end DoNextSearch
+
+// ==========================================================================
+// FUNCTION: RunL
+// ==========================================================================
+void CContainerStoreSearchHandler::RunL()
+ {
+ DoNextSearchL();
+ } // end RunL
+
+// ==========================================================================
+// FUNCTION: DoCancel
+// ==========================================================================
+void CContainerStoreSearchHandler::DoCancel()
+ {
+ // Nothing special to do.
+ } // end DoCancel
+
+// ==========================================================================
+// FUNCTION: InitializeL
+// ==========================================================================
+void CContainerStoreSearchHandler::InitializeL( TMsgStoreSearchCmdParams& aCmdParams,
+ RArray<TContainerId>& aFolderIds,
+ RPointerArray<HBufC8>& aPropertyNames )
+ {
+ iSearchParams = aCmdParams;
+
+ iFolderIds.Reset();
+ for( TInt i = 0 ; i < aFolderIds.Count() ; i++ )
+ {
+ iFolderIds.Append( aFolderIds[i] );
+ }
+
+ iPropertyNames.ResetAndDestroy();
+ for ( TInt i = 0 ; i < aPropertyNames.Count() ; i++ )
+ {
+ iPropertyNames.Append( aPropertyNames[i] );
+ }
+ aPropertyNames.Reset();
+
+ delete iSortResultSet;
+ iSortResultSet = NULL;
+ }
+
+// ==========================================================================
+// FUNCTION: SortNextFolderL
+// ==========================================================================
+TBool CContainerStoreSearchHandler::SortNextFolderL()
+ {
+ if ( ++iCurFolderIdIndex >= iFolderIds.Count() )
+ {
+ //no more folder to sort/search
+ return EFalse;
+ }
+
+ TMsgStoreSortCriteria sortCriteria;
+
+ sortCriteria.iFolderId = iFolderIds[ iCurFolderIdIndex ];
+ sortCriteria.iSortBy = iSearchParams.iSortBy;
+ sortCriteria.iSortOrder = iSearchParams.iSortOrder;
+ sortCriteria.iSecondarySortOrder = iSearchParams.iSecondarySortOrder;
+
+ delete iSortResultSet;
+ iSortResultSet = NULL;
+
+ iSortResultSet = iSortingTable.SortL( sortCriteria, EFalse );
+ //disable the automatic refresh
+ iSortResultSet->SetAutoRefresh( EFalse );
+ iSortResultSet->ToTopL();
+
+ return ETrue;
+ }
+
+// ==========================================================================
+// FUNCTION: SearchL
+// ==========================================================================
+TBool CContainerStoreSearchHandler::SearchL( TContainerId aMessageId )
+ {
+ __LOG_ENTER_SUPPRESS( "SearchL" )
+
+ TBool match = EFalse;
+ TBool alreadySearched = EFalse;
+
+ //check if we've already searched this message
+ if ( !iIsNewSearch )
+ {
+ alreadySearched = iSearchResultTable.GetMessageL( aMessageId, match );
+ __LOG_WRITE8_FORMAT2_DEBUG3( "Re-search: alreadySearch=%d, match=%d", alreadySearched, match )
+ }
+
+ //we need to get the properties if
+ // 1) the message has never been searched (!alreadySearched), or
+ // 2) the meeage has been searched and it matches the search result,
+ // case 2) is used to populate the iPropertyBuf to be used by the
+ // caller of this methos
+ if ( !alreadySearched || match )
+ {
+ //get the properties first
+ TContainerId parentId;
+ iContainerStore.FastFetchPropertiesL( aMessageId, EFalse, parentId, iPropertyBuf );
+ }
+
+ //search the To, Cc, Bcc, Subject if we haven't searched this item before
+ if ( !alreadySearched )
+ {
+ //get the "subject" and "from" the from fields
+ TPropertiesDeserializer propDeserializer( iPropertyBuf );
+
+ for ( TInt i = 0 ; i < iSearchStrings.Count() ; i++ )
+ {
+ TPtrC searchString = iSearchStrings[i]->Des();
+
+ TBool moreProperties = propDeserializer.First();
+
+ match = EFalse;
+
+ while( moreProperties && !match )
+ {
+ if( propDeserializer.Name().Compare( KMsgStorePropertyTo ) == 0 ||
+ propDeserializer.Name().Compare( KMsgStorePropertyCc ) == 0 ||
+ propDeserializer.Name().Compare( KMsgStorePropertyBcc ) == 0 ||
+ propDeserializer.Name().Compare( KMsgStorePropertyFrom ) == 0 )
+ {
+ TPropertiesDeserializer addrDeserializer( propDeserializer.Value() );
+
+ //search the display name
+ RBuf displayName;
+ CleanupClosePushL( displayName );
+ if ( addrDeserializer.Find( KMsgStorePropertyDisplayName ) )
+ {
+ TPtrC8ToRBuf16L( addrDeserializer.Value(), displayName );
+ }
+
+ match = displayName.MatchC( searchString ) >= 0;
+
+ if ( !match )
+ {
+ //search the email address
+ RBuf emailAddr;
+ CleanupClosePushL( emailAddr );
+ if ( addrDeserializer.Find( KMsgStorePropertyEmailAddress ) )
+ {
+ TPtrC8ToRBuf16L( addrDeserializer.Value(), emailAddr );
+ }
+
+ match = emailAddr.MatchC( searchString ) >= 0;
+
+ CleanupStack::PopAndDestroy( &emailAddr );
+ }
+ CleanupStack::PopAndDestroy( &displayName );
+ }
+ else if ( propDeserializer.Name().Compare( KMsgStorePropertySubject ) == 0 )
+ {
+ //search the subject
+ RBuf subject;
+ CleanupClosePushL( subject );
+
+ TPtrC8ToRBuf16L( propDeserializer.Value(), subject );
+
+ match = subject.MatchC( searchString ) >= 0;
+
+ CleanupStack::PopAndDestroy( &subject );
+ }
+
+ moreProperties = propDeserializer.Next();
+ }
+
+ if ( !match )
+ {
+ //Find the first child of the message because that where the content is stored
+ TBool isContentEncrypted;
+ TMsgStoreId firstChildPartId = iContainerStore.FirstChildL( aMessageId, isContentEncrypted );
+ //check if the first child part exists, if it does, than that is the body part
+ // this is how intellisync supports plan text body. The html body is sibling
+ // of the plain text body
+ TInt bodyPartId = KMsgStoreInvalidId;
+ TRAP_IGNORE( bodyPartId=iContainerStore.FirstChildL( firstChildPartId, isContentEncrypted ) );
+ if ( bodyPartId == KMsgStoreInvalidId )
+ {
+ //this is no children of firstChildPartId, set the bodyPart to firstChildPartId
+ bodyPartId = firstChildPartId;
+ }
+
+ TRAP_IGNORE( match = iContentManager.SearchContentL( bodyPartId, searchString, iSearchBuffer, isContentEncrypted ) );
+ }
+
+ if ( !match )
+ {
+ //the list of search strings are treated as "AND", so if there is any search string
+ // that does not match, than we can decide that this msg does NOT match.
+ // So, break out of the loop
+ break;
+ }
+ } //end of for loop
+
+ //add message to the already search table
+ iSearchResultTable.AddMessageL( aMessageId, match );
+ }
+
+ return match;
+ }
+
+// ==========================================================================
+// FUNCTION: CreateSearchPatternL
+// ==========================================================================
+void CContainerStoreSearchHandler::CreateSearchPatternL( RPointerArray<HBufC>& aOriginalSearchString,
+ RPointerArray<HBufC>& aSearchPatterns )
+ {
+ __LOG_ENTER_SUPPRESS("CreateSearchPatternL")
+
+ const TChar KStarChar('*');
+
+ aSearchPatterns.ResetAndDestroy();
+
+ for ( int i = 0 ; i < aOriginalSearchString.Count() ; i++ )
+ {
+ HBufC* searchString = aOriginalSearchString[i];
+
+ __LOG_BLOCK( TPtr searchStringPtr = searchString->Des(); )
+ __LOG_WRITE_FORMAT1_INFO( "search string =%S", &searchStringPtr );
+
+ HBufC* pattern = HBufC::NewL( searchString->Length() + 2 );
+ aSearchPatterns.Append( pattern );
+ TPtr seartStringPrt( pattern->Des() );
+
+ //we are using MatchC(), so we need to add * to the start and end of the search pattern
+ if ( searchString->Locate(KStarChar) != 0 )
+ {
+ //it does NOT start with "*", so add it
+ seartStringPrt.Append( KStarChar );
+ }
+ seartStringPrt.Append( *searchString );
+ if ( searchString->LocateReverse(KStarChar) != searchString->Length() - 1 )
+ {
+ //it does NOT start with "*", so add it
+ seartStringPrt.Append( KStarChar );
+ }
+ }
+ }
+
+// ==========================================================================
+// FUNCTION: SearchL
+// ==========================================================================
+void CContainerStoreSearchHandler::TPtrC8ToRBuf16L( const TPtrC8& aPtr8, RBuf& aBuf ) const
+ {
+ RBuf8 val8;
+ CleanupClosePushL( val8 );
+
+ val8.Create( aPtr8 );
+
+ const TUint16* valuePtr16 = reinterpret_cast<const TUint16*>( val8.Ptr() );
+ TPtrC16 val16( valuePtr16, val8.Length() / 2 );
+
+ aBuf.Create( val16.Length() );
+ aBuf.Copy( val16 );
+
+ CleanupStack::PopAndDestroy( &val8 );
+ }
+
+