ipsservices/ipssosplugin/src/ipsplgmsgiterator.cpp
changeset 0 8466d47a6819
child 29 6b8f3b30d0ec
child 51 d845db10c0d4
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ipsservices/ipssosplugin/src/ipsplgmsgiterator.cpp	Thu Dec 17 08:39:21 2009 +0200
@@ -0,0 +1,484 @@
+/*
+* 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:  Freestyle message iterator implementation for Symbian Message
+*                store
+*
+*/
+
+
+#include "emailtrace.h"
+#include "ipsplgheaders.h"
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+CIpsPlgMsgIterator* CIpsPlgMsgIterator::NewL(
+    CIpsPlgSosBasePlugin& aPlugin,
+    CMsvSession& aMsvSession,
+    const TFSMailMsgId& aMailboxId,
+    const TFSMailMsgId aFolderId,
+    const TFSMailDetails aDetails,
+    const RArray<TFSMailSortCriteria>& aSorting)
+    {
+    FUNC_LOG;
+    CIpsPlgMsgIterator* self = 
+        new( ELeave ) CIpsPlgMsgIterator( aPlugin, aMailboxId, aDetails, 
+            aSorting );
+    CleanupStack::PushL( self );
+    self->ConstructL( aMsvSession, aFolderId, aSorting );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+// ---------------------------------------------------------------------------
+// ---------------------------------------------------------------------------
+//
+CIpsPlgMsgIterator* CIpsPlgMsgIterator::NewL(
+    CIpsPlgSosBasePlugin& aPlugin,
+    CMsvEntry* aFolderEntry, 
+    const TFSMailMsgId& aMailboxId,
+    const TFSMailDetails aDetails,
+    const RArray<TFSMailSortCriteria>& aSorting)
+    {
+    FUNC_LOG;
+    CIpsPlgMsgIterator* self = 
+        new( ELeave ) CIpsPlgMsgIterator( aPlugin, aMailboxId, aDetails, 
+            aSorting );
+    CleanupStack::PushL( self );
+    self->ConstructL( aFolderEntry, aSorting );
+    CleanupStack::Pop( self );
+    return self;
+    }
+
+
+// ---------------------------------------------------------------------------
+// Basic destructor
+// ---------------------------------------------------------------------------
+//
+CIpsPlgMsgIterator::~CIpsPlgMsgIterator()
+    {
+    FUNC_LOG;
+    delete iFolderEntry;
+    delete iMsgMapper;
+    delete iMsgSortKey;
+    delete iMsgSwapper;
+    }
+
+// ---------------------------------------------------------------------------
+// Searches the message matching with aCurrentMessageId and requests the
+// chunk of messages following the matching message
+// ---------------------------------------------------------------------------
+//
+TBool CIpsPlgMsgIterator::NextL(
+    TFSMailMsgId aCurrentMessageId, 
+    TUint aCount, 
+    RPointerArray<CFSMailMessage>& aMessages)
+    {
+    FUNC_LOG;
+    TBool result = EFalse;
+    TInt baseIndex;
+    
+    // Messages are sorted always before reading the messages 
+    Sort();
+    
+    CMsvEntrySelection* messages = FilterMessagesL();
+    CleanupStack::PushL( messages );
+
+    if ( !aCurrentMessageId.IsNullId() )
+        {
+        baseIndex = messages->Find( aCurrentMessageId.Id() );
+        
+        // aCurrentMessageId is not included to the result set
+        if ( baseIndex != KErrNotFound )
+            {
+            baseIndex += 1;
+            }
+        }
+    else
+        {
+        // start from the beginning of the message list
+        baseIndex = 0;
+        }
+        
+    if ( ( baseIndex != KErrNotFound ) && 
+         ( baseIndex < messages->Count() ) )
+        {
+        result = NextL(baseIndex, messages, aCount, aMessages);
+        }
+
+    CleanupStack::PopAndDestroy(messages);
+    return result;
+    }
+
+// ---------------------------------------------------------------------------
+// Searches message matching with the search string and returns a chunk of
+// messages starting from the 1st matched message
+// ---------------------------------------------------------------------------
+//
+TBool CIpsPlgMsgIterator::NextL(
+    const TDesC&  aStartWith, 
+    TUint aCount, 
+    RPointerArray<CFSMailMessage>& aMessages)
+    {
+    FUNC_LOG;
+    TBool result = EFalse;
+    TInt status;
+    TInt baseIndex;
+    
+    // Messages are sorted always before reading the messages 
+    Sort();
+
+    CMsvEntrySelection* messages = FilterMessagesL();
+    CleanupStack::PushL( messages );
+
+    status = SearchL( messages, aStartWith, baseIndex );
+    
+    if ( status == KErrNone )
+        {
+        result = NextL(baseIndex, messages, aCount, aMessages);
+        }
+
+    CleanupStack::PopAndDestroy(messages);
+    return result;
+    }
+
+// ---------------------------------------------------------------------------
+// Like NextL() with similar parameters, the method searches the message 
+// matching with aCurrentMessageId and requests a chunk of messages preceding 
+// the matching message
+// ---------------------------------------------------------------------------
+//
+TBool CIpsPlgMsgIterator::PreviousL(
+    TFSMailMsgId aCurrentMessageId, 
+    TUint aCount, 
+    RPointerArray<CFSMailMessage>& aMessages)
+    {
+    FUNC_LOG;
+    TBool result = EFalse;
+    TInt baseIndex;
+    
+    // Messages are sorted always before reading the messages 
+    Sort();
+
+    CMsvEntrySelection* messages = FilterMessagesL();
+    CleanupStack::PushL(messages);
+
+    if ( !aCurrentMessageId.IsNullId() )
+        {
+        baseIndex = messages->Find(aCurrentMessageId.Id());
+        
+        // aCurrentMessageId is not included to the result set
+        if ( baseIndex != KErrNotFound )
+            {
+            baseIndex -= 1;
+            }
+        }
+    else
+        {
+        // check whether we should start from the end of 
+        // the message list in the case of a NULL ID
+        baseIndex = messages->Count() - 1;
+        }
+
+    // Actually, if the matching message is the first one, baseIndex is equal
+    // to -1 which is also the value of KErrNotFound. So, the condition could be
+    // simpler, but it would not inappropriate to trust that the numerical value 
+    // of the error code is known.
+    if ( ( baseIndex != KErrNotFound ) &&
+         ( baseIndex >= 0 ) )
+        {
+        result = PreviousL(baseIndex, messages, aCount, aMessages);
+        }
+
+    CleanupStack::PopAndDestroy(messages);
+    return result;
+    }
+
+// ---------------------------------------------------------------------------
+// Searches the first message matching with the search string and requests
+// a chunk of messages including the matching message and messages preceding 
+// it.
+// The return value tells currently only, if there are more messages, but it
+// is not checked whether they are deleted. It is probably more important
+// to return as fast as possible than check the remaining messages. The same
+// concerns PreviousL().
+// ---------------------------------------------------------------------------
+//
+TBool CIpsPlgMsgIterator::PreviousL(
+    const TDesC&  aStartWith, 
+    TUint aCount, 
+    RPointerArray<CFSMailMessage>& aMessages)
+    {
+    FUNC_LOG;
+    TBool result = EFalse;
+    TInt status;
+    TInt baseIndex;
+    
+    // Messages are sorted always before reading the messages 
+    Sort();
+
+    CMsvEntrySelection* messages = FilterMessagesL();
+    CleanupStack::PushL( messages );
+
+    status = SearchL( messages, aStartWith, baseIndex );
+    
+    if (  status == KErrNone ) 
+        {
+        result = PreviousL(baseIndex, messages, aCount, aMessages);
+        }
+
+    CleanupStack::PopAndDestroy(messages);
+    return result;
+    }
+
+// ---------------------------------------------------------------------------
+// Loops over the requested messages noticing the ends of the message array
+// ---------------------------------------------------------------------------
+//
+TBool CIpsPlgMsgIterator::NextL(
+    TInt aStart,
+    CMsvEntrySelection* aMessageEntries,
+    TUint aCount,
+    RPointerArray<CFSMailMessage>& aMessages)
+    {
+    FUNC_LOG;
+    TInt i = aStart;
+    TInt counter( 0 );
+    CFSMailMessage* fsMsg;
+        
+    while (( counter < aCount ) && ( i < aMessageEntries->Count() ) )
+        {
+        const TMsvEmailEntry& entry( 
+            iFolderEntry->ChildDataL( aMessageEntries->At(i) ) );
+        if ( ( EDisconnectedDeleteOperation != entry.DisconnectedOperation() ) &&
+        	(( entry.iMtm != KSenduiMtmImap4Uid )  || !entry.DeletedIMAP4Flag() ) &&
+        	 ( entry.iType == KUidMsvMessageEntry ) )
+            {
+            fsMsg = iMsgMapper->GetMailMessageL( iMailboxId, entry, 
+                iRequestedDetails );
+            aMessages.Append( fsMsg );
+            counter++;
+            }
+        i++;
+        }
+    
+    return ( i < aMessageEntries->Count() );
+    }
+
+// ---------------------------------------------------------------------------
+// Loops over the requested messages noticing the ends of the message array.
+// The implementation is somewhat more complex than the corresponding NextL()
+// because the messages are processed in the order they are inserted to the
+// result array.
+// ---------------------------------------------------------------------------
+//
+TBool CIpsPlgMsgIterator::PreviousL(
+    TInt aEnd,
+    CMsvEntrySelection* aMessageEntries,
+    TUint aCount,
+    RPointerArray<CFSMailMessage>& aMessages)
+    {
+    FUNC_LOG;
+    __ASSERT_DEBUG( ( aEnd < aMessageEntries->Count() ), 
+        User::Panic( KIpsPlgPanicCategory, EIpsPlgInvalidMessageIndex ) );
+     
+    TInt i = aEnd;
+    TInt counter( 0 );
+    CFSMailMessage* fsMsg; 
+    
+    while (( counter < aCount ) && ( i >= 0 ) )
+        {
+        const TMsvEmailEntry& entry( 
+            iFolderEntry->ChildDataL( aMessageEntries->At(i) ) );
+        if ( ( EDisconnectedDeleteOperation != entry.DisconnectedOperation() ) &&
+        	(( entry.iMtm != KSenduiMtmImap4Uid )  || !entry.DeletedIMAP4Flag() ) &&	
+   	 		 ( entry.iType == KUidMsvMessageEntry ) )
+            {
+            fsMsg = iMsgMapper->GetMailMessageL( iMailboxId, entry, 
+                iRequestedDetails );
+            aMessages.Insert( fsMsg, 0 );
+            counter++;
+            }
+        i--;
+        }
+    
+    return ( i > 0 );
+    }
+
+// ---------------------------------------------------------------------------
+// Constructor. Initializes the static data members.
+// ---------------------------------------------------------------------------
+//
+CIpsPlgMsgIterator::CIpsPlgMsgIterator( 
+    CIpsPlgSosBasePlugin& aPlugin,
+    const TFSMailMsgId& aMailboxId,
+    const TFSMailDetails aDetails,
+    const RArray<TFSMailSortCriteria>& aSorting )
+    : iPlugin( aPlugin ), iRequestedDetails( aDetails ), 
+      iSortingCriteria( aSorting ), iMailboxId( aMailboxId )
+    {
+    FUNC_LOG;
+    // none
+    }
+
+// ---------------------------------------------------------------------------
+// Second level constructor. Creates the data members to the heap.
+// Creates also the folder CMsvEntry.
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgMsgIterator::ConstructL(        
+    CMsvSession& aMsvSession,
+    const TFSMailMsgId aFolderId,
+    const RArray<TFSMailSortCriteria>& aSorting )
+    {
+    FUNC_LOG;
+    iFolderEntry  = aMsvSession.GetEntryL( aFolderId.Id() );
+    iMsgSortKey   = new (ELeave) TIpsPlgMsgKey( *iFolderEntry, aSorting );
+    iMsgSwapper   = new (ELeave) TIpsPlgMsgSwap( *iFolderEntry );
+    iSortingOn    = 
+        ( aSorting.Count() > 0 ) && ( aSorting[0].iField != EFSMailDontCare);
+    iMsgMapper    = CIpsPlgMsgMapper::NewL( aMsvSession, iPlugin );
+    iMsvSession   = &aMsvSession;
+    }
+    
+// ---------------------------------------------------------------------------
+// Second level constructor. Creates the data members to the heap.
+// Version which gets the folder CMsvEntry as a parameter.
+// ---------------------------------------------------------------------------
+//
+void CIpsPlgMsgIterator::ConstructL(        
+    CMsvEntry* aFolderEntry, 
+    const RArray<TFSMailSortCriteria>& aSorting )
+    {
+    FUNC_LOG;
+    iFolderEntry  = aFolderEntry;
+    iMsgSortKey   = new (ELeave) TIpsPlgMsgKey( *iFolderEntry, aSorting );
+    iMsgSwapper   = new (ELeave) TIpsPlgMsgSwap( *iFolderEntry );
+    iSortingOn    = 
+        ( aSorting.Count() > 0 ) && ( aSorting[0].iField != EFSMailDontCare);
+    iMsgMapper = CIpsPlgMsgMapper::NewL( aFolderEntry->Session(), iPlugin );
+    iMsvSession = NULL;
+    }
+    
+// ---------------------------------------------------------------------------
+// Sorting is based on the quick sort algorithm implemented in User module
+// ---------------------------------------------------------------------------
+
+void CIpsPlgMsgIterator::Sort()
+    {
+    FUNC_LOG;
+    if ( iSortingOn )
+        {
+        User::QuickSort( iFolderEntry->Count(), *iMsgSortKey, *iMsgSwapper );
+        }
+    }
+    
+// ---------------------------------------------------------------------------
+// Searches the first message matching the search string.
+// This function is supported only when the messages are sorted by the subject
+// or by the sender (or the receiver in Drafts/Outbox/Sent folders) as 
+// a primary sorting key. The fields to be compared is selected on the basis 
+// of the sorting key.
+// ---------------------------------------------------------------------------
+
+TInt CIpsPlgMsgIterator::SearchL( 
+    CMsvEntrySelection* aMessageEntries,
+    const TDesC& aStartWith,
+    TInt& aIndex )
+    {
+    FUNC_LOG;
+    TInt result( KErrNotFound );
+    TInt i;
+    TInt findStatus;
+    TInt offset;
+    TFSMailSortField primaryKey = EFSMailDontCare;
+    TPtrC subject;
+
+    // Check whether the search is supported
+    if ( iSortingCriteria.Count() > 0 )
+        {
+        primaryKey = iSortingCriteria[0].iField;
+        }
+    if ( !iSortingOn ||
+         ( ( primaryKey != EFSMailSortBySender ) &&
+           ( primaryKey != EFSMailSortBySubject ) ) )
+        {
+        result = KErrNotSupported;
+        }
+        
+    // Actual search        
+    i = 0;
+    while ( ( result == KErrNotFound ) && ( i < aMessageEntries->Count() ) )
+        {
+        const TMsvEntry& entry( 
+            iFolderEntry->ChildDataL( aMessageEntries->At(i) ) );
+
+        findStatus = KErrNotFound;
+
+        if ( primaryKey == EFSMailSortBySender )
+            {
+            findStatus = entry.iDetails.FindF( aStartWith );
+            }
+        if ( primaryKey == EFSMailSortBySubject )
+            {
+            // Strip the prefixes (Re:, Fwd: etc) from the subject before
+            // matching
+            offset = iMsgSortKey->FindSubjectStart( entry.iDescription );
+            subject.Set( 
+                entry.iDescription.Ptr() + offset, 
+                entry.iDescription.Length() - offset );
+            findStatus = subject.FindF( aStartWith );
+            }
+        
+        // Checks whether a matching message has been found
+        if ( findStatus == 0 ) 
+            {
+            result = KErrNone;
+            aIndex = i;
+            }
+
+        i++;
+        }
+        
+    return result;
+    }
+// ---------------------------------------------------------------------------
+// Filters messages in global folders (Drafts/Sent/Outbox) that belongs to
+// specified mailbox. When messages in inbox asked, returns selection from 
+// wanted mailbox.
+// ---------------------------------------------------------------------------
+CMsvEntrySelection* CIpsPlgMsgIterator::FilterMessagesL()
+	{
+    FUNC_LOG;
+	TMsvId serviceId;
+	TMsvEntry tEntry;
+	TMsvEntry mailboxServiceEntry;
+	CMsvEntrySelection* filteredEntries;
+	
+	if( iMsvSession && iFolderEntry->Entry().Parent() == KMsvLocalServiceIndexEntryIdValue )
+		{
+		User::LeaveIfError(
+			iMsvSession->GetEntry( iMailboxId.Id(), serviceId, tEntry ) );
+		User::LeaveIfError(
+		    iMsvSession->GetEntry( tEntry.iRelatedId, serviceId, mailboxServiceEntry ) );
+			
+		filteredEntries = iFolderEntry->ChildrenWithServiceL( serviceId );
+		}
+	else
+		{
+ 		filteredEntries = iFolderEntry->ChildrenWithServiceL( iMailboxId.Id() );
+		}
+	return filteredEntries;
+	}
+