mmsengine/mmsmessage/src/mmsmessageoperation.cpp
changeset 31 ebfee66fde93
child 47 5b14749788d7
child 70 a15d9966050f
equal deleted inserted replaced
30:6a20128ce557 31:ebfee66fde93
       
     1 /*
       
     2 * Copyright (c) 2002-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:  
       
    15 *      CMsvOperation class for MMS message creation.
       
    16 *
       
    17 */
       
    18 
       
    19 
       
    20 
       
    21 // INCLUDE FILES
       
    22 #include    <msvids.h>
       
    23 #include    <msvstore.h>
       
    24 #include    <mtmdef.h>
       
    25 #include    <mtmuids.h> 
       
    26 #include    <mmsvattachmentmanager.h>
       
    27 #include    <cmsvattachment.h>
       
    28 #include    <cmsvmimeheaders.h>
       
    29 
       
    30 #include    "mmsmessageoperation.h"
       
    31 #include    "mmsconst.h"
       
    32 #include    "mmssettings.h"
       
    33 #include    "mmsheaders.h"
       
    34 #include    "mmsgenutils.h"
       
    35 #include    "mmsownnumber.h"
       
    36 
       
    37 // EXTERNAL DATA STRUCTURES
       
    38 
       
    39 // EXTERNAL FUNCTION PROTOTYPES  
       
    40 extern void gPanic( TMmsPanic aPanic );
       
    41 
       
    42 // CONSTANTS
       
    43 const TInt KMmsRecipientGranularity = 6;
       
    44 
       
    45 // MACROS
       
    46 
       
    47 // LOCAL CONSTANTS AND MACROS
       
    48 
       
    49 // MODULE DATA STRUCTURES
       
    50 
       
    51 // LOCAL FUNCTION PROTOTYPES
       
    52 
       
    53 // ==================== LOCAL FUNCTIONS ====================
       
    54 //
       
    55 
       
    56 // ================= MEMBER FUNCTIONS =======================
       
    57 
       
    58 // C++ default constructor can NOT contain any code, that
       
    59 // might leave.
       
    60 //
       
    61 
       
    62 CMmsMessageOperation::~CMmsMessageOperation()
       
    63     {
       
    64     Cancel();
       
    65     delete iSourceStore;
       
    66     delete iTargetStore;
       
    67     delete iSourceEntry;
       
    68     delete iTargetEntry;
       
    69     delete iMsvOperation;
       
    70     delete iSettings;
       
    71     delete iNewMmsHeaders;
       
    72     delete iDescription;
       
    73     }
       
    74 
       
    75 // ---------------------------------------------------------
       
    76 // CMmsMessageOperation::CreateNewL
       
    77 //
       
    78 // ---------------------------------------------------------
       
    79 EXPORT_C CMmsMessageOperation* CMmsMessageOperation::CreateNewL(
       
    80     TRequestStatus& aObserverRequestStatus,
       
    81     CMsvSession& aMsvSession,
       
    82     TMsvId aDestination,
       
    83     TMsvId aServiceId,
       
    84     TBool  aVisible,
       
    85     TBool  aInPreparation )
       
    86     {
       
    87 
       
    88     TMsvPartList parts = 0;
       
    89 
       
    90     CMmsMessageOperation* self = new(ELeave) CMmsMessageOperation(
       
    91         aObserverRequestStatus,
       
    92         aMsvSession,
       
    93         aDestination,
       
    94         parts,
       
    95         aServiceId,
       
    96         aVisible,
       
    97         aInPreparation );
       
    98     CleanupStack::PushL( self );
       
    99     self->ConstructL( KMsvNullIndexEntryId, ENew );
       
   100     CleanupStack::Pop( self );
       
   101     return self;
       
   102     }
       
   103 
       
   104 // ---------------------------------------------------------
       
   105 // CMmsMessageOperation::CreateReplyL
       
   106 //
       
   107 // ---------------------------------------------------------
       
   108 EXPORT_C CMmsMessageOperation* CMmsMessageOperation::CreateReplyL(
       
   109     TRequestStatus& aObserverRequestStatus,
       
   110     CMsvSession& aMsvSession,
       
   111     TMsvId aMessageId,
       
   112     TMsvId aDestination,
       
   113     TMsvPartList aPartList,
       
   114     TMsvId aServiceId,
       
   115     TBool  aVisible,
       
   116     TBool  aInPreparation )
       
   117     {
       
   118     if ( aMessageId == KMsvNullIndexEntryId )
       
   119         {
       
   120         // if no source cannot reply
       
   121         User::Leave( KErrArgument );
       
   122         }
       
   123 
       
   124     // Set the attachment part flag off
       
   125     TMsvPartList parts = aPartList & ~KMsvMessagePartAttachments;
       
   126 
       
   127     CMmsMessageOperation* self = new(ELeave) CMmsMessageOperation(
       
   128         aObserverRequestStatus,
       
   129         aMsvSession,
       
   130         aDestination,
       
   131         parts,
       
   132         aServiceId,
       
   133         aVisible,
       
   134         aInPreparation );
       
   135     CleanupStack::PushL( self );
       
   136     self->ConstructL( aMessageId, EReply );
       
   137     CleanupStack::Pop( self );
       
   138     return self;
       
   139     }
       
   140 
       
   141 // ---------------------------------------------------------
       
   142 // CMmsMessageOperation::CreateForwardL
       
   143 //
       
   144 // ---------------------------------------------------------
       
   145 EXPORT_C CMmsMessageOperation* CMmsMessageOperation::CreateForwardL(
       
   146     TRequestStatus& aObserverRequestStatus,
       
   147     CMsvSession& aMsvSession,
       
   148     TMsvId aMessageId,
       
   149     TMsvId aDestination,
       
   150     TMsvPartList aPartList,
       
   151     TMsvId aServiceId,
       
   152     TBool  aVisible,
       
   153     TBool  aInPreparation )
       
   154     {
       
   155 
       
   156     if ( aMessageId == KMsvNullIndexEntryId )
       
   157         {
       
   158         // if no source cannot forward
       
   159         User::Leave( KErrArgument );
       
   160         }
       
   161 
       
   162     // Set the attachment part flag on
       
   163     TMsvPartList parts = aPartList | KMsvMessagePartAttachments;
       
   164 
       
   165     CMmsMessageOperation* self = new(ELeave) CMmsMessageOperation(
       
   166         aObserverRequestStatus,
       
   167         aMsvSession,
       
   168         aDestination,
       
   169         parts,
       
   170         aServiceId,
       
   171         aVisible,
       
   172         aInPreparation );
       
   173     CleanupStack::PushL( self );
       
   174     self->ConstructL( aMessageId, EForward );
       
   175     CleanupStack::Pop( self );
       
   176     return self;
       
   177     }
       
   178 
       
   179 // ---------------------------------------------------------
       
   180 // CMmsMessageOperation::CreateForwardWithoutRetrievalL
       
   181 //
       
   182 // ---------------------------------------------------------
       
   183 //
       
   184 EXPORT_C TMsvId CMmsMessageOperation::CreateForwardWithoutRetrievalL( 
       
   185     CMsvSession& aMsvSession,
       
   186     const CMmsHeaders& aNotificationHeaders,
       
   187     const TMsvId aRelatedEntry,
       
   188     const TMsvId aDestination,
       
   189     TMsvId aServiceId,
       
   190     TBool  aVisible,
       
   191     TBool  aInPreparation )
       
   192     {
       
   193     //
       
   194     // Create entry
       
   195     //
       
   196     TMsvEntry entry;
       
   197     CMsvEntry* cMsvEntry = CMsvEntry::NewL( 
       
   198         aMsvSession, aDestination, TMsvSelectionOrdering() );
       
   199     CleanupStack::PushL( cMsvEntry );
       
   200     entry.iType = KUidMsvMessageEntry;
       
   201     entry.iServiceId = aServiceId;
       
   202     entry.iMtm = KUidMsgMMSNotification;
       
   203     entry.iMtmData1 |= KMmsMessageForwardReq;
       
   204     entry.iDate.UniversalTime();
       
   205     entry.SetInPreparation( aInPreparation );    
       
   206     entry.SetVisible( aVisible );
       
   207     cMsvEntry->CreateL( entry );
       
   208 
       
   209     //
       
   210     // Get MMS settings
       
   211     //
       
   212     CMmsSettings* settings = CMmsSettings::NewL();
       
   213     CleanupStack::PushL( settings );
       
   214     settings->LoadSettingsL();
       
   215     
       
   216     //
       
   217     // Create headers object
       
   218     //
       
   219     CMmsHeaders* headers = CMmsHeaders::NewL( settings->MmsVersion() );
       
   220     CleanupStack::PushL( headers );
       
   221     headers->SetSettings( settings );
       
   222     
       
   223     //
       
   224     // Set ContentLocation to headers object
       
   225     //
       
   226     headers->SetContentLocationL( aNotificationHeaders.ContentLocation() );
       
   227     headers->SetRelatedEntry( aRelatedEntry );
       
   228     // Following entries are copied to the forward request on purpose
       
   229     // even though they do not belong to the PDU sent to the network
       
   230     headers->SetSubjectL( aNotificationHeaders.Subject() );
       
   231     headers->SetMessageSize( aNotificationHeaders.MessageSize() );   
       
   232     headers->SetMessageClass( aNotificationHeaders.MessageClass() );
       
   233     headers->SetMessagePriority( aNotificationHeaders.MessagePriority() );
       
   234     // Set Report Allowed according to settings
       
   235     headers->SetReportAllowed( settings->DeliveryReportSendingAllowed() );
       
   236 
       
   237     //
       
   238     // Check diskspace before storing headers
       
   239     //
       
   240     RFs fs = aMsvSession.FileSession();
       
   241     if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL(
       
   242         &fs, 
       
   243         headers->Size(),
       
   244         aMsvSession.CurrentDriveL() ) )
       
   245         {
       
   246         User::Leave( KErrDiskFull );
       
   247         }
       
   248 
       
   249     //
       
   250     // Store headers to MessageStore
       
   251     //
       
   252     cMsvEntry->SetEntryL( entry.Id() );
       
   253     CMsvStore* store = cMsvEntry->EditStoreL();
       
   254     CleanupStack::PushL( store );   // ***
       
   255     headers->StoreL( *store );
       
   256     store->CommitL();
       
   257 
       
   258     //
       
   259     // Update and save index entry
       
   260     //
       
   261     entry.iSize = headers->Size();
       
   262     cMsvEntry->ChangeL( entry );
       
   263 
       
   264     CleanupStack::PopAndDestroy( store );
       
   265     CleanupStack::PopAndDestroy( headers );
       
   266     CleanupStack::PopAndDestroy( settings );
       
   267     CleanupStack::PopAndDestroy( cMsvEntry );
       
   268     return entry.Id();
       
   269     }
       
   270 
       
   271 // ---------------------------------------------------------
       
   272 // CMmsMessageOperation::ConstructL
       
   273 //
       
   274 // ---------------------------------------------------------
       
   275 void CMmsMessageOperation::ConstructL( 
       
   276             TMsvId aMessageId, 
       
   277             TMmsOperation aOperation )
       
   278     {
       
   279 
       
   280     iOrigMessageId = aMessageId;
       
   281     iOperation = aOperation;
       
   282     iDataMember = KMsvNullIndexEntryId;
       
   283     iState = ECreateMmsHeaders;
       
   284     iAttachmentsSize = 0;
       
   285     iDescription = NULL;
       
   286     iOriginalRoot = 0;
       
   287     iAttachmentCount = 0;
       
   288     iNewRoot = -1; // not found yet
       
   289 
       
   290     // Create new message entry object to work with
       
   291     // iDestinationId is the target folder
       
   292     iTargetEntry = CMsvEntry::NewL( 
       
   293         iMsvSession, iDestinationId, TMsvSelectionOrdering() );
       
   294     // Show invisible entries too.
       
   295     iTargetEntry->SetSortTypeL( TMsvSelectionOrdering( 
       
   296         KMsvNoGrouping, EMsvSortByNone, ETrue ));
       
   297 
       
   298     if ( iOrigMessageId != KMsvNullIndexEntryId )
       
   299         {
       
   300         // Create entry for the original entry
       
   301         iSourceEntry = CMsvEntry::NewL( 
       
   302             iMsvSession, iOrigMessageId, TMsvSelectionOrdering() );
       
   303         // Show invisible entries too.
       
   304         iSourceEntry->SetSortTypeL( TMsvSelectionOrdering( 
       
   305             KMsvNoGrouping, EMsvSortByNone, ETrue ));
       
   306         // if we have an original entry, it will be read    
       
   307         iSourceStore = iSourceEntry->ReadStoreL();    
       
   308         }
       
   309 
       
   310     iSettings = CMmsSettings::NewL();
       
   311     
       
   312     // Add this objet to the scheduler
       
   313     CActiveScheduler::Add( this );
       
   314 
       
   315     ChangeStateL();
       
   316 
       
   317     iObserverRequestStatus = KRequestPending;
       
   318 
       
   319     SetActive();
       
   320 
       
   321     }
       
   322 
       
   323 // ---------------------------------------------------------
       
   324 // CMmsMessageOperation::FinalProgress
       
   325 //
       
   326 // ---------------------------------------------------------
       
   327 //
       
   328 EXPORT_C const TDesC8& CMmsMessageOperation::FinalProgress()
       
   329    {
       
   330     __ASSERT_ALWAYS( !IsActive(), gPanic( EMmsActiveInFinalProgress ));
       
   331     const TDesC8* progress = &KNullDesC8();
       
   332     TRAPD( leave, {progress = &ProgressL();} );
       
   333     __ASSERT_ALWAYS( leave == KErrNone, gPanic( EMmsFinalProgressFailed ));
       
   334     return *progress;
       
   335    }
       
   336 
       
   337 // ---------------------------------------------------------
       
   338 // CMmsMessageOperation::ProgressL
       
   339 //
       
   340 // ---------------------------------------------------------
       
   341 //
       
   342 const TDesC8& CMmsMessageOperation::ProgressL()
       
   343    {
       
   344    if (iState == EFinished )
       
   345        {
       
   346        iDataMember() = iNewMessageId;
       
   347        }
       
   348    return iDataMember;
       
   349    }
       
   350 
       
   351 // ---------------------------------------------------------
       
   352 // CMmsMessageOperation::RunL
       
   353 //
       
   354 // ---------------------------------------------------------
       
   355 //
       
   356 void CMmsMessageOperation::RunL()
       
   357     {
       
   358 
       
   359     if (iStatus.Int() != KErrNone )
       
   360         {
       
   361         ErrorRecovery( iStatus.Int() );
       
   362         return;
       
   363         }
       
   364 
       
   365     // Check the progress status in case that real progress is available.
       
   366     // only entry creation returns correct progress info
       
   367     if ( iState == ECreateMessageEntry ) 
       
   368         {
       
   369         TMsvLocalOperationProgress  progress = 
       
   370             McliUtils::GetLocalProgressL( *iMsvOperation );
       
   371         if ( progress.iError != KErrNone )
       
   372             {
       
   373             ErrorRecovery( progress.iError );
       
   374             return;
       
   375             }
       
   376         }
       
   377     if ( iState != EFinished )
       
   378         {
       
   379         TRAPD( error, SelectAndChangeToNextStateL() );
       
   380         if ( error )
       
   381             {
       
   382             ErrorRecovery( error );
       
   383             return;
       
   384             }
       
   385         else if ( iState != EFinished )
       
   386             {
       
   387             // Here we go again.
       
   388             SetActive();
       
   389             }
       
   390         else
       
   391             {
       
   392             // keep LINT happy
       
   393             }
       
   394         }
       
   395     }
       
   396 
       
   397 // ---------------------------------------------------------
       
   398 // CMmsMessageOperation::CMmsMessageOperation
       
   399 //
       
   400 // ---------------------------------------------------------
       
   401 CMmsMessageOperation::CMmsMessageOperation(
       
   402     TRequestStatus& aObserverRequestStatus, 
       
   403     CMsvSession& aMsvSession, 
       
   404     TMsvId aDestination, 
       
   405     TMsvPartList aPartList,
       
   406     TMsvId aServiceId,
       
   407     TBool aVisible,
       
   408     TBool  aInPreparation )
       
   409     : CMsvOperation( aMsvSession, EPriorityStandard, aObserverRequestStatus ),
       
   410       iDestinationId( aDestination ),
       
   411       iPartList( aPartList ),
       
   412       iServiceId( aServiceId ),
       
   413       iSettings( NULL ),
       
   414       iNewMmsHeaders( NULL ),
       
   415       iVisible( aVisible ),
       
   416       iInPreparation ( aInPreparation )
       
   417     {
       
   418     }
       
   419 
       
   420 // ---------------------------------------------------------
       
   421 // CMmsMessageOperation::ErrorRecovery
       
   422 //
       
   423 // ---------------------------------------------------------
       
   424 void CMmsMessageOperation::ErrorRecovery( TInt aError )
       
   425     {
       
   426     // Delete entry and store objects associated with the new entry.
       
   427     // If an error is encountered, store is not committed, and the
       
   428     // entry under construction is deleted.
       
   429     // Deleting the message entry deletes all attachments that are
       
   430     // stored in the message store. Linked attachments are not deleted.
       
   431     delete iTargetStore;
       
   432     iTargetStore = NULL;
       
   433     delete iTargetEntry;
       
   434     iTargetEntry = NULL;
       
   435     // Remove the new message entry
       
   436     if ( iNewMessageId != KMsvNullIndexEntryId )
       
   437         {
       
   438         iMsvSession.RemoveEntry( iNewMessageId );
       
   439         }
       
   440     delete iSourceStore;
       
   441     iSourceStore = NULL;
       
   442     delete iSourceEntry;
       
   443     iSourceEntry = NULL;
       
   444         
       
   445     // complete the observer with error
       
   446     TRequestStatus* status = &iObserverRequestStatus;
       
   447     User::RequestComplete( status, aError );
       
   448     }
       
   449 
       
   450 // ---------------------------------------------------------
       
   451 // CMmsMessageOperation::ChangeStateL
       
   452 //
       
   453 // ---------------------------------------------------------
       
   454 void CMmsMessageOperation::ChangeStateL()
       
   455     {
       
   456     switch (iState)
       
   457         {
       
   458         case ECreateMmsHeaders:
       
   459             CreateNewMmsHeaderL();
       
   460             break;
       
   461         case ECreateMessageEntry:
       
   462             CreateMessageEntryL();
       
   463             break;
       
   464         case ECopyAttachments:
       
   465             CopyAttachmentsL();
       
   466             // Attachments are copied one by one.
       
   467             // We stay in ECopyAttachment state until all attachments have
       
   468             // been handled.
       
   469             iCurrentAttachment++;
       
   470             break;
       
   471         case EStoreMmsHeaders:
       
   472             StoreMmsHeadersL();
       
   473             break;
       
   474         case ECompleteMessage:
       
   475             CompleteMessageL();
       
   476             break;
       
   477         case EFinished:
       
   478             {
       
   479             TRequestStatus* status = &iObserverRequestStatus;
       
   480             User::RequestComplete( status, KErrNone );
       
   481             }
       
   482             break;
       
   483         default:
       
   484             // We are never supposed to be here.
       
   485             User::LeaveIfError( KErrNotSupported );
       
   486             break;
       
   487         }
       
   488     }
       
   489 
       
   490 // ---------------------------------------------------------
       
   491 // CMmsMessageOperation::RequestComplete
       
   492 //
       
   493 // ---------------------------------------------------------
       
   494 void CMmsMessageOperation::RequestComplete( TInt aError )
       
   495     {
       
   496     iStatus = KRequestPending;
       
   497     TRequestStatus* status = &iStatus;
       
   498     User::RequestComplete( status, aError );
       
   499     }
       
   500 
       
   501 // ---------------------------------------------------------
       
   502 // CMmsMessageOperation::SelectNextStateL
       
   503 //
       
   504 // ---------------------------------------------------------
       
   505 void CMmsMessageOperation::SelectNextStateL()
       
   506     {
       
   507 
       
   508     switch (iState)
       
   509         {
       
   510         case ECreateMmsHeaders:
       
   511             iState = ECreateMessageEntry;
       
   512             break;
       
   513         case ECreateMessageEntry:
       
   514             {
       
   515             // Get the id of new entry
       
   516             TMsvLocalOperationProgress progress = 
       
   517                 McliUtils::GetLocalProgressL( *iMsvOperation );
       
   518             iNewMessageId = progress.iId;
       
   519             
       
   520             iTargetEntry->SetEntryL( iNewMessageId );
       
   521             iTargetStore = iTargetEntry->EditStoreL();
       
   522             }
       
   523             // Fall through on purpose.
       
   524             // Attachment are copied before MMS headers are saved
       
   525             // so that we can adjust the root attachment id.
       
   526             // If the message has no attachments, we proceed directly
       
   527             // to saving MMS headers.
       
   528         case ECopyAttachments:
       
   529             if ( iPartList & KMsvMessagePartAttachments &&
       
   530                 iCurrentAttachment < iAttachmentCount )
       
   531                 {
       
   532                 iState = ECopyAttachments;
       
   533                 }
       
   534             else
       
   535                 {
       
   536                 iState = EStoreMmsHeaders;
       
   537                 }
       
   538             break;
       
   539         case EStoreMmsHeaders:
       
   540             iState = ECompleteMessage;
       
   541             break;
       
   542         case ECompleteMessage:
       
   543             iState = EFinished;
       
   544             break;
       
   545         default:
       
   546             User::LeaveIfError( KErrNotSupported );
       
   547         }
       
   548     }
       
   549 
       
   550 // ---------------------------------------------------------
       
   551 // CMmsMessageOperation::SelectAndChangeToNextStateL
       
   552 //
       
   553 // ---------------------------------------------------------
       
   554 void CMmsMessageOperation::SelectAndChangeToNextStateL()
       
   555     {
       
   556     SelectNextStateL();
       
   557     ChangeStateL();
       
   558     }
       
   559 
       
   560 // ---------------------------------------------------------
       
   561 // CMmsMessageOperation::CreateNewMmsHeaderL
       
   562 //
       
   563 // ---------------------------------------------------------
       
   564 void CMmsMessageOperation::CreateNewMmsHeaderL()
       
   565     {
       
   566     // Load settings
       
   567     iSettings->LoadSettingsL();
       
   568 
       
   569     // Create MMS headers object
       
   570     CMmsHeaders* originalMmsHeaders = NULL;
       
   571     delete iNewMmsHeaders;
       
   572     iNewMmsHeaders = NULL;
       
   573 
       
   574     if ( ( iOperation == EReply ) ||
       
   575          ( iOperation == EForward ))
       
   576         {
       
   577         // Copy appropriate parts from original MMS headers
       
   578         // We checked in the beginning that we have a source entry
       
   579         originalMmsHeaders = CMmsHeaders::NewL( iSettings->MmsVersion() );
       
   580         CleanupStack::PushL( originalMmsHeaders );     // ***
       
   581         // Get the original message's MMS headers
       
   582         originalMmsHeaders->RestoreL( *iSourceStore );
       
   583         // Copy data
       
   584         TBool isReply = iOperation == EReply ? ETrue : EFalse;
       
   585         
       
   586         iNewMmsHeaders = originalMmsHeaders->CopyL( iPartList, isReply, iMsvSession.FileSession() );
       
   587         
       
   588         // Remove own number from list if creating Reply
       
   589         if ( iOperation == EReply )
       
   590             {
       
   591             CDesCArray* recipientList = new ( ELeave )CDesCArrayFlat( KMmsRecipientGranularity );
       
   592             CleanupStack::PushL( recipientList );
       
   593             TInt i;
       
   594             for ( i = 0; i < iNewMmsHeaders->ToRecipients().MdcaCount(); i++ )
       
   595                 {
       
   596                 recipientList->AppendL(
       
   597                     TMmsGenUtils::PureAddress( iNewMmsHeaders->ToRecipients().MdcaPoint( i ) ) );
       
   598                 }
       
   599             for ( i = 0; i < iNewMmsHeaders->CcRecipients().MdcaCount(); i++ )
       
   600                 {
       
   601                 recipientList->AppendL(
       
   602                     TMmsGenUtils::PureAddress( iNewMmsHeaders->CcRecipients().MdcaPoint( i ) ) );
       
   603                 }
       
   604             for ( i = 0; i < iNewMmsHeaders->BccRecipients().MdcaCount(); i++ )
       
   605                 {
       
   606                 recipientList->AppendL(
       
   607                     TMmsGenUtils::PureAddress( iNewMmsHeaders->BccRecipients().MdcaPoint( i ) ) );
       
   608                 }
       
   609                 
       
   610            
       
   611             CleanupStack::PopAndDestroy( recipientList );
       
   612             }
       
   613 
       
   614         // the root must always be retained if it is specified
       
   615         if ( iPartList & KMsvMessagePartAttachments )
       
   616             {
       
   617             iOriginalRoot = originalMmsHeaders->MessageRoot();
       
   618             iNewMmsHeaders->SetRootContentIdL( originalMmsHeaders->RootContentId() );
       
   619             }
       
   620         CleanupStack::PopAndDestroy( originalMmsHeaders );
       
   621         }
       
   622     else
       
   623         {
       
   624         // No original message available
       
   625         iNewMmsHeaders = CMmsHeaders::NewL( iSettings->MmsVersion() );
       
   626         }
       
   627     // Reset MMS settings
       
   628     iNewMmsHeaders->SetSettings( iSettings );
       
   629 
       
   630     RequestComplete( KErrNone );
       
   631 
       
   632     }
       
   633 
       
   634 // ---------------------------------------------------------
       
   635 // CMmsMessageOperation::CreateMessageEntryL
       
   636 //
       
   637 // ---------------------------------------------------------
       
   638 void CMmsMessageOperation::CreateMessageEntryL()
       
   639     {
       
   640 
       
   641     // Create new message entry
       
   642 
       
   643     // CREATE NEW INDEX ENTRY
       
   644     TMsvEntry entry;
       
   645     entry.iType = KUidMsvMessageEntry;
       
   646     entry.iServiceId = iServiceId;
       
   647     entry.iMtm = KUidMsgTypeMultimedia;
       
   648     entry.iDate.UniversalTime();
       
   649 
       
   650     // Set iMtmData extension flags
       
   651     if ( iOperation == EForward )
       
   652         {
       
   653         entry.iMtmData1 |= KMmsMessageForwarded;
       
   654         }
       
   655 
       
   656     // Set iDetails
       
   657     TPtrC to;
       
   658     if ( iNewMmsHeaders->ToRecipients().Count() > 0 )
       
   659         {
       
   660         to.Set( iNewMmsHeaders->ToRecipients()[0] );
       
   661         }
       
   662     HBufC* buffer = HBufC::NewL( KMmsMaxDescription );
       
   663     CleanupStack::PushL( buffer );
       
   664     TPtr pBuffer = buffer->Des();
       
   665 
       
   666     if ( TMmsGenUtils::IsValidMMSPhoneAddress( to, EFalse ) )
       
   667         {
       
   668         if ( TMmsGenUtils::GenerateDetails( to,
       
   669             pBuffer, KMmsMaxDescription, iMsvSession.FileSession() ) == KErrNone )
       
   670             {
       
   671             entry.iDetails.Set( pBuffer );
       
   672             }
       
   673         else
       
   674             {
       
   675             entry.iDetails.Set( to );
       
   676             }
       
   677         }
       
   678     else
       
   679         {
       
   680         entry.iDetails.Set( to );
       
   681         }
       
   682 
       
   683     // Set iDescription
       
   684     entry.iDescription.Set( iNewMmsHeaders->Subject());
       
   685     // if no subject, copy old description
       
   686     if ( ( iPartList & KMsvMessagePartAttachments ) &&
       
   687          ( iOrigMessageId != KMsvNullIndexEntryId ) &&
       
   688          ( entry.iDescription.Length() == 0 ) )
       
   689         {
       
   690         // Copy the old description, no need to scan message files again ...
       
   691         TPtrC pp;
       
   692         pp.Set( iSourceEntry->Entry().iDescription );
       
   693         delete iDescription;
       
   694         iDescription = NULL;
       
   695         iDescription = pp.AllocL();
       
   696         entry.iDescription.Set( *iDescription );
       
   697         }
       
   698 
       
   699     // The following ones will be set in completion.
       
   700     entry.SetInPreparation( ETrue );    
       
   701     entry.SetVisible( EFalse );         
       
   702     entry.iSize = 0;
       
   703     
       
   704     // Create the new message entry asynchronically.
       
   705     delete iMsvOperation;
       
   706     iMsvOperation = NULL;
       
   707     iCurrentAttachment = 0;
       
   708     
       
   709     if ( iPartList & KMsvMessagePartAttachments )
       
   710         {
       
   711         // get number of attachments
       
   712         MMsvAttachmentManager& sourceAttaMan = iSourceStore->AttachmentManagerL();
       
   713         iAttachmentCount = sourceAttaMan.AttachmentCount();
       
   714         }
       
   715 
       
   716     // Check that sufficient disk space available
       
   717     // for index entry
       
   718     iTargetEntry->SetEntryL( iDestinationId );
       
   719     RFs fs = iMsvSession.FileSession();
       
   720     if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( &fs, 
       
   721         sizeof( TMsvEntry ) 
       
   722         + entry.iDescription.Length() 
       
   723         + entry.iDetails.Length(),
       
   724         iMsvSession.CurrentDriveL() ) )
       
   725             {
       
   726             // we use standard error code here
       
   727             User::Leave( KErrDiskFull );
       
   728             }
       
   729     // Target entry still points to destination folder
       
   730     iMsvOperation = iTargetEntry->CreateL( entry, iStatus );
       
   731 
       
   732     CleanupStack::PopAndDestroy( buffer );
       
   733     }
       
   734 
       
   735 // ---------------------------------------------------------
       
   736 // CMmsMessageOperation::StoreMmsHeadersL
       
   737 //
       
   738 // ---------------------------------------------------------
       
   739 void CMmsMessageOperation::StoreMmsHeadersL()
       
   740     {
       
   741 
       
   742     // save the correct id for new root
       
   743     if ( iPartList & KMsvMessagePartAttachments && 
       
   744         iNewRoot != -1 )
       
   745         {
       
   746         MMsvAttachmentManager& targetAttaMan = iTargetStore->AttachmentManagerL();
       
   747         CMsvAttachment* targetAtta = targetAttaMan.GetAttachmentInfoL( iNewRoot );
       
   748         CleanupStack::PushL( targetAtta );
       
   749         iNewMmsHeaders->SetMessageRoot( targetAtta->Id() );
       
   750         CleanupStack::PopAndDestroy( targetAtta );
       
   751         }
       
   752     else
       
   753         {
       
   754         iNewMmsHeaders->SetRootContentIdL( TPtrC8() );
       
   755         }
       
   756         
       
   757 
       
   758     // Check that sufficient disk space available
       
   759     // for MMS headers stream
       
   760     RFs fs = iMsvSession.FileSession();
       
   761     if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( &fs, 
       
   762         iNewMmsHeaders->Size(),
       
   763         iMsvSession.CurrentDriveL() ) )
       
   764         {
       
   765         // we use standard error code here
       
   766         User::Leave( KErrDiskFull );
       
   767         }
       
   768 
       
   769     // Externalize MMS headers
       
   770     iNewMmsHeaders->StoreL( *iTargetStore );
       
   771     // This is the last stage in creating the new entry.
       
   772     // Now the store is committed and deleted.
       
   773     iTargetStore->CommitL();
       
   774     delete iTargetStore;
       
   775     iTargetStore = NULL;
       
   776 
       
   777     // Free the memory
       
   778     iMmsHeaderSize = iNewMmsHeaders->Size();
       
   779     delete iNewMmsHeaders;
       
   780     iNewMmsHeaders = NULL;
       
   781     delete iDescription;
       
   782     iDescription = NULL;
       
   783 
       
   784     RequestComplete( KErrNone );
       
   785 
       
   786     }
       
   787 
       
   788 // ---------------------------------------------------------
       
   789 // CMmsMessageOperation::CopyAttachmentsL
       
   790 //
       
   791 // ---------------------------------------------------------
       
   792 void CMmsMessageOperation::CopyAttachmentsL()
       
   793     {
       
   794     
       
   795     // Attachments must be copied one by one because of the asynchronous
       
   796     // nature of the attachment manager functions.
       
   797     
       
   798     // We get here only if the message has attachments and the part list
       
   799     // specifies that the attachments must be copied.
       
   800 
       
   801     // Get next attachment
       
   802     
       
   803     MMsvAttachmentManager& sourceAttaMan = iSourceStore->AttachmentManagerL();
       
   804     CMsvAttachment* sourceAtta = sourceAttaMan.GetAttachmentInfoL( iCurrentAttachment );
       
   805     CleanupStack::PushL( sourceAtta );
       
   806     CMsvMimeHeaders* mime = CMsvMimeHeaders::NewL();
       
   807     CleanupStack::PushL( mime );
       
   808     mime->RestoreL( *sourceAtta );
       
   809     
       
   810     delete iMsvOperation;
       
   811     iMsvOperation = NULL;
       
   812     
       
   813     TInt size = 0;
       
   814     // We need to check disk space for mime headers and file attachments
       
   815     // Linked attachments are not copied, and do not take up space
       
   816     
       
   817     size += mime->Size(); // size of mime headers
       
   818     if ( sourceAtta->Type() == CMsvAttachment::EMsvFile )
       
   819         {
       
   820         // Add file size only if the attachment file must be copied.
       
   821         // Linked attachment files are not copied, just the link is added
       
   822         size += sourceAtta->Size();
       
   823         }
       
   824     
       
   825     RFs fs = iMsvSession.FileSession();
       
   826     
       
   827     if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( &fs, 
       
   828         size,
       
   829         iMsvSession.CurrentDriveL() ) )
       
   830         {
       
   831         delete iTargetStore;
       
   832         iTargetStore = NULL;
       
   833         delete iTargetEntry;
       
   834         iTargetEntry = NULL;
       
   835         CleanupStack::PopAndDestroy( mime );
       
   836         CleanupStack::PopAndDestroy( sourceAtta );
       
   837         // we use standard error code here
       
   838         User::Leave( KErrDiskFull );
       
   839         }
       
   840     
       
   841     // Copy the attachment
       
   842     
       
   843     MMsvAttachmentManager& targetAttaMan = iTargetStore->AttachmentManagerL();
       
   844     CMsvAttachment* targetAtta = NULL;
       
   845     
       
   846     HBufC8* mimeType = sourceAtta->MimeType().AllocL();
       
   847     CleanupStack::PushL( mimeType );
       
   848     TParse fParse;
       
   849     User::LeaveIfError( fParse.Set( sourceAtta->FilePath(), NULL, NULL ) );
       
   850     HBufC* attaName = fParse.NameAndExt().AllocL();
       
   851     CleanupStack::PushL( attaName );
       
   852     
       
   853     targetAtta = CMsvAttachment::NewL(
       
   854          sourceAtta->Type(),
       
   855          sourceAtta->Size(),
       
   856          mimeType,
       
   857          attaName
       
   858          );
       
   859     CleanupStack::Pop( attaName ); // ownership of attaName transferred to targetAtta
       
   860     CleanupStack::Pop( mimeType ); // ownership of mimeType transferred to targetAtta
       
   861          
       
   862     CleanupStack::PushL( targetAtta );
       
   863     
       
   864     mime->StoreL( *targetAtta );
       
   865         
       
   866     if ( sourceAtta->Type() == CMsvAttachment::EMsvFile )
       
   867         {
       
   868         RFile sourceFile = sourceAttaMan.GetAttachmentFileL( iCurrentAttachment );
       
   869         CleanupClosePushL( sourceFile );
       
   870         targetAttaMan.AddAttachmentL( sourceFile, 
       
   871                                       targetAtta, 
       
   872                                       iStatus );
       
   873         CleanupStack::Pop( &sourceFile ); // close file
       
   874         }
       
   875     else // linked file
       
   876         {
       
   877         targetAttaMan.AddLinkedAttachmentL( sourceAtta->FilePath(), targetAtta, iStatus );
       
   878         }
       
   879         
       
   880     if ( sourceAtta->Id() == iOriginalRoot )
       
   881         {
       
   882         iNewRoot = iCurrentAttachment; // save the index
       
   883         }
       
   884     
       
   885     // Ownership of targetAtta was transferred to attachment manager
       
   886     CleanupStack::Pop( targetAtta ); // targetAtta
       
   887     CleanupStack::PopAndDestroy( mime );
       
   888     CleanupStack::PopAndDestroy( sourceAtta );
       
   889 
       
   890 // RunL sets us active
       
   891     }
       
   892 
       
   893 // ---------------------------------------------------------
       
   894 // CMmsMessageOperation::CompleteMessageL
       
   895 //
       
   896 // ---------------------------------------------------------
       
   897 void CMmsMessageOperation::CompleteMessageL()
       
   898     {
       
   899 // As the attachments are not separate entries, iTargetEntry always points to
       
   900 // the new message entry. No need to set iTargetEntry to the new entry anymore.
       
   901     TMsvEntry entry = iTargetEntry->Entry();
       
   902     AttachmentsSizeL();
       
   903     // iTargetStore is recreated in AttachmentSizeL(), we must kill it
       
   904     // to prevent a crash if the user cancels the operation at the last minute.
       
   905     // The actual problem is in Symbian attachment manager code, DoCancel() 
       
   906     // should not do anything if the active object is not active (Symbian code does
       
   907     // not check the state).
       
   908     delete iTargetStore;
       
   909     iTargetStore = NULL;
       
   910     entry.iSize = ( iAttachmentsSize + iMmsHeaderSize );
       
   911     entry.SetVisible( iVisible );
       
   912     entry.SetInPreparation( iInPreparation );
       
   913     entry.SetAttachment( iAttachmentsSize ? ETrue : EFalse );
       
   914     
       
   915     iTargetEntry->ChangeL( entry );
       
   916 
       
   917     RequestComplete( KErrNone );
       
   918 
       
   919     }
       
   920 
       
   921 // ---------------------------------------------------------
       
   922 // CMmsMessageOperation::DoCancel
       
   923 //
       
   924 // ---------------------------------------------------------
       
   925 void CMmsMessageOperation::DoCancel()
       
   926     {
       
   927 
       
   928     // Cancel all the pending requests
       
   929     if ( iMsvOperation )
       
   930         {
       
   931         iMsvOperation->Cancel();
       
   932         }
       
   933         
       
   934     if ( iTargetStore )
       
   935         {
       
   936         // cancel attachment manager operations if any are active
       
   937         TRAP_IGNORE( 
       
   938             {
       
   939             // This will leave only if there is no attachment manager
       
   940             // Otherwise it will just return reference to the existing manager
       
   941             MMsvAttachmentManager& attaMan = iTargetStore->AttachmentManagerL();
       
   942             // If there is no attachment manager, there cannot be any ongoing request
       
   943             // So the request needs to be cancelled only if the previous function
       
   944             // did not leave
       
   945             attaMan.CancelRequest();
       
   946             });
       
   947         delete iTargetStore;
       
   948         iTargetStore = NULL;
       
   949         }
       
   950         
       
   951     delete iTargetEntry;
       
   952     iTargetEntry = NULL;
       
   953     delete iSourceStore;
       
   954     iSourceStore = NULL;
       
   955     delete iSourceEntry;
       
   956     iSourceEntry = NULL;
       
   957                 
       
   958     // Remove the new message entry
       
   959     if ( iNewMessageId != KMsvNullIndexEntryId )
       
   960         {
       
   961         iMsvSession.RemoveEntry( iNewMessageId );
       
   962         }
       
   963     iNewMessageId = KMsvNullIndexEntryId;
       
   964 
       
   965     TRequestStatus* st = &iObserverRequestStatus;
       
   966     User::RequestComplete( st, KErrCancel );
       
   967     }
       
   968 
       
   969 // ---------------------------------------------------------
       
   970 // CMmsMessageOperation::AttachmentsSizeL
       
   971 //
       
   972 // ---------------------------------------------------------
       
   973 void CMmsMessageOperation::AttachmentsSizeL()
       
   974     {
       
   975     // We just scan the attachment entries and
       
   976     // and calculate the total amount of size.
       
   977 
       
   978     iAttachmentsSize = 0;
       
   979     
       
   980     if ( !iTargetStore )
       
   981         {
       
   982         iTargetStore = iTargetEntry->ReadStoreL();
       
   983         }
       
   984     MMsvAttachmentManager& targetAttaMan = iTargetStore->AttachmentManagerL();
       
   985     
       
   986     TInt counter = targetAttaMan.AttachmentCount();
       
   987     
       
   988     for ( TInt i = 0; i < counter; i++ )
       
   989         {
       
   990         CMsvAttachment* attaInfo = targetAttaMan.GetAttachmentInfoL( i );
       
   991         CleanupStack::PushL( attaInfo );
       
   992         iAttachmentsSize += attaInfo->Size();
       
   993         CMsvMimeHeaders* mime = CMsvMimeHeaders::NewL();
       
   994         CleanupStack::PushL( mime );
       
   995         mime->RestoreL( *attaInfo );
       
   996         iAttachmentsSize += mime->Size();
       
   997         CleanupStack::PopAndDestroy( mime );
       
   998         CleanupStack::PopAndDestroy( attaInfo );
       
   999         }
       
  1000     }
       
  1001 
       
  1002 // ================= OTHER EXPORTED FUNCTIONS ==============
       
  1003 
       
  1004 //  End of File  
       
  1005