ipsservices/ipssosplugin/src/ipsplgmsgiterator.cpp
changeset 0 8466d47a6819
child 29 6b8f3b30d0ec
child 51 d845db10c0d4
equal deleted inserted replaced
-1:000000000000 0:8466d47a6819
       
     1 /*
       
     2 * Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). 
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:  Freestyle message iterator implementation for Symbian Message
       
    15 *                store
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 #include "emailtrace.h"
       
    21 #include "ipsplgheaders.h"
       
    22 
       
    23 // ---------------------------------------------------------------------------
       
    24 // ---------------------------------------------------------------------------
       
    25 //
       
    26 CIpsPlgMsgIterator* CIpsPlgMsgIterator::NewL(
       
    27     CIpsPlgSosBasePlugin& aPlugin,
       
    28     CMsvSession& aMsvSession,
       
    29     const TFSMailMsgId& aMailboxId,
       
    30     const TFSMailMsgId aFolderId,
       
    31     const TFSMailDetails aDetails,
       
    32     const RArray<TFSMailSortCriteria>& aSorting)
       
    33     {
       
    34     FUNC_LOG;
       
    35     CIpsPlgMsgIterator* self = 
       
    36         new( ELeave ) CIpsPlgMsgIterator( aPlugin, aMailboxId, aDetails, 
       
    37             aSorting );
       
    38     CleanupStack::PushL( self );
       
    39     self->ConstructL( aMsvSession, aFolderId, aSorting );
       
    40     CleanupStack::Pop( self );
       
    41     return self;
       
    42     }
       
    43 
       
    44 // ---------------------------------------------------------------------------
       
    45 // ---------------------------------------------------------------------------
       
    46 //
       
    47 CIpsPlgMsgIterator* CIpsPlgMsgIterator::NewL(
       
    48     CIpsPlgSosBasePlugin& aPlugin,
       
    49     CMsvEntry* aFolderEntry, 
       
    50     const TFSMailMsgId& aMailboxId,
       
    51     const TFSMailDetails aDetails,
       
    52     const RArray<TFSMailSortCriteria>& aSorting)
       
    53     {
       
    54     FUNC_LOG;
       
    55     CIpsPlgMsgIterator* self = 
       
    56         new( ELeave ) CIpsPlgMsgIterator( aPlugin, aMailboxId, aDetails, 
       
    57             aSorting );
       
    58     CleanupStack::PushL( self );
       
    59     self->ConstructL( aFolderEntry, aSorting );
       
    60     CleanupStack::Pop( self );
       
    61     return self;
       
    62     }
       
    63 
       
    64 
       
    65 // ---------------------------------------------------------------------------
       
    66 // Basic destructor
       
    67 // ---------------------------------------------------------------------------
       
    68 //
       
    69 CIpsPlgMsgIterator::~CIpsPlgMsgIterator()
       
    70     {
       
    71     FUNC_LOG;
       
    72     delete iFolderEntry;
       
    73     delete iMsgMapper;
       
    74     delete iMsgSortKey;
       
    75     delete iMsgSwapper;
       
    76     }
       
    77 
       
    78 // ---------------------------------------------------------------------------
       
    79 // Searches the message matching with aCurrentMessageId and requests the
       
    80 // chunk of messages following the matching message
       
    81 // ---------------------------------------------------------------------------
       
    82 //
       
    83 TBool CIpsPlgMsgIterator::NextL(
       
    84     TFSMailMsgId aCurrentMessageId, 
       
    85     TUint aCount, 
       
    86     RPointerArray<CFSMailMessage>& aMessages)
       
    87     {
       
    88     FUNC_LOG;
       
    89     TBool result = EFalse;
       
    90     TInt baseIndex;
       
    91     
       
    92     // Messages are sorted always before reading the messages 
       
    93     Sort();
       
    94     
       
    95     CMsvEntrySelection* messages = FilterMessagesL();
       
    96     CleanupStack::PushL( messages );
       
    97 
       
    98     if ( !aCurrentMessageId.IsNullId() )
       
    99         {
       
   100         baseIndex = messages->Find( aCurrentMessageId.Id() );
       
   101         
       
   102         // aCurrentMessageId is not included to the result set
       
   103         if ( baseIndex != KErrNotFound )
       
   104             {
       
   105             baseIndex += 1;
       
   106             }
       
   107         }
       
   108     else
       
   109         {
       
   110         // start from the beginning of the message list
       
   111         baseIndex = 0;
       
   112         }
       
   113         
       
   114     if ( ( baseIndex != KErrNotFound ) && 
       
   115          ( baseIndex < messages->Count() ) )
       
   116         {
       
   117         result = NextL(baseIndex, messages, aCount, aMessages);
       
   118         }
       
   119 
       
   120     CleanupStack::PopAndDestroy(messages);
       
   121     return result;
       
   122     }
       
   123 
       
   124 // ---------------------------------------------------------------------------
       
   125 // Searches message matching with the search string and returns a chunk of
       
   126 // messages starting from the 1st matched message
       
   127 // ---------------------------------------------------------------------------
       
   128 //
       
   129 TBool CIpsPlgMsgIterator::NextL(
       
   130     const TDesC&  aStartWith, 
       
   131     TUint aCount, 
       
   132     RPointerArray<CFSMailMessage>& aMessages)
       
   133     {
       
   134     FUNC_LOG;
       
   135     TBool result = EFalse;
       
   136     TInt status;
       
   137     TInt baseIndex;
       
   138     
       
   139     // Messages are sorted always before reading the messages 
       
   140     Sort();
       
   141 
       
   142     CMsvEntrySelection* messages = FilterMessagesL();
       
   143     CleanupStack::PushL( messages );
       
   144 
       
   145     status = SearchL( messages, aStartWith, baseIndex );
       
   146     
       
   147     if ( status == KErrNone )
       
   148         {
       
   149         result = NextL(baseIndex, messages, aCount, aMessages);
       
   150         }
       
   151 
       
   152     CleanupStack::PopAndDestroy(messages);
       
   153     return result;
       
   154     }
       
   155 
       
   156 // ---------------------------------------------------------------------------
       
   157 // Like NextL() with similar parameters, the method searches the message 
       
   158 // matching with aCurrentMessageId and requests a chunk of messages preceding 
       
   159 // the matching message
       
   160 // ---------------------------------------------------------------------------
       
   161 //
       
   162 TBool CIpsPlgMsgIterator::PreviousL(
       
   163     TFSMailMsgId aCurrentMessageId, 
       
   164     TUint aCount, 
       
   165     RPointerArray<CFSMailMessage>& aMessages)
       
   166     {
       
   167     FUNC_LOG;
       
   168     TBool result = EFalse;
       
   169     TInt baseIndex;
       
   170     
       
   171     // Messages are sorted always before reading the messages 
       
   172     Sort();
       
   173 
       
   174     CMsvEntrySelection* messages = FilterMessagesL();
       
   175     CleanupStack::PushL(messages);
       
   176 
       
   177     if ( !aCurrentMessageId.IsNullId() )
       
   178         {
       
   179         baseIndex = messages->Find(aCurrentMessageId.Id());
       
   180         
       
   181         // aCurrentMessageId is not included to the result set
       
   182         if ( baseIndex != KErrNotFound )
       
   183             {
       
   184             baseIndex -= 1;
       
   185             }
       
   186         }
       
   187     else
       
   188         {
       
   189         // check whether we should start from the end of 
       
   190         // the message list in the case of a NULL ID
       
   191         baseIndex = messages->Count() - 1;
       
   192         }
       
   193 
       
   194     // Actually, if the matching message is the first one, baseIndex is equal
       
   195     // to -1 which is also the value of KErrNotFound. So, the condition could be
       
   196     // simpler, but it would not inappropriate to trust that the numerical value 
       
   197     // of the error code is known.
       
   198     if ( ( baseIndex != KErrNotFound ) &&
       
   199          ( baseIndex >= 0 ) )
       
   200         {
       
   201         result = PreviousL(baseIndex, messages, aCount, aMessages);
       
   202         }
       
   203 
       
   204     CleanupStack::PopAndDestroy(messages);
       
   205     return result;
       
   206     }
       
   207 
       
   208 // ---------------------------------------------------------------------------
       
   209 // Searches the first message matching with the search string and requests
       
   210 // a chunk of messages including the matching message and messages preceding 
       
   211 // it.
       
   212 // The return value tells currently only, if there are more messages, but it
       
   213 // is not checked whether they are deleted. It is probably more important
       
   214 // to return as fast as possible than check the remaining messages. The same
       
   215 // concerns PreviousL().
       
   216 // ---------------------------------------------------------------------------
       
   217 //
       
   218 TBool CIpsPlgMsgIterator::PreviousL(
       
   219     const TDesC&  aStartWith, 
       
   220     TUint aCount, 
       
   221     RPointerArray<CFSMailMessage>& aMessages)
       
   222     {
       
   223     FUNC_LOG;
       
   224     TBool result = EFalse;
       
   225     TInt status;
       
   226     TInt baseIndex;
       
   227     
       
   228     // Messages are sorted always before reading the messages 
       
   229     Sort();
       
   230 
       
   231     CMsvEntrySelection* messages = FilterMessagesL();
       
   232     CleanupStack::PushL( messages );
       
   233 
       
   234     status = SearchL( messages, aStartWith, baseIndex );
       
   235     
       
   236     if (  status == KErrNone ) 
       
   237         {
       
   238         result = PreviousL(baseIndex, messages, aCount, aMessages);
       
   239         }
       
   240 
       
   241     CleanupStack::PopAndDestroy(messages);
       
   242     return result;
       
   243     }
       
   244 
       
   245 // ---------------------------------------------------------------------------
       
   246 // Loops over the requested messages noticing the ends of the message array
       
   247 // ---------------------------------------------------------------------------
       
   248 //
       
   249 TBool CIpsPlgMsgIterator::NextL(
       
   250     TInt aStart,
       
   251     CMsvEntrySelection* aMessageEntries,
       
   252     TUint aCount,
       
   253     RPointerArray<CFSMailMessage>& aMessages)
       
   254     {
       
   255     FUNC_LOG;
       
   256     TInt i = aStart;
       
   257     TInt counter( 0 );
       
   258     CFSMailMessage* fsMsg;
       
   259         
       
   260     while (( counter < aCount ) && ( i < aMessageEntries->Count() ) )
       
   261         {
       
   262         const TMsvEmailEntry& entry( 
       
   263             iFolderEntry->ChildDataL( aMessageEntries->At(i) ) );
       
   264         if ( ( EDisconnectedDeleteOperation != entry.DisconnectedOperation() ) &&
       
   265         	(( entry.iMtm != KSenduiMtmImap4Uid )  || !entry.DeletedIMAP4Flag() ) &&
       
   266         	 ( entry.iType == KUidMsvMessageEntry ) )
       
   267             {
       
   268             fsMsg = iMsgMapper->GetMailMessageL( iMailboxId, entry, 
       
   269                 iRequestedDetails );
       
   270             aMessages.Append( fsMsg );
       
   271             counter++;
       
   272             }
       
   273         i++;
       
   274         }
       
   275     
       
   276     return ( i < aMessageEntries->Count() );
       
   277     }
       
   278 
       
   279 // ---------------------------------------------------------------------------
       
   280 // Loops over the requested messages noticing the ends of the message array.
       
   281 // The implementation is somewhat more complex than the corresponding NextL()
       
   282 // because the messages are processed in the order they are inserted to the
       
   283 // result array.
       
   284 // ---------------------------------------------------------------------------
       
   285 //
       
   286 TBool CIpsPlgMsgIterator::PreviousL(
       
   287     TInt aEnd,
       
   288     CMsvEntrySelection* aMessageEntries,
       
   289     TUint aCount,
       
   290     RPointerArray<CFSMailMessage>& aMessages)
       
   291     {
       
   292     FUNC_LOG;
       
   293     __ASSERT_DEBUG( ( aEnd < aMessageEntries->Count() ), 
       
   294         User::Panic( KIpsPlgPanicCategory, EIpsPlgInvalidMessageIndex ) );
       
   295      
       
   296     TInt i = aEnd;
       
   297     TInt counter( 0 );
       
   298     CFSMailMessage* fsMsg; 
       
   299     
       
   300     while (( counter < aCount ) && ( i >= 0 ) )
       
   301         {
       
   302         const TMsvEmailEntry& entry( 
       
   303             iFolderEntry->ChildDataL( aMessageEntries->At(i) ) );
       
   304         if ( ( EDisconnectedDeleteOperation != entry.DisconnectedOperation() ) &&
       
   305         	(( entry.iMtm != KSenduiMtmImap4Uid )  || !entry.DeletedIMAP4Flag() ) &&	
       
   306    	 		 ( entry.iType == KUidMsvMessageEntry ) )
       
   307             {
       
   308             fsMsg = iMsgMapper->GetMailMessageL( iMailboxId, entry, 
       
   309                 iRequestedDetails );
       
   310             aMessages.Insert( fsMsg, 0 );
       
   311             counter++;
       
   312             }
       
   313         i--;
       
   314         }
       
   315     
       
   316     return ( i > 0 );
       
   317     }
       
   318 
       
   319 // ---------------------------------------------------------------------------
       
   320 // Constructor. Initializes the static data members.
       
   321 // ---------------------------------------------------------------------------
       
   322 //
       
   323 CIpsPlgMsgIterator::CIpsPlgMsgIterator( 
       
   324     CIpsPlgSosBasePlugin& aPlugin,
       
   325     const TFSMailMsgId& aMailboxId,
       
   326     const TFSMailDetails aDetails,
       
   327     const RArray<TFSMailSortCriteria>& aSorting )
       
   328     : iPlugin( aPlugin ), iRequestedDetails( aDetails ), 
       
   329       iSortingCriteria( aSorting ), iMailboxId( aMailboxId )
       
   330     {
       
   331     FUNC_LOG;
       
   332     // none
       
   333     }
       
   334 
       
   335 // ---------------------------------------------------------------------------
       
   336 // Second level constructor. Creates the data members to the heap.
       
   337 // Creates also the folder CMsvEntry.
       
   338 // ---------------------------------------------------------------------------
       
   339 //
       
   340 void CIpsPlgMsgIterator::ConstructL(        
       
   341     CMsvSession& aMsvSession,
       
   342     const TFSMailMsgId aFolderId,
       
   343     const RArray<TFSMailSortCriteria>& aSorting )
       
   344     {
       
   345     FUNC_LOG;
       
   346     iFolderEntry  = aMsvSession.GetEntryL( aFolderId.Id() );
       
   347     iMsgSortKey   = new (ELeave) TIpsPlgMsgKey( *iFolderEntry, aSorting );
       
   348     iMsgSwapper   = new (ELeave) TIpsPlgMsgSwap( *iFolderEntry );
       
   349     iSortingOn    = 
       
   350         ( aSorting.Count() > 0 ) && ( aSorting[0].iField != EFSMailDontCare);
       
   351     iMsgMapper    = CIpsPlgMsgMapper::NewL( aMsvSession, iPlugin );
       
   352     iMsvSession   = &aMsvSession;
       
   353     }
       
   354     
       
   355 // ---------------------------------------------------------------------------
       
   356 // Second level constructor. Creates the data members to the heap.
       
   357 // Version which gets the folder CMsvEntry as a parameter.
       
   358 // ---------------------------------------------------------------------------
       
   359 //
       
   360 void CIpsPlgMsgIterator::ConstructL(        
       
   361     CMsvEntry* aFolderEntry, 
       
   362     const RArray<TFSMailSortCriteria>& aSorting )
       
   363     {
       
   364     FUNC_LOG;
       
   365     iFolderEntry  = aFolderEntry;
       
   366     iMsgSortKey   = new (ELeave) TIpsPlgMsgKey( *iFolderEntry, aSorting );
       
   367     iMsgSwapper   = new (ELeave) TIpsPlgMsgSwap( *iFolderEntry );
       
   368     iSortingOn    = 
       
   369         ( aSorting.Count() > 0 ) && ( aSorting[0].iField != EFSMailDontCare);
       
   370     iMsgMapper = CIpsPlgMsgMapper::NewL( aFolderEntry->Session(), iPlugin );
       
   371     iMsvSession = NULL;
       
   372     }
       
   373     
       
   374 // ---------------------------------------------------------------------------
       
   375 // Sorting is based on the quick sort algorithm implemented in User module
       
   376 // ---------------------------------------------------------------------------
       
   377 
       
   378 void CIpsPlgMsgIterator::Sort()
       
   379     {
       
   380     FUNC_LOG;
       
   381     if ( iSortingOn )
       
   382         {
       
   383         User::QuickSort( iFolderEntry->Count(), *iMsgSortKey, *iMsgSwapper );
       
   384         }
       
   385     }
       
   386     
       
   387 // ---------------------------------------------------------------------------
       
   388 // Searches the first message matching the search string.
       
   389 // This function is supported only when the messages are sorted by the subject
       
   390 // or by the sender (or the receiver in Drafts/Outbox/Sent folders) as 
       
   391 // a primary sorting key. The fields to be compared is selected on the basis 
       
   392 // of the sorting key.
       
   393 // ---------------------------------------------------------------------------
       
   394 
       
   395 TInt CIpsPlgMsgIterator::SearchL( 
       
   396     CMsvEntrySelection* aMessageEntries,
       
   397     const TDesC& aStartWith,
       
   398     TInt& aIndex )
       
   399     {
       
   400     FUNC_LOG;
       
   401     TInt result( KErrNotFound );
       
   402     TInt i;
       
   403     TInt findStatus;
       
   404     TInt offset;
       
   405     TFSMailSortField primaryKey = EFSMailDontCare;
       
   406     TPtrC subject;
       
   407 
       
   408     // Check whether the search is supported
       
   409     if ( iSortingCriteria.Count() > 0 )
       
   410         {
       
   411         primaryKey = iSortingCriteria[0].iField;
       
   412         }
       
   413     if ( !iSortingOn ||
       
   414          ( ( primaryKey != EFSMailSortBySender ) &&
       
   415            ( primaryKey != EFSMailSortBySubject ) ) )
       
   416         {
       
   417         result = KErrNotSupported;
       
   418         }
       
   419         
       
   420     // Actual search        
       
   421     i = 0;
       
   422     while ( ( result == KErrNotFound ) && ( i < aMessageEntries->Count() ) )
       
   423         {
       
   424         const TMsvEntry& entry( 
       
   425             iFolderEntry->ChildDataL( aMessageEntries->At(i) ) );
       
   426 
       
   427         findStatus = KErrNotFound;
       
   428 
       
   429         if ( primaryKey == EFSMailSortBySender )
       
   430             {
       
   431             findStatus = entry.iDetails.FindF( aStartWith );
       
   432             }
       
   433         if ( primaryKey == EFSMailSortBySubject )
       
   434             {
       
   435             // Strip the prefixes (Re:, Fwd: etc) from the subject before
       
   436             // matching
       
   437             offset = iMsgSortKey->FindSubjectStart( entry.iDescription );
       
   438             subject.Set( 
       
   439                 entry.iDescription.Ptr() + offset, 
       
   440                 entry.iDescription.Length() - offset );
       
   441             findStatus = subject.FindF( aStartWith );
       
   442             }
       
   443         
       
   444         // Checks whether a matching message has been found
       
   445         if ( findStatus == 0 ) 
       
   446             {
       
   447             result = KErrNone;
       
   448             aIndex = i;
       
   449             }
       
   450 
       
   451         i++;
       
   452         }
       
   453         
       
   454     return result;
       
   455     }
       
   456 // ---------------------------------------------------------------------------
       
   457 // Filters messages in global folders (Drafts/Sent/Outbox) that belongs to
       
   458 // specified mailbox. When messages in inbox asked, returns selection from 
       
   459 // wanted mailbox.
       
   460 // ---------------------------------------------------------------------------
       
   461 CMsvEntrySelection* CIpsPlgMsgIterator::FilterMessagesL()
       
   462 	{
       
   463     FUNC_LOG;
       
   464 	TMsvId serviceId;
       
   465 	TMsvEntry tEntry;
       
   466 	TMsvEntry mailboxServiceEntry;
       
   467 	CMsvEntrySelection* filteredEntries;
       
   468 	
       
   469 	if( iMsvSession && iFolderEntry->Entry().Parent() == KMsvLocalServiceIndexEntryIdValue )
       
   470 		{
       
   471 		User::LeaveIfError(
       
   472 			iMsvSession->GetEntry( iMailboxId.Id(), serviceId, tEntry ) );
       
   473 		User::LeaveIfError(
       
   474 		    iMsvSession->GetEntry( tEntry.iRelatedId, serviceId, mailboxServiceEntry ) );
       
   475 			
       
   476 		filteredEntries = iFolderEntry->ChildrenWithServiceL( serviceId );
       
   477 		}
       
   478 	else
       
   479 		{
       
   480  		filteredEntries = iFolderEntry->ChildrenWithServiceL( iMailboxId.Id() );
       
   481 		}
       
   482 	return filteredEntries;
       
   483 	}
       
   484