ipsservices/ipssosplugin/src/ipsplgmsgmapper.cpp
changeset 0 8466d47a6819
child 1 12c456ceeff2
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: This file implements class CIpsPlgMsgMapper.
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 
       
    20 #include "emailtrace.h"
       
    21 #include "ipsplgheaders.h"
       
    22 
       
    23 _LIT( KMimeTypeTextPlain, "text/plain" );
       
    24 _LIT( KMimeTypeTextHtml, "text/html" );
       
    25 _LIT( KMimeTypeTextRtf, "text/rtf" );
       
    26 _LIT( KSlash, "/" );
       
    27 
       
    28 _LIT( KCharSemicolon, ";" );
       
    29 _LIT( KCharEquals, "=" );
       
    30 _LIT( KCharsetTag, "CHARSET" );
       
    31 _LIT( KMessageExtension, ".eml" );
       
    32 
       
    33 // Supported multipart content types
       
    34 _LIT( KMimeTypeMultipartRelated, "multipart/related" );
       
    35 _LIT( KMimeTypeMultipartMixed, "multipart/mixed" );
       
    36 _LIT( KMimeTypeMultipartAlternative, "multipart/alternative" );
       
    37 _LIT( KMimeTypeMultipartDigest, "multipart/digest" );
       
    38 _LIT( KMimeTypeMultipartRfc822, "message/rfc822" );
       
    39 _LIT( KMimeTypeMultipartPartial, "message/partial" );
       
    40 _LIT( KMimeTypeMultipartDirectory, "text/directory" );
       
    41 _LIT( KMimeTypeMultipartExternalBody, "message/external-body" );
       
    42 _LIT( KMimeTypeMultipartParallel, "multipart/parallel" );
       
    43 
       
    44 const TInt KCharEscape       = 0x5C;
       
    45 const TInt KCharNonPrintable = 0x1F;
       
    46 const TInt KCharAt           = 0x40;
       
    47 const TInt KMaxContentTypeLength = 200;
       
    48 const TInt KEmbeddedMsgExtensionLength  = 4;
       
    49 
       
    50 // ======== CONSTRUCTORS & DESTRUCTOR ========
       
    51 
       
    52 // ---------------------------------------------------------------------------
       
    53 // CIpsPlgMsgMapper::NewL()
       
    54 // ---------------------------------------------------------------------------
       
    55 //
       
    56 CIpsPlgMsgMapper* CIpsPlgMsgMapper::NewL(
       
    57     CMsvSession& aSession,
       
    58     CIpsPlgSosBasePlugin& aPlugin )
       
    59     {
       
    60     FUNC_LOG;
       
    61     CIpsPlgMsgMapper* self = CIpsPlgMsgMapper::NewLC( aSession, aPlugin );
       
    62     CleanupStack::Pop( self );
       
    63     return self;
       
    64     }
       
    65 
       
    66 // ---------------------------------------------------------------------------
       
    67 // CIpsPlgMsgMapper::NewLC()
       
    68 // ---------------------------------------------------------------------------
       
    69 //
       
    70 CIpsPlgMsgMapper* CIpsPlgMsgMapper::NewLC(
       
    71     CMsvSession& aSession,
       
    72     CIpsPlgSosBasePlugin& aPlugin )
       
    73     {
       
    74     FUNC_LOG;
       
    75     CIpsPlgMsgMapper* self =
       
    76         new( ELeave ) CIpsPlgMsgMapper( aSession, aPlugin );
       
    77     CleanupStack::PushL( self );
       
    78     self->ConstructL();
       
    79     return self;
       
    80     }
       
    81 
       
    82 // ---------------------------------------------------------------------------
       
    83 // CIpsPlgMsgMapper::~CIpsPlgMsgMapper()
       
    84 // ---------------------------------------------------------------------------
       
    85 //
       
    86 CIpsPlgMsgMapper::~CIpsPlgMsgMapper()
       
    87     {
       
    88     FUNC_LOG;
       
    89     }
       
    90 
       
    91 // ---------------------------------------------------------------------------
       
    92 // CIpsPlgMsgMapper::CIpsPlgMsgMapper()
       
    93 // ---------------------------------------------------------------------------
       
    94 //
       
    95 CIpsPlgMsgMapper::CIpsPlgMsgMapper(
       
    96     CMsvSession& aSession,
       
    97     CIpsPlgSosBasePlugin& aPlugin )
       
    98     : iSession( aSession ), iPlugin( aPlugin )
       
    99     {
       
   100     FUNC_LOG;
       
   101     }
       
   102 
       
   103 // ---------------------------------------------------------------------------
       
   104 // CIpsPlgMsgMapper::ConstructL()
       
   105 // ---------------------------------------------------------------------------
       
   106 //
       
   107 void CIpsPlgMsgMapper::ConstructL()
       
   108     {
       
   109     FUNC_LOG;
       
   110     }
       
   111 
       
   112 // ---------------------------------------------------------------------------
       
   113 // CIpsPlgMsgMapper::GetMailMessageL()
       
   114 // ---------------------------------------------------------------------------
       
   115 //
       
   116 CFSMailMessage* CIpsPlgMsgMapper::GetMailMessageL(
       
   117     CMsvEntry& aEntry )
       
   118     {
       
   119     FUNC_LOG;
       
   120     TFSMailMsgId msgId( iPlugin.PluginId(), aEntry.Entry().Id() );
       
   121     CFSMailMessage* fsMsg = CFSMailMessage::NewLC( msgId );
       
   122 
       
   123     fsMsg->SetFolderId(
       
   124         TFSMailMsgId( iPlugin.PluginId(), aEntry.Entry().Parent() ) );
       
   125 
       
   126     CMsvStore* store( NULL );
       
   127 
       
   128     if ( aEntry.HasStoreL() )
       
   129         {
       
   130         store = aEntry.ReadStoreL();
       
   131         CleanupStack::PushL( store );
       
   132         }
       
   133 
       
   134     SetEnvelopeL( &aEntry, store, *fsMsg );
       
   135 
       
   136     // Apparently, this should be done only with
       
   137     // EFSMsgDataStructure, but EFSMsgDataEnvelope is currently
       
   138     // used by assuming that it reads also the content-type of
       
   139     // the message
       
   140     SetStructureL( &aEntry, *fsMsg );
       
   141 
       
   142     TMsvEmailEntry tEntry( aEntry.Entry() );
       
   143 
       
   144     SetFlags( tEntry, *fsMsg );
       
   145 
       
   146     if ( store )
       
   147         {
       
   148         CleanupStack::PopAndDestroy( store );
       
   149         }
       
   150 
       
   151     CleanupStack::Pop( fsMsg );
       
   152     return fsMsg;
       
   153     }
       
   154 
       
   155 // ---------------------------------------------------------------------------
       
   156 // CIpsPlgMsgMapper::GetMailMessageL()
       
   157 // ---------------------------------------------------------------------------
       
   158 //
       
   159 CFSMailMessage* CIpsPlgMsgMapper::GetMailMessageL(
       
   160     const TFSMailMsgId& aMailboxId,
       
   161     const TMsvEmailEntry& aEntry,
       
   162     const TFSMailDetails& aDetails )
       
   163     {
       
   164     FUNC_LOG;
       
   165     TFSMailMsgId msgId( iPlugin.PluginId(), aEntry.Id() );
       
   166     CFSMailMessage* result = CFSMailMessage::NewLC( msgId );
       
   167 
       
   168     result->SetMailBoxId( aMailboxId );
       
   169     result->SetFolderId(
       
   170         TFSMailMsgId( iPlugin.PluginId(), aEntry.Parent() ) );
       
   171 
       
   172     SetFlags( aEntry, *result );
       
   173     SetFetchStateL( aEntry, aEntry.Id(), EFalse, *result );
       
   174 
       
   175     switch( aDetails )
       
   176         {
       
   177         case EFSMsgDataDate:
       
   178             SetDateL( aEntry, *result );
       
   179             break;
       
   180         case EFSMsgDataSubject:
       
   181             SetSubjectL( aEntry, *result );
       
   182             break;
       
   183         case EFSMsgDataSender:
       
   184             SetSenderL( aEntry.iDetails, *result );
       
   185             break;
       
   186         case EFSMsgDataEnvelope:
       
   187         case EFSMsgDataStructure:
       
   188             {
       
   189             CMsvStore* store( NULL );
       
   190             CMsvEntry* cEntry = iSession.GetEntryL( aEntry.Id() );
       
   191             CleanupStack::PushL( cEntry );
       
   192 
       
   193             if ( cEntry && cEntry->HasStoreL() )
       
   194                 {
       
   195                 store = cEntry->ReadStoreL();
       
   196                 CleanupStack::PushL( store );
       
   197                 }
       
   198 
       
   199             SetEnvelopeL( cEntry, store, *result );
       
   200 
       
   201             // Apparently, this should be done only with
       
   202             // EFSMsgDataStructure, but EFSMsgDataEnvelope is currently
       
   203             // used by assuming that it reads also the content-type of
       
   204             // the message
       
   205             SetStructureL( cEntry, *result );
       
   206 
       
   207             if ( store )
       
   208                 {
       
   209                 CleanupStack::PopAndDestroy( store );
       
   210                 }
       
   211             CleanupStack::PopAndDestroy( cEntry );
       
   212             break;
       
   213             }
       
   214         case EFSMsgDataIdOnly:
       
   215         default:
       
   216             break;
       
   217         }
       
   218 
       
   219     CleanupStack::Pop( result );
       
   220     return result;
       
   221     }
       
   222 
       
   223 // ---------------------------------------------------------------------------
       
   224 // ---------------------------------------------------------------------------
       
   225 void CIpsPlgMsgMapper::GetChildPartsL(
       
   226     const TFSMailMsgId& aMailBoxId,
       
   227     const TFSMailMsgId& aMessageId,
       
   228     const TFSMailMsgId& aParentId,
       
   229     RPointerArray<CFSMailMessagePart>& aParts )
       
   230     {
       
   231     FUNC_LOG;
       
   232 
       
   233     if ( aParentId.IsNullId() )
       
   234         // the caller wants the children of the message
       
   235         {
       
   236         GetChildPartsOfMessageEntryL( aMailBoxId, aMessageId, aParts );
       
   237         }
       
   238     else
       
   239         // the caller wants the parts of the 'real' subpart
       
   240         {
       
   241         GetChildPartsOfFolderEntryL( aMailBoxId, aMessageId, aParentId.Id(),
       
   242             aParts );
       
   243         }
       
   244     }
       
   245 
       
   246 // ---------------------------------------------------------------------------
       
   247 // ---------------------------------------------------------------------------
       
   248 CFSMailMessagePart* CIpsPlgMsgMapper::GetMessagePartL(
       
   249     TMsvId aEntryId,
       
   250     const TFSMailMsgId& aMailBoxId,
       
   251     const TFSMailMsgId& aMessageId )
       
   252     {
       
   253     FUNC_LOG;
       
   254     CFSMailMessagePart* result( NULL );
       
   255     TInt status;
       
   256     TMsvId serviceId;
       
   257     TMsvEmailEntry tEntry;
       
   258 
       
   259     status = iSession.GetEntry( aEntryId, serviceId, tEntry );
       
   260 
       
   261     if ( status == KErrNone )
       
   262         {
       
   263         switch ( tEntry.iType.iUid )
       
   264             {
       
   265             case KUidMsvFolderEntryValue:
       
   266                 {
       
   267                 result = ConvertFolderEntry2MessagePartL( tEntry,
       
   268                     aMailBoxId, aMessageId );
       
   269                 break;
       
   270                 }
       
   271             case KUidMsvAttachmentEntryValue:
       
   272             case KUidMsvMessageEntryValue:
       
   273                 {
       
   274                 result = ConvertAttachmentEntry2MessagePartL( tEntry,
       
   275                     aMailBoxId, aMessageId );
       
   276                 break;
       
   277                 }
       
   278             case KUidMsvEmailTextEntryValue:
       
   279             case KUidMsvEmailHtmlEntryValue:
       
   280             case KUidMsvEmailExternalBodyEntryValue:
       
   281             case KUidMsvEmailRtfEntryValue:
       
   282                 {
       
   283                 result = ConvertBodyEntry2MessagePartL( tEntry, aMailBoxId,
       
   284                     aMessageId );
       
   285                 break;
       
   286                 }
       
   287             }
       
   288         }
       
   289 
       
   290     return result;
       
   291     }
       
   292 
       
   293 // ---------------------------------------------------------------------------
       
   294 // ---------------------------------------------------------------------------
       
   295 TBool CIpsPlgMsgMapper::ChangeTEntryFlagsL(
       
   296     TMsvEmailEntry& aEmlEntry,
       
   297     const CFSMailMessage& aMessage )
       
   298     {
       
   299     FUNC_LOG;
       
   300     TInt msgFlags = aMessage.GetFlags();
       
   301     TBool modified ( EFalse );
       
   302     TBool unread( aEmlEntry.Unread() );
       
   303 
       
   304     if ( !LogicalXor( unread, msgFlags & EFSMsgFlag_Read ) )
       
   305         {
       
   306         aEmlEntry.SetUnread( !unread );
       
   307         modified = ETrue;
       
   308         }
       
   309 
       
   310     // EFSMsgFlag_Low
       
   311     // EFSMsgFlag_Important
       
   312     TMsvPriority msgPriority;
       
   313 
       
   314     if ( msgFlags & EFSMsgFlag_Important )
       
   315         {
       
   316         msgPriority = EMsvHighPriority;
       
   317         }
       
   318     else if ( msgFlags & EFSMsgFlag_Low )
       
   319         {
       
   320         msgPriority = EMsvLowPriority;
       
   321         }
       
   322     else
       
   323         {
       
   324         msgPriority = EMsvMediumPriority;
       
   325         }
       
   326 
       
   327     if ( aEmlEntry.Priority() != msgPriority )
       
   328         {
       
   329         aEmlEntry.SetPriority( msgPriority );
       
   330         modified = ETrue;
       
   331         }
       
   332 
       
   333     // EFSMsgFlag_FollowUpComplete: no counterpart in Symbian message
       
   334 
       
   335     // EFSMsgFlag_FollowUp: supported only with IMAP4 (see below)
       
   336 
       
   337     // EFSMsgFlag_Attachments: It does not seem reasonable to update
       
   338     // this flag here (but when attachments are added)
       
   339 
       
   340     // EFSMsgFlag_Multiple: no counterpart in Symbian message
       
   341 
       
   342     // EFSMsgFlag_CalendarMsg
       
   343     if( ( aEmlEntry.iMtm == KSenduiMtmSmtpUid ) && ( msgFlags & EFSMsgFlag_CalendarMsg ) )
       
   344         {
       
   345         if( !aEmlEntry.ICalendar() )
       
   346             {
       
   347             aEmlEntry.SetICalendar( ETrue );
       
   348             modified = ETrue;
       
   349             }
       
   350         }
       
   351 
       
   352 
       
   353     // EFSMsgFlag_Answered: supported only with IMAP4 (see below)
       
   354 
       
   355     // EFSMsgFlag_Forwarded: no counterpart in Symbian message in S60 3.1
       
   356 
       
   357     // EFSMsgFlag_OnlyToMe: no counterpart in Symbian message
       
   358 
       
   359     // EFSMsgFlag_RemoteDeleted: no counterpart in Symbian message
       
   360 
       
   361     // EFSMsgFlag_HasMsgSender: no counterpart in Symbian message
       
   362 
       
   363 
       
   364     //this applies to POP too. Just ignore the misleading naming
       
   365     // moved to fix EANA-7HUD2G, pop doesn't support permanent flags
       
   366     // EFSMsgFlag_Answered
       
   367 
       
   368     // IMAP flags
       
   369     if ( aEmlEntry.iMtm == KSenduiMtmImap4Uid )
       
   370         {
       
   371             // EFSMsgFlag_FollowUp
       
   372         if ( LogicalXor( aEmlEntry.FlaggedIMAP4Flag(),
       
   373                          ( msgFlags & EFSMsgFlag_FollowUp ) ) )
       
   374             {
       
   375             aEmlEntry.SetFlaggedIMAP4Flag( !aEmlEntry.FlaggedIMAP4Flag() );
       
   376             modified = ETrue;
       
   377             }
       
   378         // EFSMsgFlag_Answered
       
   379         if ( LogicalXor( aEmlEntry.AnsweredIMAP4Flag(),
       
   380                          ( msgFlags & EFSMsgFlag_Answered ) ) )
       
   381             {
       
   382             aEmlEntry.SetAnsweredIMAP4Flag( !aEmlEntry.AnsweredIMAP4Flag() );
       
   383             modified = ETrue;
       
   384             }
       
   385         }
       
   386     return modified;
       
   387     }
       
   388 
       
   389 // ---------------------------------------------------------------------------
       
   390 // ---------------------------------------------------------------------------
       
   391 void CIpsPlgMsgMapper::UpdateMessageFlagsL(
       
   392     TMsvId aEntryId,
       
   393     const CFSMailMessage& aMessage )
       
   394     {
       
   395     FUNC_LOG;
       
   396     // This function updates tEntry from aMessage
       
   397     CMsvEntry* cEntry = iSession.GetEntryL( aEntryId );
       
   398     CleanupStack::PushL( cEntry );
       
   399 
       
   400     TMsvEmailEntry tEntry( cEntry->Entry() );
       
   401     TBool isModified = ChangeTEntryFlagsL( tEntry, aMessage );
       
   402 
       
   403     if ( isModified )
       
   404         {
       
   405         CIpsPlgOperationWait* waiter = CIpsPlgOperationWait::NewLC();
       
   406         CMsvOperation* ops = cEntry->ChangeL( tEntry, waiter->iStatus );
       
   407         CleanupStack::PushL( ops );
       
   408         waiter->Start();
       
   409         CleanupStack::PopAndDestroy( 2, waiter );
       
   410         }
       
   411 
       
   412     CleanupStack::PopAndDestroy( cEntry );
       
   413     }
       
   414 
       
   415 // ---------------------------------------------------------------------------
       
   416 // ---------------------------------------------------------------------------
       
   417 CMsvOperation* CIpsPlgMsgMapper::UpdateMessageFlagsAsyncL(
       
   418     TMsvId aEntryId,
       
   419     const CFSMailMessage& aMessage,
       
   420     TRequestStatus& aStatus )
       
   421     {
       
   422     FUNC_LOG;
       
   423     // This function updates tEntry from aMessage
       
   424     CMsvEntry* cEntry = iSession.GetEntryL( aEntryId );
       
   425     CleanupStack::PushL( cEntry );
       
   426     TMsvEmailEntry tEntry( cEntry->Entry() );
       
   427 
       
   428     TBool isModified = ChangeTEntryFlagsL( tEntry, aMessage );
       
   429     CMsvOperation* ops = NULL;
       
   430     if ( isModified )
       
   431         {
       
   432         ops = cEntry->ChangeL( tEntry, aStatus );
       
   433         }
       
   434 
       
   435     CleanupStack::PopAndDestroy( cEntry );
       
   436     return ops;
       
   437     }
       
   438 
       
   439 // ---------------------------------------------------------------------------
       
   440 // ---------------------------------------------------------------------------
       
   441 void CIpsPlgMsgMapper::SetFSMessageFlagsL(
       
   442     const TMsvEmailEntry& aEntry, CFSMailMessage& aMsg )
       
   443     {
       
   444     FUNC_LOG;
       
   445     // this is just stupid through call, but now not need to
       
   446     // move SetFlags to public
       
   447     SetFlags( aEntry, aMsg );
       
   448     }
       
   449 
       
   450 // ---------------------------------------------------------------------------
       
   451 // CIpsPlgMsgMapper::NewChildPartL
       
   452 // The method supports currently only the multipart/alternative structure
       
   453 // construction (which is needed in the meeting request messages).
       
   454 // The creation of the multipart structure happens by changing the folder
       
   455 // type of the (SMTP) message entry itself. The folder entry is created
       
   456 // by Symbian MTM later when new parts are added below the multipart
       
   457 // structure. This causes some problems because there is no new entry
       
   458 // in this phase and so the new CFSMailMessagePart instance do not
       
   459 // ---------------------------------------------------------------------------
       
   460 CFSMailMessagePart* CIpsPlgMsgMapper::NewChildPartL(
       
   461     const TFSMailMsgId& /* aMailBoxId */,
       
   462     const TFSMailMsgId& aMessageId,
       
   463     const TFSMailMsgId& /* aParentPartId */,
       
   464     const TDesC& /*aContentType*/ )
       
   465     {
       
   466     FUNC_LOG;
       
   467     CFSMailMessagePart* result( NULL );
       
   468     result = CFSMailMessagePart::NewLC( aMessageId,
       
   469                 TFSMailMsgId( aMessageId.PluginId().iUid,
       
   470                     KMsvNullIndexEntryIdValue ) );
       
   471     CleanupStack::Pop( result );
       
   472     return result;
       
   473     }
       
   474 
       
   475 // ---------------------------------------------------------------------------
       
   476 // CIpsPlgMsgMapper::SetDateL
       
   477 // ---------------------------------------------------------------------------
       
   478 //
       
   479 void CIpsPlgMsgMapper::SetDateL(
       
   480     const TMsvEntry& aEntry,
       
   481     CFSMailMessage& aMsg )
       
   482     {
       
   483     FUNC_LOG;
       
   484     const TTime date =  aEntry.iDate;
       
   485     aMsg.SetDate( date );
       
   486     }
       
   487 
       
   488 // ---------------------------------------------------------------------------
       
   489 // CIpsPlgMsgMapper::SetSubjectL
       
   490 // ---------------------------------------------------------------------------
       
   491 //
       
   492 void CIpsPlgMsgMapper::SetSubjectL(
       
   493     const TMsvEntry& aEntry,
       
   494     CFSMailMessage& aMsg )
       
   495     {
       
   496     FUNC_LOG;
       
   497     aMsg.SetSubject( aEntry.iDescription );
       
   498     }
       
   499 
       
   500 // ---------------------------------------------------------------------------
       
   501 // CIpsPlgMsgMapper::SetSenderL
       
   502 // ---------------------------------------------------------------------------
       
   503 //
       
   504 void CIpsPlgMsgMapper::SetSenderL(
       
   505     TPtrC aSender,
       
   506     CFSMailMessage& aMsg )
       
   507     {
       
   508     FUNC_LOG;
       
   509     CFSMailAddress* addr = CFSMailAddress::NewLC();
       
   510     ConvertAddressL( aSender, *addr );
       
   511     aMsg.SetSender( addr );
       
   512     CleanupStack::Pop( addr );
       
   513     }
       
   514 
       
   515 // ---------------------------------------------------------------------------
       
   516 // ---------------------------------------------------------------------------
       
   517 void CIpsPlgMsgMapper::SetEnvelopeL(
       
   518     const CMsvEntry* aEntry,
       
   519     CMsvStore* aStore,
       
   520     CFSMailMessage& aMsg )
       
   521     {
       
   522     FUNC_LOG;
       
   523     CFSMailAddress* addr = NULL;
       
   524 
       
   525     TMsvEmailEntry tEntry( aEntry->Entry() );
       
   526 
       
   527     SetDateL( tEntry, aMsg );
       
   528     SetSubjectL( tEntry, aMsg );
       
   529 
       
   530     if ( aStore && aStore->IsPresentL( KUidMsgFileIMailHeader ) )
       
   531         {
       
   532         CImHeader* header = CImHeader::NewLC();
       
   533         header->RestoreL( *aStore );
       
   534 
       
   535         SetSenderL( header->From(), aMsg );
       
   536 
       
   537         const CDesCArray& toRecs = header->ToRecipients();
       
   538 
       
   539         for( TInt i=0; i<toRecs.Count(); i++ )
       
   540             {
       
   541             addr = CFSMailAddress::NewLC();
       
   542             ConvertAddressL( toRecs[i], *addr );
       
   543             aMsg.AppendToRecipient( addr );
       
   544             CleanupStack::Pop( addr );
       
   545             }
       
   546 
       
   547         const CDesCArray& ccRecs = header->CcRecipients();
       
   548 
       
   549         for( TInt i=0; i<ccRecs.Count(); i++ )
       
   550             {
       
   551             addr = CFSMailAddress::NewLC();
       
   552             ConvertAddressL( ccRecs[i], *addr );
       
   553             aMsg.AppendCCRecipient( addr );
       
   554             CleanupStack::Pop( addr );
       
   555             }
       
   556 
       
   557         const CDesCArray& bccRecs = header->BccRecipients();
       
   558 
       
   559         for( TInt i=0; i< bccRecs.Count(); i++ )
       
   560             {
       
   561             addr = CFSMailAddress::NewLC();
       
   562             ConvertAddressL( bccRecs[i], *addr );
       
   563             aMsg.AppendBCCRecipient( addr );
       
   564             CleanupStack::Pop( addr );
       
   565             }
       
   566 
       
   567         CleanupStack::PopAndDestroy( header );
       
   568         }
       
   569     else
       
   570         {
       
   571         // if the email header stream is not available, the sender
       
   572         // information is taken from the index entry
       
   573         SetSenderL( aEntry->Entry().iDetails, aMsg );
       
   574         }
       
   575     }
       
   576 
       
   577 // ---------------------------------------------------------------------------
       
   578 // ---------------------------------------------------------------------------
       
   579 void CIpsPlgMsgMapper::SetStructureL(
       
   580     const CMsvEntry* aEntry,
       
   581     CFSMailMessage& aMessage )
       
   582     {
       
   583     FUNC_LOG;
       
   584     // Find out the content type by studying the child entry:
       
   585     // If there are no children, the message contents are not fetched and
       
   586     // thus the content type cannot be inferred. On the other hand,
       
   587     // the message entry should never have more than one child entry
       
   588     // (otherwise, it should be a multipart message)
       
   589     if ( aEntry->Count() == 1 )
       
   590         {
       
   591         TMsvEmailEntry tEntry = (*aEntry)[0];
       
   592         if ( tEntry.iType == KUidMsvFolderEntry )
       
   593             {
       
   594             aMessage.SetContentType(
       
   595                 ConvertMultipartMimeType( tEntry.MessageFolderType() ) );
       
   596             }
       
   597         else
       
   598             // The case in which the content entry is directly below
       
   599             // the message entry..
       
   600             {
       
   601             aMessage.SetContentType( KMimeTypeMultipartMixed );
       
   602             }
       
   603         }
       
   604     else
       
   605         {
       
   606         // mark message structure state unknown if we don't have any
       
   607         // child parts. This needed to ui start fetch
       
   608         aMessage.SetMessagePartsStatus( EFSEmailStructureUnknown );
       
   609         }
       
   610 
       
   611     aMessage.SetContentSize( aEntry->Entry().iSize );
       
   612     }
       
   613 
       
   614 // ---------------------------------------------------------------------------
       
   615 // CIpsPlgMsgMapper::SetFlags
       
   616 // FS framework's flag definitions and methods are somewhat clumsy and thus
       
   617 // there is quite much code for a pretty simple function..
       
   618 // ---------------------------------------------------------------------------
       
   619 void CIpsPlgMsgMapper::SetFlags(
       
   620     const TMsvEmailEntry& aEntry,
       
   621     CFSMailMessage& aMsg )
       
   622     {
       
   623     FUNC_LOG;
       
   624 
       
   625     TBool forwardedMeetingRequest = EFalse;
       
   626     
       
   627     // EFSMsgFlag_Read
       
   628     // EFSMsgFlag_Read_Locally
       
   629     if ( aEntry.Unread() )
       
   630         {
       
   631             aMsg.ResetFlag( EFSMsgFlag_Read );
       
   632             aMsg.ResetFlag( EFSMsgFlag_Read_Locally );
       
   633             }
       
   634     else
       
   635         {
       
   636         aMsg.SetFlag( EFSMsgFlag_Read );
       
   637         aMsg.SetFlag( EFSMsgFlag_Read_Locally );
       
   638         }
       
   639 
       
   640     // EFSMsgFlag_Low
       
   641     // EFSMsgFlag_Important
       
   642     switch ( aEntry.Priority() )
       
   643         {
       
   644         case EMsvHighPriority:
       
   645             {
       
   646             aMsg.SetFlag( EFSMsgFlag_Important );
       
   647             aMsg.ResetFlag( EFSMsgFlag_Low );
       
   648             break;
       
   649             }
       
   650         case EMsvMediumPriority:
       
   651             {
       
   652             aMsg.ResetFlag( EFSMsgFlag_Important );
       
   653             aMsg.ResetFlag( EFSMsgFlag_Low );
       
   654             break;
       
   655             }
       
   656         case EMsvLowPriority:
       
   657             {
       
   658             aMsg.ResetFlag( EFSMsgFlag_Important );
       
   659             aMsg.SetFlag( EFSMsgFlag_Low );
       
   660             break;
       
   661             }
       
   662         }
       
   663 
       
   664     // EFSMsgFlag_FollowUpComplete: cannot be supported with Symbian messages?
       
   665 
       
   666     // EFSMsgFlag_FollowUp: supported only with IMAP4 messages (see below)
       
   667     aMsg.ResetFlag( EFSMsgFlag_FollowUp );
       
   668 
       
   669 // <cmail>
       
   670     //only for incomplete POP3 messages
       
   671     if ( aEntry.iMtm.iUid == KSenduiMtmPop3UidValue &&
       
   672             ( !aEntry.Complete() || aEntry.PartialDownloaded () ) )
       
   673         {
       
   674         TRAP_IGNORE( AttaCheckForIncompleteMsgL( aEntry, aMsg ) );
       
   675         }
       
   676 // </cmail>
       
   677     else
       
   678         {
       
   679         // EFSMsgFlag_Attachments
       
   680         if ( aEntry.Attachment() )
       
   681             {
       
   682             aMsg.SetFlag( EFSMsgFlag_Attachments );
       
   683 
       
   684             if ( aEntry.ICalendar() )
       
   685                 {
       
   686                 // <cmail> implementation changed due to cs warning
       
   687                 TInt attCount = 0;
       
   688                 TRAPD ( err, attCount = GetAttachmentCountL( aEntry ) );
       
   689                 if ( err == KErrNone && attCount == 1 )
       
   690                 	{
       
   691                 	CMsvEntry* cEntry = NULL;
       
   692                 	TRAPD ( err2, cEntry = iSession.GetEntryL( aEntry.Id() ) );
       
   693                 	if ( err2 == KErrNone && cEntry->Count() == 1 )
       
   694                 		{
       
   695                 		TMsvEmailEntry tEntry = (*cEntry)[0];
       
   696                 		TImEmailFolderType ft = tEntry.MessageFolderType();
       
   697                 		if ( tEntry.iType == KUidMsvFolderEntry && ft == EFolderTypeMixed  )
       
   698                 			{
       
   699                            	// Message with calendar object. But based on content type
       
   700                 			// (multipart/mixed) we know that this is meeting request
       
   701                 			// forwarded as email, so it must be seen as normal email.
       
   702                    			forwardedMeetingRequest = ETrue;
       
   703                    			aMsg.ResetFlag( EFSMsgFlag_CalendarMsg );
       
   704                    			aMsg.SetFlag( EFSMsgFlag_Attachments );
       
   705                         	}
       
   706 						else
       
   707 							{
       
   708 							// Only text/calendar part included as attachment
       
   709 							aMsg.ResetFlag( EFSMsgFlag_Attachments );
       
   710 							//Set Attachment flag for CMsvEntry (needed for sorting)
       
   711 							TRAP_IGNORE( SetAttachmentFlagL( aEntry, EFalse ) );
       
   712 							}
       
   713                 		}
       
   714                 	delete cEntry;
       
   715                 	cEntry = NULL;
       
   716                 	}
       
   717                 // </cmail>
       
   718                 }
       
   719             }
       
   720         else
       
   721             {
       
   722             aMsg.ResetFlag( EFSMsgFlag_Attachments );
       
   723             }
       
   724         }
       
   725 
       
   726     // EFSMsgFlag_Multiple: currently this is not used anywhere and
       
   727     // to evaluate the value, the CMsvStore of the message should be
       
   728     // accessed which is relatively slow (compared to the access of
       
   729     // the index entry)
       
   730 
       
   731     // EFSMsgFlag_CalendarMsg
       
   732     if ( aEntry.ICalendar() && !forwardedMeetingRequest ) // <cmail>
       
   733         {
       
   734         aMsg.SetFlag( EFSMsgFlag_CalendarMsg );
       
   735         }
       
   736     else if( !( aMsg.GetFlags() & EFSMsgFlag_CalendarMsg ) )
       
   737         {
       
   738         // Flag not set by mrui, we can reset it
       
   739         aMsg.ResetFlag( EFSMsgFlag_CalendarMsg );
       
   740         }
       
   741 
       
   742     // EFSMsgFlag_Answered: supported only with IMAP4 messages (see below)
       
   743     aMsg.ResetFlag( EFSMsgFlag_Answered );
       
   744 
       
   745     // EFSMsgFlag_Forwarded: not supported in S60 3.1
       
   746     aMsg.ResetFlag( EFSMsgFlag_Forwarded );
       
   747 
       
   748     // EFSMsgFlag_OnlyToMe: like EFSMsgFlag_Multiple
       
   749 
       
   750     // EFSMsgFlag_RemoteDeleted: no reasonable use in IPS
       
   751 
       
   752     // EFSMsgFlag_HasMsgSender: currently not used anywhere. Could be
       
   753     // probably be supported by checking the contents of TmsvEntry::iDetails
       
   754     // but this should be tested
       
   755 
       
   756     // Additional logic for IMAP4 messages
       
   757     if ( aEntry.iMtm == KSenduiMtmImap4Uid )
       
   758         {
       
   759         if ( aEntry.FlaggedIMAP4Flag() )
       
   760             {
       
   761             aMsg.SetFlag( EFSMsgFlag_FollowUp );
       
   762             }
       
   763         // moved to fix EANA-7HUD2G, pop doesn't support permanent flags
       
   764         if ( aEntry.AnsweredIMAP4Flag() )
       
   765             {
       
   766             aMsg.SetFlag( EFSMsgFlag_Answered );
       
   767             }
       
   768         }
       
   769     }
       
   770 
       
   771 // ---------------------------------------------------------------------------
       
   772 // ---------------------------------------------------------------------------
       
   773 void CIpsPlgMsgMapper::SetFetchStateL(
       
   774     const TMsvEmailEntry& aEntry,
       
   775     TMsvId aMsgMainId,
       
   776     TBool aIsAtta,
       
   777     CFSMailMessagePart& aMessage )
       
   778     {
       
   779     FUNC_LOG;
       
   780     if ( aEntry.iMtm.iUid == KSenduiMtmPop3UidValue && 
       
   781             aEntry.Id() != aMsgMainId &&
       
   782             !aIsAtta )
       
   783         {
       
   784         TInt error = KErrNone;
       
   785         TMsvEmailEntry emlEntry;
       
   786         TMsvId dummy;
       
   787 
       
   788         error = iSession.GetEntry( aMsgMainId , dummy, emlEntry );
       
   789 
       
   790         if ( error == KErrNone )
       
   791             {
       
   792             DoSetFetchStateL( emlEntry, aMsgMainId, aIsAtta, aMessage );
       
   793             }
       
   794         else
       
   795             {
       
   796             aMessage.SetMessagePartsStatus( EFSEmailStructureUnknown );
       
   797             }
       
   798         }
       
   799     else
       
   800         {
       
   801         DoSetFetchStateL( aEntry, aMsgMainId, aIsAtta, aMessage );
       
   802         }
       
   803     }
       
   804 
       
   805 // ---------------------------------------------------------------------------
       
   806 // ---------------------------------------------------------------------------
       
   807 void CIpsPlgMsgMapper::DoSetFetchStateL(
       
   808     const TMsvEmailEntry& aEntry,
       
   809     TMsvId aMsgMainId,
       
   810     TBool aIsAtta,
       
   811     CFSMailMessagePart& aMessage )
       
   812     {
       
   813     FUNC_LOG;
       
   814     if ( aEntry.PartialDownloaded() )
       
   815         {
       
   816         aMessage.SetMessagePartsStatus( EFSPartial );
       
   817         }
       
   818     else if ( aEntry.BodyTextComplete() && !aIsAtta )
       
   819         {
       
   820         aMessage.SetMessagePartsStatus( EFSFull );
       
   821         }
       
   822     else if ( aEntry.Complete() && !aIsAtta )
       
   823         {
       
   824         aMessage.SetMessagePartsStatus( EFSFull );
       
   825         }
       
   826     else if ( aEntry.Complete() && aIsAtta )
       
   827         {
       
   828         CMsvEntry* cEntry = iSession.GetEntryL( aEntry.Id() );
       
   829 
       
   830         CleanupStack::PushL( cEntry );
       
   831 
       
   832         TBool hasStore = cEntry->HasStoreL();
       
   833 
       
   834         if ( hasStore )
       
   835             {
       
   836             CMsvStore* store = cEntry->EditStoreL();
       
   837     
       
   838             CleanupStack::PushL( store );
       
   839 
       
   840             MMsvAttachmentManager& attMgr = store->AttachmentManagerL();
       
   841         
       
   842             if ( attMgr.AttachmentCount() )
       
   843                 {
       
   844                 aMessage.SetMessagePartsStatus( EFSFull );
       
   845                 }
       
   846             else
       
   847                 {
       
   848                 aMessage.SetMessagePartsStatus( EFSNone );
       
   849                 }
       
   850             
       
   851             CleanupStack::PopAndDestroy( store );
       
   852             }
       
   853 
       
   854         CleanupStack::PopAndDestroy( cEntry );
       
   855         }
       
   856     else if ( aEntry.Id() != aMsgMainId )
       
   857         {
       
   858         // fetch state of some message part, then we sure know
       
   859         // structure, but its not complete nor partial so state must be
       
   860         // none
       
   861         aMessage.SetMessagePartsStatus( EFSNone );
       
   862         }
       
   863     else
       
   864         {
       
   865         aMessage.SetMessagePartsStatus( EFSEmailStructureUnknown );
       
   866         }
       
   867     }
       
   868 
       
   869 
       
   870 // ---------------------------------------------------------------------------
       
   871 // ---------------------------------------------------------------------------
       
   872 TPtrC CIpsPlgMsgMapper::ConvertMultipartMimeType(
       
   873     TImEmailFolderType aFolderType ) const
       
   874     {
       
   875     FUNC_LOG;
       
   876     TPtrC result;
       
   877 
       
   878     switch ( aFolderType )
       
   879     {
       
   880     case EFolderTypeRelated:
       
   881         {
       
   882         result.Set( KMimeTypeMultipartRelated );
       
   883         break;
       
   884         }
       
   885     case EFolderTypeMixed:
       
   886         {
       
   887         result.Set( KMimeTypeMultipartMixed );
       
   888         break;
       
   889         }
       
   890     case EFolderTypeParallel:
       
   891         {
       
   892         result.Set( KMimeTypeMultipartParallel );
       
   893         break;
       
   894         }
       
   895     case EFolderTypeAlternative:
       
   896         {
       
   897         result.Set( KMimeTypeMultipartAlternative );
       
   898         break;
       
   899         }
       
   900     case EFolderTypeDigest:
       
   901         {
       
   902         result.Set( KMimeTypeMultipartDigest );
       
   903         break;
       
   904         }
       
   905     case EFolderTypeRFC822:
       
   906         {
       
   907         result.Set( KMimeTypeMultipartRfc822 );
       
   908         break;
       
   909         }
       
   910     case EFolderTypePartial:
       
   911         {
       
   912         result.Set( KMimeTypeMultipartPartial );
       
   913         break;
       
   914         }
       
   915     case EFolderTypeDirectory:
       
   916         {
       
   917         result.Set( KMimeTypeMultipartDirectory );
       
   918         break;
       
   919         }
       
   920     case EFolderTypeExternal:
       
   921         {
       
   922         result.Set( KMimeTypeMultipartExternalBody );
       
   923         break;
       
   924         }
       
   925     case EFolderTypeUnknown:
       
   926     default:
       
   927         {
       
   928         result.Set( KNullDesC16 );
       
   929         break;
       
   930         }
       
   931     }
       
   932 
       
   933     return result;
       
   934     }
       
   935 
       
   936 // ---------------------------------------------------------------------------
       
   937 // ---------------------------------------------------------------------------
       
   938 // <cmail>
       
   939 TInt CIpsPlgMsgMapper::ConvertBodyPartMimeType(
       
   940     const TUid& aEntryType,
       
   941     TDes& aMimeType )
       
   942     {
       
   943     FUNC_LOG;
       
   944     TInt result( KErrNone );
       
   945 
       
   946     switch ( aEntryType.iUid )
       
   947     {
       
   948     case KUidMsvEmailTextEntryValue:
       
   949         {
       
   950             aMimeType.Append( KMimeTypeTextPlain );
       
   951         break;
       
   952         }
       
   953     case KUidMsvEmailHtmlEntryValue:
       
   954         {
       
   955             aMimeType.Append( KMimeTypeTextHtml );
       
   956         break;
       
   957         }
       
   958     case KUidMsvEmailExternalBodyEntryValue:
       
   959         {
       
   960         // This seems a bit suspicious, but it is improbable that this case
       
   961         // is ever used..
       
   962             aMimeType.Append( KMimeTypeMultipartExternalBody );
       
   963         break;
       
   964         }
       
   965     case KUidMsvEmailRtfEntryValue:
       
   966         {
       
   967             aMimeType.Append( KMimeTypeTextRtf );
       
   968         break;
       
   969         }
       
   970     default:
       
   971         {
       
   972         result = KErrNotFound;
       
   973         }
       
   974     }
       
   975     return result;
       
   976     }
       
   977 // </cmail>
       
   978 
       
   979 // ---------------------------------------------------------------------------
       
   980 // ---------------------------------------------------------------------------
       
   981 void CIpsPlgMsgMapper::ConvertAddressL(
       
   982     TPtrC aSourceAddress,
       
   983     CFSMailAddress& aTargetAddress )
       
   984     {
       
   985     FUNC_LOG;
       
   986     TInt status( KErrNone );
       
   987     TImMessageField mailField;
       
   988 
       
   989     aTargetAddress.SetEmailAddress(
       
   990         mailField.GetValidInternetEmailAddressFromString( aSourceAddress ) );
       
   991 
       
   992 // <cmail>
       
   993     // If previous validation fails because of invalid email address.
       
   994     // e.g '@' is missing. Then address between '<' and '>' marks is used.
       
   995     TInt start( aSourceAddress.LocateReverse('<') );
       
   996     if ( start != KErrNotFound && start > 0)
       
   997     	{
       
   998     	TInt end( aSourceAddress.LocateReverse('>') );
       
   999     	start += 1;
       
  1000     	aTargetAddress.SetEmailAddress( aSourceAddress.Mid( start, ( end - start ) ) );
       
  1001     	}
       
  1002 // </cmail>
       
  1003 
       
  1004     TPtrC alias = mailField.GetValidAlias( aSourceAddress, status );
       
  1005     if ( status == KErrNone )
       
  1006         {
       
  1007         TPtr alias2 = alias.AllocLC()->Des(); // have to create copy because alias might change
       
  1008         for ( TInt ii = 0; ii < alias2.Length(); ii++ )
       
  1009             {
       
  1010             if ( alias2[ii] <= KCharNonPrintable )
       
  1011                 {
       
  1012                 alias2.Delete( ii, 1 );
       
  1013                 ii--;
       
  1014                 }
       
  1015             else if ( ii < ( alias2.Length() - 1 ) &&
       
  1016                       alias2[ii] == KCharEscape )
       
  1017                 {
       
  1018                 if( alias2[ii+1] == KCharAt )
       
  1019                     {
       
  1020                     alias2.Delete( ii, 1 );
       
  1021                     ii--;
       
  1022                     }
       
  1023                 }
       
  1024             }
       
  1025         aTargetAddress.SetDisplayName( alias2 ); // creates its own copy
       
  1026         CleanupStack::PopAndDestroy();
       
  1027         }
       
  1028     else
       
  1029         {
       
  1030 // <cmail>
       
  1031        	aTargetAddress.SetDisplayName( aTargetAddress.GetEmailAddress() );
       
  1032 // </cmail>
       
  1033         }
       
  1034     }
       
  1035 
       
  1036 
       
  1037 // ---------------------------------------------------------------------------
       
  1038 // ---------------------------------------------------------------------------
       
  1039 void CIpsPlgMsgMapper::SetContentTypeL(
       
  1040     CImMimeHeader& aMimeHeader,
       
  1041     CFSMailMessagePart& aMessagePart )
       
  1042     {
       
  1043     FUNC_LOG;
       
  1044     HBufC8* buffer8 = HBufC8::NewLC(
       
  1045         aMimeHeader.ContentType().Length() +
       
  1046         aMimeHeader.ContentSubType().Length() + 1 );
       
  1047     buffer8->Des().Append( aMimeHeader.ContentType() );
       
  1048     buffer8->Des().Append( KSlash );
       
  1049     buffer8->Des().Append( aMimeHeader.ContentSubType() );
       
  1050     HBufC* buffer = HBufC::NewLC( buffer8->Length() );
       
  1051     buffer->Des().Copy( buffer8->Des() );
       
  1052     aMessagePart.SetContentType( *buffer );
       
  1053     CleanupStack::PopAndDestroy( 2, buffer8 ); // buffer
       
  1054     }
       
  1055 
       
  1056 // ---------------------------------------------------------------------------
       
  1057 // ---------------------------------------------------------------------------
       
  1058 void CIpsPlgMsgMapper::GetChildPartsOfMessageEntryL(
       
  1059     const TFSMailMsgId& aMailBoxId,
       
  1060     const TFSMailMsgId& aMessageId,
       
  1061     RPointerArray<CFSMailMessagePart>& aParts )
       
  1062     {
       
  1063     FUNC_LOG;
       
  1064     CFSMailMessagePart* childPart( NULL );
       
  1065     CMsvEntry* cEntry = iSession.GetEntryL( aMessageId.Id() );
       
  1066     CleanupStack::PushL( cEntry );
       
  1067 
       
  1068     if ( cEntry->Count() > 0 )
       
  1069         {
       
  1070         // Note: it is assumed that there is only one child which is
       
  1071         // either the body part (simple message) or the folder entry
       
  1072         // representing the main level multipart structure
       
  1073         if ( (*cEntry)[0].iType == KUidMsvFolderEntry )
       
  1074             {
       
  1075             GetChildPartsOfFolderEntryL( aMailBoxId, aMessageId,
       
  1076                 (*cEntry)[0].Id(), aParts);
       
  1077             }
       
  1078         else
       
  1079             {
       
  1080             childPart = GetMessagePartL( (*cEntry)[0].Id(), aMailBoxId, aMessageId );
       
  1081             if( childPart )
       
  1082                 {
       
  1083                 aParts.Append( childPart );
       
  1084                 }
       
  1085             }
       
  1086         }
       
  1087     CleanupStack::PopAndDestroy( cEntry );
       
  1088     }
       
  1089 
       
  1090 // ---------------------------------------------------------------------------
       
  1091 // CIpsPlgMsgMapper::GetChildPartsOfFolderEntryL
       
  1092 // Note: if the aParentId does not refer to a folder entry, childCount
       
  1093 // will be zero and the method does not do anything.
       
  1094 // It assumed that the method is called mainly for the folder entries
       
  1095 // and thus CMsvEntry is constructed without checking the entry type
       
  1096 // beforehand. If the assumption is not correct, the performance can be
       
  1097 // optimized by checking the entry type first.
       
  1098 // ---------------------------------------------------------------------------
       
  1099 void CIpsPlgMsgMapper::GetChildPartsOfFolderEntryL(
       
  1100     const TFSMailMsgId& aMailBoxId,
       
  1101     const TFSMailMsgId& aMessageId,
       
  1102     TMsvId aParentId,
       
  1103     RPointerArray<CFSMailMessagePart>& aParts )
       
  1104     {
       
  1105     FUNC_LOG;
       
  1106     CMsvEntry* cEntry = iSession.GetEntryL( aParentId );
       
  1107     CleanupStack::PushL( cEntry );
       
  1108     CFSMailMessagePart* childPart( NULL );
       
  1109     TInt childCount( cEntry->Count() );
       
  1110     TInt i;
       
  1111     TInt position;
       
  1112     TBool textBodyPartFound( EFalse );
       
  1113 
       
  1114     for (i = 0; i < childCount; i++ )
       
  1115         {
       
  1116         childPart = GetMessagePartL( (*cEntry)[i].Id(), aMailBoxId, aMessageId );
       
  1117 
       
  1118         // Child parts have to be ordered so that the plain text body
       
  1119         // part is first (if such exists) and the HTML body is next.
       
  1120         // The rest of the children can be in any order.
       
  1121         if ( (*cEntry)[i].iType == KUidMsvEmailTextEntry )
       
  1122             {
       
  1123             position = 0;
       
  1124             textBodyPartFound = ETrue;
       
  1125             }
       
  1126         else if ( (*cEntry)[i].iType == KUidMsvEmailHtmlEntry )
       
  1127             {
       
  1128             if ( textBodyPartFound )
       
  1129                 {
       
  1130                 position = 1;
       
  1131                 }
       
  1132             else
       
  1133                 {
       
  1134                 position = 0;
       
  1135                 }
       
  1136             }
       
  1137         else
       
  1138             {
       
  1139             position = i;
       
  1140             }
       
  1141 
       
  1142         // Insert the new child part to the result array
       
  1143         if ( childPart )
       
  1144             {
       
  1145             aParts.Insert( childPart, position );
       
  1146             childPart = NULL;
       
  1147             }
       
  1148         }
       
  1149     CleanupStack::PopAndDestroy( cEntry );
       
  1150     }
       
  1151 
       
  1152 // ---------------------------------------------------------------------------
       
  1153 // ---------------------------------------------------------------------------
       
  1154 CFSMailMessagePart* CIpsPlgMsgMapper::ConvertBodyEntry2MessagePartL(
       
  1155     const TMsvEmailEntry& aEntry,
       
  1156     const TFSMailMsgId& aMailBoxId,
       
  1157     const TFSMailMsgId& aMessageId )
       
  1158     {
       
  1159     FUNC_LOG;
       
  1160     CFSMailMessagePart* result( NULL );
       
  1161     TInt status;
       
  1162 // <cmail>
       
  1163     HBufC* buf = HBufC::NewLC( KMaxContentTypeLength );
       
  1164     TPtr contentType = buf->Des();
       
  1165 
       
  1166     status = ConvertBodyPartMimeType( aEntry.iType, contentType );
       
  1167     __ASSERT_DEBUG( ( status == KErrNone ),
       
  1168         User::Panic( KIpsPlgPanicCategory, EIpsPlgInvalidEntry ) );
       
  1169     if ( status == KErrNone )
       
  1170         {
       
  1171         result = CFSMailMessagePart::NewLC(
       
  1172             aMessageId, TFSMailMsgId( iPlugin.PluginId(), aEntry.Id() ) );
       
  1173 
       
  1174         // If mimetype is 'text/html' add charset parameter
       
  1175         if ( aEntry.iType.iUid == KUidMsvEmailHtmlEntryValue )
       
  1176             {
       
  1177             GetCharsetParameterL( aEntry, contentType );
       
  1178             }
       
  1179 // </cmail>
       
  1180         result->SetContentType( contentType );
       
  1181         result->SetMailBoxId( aMailBoxId );
       
  1182 
       
  1183         // Size
       
  1184         result->SetContentSize( aEntry.iSize );
       
  1185 
       
  1186         if ( aEntry.Complete() )
       
  1187             {
       
  1188             TMsvEmailEntry parent;
       
  1189             TMsvId dummy;
       
  1190             if ( aEntry.PartialDownloaded() )
       
  1191                 {
       
  1192                 CMsvEntry* cEntry = iSession.GetEntryL( aEntry.Id() );
       
  1193                 CleanupStack::PushL( cEntry );
       
  1194                 if ( cEntry->HasStoreL() )
       
  1195                     {
       
  1196                     CMsvStore* store = cEntry->ReadStoreL();
       
  1197                     CleanupStack::PushL( store );
       
  1198                     result->SetFetchedContentSize( store->SizeL() );
       
  1199                     CleanupStack::PopAndDestroy( store );
       
  1200                     }
       
  1201 
       
  1202                 // sometimes store size is bigger than msg size
       
  1203                 // even if msg is partially downloaded, then set
       
  1204                 // fetched content size smaller than msg size
       
  1205                 TUint fetchedSize = result->FetchedContentSize();
       
  1206                 TUint contentSize = result->ContentSize();
       
  1207                 if ( (contentSize > 0) && (fetchedSize > contentSize) )
       
  1208                     {
       
  1209                     result->SetFetchedContentSize( contentSize - 1 );
       
  1210                     }
       
  1211 
       
  1212                 CleanupStack::PopAndDestroy( cEntry );
       
  1213                 }
       
  1214             else if ( aEntry.iMtm == KSenduiMtmPop3Uid &&
       
  1215                     iSession.GetEntry( aEntry.Parent(), dummy, parent )
       
  1216                     == KErrNone && parent.PartialDownloaded() )
       
  1217                 {
       
  1218                 // we cant know remote size of pop body part, but
       
  1219                 // we know it is not completely fetched at this point
       
  1220                 // set content size fetchedSize+1 to make framework know that
       
  1221                 // this message is not completely fetched
       
  1222 
       
  1223                 result->SetContentSize( aEntry.iSize+1 );
       
  1224                 result->SetFetchedContentSize( aEntry.iSize );
       
  1225 
       
  1226                 }
       
  1227             else
       
  1228                 {
       
  1229                 result->SetFetchedContentSize( aEntry.iSize );
       
  1230                 }
       
  1231             // This is "gludge-fix" for situation when
       
  1232             // content size is zero and message is complete
       
  1233             // mark sizes to 1 then ui not assume that something
       
  1234             // missing and not try to fetch it
       
  1235             if ( aEntry.iSize == 0 )
       
  1236                 {
       
  1237                 result->SetContentSize(1);
       
  1238                 result->SetFetchedContentSize(1);
       
  1239                 }
       
  1240             }
       
  1241         else
       
  1242             {
       
  1243             result->SetFetchedContentSize( 0 );
       
  1244             }
       
  1245 
       
  1246         CleanupStack::Pop( result );
       
  1247         }
       
  1248     SetFetchStateL( aEntry, aMessageId.Id(), EFalse, *result );
       
  1249     CleanupStack::PopAndDestroy( buf );
       
  1250     return result;
       
  1251     }
       
  1252 
       
  1253 // ---------------------------------------------------------------------------
       
  1254 // ---------------------------------------------------------------------------
       
  1255 CFSMailMessagePart* CIpsPlgMsgMapper::ConvertAttachmentEntry2MessagePartL(
       
  1256     const TMsvEmailEntry& aEntry,
       
  1257     const TFSMailMsgId& aMailBoxId,
       
  1258     const TFSMailMsgId& aMessageId )
       
  1259     {
       
  1260     FUNC_LOG;
       
  1261     CFSMailMessagePart* result( NULL );
       
  1262     HBufC* buffer;
       
  1263     CMsvEntry* cEntry;
       
  1264 
       
  1265     __ASSERT_DEBUG( ( aEntry.iType == KUidMsvAttachmentEntry || 
       
  1266     	aEntry.iType == KUidMsvMessageEntry ),
       
  1267         User::Panic( KIpsPlgPanicCategory, EIpsPlgInvalidEntry ) );
       
  1268 
       
  1269     cEntry = iSession.GetEntryL( aEntry.Id() );
       
  1270     CleanupStack::PushL( cEntry );
       
  1271 
       
  1272     if ( cEntry->HasStoreL() )
       
  1273         {
       
  1274         result = CFSMailMessagePart::NewLC( aMessageId,
       
  1275             TFSMailMsgId( iPlugin.PluginId(), aEntry.Id() ) );
       
  1276 
       
  1277         CMsvStore* store = cEntry->ReadStoreL();
       
  1278         CleanupStack::PushL( store );
       
  1279 
       
  1280         if ( store->IsPresentL( KUidMsgFileMimeHeader ) )
       
  1281             {
       
  1282             CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
       
  1283             mimeHeader->RestoreL( *store );
       
  1284 
       
  1285             // Content-type
       
  1286             if ( aEntry.iType.iUid == KUidMsvMessageEntryValue )
       
  1287                 {
       
  1288                 result->SetContentType( KMimeTypeMultipartRfc822 );
       
  1289                 }
       
  1290             else
       
  1291                 {
       
  1292                 SetContentTypeL( *mimeHeader, *result );
       
  1293                 }
       
  1294 
       
  1295             // Content-description
       
  1296             buffer = HBufC::NewLC(
       
  1297                 mimeHeader->ContentDescription().Length ( ) );
       
  1298             buffer->Des().Copy ( mimeHeader->ContentDescription ( ) );
       
  1299             result->SetContentDescription ( *buffer );
       
  1300             CleanupStack::PopAndDestroy ( buffer );
       
  1301             buffer = NULL;
       
  1302 
       
  1303             // Content-disposition
       
  1304             buffer = HBufC::NewLC(
       
  1305                 mimeHeader->ContentDisposition().Length ( ) );
       
  1306             buffer->Des().Copy( mimeHeader->ContentDisposition() );
       
  1307             result->SetContentDisposition( *buffer );
       
  1308             CleanupStack::PopAndDestroy( buffer );
       
  1309             buffer = NULL;
       
  1310 
       
  1311             // Content-type parameters
       
  1312 
       
  1313             CDesC8Array& sourceArray( mimeHeader->ContentTypeParams() );
       
  1314             CDesCArray& targetArray( result->ContentTypeParameters() );
       
  1315             for ( TInt i=0; i<sourceArray.Count(); i++ )
       
  1316                 {
       
  1317                 buffer = HBufC::NewLC( sourceArray[i].Length() );
       
  1318                 buffer->Des().Copy( sourceArray[i] );
       
  1319                 targetArray.AppendL( buffer->Des() );
       
  1320                 CleanupStack::PopAndDestroy( buffer );
       
  1321                 buffer = NULL;
       
  1322                 i++;
       
  1323                 }
       
  1324 
       
  1325             // Content ID
       
  1326             buffer = HBufC::NewLC(
       
  1327                 mimeHeader->ContentID().Length ( ) );
       
  1328             buffer->Des().Copy( mimeHeader->ContentID() );
       
  1329             result->SetContentIDL( *buffer );
       
  1330             CleanupStack::PopAndDestroy( buffer );
       
  1331             buffer = NULL;
       
  1332 
       
  1333             // Content-class: not supported by Symbian (non-standard field)
       
  1334 
       
  1335             CleanupStack::PopAndDestroy( mimeHeader );
       
  1336             }
       
  1337         // Name
       
  1338         if ( aEntry.iType.iUid == KUidMsvMessageEntryValue )
       
  1339             {
       
  1340             HBufC* att = HBufC::NewLC( aEntry.iDescription.Length() + KEmbeddedMsgExtensionLength );
       
  1341             att->Des().Copy( aEntry.iDescription );
       
  1342             att->Des().Append( KMessageExtension );
       
  1343             result->SetAttachmentNameL( att->Des() );
       
  1344             CleanupStack::PopAndDestroy( att );
       
  1345             }
       
  1346         else
       
  1347             {
       
  1348             result->SetAttachmentNameL( aEntry.iDetails );
       
  1349             }
       
  1350 
       
  1351         // Size
       
  1352         result->SetContentSize( aEntry.iSize );
       
  1353 
       
  1354         if ( aEntry.Complete() )
       
  1355             {
       
  1356             result->SetFetchedContentSize( aEntry.iSize );
       
  1357             }
       
  1358         else
       
  1359             {
       
  1360             result->SetFetchedContentSize( 0 );
       
  1361             }
       
  1362         result->SetMailBoxId( aMailBoxId );
       
  1363         CleanupStack::PopAndDestroy(store);
       
  1364         CleanupStack::Pop( result );
       
  1365         }
       
  1366     SetFetchStateL( aEntry, aMessageId.Id(), ETrue, *result );
       
  1367     CleanupStack::PopAndDestroy( cEntry );
       
  1368 
       
  1369     return result;
       
  1370     }
       
  1371 
       
  1372 // ---------------------------------------------------------------------------
       
  1373 // ---------------------------------------------------------------------------
       
  1374 CFSMailMessagePart* CIpsPlgMsgMapper::ConvertFolderEntry2MessagePartL(
       
  1375     const TMsvEmailEntry& aEntry,
       
  1376     const TFSMailMsgId& aMailBoxId,
       
  1377     const TFSMailMsgId& aMessageId )
       
  1378     {
       
  1379     FUNC_LOG;
       
  1380     CFSMailMessagePart* result( NULL );
       
  1381 
       
  1382     __ASSERT_DEBUG( ( aEntry.iType == KUidMsvFolderEntry ),
       
  1383         User::Panic( KIpsPlgPanicCategory, EIpsPlgInvalidEntry ) );
       
  1384 
       
  1385     TPtrC mimeType = ConvertMultipartMimeType( aEntry.MessageFolderType() );
       
  1386 
       
  1387     if ( mimeType.Length() > 0 )
       
  1388         {
       
  1389         result = CFSMailMessagePart::NewLC(
       
  1390             aMessageId, TFSMailMsgId( iPlugin.PluginId(), aEntry.Id() ) );
       
  1391 
       
  1392         result->SetContentType( mimeType );
       
  1393         result->SetMailBoxId( aMailBoxId );
       
  1394 
       
  1395         CleanupStack::Pop( result );
       
  1396         }
       
  1397 
       
  1398     return result;
       
  1399     }
       
  1400 
       
  1401 
       
  1402 // ---------------------------------------------------------------------------
       
  1403 //
       
  1404 //
       
  1405 // ---------------------------------------------------------------------------
       
  1406 // <cmail> implemented to get rid of cs warning
       
  1407 TInt CIpsPlgMsgMapper::GetAttachmentCountL(
       
  1408     const TMsvEmailEntry& aEntry )
       
  1409     {
       
  1410     FUNC_LOG;
       
  1411     TInt result( KErrNone );
       
  1412 
       
  1413     CMsvEntry *cEntry = iSession.GetEntryL( aEntry.Id() );
       
  1414     CleanupStack::PushL( cEntry );
       
  1415     CImEmailMessage* message = CImEmailMessage::NewLC( *cEntry );
       
  1416 
       
  1417     message->GetAttachmentsListL( cEntry->Entry().Id( ),
       
  1418         CImEmailMessage::EAllAttachments, CImEmailMessage::EThisMessageOnly );
       
  1419 
       
  1420     result = message->Selection().Count();
       
  1421 
       
  1422     CleanupStack::PopAndDestroy( 2, cEntry ); // message, cEntry
       
  1423 
       
  1424     return result;
       
  1425     }
       
  1426 // </cmail>
       
  1427 
       
  1428 // ---------------------------------------------------------------------------
       
  1429 // ---------------------------------------------------------------------------
       
  1430 void CIpsPlgMsgMapper::AttaCheckForIncompleteMsgL(
       
  1431         const TMsvEmailEntry& aEntry,
       
  1432         CFSMailMessage& aMsg )
       
  1433     {
       
  1434     aMsg.ResetFlag( EFSMsgFlag_Attachments );
       
  1435 
       
  1436     TImEmailFolderType ft = aEntry.MessageFolderType();
       
  1437 
       
  1438     if ( ft == EFolderTypeUnknown )
       
  1439         {
       
  1440         CMsvEntry* cEntry = iSession.GetEntryL( aEntry.Id() );
       
  1441         CleanupStack::PushL( cEntry );
       
  1442 
       
  1443         if ( cEntry->HasStoreL() )
       
  1444             {
       
  1445             CMsvStore* store = cEntry->ReadStoreL();
       
  1446             CleanupStack::PushL( store );
       
  1447 
       
  1448             if ( store->IsPresentL( KUidMsgFileMimeHeader ) )
       
  1449                 {
       
  1450                 CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
       
  1451                 mimeHeader->RestoreL( *store );
       
  1452 
       
  1453                 HBufC8* buffer8 = HBufC8::NewLC(
       
  1454                 mimeHeader->ContentType().Length() +
       
  1455                 mimeHeader->ContentSubType().Length() + 1 );
       
  1456 
       
  1457                 buffer8->Des().Append( mimeHeader->ContentType() );
       
  1458                 buffer8->Des().Append( KSlash );
       
  1459                 buffer8->Des().Append( mimeHeader->ContentSubType() );
       
  1460 
       
  1461                 HBufC* buffer = HBufC::NewLC( buffer8->Length() );
       
  1462                 buffer->Des().Copy( buffer8->Des() );
       
  1463 
       
  1464                 if ( buffer->CompareF( KMimeTypeMultipartMixed ) == 0 ||
       
  1465                      buffer->CompareF( KMimeTypeMultipartRelated ) == 0 )
       
  1466                     {
       
  1467                     aMsg.SetFlag( EFSMsgFlag_Attachments );
       
  1468                     if ( !aEntry.Attachment() )
       
  1469                     	{
       
  1470                     	SetAttachmentFlagL( aEntry, ETrue );
       
  1471                     	}
       
  1472                     }
       
  1473 
       
  1474                 CleanupStack::PopAndDestroy( 3, mimeHeader );
       
  1475                 }
       
  1476 
       
  1477             CleanupStack::PopAndDestroy( store );
       
  1478             }
       
  1479         CleanupStack::PopAndDestroy( cEntry );
       
  1480         }
       
  1481     else if ( ft == EFolderTypeMixed || ft == EFolderTypeRelated )
       
  1482         {
       
  1483         aMsg.SetFlag( EFSMsgFlag_Attachments );
       
  1484         if ( !aEntry.Attachment() )
       
  1485         	{
       
  1486         	SetAttachmentFlagL( aEntry, ETrue );
       
  1487         	}
       
  1488         }
       
  1489 
       
  1490     if ( !aMsg.IsFlagSet( EFSMsgFlag_Attachments ) && aEntry.Attachment() )
       
  1491     	{
       
  1492     	SetAttachmentFlagL( aEntry, EFalse );
       
  1493     	}
       
  1494     }
       
  1495 // </cmail>
       
  1496 
       
  1497 
       
  1498 // ---------------------------------------------------------------------------
       
  1499 // ---------------------------------------------------------------------------
       
  1500 // <cmail>
       
  1501 void CIpsPlgMsgMapper::SetAttachmentFlagL( const TMsvEmailEntry& aEntry,
       
  1502 										   TBool aHasAttachment )
       
  1503 	{
       
  1504 	FUNC_LOG;
       
  1505 	CMsvEntry* cEntry = iSession.GetEntryL( aEntry.Id() );
       
  1506 	CleanupStack::PushL( cEntry );
       
  1507 	// Only text/calendar part included as attachment
       
  1508 	TMsvEmailEntry entryToBeChanged( aEntry );
       
  1509 	entryToBeChanged.SetAttachment( aHasAttachment );
       
  1510 	CIpsPlgOperationWait* waiter = CIpsPlgOperationWait::NewLC();
       
  1511 	CMsvOperation* ops = cEntry->ChangeL( entryToBeChanged, waiter->iStatus );
       
  1512 	CleanupStack::PushL( ops );
       
  1513 	waiter->Start();
       
  1514 	CleanupStack::PopAndDestroy( 3, cEntry );
       
  1515 	}
       
  1516 // </cmail>
       
  1517 
       
  1518 // <cmail>
       
  1519 // ---------------------------------------------------------------------------
       
  1520 // ---------------------------------------------------------------------------
       
  1521 void CIpsPlgMsgMapper::GetCharsetParameterL(
       
  1522     const TMsvEmailEntry& aEntry, TDes& aContentType )
       
  1523     {
       
  1524     FUNC_LOG;
       
  1525 
       
  1526     CMsvEntry* cEntry = iSession.GetEntryL( aEntry.Id() );
       
  1527     CleanupStack::PushL( cEntry );
       
  1528     if ( cEntry->HasStoreL() )
       
  1529         {
       
  1530         CMsvStore* store = cEntry->ReadStoreL();
       
  1531         CleanupStack::PushL( store );
       
  1532         if ( store->IsPresentL( KUidMsgFileMimeHeader ) )
       
  1533             {
       
  1534             CImMimeHeader* mimeHeader = CImMimeHeader::NewLC();
       
  1535             mimeHeader->RestoreL( *store );
       
  1536 
       
  1537             TInt count = mimeHeader->ContentTypeParams().MdcaCount();
       
  1538             INFO_1("# of CT params: %d", count);
       
  1539             for ( TInt i = 0; i < count; i++ )
       
  1540                 {
       
  1541                 TPtrC8 key8 = mimeHeader->ContentTypeParams().MdcaPoint( i );
       
  1542                 INFO_1("%S", &key8);
       
  1543                 TPtr16 keyUppercase16 = HBufC::NewLC( key8.Length() )->Des();
       
  1544                 keyUppercase16.Copy( key8 );
       
  1545                 keyUppercase16.UpperCase();
       
  1546                 if ( keyUppercase16.Compare( KCharsetTag ) == 0 &&
       
  1547                      count >= i+1 ) // prevent possible indexing over array limits
       
  1548                     {
       
  1549                     // Starting to append text to the current content-type header..
       
  1550                     // First, add ';'
       
  1551                     aContentType.Append( KCharSemicolon );
       
  1552 
       
  1553                     // Then, 'CHARSET'
       
  1554                     aContentType.Append( keyUppercase16 );
       
  1555 
       
  1556                     // '='
       
  1557                     aContentType.Append( KCharEquals );
       
  1558 
       
  1559                     // Finally, the actual charset value (e.g. 'utf-8' or similar)
       
  1560                     TPtrC8 value8 = mimeHeader->ContentTypeParams().MdcaPoint( i+1 );
       
  1561                     TPtr16 value16 = HBufC::NewLC( value8.Length() )->Des();
       
  1562                     value16.Copy( value8 );
       
  1563                     aContentType.Append( value16 );
       
  1564                     CleanupStack::PopAndDestroy(); // value16
       
  1565                     }
       
  1566                 CleanupStack::PopAndDestroy(); // keyUppercase16
       
  1567                 } // for loop
       
  1568             CleanupStack::PopAndDestroy( mimeHeader );
       
  1569             }
       
  1570         CleanupStack::PopAndDestroy( store );
       
  1571         }
       
  1572     CleanupStack::PopAndDestroy( cEntry );
       
  1573     }
       
  1574 // </cmail>