emailservices/emailstore/message_store/server/src/ContainerStoreSearchHandler.cpp
changeset 0 8466d47a6819
child 8 e1b6206813b4
child 51 d845db10c0d4
--- /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 );
+    }
+
+