/*
* Copyright (c) 2002-2007 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
* CMsvOperation class for MMS message creation.
*
*/
// INCLUDE FILES
#include <msvids.h>
#include <msvstore.h>
#include <mtmdef.h>
#include <mtmuids.h>
#include <mmsvattachmentmanager.h>
#include <cmsvattachment.h>
#include <cmsvmimeheaders.h>
#include "mmsmessageoperation.h"
#include "mmsconst.h"
#include "mmssettings.h"
#include "mmsheaders.h"
#include "mmsgenutils.h"
#include "mmsownnumber.h"
// EXTERNAL DATA STRUCTURES
// EXTERNAL FUNCTION PROTOTYPES
extern void gPanic( TMmsPanic aPanic );
// CONSTANTS
const TInt KMmsRecipientGranularity = 6;
// MACROS
// LOCAL CONSTANTS AND MACROS
// MODULE DATA STRUCTURES
// LOCAL FUNCTION PROTOTYPES
// ==================== LOCAL FUNCTIONS ====================
//
// ================= MEMBER FUNCTIONS =======================
// C++ default constructor can NOT contain any code, that
// might leave.
//
CMmsMessageOperation::~CMmsMessageOperation()
{
Cancel();
delete iSourceStore;
delete iTargetStore;
delete iSourceEntry;
delete iTargetEntry;
delete iMsvOperation;
delete iSettings;
delete iNewMmsHeaders;
delete iDescription;
}
// ---------------------------------------------------------
// CMmsMessageOperation::CreateNewL
//
// ---------------------------------------------------------
EXPORT_C CMmsMessageOperation* CMmsMessageOperation::CreateNewL(
TRequestStatus& aObserverRequestStatus,
CMsvSession& aMsvSession,
TMsvId aDestination,
TMsvId aServiceId,
TBool aVisible,
TBool aInPreparation )
{
TMsvPartList parts = 0;
CMmsMessageOperation* self = new(ELeave) CMmsMessageOperation(
aObserverRequestStatus,
aMsvSession,
aDestination,
parts,
aServiceId,
aVisible,
aInPreparation );
CleanupStack::PushL( self );
self->ConstructL( KMsvNullIndexEntryId, ENew );
CleanupStack::Pop( self );
return self;
}
// ---------------------------------------------------------
// CMmsMessageOperation::CreateReplyL
//
// ---------------------------------------------------------
EXPORT_C CMmsMessageOperation* CMmsMessageOperation::CreateReplyL(
TRequestStatus& aObserverRequestStatus,
CMsvSession& aMsvSession,
TMsvId aMessageId,
TMsvId aDestination,
TMsvPartList aPartList,
TMsvId aServiceId,
TBool aVisible,
TBool aInPreparation )
{
if ( aMessageId == KMsvNullIndexEntryId )
{
// if no source cannot reply
User::Leave( KErrArgument );
}
// Set the attachment part flag off
TMsvPartList parts = aPartList & ~KMsvMessagePartAttachments;
CMmsMessageOperation* self = new(ELeave) CMmsMessageOperation(
aObserverRequestStatus,
aMsvSession,
aDestination,
parts,
aServiceId,
aVisible,
aInPreparation );
CleanupStack::PushL( self );
self->ConstructL( aMessageId, EReply );
CleanupStack::Pop( self );
return self;
}
// ---------------------------------------------------------
// CMmsMessageOperation::CreateForwardL
//
// ---------------------------------------------------------
EXPORT_C CMmsMessageOperation* CMmsMessageOperation::CreateForwardL(
TRequestStatus& aObserverRequestStatus,
CMsvSession& aMsvSession,
TMsvId aMessageId,
TMsvId aDestination,
TMsvPartList aPartList,
TMsvId aServiceId,
TBool aVisible,
TBool aInPreparation )
{
if ( aMessageId == KMsvNullIndexEntryId )
{
// if no source cannot forward
User::Leave( KErrArgument );
}
// Set the attachment part flag on
TMsvPartList parts = aPartList | KMsvMessagePartAttachments;
CMmsMessageOperation* self = new(ELeave) CMmsMessageOperation(
aObserverRequestStatus,
aMsvSession,
aDestination,
parts,
aServiceId,
aVisible,
aInPreparation );
CleanupStack::PushL( self );
self->ConstructL( aMessageId, EForward );
CleanupStack::Pop( self );
return self;
}
// ---------------------------------------------------------
// CMmsMessageOperation::CreateForwardWithoutRetrievalL
//
// ---------------------------------------------------------
//
EXPORT_C TMsvId CMmsMessageOperation::CreateForwardWithoutRetrievalL(
CMsvSession& aMsvSession,
const CMmsHeaders& aNotificationHeaders,
const TMsvId aRelatedEntry,
const TMsvId aDestination,
TMsvId aServiceId,
TBool aVisible,
TBool aInPreparation )
{
//
// Create entry
//
TMsvEntry entry;
CMsvEntry* cMsvEntry = CMsvEntry::NewL(
aMsvSession, aDestination, TMsvSelectionOrdering() );
CleanupStack::PushL( cMsvEntry );
entry.iType = KUidMsvMessageEntry;
entry.iServiceId = aServiceId;
entry.iMtm = KUidMsgMMSNotification;
entry.iMtmData1 |= KMmsMessageForwardReq;
entry.iDate.UniversalTime();
entry.SetInPreparation( aInPreparation );
entry.SetVisible( aVisible );
cMsvEntry->CreateL( entry );
//
// Get MMS settings
//
CMmsSettings* settings = CMmsSettings::NewL();
CleanupStack::PushL( settings );
settings->LoadSettingsL();
//
// Create headers object
//
CMmsHeaders* headers = CMmsHeaders::NewL( settings->MmsVersion() );
CleanupStack::PushL( headers );
headers->SetSettings( settings );
//
// Set ContentLocation to headers object
//
headers->SetContentLocationL( aNotificationHeaders.ContentLocation() );
headers->SetRelatedEntry( aRelatedEntry );
// Following entries are copied to the forward request on purpose
// even though they do not belong to the PDU sent to the network
headers->SetSubjectL( aNotificationHeaders.Subject() );
headers->SetMessageSize( aNotificationHeaders.MessageSize() );
headers->SetMessageClass( aNotificationHeaders.MessageClass() );
headers->SetMessagePriority( aNotificationHeaders.MessagePriority() );
// Set Report Allowed according to settings
headers->SetReportAllowed( settings->DeliveryReportSendingAllowed() );
//
// Check diskspace before storing headers
//
RFs fs = aMsvSession.FileSession();
if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL(
&fs,
headers->Size(),
aMsvSession.CurrentDriveL() ) )
{
User::Leave( KErrDiskFull );
}
//
// Store headers to MessageStore
//
cMsvEntry->SetEntryL( entry.Id() );
CMsvStore* store = cMsvEntry->EditStoreL();
CleanupStack::PushL( store ); // ***
headers->StoreL( *store );
store->CommitL();
//
// Update and save index entry
//
entry.iSize = headers->Size();
cMsvEntry->ChangeL( entry );
CleanupStack::PopAndDestroy( store );
CleanupStack::PopAndDestroy( headers );
CleanupStack::PopAndDestroy( settings );
CleanupStack::PopAndDestroy( cMsvEntry );
return entry.Id();
}
// ---------------------------------------------------------
// CMmsMessageOperation::ConstructL
//
// ---------------------------------------------------------
void CMmsMessageOperation::ConstructL(
TMsvId aMessageId,
TMmsOperation aOperation )
{
iOrigMessageId = aMessageId;
iOperation = aOperation;
iDataMember = KMsvNullIndexEntryId;
iState = ECreateMmsHeaders;
iAttachmentsSize = 0;
iDescription = NULL;
iOriginalRoot = 0;
iAttachmentCount = 0;
iNewRoot = -1; // not found yet
// Create new message entry object to work with
// iDestinationId is the target folder
iTargetEntry = CMsvEntry::NewL(
iMsvSession, iDestinationId, TMsvSelectionOrdering() );
// Show invisible entries too.
iTargetEntry->SetSortTypeL( TMsvSelectionOrdering(
KMsvNoGrouping, EMsvSortByNone, ETrue ));
if ( iOrigMessageId != KMsvNullIndexEntryId )
{
// Create entry for the original entry
iSourceEntry = CMsvEntry::NewL(
iMsvSession, iOrigMessageId, TMsvSelectionOrdering() );
// Show invisible entries too.
iSourceEntry->SetSortTypeL( TMsvSelectionOrdering(
KMsvNoGrouping, EMsvSortByNone, ETrue ));
// if we have an original entry, it will be read
iSourceStore = iSourceEntry->ReadStoreL();
}
iSettings = CMmsSettings::NewL();
// Add this objet to the scheduler
CActiveScheduler::Add( this );
ChangeStateL();
iObserverRequestStatus = KRequestPending;
SetActive();
}
// ---------------------------------------------------------
// CMmsMessageOperation::FinalProgress
//
// ---------------------------------------------------------
//
EXPORT_C const TDesC8& CMmsMessageOperation::FinalProgress()
{
__ASSERT_ALWAYS( !IsActive(), gPanic( EMmsActiveInFinalProgress ));
const TDesC8* progress = &KNullDesC8();
TRAPD( leave, {progress = &ProgressL();} );
__ASSERT_ALWAYS( leave == KErrNone, gPanic( EMmsFinalProgressFailed ));
return *progress;
}
// ---------------------------------------------------------
// CMmsMessageOperation::ProgressL
//
// ---------------------------------------------------------
//
const TDesC8& CMmsMessageOperation::ProgressL()
{
if (iState == EFinished )
{
iDataMember() = iNewMessageId;
}
return iDataMember;
}
// ---------------------------------------------------------
// CMmsMessageOperation::RunL
//
// ---------------------------------------------------------
//
void CMmsMessageOperation::RunL()
{
if (iStatus.Int() != KErrNone )
{
ErrorRecovery( iStatus.Int() );
return;
}
// Check the progress status in case that real progress is available.
// only entry creation returns correct progress info
if ( iState == ECreateMessageEntry )
{
TMsvLocalOperationProgress progress =
McliUtils::GetLocalProgressL( *iMsvOperation );
if ( progress.iError != KErrNone )
{
ErrorRecovery( progress.iError );
return;
}
}
if ( iState != EFinished )
{
TRAPD( error, SelectAndChangeToNextStateL() );
if ( error )
{
ErrorRecovery( error );
return;
}
else if ( iState != EFinished )
{
// Here we go again.
SetActive();
}
else
{
// keep LINT happy
}
}
}
// ---------------------------------------------------------
// CMmsMessageOperation::CMmsMessageOperation
//
// ---------------------------------------------------------
CMmsMessageOperation::CMmsMessageOperation(
TRequestStatus& aObserverRequestStatus,
CMsvSession& aMsvSession,
TMsvId aDestination,
TMsvPartList aPartList,
TMsvId aServiceId,
TBool aVisible,
TBool aInPreparation )
: CMsvOperation( aMsvSession, EPriorityStandard, aObserverRequestStatus ),
iDestinationId( aDestination ),
iPartList( aPartList ),
iServiceId( aServiceId ),
iSettings( NULL ),
iNewMmsHeaders( NULL ),
iVisible( aVisible ),
iInPreparation ( aInPreparation )
{
}
// ---------------------------------------------------------
// CMmsMessageOperation::ErrorRecovery
//
// ---------------------------------------------------------
void CMmsMessageOperation::ErrorRecovery( TInt aError )
{
// Delete entry and store objects associated with the new entry.
// If an error is encountered, store is not committed, and the
// entry under construction is deleted.
// Deleting the message entry deletes all attachments that are
// stored in the message store. Linked attachments are not deleted.
delete iTargetStore;
iTargetStore = NULL;
delete iTargetEntry;
iTargetEntry = NULL;
// Remove the new message entry
if ( iNewMessageId != KMsvNullIndexEntryId )
{
iMsvSession.RemoveEntry( iNewMessageId );
}
delete iSourceStore;
iSourceStore = NULL;
delete iSourceEntry;
iSourceEntry = NULL;
// complete the observer with error
TRequestStatus* status = &iObserverRequestStatus;
User::RequestComplete( status, aError );
}
// ---------------------------------------------------------
// CMmsMessageOperation::ChangeStateL
//
// ---------------------------------------------------------
void CMmsMessageOperation::ChangeStateL()
{
switch (iState)
{
case ECreateMmsHeaders:
CreateNewMmsHeaderL();
break;
case ECreateMessageEntry:
CreateMessageEntryL();
break;
case ECopyAttachments:
CopyAttachmentsL();
// Attachments are copied one by one.
// We stay in ECopyAttachment state until all attachments have
// been handled.
iCurrentAttachment++;
break;
case EStoreMmsHeaders:
StoreMmsHeadersL();
break;
case ECompleteMessage:
CompleteMessageL();
break;
case EFinished:
{
TRequestStatus* status = &iObserverRequestStatus;
User::RequestComplete( status, KErrNone );
}
break;
default:
// We are never supposed to be here.
User::LeaveIfError( KErrNotSupported );
break;
}
}
// ---------------------------------------------------------
// CMmsMessageOperation::RequestComplete
//
// ---------------------------------------------------------
void CMmsMessageOperation::RequestComplete( TInt aError )
{
iStatus = KRequestPending;
TRequestStatus* status = &iStatus;
User::RequestComplete( status, aError );
}
// ---------------------------------------------------------
// CMmsMessageOperation::SelectNextStateL
//
// ---------------------------------------------------------
void CMmsMessageOperation::SelectNextStateL()
{
switch (iState)
{
case ECreateMmsHeaders:
iState = ECreateMessageEntry;
break;
case ECreateMessageEntry:
{
// Get the id of new entry
TMsvLocalOperationProgress progress =
McliUtils::GetLocalProgressL( *iMsvOperation );
iNewMessageId = progress.iId;
iTargetEntry->SetEntryL( iNewMessageId );
iTargetStore = iTargetEntry->EditStoreL();
}
// Fall through on purpose.
// Attachment are copied before MMS headers are saved
// so that we can adjust the root attachment id.
// If the message has no attachments, we proceed directly
// to saving MMS headers.
case ECopyAttachments:
if ( iPartList & KMsvMessagePartAttachments &&
iCurrentAttachment < iAttachmentCount )
{
iState = ECopyAttachments;
}
else
{
iState = EStoreMmsHeaders;
}
break;
case EStoreMmsHeaders:
iState = ECompleteMessage;
break;
case ECompleteMessage:
iState = EFinished;
break;
default:
User::LeaveIfError( KErrNotSupported );
}
}
// ---------------------------------------------------------
// CMmsMessageOperation::SelectAndChangeToNextStateL
//
// ---------------------------------------------------------
void CMmsMessageOperation::SelectAndChangeToNextStateL()
{
SelectNextStateL();
ChangeStateL();
}
// ---------------------------------------------------------
// CMmsMessageOperation::CreateNewMmsHeaderL
//
// ---------------------------------------------------------
void CMmsMessageOperation::CreateNewMmsHeaderL()
{
// Load settings
iSettings->LoadSettingsL();
// Create MMS headers object
CMmsHeaders* originalMmsHeaders = NULL;
delete iNewMmsHeaders;
iNewMmsHeaders = NULL;
if ( ( iOperation == EReply ) ||
( iOperation == EForward ))
{
// Copy appropiate parts from original MMS headers
// We checked in the beginning that we have a source entry
originalMmsHeaders = CMmsHeaders::NewL( iSettings->MmsVersion() );
CleanupStack::PushL( originalMmsHeaders ); // ***
// Get the original message's MMS headers
originalMmsHeaders->RestoreL( *iSourceStore );
// Copy data
TBool isReply = iOperation == EReply ? ETrue : EFalse;
iNewMmsHeaders = originalMmsHeaders->CopyL( iPartList, isReply, iMsvSession.FileSession() );
// Remove own number from list if creating Reply
if ( iOperation == EReply )
{
CDesCArray* recipientList = new ( ELeave )CDesCArrayFlat( KMmsRecipientGranularity );
CleanupStack::PushL( recipientList );
TInt i;
for ( i = 0; i < iNewMmsHeaders->ToRecipients().MdcaCount(); i++ )
{
recipientList->AppendL(
TMmsGenUtils::PureAddress( iNewMmsHeaders->ToRecipients().MdcaPoint( i ) ) );
}
for ( i = 0; i < iNewMmsHeaders->CcRecipients().MdcaCount(); i++ )
{
recipientList->AppendL(
TMmsGenUtils::PureAddress( iNewMmsHeaders->CcRecipients().MdcaPoint( i ) ) );
}
for ( i = 0; i < iNewMmsHeaders->BccRecipients().MdcaCount(); i++ )
{
recipientList->AppendL(
TMmsGenUtils::PureAddress( iNewMmsHeaders->BccRecipients().MdcaPoint( i ) ) );
}
// Find own number
// don't remove if only one recipient in the list
if ( recipientList->MdcaCount() > 1 )
{
CMmsOwnNumber* ownNumberSearcher =
CMmsOwnNumber::NewL( &iMsvSession.FileSession() );
CleanupStack::PushL( ownNumberSearcher );
TInt index = -1;
index = ownNumberSearcher->StartL( *recipientList );
if ( index >= 0 )
{
// found something
while ( iNewMmsHeaders->RemoveAddressee( recipientList->MdcaPoint( index ) ) )
{
}
}
CleanupStack::PopAndDestroy( ownNumberSearcher );
}
CleanupStack::PopAndDestroy( recipientList );
}
// the root must always be retained if it is specified
if ( iPartList & KMsvMessagePartAttachments )
{
iOriginalRoot = originalMmsHeaders->MessageRoot();
iNewMmsHeaders->SetRootContentIdL( originalMmsHeaders->RootContentId() );
}
CleanupStack::PopAndDestroy( originalMmsHeaders );
}
else
{
// No original message available
iNewMmsHeaders = CMmsHeaders::NewL( iSettings->MmsVersion() );
}
// Reset MMS settings
iNewMmsHeaders->SetSettings( iSettings );
RequestComplete( KErrNone );
}
// ---------------------------------------------------------
// CMmsMessageOperation::CreateMessageEntryL
//
// ---------------------------------------------------------
void CMmsMessageOperation::CreateMessageEntryL()
{
// Create new message entry
// CREATE NEW INDEX ENTRY
TMsvEntry entry;
entry.iType = KUidMsvMessageEntry;
entry.iServiceId = iServiceId;
entry.iMtm = KUidMsgTypeMultimedia;
entry.iDate.UniversalTime();
// Set iMtmData extension flags
if ( iOperation == EForward )
{
entry.iMtmData1 |= KMmsMessageForwarded;
}
// Set iDetails
TPtrC to;
if ( iNewMmsHeaders->ToRecipients().Count() > 0 )
{
to.Set( iNewMmsHeaders->ToRecipients()[0] );
}
HBufC* buffer = HBufC::NewL( KMmsMaxDescription );
CleanupStack::PushL( buffer );
TPtr pBuffer = buffer->Des();
if ( TMmsGenUtils::IsValidMMSPhoneAddress( to, EFalse ) )
{
if ( TMmsGenUtils::GenerateDetails( to,
pBuffer, KMmsMaxDescription, iMsvSession.FileSession() ) == KErrNone )
{
entry.iDetails.Set( pBuffer );
}
else
{
entry.iDetails.Set( to );
}
}
else
{
entry.iDetails.Set( to );
}
// Set iDescription
entry.iDescription.Set( iNewMmsHeaders->Subject());
// if no subject, copy old description
if ( ( iPartList & KMsvMessagePartAttachments ) &&
( iOrigMessageId != KMsvNullIndexEntryId ) &&
( entry.iDescription.Length() == 0 ) )
{
// Copy the old description, no need to scan message files again ...
TPtrC pp;
pp.Set( iSourceEntry->Entry().iDescription );
delete iDescription;
iDescription = NULL;
iDescription = pp.AllocL();
entry.iDescription.Set( *iDescription );
}
// The following ones will be set in completion.
entry.SetInPreparation( ETrue );
entry.SetVisible( EFalse );
entry.iSize = 0;
// Create the new message entry asynchronically.
delete iMsvOperation;
iMsvOperation = NULL;
iCurrentAttachment = 0;
if ( iPartList & KMsvMessagePartAttachments )
{
// get number of attachments
MMsvAttachmentManager& sourceAttaMan = iSourceStore->AttachmentManagerL();
iAttachmentCount = sourceAttaMan.AttachmentCount();
}
// Check that sufficient disk space available
// for index entry
iTargetEntry->SetEntryL( iDestinationId );
RFs fs = iMsvSession.FileSession();
if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( &fs,
sizeof( TMsvEntry )
+ entry.iDescription.Length()
+ entry.iDetails.Length(),
iMsvSession.CurrentDriveL() ) )
{
// we use standard error code here
User::Leave( KErrDiskFull );
}
// Target entry still points to destination folder
iMsvOperation = iTargetEntry->CreateL( entry, iStatus );
CleanupStack::PopAndDestroy( buffer );
}
// ---------------------------------------------------------
// CMmsMessageOperation::StoreMmsHeadersL
//
// ---------------------------------------------------------
void CMmsMessageOperation::StoreMmsHeadersL()
{
// save the correct id for new root
if ( iPartList & KMsvMessagePartAttachments &&
iNewRoot != -1 )
{
MMsvAttachmentManager& targetAttaMan = iTargetStore->AttachmentManagerL();
CMsvAttachment* targetAtta = targetAttaMan.GetAttachmentInfoL( iNewRoot );
CleanupStack::PushL( targetAtta );
iNewMmsHeaders->SetMessageRoot( targetAtta->Id() );
CleanupStack::PopAndDestroy( targetAtta );
}
else
{
iNewMmsHeaders->SetRootContentIdL( TPtrC8() );
}
// Check that sufficient disk space available
// for MMS headers stream
RFs fs = iMsvSession.FileSession();
if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( &fs,
iNewMmsHeaders->Size(),
iMsvSession.CurrentDriveL() ) )
{
// we use standard error code here
User::Leave( KErrDiskFull );
}
// Externalize MMS headers
iNewMmsHeaders->StoreL( *iTargetStore );
// This is the last stage in creating the new entry.
// Now the store is committed and deleted.
iTargetStore->CommitL();
delete iTargetStore;
iTargetStore = NULL;
// Free the memory
iMmsHeaderSize = iNewMmsHeaders->Size();
delete iNewMmsHeaders;
iNewMmsHeaders = NULL;
delete iDescription;
iDescription = NULL;
RequestComplete( KErrNone );
}
// ---------------------------------------------------------
// CMmsMessageOperation::CopyAttachmentsL
//
// ---------------------------------------------------------
void CMmsMessageOperation::CopyAttachmentsL()
{
// Attachments must be copied one by one because of the asynchronous
// nature of the attachment manager functions.
// We get here only if the message has attachments and the part list
// specifies that the attachments must be copied.
// Get next attachment
MMsvAttachmentManager& sourceAttaMan = iSourceStore->AttachmentManagerL();
CMsvAttachment* sourceAtta = sourceAttaMan.GetAttachmentInfoL( iCurrentAttachment );
CleanupStack::PushL( sourceAtta );
CMsvMimeHeaders* mime = CMsvMimeHeaders::NewL();
CleanupStack::PushL( mime );
mime->RestoreL( *sourceAtta );
delete iMsvOperation;
iMsvOperation = NULL;
TInt size = 0;
// We need to check disk space for mime headers and file attachments
// Linked attachments are not copied, and do not take up space
size += mime->Size(); // size of mime headers
if ( sourceAtta->Type() == CMsvAttachment::EMsvFile )
{
// Add file size only if the attachment file must be copied.
// Linked attachment files are not copied, just the link is added
size += sourceAtta->Size();
}
RFs fs = iMsvSession.FileSession();
if ( TMmsGenUtils::DiskSpaceBelowCriticalLevelL( &fs,
size,
iMsvSession.CurrentDriveL() ) )
{
delete iTargetStore;
iTargetStore = NULL;
delete iTargetEntry;
iTargetEntry = NULL;
CleanupStack::PopAndDestroy( mime );
CleanupStack::PopAndDestroy( sourceAtta );
// we use standard error code here
User::Leave( KErrDiskFull );
}
// Copy the attachment
MMsvAttachmentManager& targetAttaMan = iTargetStore->AttachmentManagerL();
CMsvAttachment* targetAtta = NULL;
HBufC8* mimeType = sourceAtta->MimeType().AllocL();
CleanupStack::PushL( mimeType );
TParse fParse;
User::LeaveIfError( fParse.Set( sourceAtta->FilePath(), NULL, NULL ) );
HBufC* attaName = fParse.NameAndExt().AllocL();
CleanupStack::PushL( attaName );
targetAtta = CMsvAttachment::NewL(
sourceAtta->Type(),
sourceAtta->Size(),
mimeType,
attaName
);
CleanupStack::Pop( attaName ); // ownership of attaName transferred to targetAtta
CleanupStack::Pop( mimeType ); // ownership of mimeType transferred to targetAtta
CleanupStack::PushL( targetAtta );
mime->StoreL( *targetAtta );
if ( sourceAtta->Type() == CMsvAttachment::EMsvFile )
{
RFile sourceFile = sourceAttaMan.GetAttachmentFileL( iCurrentAttachment );
CleanupClosePushL( sourceFile );
targetAttaMan.AddAttachmentL( sourceFile,
targetAtta,
iStatus );
CleanupStack::Pop( &sourceFile ); // close file
}
else // linked file
{
targetAttaMan.AddLinkedAttachmentL( sourceAtta->FilePath(), targetAtta, iStatus );
}
if ( sourceAtta->Id() == iOriginalRoot )
{
iNewRoot = iCurrentAttachment; // save the index
}
// Ownership of targetAtta was transferred to attachment manager
CleanupStack::Pop( targetAtta ); // targetAtta
CleanupStack::PopAndDestroy( mime );
CleanupStack::PopAndDestroy( sourceAtta );
// RunL sets us active
}
// ---------------------------------------------------------
// CMmsMessageOperation::CompleteMessageL
//
// ---------------------------------------------------------
void CMmsMessageOperation::CompleteMessageL()
{
// As the attachments are not separate entries, iTargetEntry always points to
// the new message entry. No need to set iTargetEntry to the new entry anymore.
TMsvEntry entry = iTargetEntry->Entry();
AttachmentsSizeL();
// iTargetStore is recreated in AttachmentSizeL(), we must kill it
// to prevent a crash if the user cancels the operation at the last minute.
// The actual problem is in Symbian attachment manager code, DoCancel()
// should not do anything if the active object is not active (Symbian code does
// not check the state).
delete iTargetStore;
iTargetStore = NULL;
entry.iSize = ( iAttachmentsSize + iMmsHeaderSize );
entry.SetVisible( iVisible );
entry.SetInPreparation( iInPreparation );
entry.SetAttachment( iAttachmentsSize ? ETrue : EFalse );
iTargetEntry->ChangeL( entry );
RequestComplete( KErrNone );
}
// ---------------------------------------------------------
// CMmsMessageOperation::DoCancel
//
// ---------------------------------------------------------
void CMmsMessageOperation::DoCancel()
{
// Cancel all the pending requests
if ( iMsvOperation )
{
iMsvOperation->Cancel();
}
if ( iTargetStore )
{
// cancel attachment manager operations if any are active
TRAP_IGNORE(
{
// This will leave only if there is no attachment manager
// Otherwise it will just return reference to the existing manager
MMsvAttachmentManager& attaMan = iTargetStore->AttachmentManagerL();
// If there is no attachment manager, there cannot be any ongoing request
// So the request needs to be cancelled only if the previous function
// did not leave
attaMan.CancelRequest();
});
delete iTargetStore;
iTargetStore = NULL;
}
delete iTargetEntry;
iTargetEntry = NULL;
delete iSourceStore;
iSourceStore = NULL;
delete iSourceEntry;
iSourceEntry = NULL;
// Remove the new message entry
if ( iNewMessageId != KMsvNullIndexEntryId )
{
iMsvSession.RemoveEntry( iNewMessageId );
}
iNewMessageId = KMsvNullIndexEntryId;
TRequestStatus* st = &iObserverRequestStatus;
User::RequestComplete( st, KErrCancel );
}
// ---------------------------------------------------------
// CMmsMessageOperation::AttachmentsSizeL
//
// ---------------------------------------------------------
void CMmsMessageOperation::AttachmentsSizeL()
{
// We just scan the attachment entries and
// and calculate the total amount of size.
iAttachmentsSize = 0;
if ( !iTargetStore )
{
iTargetStore = iTargetEntry->ReadStoreL();
}
MMsvAttachmentManager& targetAttaMan = iTargetStore->AttachmentManagerL();
TInt counter = targetAttaMan.AttachmentCount();
for ( TInt i = 0; i < counter; i++ )
{
CMsvAttachment* attaInfo = targetAttaMan.GetAttachmentInfoL( i );
CleanupStack::PushL( attaInfo );
iAttachmentsSize += attaInfo->Size();
CMsvMimeHeaders* mime = CMsvMimeHeaders::NewL();
CleanupStack::PushL( mime );
mime->RestoreL( *attaInfo );
iAttachmentsSize += mime->Size();
CleanupStack::PopAndDestroy( mime );
CleanupStack::PopAndDestroy( attaInfo );
}
}
// ================= OTHER EXPORTED FUNCTIONS ==============
// End of File