mmsengine/mmsmessage/src/mmsmessageoperation.cpp
changeset 0 72b543305e3a
child 23 238255e8b033
equal deleted inserted replaced
-1:000000000000 0:72b543305e3a
       
     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 appropiate 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             // Find own number
       
   611             // don't remove if only one recipient in the list
       
   612             if ( recipientList->MdcaCount() > 1 )
       
   613                 {
       
   614                 CMmsOwnNumber* ownNumberSearcher = 
       
   615                     CMmsOwnNumber::NewL( &iMsvSession.FileSession() );
       
   616                 CleanupStack::PushL( ownNumberSearcher );
       
   617                 
       
   618                 TInt index = -1;
       
   619                 index = ownNumberSearcher->StartL( *recipientList );
       
   620                 
       
   621                 if ( index >= 0 )
       
   622                     {
       
   623                     // found something
       
   624                     while ( iNewMmsHeaders->RemoveAddressee( recipientList->MdcaPoint( index ) ) )
       
   625                         {
       
   626                         }
       
   627                     }
       
   628                     
       
   629                 CleanupStack::PopAndDestroy( ownNumberSearcher );
       
   630                 }
       
   631             CleanupStack::PopAndDestroy( recipientList );
       
   632             }
       
   633 
       
   634         // the root must always be retained if it is specified
       
   635         if ( iPartList & KMsvMessagePartAttachments )
       
   636             {
       
   637             iOriginalRoot = originalMmsHeaders->MessageRoot();
       
   638             iNewMmsHeaders->SetRootContentIdL( originalMmsHeaders->RootContentId() );
       
   639             }
       
   640         CleanupStack::PopAndDestroy( originalMmsHeaders );
       
   641         }
       
   642     else
       
   643         {
       
   644         // No original message available
       
   645         iNewMmsHeaders = CMmsHeaders::NewL( iSettings->MmsVersion() );
       
   646         }
       
   647     // Reset MMS settings
       
   648     iNewMmsHeaders->SetSettings( iSettings );
       
   649 
       
   650     RequestComplete( KErrNone );
       
   651 
       
   652     }
       
   653 
       
   654 // ---------------------------------------------------------
       
   655 // CMmsMessageOperation::CreateMessageEntryL
       
   656 //
       
   657 // ---------------------------------------------------------
       
   658 void CMmsMessageOperation::CreateMessageEntryL()
       
   659     {
       
   660 
       
   661     // Create new message entry
       
   662 
       
   663     // CREATE NEW INDEX ENTRY
       
   664     TMsvEntry entry;
       
   665     entry.iType = KUidMsvMessageEntry;
       
   666     entry.iServiceId = iServiceId;
       
   667     entry.iMtm = KUidMsgTypeMultimedia;
       
   668     entry.iDate.UniversalTime();
       
   669 
       
   670     // Set iMtmData extension flags
       
   671     if ( iOperation == EForward )
       
   672         {
       
   673         entry.iMtmData1 |= KMmsMessageForwarded;
       
   674         }
       
   675 
       
   676     // Set iDetails
       
   677     TPtrC to;
       
   678     if ( iNewMmsHeaders->ToRecipients().Count() > 0 )
       
   679         {
       
   680         to.Set( iNewMmsHeaders->ToRecipients()[0] );
       
   681         }
       
   682     HBufC* buffer = HBufC::NewL( KMmsMaxDescription );
       
   683     CleanupStack::PushL( buffer );
       
   684     TPtr pBuffer = buffer->Des();
       
   685 
       
   686     if ( TMmsGenUtils::IsValidMMSPhoneAddress( to, EFalse ) )
       
   687         {
       
   688         if ( TMmsGenUtils::GenerateDetails( to,
       
   689             pBuffer, KMmsMaxDescription, iMsvSession.FileSession() ) == KErrNone )
       
   690             {
       
   691             entry.iDetails.Set( pBuffer );
       
   692             }
       
   693         else
       
   694             {
       
   695             entry.iDetails.Set( to );
       
   696             }
       
   697         }
       
   698     else
       
   699         {
       
   700         entry.iDetails.Set( to );
       
   701         }
       
   702 
       
   703     // Set iDescription
       
   704     entry.iDescription.Set( iNewMmsHeaders->Subject());
       
   705     // if no subject, copy old description
       
   706     if ( ( iPartList & KMsvMessagePartAttachments ) &&
       
   707          ( iOrigMessageId != KMsvNullIndexEntryId ) &&
       
   708          ( entry.iDescription.Length() == 0 ) )
       
   709         {
       
   710         // Copy the old description, no need to scan message files again ...
       
   711         TPtrC pp;
       
   712         pp.Set( iSourceEntry->Entry().iDescription );
       
   713         delete iDescription;
       
   714         iDescription = NULL;
       
   715         iDescription = pp.AllocL();
       
   716         entry.iDescription.Set( *iDescription );
       
   717         }
       
   718 
       
   719     // The following ones will be set in completion.
       
   720     entry.SetInPreparation( ETrue );    
       
   721     entry.SetVisible( EFalse );         
       
   722     entry.iSize = 0;
       
   723     
       
   724     // Create the new message entry asynchronically.
       
   725     delete iMsvOperation;
       
   726     iMsvOperation = NULL;
       
   727     iCurrentAttachment = 0;
       
   728     
       
   729     if ( iPartList & KMsvMessagePartAttachments )
       
   730         {
       
   731         // get number of attachments
       
   732         MMsvAttachmentManager& sourceAttaMan = iSourceStore->AttachmentManagerL();
       
   733         iAttachmentCount = sourceAttaMan.AttachmentCount();
       
   734         }
       
   735 
       
   736     // Check that sufficient disk space available
       
   737     // for index entry
       
   738     iTargetEntry->SetEntryL( iDestinationId );
       
   739     RFs fs = iMsvSession.FileSession();
       
   740     if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( &fs, 
       
   741         sizeof( TMsvEntry ) 
       
   742         + entry.iDescription.Length() 
       
   743         + entry.iDetails.Length(),
       
   744         iMsvSession.CurrentDriveL() ) )
       
   745             {
       
   746             // we use standard error code here
       
   747             User::Leave( KErrDiskFull );
       
   748             }
       
   749     // Target entry still points to destination folder
       
   750     iMsvOperation = iTargetEntry->CreateL( entry, iStatus );
       
   751 
       
   752     CleanupStack::PopAndDestroy( buffer );
       
   753     }
       
   754 
       
   755 // ---------------------------------------------------------
       
   756 // CMmsMessageOperation::StoreMmsHeadersL
       
   757 //
       
   758 // ---------------------------------------------------------
       
   759 void CMmsMessageOperation::StoreMmsHeadersL()
       
   760     {
       
   761 
       
   762     // save the correct id for new root
       
   763     if ( iPartList & KMsvMessagePartAttachments && 
       
   764         iNewRoot != -1 )
       
   765         {
       
   766         MMsvAttachmentManager& targetAttaMan = iTargetStore->AttachmentManagerL();
       
   767         CMsvAttachment* targetAtta = targetAttaMan.GetAttachmentInfoL( iNewRoot );
       
   768         CleanupStack::PushL( targetAtta );
       
   769         iNewMmsHeaders->SetMessageRoot( targetAtta->Id() );
       
   770         CleanupStack::PopAndDestroy( targetAtta );
       
   771         }
       
   772     else
       
   773         {
       
   774         iNewMmsHeaders->SetRootContentIdL( TPtrC8() );
       
   775         }
       
   776         
       
   777 
       
   778     // Check that sufficient disk space available
       
   779     // for MMS headers stream
       
   780     RFs fs = iMsvSession.FileSession();
       
   781     if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( &fs, 
       
   782         iNewMmsHeaders->Size(),
       
   783         iMsvSession.CurrentDriveL() ) )
       
   784         {
       
   785         // we use standard error code here
       
   786         User::Leave( KErrDiskFull );
       
   787         }
       
   788 
       
   789     // Externalize MMS headers
       
   790     iNewMmsHeaders->StoreL( *iTargetStore );
       
   791     // This is the last stage in creating the new entry.
       
   792     // Now the store is committed and deleted.
       
   793     iTargetStore->CommitL();
       
   794     delete iTargetStore;
       
   795     iTargetStore = NULL;
       
   796 
       
   797     // Free the memory
       
   798     iMmsHeaderSize = iNewMmsHeaders->Size();
       
   799     delete iNewMmsHeaders;
       
   800     iNewMmsHeaders = NULL;
       
   801     delete iDescription;
       
   802     iDescription = NULL;
       
   803 
       
   804     RequestComplete( KErrNone );
       
   805 
       
   806     }
       
   807 
       
   808 // ---------------------------------------------------------
       
   809 // CMmsMessageOperation::CopyAttachmentsL
       
   810 //
       
   811 // ---------------------------------------------------------
       
   812 void CMmsMessageOperation::CopyAttachmentsL()
       
   813     {
       
   814     
       
   815     // Attachments must be copied one by one because of the asynchronous
       
   816     // nature of the attachment manager functions.
       
   817     
       
   818     // We get here only if the message has attachments and the part list
       
   819     // specifies that the attachments must be copied.
       
   820 
       
   821     // Get next attachment
       
   822     
       
   823     MMsvAttachmentManager& sourceAttaMan = iSourceStore->AttachmentManagerL();
       
   824     CMsvAttachment* sourceAtta = sourceAttaMan.GetAttachmentInfoL( iCurrentAttachment );
       
   825     CleanupStack::PushL( sourceAtta );
       
   826     CMsvMimeHeaders* mime = CMsvMimeHeaders::NewL();
       
   827     CleanupStack::PushL( mime );
       
   828     mime->RestoreL( *sourceAtta );
       
   829     
       
   830     delete iMsvOperation;
       
   831     iMsvOperation = NULL;
       
   832     
       
   833     TInt size = 0;
       
   834     // We need to check disk space for mime headers and file attachments
       
   835     // Linked attachments are not copied, and do not take up space
       
   836     
       
   837     size += mime->Size(); // size of mime headers
       
   838     if ( sourceAtta->Type() == CMsvAttachment::EMsvFile )
       
   839         {
       
   840         // Add file size only if the attachment file must be copied.
       
   841         // Linked attachment files are not copied, just the link is added
       
   842         size += sourceAtta->Size();
       
   843         }
       
   844     
       
   845     RFs fs = iMsvSession.FileSession();
       
   846     
       
   847     if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( &fs, 
       
   848         size,
       
   849         iMsvSession.CurrentDriveL() ) )
       
   850         {
       
   851         delete iTargetStore;
       
   852         iTargetStore = NULL;
       
   853         delete iTargetEntry;
       
   854         iTargetEntry = NULL;
       
   855         CleanupStack::PopAndDestroy( mime );
       
   856         CleanupStack::PopAndDestroy( sourceAtta );
       
   857         // we use standard error code here
       
   858         User::Leave( KErrDiskFull );
       
   859         }
       
   860     
       
   861     // Copy the attachment
       
   862     
       
   863     MMsvAttachmentManager& targetAttaMan = iTargetStore->AttachmentManagerL();
       
   864     CMsvAttachment* targetAtta = NULL;
       
   865     
       
   866     HBufC8* mimeType = sourceAtta->MimeType().AllocL();
       
   867     CleanupStack::PushL( mimeType );
       
   868     TParse fParse;
       
   869     User::LeaveIfError( fParse.Set( sourceAtta->FilePath(), NULL, NULL ) );
       
   870     HBufC* attaName = fParse.NameAndExt().AllocL();
       
   871     CleanupStack::PushL( attaName );
       
   872     
       
   873     targetAtta = CMsvAttachment::NewL(
       
   874          sourceAtta->Type(),
       
   875          sourceAtta->Size(),
       
   876          mimeType,
       
   877          attaName
       
   878          );
       
   879     CleanupStack::Pop( attaName ); // ownership of attaName transferred to targetAtta
       
   880     CleanupStack::Pop( mimeType ); // ownership of mimeType transferred to targetAtta
       
   881          
       
   882     CleanupStack::PushL( targetAtta );
       
   883     
       
   884     mime->StoreL( *targetAtta );
       
   885         
       
   886     if ( sourceAtta->Type() == CMsvAttachment::EMsvFile )
       
   887         {
       
   888         RFile sourceFile = sourceAttaMan.GetAttachmentFileL( iCurrentAttachment );
       
   889         CleanupClosePushL( sourceFile );
       
   890         targetAttaMan.AddAttachmentL( sourceFile, 
       
   891                                       targetAtta, 
       
   892                                       iStatus );
       
   893         CleanupStack::Pop( &sourceFile ); // close file
       
   894         }
       
   895     else // linked file
       
   896         {
       
   897         targetAttaMan.AddLinkedAttachmentL( sourceAtta->FilePath(), targetAtta, iStatus );
       
   898         }
       
   899         
       
   900     if ( sourceAtta->Id() == iOriginalRoot )
       
   901         {
       
   902         iNewRoot = iCurrentAttachment; // save the index
       
   903         }
       
   904     
       
   905     // Ownership of targetAtta was transferred to attachment manager
       
   906     CleanupStack::Pop( targetAtta ); // targetAtta
       
   907     CleanupStack::PopAndDestroy( mime );
       
   908     CleanupStack::PopAndDestroy( sourceAtta );
       
   909 
       
   910 // RunL sets us active
       
   911     }
       
   912 
       
   913 // ---------------------------------------------------------
       
   914 // CMmsMessageOperation::CompleteMessageL
       
   915 //
       
   916 // ---------------------------------------------------------
       
   917 void CMmsMessageOperation::CompleteMessageL()
       
   918     {
       
   919 // As the attachments are not separate entries, iTargetEntry always points to
       
   920 // the new message entry. No need to set iTargetEntry to the new entry anymore.
       
   921     TMsvEntry entry = iTargetEntry->Entry();
       
   922     AttachmentsSizeL();
       
   923     // iTargetStore is recreated in AttachmentSizeL(), we must kill it
       
   924     // to prevent a crash if the user cancels the operation at the last minute.
       
   925     // The actual problem is in Symbian attachment manager code, DoCancel() 
       
   926     // should not do anything if the active object is not active (Symbian code does
       
   927     // not check the state).
       
   928     delete iTargetStore;
       
   929     iTargetStore = NULL;
       
   930     entry.iSize = ( iAttachmentsSize + iMmsHeaderSize );
       
   931     entry.SetVisible( iVisible );
       
   932     entry.SetInPreparation( iInPreparation );
       
   933     entry.SetAttachment( iAttachmentsSize ? ETrue : EFalse );
       
   934     
       
   935     iTargetEntry->ChangeL( entry );
       
   936 
       
   937     RequestComplete( KErrNone );
       
   938 
       
   939     }
       
   940 
       
   941 // ---------------------------------------------------------
       
   942 // CMmsMessageOperation::DoCancel
       
   943 //
       
   944 // ---------------------------------------------------------
       
   945 void CMmsMessageOperation::DoCancel()
       
   946     {
       
   947 
       
   948     // Cancel all the pending requests
       
   949     if ( iMsvOperation )
       
   950         {
       
   951         iMsvOperation->Cancel();
       
   952         }
       
   953         
       
   954     if ( iTargetStore )
       
   955         {
       
   956         // cancel attachment manager operations if any are active
       
   957         TRAP_IGNORE( 
       
   958             {
       
   959             // This will leave only if there is no attachment manager
       
   960             // Otherwise it will just return reference to the existing manager
       
   961             MMsvAttachmentManager& attaMan = iTargetStore->AttachmentManagerL();
       
   962             // If there is no attachment manager, there cannot be any ongoing request
       
   963             // So the request needs to be cancelled only if the previous function
       
   964             // did not leave
       
   965             attaMan.CancelRequest();
       
   966             });
       
   967         delete iTargetStore;
       
   968         iTargetStore = NULL;
       
   969         }
       
   970         
       
   971     delete iTargetEntry;
       
   972     iTargetEntry = NULL;
       
   973     delete iSourceStore;
       
   974     iSourceStore = NULL;
       
   975     delete iSourceEntry;
       
   976     iSourceEntry = NULL;
       
   977                 
       
   978     // Remove the new message entry
       
   979     if ( iNewMessageId != KMsvNullIndexEntryId )
       
   980         {
       
   981         iMsvSession.RemoveEntry( iNewMessageId );
       
   982         }
       
   983     iNewMessageId = KMsvNullIndexEntryId;
       
   984 
       
   985     TRequestStatus* st = &iObserverRequestStatus;
       
   986     User::RequestComplete( st, KErrCancel );
       
   987     }
       
   988 
       
   989 // ---------------------------------------------------------
       
   990 // CMmsMessageOperation::AttachmentsSizeL
       
   991 //
       
   992 // ---------------------------------------------------------
       
   993 void CMmsMessageOperation::AttachmentsSizeL()
       
   994     {
       
   995     // We just scan the attachment entries and
       
   996     // and calculate the total amount of size.
       
   997 
       
   998     iAttachmentsSize = 0;
       
   999     
       
  1000     if ( !iTargetStore )
       
  1001         {
       
  1002         iTargetStore = iTargetEntry->ReadStoreL();
       
  1003         }
       
  1004     MMsvAttachmentManager& targetAttaMan = iTargetStore->AttachmentManagerL();
       
  1005     
       
  1006     TInt counter = targetAttaMan.AttachmentCount();
       
  1007     
       
  1008     for ( TInt i = 0; i < counter; i++ )
       
  1009         {
       
  1010         CMsvAttachment* attaInfo = targetAttaMan.GetAttachmentInfoL( i );
       
  1011         CleanupStack::PushL( attaInfo );
       
  1012         iAttachmentsSize += attaInfo->Size();
       
  1013         CMsvMimeHeaders* mime = CMsvMimeHeaders::NewL();
       
  1014         CleanupStack::PushL( mime );
       
  1015         mime->RestoreL( *attaInfo );
       
  1016         iAttachmentsSize += mime->Size();
       
  1017         CleanupStack::PopAndDestroy( mime );
       
  1018         CleanupStack::PopAndDestroy( attaInfo );
       
  1019         }
       
  1020     }
       
  1021 
       
  1022 // ================= OTHER EXPORTED FUNCTIONS ==============
       
  1023 
       
  1024 //  End of File  
       
  1025