ipsservices/ipssosplugin/src/ipsplgsearch.cpp
changeset 0 8466d47a6819
child 1 12c456ceeff2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ipsservices/ipssosplugin/src/ipsplgsearch.cpp	Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,986 @@
+/*
+* Copyright (c) 2007 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: This file implements classes TMsgContainer, Search, Search, Search. 
+*
+*/
+
+
+#include "emailtrace.h"
+#include "ipsplgheaders.h"
+
+
+// To skip deleted folder
+_LIT( KIpsPlgDeleted, "Deleted" );
+
+// ======== CLASS TSEARCHPARAMS ======== 
+
+// ======== MEMBER FUNCTIONS ======== 
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::TSearchParams::operator==()
+// ---------------------------------------------------------------------------
+//
+TBool CIpsPlgSearch::TSearchParams::operator==( 
+    const TSearchParams& aParams ) const
+    {
+    FUNC_LOG;
+    // This variable indicates if the search is same as previous search or
+    // not. If the search is new, previous data can be reused.
+    TBool isNew = EFalse;
+    
+    // Search strings must have an exact match
+    TInt newCnt = aParams.iSearchStrings->Count();
+    TInt oldCnt = iSearchStrings ? iSearchStrings->Count() : KErrNotFound;
+    if ( newCnt == oldCnt )
+        {
+        while ( !isNew && --newCnt >= 0 )
+            {
+            while ( !isNew && --oldCnt >= 0 )
+                {
+                // Even if one of the items fails, the search is different.
+                if ( ( *aParams.iSearchStrings )[newCnt].Compare( 
+                    ( *iSearchStrings )[oldCnt] ) )
+                    {
+                    isNew = ETrue;
+                    }
+                }
+            }
+        }
+    else
+        {
+        // This search has different 
+        isNew = ETrue;
+        }
+    
+    // Search strings are the same than in previous round. If search
+    // folders are added, but not removed, then search can continue
+    // from last location.
+    if ( !isNew )
+        {
+        isNew = EFalse;
+        newCnt = aParams.iFolderIds.Count();
+        oldCnt = iFolderIds.Count();
+
+        // If folder count has been added, look for added folders.
+        // If there is folder removed, search has to be started again.
+        if ( newCnt >= oldCnt )
+            {
+            TInt hits = 0;
+            TBool found = EFalse;
+            
+            // All of the old folders must be found from the new folders.
+            for ( TInt old = 0; old < oldCnt; old++ )
+                {
+                found = EFalse;
+                
+                for ( TInt item = 0; !found && item < newCnt; item++ )
+                    {
+                    found = iFolderIds[old] == aParams.iFolderIds[item];
+                    hits += found;
+                    }
+                }    
+            
+            isNew = hits != oldCnt;                                        
+            }                                
+        }
+    // Test is about: "is the new search the same as previous?" 
+    // so if the result of the above analyze is "new search", in that 
+    // case we must return the answer: "no, search is not the same".
+    // Confusing huh?
+    return !isNew;
+    }
+    
+// ======== CLASS TMSGCONTAINER ======== 
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::TMsgContainer::TMsgContainer()
+// ---------------------------------------------------------------------------
+//
+CIpsPlgSearch::TMsgContainer::TMsgContainer( 
+    const TMsvId& aId, 
+    const TFSMailSortCriteria& aCriteria,
+    CMsvSession& aMsvSession )
+    :
+    iId( aId ),
+    iCriteria( aCriteria ),
+    iMsvSession( aMsvSession )
+    {
+    FUNC_LOG;
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::TMsgContainer::TMsgContainer()
+// ---------------------------------------------------------------------------
+//
+TBool CIpsPlgSearch::TMsgContainer::operator>( 
+    const TMsgContainer& aMsgContainer ) const
+    {
+    FUNC_LOG;
+    TBool result = EFalse;
+    
+    switch ( iCriteria.iField )
+        {
+    default:        
+    case EFSMailDontCare:
+        break;
+        
+    case EFSMailSortByDate:
+        result = Entry( iId ).iDate > Entry( aMsgContainer.Id() ).iDate;
+        break;
+
+    case EFSMailSortBySender:
+        {
+        HBufC* leftSender = NULL;
+        HBufC* rightSender = NULL;
+        
+        GetSenderStringsCC( 
+            iId, 
+            aMsgContainer.Id(),  
+            leftSender, 
+            rightSender );
+        
+        result = *leftSender > *rightSender;
+        CleanupStack::PopAndDestroy( 2, leftSender ); 
+        }
+        break;
+    
+    case EFSMailSortBySubject:
+        {
+        HBufC* leftSubject = NULL;
+        HBufC* rightSubject = NULL;
+        
+        GetSubjectStringsCC( 
+            iId, 
+            aMsgContainer.Id(), 
+            leftSubject, 
+            rightSubject );
+
+        result = *leftSubject > *rightSubject;
+        CleanupStack::PopAndDestroy( 2, leftSubject ); 
+        }
+        break;
+
+    case EFSMailSortByPriority:
+        result = Entry( iId ).Priority() > Entry( aMsgContainer.Id() ).Priority();        
+        break;
+    
+    case EFSMailSortByFlagStatus:
+        result = Entry( iId ).New() > Entry( aMsgContainer.Id() ).New();
+        break;
+    
+    case EFSMailSortByUnread:
+        result = Entry( iId ).Unread() > Entry( aMsgContainer.Id() ).Unread();
+        break;
+    
+    case EFSMailSortBySize:
+        result = Entry( iId ).iSize > Entry( aMsgContainer.Id() ).iSize;
+        break;
+    
+    case EFSMailSortByAttachment:
+        result = Entry( iId ).iDate > Entry( aMsgContainer.Id() ).iDate;        
+        break;
+        }
+           
+    return result;        
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::TMsgContainer::TMsgContainer()
+// ---------------------------------------------------------------------------
+//
+TBool CIpsPlgSearch::TMsgContainer::operator>=( 
+    const TMsgContainer& aMsgContainer ) const
+    {
+    FUNC_LOG;
+    TBool result = EFalse;
+    
+    switch ( iCriteria.iField )
+        {
+    default:        
+    case EFSMailDontCare:
+        break;
+        
+    case EFSMailSortByDate:
+        result = Entry( iId ).iDate >= Entry( aMsgContainer.Id() ).iDate;
+        break;
+        
+    case EFSMailSortBySender:
+        {
+        HBufC* leftSender = NULL;
+        HBufC* rightSender = NULL;
+        
+        GetSenderStringsCC( 
+            iId, 
+            aMsgContainer.Id(),  
+            leftSender, 
+            rightSender );
+        
+        result = *leftSender >= *rightSender;
+        CleanupStack::PopAndDestroy( 2, leftSender ); 
+        }
+        break;
+        
+    case EFSMailSortBySubject:
+        {
+        HBufC* leftSubject = NULL;
+        HBufC* rightSubject = NULL;
+        
+        GetSubjectStringsCC( 
+            iId, 
+            aMsgContainer.Id(), 
+            leftSubject, 
+            rightSubject );
+
+        result = *leftSubject >= *rightSubject;
+        CleanupStack::PopAndDestroy( 2, leftSubject ); 
+        }
+        break;
+            
+    case EFSMailSortByPriority:
+        result = Entry( iId ).Priority() >= Entry( aMsgContainer.Id() ).Priority();        
+        break;
+    
+    case EFSMailSortByFlagStatus:
+        result = Entry( iId ).New() >= Entry( aMsgContainer.Id() ).New();
+        break;
+    
+    case EFSMailSortByUnread:
+        result = Entry( iId ).Unread() >= Entry( aMsgContainer.Id() ).Unread();
+        break;
+    
+    case EFSMailSortBySize:
+        result = Entry( iId ).iSize >= Entry( aMsgContainer.Id() ).iSize;
+        break;
+    
+    case EFSMailSortByAttachment:
+        result = Entry( iId ).iDate >= Entry( aMsgContainer.Id() ).iDate;        
+        break;
+        }
+        
+    return result;        
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::TMsgContainer::TMsgContainer()
+// ---------------------------------------------------------------------------
+//
+TBool CIpsPlgSearch::TMsgContainer::operator<=( 
+    const TMsgContainer& aMsgContainer ) const
+    {
+    FUNC_LOG;
+    TBool result = EFalse;
+    
+    switch ( iCriteria.iField )
+        {
+    default:        
+    case EFSMailDontCare:
+        break;
+        
+    case EFSMailSortByDate:
+        result = Entry( iId ).iDate <= Entry( aMsgContainer.Id() ).iDate;
+        break;
+
+    case EFSMailSortBySender:
+        {
+        HBufC* leftSender = NULL;
+        HBufC* rightSender = NULL;
+        
+        GetSenderStringsCC( 
+            iId, 
+            aMsgContainer.Id(),  
+            leftSender, 
+            rightSender );
+        
+        result = *leftSender <= *rightSender;
+        CleanupStack::PopAndDestroy( 2, leftSender ); 
+        }
+        break;
+    
+    case EFSMailSortBySubject:
+        {
+        HBufC* leftSubject = NULL;
+        HBufC* rightSubject = NULL;
+        
+        GetSubjectStringsCC( 
+            iId, 
+            aMsgContainer.Id(), 
+            leftSubject, 
+            rightSubject );
+
+        result = *leftSubject <= *rightSubject;
+        CleanupStack::PopAndDestroy( 2, leftSubject ); 
+        }
+        break;
+
+    case EFSMailSortByPriority:
+        result = Entry( iId ).Priority() <= Entry( aMsgContainer.Id() ).Priority();        
+        break;
+    
+    case EFSMailSortByFlagStatus:
+        result = Entry( iId ).New() <= Entry( aMsgContainer.Id() ).New();
+        break;
+    
+    case EFSMailSortByUnread:
+        result = Entry( iId ).Unread() <= Entry( aMsgContainer.Id() ).Unread();
+        break;
+    
+    case EFSMailSortBySize:
+        result = Entry( iId ).iSize <= Entry( aMsgContainer.Id() ).iSize;
+        break;
+    
+    case EFSMailSortByAttachment:
+        result = Entry( iId ).iDate <= Entry( aMsgContainer.Id() ).iDate;        
+        break;
+        }
+        
+    return result;        
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::TMsgContainer::GetSenderStringsCC()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSearch::TMsgContainer::GetSenderStringsCC( 
+    const TMsvId aLeft, 
+    const TMsvId aRight,
+    HBufC*& aLeftSender,
+    HBufC*& aRightSender ) const
+    {
+    FUNC_LOG;
+    TMsvEntry entry = Entry( aLeft );
+    aLeftSender = entry.iDetails.Alloc();
+    TRAP_IGNORE( CleanupStack::PushL( aLeftSender ) );
+    
+    entry = Entry( aRight );
+    aRightSender = entry.iDetails.Alloc();
+    TRAP_IGNORE( CleanupStack::PushL( aRightSender ) );
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::TMsgContainer::GetSubjectStringsCC()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSearch::TMsgContainer::GetSubjectStringsCC( 
+    const TMsvId aLeft, 
+    const TMsvId aRight,
+    HBufC*& aLeftSubject,
+    HBufC*& aRightSubject ) const
+    {
+    FUNC_LOG;
+    TMsvEntry entry = Entry( aLeft );
+    aLeftSubject = entry.iDescription.Alloc();
+    TRAP_IGNORE( CleanupStack::PushL( aLeftSubject ) );
+    
+    entry = Entry( aRight );
+    aRightSubject = entry.iDescription.Alloc();
+    TRAP_IGNORE( CleanupStack::PushL( aRightSubject ) );
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::TMsgContainer::TMsgContainer()
+// ---------------------------------------------------------------------------
+//
+CIpsPlgSearch::TMsgContainer& CIpsPlgSearch::TMsgContainer::operator=( 
+    const TMsgContainer& aMsgContainer )
+    {
+    FUNC_LOG;
+    iId = aMsgContainer.Id();
+    return *this;
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::TMsgContainer::Entry()
+// ---------------------------------------------------------------------------
+//
+TMsvEntry CIpsPlgSearch::TMsgContainer::Entry( const TMsvId aId ) const
+    {
+    FUNC_LOG;
+    return CIpsPlgSearch::TMsgContainer::Entry( iMsvSession, aId );
+    }
+    
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::TMsgContainer::Entry()
+// ---------------------------------------------------------------------------
+//
+TMsvEntry CIpsPlgSearch::TMsgContainer::Entry( 
+    CMsvSession& aMsvSession, 
+    const TMsvId aId )
+    {
+    FUNC_LOG;
+    TMsvId service;
+    TMsvEntry entry;
+    aMsvSession.GetEntry( aId, service, entry );
+    return entry;
+    }
+
+// ======== CLASS CIPSPLGSEARCH ========     
+    
+// ======== CONSTRUCTORS & DESTRUCTOR ========
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::NewL()
+// ---------------------------------------------------------------------------
+//
+CIpsPlgSearch* CIpsPlgSearch::NewL(
+    CMsvSession& aMsvSession,
+    CIpsPlgSosBasePlugin& aPlugin )
+    {
+    FUNC_LOG;
+    CIpsPlgSearch* self = CIpsPlgSearch::NewLC( aMsvSession, aPlugin );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::NewLC()
+// ---------------------------------------------------------------------------
+//
+CIpsPlgSearch* CIpsPlgSearch::NewLC(
+    CMsvSession& aMsvSession,
+    CIpsPlgSosBasePlugin& aPlugin )
+    {
+    FUNC_LOG;
+    CIpsPlgSearch* self = new( ELeave ) CIpsPlgSearch( aMsvSession, aPlugin );
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::~CIpsPlgSearch()
+// ---------------------------------------------------------------------------
+//
+CIpsPlgSearch::~CIpsPlgSearch()
+    {
+    FUNC_LOG;
+    // Any running search operations must be cancelled before deletion.
+    if ( iOperation )
+        {
+        iOperation->Cancel();
+        }
+        
+    delete iOperation;
+    iOperation = NULL;
+    
+    iObserver = NULL;
+    
+    delete iActiveEntry;
+    iActiveEntry = NULL;
+    
+    delete iMapper;
+    iMapper = NULL;
+    
+    iCache.Reset();
+    iEmailMessages.Reset();
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::CIpsPlgSearch()
+// ---------------------------------------------------------------------------
+//
+CIpsPlgSearch::CIpsPlgSearch(
+    CMsvSession& aMsvSession,
+    CIpsPlgSosBasePlugin& aPlugin )
+    :
+    iMsvSession( aMsvSession ),
+    iActiveEntry( NULL ),
+    iOperation( NULL ),
+    iObserver( NULL ),
+    iPlugin( aPlugin ),
+    iMapper( NULL )
+    {
+    FUNC_LOG;
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::ConstructL()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSearch::ConstructL()
+    {
+    FUNC_LOG;
+    iMapper = CIpsPlgMsgMapper::NewL( iMsvSession, iPlugin );
+    iActiveEntry = iMsvSession.GetEntryL( KMsvLocalServiceIndexEntryId );
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::Cancel()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSearch::Cancel()
+    {
+    FUNC_LOG;
+    // Cancel the operation before deleting.
+    if ( iOperation )
+        {
+        iOperation->Cancel();
+        }
+        
+    // All checks are based on pointer value, so make it NULL
+    delete iOperation;
+    iOperation = NULL;
+    
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::ClearCache()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSearch::ClearCache()
+    {
+    FUNC_LOG;
+    iCache.Reset();
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::GetFoldersL()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSearch::GetFoldersL( TSearchParams& aParams )
+    {
+    FUNC_LOG;
+    iActiveEntry->SetEntryL( aParams.iMailbox.Id() );
+    
+    if ( iActiveEntry->Entry().iMtm == KSenduiMtmPop3Uid )
+        {
+        aParams.iFolderIds.AppendL( 
+            TFSMailMsgId( iPlugin.PluginId(), aParams.iMailbox.Id() ) );
+        return;
+        }
+    const TInt folders = iActiveEntry->Count();
+    for ( TInt folder = 0; folder < folders; folder++ )
+        {
+        const TMsvEntry& entry = ( *iActiveEntry )[folder];
+        if ( entry.iType == KUidMsvFolderEntry &&
+             entry.iDescription.Compare( KIpsPlgDeleted ) )
+            {
+            GetFoldersL( entry.Id(), aParams.iFolderIds );
+            }
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::GetFoldersL()
+// ---------------------------------------------------------------------------
+void CIpsPlgSearch::GetFoldersL( 
+    const TMsvId aFolderId, 
+    RArray<TFSMailMsgId>& aFolders )
+    {
+    FUNC_LOG;
+    // Add this folder to array.
+    aFolders.AppendL( TFSMailMsgId( iPlugin.PluginId(), aFolderId ) );
+    
+    CMsvEntry* entry = iMsvSession.GetEntryL( aFolderId );
+    CleanupStack::PushL( entry );
+
+    const TInt count = entry->Count();
+    for ( TInt loop = 0; loop < count; loop++ )
+        {
+        const TMsvEntry& tEntry = (*entry)[loop];
+        if ( tEntry.iType == KUidMsvFolderEntry )
+            {
+            GetFoldersL( tEntry.Id(), aFolders );
+            }        
+        }
+
+    CleanupStack::PopAndDestroy( entry );
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::SearchL()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSearch::SearchL( 
+    const TFSMailMsgId& aMailBoxId,
+    const RArray<TFSMailMsgId>& aFolderIds,
+    const RPointerArray<TDesC>& aSearchStrings,
+    const TFSMailSortCriteria& aSortCriteria,
+    MFSMailBoxSearchObserver& aSearchObserver )
+    {
+    FUNC_LOG;
+    if ( iOperation )
+        {
+        // if there is ongoing search, it must be canceled
+        // according to UI specs
+        Cancel();
+        }
+
+    // Create search parameters group for init.
+    TSearchParams newSearch( 
+        aSearchStrings, 
+        aMailBoxId, 
+        aFolderIds,  
+        aSortCriteria );
+
+    // If folder list is empty, whole mailbox needs to be searched.
+    if ( !newSearch.iFolderIds.Count() )
+        {
+        GetFoldersL( newSearch );
+        }
+    
+    // If search strings are same than last time, then sorting is same.
+    // Clear previous cache and continue.
+    if ( iPreviousSearch == newSearch )
+        {
+        // At this point, append new folders to list.
+        iCurrentSearch += newSearch;
+        iPreviousSearch += newSearch;
+        }
+    else
+        {
+        ClearCache();
+        iCurrentSearch = newSearch;
+        iPreviousSearch = newSearch;
+        }
+            
+    iCurrentMessage.SetPluginId( aMailBoxId.PluginId() );
+    iObserver = &aSearchObserver;
+        
+    iOperation = CIpsPlgSearchOp::NewL( *this );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIpsPlgSearch.
+// CIpsPlgSearch::Session()
+// ---------------------------------------------------------------------------
+//
+CMsvSession& CIpsPlgSearch::Session()
+    {
+    FUNC_LOG;
+    return iMsvSession;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIpsPlgSearch.
+// CIpsPlgSearch::MailboxId()
+// ---------------------------------------------------------------------------
+//
+TMsvId CIpsPlgSearch::MailboxId()
+    {
+    FUNC_LOG;
+    return iCurrentSearch.iMailbox.Id();
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIpsPlgSearch.
+// CIpsPlgSearch::FolderId()
+// ---------------------------------------------------------------------------
+//
+TMsvId CIpsPlgSearch::FolderId()
+    {
+    FUNC_LOG;
+    return iActiveEntry->EntryId();
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIpsPlgSearch.
+// CIpsPlgSearch::CurrentMessage()
+// ---------------------------------------------------------------------------
+//
+const TFSMailMsgId& CIpsPlgSearch::CurrentMessage() const
+    {
+    FUNC_LOG;
+    return iCurrentMessage;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIpsPlgSearch.
+// CIpsPlgSearch::SearchStringsL()
+// ---------------------------------------------------------------------------
+//
+const CDesC16Array& CIpsPlgSearch::SearchStringsL()
+    {
+    FUNC_LOG;
+    return *iCurrentSearch.iSearchStrings;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIpsPlgSearch.
+// CIpsPlgSearch::MatchFound()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSearch::MatchFoundL()
+    {
+    FUNC_LOG;
+    // Set current email as an entry and create messages for both cache and
+    // observer, for now like this.
+    iActiveEntry->SetEntryL( iCurrentMessage.Id() );                
+    iCache.AppendL( SendToObserverL() );
+    }
+    
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::SendToObserverL()
+// ---------------------------------------------------------------------------
+//
+TFSMailMsgId CIpsPlgSearch::SendToObserverL()
+    {
+    FUNC_LOG;
+    CFSMailMessage* obsMail = iMapper->GetMailMessageL( *iActiveEntry );
+    CleanupStack::PushL( obsMail );    
+    
+    iObserver->MatchFoundL( obsMail );    
+    
+    CleanupStack::Pop( obsMail );
+    return obsMail->GetMessageId();        
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIpsPlgSearch.
+// CIpsPlgSearch::SearchFinished()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSearch::SearchFinishedL()
+    {
+    FUNC_LOG;
+    iObserver->SearchCompletedL();
+    
+    delete iOperation;
+    iOperation = NULL;
+    }
+    
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::NextItem()
+// ---------------------------------------------------------------------------
+//
+CIpsPlgSearch::TMsgContainer& CIpsPlgSearch::NextItem()
+    {
+    FUNC_LOG;
+    if ( iCurrentSearch.iSortCriteria.iOrder == EFSMailAscending )
+        {
+        return iEmailMessages[0];
+        }
+    else
+        {
+        return iEmailMessages[iEmailMessages.Count() - 1];
+        }
+    }
+   
+// ---------------------------------------------------------------------------
+// From class MIpsPlgSearch.
+// CIpsPlgSearch::NextMessageL()
+// ---------------------------------------------------------------------------
+//
+CImEmailMessage* CIpsPlgSearch::NextMessageL()
+    {
+    FUNC_LOG;
+    // Items, that are already in cache, are not needed to be searched.
+    while ( iEmailMessages.Count() )
+        {
+        TFSMailMsgId id(
+            iCurrentSearch.iMailbox.PluginId().iUid, NextItem().Id() );
+            
+        TInt index=KErrNotFound;
+        TInt count = iCache.Count();
+        
+        for( TInt i=0; i<count; i++ )
+            {
+            if ( iCache[i].Id() == id.Id() )
+                {
+                index = i;
+                }
+            }
+        
+        if ( index > KErrNotFound )
+            {
+            iActiveEntry->SetEntryL( id.Id() );
+            
+            if( iCurrentSearch.iSortCriteria.iOrder == EFSMailAscending )
+            	{
+                iEmailMessages.Remove( 0 );
+            	}
+            else
+            	{
+            	iEmailMessages.Remove( iEmailMessages.Count()-1 );
+            	}            
+            SendToObserverL();
+            }
+        else
+            {
+            break;
+            }
+        }
+
+    // Return next available message.        
+    if ( iEmailMessages.Count() )
+        {
+        iCurrentMessage.SetId( NextItem().Id() );
+        
+        if( iCurrentSearch.iSortCriteria.iOrder == EFSMailAscending )
+        	{
+            iEmailMessages.Remove( 0 );
+        	}
+        else
+        	{
+        	iEmailMessages.Remove( iEmailMessages.Count()-1 );
+        	}
+        iActiveEntry->SetEntryL( iCurrentMessage.Id() );
+        return CImEmailMessage::NewL( *iActiveEntry );
+        }
+    else
+        {
+        // Empty, return Null index, so the search can be finished.
+        return NULL;
+        }
+    }    
+    
+// ---------------------------------------------------------------------------
+// From class MIpsPlgSearch.
+// CIpsPlgSearch::MessageHeaderL()
+// ---------------------------------------------------------------------------
+//
+CImHeader* CIpsPlgSearch::MessageHeaderL()
+    {
+    FUNC_LOG;
+    CImHeader* header = NULL;
+    CMsvStore* store = iActiveEntry->EditStoreL();
+    CleanupStack::PushL( store );    
+    
+    if ( store->IsPresentL( KUidMsgFileIMailHeader ) )
+        {        
+        header = CImHeader::NewLC();
+        header->RestoreL( *store );
+        CleanupStack::Pop( header );
+        }
+        
+    CleanupStack::PopAndDestroy( store );        
+    return header;
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIpsPlgSearch.
+// CIpsPlgSearch::GetSubjectL()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSearch::GetSubjectL( RBuf& aSubject )
+    {
+    FUNC_LOG;
+    TMsvEntry email = iActiveEntry->Entry();
+    aSubject.CreateL( email.iDescription );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIpsPlgSearch.
+// CIpsPlgSearch::GetSenderL()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSearch::GetSenderL( RBuf& aSubject )
+    {
+    FUNC_LOG;
+    TMsvEntry email = iActiveEntry->Entry();
+    aSubject.CreateL( email.iDetails );
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIpsPlgSearch.
+// CIpsPlgSearch::Sort()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSearch::Sort()
+    {
+    FUNC_LOG;
+    // Here we use quick sort algorithm
+    QuickSort( iEmailMessages, 0, iEmailMessages.Count() - 1 );
+    }
+
+// ---------------------------------------------------------------------------
+// CIpsPlgSearch::QuickSort()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSearch::QuickSort( 
+    RArray<TMsgContainer>& aMessages, 
+    TInt aLeft, 
+    TInt aRight )
+    {
+    FUNC_LOG;
+    if( aMessages.Count() <= 1 )
+        {
+        return;
+        }
+    TInt leftHold = aLeft;
+    TInt rightHold = aRight;
+    TMsgContainer pivot = aMessages[aLeft];
+
+    while ( aLeft < aRight )
+        {
+        while ( ( aMessages[aRight] >= pivot ) && ( aLeft < aRight ) )
+            {            
+            aRight--;
+            }
+            
+        if (aLeft != aRight)
+            {
+            aMessages[aLeft] = aMessages[aRight];
+            aLeft++;
+            }
+
+        while ( ( aMessages[aLeft] <= pivot ) && ( aLeft < aRight ) )
+            {            
+            aLeft++;
+            }
+
+        if ( aLeft != aRight )
+            {
+            aMessages[aRight] = aMessages[aLeft];
+            aRight--;
+            }
+        }
+
+    aMessages[aLeft] = pivot;
+    
+    TInt pivotIndex = aLeft;
+    aLeft = leftHold;
+    aRight = rightHold;
+    if ( aLeft < pivotIndex )
+        {        
+        QuickSort( aMessages, aLeft, pivotIndex-1);
+        }
+    
+    if ( aRight > pivotIndex )
+        {        
+        QuickSort( aMessages, pivotIndex+1, aRight);
+        }
+    }
+
+// ---------------------------------------------------------------------------
+// From class MIpsPlgSearch.
+// CIpsPlgSearch::CollectMessagesL()
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgSearch::CollectMessagesL()
+    {
+    FUNC_LOG;
+    // Lets make a huge list of message id's. 
+    iEmailMessages.Reset();    
+    
+    const TInt folders = iCurrentSearch.iFolderIds.Count();
+    for ( TInt folder = 0; folder < folders; folder++ )
+        {
+        iActiveEntry->SetEntryL( iCurrentSearch.iFolderIds[folder].Id() );        
+        const TInt msgs = iActiveEntry->Count();
+        for ( TInt msg = 0; msg < msgs; msg++ )
+            {
+            const TMsvEntry& entry = ( *iActiveEntry )[msg];
+            if ( entry.iType == KUidMsvMessageEntry &&
+                 ( entry.iMtm.iUid == KSenduiMtmSmtpUidValue ||
+                   entry.iMtm.iUid == iPlugin.MtmId().iUid ) )
+                {
+                iEmailMessages.AppendL( TMsgContainer( 
+                    entry.Id(), iCurrentSearch.iSortCriteria, iMsvSession ) );
+                }        
+            }
+        }    
+    }
+    
+// End of File
+